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