7b47a9903512a5eefb2ca2aec58f3957a0a113ac
[mesa.git] / src / mesa / main / fbobject.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.3
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 "hash.h"
35 #include "teximage.h"
36 #include "texstore.h"
37
38
39 /*
40 * When glGenRender/FramebuffersEXT() is called we insert pointers to
41 * these placeholder objects into the hash table.
42 * Later, when the object ID is first bound, we replace the placeholder
43 * with the real frame/renderbuffer.
44 */
45 static struct gl_frame_buffer_object DummyFramebuffer;
46 static struct gl_render_buffer_object DummyRenderbuffer;
47
48
49 #define IS_CUBE_FACE(TARGET) \
50 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
51 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
52
53
54 /**
55 * Helper routine for getting a gl_render_buffer_object.
56 */
57 static struct gl_render_buffer_object *
58 lookup_renderbuffer(GLcontext *ctx, GLuint id)
59 {
60 struct gl_render_buffer_object *rb;
61
62 if (id == 0)
63 return NULL;
64
65 rb = (struct gl_render_buffer_object *)
66 _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
67 return rb;
68 }
69
70
71 /**
72 * Helper routine for getting a gl_frame_buffer_object.
73 */
74 static struct gl_frame_buffer_object *
75 lookup_framebuffer(GLcontext *ctx, GLuint id)
76 {
77 struct gl_frame_buffer_object *fb;
78
79 if (id == 0)
80 return NULL;
81
82 fb = (struct gl_frame_buffer_object *)
83 _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
84 return fb;
85 }
86
87
88 /**
89 * Allocate a new gl_render_buffer_object.
90 * XXX make this a device driver function.
91 */
92 static struct gl_render_buffer_object *
93 new_renderbuffer(GLcontext *ctx, GLuint name)
94 {
95 struct gl_render_buffer_object *rb = CALLOC_STRUCT(gl_render_buffer_object);
96 if (rb) {
97 rb->Name = name;
98 rb->RefCount = 1;
99 /* other fields are zero */
100 }
101 return rb;
102 }
103
104
105 /**
106 * Allocate a new gl_frame_buffer_object.
107 * XXX make this a device driver function.
108 */
109 static struct gl_frame_buffer_object *
110 new_framebuffer(GLcontext *ctx, GLuint name)
111 {
112 struct gl_frame_buffer_object *fb = CALLOC_STRUCT(gl_frame_buffer_object);
113 if (fb) {
114 fb->Name = name;
115 fb->RefCount = 1;
116 }
117 return fb;
118 }
119
120
121 static struct gl_render_buffer_attachment *
122 get_attachment(GLcontext *ctx, GLenum attachment)
123 {
124 GLuint i;
125
126 switch (attachment) {
127 case GL_COLOR_ATTACHMENT0_EXT:
128 case GL_COLOR_ATTACHMENT1_EXT:
129 case GL_COLOR_ATTACHMENT2_EXT:
130 case GL_COLOR_ATTACHMENT3_EXT:
131 case GL_COLOR_ATTACHMENT4_EXT:
132 case GL_COLOR_ATTACHMENT5_EXT:
133 case GL_COLOR_ATTACHMENT6_EXT:
134 case GL_COLOR_ATTACHMENT7_EXT:
135 case GL_COLOR_ATTACHMENT8_EXT:
136 case GL_COLOR_ATTACHMENT9_EXT:
137 case GL_COLOR_ATTACHMENT10_EXT:
138 case GL_COLOR_ATTACHMENT11_EXT:
139 case GL_COLOR_ATTACHMENT12_EXT:
140 case GL_COLOR_ATTACHMENT13_EXT:
141 case GL_COLOR_ATTACHMENT14_EXT:
142 case GL_COLOR_ATTACHMENT15_EXT:
143 i = attachment - GL_COLOR_ATTACHMENT0_EXT;
144 if (i >= ctx->Const.MaxColorAttachments) {
145 return NULL;
146 }
147 return &ctx->CurrentFramebuffer->ColorAttachment[i];
148 case GL_DEPTH_ATTACHMENT_EXT:
149 return &ctx->CurrentFramebuffer->DepthAttachment;
150 case GL_STENCIL_ATTACHMENT_EXT:
151 return &ctx->CurrentFramebuffer->StencilAttachment;
152 default:
153 return NULL;
154 }
155 }
156
157
158 static void
159 remove_attachment(GLcontext *ctx, struct gl_render_buffer_attachment *att)
160 {
161 if (att->Type == GL_TEXTURE) {
162 ASSERT(att->Texture);
163 ASSERT(!att->Renderbuffer);
164 att->Texture->RefCount--;
165 if (att->Texture->RefCount == 0) {
166 ctx->Driver.DeleteTexture(ctx, att->Texture);
167 }
168 att->Texture = NULL;
169 }
170 else if (att->Type == GL_RENDERBUFFER_EXT) {
171 ASSERT(att->Renderbuffer);
172 ASSERT(!att->Texture);
173 att->Renderbuffer->RefCount--;
174 if (att->Renderbuffer->RefCount == 0) {
175 _mesa_free(att->Renderbuffer); /* XXX driver free */
176 }
177 att->Renderbuffer = NULL;
178 }
179 att->Type = GL_NONE;
180 }
181
182
183 static void
184 set_texture_attachment(GLcontext *ctx,
185 struct gl_render_buffer_attachment *att,
186 struct gl_texture_object *texObj,
187 GLenum texTarget, GLuint level, GLuint zoffset)
188 {
189 remove_attachment(ctx, att);
190 att->Type = GL_TEXTURE;
191 att->Texture = texObj;
192 att->TextureLevel = level;
193 if (IS_CUBE_FACE(texTarget)) {
194 att->CubeMapFace = texTarget - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
195 }
196 else {
197 att->CubeMapFace = 0;
198 }
199 att->Zoffset = zoffset;
200 texObj->RefCount++;
201 }
202
203
204 static void
205 set_renderbuffer_attachment(GLcontext *ctx,
206 struct gl_render_buffer_attachment *att,
207 struct gl_render_buffer_object *rb)
208 {
209 remove_attachment(ctx, att);
210 att->Type = GL_RENDERBUFFER_EXT;
211 att->Renderbuffer = rb;
212 rb->RefCount++;
213 }
214
215
216 GLboolean GLAPIENTRY
217 _mesa_IsRenderbufferEXT(GLuint renderbuffer)
218 {
219 struct gl_render_buffer_object *rb;
220 GET_CURRENT_CONTEXT(ctx);
221
222 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
223
224 rb = lookup_renderbuffer(ctx, renderbuffer);
225 return rb ? GL_TRUE : GL_FALSE;
226 }
227
228
229 void GLAPIENTRY
230 _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
231 {
232 struct gl_render_buffer_object *newRb, *oldRb;
233 GET_CURRENT_CONTEXT(ctx);
234
235 ASSERT_OUTSIDE_BEGIN_END(ctx);
236
237 if (target != GL_RENDERBUFFER_EXT) {
238 _mesa_error(ctx, GL_INVALID_ENUM,
239 "glBindRenderbufferEXT(target)");
240 return;
241 }
242
243 if (renderbuffer) {
244 newRb = lookup_renderbuffer(ctx, renderbuffer);
245 if (newRb == &DummyRenderbuffer) {
246 /* ID was reserved, but no real renderbuffer object made yet */
247 newRb = NULL;
248 }
249 if (!newRb) {
250 /* create new renderbuffer object */
251 newRb = new_renderbuffer(ctx, renderbuffer);
252 if (!newRb) {
253 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
254 return;
255 }
256 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
257 }
258 newRb->RefCount++;
259 }
260 else {
261 newRb = NULL;
262 }
263
264 oldRb = ctx->CurrentRenderbuffer;
265 if (oldRb) {
266 oldRb->RefCount--;
267 if (oldRb->RefCount == 0) {
268 _mesa_free(oldRb); /* XXX device driver function */
269 }
270 }
271
272 ASSERT(newRb != &DummyRenderbuffer);
273
274 ctx->CurrentRenderbuffer = newRb;
275 }
276
277
278 void GLAPIENTRY
279 _mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
280 {
281 GLint i;
282 GET_CURRENT_CONTEXT(ctx);
283
284 ASSERT_OUTSIDE_BEGIN_END(ctx);
285
286 for (i = 0; i < n; i++) {
287 if (renderbuffers[i]) {
288 struct gl_render_buffer_object *rb;
289 rb = lookup_renderbuffer(ctx, renderbuffers[i]);
290 if (rb) {
291 /* remove from hash table immediately, to free the ID */
292 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
293
294 if (rb != &DummyRenderbuffer) {
295 /* But the object will not be freed until it's no longer
296 * bound in any context.
297 */
298 rb->RefCount--;
299 if (rb->RefCount == 0) {
300 _mesa_free(rb); /* XXX call device driver function */
301 }
302 }
303 }
304 }
305 }
306 }
307
308
309 void GLAPIENTRY
310 _mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
311 {
312 GET_CURRENT_CONTEXT(ctx);
313 GLuint first;
314 GLint i;
315
316 ASSERT_OUTSIDE_BEGIN_END(ctx);
317
318 if (n < 0) {
319 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
320 return;
321 }
322
323 if (!renderbuffers)
324 return;
325
326 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
327
328 for (i = 0; i < n; i++) {
329 GLuint name = first + i;
330
331 /* insert dummy placeholder into hash table */
332 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
333 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
334 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
335
336 renderbuffers[i] = name;
337 }
338 }
339
340
341 static GLenum
342 base_internal_format(GLcontext *ctx, GLenum internalFormat)
343 {
344 switch (internalFormat) {
345 /*case GL_ALPHA:*/
346 case GL_ALPHA4:
347 case GL_ALPHA8:
348 case GL_ALPHA12:
349 case GL_ALPHA16:
350 return GL_ALPHA;
351 /*case GL_LUMINANCE:*/
352 case GL_LUMINANCE4:
353 case GL_LUMINANCE8:
354 case GL_LUMINANCE12:
355 case GL_LUMINANCE16:
356 return GL_LUMINANCE;
357 /*case GL_LUMINANCE_ALPHA:*/
358 case GL_LUMINANCE4_ALPHA4:
359 case GL_LUMINANCE6_ALPHA2:
360 case GL_LUMINANCE8_ALPHA8:
361 case GL_LUMINANCE12_ALPHA4:
362 case GL_LUMINANCE12_ALPHA12:
363 case GL_LUMINANCE16_ALPHA16:
364 return GL_LUMINANCE_ALPHA;
365 /*case GL_INTENSITY:*/
366 case GL_INTENSITY4:
367 case GL_INTENSITY8:
368 case GL_INTENSITY12:
369 case GL_INTENSITY16:
370 return GL_INTENSITY;
371 /*case GL_RGB:*/
372 case GL_R3_G3_B2:
373 case GL_RGB4:
374 case GL_RGB5:
375 case GL_RGB8:
376 case GL_RGB10:
377 case GL_RGB12:
378 case GL_RGB16:
379 return GL_RGB;
380 /*case GL_RGBA:*/
381 case GL_RGBA2:
382 case GL_RGBA4:
383 case GL_RGB5_A1:
384 case GL_RGBA8:
385 case GL_RGB10_A2:
386 case GL_RGBA12:
387 case GL_RGBA16:
388 return GL_RGBA;
389 case GL_STENCIL_INDEX1_EXT:
390 case GL_STENCIL_INDEX4_EXT:
391 case GL_STENCIL_INDEX8_EXT:
392 case GL_STENCIL_INDEX16_EXT:
393 return GL_STENCIL_INDEX;
394 default:
395 ; /* fallthrough */
396 }
397
398 if (ctx->Extensions.SGIX_depth_texture) {
399 switch (internalFormat) {
400 /*case GL_DEPTH_COMPONENT:*/
401 case GL_DEPTH_COMPONENT16_SGIX:
402 case GL_DEPTH_COMPONENT24_SGIX:
403 case GL_DEPTH_COMPONENT32_SGIX:
404 return GL_DEPTH_COMPONENT;
405 default:
406 ; /* fallthrough */
407 }
408 }
409
410 return 0;
411 }
412
413
414 void GLAPIENTRY
415 _mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
416 GLsizei width, GLsizei height)
417 {
418 GLenum baseFormat;
419 GET_CURRENT_CONTEXT(ctx);
420
421 ASSERT_OUTSIDE_BEGIN_END(ctx);
422
423 if (target != GL_RENDERBUFFER_EXT) {
424 _mesa_error(ctx, GL_INVALID_ENUM, "glRenderbufferStorageEXT(target)");
425 return;
426 }
427
428 baseFormat = base_internal_format(ctx, internalFormat);
429 if (baseFormat == 0) {
430 _mesa_error(ctx, GL_INVALID_ENUM,
431 "glRenderbufferStorageEXT(internalFormat)");
432 return;
433 }
434
435 if (width < 1 || width > ctx->Const.MaxRenderbufferSize) {
436 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(width)");
437 return;
438 }
439
440 if (height < 1 || height > ctx->Const.MaxRenderbufferSize) {
441 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(height)");
442 return;
443 }
444
445 /* XXX this check isn't in the spec, but seems necessary */
446 if (!ctx->CurrentRenderbuffer) {
447 _mesa_error(ctx, GL_INVALID_OPERATION, "glRenderbufferStorageEXT");
448 return;
449 }
450
451 if (ctx->CurrentRenderbuffer->Data) {
452 /* XXX device driver free */
453 _mesa_free(ctx->CurrentRenderbuffer->Data);
454 }
455
456 /* XXX device driver allocate, fix size */
457 ctx->CurrentRenderbuffer->Data = _mesa_malloc(width * height * 4);
458 if (ctx->CurrentRenderbuffer->Data == NULL) {
459 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glRenderbufferStorageEXT");
460 return;
461 }
462 ctx->CurrentRenderbuffer->InternalFormat = internalFormat;
463 ctx->CurrentRenderbuffer->Width = width;
464 ctx->CurrentRenderbuffer->Height = height;
465 }
466
467
468 void GLAPIENTRY
469 _mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
470 {
471 GET_CURRENT_CONTEXT(ctx);
472
473 ASSERT_OUTSIDE_BEGIN_END(ctx);
474
475 if (target != GL_RENDERBUFFER_EXT) {
476 _mesa_error(ctx, GL_INVALID_ENUM,
477 "glGetRenderbufferParameterivEXT(target)");
478 return;
479 }
480
481 if (!ctx->CurrentRenderbuffer) {
482 _mesa_error(ctx, GL_INVALID_OPERATION,
483 "glGetRenderbufferParameterivEXT");
484 return;
485 }
486
487 switch (pname) {
488 case GL_RENDERBUFFER_WIDTH_EXT:
489 *params = ctx->CurrentRenderbuffer->Width;
490 return;
491 case GL_RENDERBUFFER_HEIGHT_EXT:
492 *params = ctx->CurrentRenderbuffer->Height;
493 return;
494 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
495 *params = ctx->CurrentRenderbuffer->InternalFormat;
496 return;
497 default:
498 _mesa_error(ctx, GL_INVALID_ENUM,
499 "glGetRenderbufferParameterivEXT(target)");
500 return;
501 }
502 }
503
504
505 GLboolean GLAPIENTRY
506 _mesa_IsFramebufferEXT(GLuint framebuffer)
507 {
508 struct gl_frame_buffer_object *fb;
509 GET_CURRENT_CONTEXT(ctx);
510
511 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
512
513 fb = lookup_framebuffer(ctx, framebuffer);
514 return fb ? GL_TRUE : GL_FALSE;
515 }
516
517
518 void GLAPIENTRY
519 _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
520 {
521 struct gl_frame_buffer_object *newFb, *oldFb;
522 GET_CURRENT_CONTEXT(ctx);
523
524 ASSERT_OUTSIDE_BEGIN_END(ctx);
525
526 if (target != GL_FRAMEBUFFER_EXT) {
527 _mesa_error(ctx, GL_INVALID_ENUM,
528 "glBindFramebufferEXT(target)");
529 return;
530 }
531
532 if (framebuffer) {
533 newFb = lookup_framebuffer(ctx, framebuffer);
534 if (newFb == &DummyFramebuffer) {
535 /* ID was reserved, but no real framebuffer object made yet */
536 newFb = NULL;
537 }
538 if (!newFb) {
539 /* create new framebuffer object */
540 newFb = new_framebuffer(ctx, framebuffer);
541 if (!newFb) {
542 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
543 return;
544 }
545 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb);
546 }
547 newFb->RefCount++;
548 }
549 else {
550 newFb = NULL;
551 }
552
553 oldFb = ctx->CurrentFramebuffer;
554 if (oldFb) {
555 oldFb->RefCount--;
556 if (oldFb->RefCount == 0) {
557 _mesa_free(oldFb); /* XXX device driver function */
558 }
559 }
560
561 ASSERT(newFb != &DummyFramebuffer);
562
563 ctx->CurrentFramebuffer = newFb;
564 }
565
566
567 void GLAPIENTRY
568 _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
569 {
570 GLint i;
571 GET_CURRENT_CONTEXT(ctx);
572
573 ASSERT_OUTSIDE_BEGIN_END(ctx);
574
575 for (i = 0; i < n; i++) {
576 if (framebuffers[i]) {
577 struct gl_frame_buffer_object *fb;
578 fb = lookup_framebuffer(ctx, framebuffers[i]);
579 if (fb) {
580 /* remove from hash table immediately, to free the ID */
581 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
582
583 if (fb != &DummyFramebuffer) {
584 /* But the object will not be freed until it's no longer
585 * bound in any context.
586 */
587 fb->RefCount--;
588 if (fb->RefCount == 0) {
589 _mesa_free(fb); /* XXX call device driver function */
590 }
591 }
592 }
593 }
594 }
595 }
596
597
598 void GLAPIENTRY
599 _mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
600 {
601 GET_CURRENT_CONTEXT(ctx);
602 GLuint first;
603 GLint i;
604
605 ASSERT_OUTSIDE_BEGIN_END(ctx);
606
607 if (n < 0) {
608 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
609 return;
610 }
611
612 if (!framebuffers)
613 return;
614
615 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
616
617 for (i = 0; i < n; i++) {
618 GLuint name = first + i;
619
620 /* insert into hash table */
621 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
622 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
623 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
624
625 framebuffers[i] = name;
626 }
627 }
628
629
630
631 GLenum GLAPIENTRY
632 _mesa_CheckFramebufferStatusEXT(GLenum target)
633 {
634 GET_CURRENT_CONTEXT(ctx);
635
636 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FRAMEBUFFER_STATUS_ERROR_EXT);
637
638 if (target != GL_FRAMEBUFFER_EXT) {
639 _mesa_error(ctx, GL_INVALID_ENUM,
640 "glCheckFramebufferStatus(target)");
641 return GL_FRAMEBUFFER_STATUS_ERROR_EXT;
642 }
643
644 /* return one of:
645 GL_FRAMEBUFFER_COMPLETE_EXT
646 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT
647 GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT
648 GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
649 GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT
650 GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT
651 GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT
652 GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT
653 GL_FRAMEBUFFER_UNSUPPORTED_EXT
654 GL_FRAMEBUFFER_STATUS_ERROR_EXT
655 */
656 return GL_FRAMEBUFFER_STATUS_ERROR_EXT;
657 }
658
659
660
661 /**
662 * Do error checking common to glFramebufferTexture1D/2D/3DEXT.
663 * \return GL_TRUE if any error, GL_FALSE otherwise
664 */
665 static GLboolean
666 error_check_framebuffer_texture(GLcontext *ctx, GLuint dims,
667 GLenum target, GLenum attachment,
668 GLenum textarget, GLuint texture, GLint level)
669 {
670 ASSERT(dims >= 1 && dims <= 3);
671
672 if (target != GL_FRAMEBUFFER_EXT) {
673 _mesa_error(ctx, GL_INVALID_ENUM,
674 "glFramebufferTexture%dDEXT(target)", dims);
675 return GL_TRUE;
676 }
677
678 if (ctx->CurrentFramebuffer == NULL) {
679 _mesa_error(ctx, GL_INVALID_OPERATION,
680 "glFramebufferTexture%dDEXT", dims);
681 return GL_TRUE;
682 }
683
684 /* only check textarget, level if texture ID is non-zero*/
685 if (texture) {
686 if ((dims == 1 && textarget != GL_TEXTURE_1D) ||
687 (dims == 3 && textarget != GL_TEXTURE_3D) ||
688 (dims == 2 && textarget != GL_TEXTURE_2D &&
689 textarget != GL_TEXTURE_RECTANGLE_ARB &&
690 !IS_CUBE_FACE(textarget))) {
691 _mesa_error(ctx, GL_INVALID_VALUE,
692 "glFramebufferTexture%dDEXT(textarget)", dims);
693 return GL_TRUE;
694 }
695
696 if ((level < 0) || level >= _mesa_max_texture_levels(ctx, textarget)) {
697 _mesa_error(ctx, GL_INVALID_VALUE,
698 "glFramebufferTexture%dDEXT(level)", dims);
699 return GL_TRUE;
700 }
701 }
702
703 return GL_FALSE;
704 }
705
706
707 void GLAPIENTRY
708 _mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
709 GLenum textarget, GLuint texture, GLint level)
710 {
711 struct gl_render_buffer_attachment *att;
712 GET_CURRENT_CONTEXT(ctx);
713
714 ASSERT_OUTSIDE_BEGIN_END(ctx);
715
716 if (error_check_framebuffer_texture(ctx, 1, target, attachment,
717 textarget, texture, level))
718 return;
719
720 ASSERT(textarget == GL_TEXTURE_1D);
721
722 att = get_attachment(ctx, attachment);
723 if (att == NULL) {
724 _mesa_error(ctx, GL_INVALID_ENUM,
725 "glFramebufferTexture1DEXT(attachment)");
726 return;
727 }
728
729 if (texture) {
730 struct gl_texture_object *texObj = (struct gl_texture_object *)
731 _mesa_HashLookup(ctx->Shared->TexObjects, texture);
732 if (!texObj) {
733 _mesa_error(ctx, GL_INVALID_VALUE,
734 "glFramebufferTexture1DEXT(texture)");
735 return;
736 }
737 if (texObj->Target != textarget) {
738 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */
739 "glFramebufferTexture1DEXT(texture target)");
740 return;
741 }
742 set_texture_attachment(ctx, att, texObj, textarget, level, 0);
743 }
744 else {
745 remove_attachment(ctx, att);
746 }
747
748 /* XXX call a driver function to signal new attachment? */
749 }
750
751
752 void GLAPIENTRY
753 _mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
754 GLenum textarget, GLuint texture, GLint level)
755 {
756 struct gl_render_buffer_attachment *att;
757 GET_CURRENT_CONTEXT(ctx);
758
759 ASSERT_OUTSIDE_BEGIN_END(ctx);
760
761 if (error_check_framebuffer_texture(ctx, 2, target, attachment,
762 textarget, texture, level))
763 return;
764
765 ASSERT(textarget == GL_TEXTURE_2D ||
766 textarget == GL_TEXTURE_RECTANGLE_ARB ||
767 IS_CUBE_FACE(textarget));
768
769 att = get_attachment(ctx, attachment);
770 if (att == NULL) {
771 _mesa_error(ctx, GL_INVALID_ENUM,
772 "glFramebufferTexture2DEXT(attachment)");
773 return;
774 }
775
776 if (texture) {
777 struct gl_texture_object *texObj = (struct gl_texture_object *)
778 _mesa_HashLookup(ctx->Shared->TexObjects, texture);
779 if (!texObj) {
780 _mesa_error(ctx, GL_INVALID_VALUE,
781 "glFramebufferTexture2DEXT(texture)");
782 return;
783 }
784 if ((texObj->Target == GL_TEXTURE_2D && textarget != GL_TEXTURE_2D) ||
785 (texObj->Target == GL_TEXTURE_RECTANGLE_ARB
786 && textarget != GL_TEXTURE_RECTANGLE_ARB) ||
787 (texObj->Target == GL_TEXTURE_CUBE_MAP
788 && !IS_CUBE_FACE(textarget))) {
789 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */
790 "glFramebufferTexture2DEXT(texture target)");
791 return;
792 }
793 set_texture_attachment(ctx, att, texObj, textarget, level, 0);
794 }
795 else {
796 remove_attachment(ctx, att);
797 }
798
799 }
800
801
802 void GLAPIENTRY
803 _mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
804 GLenum textarget, GLuint texture,
805 GLint level, GLint zoffset)
806 {
807 struct gl_render_buffer_attachment *att;
808 GET_CURRENT_CONTEXT(ctx);
809
810 ASSERT_OUTSIDE_BEGIN_END(ctx);
811
812 if (error_check_framebuffer_texture(ctx, 3, target, attachment,
813 textarget, texture, level))
814 return;
815
816 ASSERT(textarget == GL_TEXTURE_3D);
817
818 att = get_attachment(ctx, attachment);
819 if (att == NULL) {
820 _mesa_error(ctx, GL_INVALID_ENUM,
821 "glFramebufferTexture1DEXT(attachment)");
822 return;
823 }
824
825 if (texture) {
826 struct gl_texture_object *texObj = (struct gl_texture_object *)
827 _mesa_HashLookup(ctx->Shared->TexObjects, texture);
828 if (!texObj) {
829 _mesa_error(ctx, GL_INVALID_VALUE,
830 "glFramebufferTexture3DEXT(texture)");
831 return;
832 }
833 if (texObj->Target != textarget) {
834 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */
835 "glFramebufferTexture3DEXT(texture target)");
836 return;
837 }
838 if (zoffset >= texObj->Image[0][level]->Depth) {
839 _mesa_error(ctx, GL_INVALID_VALUE,
840 "glFramebufferTexture3DEXT(zoffset)");
841 return;
842 }
843 set_texture_attachment(ctx, att, texObj, textarget, level, zoffset);
844 }
845 else {
846 remove_attachment(ctx, att);
847 }
848 }
849
850
851 void GLAPIENTRY
852 _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
853 GLenum renderbufferTarget,
854 GLuint renderbuffer)
855 {
856 struct gl_render_buffer_attachment *att;
857 GET_CURRENT_CONTEXT(ctx);
858
859 ASSERT_OUTSIDE_BEGIN_END(ctx);
860
861 if (target != GL_FRAMEBUFFER_EXT) {
862 _mesa_error(ctx, GL_INVALID_ENUM,
863 "glFramebufferRenderbufferEXT(target)");
864 return;
865 }
866
867 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
868 _mesa_error(ctx, GL_INVALID_ENUM,
869 "glFramebufferRenderbufferEXT(renderbufferTarget)");
870 return;
871 }
872
873 if (ctx->CurrentFramebuffer == NULL) {
874 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
875 return;
876 }
877
878 att = get_attachment(ctx, attachment);
879 if (att == NULL) {
880 _mesa_error(ctx, GL_INVALID_ENUM,
881 "glFramebufferRenderbufferEXT(attachment)");
882 return;
883 }
884
885 if (renderbuffer) {
886 struct gl_render_buffer_object *rb;
887 rb = lookup_renderbuffer(ctx, renderbuffer);
888 if (!rb) {
889 _mesa_error(ctx, GL_INVALID_VALUE,
890 "glFramebufferRenderbufferEXT(renderbuffer)");
891 return;
892 }
893 set_renderbuffer_attachment(ctx, att, rb);
894 }
895 else {
896 remove_attachment(ctx, att);
897 }
898 }
899
900
901 void GLAPIENTRY
902 _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
903 GLenum pname, GLint *params)
904 {
905 const struct gl_render_buffer_attachment *att;
906 GET_CURRENT_CONTEXT(ctx);
907
908 ASSERT_OUTSIDE_BEGIN_END(ctx);
909
910 if (target != GL_FRAMEBUFFER_EXT) {
911 _mesa_error(ctx, GL_INVALID_ENUM,
912 "glGetFramebufferAttachmentParameterivEXT(target)");
913 return;
914 }
915
916 if (ctx->CurrentFramebuffer == NULL) {
917 _mesa_error(ctx, GL_INVALID_OPERATION,
918 "glGetFramebufferAttachmentParameterivEXT");
919 return;
920 }
921
922 att = get_attachment(ctx, attachment);
923 if (att == NULL) {
924 _mesa_error(ctx, GL_INVALID_ENUM,
925 "glGetFramebufferAttachmentParameterivEXT(attachment)");
926 return;
927 }
928
929 switch (pname) {
930 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
931 *params = att->Type;
932 return;
933 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
934 if (att->Type == GL_RENDERBUFFER_EXT) {
935 *params = att->Renderbuffer->Name;
936 }
937 else if (att->Type == GL_TEXTURE) {
938 *params = att->Texture->Name;
939 }
940 else {
941 _mesa_error(ctx, GL_INVALID_ENUM,
942 "glGetFramebufferAttachmentParameterivEXT(pname)");
943 }
944 return;
945 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
946 if (att->Type == GL_TEXTURE) {
947 *params = att->TextureLevel;
948 }
949 else {
950 _mesa_error(ctx, GL_INVALID_ENUM,
951 "glGetFramebufferAttachmentParameterivEXT(pname)");
952 }
953 return;
954 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
955 if (att->Type == GL_TEXTURE) {
956 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
957 }
958 else {
959 _mesa_error(ctx, GL_INVALID_ENUM,
960 "glGetFramebufferAttachmentParameterivEXT(pname)");
961 }
962 return;
963 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
964 if (att->Type == GL_TEXTURE) {
965 *params = att->Zoffset;
966 }
967 else {
968 _mesa_error(ctx, GL_INVALID_ENUM,
969 "glGetFramebufferAttachmentParameterivEXT(pname)");
970 }
971 return;
972 default:
973 _mesa_error(ctx, GL_INVALID_ENUM,
974 "glGetFramebufferAttachmentParameterivEXT(pname)");
975 return;
976 }
977 }
978
979
980 void GLAPIENTRY
981 _mesa_GenerateMipmapEXT(GLenum target)
982 {
983 struct gl_texture_unit *texUnit;
984 struct gl_texture_object *texObj;
985 GET_CURRENT_CONTEXT(ctx);
986
987 ASSERT_OUTSIDE_BEGIN_END(ctx);
988
989 switch (target) {
990 case GL_TEXTURE_1D:
991 case GL_TEXTURE_2D:
992 case GL_TEXTURE_3D:
993 case GL_TEXTURE_CUBE_MAP:
994 break;
995 default:
996 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
997 return;
998 }
999
1000 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1001 texObj = _mesa_select_tex_object(ctx, texUnit, target);
1002
1003 /* XXX this might not handle cube maps correctly */
1004 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
1005 }