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