mesa: add new ARB_fbo queries, fix some error tests
[mesa.git] / src / mesa / main / fbobject.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27 /*
28 * GL_EXT/ARB_framebuffer_object extensions
29 *
30 * Authors:
31 * Brian Paul
32 */
33
34
35 #include "buffers.h"
36 #include "context.h"
37 #include "fbobject.h"
38 #include "framebuffer.h"
39 #include "hash.h"
40 #include "macros.h"
41 #include "mipmap.h"
42 #include "renderbuffer.h"
43 #include "state.h"
44 #include "teximage.h"
45 #include "texobj.h"
46 #include "texstore.h"
47
48
49 /**
50 * Notes:
51 *
52 * None of the GL_EXT_framebuffer_object functions are compiled into
53 * display lists.
54 */
55
56
57
58 /*
59 * When glGenRender/FramebuffersEXT() is called we insert pointers to
60 * these placeholder objects into the hash table.
61 * Later, when the object ID is first bound, we replace the placeholder
62 * with the real frame/renderbuffer.
63 */
64 static struct gl_framebuffer DummyFramebuffer;
65 static struct gl_renderbuffer DummyRenderbuffer;
66
67
68 #define IS_CUBE_FACE(TARGET) \
69 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
70 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
71
72
73 static void
74 delete_dummy_renderbuffer(struct gl_renderbuffer *rb)
75 {
76 /* no op */
77 }
78
79 static void
80 delete_dummy_framebuffer(struct gl_framebuffer *fb)
81 {
82 /* no op */
83 }
84
85
86 void
87 _mesa_init_fbobjects(GLcontext *ctx)
88 {
89 DummyFramebuffer.Delete = delete_dummy_framebuffer;
90 DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
91 }
92
93
94 /**
95 * Helper routine for getting a gl_renderbuffer.
96 */
97 struct gl_renderbuffer *
98 _mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id)
99 {
100 struct gl_renderbuffer *rb;
101
102 if (id == 0)
103 return NULL;
104
105 rb = (struct gl_renderbuffer *)
106 _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
107 return rb;
108 }
109
110
111 /**
112 * Helper routine for getting a gl_framebuffer.
113 */
114 struct gl_framebuffer *
115 _mesa_lookup_framebuffer(GLcontext *ctx, GLuint id)
116 {
117 struct gl_framebuffer *fb;
118
119 if (id == 0)
120 return NULL;
121
122 fb = (struct gl_framebuffer *)
123 _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
124 return fb;
125 }
126
127
128 /**
129 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
130 * gl_renderbuffer_attachment object.
131 */
132 struct gl_renderbuffer_attachment *
133 _mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb,
134 GLenum attachment)
135 {
136 GLuint i;
137
138 switch (attachment) {
139 case GL_COLOR_ATTACHMENT0_EXT:
140 case GL_COLOR_ATTACHMENT1_EXT:
141 case GL_COLOR_ATTACHMENT2_EXT:
142 case GL_COLOR_ATTACHMENT3_EXT:
143 case GL_COLOR_ATTACHMENT4_EXT:
144 case GL_COLOR_ATTACHMENT5_EXT:
145 case GL_COLOR_ATTACHMENT6_EXT:
146 case GL_COLOR_ATTACHMENT7_EXT:
147 case GL_COLOR_ATTACHMENT8_EXT:
148 case GL_COLOR_ATTACHMENT9_EXT:
149 case GL_COLOR_ATTACHMENT10_EXT:
150 case GL_COLOR_ATTACHMENT11_EXT:
151 case GL_COLOR_ATTACHMENT12_EXT:
152 case GL_COLOR_ATTACHMENT13_EXT:
153 case GL_COLOR_ATTACHMENT14_EXT:
154 case GL_COLOR_ATTACHMENT15_EXT:
155 i = attachment - GL_COLOR_ATTACHMENT0_EXT;
156 if (i >= ctx->Const.MaxColorAttachments) {
157 return NULL;
158 }
159 return &fb->Attachment[BUFFER_COLOR0 + i];
160 case GL_DEPTH_ATTACHMENT_EXT:
161 return &fb->Attachment[BUFFER_DEPTH];
162 case GL_STENCIL_ATTACHMENT_EXT:
163 return &fb->Attachment[BUFFER_STENCIL];
164 default:
165 return NULL;
166 }
167 }
168
169
170 /**
171 * Remove any texture or renderbuffer attached to the given attachment
172 * point. Update reference counts, etc.
173 */
174 void
175 _mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
176 {
177 if (att->Type == GL_TEXTURE) {
178 ASSERT(att->Texture);
179 if (ctx->Driver.FinishRenderTexture) {
180 /* tell driver we're done rendering to this texobj */
181 ctx->Driver.FinishRenderTexture(ctx, att);
182 }
183 _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
184 ASSERT(!att->Texture);
185 }
186 if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
187 ASSERT(!att->Texture);
188 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
189 ASSERT(!att->Renderbuffer);
190 }
191 att->Type = GL_NONE;
192 att->Complete = GL_TRUE;
193 }
194
195
196 /**
197 * Bind a texture object to an attachment point.
198 * The previous binding, if any, will be removed first.
199 */
200 void
201 _mesa_set_texture_attachment(GLcontext *ctx,
202 struct gl_framebuffer *fb,
203 struct gl_renderbuffer_attachment *att,
204 struct gl_texture_object *texObj,
205 GLenum texTarget, GLuint level, GLuint zoffset)
206 {
207 if (att->Texture == texObj) {
208 /* re-attaching same texture */
209 ASSERT(att->Type == GL_TEXTURE);
210 }
211 else {
212 /* new attachment */
213 _mesa_remove_attachment(ctx, att);
214 att->Type = GL_TEXTURE;
215 assert(!att->Texture);
216 _mesa_reference_texobj(&att->Texture, texObj);
217 }
218
219 /* always update these fields */
220 att->TextureLevel = level;
221 if (IS_CUBE_FACE(texTarget)) {
222 att->CubeMapFace = texTarget - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
223 }
224 else {
225 att->CubeMapFace = 0;
226 }
227 att->Zoffset = zoffset;
228 att->Complete = GL_FALSE;
229
230 if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
231 ctx->Driver.RenderTexture(ctx, fb, att);
232 }
233 }
234
235
236 /**
237 * Bind a renderbuffer to an attachment point.
238 * The previous binding, if any, will be removed first.
239 */
240 void
241 _mesa_set_renderbuffer_attachment(GLcontext *ctx,
242 struct gl_renderbuffer_attachment *att,
243 struct gl_renderbuffer *rb)
244 {
245 /* XXX check if re-doing same attachment, exit early */
246 _mesa_remove_attachment(ctx, att);
247 att->Type = GL_RENDERBUFFER_EXT;
248 att->Texture = NULL; /* just to be safe */
249 att->Complete = GL_FALSE;
250 _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
251 }
252
253
254 /**
255 * Fallback for ctx->Driver.FramebufferRenderbuffer()
256 * Attach a renderbuffer object to a framebuffer object.
257 */
258 void
259 _mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
260 GLenum attachment, struct gl_renderbuffer *rb)
261 {
262 struct gl_renderbuffer_attachment *att;
263
264 _glthread_LOCK_MUTEX(fb->Mutex);
265
266 att = _mesa_get_attachment(ctx, fb, attachment);
267 ASSERT(att);
268 if (rb) {
269 _mesa_set_renderbuffer_attachment(ctx, att, rb);
270 }
271 else {
272 _mesa_remove_attachment(ctx, att);
273 }
274
275 _glthread_UNLOCK_MUTEX(fb->Mutex);
276 }
277
278
279 /**
280 * Test if an attachment point is complete and update its Complete field.
281 * \param format if GL_COLOR, this is a color attachment point,
282 * if GL_DEPTH, this is a depth component attachment point,
283 * if GL_STENCIL, this is a stencil component attachment point.
284 */
285 static void
286 test_attachment_completeness(const GLcontext *ctx, GLenum format,
287 struct gl_renderbuffer_attachment *att)
288 {
289 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
290
291 /* assume complete */
292 att->Complete = GL_TRUE;
293
294 /* Look for reasons why the attachment might be incomplete */
295 if (att->Type == GL_TEXTURE) {
296 const struct gl_texture_object *texObj = att->Texture;
297 struct gl_texture_image *texImage;
298
299 if (!texObj) {
300 att->Complete = GL_FALSE;
301 return;
302 }
303
304 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
305 if (!texImage) {
306 att->Complete = GL_FALSE;
307 return;
308 }
309 if (texImage->Width < 1 || texImage->Height < 1) {
310 att->Complete = GL_FALSE;
311 return;
312 }
313 if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
314 att->Complete = GL_FALSE;
315 return;
316 }
317
318 if (format == GL_COLOR) {
319 if (texImage->TexFormat->BaseFormat != GL_RGB &&
320 texImage->TexFormat->BaseFormat != GL_RGBA) {
321 att->Complete = GL_FALSE;
322 return;
323 }
324 }
325 else if (format == GL_DEPTH) {
326 if (texImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) {
327 /* OK */
328 }
329 else if (ctx->Extensions.EXT_packed_depth_stencil &&
330 texImage->TexFormat->BaseFormat == GL_DEPTH_STENCIL_EXT) {
331 /* OK */
332 }
333 else {
334 att->Complete = GL_FALSE;
335 return;
336 }
337 }
338 else {
339 /* no such thing as stencil textures */
340 att->Complete = GL_FALSE;
341 return;
342 }
343 }
344 else if (att->Type == GL_RENDERBUFFER_EXT) {
345 ASSERT(att->Renderbuffer);
346 if (!att->Renderbuffer->InternalFormat ||
347 att->Renderbuffer->Width < 1 ||
348 att->Renderbuffer->Height < 1) {
349 att->Complete = GL_FALSE;
350 return;
351 }
352 if (format == GL_COLOR) {
353 if (att->Renderbuffer->_BaseFormat != GL_RGB &&
354 att->Renderbuffer->_BaseFormat != GL_RGBA) {
355 ASSERT(att->Renderbuffer->RedBits);
356 ASSERT(att->Renderbuffer->GreenBits);
357 ASSERT(att->Renderbuffer->BlueBits);
358 att->Complete = GL_FALSE;
359 return;
360 }
361 }
362 else if (format == GL_DEPTH) {
363 ASSERT(att->Renderbuffer->DepthBits);
364 if (att->Renderbuffer->_BaseFormat == GL_DEPTH_COMPONENT) {
365 /* OK */
366 }
367 else if (ctx->Extensions.EXT_packed_depth_stencil &&
368 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
369 /* OK */
370 }
371 else {
372 att->Complete = GL_FALSE;
373 return;
374 }
375 }
376 else {
377 assert(format == GL_STENCIL);
378 ASSERT(att->Renderbuffer->StencilBits);
379 if (att->Renderbuffer->_BaseFormat == GL_STENCIL_INDEX) {
380 /* OK */
381 }
382 else if (ctx->Extensions.EXT_packed_depth_stencil &&
383 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
384 /* OK */
385 }
386 else {
387 att->Complete = GL_FALSE;
388 return;
389 }
390 }
391 }
392 else {
393 ASSERT(att->Type == GL_NONE);
394 /* complete */
395 return;
396 }
397 }
398
399
400 /**
401 * Helpful for debugging
402 */
403 static void
404 fbo_incomplete(const char *msg, int index)
405 {
406 (void) msg;
407 (void) index;
408 /*
409 _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
410 */
411 }
412
413
414 /**
415 * Test if the given framebuffer object is complete and update its
416 * Status field with the results.
417 * Also update the framebuffer's Width and Height fields if the
418 * framebuffer is complete.
419 */
420 void
421 _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb)
422 {
423 GLuint numImages;
424 GLenum intFormat = GL_NONE; /* color buffers' internal format */
425 GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
426 GLint i;
427 GLuint j;
428
429 assert(fb->Name != 0);
430
431 numImages = 0;
432 fb->Width = 0;
433 fb->Height = 0;
434
435 /* Start at -2 to more easily loop over all attachment points.
436 * -2: depth buffer
437 * -1: stencil buffer
438 * >=0: color buffer
439 */
440 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
441 struct gl_renderbuffer_attachment *att;
442 GLenum f;
443
444 /*
445 * XXX for ARB_fbo, only check color buffers that are named by
446 * GL_READ_BUFFER and GL_DRAW_BUFFERi.
447 */
448
449 /* check for attachment completeness
450 */
451 if (i == -2) {
452 att = &fb->Attachment[BUFFER_DEPTH];
453 test_attachment_completeness(ctx, GL_DEPTH, att);
454 if (!att->Complete) {
455 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
456 fbo_incomplete("depth attachment incomplete", -1);
457 return;
458 }
459 }
460 else if (i == -1) {
461 att = &fb->Attachment[BUFFER_STENCIL];
462 test_attachment_completeness(ctx, GL_STENCIL, att);
463 if (!att->Complete) {
464 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
465 fbo_incomplete("stencil attachment incomplete", -1);
466 return;
467 }
468 }
469 else {
470 att = &fb->Attachment[BUFFER_COLOR0 + i];
471 test_attachment_completeness(ctx, GL_COLOR, att);
472 if (!att->Complete) {
473 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
474 fbo_incomplete("color attachment incomplete", i);
475 return;
476 }
477 }
478
479 /* get width, height, format of the renderbuffer/texture
480 */
481 if (att->Type == GL_TEXTURE) {
482 const struct gl_texture_image *texImg
483 = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
484 minWidth = MIN2(minWidth, texImg->Width);
485 maxWidth = MAX2(maxWidth, texImg->Width);
486 minHeight = MIN2(minHeight, texImg->Height);
487 maxHeight = MAX2(maxHeight, texImg->Height);
488 f = texImg->_BaseFormat;
489 numImages++;
490 if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT
491 && f != GL_DEPTH_STENCIL_EXT) {
492 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
493 fbo_incomplete("texture attachment incomplete", -1);
494 return;
495 }
496 }
497 else if (att->Type == GL_RENDERBUFFER_EXT) {
498 minWidth = MIN2(minWidth, att->Renderbuffer->Width);
499 maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
500 minHeight = MIN2(minHeight, att->Renderbuffer->Height);
501 maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
502 f = att->Renderbuffer->InternalFormat;
503 numImages++;
504 }
505 else {
506 assert(att->Type == GL_NONE);
507 continue;
508 }
509
510 /* Error-check width, height, format
511 */
512 if (numImages == 1) {
513 /* save format */
514 if (i >= 0)
515 intFormat = f;
516 }
517 else {
518 if (!ctx->Extensions.ARB_framebuffer_object) {
519 /* check that width, height, format are same */
520 if (minWidth != maxWidth || minHeight != maxHeight) {
521 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
522 fbo_incomplete("width or height mismatch", -1);
523 return;
524 }
525 /* check that all color buffer have same format */
526 if (intFormat != GL_NONE && f != intFormat) {
527 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
528 fbo_incomplete("format mismatch", -1);
529 return;
530 }
531 }
532 }
533 }
534
535 #ifndef FEATURE_OES_framebuffer_object
536 /* Check that all DrawBuffers are present */
537 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
538 if (fb->ColorDrawBuffer[j] != GL_NONE) {
539 const struct gl_renderbuffer_attachment *att
540 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
541 assert(att);
542 if (att->Type == GL_NONE) {
543 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
544 fbo_incomplete("missing drawbuffer", j);
545 return;
546 }
547 }
548 }
549
550 /* Check that the ReadBuffer is present */
551 if (fb->ColorReadBuffer != GL_NONE) {
552 const struct gl_renderbuffer_attachment *att
553 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
554 assert(att);
555 if (att->Type == GL_NONE) {
556 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
557 fbo_incomplete("missing readbuffer", -1);
558 return;
559 }
560 }
561 #endif
562
563 if (numImages == 0) {
564 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
565 fbo_incomplete("no attachments", -1);
566 return;
567 }
568
569 /*
570 * If we get here, the framebuffer is complete!
571 * Note that if ARB_framebuffer_object is supported and the attached
572 * renderbuffers/textures are different sizes, the framebuffer width/height
573 * will be set to the smallest width/height.
574 */
575 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
576 fb->Width = minWidth;
577 fb->Height = minHeight;
578 }
579
580
581 GLboolean GLAPIENTRY
582 _mesa_IsRenderbufferEXT(GLuint renderbuffer)
583 {
584 GET_CURRENT_CONTEXT(ctx);
585 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
586 if (renderbuffer) {
587 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
588 if (rb != NULL && rb != &DummyRenderbuffer)
589 return GL_TRUE;
590 }
591 return GL_FALSE;
592 }
593
594
595 void GLAPIENTRY
596 _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
597 {
598 struct gl_renderbuffer *newRb;
599 GET_CURRENT_CONTEXT(ctx);
600
601 ASSERT_OUTSIDE_BEGIN_END(ctx);
602
603 if (target != GL_RENDERBUFFER_EXT) {
604 _mesa_error(ctx, GL_INVALID_ENUM,
605 "glBindRenderbufferEXT(target)");
606 return;
607 }
608
609 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
610 /* The above doesn't fully flush the drivers in the way that a
611 * glFlush does, but that is required here:
612 */
613 if (ctx->Driver.Flush)
614 ctx->Driver.Flush(ctx);
615
616
617 if (renderbuffer) {
618 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
619 if (newRb == &DummyRenderbuffer) {
620 /* ID was reserved, but no real renderbuffer object made yet */
621 newRb = NULL;
622 }
623 else if (!newRb && ctx->Extensions.ARB_framebuffer_object) {
624 /* All RB IDs must be Gen'd */
625 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
626 return;
627 }
628
629 if (!newRb) {
630 /* create new renderbuffer object */
631 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
632 if (!newRb) {
633 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
634 return;
635 }
636 ASSERT(newRb->AllocStorage);
637 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
638 newRb->RefCount = 1; /* referenced by hash table */
639 }
640 }
641 else {
642 newRb = NULL;
643 }
644
645 ASSERT(newRb != &DummyRenderbuffer);
646
647 _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
648 }
649
650
651 void GLAPIENTRY
652 _mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
653 {
654 GLint i;
655 GET_CURRENT_CONTEXT(ctx);
656
657 ASSERT_OUTSIDE_BEGIN_END(ctx);
658 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
659
660 for (i = 0; i < n; i++) {
661 if (renderbuffers[i] > 0) {
662 struct gl_renderbuffer *rb;
663 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
664 if (rb) {
665 /* check if deleting currently bound renderbuffer object */
666 if (rb == ctx->CurrentRenderbuffer) {
667 /* bind default */
668 ASSERT(rb->RefCount >= 2);
669 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
670 }
671
672 /* Remove from hash table immediately, to free the ID.
673 * But the object will not be freed until it's no longer
674 * referenced anywhere else.
675 */
676 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
677
678 if (rb != &DummyRenderbuffer) {
679 /* no longer referenced by hash table */
680 _mesa_reference_renderbuffer(&rb, NULL);
681 }
682 }
683 }
684 }
685 }
686
687
688 void GLAPIENTRY
689 _mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
690 {
691 GET_CURRENT_CONTEXT(ctx);
692 GLuint first;
693 GLint i;
694
695 ASSERT_OUTSIDE_BEGIN_END(ctx);
696
697 if (n < 0) {
698 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
699 return;
700 }
701
702 if (!renderbuffers)
703 return;
704
705 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
706
707 for (i = 0; i < n; i++) {
708 GLuint name = first + i;
709 renderbuffers[i] = name;
710 /* insert dummy placeholder into hash table */
711 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
712 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
713 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
714 }
715 }
716
717
718 /**
719 * Given an internal format token for a render buffer, return the
720 * corresponding base format.
721 * This is very similar to _mesa_base_tex_format() but the set of valid
722 * internal formats is somewhat different.
723 *
724 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
725 * GL_DEPTH_STENCIL_EXT or zero if error.
726 */
727 GLenum
728 _mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat)
729 {
730 switch (internalFormat) {
731 case GL_RGB:
732 case GL_R3_G3_B2:
733 case GL_RGB4:
734 case GL_RGB5:
735 case GL_RGB8:
736 case GL_RGB10:
737 case GL_RGB12:
738 case GL_RGB16:
739 return GL_RGB;
740 case GL_RGBA:
741 case GL_RGBA2:
742 case GL_RGBA4:
743 case GL_RGB5_A1:
744 case GL_RGBA8:
745 case GL_RGB10_A2:
746 case GL_RGBA12:
747 case GL_RGBA16:
748 return GL_RGBA;
749 case GL_STENCIL_INDEX:
750 case GL_STENCIL_INDEX1_EXT:
751 case GL_STENCIL_INDEX4_EXT:
752 case GL_STENCIL_INDEX8_EXT:
753 case GL_STENCIL_INDEX16_EXT:
754 return GL_STENCIL_INDEX;
755 case GL_DEPTH_COMPONENT:
756 case GL_DEPTH_COMPONENT16:
757 case GL_DEPTH_COMPONENT24:
758 case GL_DEPTH_COMPONENT32:
759 return GL_DEPTH_COMPONENT;
760 case GL_DEPTH_STENCIL_EXT:
761 case GL_DEPTH24_STENCIL8_EXT:
762 if (ctx->Extensions.EXT_packed_depth_stencil)
763 return GL_DEPTH_STENCIL_EXT;
764 else
765 return 0;
766 /* XXX add floating point formats eventually */
767 default:
768 return 0;
769 }
770 }
771
772
773 void GLAPIENTRY
774 _mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
775 GLsizei width, GLsizei height)
776 {
777 struct gl_renderbuffer *rb;
778 GLenum baseFormat;
779 GET_CURRENT_CONTEXT(ctx);
780
781 ASSERT_OUTSIDE_BEGIN_END(ctx);
782
783 if (target != GL_RENDERBUFFER_EXT) {
784 _mesa_error(ctx, GL_INVALID_ENUM, "glRenderbufferStorageEXT(target)");
785 return;
786 }
787
788 baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
789 if (baseFormat == 0) {
790 _mesa_error(ctx, GL_INVALID_ENUM,
791 "glRenderbufferStorageEXT(internalFormat)");
792 return;
793 }
794
795 if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
796 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(width)");
797 return;
798 }
799
800 if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
801 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(height)");
802 return;
803 }
804
805 rb = ctx->CurrentRenderbuffer;
806
807 if (!rb) {
808 _mesa_error(ctx, GL_INVALID_OPERATION, "glRenderbufferStorageEXT");
809 return;
810 }
811
812 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
813
814 if (rb->InternalFormat == internalFormat &&
815 rb->Width == (GLuint) width &&
816 rb->Height == (GLuint) height) {
817 /* no change in allocation needed */
818 return;
819 }
820
821 /* These MUST get set by the AllocStorage func */
822 rb->_ActualFormat = 0;
823 rb->RedBits =
824 rb->GreenBits =
825 rb->BlueBits =
826 rb->AlphaBits =
827 rb->IndexBits =
828 rb->DepthBits =
829 rb->StencilBits = 0;
830
831 /* Now allocate the storage */
832 ASSERT(rb->AllocStorage);
833 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
834 /* No error - check/set fields now */
835 assert(rb->_ActualFormat);
836 assert(rb->Width == (GLuint) width);
837 assert(rb->Height == (GLuint) height);
838 assert(rb->RedBits || rb->GreenBits || rb->BlueBits || rb->AlphaBits ||
839 rb->DepthBits || rb->StencilBits || rb->IndexBits);
840 rb->InternalFormat = internalFormat;
841 rb->_BaseFormat = baseFormat;
842 }
843 else {
844 /* Probably ran out of memory - clear the fields */
845 rb->Width = 0;
846 rb->Height = 0;
847 rb->InternalFormat = GL_NONE;
848 rb->_ActualFormat = GL_NONE;
849 rb->_BaseFormat = GL_NONE;
850 rb->RedBits =
851 rb->GreenBits =
852 rb->BlueBits =
853 rb->AlphaBits =
854 rb->IndexBits =
855 rb->DepthBits =
856 rb->StencilBits = 0;
857 }
858
859 /*
860 test_framebuffer_completeness(ctx, fb);
861 */
862 /* XXX if this renderbuffer is attached anywhere, invalidate attachment
863 * points???
864 */
865 }
866
867
868 void GLAPIENTRY
869 _mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
870 {
871 GET_CURRENT_CONTEXT(ctx);
872
873 ASSERT_OUTSIDE_BEGIN_END(ctx);
874
875 if (target != GL_RENDERBUFFER_EXT) {
876 _mesa_error(ctx, GL_INVALID_ENUM,
877 "glGetRenderbufferParameterivEXT(target)");
878 return;
879 }
880
881 if (!ctx->CurrentRenderbuffer) {
882 _mesa_error(ctx, GL_INVALID_OPERATION,
883 "glGetRenderbufferParameterivEXT");
884 return;
885 }
886
887 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
888
889 switch (pname) {
890 case GL_RENDERBUFFER_WIDTH_EXT:
891 *params = ctx->CurrentRenderbuffer->Width;
892 return;
893 case GL_RENDERBUFFER_HEIGHT_EXT:
894 *params = ctx->CurrentRenderbuffer->Height;
895 return;
896 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
897 *params = ctx->CurrentRenderbuffer->InternalFormat;
898 return;
899 case GL_RENDERBUFFER_RED_SIZE_EXT:
900 *params = ctx->CurrentRenderbuffer->RedBits;
901 break;
902 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
903 *params = ctx->CurrentRenderbuffer->GreenBits;
904 break;
905 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
906 *params = ctx->CurrentRenderbuffer->BlueBits;
907 break;
908 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
909 *params = ctx->CurrentRenderbuffer->AlphaBits;
910 break;
911 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
912 *params = ctx->CurrentRenderbuffer->DepthBits;
913 break;
914 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
915 *params = ctx->CurrentRenderbuffer->StencilBits;
916 break;
917 default:
918 _mesa_error(ctx, GL_INVALID_ENUM,
919 "glGetRenderbufferParameterivEXT(target)");
920 return;
921 }
922 }
923
924
925 GLboolean GLAPIENTRY
926 _mesa_IsFramebufferEXT(GLuint framebuffer)
927 {
928 GET_CURRENT_CONTEXT(ctx);
929 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
930 if (framebuffer) {
931 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
932 if (rb != NULL && rb != &DummyFramebuffer)
933 return GL_TRUE;
934 }
935 return GL_FALSE;
936 }
937
938
939 static void
940 check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
941 {
942 GLuint i;
943 ASSERT(ctx->Driver.RenderTexture);
944 for (i = 0; i < BUFFER_COUNT; i++) {
945 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
946 struct gl_texture_object *texObj = att->Texture;
947 if (texObj
948 && att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
949 ctx->Driver.RenderTexture(ctx, fb, att);
950 }
951 }
952 }
953
954
955 /**
956 * Examine all the framebuffer's attachments to see if any are textures.
957 * If so, call ctx->Driver.FinishRenderTexture() for each texture to
958 * notify the device driver that the texture image may have changed.
959 */
960 static void
961 check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
962 {
963 if (ctx->Driver.FinishRenderTexture) {
964 GLuint i;
965 for (i = 0; i < BUFFER_COUNT; i++) {
966 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
967 if (att->Texture && att->Renderbuffer) {
968 ctx->Driver.FinishRenderTexture(ctx, att);
969 }
970 }
971 }
972 }
973
974
975 void GLAPIENTRY
976 _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
977 {
978 struct gl_framebuffer *newFb, *newFbread;
979 GLboolean bindReadBuf, bindDrawBuf;
980 GET_CURRENT_CONTEXT(ctx);
981
982 #ifdef DEBUG
983 if (ctx->Extensions.ARB_framebuffer_object) {
984 ASSERT(ctx->Extensions.EXT_framebuffer_object);
985 ASSERT(ctx->Extensions.EXT_framebuffer_blit);
986 }
987 #endif
988
989 ASSERT_OUTSIDE_BEGIN_END(ctx);
990
991 if (!ctx->Extensions.EXT_framebuffer_object) {
992 _mesa_error(ctx, GL_INVALID_OPERATION,
993 "glBindFramebufferEXT(unsupported)");
994 return;
995 }
996
997 switch (target) {
998 #if FEATURE_EXT_framebuffer_blit
999 case GL_DRAW_FRAMEBUFFER_EXT:
1000 if (!ctx->Extensions.EXT_framebuffer_blit) {
1001 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1002 return;
1003 }
1004 bindDrawBuf = GL_TRUE;
1005 bindReadBuf = GL_FALSE;
1006 break;
1007 case GL_READ_FRAMEBUFFER_EXT:
1008 if (!ctx->Extensions.EXT_framebuffer_blit) {
1009 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1010 return;
1011 }
1012 bindDrawBuf = GL_FALSE;
1013 bindReadBuf = GL_TRUE;
1014 break;
1015 #endif
1016 case GL_FRAMEBUFFER_EXT:
1017 bindDrawBuf = GL_TRUE;
1018 bindReadBuf = GL_TRUE;
1019 break;
1020 default:
1021 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1022 return;
1023 }
1024
1025 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1026
1027 if (ctx->Driver.Flush) {
1028 ctx->Driver.Flush(ctx);
1029 }
1030
1031 if (framebuffer) {
1032 /* Binding a user-created framebuffer object */
1033 newFb = _mesa_lookup_framebuffer(ctx, framebuffer);
1034 if (newFb == &DummyFramebuffer) {
1035 /* ID was reserved, but no real framebuffer object made yet */
1036 newFb = NULL;
1037 }
1038 else if (!newFb && ctx->Extensions.ARB_framebuffer_object) {
1039 /* All FBO IDs must be Gen'd */
1040 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
1041 return;
1042 }
1043
1044 if (!newFb) {
1045 /* create new framebuffer object */
1046 newFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
1047 if (!newFb) {
1048 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
1049 return;
1050 }
1051 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb);
1052 }
1053 newFbread = newFb;
1054 }
1055 else {
1056 /* Binding the window system framebuffer (which was originally set
1057 * with MakeCurrent).
1058 */
1059 newFb = ctx->WinSysDrawBuffer;
1060 newFbread = ctx->WinSysReadBuffer;
1061 }
1062
1063 ASSERT(newFb);
1064 ASSERT(newFb != &DummyFramebuffer);
1065
1066 /*
1067 * XXX check if re-binding same buffer and skip some of this code.
1068 */
1069
1070 if (bindReadBuf) {
1071 _mesa_reference_framebuffer(&ctx->ReadBuffer, newFbread);
1072 }
1073
1074 if (bindDrawBuf) {
1075 /* check if old FB had any texture attachments */
1076 check_end_texture_render(ctx, ctx->DrawBuffer);
1077
1078 /* check if time to delete this framebuffer */
1079 _mesa_reference_framebuffer(&ctx->DrawBuffer, newFb);
1080
1081 if (newFb->Name != 0) {
1082 /* check if newly bound framebuffer has any texture attachments */
1083 check_begin_texture_render(ctx, newFb);
1084 }
1085 }
1086
1087 if (ctx->Driver.BindFramebuffer) {
1088 ctx->Driver.BindFramebuffer(ctx, target, newFb, newFbread);
1089 }
1090 }
1091
1092
1093 void GLAPIENTRY
1094 _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
1095 {
1096 GLint i;
1097 GET_CURRENT_CONTEXT(ctx);
1098
1099 ASSERT_OUTSIDE_BEGIN_END(ctx);
1100 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1101 /* The above doesn't fully flush the drivers in the way that a
1102 * glFlush does, but that is required here:
1103 */
1104 if (ctx->Driver.Flush)
1105 ctx->Driver.Flush(ctx);
1106
1107 for (i = 0; i < n; i++) {
1108 if (framebuffers[i] > 0) {
1109 struct gl_framebuffer *fb;
1110 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
1111 if (fb) {
1112 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
1113
1114 /* check if deleting currently bound framebuffer object */
1115 if (fb == ctx->DrawBuffer) {
1116 /* bind default */
1117 ASSERT(fb->RefCount >= 2);
1118 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1119 }
1120
1121 /* remove from hash table immediately, to free the ID */
1122 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
1123
1124 if (fb != &DummyFramebuffer) {
1125 /* But the object will not be freed until it's no longer
1126 * bound in any context.
1127 */
1128 _mesa_unreference_framebuffer(&fb);
1129 }
1130 }
1131 }
1132 }
1133 }
1134
1135
1136 void GLAPIENTRY
1137 _mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
1138 {
1139 GET_CURRENT_CONTEXT(ctx);
1140 GLuint first;
1141 GLint i;
1142
1143 ASSERT_OUTSIDE_BEGIN_END(ctx);
1144
1145 if (n < 0) {
1146 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
1147 return;
1148 }
1149
1150 if (!framebuffers)
1151 return;
1152
1153 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1154
1155 for (i = 0; i < n; i++) {
1156 GLuint name = first + i;
1157 framebuffers[i] = name;
1158 /* insert dummy placeholder into hash table */
1159 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
1160 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
1161 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
1162 }
1163 }
1164
1165
1166
1167 GLenum GLAPIENTRY
1168 _mesa_CheckFramebufferStatusEXT(GLenum target)
1169 {
1170 struct gl_framebuffer *buffer;
1171 GET_CURRENT_CONTEXT(ctx);
1172
1173 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1174
1175 switch (target) {
1176 #if FEATURE_EXT_framebuffer_blit
1177 case GL_DRAW_FRAMEBUFFER_EXT:
1178 if (!ctx->Extensions.EXT_framebuffer_blit) {
1179 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1180 return 0;
1181 }
1182 buffer = ctx->DrawBuffer;
1183 break;
1184 case GL_READ_FRAMEBUFFER_EXT:
1185 if (!ctx->Extensions.EXT_framebuffer_blit) {
1186 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1187 return 0;
1188 }
1189 buffer = ctx->ReadBuffer;
1190 break;
1191 #endif
1192 case GL_FRAMEBUFFER_EXT:
1193 buffer = ctx->DrawBuffer;
1194 break;
1195 default:
1196 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1197 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
1198 }
1199
1200 if (buffer->Name == 0) {
1201 /* The window system / default framebuffer is always complete */
1202 return GL_FRAMEBUFFER_COMPLETE_EXT;
1203 }
1204
1205 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1206
1207 _mesa_test_framebuffer_completeness(ctx, buffer);
1208 return buffer->_Status;
1209 }
1210
1211
1212
1213 /**
1214 * Common code called by glFramebufferTexture1D/2D/3DEXT().
1215 */
1216 static void
1217 framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target,
1218 GLenum attachment, GLenum textarget, GLuint texture,
1219 GLint level, GLint zoffset)
1220 {
1221 struct gl_renderbuffer_attachment *att;
1222 struct gl_texture_object *texObj = NULL;
1223 struct gl_framebuffer *fb;
1224
1225 ASSERT_OUTSIDE_BEGIN_END(ctx);
1226
1227 if (target != GL_FRAMEBUFFER_EXT) {
1228 _mesa_error(ctx, GL_INVALID_ENUM,
1229 "glFramebufferTexture%sEXT(target)", caller);
1230 return;
1231 }
1232
1233 fb = ctx->DrawBuffer;
1234 ASSERT(fb);
1235
1236 /* check framebuffer binding */
1237 if (fb->Name == 0) {
1238 _mesa_error(ctx, GL_INVALID_OPERATION,
1239 "glFramebufferTexture%sEXT", caller);
1240 return;
1241 }
1242
1243
1244 /* The textarget, level, and zoffset parameters are only validated if
1245 * texture is non-zero.
1246 */
1247 if (texture) {
1248 GLboolean err = GL_TRUE;
1249
1250 texObj = _mesa_lookup_texture(ctx, texture);
1251 if (texObj != NULL) {
1252 if (textarget == 0) {
1253 err = (texObj->Target != GL_TEXTURE_3D) &&
1254 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1255 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1256 }
1257 else {
1258 err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
1259 ? !IS_CUBE_FACE(textarget)
1260 : (texObj->Target != textarget);
1261 }
1262 }
1263
1264 if (err) {
1265 _mesa_error(ctx, GL_INVALID_OPERATION,
1266 "glFramebufferTexture%sEXT(texture target mismatch)",
1267 caller);
1268 return;
1269 }
1270
1271 if (texObj->Target == GL_TEXTURE_3D) {
1272 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
1273 if (zoffset < 0 || zoffset >= maxSize) {
1274 _mesa_error(ctx, GL_INVALID_VALUE,
1275 "glFramebufferTexture%sEXT(zoffset)", caller);
1276 return;
1277 }
1278 }
1279 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
1280 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
1281 if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
1282 _mesa_error(ctx, GL_INVALID_VALUE,
1283 "glFramebufferTexture%sEXT(layer)", caller);
1284 return;
1285 }
1286 }
1287
1288
1289 if ((level < 0) ||
1290 (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
1291 _mesa_error(ctx, GL_INVALID_VALUE,
1292 "glFramebufferTexture%sEXT(level)", caller);
1293 return;
1294 }
1295 }
1296
1297 att = _mesa_get_attachment(ctx, fb, attachment);
1298 if (att == NULL) {
1299 _mesa_error(ctx, GL_INVALID_ENUM,
1300 "glFramebufferTexture%sEXT(attachment)", caller);
1301 return;
1302 }
1303
1304 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1305 /* The above doesn't fully flush the drivers in the way that a
1306 * glFlush does, but that is required here:
1307 */
1308 if (ctx->Driver.Flush)
1309 ctx->Driver.Flush(ctx);
1310
1311 _glthread_LOCK_MUTEX(fb->Mutex);
1312 if (texObj) {
1313 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
1314 level, zoffset);
1315 }
1316 else {
1317 _mesa_remove_attachment(ctx, att);
1318 }
1319 _glthread_UNLOCK_MUTEX(fb->Mutex);
1320 }
1321
1322
1323
1324 void GLAPIENTRY
1325 _mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
1326 GLenum textarget, GLuint texture, GLint level)
1327 {
1328 GET_CURRENT_CONTEXT(ctx);
1329
1330 if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
1331 _mesa_error(ctx, GL_INVALID_ENUM,
1332 "glFramebufferTexture1DEXT(textarget)");
1333 return;
1334 }
1335
1336 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
1337 level, 0);
1338 }
1339
1340
1341 void GLAPIENTRY
1342 _mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
1343 GLenum textarget, GLuint texture, GLint level)
1344 {
1345 GET_CURRENT_CONTEXT(ctx);
1346
1347 if ((texture != 0) &&
1348 (textarget != GL_TEXTURE_2D) &&
1349 (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
1350 (!IS_CUBE_FACE(textarget))) {
1351 _mesa_error(ctx, GL_INVALID_OPERATION,
1352 "glFramebufferTexture2DEXT(textarget)");
1353 return;
1354 }
1355
1356 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
1357 level, 0);
1358 }
1359
1360
1361 void GLAPIENTRY
1362 _mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
1363 GLenum textarget, GLuint texture,
1364 GLint level, GLint zoffset)
1365 {
1366 GET_CURRENT_CONTEXT(ctx);
1367
1368 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
1369 _mesa_error(ctx, GL_INVALID_ENUM,
1370 "glFramebufferTexture3DEXT(textarget)");
1371 return;
1372 }
1373
1374 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
1375 level, zoffset);
1376 }
1377
1378
1379 void GLAPIENTRY
1380 _mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
1381 GLuint texture, GLint level, GLint layer)
1382 {
1383 GET_CURRENT_CONTEXT(ctx);
1384
1385 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
1386 level, layer);
1387 }
1388
1389
1390 void GLAPIENTRY
1391 _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
1392 GLenum renderbufferTarget,
1393 GLuint renderbuffer)
1394 {
1395 struct gl_renderbuffer_attachment *att;
1396 struct gl_framebuffer *fb;
1397 struct gl_renderbuffer *rb;
1398 GET_CURRENT_CONTEXT(ctx);
1399
1400 ASSERT_OUTSIDE_BEGIN_END(ctx);
1401
1402 switch (target) {
1403 #if FEATURE_EXT_framebuffer_blit
1404 case GL_DRAW_FRAMEBUFFER_EXT:
1405 if (!ctx->Extensions.EXT_framebuffer_blit) {
1406 _mesa_error(ctx, GL_INVALID_ENUM,
1407 "glFramebufferRenderbufferEXT(target)");
1408 return;
1409 }
1410 fb = ctx->DrawBuffer;
1411 break;
1412 case GL_READ_FRAMEBUFFER_EXT:
1413 if (!ctx->Extensions.EXT_framebuffer_blit) {
1414 _mesa_error(ctx, GL_INVALID_ENUM,
1415 "glFramebufferRenderbufferEXT(target)");
1416 return;
1417 }
1418 fb = ctx->ReadBuffer;
1419 break;
1420 #endif
1421 case GL_FRAMEBUFFER_EXT:
1422 fb = ctx->DrawBuffer;
1423 break;
1424 default:
1425 _mesa_error(ctx, GL_INVALID_ENUM,
1426 "glFramebufferRenderbufferEXT(target)");
1427 return;
1428 }
1429
1430 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
1431 _mesa_error(ctx, GL_INVALID_ENUM,
1432 "glFramebufferRenderbufferEXT(renderbufferTarget)");
1433 return;
1434 }
1435
1436 if (fb->Name == 0) {
1437 /* Can't attach new renderbuffers to a window system framebuffer */
1438 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
1439 return;
1440 }
1441
1442 att = _mesa_get_attachment(ctx, fb, attachment);
1443 if (att == NULL) {
1444 _mesa_error(ctx, GL_INVALID_ENUM,
1445 "glFramebufferRenderbufferEXT(attachment)");
1446 return;
1447 }
1448
1449 if (renderbuffer) {
1450 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
1451 if (!rb) {
1452 _mesa_error(ctx, GL_INVALID_OPERATION,
1453 "glFramebufferRenderbufferEXT(renderbuffer)");
1454 return;
1455 }
1456 }
1457 else {
1458 /* remove renderbuffer attachment */
1459 rb = NULL;
1460 }
1461
1462 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1463 /* The above doesn't fully flush the drivers in the way that a
1464 * glFlush does, but that is required here:
1465 */
1466 if (ctx->Driver.Flush)
1467 ctx->Driver.Flush(ctx);
1468
1469 assert(ctx->Driver.FramebufferRenderbuffer);
1470 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
1471
1472 /* Some subsequent GL commands may depend on the framebuffer's visual
1473 * after the binding is updated. Update visual info now.
1474 */
1475 _mesa_update_framebuffer_visual(fb);
1476 }
1477
1478
1479 void GLAPIENTRY
1480 _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
1481 GLenum pname, GLint *params)
1482 {
1483 const struct gl_renderbuffer_attachment *att;
1484 struct gl_framebuffer *buffer;
1485 GET_CURRENT_CONTEXT(ctx);
1486
1487 ASSERT_OUTSIDE_BEGIN_END(ctx);
1488
1489 switch (target) {
1490 #if FEATURE_EXT_framebuffer_blit
1491 case GL_DRAW_FRAMEBUFFER_EXT:
1492 if (!ctx->Extensions.EXT_framebuffer_blit) {
1493 _mesa_error(ctx, GL_INVALID_ENUM,
1494 "glGetFramebufferAttachmentParameterivEXT(target)");
1495 return;
1496 }
1497 buffer = ctx->DrawBuffer;
1498 break;
1499 case GL_READ_FRAMEBUFFER_EXT:
1500 if (!ctx->Extensions.EXT_framebuffer_blit) {
1501 _mesa_error(ctx, GL_INVALID_ENUM,
1502 "glGetFramebufferAttachmentParameterivEXT(target)");
1503 return;
1504 }
1505 buffer = ctx->ReadBuffer;
1506 break;
1507 #endif
1508 case GL_FRAMEBUFFER_EXT:
1509 buffer = ctx->DrawBuffer;
1510 break;
1511 default:
1512 _mesa_error(ctx, GL_INVALID_ENUM,
1513 "glGetFramebufferAttachmentParameterivEXT(target)");
1514 return;
1515 }
1516
1517 if (buffer->Name == 0) {
1518 _mesa_error(ctx, GL_INVALID_OPERATION,
1519 "glGetFramebufferAttachmentParameterivEXT");
1520 return;
1521 }
1522
1523 att = _mesa_get_attachment(ctx, buffer, attachment);
1524 if (att == NULL) {
1525 _mesa_error(ctx, GL_INVALID_ENUM,
1526 "glGetFramebufferAttachmentParameterivEXT(attachment)");
1527 return;
1528 }
1529
1530 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1531 /* The above doesn't fully flush the drivers in the way that a
1532 * glFlush does, but that is required here:
1533 */
1534 if (ctx->Driver.Flush)
1535 ctx->Driver.Flush(ctx);
1536
1537 switch (pname) {
1538 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
1539 *params = att->Type;
1540 return;
1541 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
1542 if (att->Type == GL_RENDERBUFFER_EXT) {
1543 *params = att->Renderbuffer->Name;
1544 }
1545 else if (att->Type == GL_TEXTURE) {
1546 *params = att->Texture->Name;
1547 }
1548 else {
1549 _mesa_error(ctx, GL_INVALID_ENUM,
1550 "glGetFramebufferAttachmentParameterivEXT(pname)");
1551 }
1552 return;
1553 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
1554 if (att->Type == GL_TEXTURE) {
1555 *params = att->TextureLevel;
1556 }
1557 else {
1558 _mesa_error(ctx, GL_INVALID_ENUM,
1559 "glGetFramebufferAttachmentParameterivEXT(pname)");
1560 }
1561 return;
1562 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
1563 if (att->Type == GL_TEXTURE) {
1564 if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
1565 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
1566 }
1567 else {
1568 *params = 0;
1569 }
1570 }
1571 else {
1572 _mesa_error(ctx, GL_INVALID_ENUM,
1573 "glGetFramebufferAttachmentParameterivEXT(pname)");
1574 }
1575 return;
1576 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
1577 if (att->Type == GL_TEXTURE) {
1578 if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
1579 *params = att->Zoffset;
1580 }
1581 else {
1582 *params = 0;
1583 }
1584 }
1585 else {
1586 _mesa_error(ctx, GL_INVALID_ENUM,
1587 "glGetFramebufferAttachmentParameterivEXT(pname)");
1588 }
1589 return;
1590 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
1591 if (!ctx->Extensions.ARB_framebuffer_object) {
1592 _mesa_error(ctx, GL_INVALID_ENUM,
1593 "glGetFramebufferAttachmentParameterivEXT(pname)");
1594 }
1595 else {
1596 *params = att->Renderbuffer->ColorEncoding;
1597 }
1598 return;
1599 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
1600 if (!ctx->Extensions.ARB_framebuffer_object) {
1601 _mesa_error(ctx, GL_INVALID_ENUM,
1602 "glGetFramebufferAttachmentParameterivEXT(pname)");
1603 return;
1604 }
1605 else {
1606 *params = att->Renderbuffer->ComponentType;
1607 }
1608 return;
1609 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
1610 if (!ctx->Extensions.ARB_framebuffer_object) {
1611 _mesa_error(ctx, GL_INVALID_ENUM,
1612 "glGetFramebufferAttachmentParameterivEXT(pname)");
1613 }
1614 else {
1615 *params = att->Renderbuffer->RedBits;
1616 }
1617 return;
1618 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
1619 if (!ctx->Extensions.ARB_framebuffer_object) {
1620 _mesa_error(ctx, GL_INVALID_ENUM,
1621 "glGetFramebufferAttachmentParameterivEXT(pname)");
1622 }
1623 else {
1624 *params = att->Renderbuffer->GreenBits;
1625 }
1626 return;
1627 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
1628 if (!ctx->Extensions.ARB_framebuffer_object) {
1629 _mesa_error(ctx, GL_INVALID_ENUM,
1630 "glGetFramebufferAttachmentParameterivEXT(pname)");
1631 }
1632 else {
1633 *params = att->Renderbuffer->BlueBits;
1634 }
1635 return;
1636 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
1637 if (!ctx->Extensions.ARB_framebuffer_object) {
1638 _mesa_error(ctx, GL_INVALID_ENUM,
1639 "glGetFramebufferAttachmentParameterivEXT(pname)");
1640 }
1641 else {
1642 *params = att->Renderbuffer->AlphaBits;
1643 }
1644 return;
1645 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
1646 if (!ctx->Extensions.ARB_framebuffer_object) {
1647 _mesa_error(ctx, GL_INVALID_ENUM,
1648 "glGetFramebufferAttachmentParameterivEXT(pname)");
1649 }
1650 else {
1651 *params = att->Renderbuffer->DepthBits;
1652 }
1653 return;
1654 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
1655 if (!ctx->Extensions.ARB_framebuffer_object) {
1656 _mesa_error(ctx, GL_INVALID_ENUM,
1657 "glGetFramebufferAttachmentParameterivEXT(pname)");
1658 }
1659 else {
1660 *params = att->Renderbuffer->StencilBits;
1661 }
1662 return;
1663 default:
1664 _mesa_error(ctx, GL_INVALID_ENUM,
1665 "glGetFramebufferAttachmentParameterivEXT(pname)");
1666 return;
1667 }
1668 }
1669
1670
1671 void GLAPIENTRY
1672 _mesa_GenerateMipmapEXT(GLenum target)
1673 {
1674 struct gl_texture_unit *texUnit;
1675 struct gl_texture_object *texObj;
1676 GET_CURRENT_CONTEXT(ctx);
1677
1678 ASSERT_OUTSIDE_BEGIN_END(ctx);
1679 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1680
1681 switch (target) {
1682 case GL_TEXTURE_1D:
1683 case GL_TEXTURE_2D:
1684 case GL_TEXTURE_3D:
1685 case GL_TEXTURE_CUBE_MAP:
1686 /* OK, legal value */
1687 break;
1688 default:
1689 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
1690 return;
1691 }
1692
1693 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1694 texObj = _mesa_select_tex_object(ctx, texUnit, target);
1695
1696 _mesa_lock_texture(ctx, texObj);
1697 if (target == GL_TEXTURE_CUBE_MAP) {
1698 int face;
1699
1700 for (face = 0; face < 6; face++)
1701 ctx->Driver.GenerateMipmap(ctx,
1702 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
1703 texObj);
1704 } else {
1705 ctx->Driver.GenerateMipmap(ctx, target, texObj);
1706 }
1707 _mesa_unlock_texture(ctx, texObj);
1708 }
1709
1710
1711 #if FEATURE_EXT_framebuffer_blit
1712 void GLAPIENTRY
1713 _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
1714 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
1715 GLbitfield mask, GLenum filter)
1716 {
1717 GET_CURRENT_CONTEXT(ctx);
1718
1719 ASSERT_OUTSIDE_BEGIN_END(ctx);
1720 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1721
1722 if (ctx->NewState) {
1723 _mesa_update_state(ctx);
1724 }
1725
1726 if (!ctx->ReadBuffer) {
1727 /* XXX */
1728 }
1729
1730 /* check for complete framebuffers */
1731 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
1732 ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1733 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
1734 "glBlitFramebufferEXT(incomplete draw/read buffers)");
1735 return;
1736 }
1737
1738 if (filter != GL_NEAREST && filter != GL_LINEAR) {
1739 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
1740 return;
1741 }
1742
1743 if (mask & ~(GL_COLOR_BUFFER_BIT |
1744 GL_DEPTH_BUFFER_BIT |
1745 GL_STENCIL_BUFFER_BIT)) {
1746 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
1747 return;
1748 }
1749
1750 /* depth/stencil must be blitted with nearest filtering */
1751 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
1752 && filter != GL_NEAREST) {
1753 _mesa_error(ctx, GL_INVALID_OPERATION,
1754 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
1755 return;
1756 }
1757
1758 if (mask & GL_STENCIL_BUFFER_BIT) {
1759 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_StencilBuffer;
1760 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_StencilBuffer;
1761 if (readRb->StencilBits != drawRb->StencilBits) {
1762 _mesa_error(ctx, GL_INVALID_OPERATION,
1763 "glBlitFramebufferEXT(stencil buffer size mismatch");
1764 return;
1765 }
1766 }
1767
1768 if (mask & GL_DEPTH_BUFFER_BIT) {
1769 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_DepthBuffer;
1770 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_DepthBuffer;
1771 if (readRb->DepthBits != drawRb->DepthBits) {
1772 _mesa_error(ctx, GL_INVALID_OPERATION,
1773 "glBlitFramebufferEXT(depth buffer size mismatch");
1774 return;
1775 }
1776 }
1777
1778 if (!ctx->Extensions.EXT_framebuffer_blit) {
1779 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
1780 return;
1781 }
1782
1783 ASSERT(ctx->Driver.BlitFramebuffer);
1784 ctx->Driver.BlitFramebuffer(ctx,
1785 srcX0, srcY0, srcX1, srcY1,
1786 dstX0, dstY0, dstX1, dstY1,
1787 mask, filter);
1788 }
1789 #endif /* FEATURE_EXT_framebuffer_blit */