a bunch of assorted fixes
[profile/ivi/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 }