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