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