diff options
author | marha <marha@users.sourceforge.net> | 2011-02-20 14:23:37 +0000 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2011-02-20 14:23:37 +0000 |
commit | 684eb992146cad24b690073f33b909f47150b841 (patch) | |
tree | 7bc62d6f06c5e8a8114b56fa78485cb7ec08f26b /mesalib/src/mesa/main | |
parent | 53810445215dc45ae303bc89feb6e0aaf04aa6fa (diff) | |
parent | 8a191c08ddda2e66fa26f148d6c21959bb08f923 (diff) | |
download | vcxsrv-684eb992146cad24b690073f33b909f47150b841.tar.gz vcxsrv-684eb992146cad24b690073f33b909f47150b841.tar.bz2 vcxsrv-684eb992146cad24b690073f33b909f47150b841.zip |
svn merge ^/branches/released .
Diffstat (limited to 'mesalib/src/mesa/main')
-rw-r--r-- | mesalib/src/mesa/main/debug.c | 1222 | ||||
-rw-r--r-- | mesalib/src/mesa/main/debug.h | 3 | ||||
-rw-r--r-- | mesalib/src/mesa/main/drawpix.c | 23 | ||||
-rw-r--r-- | mesalib/src/mesa/main/enable.c | 3005 | ||||
-rw-r--r-- | mesalib/src/mesa/main/fbobject.c | 4981 | ||||
-rw-r--r-- | mesalib/src/mesa/main/formats.c | 6 | ||||
-rw-r--r-- | mesalib/src/mesa/main/formats.h | 3 | ||||
-rw-r--r-- | mesalib/src/mesa/main/image.c | 7 | ||||
-rw-r--r-- | mesalib/src/mesa/main/imports.c | 2 | ||||
-rw-r--r-- | mesalib/src/mesa/main/mipmap.c | 52 | ||||
-rw-r--r-- | mesalib/src/mesa/main/mtypes.h | 3 | ||||
-rw-r--r-- | mesalib/src/mesa/main/readpix.c | 8 | ||||
-rw-r--r-- | mesalib/src/mesa/main/texgetimage.c | 4 |
13 files changed, 4706 insertions, 4613 deletions
diff --git a/mesalib/src/mesa/main/debug.c b/mesalib/src/mesa/main/debug.c index c1118504f..e336b077e 100644 --- a/mesalib/src/mesa/main/debug.c +++ b/mesalib/src/mesa/main/debug.c @@ -1,612 +1,610 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. - * Copyright (C) 2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "mtypes.h" -#include "attrib.h" -#include "colormac.h" -#include "enums.h" -#include "formats.h" -#include "hash.h" -#include "imports.h" -#include "debug.h" -#include "get.h" -#include "pixelstore.h" -#include "readpix.h" -#include "texobj.h" - - -static const char * -tex_target_name(GLenum tgt) -{ - static const struct { - GLenum target; - const char *name; - } tex_targets[] = { - { GL_TEXTURE_1D, "GL_TEXTURE_1D" }, - { GL_TEXTURE_2D, "GL_TEXTURE_2D" }, - { GL_TEXTURE_3D, "GL_TEXTURE_3D" }, - { GL_TEXTURE_CUBE_MAP, "GL_TEXTURE_CUBE_MAP" }, - { GL_TEXTURE_RECTANGLE, "GL_TEXTURE_RECTANGLE" }, - { GL_TEXTURE_1D_ARRAY_EXT, "GL_TEXTURE_1D_ARRAY" }, - { GL_TEXTURE_2D_ARRAY_EXT, "GL_TEXTURE_2D_ARRAY" } - }; - GLuint i; - for (i = 0; i < Elements(tex_targets); i++) { - if (tex_targets[i].target == tgt) - return tex_targets[i].name; - } - return "UNKNOWN TEX TARGET"; -} - - -void -_mesa_print_state( const char *msg, GLuint state ) -{ - _mesa_debug(NULL, - "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", - msg, - state, - (state & _NEW_MODELVIEW) ? "ctx->ModelView, " : "", - (state & _NEW_PROJECTION) ? "ctx->Projection, " : "", - (state & _NEW_TEXTURE_MATRIX) ? "ctx->TextureMatrix, " : "", - (state & _NEW_COLOR) ? "ctx->Color, " : "", - (state & _NEW_DEPTH) ? "ctx->Depth, " : "", - (state & _NEW_EVAL) ? "ctx->Eval/EvalMap, " : "", - (state & _NEW_FOG) ? "ctx->Fog, " : "", - (state & _NEW_HINT) ? "ctx->Hint, " : "", - (state & _NEW_LIGHT) ? "ctx->Light, " : "", - (state & _NEW_LINE) ? "ctx->Line, " : "", - (state & _NEW_PIXEL) ? "ctx->Pixel, " : "", - (state & _NEW_POINT) ? "ctx->Point, " : "", - (state & _NEW_POLYGON) ? "ctx->Polygon, " : "", - (state & _NEW_POLYGONSTIPPLE) ? "ctx->PolygonStipple, " : "", - (state & _NEW_SCISSOR) ? "ctx->Scissor, " : "", - (state & _NEW_STENCIL) ? "ctx->Stencil, " : "", - (state & _NEW_TEXTURE) ? "ctx->Texture, " : "", - (state & _NEW_TRANSFORM) ? "ctx->Transform, " : "", - (state & _NEW_VIEWPORT) ? "ctx->Viewport, " : "", - (state & _NEW_PACKUNPACK) ? "ctx->Pack/Unpack, " : "", - (state & _NEW_ARRAY) ? "ctx->Array, " : "", - (state & _NEW_RENDERMODE) ? "ctx->RenderMode, " : "", - (state & _NEW_BUFFERS) ? "ctx->Visual, ctx->DrawBuffer,, " : ""); -} - - - -void -_mesa_print_tri_caps( const char *name, GLuint flags ) -{ - _mesa_debug(NULL, - "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s\n", - name, - flags, - (flags & DD_FLATSHADE) ? "flat-shade, " : "", - (flags & DD_SEPARATE_SPECULAR) ? "separate-specular, " : "", - (flags & DD_TRI_LIGHT_TWOSIDE) ? "tri-light-twoside, " : "", - (flags & DD_TRI_TWOSTENCIL) ? "tri-twostencil, " : "", - (flags & DD_TRI_UNFILLED) ? "tri-unfilled, " : "", - (flags & DD_TRI_STIPPLE) ? "tri-stipple, " : "", - (flags & DD_TRI_OFFSET) ? "tri-offset, " : "", - (flags & DD_TRI_SMOOTH) ? "tri-smooth, " : "", - (flags & DD_LINE_SMOOTH) ? "line-smooth, " : "", - (flags & DD_LINE_STIPPLE) ? "line-stipple, " : "", - (flags & DD_POINT_SMOOTH) ? "point-smooth, " : "", - (flags & DD_POINT_ATTEN) ? "point-atten, " : "", - (flags & DD_TRI_CULL_FRONT_BACK) ? "cull-all, " : "" - ); -} - - -/** - * Print information about this Mesa version and build options. - */ -void _mesa_print_info( void ) -{ - _mesa_debug(NULL, "Mesa GL_VERSION = %s\n", - (char *) _mesa_GetString(GL_VERSION)); - _mesa_debug(NULL, "Mesa GL_RENDERER = %s\n", - (char *) _mesa_GetString(GL_RENDERER)); - _mesa_debug(NULL, "Mesa GL_VENDOR = %s\n", - (char *) _mesa_GetString(GL_VENDOR)); - _mesa_debug(NULL, "Mesa GL_EXTENSIONS = %s\n", - (char *) _mesa_GetString(GL_EXTENSIONS)); -#if defined(THREADS) - _mesa_debug(NULL, "Mesa thread-safe: YES\n"); -#else - _mesa_debug(NULL, "Mesa thread-safe: NO\n"); -#endif -#if defined(USE_X86_ASM) - _mesa_debug(NULL, "Mesa x86-optimized: YES\n"); -#else - _mesa_debug(NULL, "Mesa x86-optimized: NO\n"); -#endif -#if defined(USE_SPARC_ASM) - _mesa_debug(NULL, "Mesa sparc-optimized: YES\n"); -#else - _mesa_debug(NULL, "Mesa sparc-optimized: NO\n"); -#endif -} - - -/** - * Set the debugging flags. - * - * \param debug debug string - * - * If compiled with debugging support then search for keywords in \p debug and - * enables the verbose debug output of the respective feature. - */ -static void add_debug_flags( const char *debug ) -{ -#ifdef DEBUG - struct debug_option { - const char *name; - GLbitfield flag; - }; - static const struct debug_option debug_opt[] = { - { "varray", VERBOSE_VARRAY }, - { "tex", VERBOSE_TEXTURE }, - { "mat", VERBOSE_MATERIAL }, - { "pipe", VERBOSE_PIPELINE }, - { "driver", VERBOSE_DRIVER }, - { "state", VERBOSE_STATE }, - { "api", VERBOSE_API }, - { "list", VERBOSE_DISPLAY_LIST }, - { "lighting", VERBOSE_LIGHTING }, - { "disassem", VERBOSE_DISASSEM }, - { "draw", VERBOSE_DRAW }, - { "swap", VERBOSE_SWAPBUFFERS } - }; - GLuint i; - - MESA_VERBOSE = 0x0; - for (i = 0; i < Elements(debug_opt); i++) { - if (strstr(debug, debug_opt[i].name)) - MESA_VERBOSE |= debug_opt[i].flag; - } - - /* Debug flag: - */ - if (strstr(debug, "flush")) - MESA_DEBUG_FLAGS |= DEBUG_ALWAYS_FLUSH; - -#if defined(_FPU_GETCW) && defined(_FPU_SETCW) - if (strstr(debug, "fpexceptions")) { - /* raise FP exceptions */ - fpu_control_t mask; - _FPU_GETCW(mask); - mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM - | _FPU_MASK_OM | _FPU_MASK_UM); - _FPU_SETCW(mask); - } -#endif - -#else - (void) debug; -#endif -} - - -void -_mesa_init_debug( struct gl_context *ctx ) -{ - char *c; - - /* Dither disable */ - ctx->NoDither = _mesa_getenv("MESA_NO_DITHER") ? GL_TRUE : GL_FALSE; - if (ctx->NoDither) { - if (_mesa_getenv("MESA_DEBUG")) { - _mesa_debug(ctx, "MESA_NO_DITHER set - dithering disabled\n"); - } - ctx->Color.DitherFlag = GL_FALSE; - } - - c = _mesa_getenv("MESA_DEBUG"); - if (c) - add_debug_flags(c); - - c = _mesa_getenv("MESA_VERBOSE"); - if (c) - add_debug_flags(c); -} - - -/* - * Write ppm file - */ -static void -write_ppm(const char *filename, const GLubyte *buffer, int width, int height, - int comps, int rcomp, int gcomp, int bcomp, GLboolean invert) -{ - FILE *f = fopen( filename, "w" ); - if (f) { - int x, y; - const GLubyte *ptr = buffer; - fprintf(f,"P6\n"); - fprintf(f,"# ppm-file created by osdemo.c\n"); - fprintf(f,"%i %i\n", width,height); - fprintf(f,"255\n"); - fclose(f); - f = fopen( filename, "ab" ); /* reopen in binary append mode */ - for (y=0; y < height; y++) { - for (x = 0; x < width; x++) { - int yy = invert ? (height - 1 - y) : y; - int i = (yy * width + x) * comps; - fputc(ptr[i+rcomp], f); /* write red */ - fputc(ptr[i+gcomp], f); /* write green */ - fputc(ptr[i+bcomp], f); /* write blue */ - } - } - fclose(f); - } -} - - -/** - * Write a texture image to a ppm file. - * \param face cube face in [0,5] - * \param level mipmap level - */ -static void -write_texture_image(struct gl_texture_object *texObj, - GLuint face, GLuint level) -{ - struct gl_texture_image *img = texObj->Image[face][level]; - if (img) { - GET_CURRENT_CONTEXT(ctx); - struct gl_pixelstore_attrib store; - GLubyte *buffer; - char s[100]; - - buffer = (GLubyte *) malloc(img->Width * img->Height - * img->Depth * 4); - - store = ctx->Pack; /* save */ - ctx->Pack = ctx->DefaultPacking; - - ctx->Driver.GetTexImage(ctx, texObj->Target, level, - GL_RGBA, GL_UNSIGNED_BYTE, - buffer, texObj, img); - - /* make filename */ - _mesa_snprintf(s, sizeof(s), "/tmp/tex%u.l%u.f%u.ppm", texObj->Name, level, face); - - printf(" Writing image level %u to %s\n", level, s); - write_ppm(s, buffer, img->Width, img->Height, 4, 0, 1, 2, GL_FALSE); - - ctx->Pack = store; /* restore */ - - free(buffer); - } -} - - -/** - * Write renderbuffer image to a ppm file. - */ -static void -write_renderbuffer_image(const struct gl_renderbuffer *rb) -{ - GET_CURRENT_CONTEXT(ctx); - GLubyte *buffer; - char s[100]; - GLenum format, type; - - if (rb->_BaseFormat == GL_RGB || - rb->_BaseFormat == GL_RGBA) { - format = GL_RGBA; - type = GL_UNSIGNED_BYTE; - } - else if (rb->_BaseFormat == GL_DEPTH_STENCIL) { - format = GL_DEPTH_STENCIL; - type = GL_UNSIGNED_INT_24_8; - } - else { - return; - } - - buffer = (GLubyte *) malloc(rb->Width * rb->Height * 4); - - ctx->Driver.ReadPixels(ctx, 0, 0, rb->Width, rb->Height, - format, type, &ctx->DefaultPacking, buffer); - - /* make filename */ - _mesa_snprintf(s, sizeof(s), "/tmp/renderbuffer%u.ppm", rb->Name); - - printf(" Writing renderbuffer image to %s\n", s); - write_ppm(s, buffer, rb->Width, rb->Height, 4, 0, 1, 2, GL_TRUE); - - free(buffer); -} - - -/** How many texture images (mipmap levels, faces) to write to files */ -#define WRITE_NONE 0 -#define WRITE_ONE 1 -#define WRITE_ALL 2 - -static GLuint WriteImages; - - -static void -dump_texture(struct gl_texture_object *texObj, GLuint writeImages) -{ - const GLuint numFaces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1; - GLboolean written = GL_FALSE; - GLuint i, j; - - printf("Texture %u\n", texObj->Name); - printf(" Target %s\n", tex_target_name(texObj->Target)); - for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { - for (j = 0; j < numFaces; j++) { - struct gl_texture_image *texImg = texObj->Image[j][i]; - if (texImg) { - printf(" Face %u level %u: %d x %d x %d, format %s at %p\n", - j, i, - texImg->Width, texImg->Height, texImg->Depth, - _mesa_get_format_name(texImg->TexFormat), - texImg->Data); - if (writeImages == WRITE_ALL || - (writeImages == WRITE_ONE && !written)) { - write_texture_image(texObj, j, i); - written = GL_TRUE; - } - } - } - } -} - - -/** - * Dump a single texture. - */ -void -_mesa_dump_texture(GLuint texture, GLuint writeImages) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, texture); - if (texObj) { - dump_texture(texObj, writeImages); - } -} - - -static void -dump_texture_cb(GLuint id, void *data, void *userData) -{ - struct gl_texture_object *texObj = (struct gl_texture_object *) data; - (void) userData; - dump_texture(texObj, WriteImages); -} - - -/** - * Print basic info about all texture objext to stdout. - * If dumpImages is true, write PPM of level[0] image to a file. - */ -void -_mesa_dump_textures(GLuint writeImages) -{ - GET_CURRENT_CONTEXT(ctx); - WriteImages = writeImages; - _mesa_HashWalk(ctx->Shared->TexObjects, dump_texture_cb, ctx); -} - - -static void -dump_renderbuffer(const struct gl_renderbuffer *rb, GLboolean writeImage) -{ - printf("Renderbuffer %u: %u x %u IntFormat = %s\n", - rb->Name, rb->Width, rb->Height, - _mesa_lookup_enum_by_nr(rb->InternalFormat)); - if (writeImage) { - write_renderbuffer_image(rb); - } -} - - -static void -dump_renderbuffer_cb(GLuint id, void *data, void *userData) -{ - const struct gl_renderbuffer *rb = (const struct gl_renderbuffer *) data; - (void) userData; - dump_renderbuffer(rb, WriteImages); -} - - -/** - * Print basic info about all renderbuffers to stdout. - * If dumpImages is true, write PPM of level[0] image to a file. - */ -void -_mesa_dump_renderbuffers(GLboolean writeImages) -{ - GET_CURRENT_CONTEXT(ctx); - WriteImages = writeImages; - _mesa_HashWalk(ctx->Shared->RenderBuffers, dump_renderbuffer_cb, ctx); -} - - - -void -_mesa_dump_color_buffer(const char *filename) -{ - GET_CURRENT_CONTEXT(ctx); - const GLuint w = ctx->DrawBuffer->Width; - const GLuint h = ctx->DrawBuffer->Height; - GLubyte *buf; - - buf = (GLubyte *) malloc(w * h * 4); - - _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); - _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1); - _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); - - _mesa_ReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buf); - - printf("ReadBuffer %p 0x%x DrawBuffer %p 0x%x\n", - (void *) ctx->ReadBuffer->_ColorReadBuffer, - ctx->ReadBuffer->ColorReadBuffer, - (void *) ctx->DrawBuffer->_ColorDrawBuffers[0], - ctx->DrawBuffer->ColorDrawBuffer[0]); - printf("Writing %d x %d color buffer to %s\n", w, h, filename); - write_ppm(filename, buf, w, h, 4, 0, 1, 2, GL_TRUE); - - _mesa_PopClientAttrib(); - - free(buf); -} - - -void -_mesa_dump_depth_buffer(const char *filename) -{ - GET_CURRENT_CONTEXT(ctx); - const GLuint w = ctx->DrawBuffer->Width; - const GLuint h = ctx->DrawBuffer->Height; - GLuint *buf; - GLubyte *buf2; - GLuint i; - - buf = (GLuint *) malloc(w * h * 4); /* 4 bpp */ - buf2 = (GLubyte *) malloc(w * h * 3); /* 3 bpp */ - - _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); - _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1); - _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); - - _mesa_ReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buf); - - /* spread 24 bits of Z across R, G, B */ - for (i = 0; i < w * h; i++) { - buf2[i*3+0] = (buf[i] >> 24) & 0xff; - buf2[i*3+1] = (buf[i] >> 16) & 0xff; - buf2[i*3+2] = (buf[i] >> 8) & 0xff; - } - - printf("Writing %d x %d depth buffer to %s\n", w, h, filename); - write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE); - - _mesa_PopClientAttrib(); - - free(buf); - free(buf2); -} - - -void -_mesa_dump_stencil_buffer(const char *filename) -{ - GET_CURRENT_CONTEXT(ctx); - const GLuint w = ctx->DrawBuffer->Width; - const GLuint h = ctx->DrawBuffer->Height; - GLubyte *buf; - GLubyte *buf2; - GLuint i; - - buf = (GLubyte *) malloc(w * h); /* 1 bpp */ - buf2 = (GLubyte *) malloc(w * h * 3); /* 3 bpp */ - - _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); - _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1); - _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); - - _mesa_ReadPixels(0, 0, w, h, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buf); - - for (i = 0; i < w * h; i++) { - buf2[i*3+0] = buf[i]; - buf2[i*3+1] = (buf[i] & 127) * 2; - buf2[i*3+2] = (buf[i] - 128) * 2; - } - - printf("Writing %d x %d stencil buffer to %s\n", w, h, filename); - write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE); - - _mesa_PopClientAttrib(); - - free(buf); - free(buf2); -} - - -/** - * Quick and dirty function to "print" a texture to stdout. - */ -void -_mesa_print_texture(struct gl_context *ctx, const struct gl_texture_image *img) -{ -#if CHAN_TYPE != GL_UNSIGNED_BYTE - _mesa_problem(NULL, "PrintTexture not supported"); -#else - GLuint i, j, c; - const GLubyte *data = (const GLubyte *) img->Data; - - if (!data) { - printf("No texture data\n"); - return; - } - - /* XXX add more formats or make into a new format utility function */ - switch (img->TexFormat) { - case MESA_FORMAT_A8: - case MESA_FORMAT_L8: - case MESA_FORMAT_I8: - case MESA_FORMAT_CI8: - c = 1; - break; - case MESA_FORMAT_AL88: - case MESA_FORMAT_AL88_REV: - c = 2; - break; - case MESA_FORMAT_RGB888: - case MESA_FORMAT_BGR888: - c = 3; - break; - case MESA_FORMAT_RGBA8888: - case MESA_FORMAT_ARGB8888: - c = 4; - break; - default: - _mesa_problem(NULL, "error in PrintTexture\n"); - return; - } - - for (i = 0; i < img->Height; i++) { - for (j = 0; j < img->Width; j++) { - if (c==1) - printf("%02x ", data[0]); - else if (c==2) - printf("%02x%02x ", data[0], data[1]); - else if (c==3) - printf("%02x%02x%02x ", data[0], data[1], data[2]); - else if (c==4) - printf("%02x%02x%02x%02x ", data[0], data[1], data[2], data[3]); - data += (img->RowStride - img->Width) * c; - } - /* XXX use img->ImageStride here */ - printf("\n"); - } -#endif -} +/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "mtypes.h"
+#include "attrib.h"
+#include "colormac.h"
+#include "enums.h"
+#include "formats.h"
+#include "hash.h"
+#include "imports.h"
+#include "debug.h"
+#include "get.h"
+#include "pixelstore.h"
+#include "readpix.h"
+#include "texobj.h"
+
+
+static const char *
+tex_target_name(GLenum tgt)
+{
+ static const struct {
+ GLenum target;
+ const char *name;
+ } tex_targets[] = {
+ { GL_TEXTURE_1D, "GL_TEXTURE_1D" },
+ { GL_TEXTURE_2D, "GL_TEXTURE_2D" },
+ { GL_TEXTURE_3D, "GL_TEXTURE_3D" },
+ { GL_TEXTURE_CUBE_MAP, "GL_TEXTURE_CUBE_MAP" },
+ { GL_TEXTURE_RECTANGLE, "GL_TEXTURE_RECTANGLE" },
+ { GL_TEXTURE_1D_ARRAY_EXT, "GL_TEXTURE_1D_ARRAY" },
+ { GL_TEXTURE_2D_ARRAY_EXT, "GL_TEXTURE_2D_ARRAY" }
+ };
+ GLuint i;
+ for (i = 0; i < Elements(tex_targets); i++) {
+ if (tex_targets[i].target == tgt)
+ return tex_targets[i].name;
+ }
+ return "UNKNOWN TEX TARGET";
+}
+
+
+void
+_mesa_print_state( const char *msg, GLuint state )
+{
+ _mesa_debug(NULL,
+ "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ msg,
+ state,
+ (state & _NEW_MODELVIEW) ? "ctx->ModelView, " : "",
+ (state & _NEW_PROJECTION) ? "ctx->Projection, " : "",
+ (state & _NEW_TEXTURE_MATRIX) ? "ctx->TextureMatrix, " : "",
+ (state & _NEW_COLOR) ? "ctx->Color, " : "",
+ (state & _NEW_DEPTH) ? "ctx->Depth, " : "",
+ (state & _NEW_EVAL) ? "ctx->Eval/EvalMap, " : "",
+ (state & _NEW_FOG) ? "ctx->Fog, " : "",
+ (state & _NEW_HINT) ? "ctx->Hint, " : "",
+ (state & _NEW_LIGHT) ? "ctx->Light, " : "",
+ (state & _NEW_LINE) ? "ctx->Line, " : "",
+ (state & _NEW_PIXEL) ? "ctx->Pixel, " : "",
+ (state & _NEW_POINT) ? "ctx->Point, " : "",
+ (state & _NEW_POLYGON) ? "ctx->Polygon, " : "",
+ (state & _NEW_POLYGONSTIPPLE) ? "ctx->PolygonStipple, " : "",
+ (state & _NEW_SCISSOR) ? "ctx->Scissor, " : "",
+ (state & _NEW_STENCIL) ? "ctx->Stencil, " : "",
+ (state & _NEW_TEXTURE) ? "ctx->Texture, " : "",
+ (state & _NEW_TRANSFORM) ? "ctx->Transform, " : "",
+ (state & _NEW_VIEWPORT) ? "ctx->Viewport, " : "",
+ (state & _NEW_PACKUNPACK) ? "ctx->Pack/Unpack, " : "",
+ (state & _NEW_ARRAY) ? "ctx->Array, " : "",
+ (state & _NEW_RENDERMODE) ? "ctx->RenderMode, " : "",
+ (state & _NEW_BUFFERS) ? "ctx->Visual, ctx->DrawBuffer,, " : "");
+}
+
+
+
+void
+_mesa_print_tri_caps( const char *name, GLuint flags )
+{
+ _mesa_debug(NULL,
+ "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ name,
+ flags,
+ (flags & DD_FLATSHADE) ? "flat-shade, " : "",
+ (flags & DD_SEPARATE_SPECULAR) ? "separate-specular, " : "",
+ (flags & DD_TRI_LIGHT_TWOSIDE) ? "tri-light-twoside, " : "",
+ (flags & DD_TRI_TWOSTENCIL) ? "tri-twostencil, " : "",
+ (flags & DD_TRI_UNFILLED) ? "tri-unfilled, " : "",
+ (flags & DD_TRI_STIPPLE) ? "tri-stipple, " : "",
+ (flags & DD_TRI_OFFSET) ? "tri-offset, " : "",
+ (flags & DD_TRI_SMOOTH) ? "tri-smooth, " : "",
+ (flags & DD_LINE_SMOOTH) ? "line-smooth, " : "",
+ (flags & DD_LINE_STIPPLE) ? "line-stipple, " : "",
+ (flags & DD_POINT_SMOOTH) ? "point-smooth, " : "",
+ (flags & DD_POINT_ATTEN) ? "point-atten, " : "",
+ (flags & DD_TRI_CULL_FRONT_BACK) ? "cull-all, " : ""
+ );
+}
+
+
+/**
+ * Print information about this Mesa version and build options.
+ */
+void _mesa_print_info( void )
+{
+ _mesa_debug(NULL, "Mesa GL_VERSION = %s\n",
+ (char *) _mesa_GetString(GL_VERSION));
+ _mesa_debug(NULL, "Mesa GL_RENDERER = %s\n",
+ (char *) _mesa_GetString(GL_RENDERER));
+ _mesa_debug(NULL, "Mesa GL_VENDOR = %s\n",
+ (char *) _mesa_GetString(GL_VENDOR));
+ _mesa_debug(NULL, "Mesa GL_EXTENSIONS = %s\n",
+ (char *) _mesa_GetString(GL_EXTENSIONS));
+#if defined(THREADS)
+ _mesa_debug(NULL, "Mesa thread-safe: YES\n");
+#else
+ _mesa_debug(NULL, "Mesa thread-safe: NO\n");
+#endif
+#if defined(USE_X86_ASM)
+ _mesa_debug(NULL, "Mesa x86-optimized: YES\n");
+#else
+ _mesa_debug(NULL, "Mesa x86-optimized: NO\n");
+#endif
+#if defined(USE_SPARC_ASM)
+ _mesa_debug(NULL, "Mesa sparc-optimized: YES\n");
+#else
+ _mesa_debug(NULL, "Mesa sparc-optimized: NO\n");
+#endif
+}
+
+
+/**
+ * Set the debugging flags.
+ *
+ * \param debug debug string
+ *
+ * If compiled with debugging support then search for keywords in \p debug and
+ * enables the verbose debug output of the respective feature.
+ */
+static void add_debug_flags( const char *debug )
+{
+#ifdef DEBUG
+ struct debug_option {
+ const char *name;
+ GLbitfield flag;
+ };
+ static const struct debug_option debug_opt[] = {
+ { "varray", VERBOSE_VARRAY },
+ { "tex", VERBOSE_TEXTURE },
+ { "mat", VERBOSE_MATERIAL },
+ { "pipe", VERBOSE_PIPELINE },
+ { "driver", VERBOSE_DRIVER },
+ { "state", VERBOSE_STATE },
+ { "api", VERBOSE_API },
+ { "list", VERBOSE_DISPLAY_LIST },
+ { "lighting", VERBOSE_LIGHTING },
+ { "disassem", VERBOSE_DISASSEM },
+ { "draw", VERBOSE_DRAW },
+ { "swap", VERBOSE_SWAPBUFFERS }
+ };
+ GLuint i;
+
+ MESA_VERBOSE = 0x0;
+ for (i = 0; i < Elements(debug_opt); i++) {
+ if (strstr(debug, debug_opt[i].name))
+ MESA_VERBOSE |= debug_opt[i].flag;
+ }
+
+ /* Debug flag:
+ */
+ if (strstr(debug, "flush"))
+ MESA_DEBUG_FLAGS |= DEBUG_ALWAYS_FLUSH;
+
+#if defined(_FPU_GETCW) && defined(_FPU_SETCW)
+ if (strstr(debug, "fpexceptions")) {
+ /* raise FP exceptions */
+ fpu_control_t mask;
+ _FPU_GETCW(mask);
+ mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
+ | _FPU_MASK_OM | _FPU_MASK_UM);
+ _FPU_SETCW(mask);
+ }
+#endif
+
+#else
+ (void) debug;
+#endif
+}
+
+
+void
+_mesa_init_debug( struct gl_context *ctx )
+{
+ char *c;
+ c = _mesa_getenv("MESA_DEBUG");
+ if (c)
+ add_debug_flags(c);
+
+ c = _mesa_getenv("MESA_VERBOSE");
+ if (c)
+ add_debug_flags(c);
+}
+
+
+/*
+ * Write ppm file
+ */
+static void
+write_ppm(const char *filename, const GLubyte *buffer, int width, int height,
+ int comps, int rcomp, int gcomp, int bcomp, GLboolean invert)
+{
+ FILE *f = fopen( filename, "w" );
+ if (f) {
+ int x, y;
+ const GLubyte *ptr = buffer;
+ fprintf(f,"P6\n");
+ fprintf(f,"# ppm-file created by osdemo.c\n");
+ fprintf(f,"%i %i\n", width,height);
+ fprintf(f,"255\n");
+ fclose(f);
+ f = fopen( filename, "ab" ); /* reopen in binary append mode */
+ for (y=0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ int yy = invert ? (height - 1 - y) : y;
+ int i = (yy * width + x) * comps;
+ fputc(ptr[i+rcomp], f); /* write red */
+ fputc(ptr[i+gcomp], f); /* write green */
+ fputc(ptr[i+bcomp], f); /* write blue */
+ }
+ }
+ fclose(f);
+ }
+}
+
+
+/**
+ * Write a texture image to a ppm file.
+ * \param face cube face in [0,5]
+ * \param level mipmap level
+ */
+static void
+write_texture_image(struct gl_texture_object *texObj,
+ GLuint face, GLuint level)
+{
+ struct gl_texture_image *img = texObj->Image[face][level];
+ if (img) {
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_pixelstore_attrib store;
+ GLubyte *buffer;
+ char s[100];
+
+ buffer = (GLubyte *) malloc(img->Width * img->Height
+ * img->Depth * 4);
+
+ store = ctx->Pack; /* save */
+ ctx->Pack = ctx->DefaultPacking;
+
+ ctx->Driver.GetTexImage(ctx, texObj->Target, level,
+ GL_RGBA, GL_UNSIGNED_BYTE,
+ buffer, texObj, img);
+
+ /* make filename */
+ _mesa_snprintf(s, sizeof(s), "/tmp/tex%u.l%u.f%u.ppm", texObj->Name, level, face);
+
+ printf(" Writing image level %u to %s\n", level, s);
+ write_ppm(s, buffer, img->Width, img->Height, 4, 0, 1, 2, GL_FALSE);
+
+ ctx->Pack = store; /* restore */
+
+ free(buffer);
+ }
+}
+
+
+/**
+ * Write renderbuffer image to a ppm file.
+ */
+void
+_mesa_write_renderbuffer_image(const struct gl_renderbuffer *rb)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLubyte *buffer;
+ char s[100];
+ GLenum format, type;
+
+ if (rb->_BaseFormat == GL_RGB ||
+ rb->_BaseFormat == GL_RGBA) {
+ format = GL_RGBA;
+ type = GL_UNSIGNED_BYTE;
+ }
+ else if (rb->_BaseFormat == GL_DEPTH_STENCIL) {
+ format = GL_DEPTH_STENCIL;
+ type = GL_UNSIGNED_INT_24_8;
+ }
+ else {
+ _mesa_debug(NULL,
+ "Unsupported BaseFormat 0x%x in "
+ "_mesa_write_renderbuffer_image()\n",
+ rb->_BaseFormat);
+ return;
+ }
+
+ buffer = (GLubyte *) malloc(rb->Width * rb->Height * 4);
+
+ ctx->Driver.ReadPixels(ctx, 0, 0, rb->Width, rb->Height,
+ format, type, &ctx->DefaultPacking, buffer);
+
+ /* make filename */
+ _mesa_snprintf(s, sizeof(s), "/tmp/renderbuffer%u.ppm", rb->Name);
+ _mesa_snprintf(s, sizeof(s), "C:\\renderbuffer%u.ppm", rb->Name);
+
+ printf(" Writing renderbuffer image to %s\n", s);
+
+ _mesa_debug(NULL, " Writing renderbuffer image to %s\n", s);
+
+ write_ppm(s, buffer, rb->Width, rb->Height, 4, 0, 1, 2, GL_TRUE);
+
+ free(buffer);
+}
+
+
+/** How many texture images (mipmap levels, faces) to write to files */
+#define WRITE_NONE 0
+#define WRITE_ONE 1
+#define WRITE_ALL 2
+
+static GLuint WriteImages;
+
+
+static void
+dump_texture(struct gl_texture_object *texObj, GLuint writeImages)
+{
+ const GLuint numFaces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1;
+ GLboolean written = GL_FALSE;
+ GLuint i, j;
+
+ printf("Texture %u\n", texObj->Name);
+ printf(" Target %s\n", tex_target_name(texObj->Target));
+ for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
+ for (j = 0; j < numFaces; j++) {
+ struct gl_texture_image *texImg = texObj->Image[j][i];
+ if (texImg) {
+ printf(" Face %u level %u: %d x %d x %d, format %s at %p\n",
+ j, i,
+ texImg->Width, texImg->Height, texImg->Depth,
+ _mesa_get_format_name(texImg->TexFormat),
+ texImg->Data);
+ if (writeImages == WRITE_ALL ||
+ (writeImages == WRITE_ONE && !written)) {
+ write_texture_image(texObj, j, i);
+ written = GL_TRUE;
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * Dump a single texture.
+ */
+void
+_mesa_dump_texture(GLuint texture, GLuint writeImages)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, texture);
+ if (texObj) {
+ dump_texture(texObj, writeImages);
+ }
+}
+
+
+static void
+dump_texture_cb(GLuint id, void *data, void *userData)
+{
+ struct gl_texture_object *texObj = (struct gl_texture_object *) data;
+ (void) userData;
+ dump_texture(texObj, WriteImages);
+}
+
+
+/**
+ * Print basic info about all texture objext to stdout.
+ * If dumpImages is true, write PPM of level[0] image to a file.
+ */
+void
+_mesa_dump_textures(GLuint writeImages)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ WriteImages = writeImages;
+ _mesa_HashWalk(ctx->Shared->TexObjects, dump_texture_cb, ctx);
+}
+
+
+static void
+dump_renderbuffer(const struct gl_renderbuffer *rb, GLboolean writeImage)
+{
+ printf("Renderbuffer %u: %u x %u IntFormat = %s\n",
+ rb->Name, rb->Width, rb->Height,
+ _mesa_lookup_enum_by_nr(rb->InternalFormat));
+ if (writeImage) {
+ _mesa_write_renderbuffer_image(rb);
+ }
+}
+
+
+static void
+dump_renderbuffer_cb(GLuint id, void *data, void *userData)
+{
+ const struct gl_renderbuffer *rb = (const struct gl_renderbuffer *) data;
+ (void) userData;
+ dump_renderbuffer(rb, WriteImages);
+}
+
+
+/**
+ * Print basic info about all renderbuffers to stdout.
+ * If dumpImages is true, write PPM of level[0] image to a file.
+ */
+void
+_mesa_dump_renderbuffers(GLboolean writeImages)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ WriteImages = writeImages;
+ _mesa_HashWalk(ctx->Shared->RenderBuffers, dump_renderbuffer_cb, ctx);
+}
+
+
+
+void
+_mesa_dump_color_buffer(const char *filename)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ const GLuint w = ctx->DrawBuffer->Width;
+ const GLuint h = ctx->DrawBuffer->Height;
+ GLubyte *buf;
+
+ buf = (GLubyte *) malloc(w * h * 4);
+
+ _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
+ _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
+ _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
+
+ _mesa_ReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buf);
+
+ printf("ReadBuffer %p 0x%x DrawBuffer %p 0x%x\n",
+ (void *) ctx->ReadBuffer->_ColorReadBuffer,
+ ctx->ReadBuffer->ColorReadBuffer,
+ (void *) ctx->DrawBuffer->_ColorDrawBuffers[0],
+ ctx->DrawBuffer->ColorDrawBuffer[0]);
+ printf("Writing %d x %d color buffer to %s\n", w, h, filename);
+ write_ppm(filename, buf, w, h, 4, 0, 1, 2, GL_TRUE);
+
+ _mesa_PopClientAttrib();
+
+ free(buf);
+}
+
+
+void
+_mesa_dump_depth_buffer(const char *filename)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ const GLuint w = ctx->DrawBuffer->Width;
+ const GLuint h = ctx->DrawBuffer->Height;
+ GLuint *buf;
+ GLubyte *buf2;
+ GLuint i;
+
+ buf = (GLuint *) malloc(w * h * 4); /* 4 bpp */
+ buf2 = (GLubyte *) malloc(w * h * 3); /* 3 bpp */
+
+ _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
+ _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
+ _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
+
+ _mesa_ReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buf);
+
+ /* spread 24 bits of Z across R, G, B */
+ for (i = 0; i < w * h; i++) {
+ buf2[i*3+0] = (buf[i] >> 24) & 0xff;
+ buf2[i*3+1] = (buf[i] >> 16) & 0xff;
+ buf2[i*3+2] = (buf[i] >> 8) & 0xff;
+ }
+
+ printf("Writing %d x %d depth buffer to %s\n", w, h, filename);
+ write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE);
+
+ _mesa_PopClientAttrib();
+
+ free(buf);
+ free(buf2);
+}
+
+
+void
+_mesa_dump_stencil_buffer(const char *filename)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ const GLuint w = ctx->DrawBuffer->Width;
+ const GLuint h = ctx->DrawBuffer->Height;
+ GLubyte *buf;
+ GLubyte *buf2;
+ GLuint i;
+
+ buf = (GLubyte *) malloc(w * h); /* 1 bpp */
+ buf2 = (GLubyte *) malloc(w * h * 3); /* 3 bpp */
+
+ _mesa_PushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
+ _mesa_PixelStorei(GL_PACK_ALIGNMENT, 1);
+ _mesa_PixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
+
+ _mesa_ReadPixels(0, 0, w, h, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buf);
+
+ for (i = 0; i < w * h; i++) {
+ buf2[i*3+0] = buf[i];
+ buf2[i*3+1] = (buf[i] & 127) * 2;
+ buf2[i*3+2] = (buf[i] - 128) * 2;
+ }
+
+ printf("Writing %d x %d stencil buffer to %s\n", w, h, filename);
+ write_ppm(filename, buf2, w, h, 3, 0, 1, 2, GL_TRUE);
+
+ _mesa_PopClientAttrib();
+
+ free(buf);
+ free(buf2);
+}
+
+
+/**
+ * Quick and dirty function to "print" a texture to stdout.
+ */
+void
+_mesa_print_texture(struct gl_context *ctx, const struct gl_texture_image *img)
+{
+#if CHAN_TYPE != GL_UNSIGNED_BYTE
+ _mesa_problem(NULL, "PrintTexture not supported");
+#else
+ GLuint i, j, c;
+ const GLubyte *data = (const GLubyte *) img->Data;
+
+ if (!data) {
+ printf("No texture data\n");
+ return;
+ }
+
+ /* XXX add more formats or make into a new format utility function */
+ switch (img->TexFormat) {
+ case MESA_FORMAT_A8:
+ case MESA_FORMAT_L8:
+ case MESA_FORMAT_I8:
+ case MESA_FORMAT_CI8:
+ c = 1;
+ break;
+ case MESA_FORMAT_AL88:
+ case MESA_FORMAT_AL88_REV:
+ c = 2;
+ break;
+ case MESA_FORMAT_RGB888:
+ case MESA_FORMAT_BGR888:
+ c = 3;
+ break;
+ case MESA_FORMAT_RGBA8888:
+ case MESA_FORMAT_ARGB8888:
+ c = 4;
+ break;
+ default:
+ _mesa_problem(NULL, "error in PrintTexture\n");
+ return;
+ }
+
+ for (i = 0; i < img->Height; i++) {
+ for (j = 0; j < img->Width; j++) {
+ if (c==1)
+ printf("%02x ", data[0]);
+ else if (c==2)
+ printf("%02x%02x ", data[0], data[1]);
+ else if (c==3)
+ printf("%02x%02x%02x ", data[0], data[1], data[2]);
+ else if (c==4)
+ printf("%02x%02x%02x%02x ", data[0], data[1], data[2], data[3]);
+ data += (img->RowStride - img->Width) * c;
+ }
+ /* XXX use img->ImageStride here */
+ printf("\n");
+ }
+#endif
+}
diff --git a/mesalib/src/mesa/main/debug.h b/mesalib/src/mesa/main/debug.h index ea397b72b..81fcf100d 100644 --- a/mesalib/src/mesa/main/debug.h +++ b/mesalib/src/mesa/main/debug.h @@ -64,6 +64,9 @@ extern void _mesa_init_debug( struct gl_context *ctx ); #endif
extern void
+_mesa_write_renderbuffer_image(const struct gl_renderbuffer *rb);
+
+extern void
_mesa_dump_texture(GLuint texture, GLuint writeImages);
extern void
diff --git a/mesalib/src/mesa/main/drawpix.c b/mesalib/src/mesa/main/drawpix.c index d7628c8f7..554d7a84a 100644 --- a/mesalib/src/mesa/main/drawpix.c +++ b/mesalib/src/mesa/main/drawpix.c @@ -49,6 +49,17 @@ _mesa_DrawPixels( GLsizei width, GLsizei height, GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glDrawPixels(%d, %d, %s, %s, %p) // to %s at %d, %d\n",
+ width, height,
+ _mesa_lookup_enum_by_nr(format),
+ _mesa_lookup_enum_by_nr(type),
+ pixels,
+ _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]),
+ IROUND(ctx->Current.RasterPos[0]),
+ IROUND(ctx->Current.RasterPos[1]));
+
+
if (width < 0 || height < 0) {
_mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0" );
return;
@@ -124,6 +135,18 @@ _mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+ _mesa_finish(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx,
+ "glCopyPixels(%d, %d, %d, %d, %s) // from %s to %s at %d, %d\n",
+ srcx, srcy, width, height,
+ _mesa_lookup_enum_by_nr(type),
+ _mesa_lookup_enum_by_nr(ctx->ReadBuffer->ColorReadBuffer),
+ _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]),
+ IROUND(ctx->Current.RasterPos[0]),
+ IROUND(ctx->Current.RasterPos[1]));
+
if (width < 0 || height < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)");
return;
diff --git a/mesalib/src/mesa/main/enable.c b/mesalib/src/mesa/main/enable.c index d34c6ff90..231278bee 100644 --- a/mesalib/src/mesa/main/enable.c +++ b/mesalib/src/mesa/main/enable.c @@ -1,1504 +1,1501 @@ -/** - * \file enable.c - * Enable/disable/query GL capabilities. - */ - -/* - * Mesa 3-D graphics library - * Version: 7.0.3 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#include "glheader.h" -#include "context.h" -#include "enable.h" -#include "light.h" -#include "simple_list.h" -#include "mfeatures.h" -#include "mtypes.h" -#include "enums.h" -#include "api_arrayelt.h" -#include "texstate.h" - - - -#define CHECK_EXTENSION(EXTNAME, CAP) \ - if (!ctx->Extensions.EXTNAME) { \ - goto invalid_enum_error; \ - } - - -/** - * Helper to enable/disable client-side state. - */ -static void -client_state(struct gl_context *ctx, GLenum cap, GLboolean state) -{ - struct gl_array_object *arrayObj = ctx->Array.ArrayObj; - GLuint flag; - GLboolean *var; - - switch (cap) { - case GL_VERTEX_ARRAY: - var = &arrayObj->Vertex.Enabled; - flag = _NEW_ARRAY_VERTEX; - break; - case GL_NORMAL_ARRAY: - var = &arrayObj->Normal.Enabled; - flag = _NEW_ARRAY_NORMAL; - break; - case GL_COLOR_ARRAY: - var = &arrayObj->Color.Enabled; - flag = _NEW_ARRAY_COLOR0; - break; - case GL_INDEX_ARRAY: - var = &arrayObj->Index.Enabled; - flag = _NEW_ARRAY_INDEX; - break; - case GL_TEXTURE_COORD_ARRAY: - var = &arrayObj->TexCoord[ctx->Array.ActiveTexture].Enabled; - flag = _NEW_ARRAY_TEXCOORD(ctx->Array.ActiveTexture); - break; - case GL_EDGE_FLAG_ARRAY: - var = &arrayObj->EdgeFlag.Enabled; - flag = _NEW_ARRAY_EDGEFLAG; - break; - case GL_FOG_COORDINATE_ARRAY_EXT: - var = &arrayObj->FogCoord.Enabled; - flag = _NEW_ARRAY_FOGCOORD; - break; - case GL_SECONDARY_COLOR_ARRAY_EXT: - var = &arrayObj->SecondaryColor.Enabled; - flag = _NEW_ARRAY_COLOR1; - break; - -#if FEATURE_point_size_array - case GL_POINT_SIZE_ARRAY_OES: - var = &arrayObj->PointSize.Enabled; - flag = _NEW_ARRAY_POINT_SIZE; - break; -#endif - -#if FEATURE_NV_vertex_program - case GL_VERTEX_ATTRIB_ARRAY0_NV: - case GL_VERTEX_ATTRIB_ARRAY1_NV: - case GL_VERTEX_ATTRIB_ARRAY2_NV: - case GL_VERTEX_ATTRIB_ARRAY3_NV: - case GL_VERTEX_ATTRIB_ARRAY4_NV: - case GL_VERTEX_ATTRIB_ARRAY5_NV: - case GL_VERTEX_ATTRIB_ARRAY6_NV: - case GL_VERTEX_ATTRIB_ARRAY7_NV: - case GL_VERTEX_ATTRIB_ARRAY8_NV: - case GL_VERTEX_ATTRIB_ARRAY9_NV: - case GL_VERTEX_ATTRIB_ARRAY10_NV: - case GL_VERTEX_ATTRIB_ARRAY11_NV: - case GL_VERTEX_ATTRIB_ARRAY12_NV: - case GL_VERTEX_ATTRIB_ARRAY13_NV: - case GL_VERTEX_ATTRIB_ARRAY14_NV: - case GL_VERTEX_ATTRIB_ARRAY15_NV: - CHECK_EXTENSION(NV_vertex_program, cap); - { - GLint n = (GLint) cap - GL_VERTEX_ATTRIB_ARRAY0_NV; - ASSERT(n < Elements(ctx->Array.ArrayObj->VertexAttrib)); - var = &arrayObj->VertexAttrib[n].Enabled; - flag = _NEW_ARRAY_ATTRIB(n); - } - break; -#endif /* FEATURE_NV_vertex_program */ - - /* GL_NV_primitive_restart */ - case GL_PRIMITIVE_RESTART_NV: - if (!ctx->Extensions.NV_primitive_restart) { - goto invalid_enum_error; - } - var = &ctx->Array.PrimitiveRestart; - flag = 0; - break; - - default: - goto invalid_enum_error; - } - - if (*var == state) - return; - - FLUSH_VERTICES(ctx, _NEW_ARRAY); - ctx->Array.NewState |= flag; - - _ae_invalidate_state(ctx, _NEW_ARRAY); - - *var = state; - - if (state) - ctx->Array.ArrayObj->_Enabled |= flag; - else - ctx->Array.ArrayObj->_Enabled &= ~flag; - - if (ctx->Driver.Enable) { - ctx->Driver.Enable( ctx, cap, state ); - } - - return; - -invalid_enum_error: - _mesa_error(ctx, GL_INVALID_ENUM, "gl%sClientState(0x%x)", - state ? "Enable" : "Disable", cap); -} - - -/** - * Enable GL capability. - * \param cap state to enable/disable. - * - * Get's the current context, assures that we're outside glBegin()/glEnd() and - * calls client_state(). - */ -void GLAPIENTRY -_mesa_EnableClientState( GLenum cap ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - client_state( ctx, cap, GL_TRUE ); -} - - -/** - * Disable GL capability. - * \param cap state to enable/disable. - * - * Get's the current context, assures that we're outside glBegin()/glEnd() and - * calls client_state(). - */ -void GLAPIENTRY -_mesa_DisableClientState( GLenum cap ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - client_state( ctx, cap, GL_FALSE ); -} - - -#undef CHECK_EXTENSION -#define CHECK_EXTENSION(EXTNAME, CAP) \ - if (!ctx->Extensions.EXTNAME) { \ - goto invalid_enum_error; \ - } - -#define CHECK_EXTENSION2(EXT1, EXT2, CAP) \ - if (!ctx->Extensions.EXT1 && !ctx->Extensions.EXT2) { \ - goto invalid_enum_error; \ - } - - - -/** - * Return pointer to current texture unit for setting/getting coordinate - * state. - * Note that we'll set GL_INVALID_OPERATION if the active texture unit is - * higher than the number of supported coordinate units. And we'll return NULL. - */ -static struct gl_texture_unit * -get_texcoord_unit(struct gl_context *ctx) -{ - if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glEnable/Disable(texcoord unit)"); - return NULL; - } - else { - return &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - } -} - - -/** - * Helper function to enable or disable a texture target. - * \param bit one of the TEXTURE_x_BIT values - * \return GL_TRUE if state is changing or GL_FALSE if no change - */ -static GLboolean -enable_texture(struct gl_context *ctx, GLboolean state, GLbitfield texBit) -{ - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - const GLbitfield newenabled = state - ? (texUnit->Enabled | texBit) : (texUnit->Enabled & ~texBit); - - if (texUnit->Enabled == newenabled) - return GL_FALSE; - - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - texUnit->Enabled = newenabled; - return GL_TRUE; -} - - -/** - * Helper function to enable or disable state. - * - * \param ctx GL context. - * \param cap the state to enable/disable - * \param state whether to enable or disable the specified capability. - * - * Updates the current context and flushes the vertices as needed. For - * capabilities associated with extensions it verifies that those extensions - * are effectivly present before updating. Notifies the driver via - * dd_function_table::Enable. - */ -void -_mesa_set_enable(struct gl_context *ctx, GLenum cap, GLboolean state) -{ - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "%s %s (newstate is %x)\n", - state ? "glEnable" : "glDisable", - _mesa_lookup_enum_by_nr(cap), - ctx->NewState); - - switch (cap) { - case GL_ALPHA_TEST: - if (ctx->Color.AlphaEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.AlphaEnabled = state; - break; - case GL_AUTO_NORMAL: - if (ctx->Eval.AutoNormal == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.AutoNormal = state; - break; - case GL_BLEND: - { - GLbitfield newEnabled = state * ((1 << ctx->Const.MaxDrawBuffers) - 1); - if (newEnabled != ctx->Color.BlendEnabled) { - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.BlendEnabled = newEnabled; - } - } - break; -#if FEATURE_userclip - case GL_CLIP_PLANE0: - case GL_CLIP_PLANE1: - case GL_CLIP_PLANE2: - case GL_CLIP_PLANE3: - case GL_CLIP_PLANE4: - case GL_CLIP_PLANE5: - { - const GLuint p = cap - GL_CLIP_PLANE0; - - if ((ctx->Transform.ClipPlanesEnabled & (1 << p)) == ((GLuint) state << p)) - return; - - FLUSH_VERTICES(ctx, _NEW_TRANSFORM); - - if (state) { - ctx->Transform.ClipPlanesEnabled |= (1 << p); - - if (_math_matrix_is_dirty(ctx->ProjectionMatrixStack.Top)) - _math_matrix_analyse( ctx->ProjectionMatrixStack.Top ); - - /* This derived state also calculated in clip.c and - * from _mesa_update_state() on changes to EyeUserPlane - * and ctx->ProjectionMatrix respectively. - */ - _mesa_transform_vector( ctx->Transform._ClipUserPlane[p], - ctx->Transform.EyeUserPlane[p], - ctx->ProjectionMatrixStack.Top->inv ); - } - else { - ctx->Transform.ClipPlanesEnabled &= ~(1 << p); - } - } - break; -#endif - case GL_COLOR_MATERIAL: - if (ctx->Light.ColorMaterialEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_LIGHT); - FLUSH_CURRENT(ctx, 0); - ctx->Light.ColorMaterialEnabled = state; - if (state) { - _mesa_update_color_material( ctx, - ctx->Current.Attrib[VERT_ATTRIB_COLOR0] ); - } - break; - case GL_CULL_FACE: - if (ctx->Polygon.CullFlag == state) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.CullFlag = state; - break; - case GL_DEPTH_TEST: - if (ctx->Depth.Test == state) - return; - FLUSH_VERTICES(ctx, _NEW_DEPTH); - ctx->Depth.Test = state; - break; - case GL_DITHER: - if (ctx->NoDither) { - state = GL_FALSE; /* MESA_NO_DITHER env var */ - } - if (ctx->Color.DitherFlag == state) - return; - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.DitherFlag = state; - break; - case GL_FOG: - if (ctx->Fog.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_FOG); - ctx->Fog.Enabled = state; - break; - case GL_LIGHT0: - case GL_LIGHT1: - case GL_LIGHT2: - case GL_LIGHT3: - case GL_LIGHT4: - case GL_LIGHT5: - case GL_LIGHT6: - case GL_LIGHT7: - if (ctx->Light.Light[cap-GL_LIGHT0].Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_LIGHT); - ctx->Light.Light[cap-GL_LIGHT0].Enabled = state; - if (state) { - insert_at_tail(&ctx->Light.EnabledList, - &ctx->Light.Light[cap-GL_LIGHT0]); - } - else { - remove_from_list(&ctx->Light.Light[cap-GL_LIGHT0]); - } - break; - case GL_LIGHTING: - if (ctx->Light.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_LIGHT); - ctx->Light.Enabled = state; - if (ctx->Light.Enabled && ctx->Light.Model.TwoSide) - ctx->_TriangleCaps |= DD_TRI_LIGHT_TWOSIDE; - else - ctx->_TriangleCaps &= ~DD_TRI_LIGHT_TWOSIDE; - break; - case GL_LINE_SMOOTH: - if (ctx->Line.SmoothFlag == state) - return; - FLUSH_VERTICES(ctx, _NEW_LINE); - ctx->Line.SmoothFlag = state; - ctx->_TriangleCaps ^= DD_LINE_SMOOTH; - break; - case GL_LINE_STIPPLE: - if (ctx->Line.StippleFlag == state) - return; - FLUSH_VERTICES(ctx, _NEW_LINE); - ctx->Line.StippleFlag = state; - ctx->_TriangleCaps ^= DD_LINE_STIPPLE; - break; - case GL_INDEX_LOGIC_OP: - if (ctx->Color.IndexLogicOpEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.IndexLogicOpEnabled = state; - break; - case GL_COLOR_LOGIC_OP: - if (ctx->Color.ColorLogicOpEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.ColorLogicOpEnabled = state; - break; - case GL_MAP1_COLOR_4: - if (ctx->Eval.Map1Color4 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1Color4 = state; - break; - case GL_MAP1_INDEX: - if (ctx->Eval.Map1Index == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1Index = state; - break; - case GL_MAP1_NORMAL: - if (ctx->Eval.Map1Normal == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1Normal = state; - break; - case GL_MAP1_TEXTURE_COORD_1: - if (ctx->Eval.Map1TextureCoord1 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1TextureCoord1 = state; - break; - case GL_MAP1_TEXTURE_COORD_2: - if (ctx->Eval.Map1TextureCoord2 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1TextureCoord2 = state; - break; - case GL_MAP1_TEXTURE_COORD_3: - if (ctx->Eval.Map1TextureCoord3 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1TextureCoord3 = state; - break; - case GL_MAP1_TEXTURE_COORD_4: - if (ctx->Eval.Map1TextureCoord4 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1TextureCoord4 = state; - break; - case GL_MAP1_VERTEX_3: - if (ctx->Eval.Map1Vertex3 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1Vertex3 = state; - break; - case GL_MAP1_VERTEX_4: - if (ctx->Eval.Map1Vertex4 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1Vertex4 = state; - break; - case GL_MAP2_COLOR_4: - if (ctx->Eval.Map2Color4 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2Color4 = state; - break; - case GL_MAP2_INDEX: - if (ctx->Eval.Map2Index == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2Index = state; - break; - case GL_MAP2_NORMAL: - if (ctx->Eval.Map2Normal == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2Normal = state; - break; - case GL_MAP2_TEXTURE_COORD_1: - if (ctx->Eval.Map2TextureCoord1 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2TextureCoord1 = state; - break; - case GL_MAP2_TEXTURE_COORD_2: - if (ctx->Eval.Map2TextureCoord2 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2TextureCoord2 = state; - break; - case GL_MAP2_TEXTURE_COORD_3: - if (ctx->Eval.Map2TextureCoord3 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2TextureCoord3 = state; - break; - case GL_MAP2_TEXTURE_COORD_4: - if (ctx->Eval.Map2TextureCoord4 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2TextureCoord4 = state; - break; - case GL_MAP2_VERTEX_3: - if (ctx->Eval.Map2Vertex3 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2Vertex3 = state; - break; - case GL_MAP2_VERTEX_4: - if (ctx->Eval.Map2Vertex4 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2Vertex4 = state; - break; - case GL_NORMALIZE: - if (ctx->Transform.Normalize == state) - return; - FLUSH_VERTICES(ctx, _NEW_TRANSFORM); - ctx->Transform.Normalize = state; - break; - case GL_POINT_SMOOTH: - if (ctx->Point.SmoothFlag == state) - return; - FLUSH_VERTICES(ctx, _NEW_POINT); - ctx->Point.SmoothFlag = state; - ctx->_TriangleCaps ^= DD_POINT_SMOOTH; - break; - case GL_POLYGON_SMOOTH: - if (ctx->Polygon.SmoothFlag == state) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.SmoothFlag = state; - ctx->_TriangleCaps ^= DD_TRI_SMOOTH; - break; - case GL_POLYGON_STIPPLE: - if (ctx->Polygon.StippleFlag == state) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.StippleFlag = state; - ctx->_TriangleCaps ^= DD_TRI_STIPPLE; - break; - case GL_POLYGON_OFFSET_POINT: - if (ctx->Polygon.OffsetPoint == state) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.OffsetPoint = state; - break; - case GL_POLYGON_OFFSET_LINE: - if (ctx->Polygon.OffsetLine == state) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.OffsetLine = state; - break; - case GL_POLYGON_OFFSET_FILL: - /*case GL_POLYGON_OFFSET_EXT:*/ - if (ctx->Polygon.OffsetFill == state) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.OffsetFill = state; - break; - case GL_RESCALE_NORMAL_EXT: - if (ctx->Transform.RescaleNormals == state) - return; - FLUSH_VERTICES(ctx, _NEW_TRANSFORM); - ctx->Transform.RescaleNormals = state; - break; - case GL_SCISSOR_TEST: - if (ctx->Scissor.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_SCISSOR); - ctx->Scissor.Enabled = state; - break; - case GL_SHARED_TEXTURE_PALETTE_EXT: - if (ctx->Texture.SharedPalette == state) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - ctx->Texture.SharedPalette = state; - break; - case GL_STENCIL_TEST: - if (ctx->Stencil.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.Enabled = state; - break; - case GL_TEXTURE_1D: - if (!enable_texture(ctx, state, TEXTURE_1D_BIT)) { - return; - } - break; - case GL_TEXTURE_2D: - if (!enable_texture(ctx, state, TEXTURE_2D_BIT)) { - return; - } - break; - case GL_TEXTURE_3D: - if (!enable_texture(ctx, state, TEXTURE_3D_BIT)) { - return; - } - break; - case GL_TEXTURE_GEN_Q: - { - struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - GLuint newenabled = texUnit->TexGenEnabled & ~Q_BIT; - if (state) - newenabled |= Q_BIT; - if (texUnit->TexGenEnabled == newenabled) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - texUnit->TexGenEnabled = newenabled; - } - } - break; - case GL_TEXTURE_GEN_R: - { - struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - GLuint newenabled = texUnit->TexGenEnabled & ~R_BIT; - if (state) - newenabled |= R_BIT; - if (texUnit->TexGenEnabled == newenabled) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - texUnit->TexGenEnabled = newenabled; - } - } - break; - case GL_TEXTURE_GEN_S: - { - struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - GLuint newenabled = texUnit->TexGenEnabled & ~S_BIT; - if (state) - newenabled |= S_BIT; - if (texUnit->TexGenEnabled == newenabled) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - texUnit->TexGenEnabled = newenabled; - } - } - break; - case GL_TEXTURE_GEN_T: - { - struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - GLuint newenabled = texUnit->TexGenEnabled & ~T_BIT; - if (state) - newenabled |= T_BIT; - if (texUnit->TexGenEnabled == newenabled) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - texUnit->TexGenEnabled = newenabled; - } - } - break; - -#if FEATURE_ES1 - case GL_TEXTURE_GEN_STR_OES: - /* disable S, T, and R at the same time */ - { - struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - GLuint newenabled = - texUnit->TexGenEnabled & ~STR_BITS; - if (state) - newenabled |= STR_BITS; - if (texUnit->TexGenEnabled == newenabled) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - texUnit->TexGenEnabled = newenabled; - } - } - break; -#endif - - /* - * CLIENT STATE!!! - */ - case GL_VERTEX_ARRAY: - case GL_NORMAL_ARRAY: - case GL_COLOR_ARRAY: - case GL_INDEX_ARRAY: - case GL_TEXTURE_COORD_ARRAY: - case GL_EDGE_FLAG_ARRAY: - case GL_FOG_COORDINATE_ARRAY_EXT: - case GL_SECONDARY_COLOR_ARRAY_EXT: - case GL_POINT_SIZE_ARRAY_OES: - client_state( ctx, cap, state ); - return; - - /* GL_SGI_texture_color_table */ - case GL_TEXTURE_COLOR_TABLE_SGI: - CHECK_EXTENSION(SGI_texture_color_table, cap); - if (ctx->Texture.Unit[ctx->Texture.CurrentUnit].ColorTableEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - ctx->Texture.Unit[ctx->Texture.CurrentUnit].ColorTableEnabled = state; - break; - - /* GL_ARB_texture_cube_map */ - case GL_TEXTURE_CUBE_MAP_ARB: - CHECK_EXTENSION(ARB_texture_cube_map, cap); - if (!enable_texture(ctx, state, TEXTURE_CUBE_BIT)) { - return; - } - break; - - /* GL_EXT_secondary_color */ - case GL_COLOR_SUM_EXT: - CHECK_EXTENSION2(EXT_secondary_color, ARB_vertex_program, cap); - if (ctx->Fog.ColorSumEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_FOG); - ctx->Fog.ColorSumEnabled = state; - break; - - /* GL_ARB_multisample */ - case GL_MULTISAMPLE_ARB: - if (ctx->Multisample.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); - ctx->Multisample.Enabled = state; - break; - case GL_SAMPLE_ALPHA_TO_COVERAGE_ARB: - if (ctx->Multisample.SampleAlphaToCoverage == state) - return; - FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); - ctx->Multisample.SampleAlphaToCoverage = state; - break; - case GL_SAMPLE_ALPHA_TO_ONE_ARB: - if (ctx->Multisample.SampleAlphaToOne == state) - return; - FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); - ctx->Multisample.SampleAlphaToOne = state; - break; - case GL_SAMPLE_COVERAGE_ARB: - if (ctx->Multisample.SampleCoverage == state) - return; - FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); - ctx->Multisample.SampleCoverage = state; - break; - case GL_SAMPLE_COVERAGE_INVERT_ARB: - if (ctx->Multisample.SampleCoverageInvert == state) - return; - FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); - ctx->Multisample.SampleCoverageInvert = state; - break; - - /* GL_IBM_rasterpos_clip */ - case GL_RASTER_POSITION_UNCLIPPED_IBM: - CHECK_EXTENSION(IBM_rasterpos_clip, cap); - if (ctx->Transform.RasterPositionUnclipped == state) - return; - FLUSH_VERTICES(ctx, _NEW_TRANSFORM); - ctx->Transform.RasterPositionUnclipped = state; - break; - - /* GL_NV_point_sprite */ - case GL_POINT_SPRITE_NV: - CHECK_EXTENSION2(NV_point_sprite, ARB_point_sprite, cap); - if (ctx->Point.PointSprite == state) - return; - FLUSH_VERTICES(ctx, _NEW_POINT); - ctx->Point.PointSprite = state; - break; - -#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program - case GL_VERTEX_PROGRAM_ARB: - CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap); - if (ctx->VertexProgram.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - ctx->VertexProgram.Enabled = state; - break; - case GL_VERTEX_PROGRAM_POINT_SIZE_ARB: - CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap); - if (ctx->VertexProgram.PointSizeEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - ctx->VertexProgram.PointSizeEnabled = state; - break; - case GL_VERTEX_PROGRAM_TWO_SIDE_ARB: - CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap); - if (ctx->VertexProgram.TwoSideEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - ctx->VertexProgram.TwoSideEnabled = state; - break; -#endif -#if FEATURE_NV_vertex_program - case GL_MAP1_VERTEX_ATTRIB0_4_NV: - case GL_MAP1_VERTEX_ATTRIB1_4_NV: - case GL_MAP1_VERTEX_ATTRIB2_4_NV: - case GL_MAP1_VERTEX_ATTRIB3_4_NV: - case GL_MAP1_VERTEX_ATTRIB4_4_NV: - case GL_MAP1_VERTEX_ATTRIB5_4_NV: - case GL_MAP1_VERTEX_ATTRIB6_4_NV: - case GL_MAP1_VERTEX_ATTRIB7_4_NV: - case GL_MAP1_VERTEX_ATTRIB8_4_NV: - case GL_MAP1_VERTEX_ATTRIB9_4_NV: - case GL_MAP1_VERTEX_ATTRIB10_4_NV: - case GL_MAP1_VERTEX_ATTRIB11_4_NV: - case GL_MAP1_VERTEX_ATTRIB12_4_NV: - case GL_MAP1_VERTEX_ATTRIB13_4_NV: - case GL_MAP1_VERTEX_ATTRIB14_4_NV: - case GL_MAP1_VERTEX_ATTRIB15_4_NV: - CHECK_EXTENSION(NV_vertex_program, cap); - { - const GLuint map = (GLuint) (cap - GL_MAP1_VERTEX_ATTRIB0_4_NV); - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1Attrib[map] = state; - } - break; - case GL_MAP2_VERTEX_ATTRIB0_4_NV: - case GL_MAP2_VERTEX_ATTRIB1_4_NV: - case GL_MAP2_VERTEX_ATTRIB2_4_NV: - case GL_MAP2_VERTEX_ATTRIB3_4_NV: - case GL_MAP2_VERTEX_ATTRIB4_4_NV: - case GL_MAP2_VERTEX_ATTRIB5_4_NV: - case GL_MAP2_VERTEX_ATTRIB6_4_NV: - case GL_MAP2_VERTEX_ATTRIB7_4_NV: - case GL_MAP2_VERTEX_ATTRIB8_4_NV: - case GL_MAP2_VERTEX_ATTRIB9_4_NV: - case GL_MAP2_VERTEX_ATTRIB10_4_NV: - case GL_MAP2_VERTEX_ATTRIB11_4_NV: - case GL_MAP2_VERTEX_ATTRIB12_4_NV: - case GL_MAP2_VERTEX_ATTRIB13_4_NV: - case GL_MAP2_VERTEX_ATTRIB14_4_NV: - case GL_MAP2_VERTEX_ATTRIB15_4_NV: - CHECK_EXTENSION(NV_vertex_program, cap); - { - const GLuint map = (GLuint) (cap - GL_MAP2_VERTEX_ATTRIB0_4_NV); - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2Attrib[map] = state; - } - break; -#endif /* FEATURE_NV_vertex_program */ - -#if FEATURE_NV_fragment_program - case GL_FRAGMENT_PROGRAM_NV: - CHECK_EXTENSION(NV_fragment_program, cap); - if (ctx->FragmentProgram.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - ctx->FragmentProgram.Enabled = state; - break; -#endif /* FEATURE_NV_fragment_program */ - - /* GL_NV_texture_rectangle */ - case GL_TEXTURE_RECTANGLE_NV: - CHECK_EXTENSION(NV_texture_rectangle, cap); - if (!enable_texture(ctx, state, TEXTURE_RECT_BIT)) { - return; - } - break; - - /* GL_EXT_stencil_two_side */ - case GL_STENCIL_TEST_TWO_SIDE_EXT: - CHECK_EXTENSION(EXT_stencil_two_side, cap); - if (ctx->Stencil.TestTwoSide == state) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.TestTwoSide = state; - if (state) { - ctx->Stencil._BackFace = 2; - ctx->_TriangleCaps |= DD_TRI_TWOSTENCIL; - } else { - ctx->Stencil._BackFace = 1; - ctx->_TriangleCaps &= ~DD_TRI_TWOSTENCIL; - } - break; - -#if FEATURE_ARB_fragment_program - case GL_FRAGMENT_PROGRAM_ARB: - CHECK_EXTENSION(ARB_fragment_program, cap); - if (ctx->FragmentProgram.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - ctx->FragmentProgram.Enabled = state; - break; -#endif /* FEATURE_ARB_fragment_program */ - - /* GL_EXT_depth_bounds_test */ - case GL_DEPTH_BOUNDS_TEST_EXT: - CHECK_EXTENSION(EXT_depth_bounds_test, cap); - if (ctx->Depth.BoundsTest == state) - return; - FLUSH_VERTICES(ctx, _NEW_DEPTH); - ctx->Depth.BoundsTest = state; - break; - - case GL_DEPTH_CLAMP: - if (ctx->Transform.DepthClamp == state) - return; - CHECK_EXTENSION(ARB_depth_clamp, cap); - FLUSH_VERTICES(ctx, _NEW_TRANSFORM); - ctx->Transform.DepthClamp = state; - break; - -#if FEATURE_ATI_fragment_shader - case GL_FRAGMENT_SHADER_ATI: - CHECK_EXTENSION(ATI_fragment_shader, cap); - if (ctx->ATIFragmentShader.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - ctx->ATIFragmentShader.Enabled = state; - break; -#endif - - /* GL_MESA_texture_array */ - case GL_TEXTURE_1D_ARRAY_EXT: - CHECK_EXTENSION(MESA_texture_array, cap); - if (!enable_texture(ctx, state, TEXTURE_1D_ARRAY_BIT)) { - return; - } - break; - - case GL_TEXTURE_2D_ARRAY_EXT: - CHECK_EXTENSION(MESA_texture_array, cap); - if (!enable_texture(ctx, state, TEXTURE_2D_ARRAY_BIT)) { - return; - } - break; - - case GL_TEXTURE_CUBE_MAP_SEAMLESS: - CHECK_EXTENSION(ARB_seamless_cube_map, cap); - ctx->Texture.CubeMapSeamless = state; - break; - -#if FEATURE_EXT_transform_feedback - case GL_RASTERIZER_DISCARD: - CHECK_EXTENSION(EXT_transform_feedback, cap); - if (ctx->TransformFeedback.RasterDiscard != state) { - ctx->TransformFeedback.RasterDiscard = state; - FLUSH_VERTICES(ctx, _NEW_TRANSFORM); - } - break; -#endif - - /* GL 3.1 primitive restart. Note: this enum is different from - * GL_PRIMITIVE_RESTART_NV (which is client state). - */ - case GL_PRIMITIVE_RESTART: - if (ctx->VersionMajor * 10 + ctx->VersionMinor < 31) { - goto invalid_enum_error; - } - if (ctx->Array.PrimitiveRestart != state) { - FLUSH_VERTICES(ctx, _NEW_TRANSFORM); - ctx->Array.PrimitiveRestart = state; - } - break; - - /* GL3.0 - GL_framebuffer_sRGB */ - case GL_FRAMEBUFFER_SRGB_EXT: - CHECK_EXTENSION(EXT_framebuffer_sRGB, cap); - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - ctx->Color.sRGBEnabled = state; - break; - - default: - goto invalid_enum_error; - } - - if (ctx->Driver.Enable) { - ctx->Driver.Enable( ctx, cap, state ); - } - - return; - -invalid_enum_error: - _mesa_error(ctx, GL_INVALID_ENUM, "gl%s(0x%x)", - state ? "Enable" : "Disable", cap); -} - - -/** - * Enable GL capability. Called by glEnable() - * \param cap state to enable. - */ -void GLAPIENTRY -_mesa_Enable( GLenum cap ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - _mesa_set_enable( ctx, cap, GL_TRUE ); -} - - -/** - * Disable GL capability. Called by glDisable() - * \param cap state to disable. - */ -void GLAPIENTRY -_mesa_Disable( GLenum cap ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - _mesa_set_enable( ctx, cap, GL_FALSE ); -} - - - -/** - * Enable/disable an indexed state var. - */ -void -_mesa_set_enablei(struct gl_context *ctx, GLenum cap, GLuint index, GLboolean state) -{ - ASSERT(state == 0 || state == 1); - switch (cap) { - case GL_BLEND: - if (!ctx->Extensions.EXT_draw_buffers2) { - goto invalid_enum_error; - } - if (index >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%u)", - state ? "glEnableIndexed" : "glDisableIndexed", index); - return; - } - if (((ctx->Color.BlendEnabled >> index) & 1) != state) { - FLUSH_VERTICES(ctx, _NEW_COLOR); - if (state) - ctx->Color.BlendEnabled |= (1 << index); - else - ctx->Color.BlendEnabled &= ~(1 << index); - } - break; - default: - goto invalid_enum_error; - } - return; - -invalid_enum_error: - _mesa_error(ctx, GL_INVALID_ENUM, "%s(cap=%s)", - state ? "glEnablei" : "glDisablei", - _mesa_lookup_enum_by_nr(cap)); -} - - -void GLAPIENTRY -_mesa_DisableIndexed( GLenum cap, GLuint index ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - _mesa_set_enablei(ctx, cap, index, GL_FALSE); -} - - -void GLAPIENTRY -_mesa_EnableIndexed( GLenum cap, GLuint index ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - _mesa_set_enablei(ctx, cap, index, GL_TRUE); -} - - -GLboolean GLAPIENTRY -_mesa_IsEnabledIndexed( GLenum cap, GLuint index ) -{ - GET_CURRENT_CONTEXT(ctx); - switch (cap) { - case GL_BLEND: - if (index >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glIsEnabledIndexed(index=%u)", - index); - return GL_FALSE; - } - return (ctx->Color.BlendEnabled >> index) & 1; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glIsEnabledIndexed(cap=%s)", - _mesa_lookup_enum_by_nr(cap)); - return GL_FALSE; - } -} - - - - -#undef CHECK_EXTENSION -#define CHECK_EXTENSION(EXTNAME) \ - if (!ctx->Extensions.EXTNAME) { \ - goto invalid_enum_error; \ - } - -#undef CHECK_EXTENSION2 -#define CHECK_EXTENSION2(EXT1, EXT2) \ - if (!ctx->Extensions.EXT1 && !ctx->Extensions.EXT2) { \ - goto invalid_enum_error; \ - } - - -/** - * Helper function to determine whether a texture target is enabled. - */ -static GLboolean -is_texture_enabled(struct gl_context *ctx, GLbitfield bit) -{ - const struct gl_texture_unit *const texUnit = - &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - return (texUnit->Enabled & bit) ? GL_TRUE : GL_FALSE; -} - - -/** - * Return simple enable/disable state. - * - * \param cap state variable to query. - * - * Returns the state of the specified capability from the current GL context. - * For the capabilities associated with extensions verifies that those - * extensions are effectively present before reporting. - */ -GLboolean GLAPIENTRY -_mesa_IsEnabled( GLenum cap ) -{ - GET_CURRENT_CONTEXT(ctx); - switch (cap) { - case GL_ALPHA_TEST: - return ctx->Color.AlphaEnabled; - case GL_AUTO_NORMAL: - return ctx->Eval.AutoNormal; - case GL_BLEND: - return ctx->Color.BlendEnabled & 1; /* return state for buffer[0] */ - case GL_CLIP_PLANE0: - case GL_CLIP_PLANE1: - case GL_CLIP_PLANE2: - case GL_CLIP_PLANE3: - case GL_CLIP_PLANE4: - case GL_CLIP_PLANE5: - return (ctx->Transform.ClipPlanesEnabled >> (cap - GL_CLIP_PLANE0)) & 1; - case GL_COLOR_MATERIAL: - return ctx->Light.ColorMaterialEnabled; - case GL_CULL_FACE: - return ctx->Polygon.CullFlag; - case GL_DEPTH_TEST: - return ctx->Depth.Test; - case GL_DITHER: - return ctx->Color.DitherFlag; - case GL_FOG: - return ctx->Fog.Enabled; - case GL_LIGHTING: - return ctx->Light.Enabled; - case GL_LIGHT0: - case GL_LIGHT1: - case GL_LIGHT2: - case GL_LIGHT3: - case GL_LIGHT4: - case GL_LIGHT5: - case GL_LIGHT6: - case GL_LIGHT7: - return ctx->Light.Light[cap-GL_LIGHT0].Enabled; - case GL_LINE_SMOOTH: - return ctx->Line.SmoothFlag; - case GL_LINE_STIPPLE: - return ctx->Line.StippleFlag; - case GL_INDEX_LOGIC_OP: - return ctx->Color.IndexLogicOpEnabled; - case GL_COLOR_LOGIC_OP: - return ctx->Color.ColorLogicOpEnabled; - case GL_MAP1_COLOR_4: - return ctx->Eval.Map1Color4; - case GL_MAP1_INDEX: - return ctx->Eval.Map1Index; - case GL_MAP1_NORMAL: - return ctx->Eval.Map1Normal; - case GL_MAP1_TEXTURE_COORD_1: - return ctx->Eval.Map1TextureCoord1; - case GL_MAP1_TEXTURE_COORD_2: - return ctx->Eval.Map1TextureCoord2; - case GL_MAP1_TEXTURE_COORD_3: - return ctx->Eval.Map1TextureCoord3; - case GL_MAP1_TEXTURE_COORD_4: - return ctx->Eval.Map1TextureCoord4; - case GL_MAP1_VERTEX_3: - return ctx->Eval.Map1Vertex3; - case GL_MAP1_VERTEX_4: - return ctx->Eval.Map1Vertex4; - case GL_MAP2_COLOR_4: - return ctx->Eval.Map2Color4; - case GL_MAP2_INDEX: - return ctx->Eval.Map2Index; - case GL_MAP2_NORMAL: - return ctx->Eval.Map2Normal; - case GL_MAP2_TEXTURE_COORD_1: - return ctx->Eval.Map2TextureCoord1; - case GL_MAP2_TEXTURE_COORD_2: - return ctx->Eval.Map2TextureCoord2; - case GL_MAP2_TEXTURE_COORD_3: - return ctx->Eval.Map2TextureCoord3; - case GL_MAP2_TEXTURE_COORD_4: - return ctx->Eval.Map2TextureCoord4; - case GL_MAP2_VERTEX_3: - return ctx->Eval.Map2Vertex3; - case GL_MAP2_VERTEX_4: - return ctx->Eval.Map2Vertex4; - case GL_NORMALIZE: - return ctx->Transform.Normalize; - case GL_POINT_SMOOTH: - return ctx->Point.SmoothFlag; - case GL_POLYGON_SMOOTH: - return ctx->Polygon.SmoothFlag; - case GL_POLYGON_STIPPLE: - return ctx->Polygon.StippleFlag; - case GL_POLYGON_OFFSET_POINT: - return ctx->Polygon.OffsetPoint; - case GL_POLYGON_OFFSET_LINE: - return ctx->Polygon.OffsetLine; - case GL_POLYGON_OFFSET_FILL: - /*case GL_POLYGON_OFFSET_EXT:*/ - return ctx->Polygon.OffsetFill; - case GL_RESCALE_NORMAL_EXT: - return ctx->Transform.RescaleNormals; - case GL_SCISSOR_TEST: - return ctx->Scissor.Enabled; - case GL_SHARED_TEXTURE_PALETTE_EXT: - return ctx->Texture.SharedPalette; - case GL_STENCIL_TEST: - return ctx->Stencil.Enabled; - case GL_TEXTURE_1D: - return is_texture_enabled(ctx, TEXTURE_1D_BIT); - case GL_TEXTURE_2D: - return is_texture_enabled(ctx, TEXTURE_2D_BIT); - case GL_TEXTURE_3D: - return is_texture_enabled(ctx, TEXTURE_3D_BIT); - case GL_TEXTURE_GEN_Q: - { - const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - return (texUnit->TexGenEnabled & Q_BIT) ? GL_TRUE : GL_FALSE; - } - } - return GL_FALSE; - case GL_TEXTURE_GEN_R: - { - const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - return (texUnit->TexGenEnabled & R_BIT) ? GL_TRUE : GL_FALSE; - } - } - return GL_FALSE; - case GL_TEXTURE_GEN_S: - { - const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - return (texUnit->TexGenEnabled & S_BIT) ? GL_TRUE : GL_FALSE; - } - } - return GL_FALSE; - case GL_TEXTURE_GEN_T: - { - const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - return (texUnit->TexGenEnabled & T_BIT) ? GL_TRUE : GL_FALSE; - } - } - return GL_FALSE; -#if FEATURE_ES1 - case GL_TEXTURE_GEN_STR_OES: - { - const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - return (texUnit->TexGenEnabled & STR_BITS) == STR_BITS ? GL_TRUE : GL_FALSE; - } - } -#endif - - /* - * CLIENT STATE!!! - */ - case GL_VERTEX_ARRAY: - return (ctx->Array.ArrayObj->Vertex.Enabled != 0); - case GL_NORMAL_ARRAY: - return (ctx->Array.ArrayObj->Normal.Enabled != 0); - case GL_COLOR_ARRAY: - return (ctx->Array.ArrayObj->Color.Enabled != 0); - case GL_INDEX_ARRAY: - return (ctx->Array.ArrayObj->Index.Enabled != 0); - case GL_TEXTURE_COORD_ARRAY: - return (ctx->Array.ArrayObj->TexCoord[ctx->Array.ActiveTexture].Enabled != 0); - case GL_EDGE_FLAG_ARRAY: - return (ctx->Array.ArrayObj->EdgeFlag.Enabled != 0); - case GL_FOG_COORDINATE_ARRAY_EXT: - CHECK_EXTENSION(EXT_fog_coord); - return (ctx->Array.ArrayObj->FogCoord.Enabled != 0); - case GL_SECONDARY_COLOR_ARRAY_EXT: - CHECK_EXTENSION(EXT_secondary_color); - return (ctx->Array.ArrayObj->SecondaryColor.Enabled != 0); -#if FEATURE_point_size_array - case GL_POINT_SIZE_ARRAY_OES: - return (ctx->Array.ArrayObj->PointSize.Enabled != 0); -#endif - - /* GL_SGI_texture_color_table */ - case GL_TEXTURE_COLOR_TABLE_SGI: - CHECK_EXTENSION(SGI_texture_color_table); - return ctx->Texture.Unit[ctx->Texture.CurrentUnit].ColorTableEnabled; - - /* GL_ARB_texture_cube_map */ - case GL_TEXTURE_CUBE_MAP_ARB: - CHECK_EXTENSION(ARB_texture_cube_map); - return is_texture_enabled(ctx, TEXTURE_CUBE_BIT); - - /* GL_EXT_secondary_color */ - case GL_COLOR_SUM_EXT: - CHECK_EXTENSION2(EXT_secondary_color, ARB_vertex_program); - return ctx->Fog.ColorSumEnabled; - - /* GL_ARB_multisample */ - case GL_MULTISAMPLE_ARB: - return ctx->Multisample.Enabled; - case GL_SAMPLE_ALPHA_TO_COVERAGE_ARB: - return ctx->Multisample.SampleAlphaToCoverage; - case GL_SAMPLE_ALPHA_TO_ONE_ARB: - return ctx->Multisample.SampleAlphaToOne; - case GL_SAMPLE_COVERAGE_ARB: - return ctx->Multisample.SampleCoverage; - case GL_SAMPLE_COVERAGE_INVERT_ARB: - return ctx->Multisample.SampleCoverageInvert; - - /* GL_IBM_rasterpos_clip */ - case GL_RASTER_POSITION_UNCLIPPED_IBM: - CHECK_EXTENSION(IBM_rasterpos_clip); - return ctx->Transform.RasterPositionUnclipped; - - /* GL_NV_point_sprite */ - case GL_POINT_SPRITE_NV: - CHECK_EXTENSION2(NV_point_sprite, ARB_point_sprite) - return ctx->Point.PointSprite; - -#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program - case GL_VERTEX_PROGRAM_ARB: - CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program); - return ctx->VertexProgram.Enabled; - case GL_VERTEX_PROGRAM_POINT_SIZE_ARB: - CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program); - return ctx->VertexProgram.PointSizeEnabled; - case GL_VERTEX_PROGRAM_TWO_SIDE_ARB: - CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program); - return ctx->VertexProgram.TwoSideEnabled; -#endif -#if FEATURE_NV_vertex_program - case GL_VERTEX_ATTRIB_ARRAY0_NV: - case GL_VERTEX_ATTRIB_ARRAY1_NV: - case GL_VERTEX_ATTRIB_ARRAY2_NV: - case GL_VERTEX_ATTRIB_ARRAY3_NV: - case GL_VERTEX_ATTRIB_ARRAY4_NV: - case GL_VERTEX_ATTRIB_ARRAY5_NV: - case GL_VERTEX_ATTRIB_ARRAY6_NV: - case GL_VERTEX_ATTRIB_ARRAY7_NV: - case GL_VERTEX_ATTRIB_ARRAY8_NV: - case GL_VERTEX_ATTRIB_ARRAY9_NV: - case GL_VERTEX_ATTRIB_ARRAY10_NV: - case GL_VERTEX_ATTRIB_ARRAY11_NV: - case GL_VERTEX_ATTRIB_ARRAY12_NV: - case GL_VERTEX_ATTRIB_ARRAY13_NV: - case GL_VERTEX_ATTRIB_ARRAY14_NV: - case GL_VERTEX_ATTRIB_ARRAY15_NV: - CHECK_EXTENSION(NV_vertex_program); - { - GLint n = (GLint) cap - GL_VERTEX_ATTRIB_ARRAY0_NV; - ASSERT(n < Elements(ctx->Array.ArrayObj->VertexAttrib)); - return (ctx->Array.ArrayObj->VertexAttrib[n].Enabled != 0); - } - case GL_MAP1_VERTEX_ATTRIB0_4_NV: - case GL_MAP1_VERTEX_ATTRIB1_4_NV: - case GL_MAP1_VERTEX_ATTRIB2_4_NV: - case GL_MAP1_VERTEX_ATTRIB3_4_NV: - case GL_MAP1_VERTEX_ATTRIB4_4_NV: - case GL_MAP1_VERTEX_ATTRIB5_4_NV: - case GL_MAP1_VERTEX_ATTRIB6_4_NV: - case GL_MAP1_VERTEX_ATTRIB7_4_NV: - case GL_MAP1_VERTEX_ATTRIB8_4_NV: - case GL_MAP1_VERTEX_ATTRIB9_4_NV: - case GL_MAP1_VERTEX_ATTRIB10_4_NV: - case GL_MAP1_VERTEX_ATTRIB11_4_NV: - case GL_MAP1_VERTEX_ATTRIB12_4_NV: - case GL_MAP1_VERTEX_ATTRIB13_4_NV: - case GL_MAP1_VERTEX_ATTRIB14_4_NV: - case GL_MAP1_VERTEX_ATTRIB15_4_NV: - CHECK_EXTENSION(NV_vertex_program); - { - const GLuint map = (GLuint) (cap - GL_MAP1_VERTEX_ATTRIB0_4_NV); - return ctx->Eval.Map1Attrib[map]; - } - case GL_MAP2_VERTEX_ATTRIB0_4_NV: - case GL_MAP2_VERTEX_ATTRIB1_4_NV: - case GL_MAP2_VERTEX_ATTRIB2_4_NV: - case GL_MAP2_VERTEX_ATTRIB3_4_NV: - case GL_MAP2_VERTEX_ATTRIB4_4_NV: - case GL_MAP2_VERTEX_ATTRIB5_4_NV: - case GL_MAP2_VERTEX_ATTRIB6_4_NV: - case GL_MAP2_VERTEX_ATTRIB7_4_NV: - case GL_MAP2_VERTEX_ATTRIB8_4_NV: - case GL_MAP2_VERTEX_ATTRIB9_4_NV: - case GL_MAP2_VERTEX_ATTRIB10_4_NV: - case GL_MAP2_VERTEX_ATTRIB11_4_NV: - case GL_MAP2_VERTEX_ATTRIB12_4_NV: - case GL_MAP2_VERTEX_ATTRIB13_4_NV: - case GL_MAP2_VERTEX_ATTRIB14_4_NV: - case GL_MAP2_VERTEX_ATTRIB15_4_NV: - CHECK_EXTENSION(NV_vertex_program); - { - const GLuint map = (GLuint) (cap - GL_MAP2_VERTEX_ATTRIB0_4_NV); - return ctx->Eval.Map2Attrib[map]; - } -#endif /* FEATURE_NV_vertex_program */ - -#if FEATURE_NV_fragment_program - case GL_FRAGMENT_PROGRAM_NV: - CHECK_EXTENSION(NV_fragment_program); - return ctx->FragmentProgram.Enabled; -#endif /* FEATURE_NV_fragment_program */ - - /* GL_NV_texture_rectangle */ - case GL_TEXTURE_RECTANGLE_NV: - CHECK_EXTENSION(NV_texture_rectangle); - return is_texture_enabled(ctx, TEXTURE_RECT_BIT); - - /* GL_EXT_stencil_two_side */ - case GL_STENCIL_TEST_TWO_SIDE_EXT: - CHECK_EXTENSION(EXT_stencil_two_side); - return ctx->Stencil.TestTwoSide; - -#if FEATURE_ARB_fragment_program - case GL_FRAGMENT_PROGRAM_ARB: - return ctx->FragmentProgram.Enabled; -#endif /* FEATURE_ARB_fragment_program */ - - /* GL_EXT_depth_bounds_test */ - case GL_DEPTH_BOUNDS_TEST_EXT: - CHECK_EXTENSION(EXT_depth_bounds_test); - return ctx->Depth.BoundsTest; - - /* GL_ARB_depth_clamp */ - case GL_DEPTH_CLAMP: - CHECK_EXTENSION(ARB_depth_clamp); - return ctx->Transform.DepthClamp; - -#if FEATURE_ATI_fragment_shader - case GL_FRAGMENT_SHADER_ATI: - CHECK_EXTENSION(ATI_fragment_shader); - return ctx->ATIFragmentShader.Enabled; -#endif /* FEATURE_ATI_fragment_shader */ - - case GL_TEXTURE_CUBE_MAP_SEAMLESS: - CHECK_EXTENSION(ARB_seamless_cube_map); - return ctx->Texture.CubeMapSeamless; - -#if FEATURE_EXT_transform_feedback - case GL_RASTERIZER_DISCARD: - CHECK_EXTENSION(EXT_transform_feedback); - return ctx->TransformFeedback.RasterDiscard; -#endif - - /* GL_NV_primitive_restart */ - case GL_PRIMITIVE_RESTART_NV: - if (!ctx->Extensions.NV_primitive_restart) { - goto invalid_enum_error; - } - return ctx->Array.PrimitiveRestart; - - /* GL 3.1 primitive restart */ - case GL_PRIMITIVE_RESTART: - if (ctx->VersionMajor * 10 + ctx->VersionMinor < 31) { - goto invalid_enum_error; - } - return ctx->Array.PrimitiveRestart; - - /* GL3.0 - GL_framebuffer_sRGB */ - case GL_FRAMEBUFFER_SRGB_EXT: - CHECK_EXTENSION(EXT_framebuffer_sRGB); - return ctx->Color.sRGBEnabled; - - default: - goto invalid_enum_error; - } - - return GL_FALSE; - -invalid_enum_error: - _mesa_error(ctx, GL_INVALID_ENUM, "glIsEnabled(0x%x)", (int) cap); - return GL_FALSE; -} +/**
+ * \file enable.c
+ * Enable/disable/query GL capabilities.
+ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.0.3
+ *
+ * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "enable.h"
+#include "light.h"
+#include "simple_list.h"
+#include "mfeatures.h"
+#include "mtypes.h"
+#include "enums.h"
+#include "api_arrayelt.h"
+#include "texstate.h"
+
+
+
+#define CHECK_EXTENSION(EXTNAME, CAP) \
+ if (!ctx->Extensions.EXTNAME) { \
+ goto invalid_enum_error; \
+ }
+
+
+/**
+ * Helper to enable/disable client-side state.
+ */
+static void
+client_state(struct gl_context *ctx, GLenum cap, GLboolean state)
+{
+ struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
+ GLuint flag;
+ GLboolean *var;
+
+ switch (cap) {
+ case GL_VERTEX_ARRAY:
+ var = &arrayObj->Vertex.Enabled;
+ flag = _NEW_ARRAY_VERTEX;
+ break;
+ case GL_NORMAL_ARRAY:
+ var = &arrayObj->Normal.Enabled;
+ flag = _NEW_ARRAY_NORMAL;
+ break;
+ case GL_COLOR_ARRAY:
+ var = &arrayObj->Color.Enabled;
+ flag = _NEW_ARRAY_COLOR0;
+ break;
+ case GL_INDEX_ARRAY:
+ var = &arrayObj->Index.Enabled;
+ flag = _NEW_ARRAY_INDEX;
+ break;
+ case GL_TEXTURE_COORD_ARRAY:
+ var = &arrayObj->TexCoord[ctx->Array.ActiveTexture].Enabled;
+ flag = _NEW_ARRAY_TEXCOORD(ctx->Array.ActiveTexture);
+ break;
+ case GL_EDGE_FLAG_ARRAY:
+ var = &arrayObj->EdgeFlag.Enabled;
+ flag = _NEW_ARRAY_EDGEFLAG;
+ break;
+ case GL_FOG_COORDINATE_ARRAY_EXT:
+ var = &arrayObj->FogCoord.Enabled;
+ flag = _NEW_ARRAY_FOGCOORD;
+ break;
+ case GL_SECONDARY_COLOR_ARRAY_EXT:
+ var = &arrayObj->SecondaryColor.Enabled;
+ flag = _NEW_ARRAY_COLOR1;
+ break;
+
+#if FEATURE_point_size_array
+ case GL_POINT_SIZE_ARRAY_OES:
+ var = &arrayObj->PointSize.Enabled;
+ flag = _NEW_ARRAY_POINT_SIZE;
+ break;
+#endif
+
+#if FEATURE_NV_vertex_program
+ case GL_VERTEX_ATTRIB_ARRAY0_NV:
+ case GL_VERTEX_ATTRIB_ARRAY1_NV:
+ case GL_VERTEX_ATTRIB_ARRAY2_NV:
+ case GL_VERTEX_ATTRIB_ARRAY3_NV:
+ case GL_VERTEX_ATTRIB_ARRAY4_NV:
+ case GL_VERTEX_ATTRIB_ARRAY5_NV:
+ case GL_VERTEX_ATTRIB_ARRAY6_NV:
+ case GL_VERTEX_ATTRIB_ARRAY7_NV:
+ case GL_VERTEX_ATTRIB_ARRAY8_NV:
+ case GL_VERTEX_ATTRIB_ARRAY9_NV:
+ case GL_VERTEX_ATTRIB_ARRAY10_NV:
+ case GL_VERTEX_ATTRIB_ARRAY11_NV:
+ case GL_VERTEX_ATTRIB_ARRAY12_NV:
+ case GL_VERTEX_ATTRIB_ARRAY13_NV:
+ case GL_VERTEX_ATTRIB_ARRAY14_NV:
+ case GL_VERTEX_ATTRIB_ARRAY15_NV:
+ CHECK_EXTENSION(NV_vertex_program, cap);
+ {
+ GLint n = (GLint) cap - GL_VERTEX_ATTRIB_ARRAY0_NV;
+ ASSERT(n < Elements(ctx->Array.ArrayObj->VertexAttrib));
+ var = &arrayObj->VertexAttrib[n].Enabled;
+ flag = _NEW_ARRAY_ATTRIB(n);
+ }
+ break;
+#endif /* FEATURE_NV_vertex_program */
+
+ /* GL_NV_primitive_restart */
+ case GL_PRIMITIVE_RESTART_NV:
+ if (!ctx->Extensions.NV_primitive_restart) {
+ goto invalid_enum_error;
+ }
+ var = &ctx->Array.PrimitiveRestart;
+ flag = 0;
+ break;
+
+ default:
+ goto invalid_enum_error;
+ }
+
+ if (*var == state)
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_ARRAY);
+ ctx->Array.NewState |= flag;
+
+ _ae_invalidate_state(ctx, _NEW_ARRAY);
+
+ *var = state;
+
+ if (state)
+ ctx->Array.ArrayObj->_Enabled |= flag;
+ else
+ ctx->Array.ArrayObj->_Enabled &= ~flag;
+
+ if (ctx->Driver.Enable) {
+ ctx->Driver.Enable( ctx, cap, state );
+ }
+
+ return;
+
+invalid_enum_error:
+ _mesa_error(ctx, GL_INVALID_ENUM, "gl%sClientState(0x%x)",
+ state ? "Enable" : "Disable", cap);
+}
+
+
+/**
+ * Enable GL capability.
+ * \param cap state to enable/disable.
+ *
+ * Get's the current context, assures that we're outside glBegin()/glEnd() and
+ * calls client_state().
+ */
+void GLAPIENTRY
+_mesa_EnableClientState( GLenum cap )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+ client_state( ctx, cap, GL_TRUE );
+}
+
+
+/**
+ * Disable GL capability.
+ * \param cap state to enable/disable.
+ *
+ * Get's the current context, assures that we're outside glBegin()/glEnd() and
+ * calls client_state().
+ */
+void GLAPIENTRY
+_mesa_DisableClientState( GLenum cap )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+ client_state( ctx, cap, GL_FALSE );
+}
+
+
+#undef CHECK_EXTENSION
+#define CHECK_EXTENSION(EXTNAME, CAP) \
+ if (!ctx->Extensions.EXTNAME) { \
+ goto invalid_enum_error; \
+ }
+
+#define CHECK_EXTENSION2(EXT1, EXT2, CAP) \
+ if (!ctx->Extensions.EXT1 && !ctx->Extensions.EXT2) { \
+ goto invalid_enum_error; \
+ }
+
+
+
+/**
+ * Return pointer to current texture unit for setting/getting coordinate
+ * state.
+ * Note that we'll set GL_INVALID_OPERATION if the active texture unit is
+ * higher than the number of supported coordinate units. And we'll return NULL.
+ */
+static struct gl_texture_unit *
+get_texcoord_unit(struct gl_context *ctx)
+{
+ if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glEnable/Disable(texcoord unit)");
+ return NULL;
+ }
+ else {
+ return &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+ }
+}
+
+
+/**
+ * Helper function to enable or disable a texture target.
+ * \param bit one of the TEXTURE_x_BIT values
+ * \return GL_TRUE if state is changing or GL_FALSE if no change
+ */
+static GLboolean
+enable_texture(struct gl_context *ctx, GLboolean state, GLbitfield texBit)
+{
+ struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
+ const GLbitfield newenabled = state
+ ? (texUnit->Enabled | texBit) : (texUnit->Enabled & ~texBit);
+
+ if (texUnit->Enabled == newenabled)
+ return GL_FALSE;
+
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ texUnit->Enabled = newenabled;
+ return GL_TRUE;
+}
+
+
+/**
+ * Helper function to enable or disable state.
+ *
+ * \param ctx GL context.
+ * \param cap the state to enable/disable
+ * \param state whether to enable or disable the specified capability.
+ *
+ * Updates the current context and flushes the vertices as needed. For
+ * capabilities associated with extensions it verifies that those extensions
+ * are effectivly present before updating. Notifies the driver via
+ * dd_function_table::Enable.
+ */
+void
+_mesa_set_enable(struct gl_context *ctx, GLenum cap, GLboolean state)
+{
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "%s %s (newstate is %x)\n",
+ state ? "glEnable" : "glDisable",
+ _mesa_lookup_enum_by_nr(cap),
+ ctx->NewState);
+
+ switch (cap) {
+ case GL_ALPHA_TEST:
+ if (ctx->Color.AlphaEnabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ ctx->Color.AlphaEnabled = state;
+ break;
+ case GL_AUTO_NORMAL:
+ if (ctx->Eval.AutoNormal == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.AutoNormal = state;
+ break;
+ case GL_BLEND:
+ {
+ GLbitfield newEnabled = state * ((1 << ctx->Const.MaxDrawBuffers) - 1);
+ if (newEnabled != ctx->Color.BlendEnabled) {
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ ctx->Color.BlendEnabled = newEnabled;
+ }
+ }
+ break;
+#if FEATURE_userclip
+ case GL_CLIP_PLANE0:
+ case GL_CLIP_PLANE1:
+ case GL_CLIP_PLANE2:
+ case GL_CLIP_PLANE3:
+ case GL_CLIP_PLANE4:
+ case GL_CLIP_PLANE5:
+ {
+ const GLuint p = cap - GL_CLIP_PLANE0;
+
+ if ((ctx->Transform.ClipPlanesEnabled & (1 << p)) == ((GLuint) state << p))
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
+
+ if (state) {
+ ctx->Transform.ClipPlanesEnabled |= (1 << p);
+
+ if (_math_matrix_is_dirty(ctx->ProjectionMatrixStack.Top))
+ _math_matrix_analyse( ctx->ProjectionMatrixStack.Top );
+
+ /* This derived state also calculated in clip.c and
+ * from _mesa_update_state() on changes to EyeUserPlane
+ * and ctx->ProjectionMatrix respectively.
+ */
+ _mesa_transform_vector( ctx->Transform._ClipUserPlane[p],
+ ctx->Transform.EyeUserPlane[p],
+ ctx->ProjectionMatrixStack.Top->inv );
+ }
+ else {
+ ctx->Transform.ClipPlanesEnabled &= ~(1 << p);
+ }
+ }
+ break;
+#endif
+ case GL_COLOR_MATERIAL:
+ if (ctx->Light.ColorMaterialEnabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_LIGHT);
+ FLUSH_CURRENT(ctx, 0);
+ ctx->Light.ColorMaterialEnabled = state;
+ if (state) {
+ _mesa_update_color_material( ctx,
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0] );
+ }
+ break;
+ case GL_CULL_FACE:
+ if (ctx->Polygon.CullFlag == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_POLYGON);
+ ctx->Polygon.CullFlag = state;
+ break;
+ case GL_DEPTH_TEST:
+ if (ctx->Depth.Test == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_DEPTH);
+ ctx->Depth.Test = state;
+ break;
+ case GL_DITHER:
+ if (ctx->Color.DitherFlag == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ ctx->Color.DitherFlag = state;
+ break;
+ case GL_FOG:
+ if (ctx->Fog.Enabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_FOG);
+ ctx->Fog.Enabled = state;
+ break;
+ case GL_LIGHT0:
+ case GL_LIGHT1:
+ case GL_LIGHT2:
+ case GL_LIGHT3:
+ case GL_LIGHT4:
+ case GL_LIGHT5:
+ case GL_LIGHT6:
+ case GL_LIGHT7:
+ if (ctx->Light.Light[cap-GL_LIGHT0].Enabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_LIGHT);
+ ctx->Light.Light[cap-GL_LIGHT0].Enabled = state;
+ if (state) {
+ insert_at_tail(&ctx->Light.EnabledList,
+ &ctx->Light.Light[cap-GL_LIGHT0]);
+ }
+ else {
+ remove_from_list(&ctx->Light.Light[cap-GL_LIGHT0]);
+ }
+ break;
+ case GL_LIGHTING:
+ if (ctx->Light.Enabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_LIGHT);
+ ctx->Light.Enabled = state;
+ if (ctx->Light.Enabled && ctx->Light.Model.TwoSide)
+ ctx->_TriangleCaps |= DD_TRI_LIGHT_TWOSIDE;
+ else
+ ctx->_TriangleCaps &= ~DD_TRI_LIGHT_TWOSIDE;
+ break;
+ case GL_LINE_SMOOTH:
+ if (ctx->Line.SmoothFlag == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_LINE);
+ ctx->Line.SmoothFlag = state;
+ ctx->_TriangleCaps ^= DD_LINE_SMOOTH;
+ break;
+ case GL_LINE_STIPPLE:
+ if (ctx->Line.StippleFlag == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_LINE);
+ ctx->Line.StippleFlag = state;
+ ctx->_TriangleCaps ^= DD_LINE_STIPPLE;
+ break;
+ case GL_INDEX_LOGIC_OP:
+ if (ctx->Color.IndexLogicOpEnabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ ctx->Color.IndexLogicOpEnabled = state;
+ break;
+ case GL_COLOR_LOGIC_OP:
+ if (ctx->Color.ColorLogicOpEnabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ ctx->Color.ColorLogicOpEnabled = state;
+ break;
+ case GL_MAP1_COLOR_4:
+ if (ctx->Eval.Map1Color4 == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map1Color4 = state;
+ break;
+ case GL_MAP1_INDEX:
+ if (ctx->Eval.Map1Index == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map1Index = state;
+ break;
+ case GL_MAP1_NORMAL:
+ if (ctx->Eval.Map1Normal == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map1Normal = state;
+ break;
+ case GL_MAP1_TEXTURE_COORD_1:
+ if (ctx->Eval.Map1TextureCoord1 == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map1TextureCoord1 = state;
+ break;
+ case GL_MAP1_TEXTURE_COORD_2:
+ if (ctx->Eval.Map1TextureCoord2 == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map1TextureCoord2 = state;
+ break;
+ case GL_MAP1_TEXTURE_COORD_3:
+ if (ctx->Eval.Map1TextureCoord3 == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map1TextureCoord3 = state;
+ break;
+ case GL_MAP1_TEXTURE_COORD_4:
+ if (ctx->Eval.Map1TextureCoord4 == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map1TextureCoord4 = state;
+ break;
+ case GL_MAP1_VERTEX_3:
+ if (ctx->Eval.Map1Vertex3 == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map1Vertex3 = state;
+ break;
+ case GL_MAP1_VERTEX_4:
+ if (ctx->Eval.Map1Vertex4 == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map1Vertex4 = state;
+ break;
+ case GL_MAP2_COLOR_4:
+ if (ctx->Eval.Map2Color4 == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map2Color4 = state;
+ break;
+ case GL_MAP2_INDEX:
+ if (ctx->Eval.Map2Index == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map2Index = state;
+ break;
+ case GL_MAP2_NORMAL:
+ if (ctx->Eval.Map2Normal == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map2Normal = state;
+ break;
+ case GL_MAP2_TEXTURE_COORD_1:
+ if (ctx->Eval.Map2TextureCoord1 == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map2TextureCoord1 = state;
+ break;
+ case GL_MAP2_TEXTURE_COORD_2:
+ if (ctx->Eval.Map2TextureCoord2 == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map2TextureCoord2 = state;
+ break;
+ case GL_MAP2_TEXTURE_COORD_3:
+ if (ctx->Eval.Map2TextureCoord3 == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map2TextureCoord3 = state;
+ break;
+ case GL_MAP2_TEXTURE_COORD_4:
+ if (ctx->Eval.Map2TextureCoord4 == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map2TextureCoord4 = state;
+ break;
+ case GL_MAP2_VERTEX_3:
+ if (ctx->Eval.Map2Vertex3 == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map2Vertex3 = state;
+ break;
+ case GL_MAP2_VERTEX_4:
+ if (ctx->Eval.Map2Vertex4 == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map2Vertex4 = state;
+ break;
+ case GL_NORMALIZE:
+ if (ctx->Transform.Normalize == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
+ ctx->Transform.Normalize = state;
+ break;
+ case GL_POINT_SMOOTH:
+ if (ctx->Point.SmoothFlag == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_POINT);
+ ctx->Point.SmoothFlag = state;
+ ctx->_TriangleCaps ^= DD_POINT_SMOOTH;
+ break;
+ case GL_POLYGON_SMOOTH:
+ if (ctx->Polygon.SmoothFlag == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_POLYGON);
+ ctx->Polygon.SmoothFlag = state;
+ ctx->_TriangleCaps ^= DD_TRI_SMOOTH;
+ break;
+ case GL_POLYGON_STIPPLE:
+ if (ctx->Polygon.StippleFlag == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_POLYGON);
+ ctx->Polygon.StippleFlag = state;
+ ctx->_TriangleCaps ^= DD_TRI_STIPPLE;
+ break;
+ case GL_POLYGON_OFFSET_POINT:
+ if (ctx->Polygon.OffsetPoint == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_POLYGON);
+ ctx->Polygon.OffsetPoint = state;
+ break;
+ case GL_POLYGON_OFFSET_LINE:
+ if (ctx->Polygon.OffsetLine == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_POLYGON);
+ ctx->Polygon.OffsetLine = state;
+ break;
+ case GL_POLYGON_OFFSET_FILL:
+ /*case GL_POLYGON_OFFSET_EXT:*/
+ if (ctx->Polygon.OffsetFill == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_POLYGON);
+ ctx->Polygon.OffsetFill = state;
+ break;
+ case GL_RESCALE_NORMAL_EXT:
+ if (ctx->Transform.RescaleNormals == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
+ ctx->Transform.RescaleNormals = state;
+ break;
+ case GL_SCISSOR_TEST:
+ if (ctx->Scissor.Enabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_SCISSOR);
+ ctx->Scissor.Enabled = state;
+ break;
+ case GL_SHARED_TEXTURE_PALETTE_EXT:
+ if (ctx->Texture.SharedPalette == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ ctx->Texture.SharedPalette = state;
+ break;
+ case GL_STENCIL_TEST:
+ if (ctx->Stencil.Enabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+ ctx->Stencil.Enabled = state;
+ break;
+ case GL_TEXTURE_1D:
+ if (!enable_texture(ctx, state, TEXTURE_1D_BIT)) {
+ return;
+ }
+ break;
+ case GL_TEXTURE_2D:
+ if (!enable_texture(ctx, state, TEXTURE_2D_BIT)) {
+ return;
+ }
+ break;
+ case GL_TEXTURE_3D:
+ if (!enable_texture(ctx, state, TEXTURE_3D_BIT)) {
+ return;
+ }
+ break;
+ case GL_TEXTURE_GEN_Q:
+ {
+ struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
+ if (texUnit) {
+ GLuint newenabled = texUnit->TexGenEnabled & ~Q_BIT;
+ if (state)
+ newenabled |= Q_BIT;
+ if (texUnit->TexGenEnabled == newenabled)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ texUnit->TexGenEnabled = newenabled;
+ }
+ }
+ break;
+ case GL_TEXTURE_GEN_R:
+ {
+ struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
+ if (texUnit) {
+ GLuint newenabled = texUnit->TexGenEnabled & ~R_BIT;
+ if (state)
+ newenabled |= R_BIT;
+ if (texUnit->TexGenEnabled == newenabled)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ texUnit->TexGenEnabled = newenabled;
+ }
+ }
+ break;
+ case GL_TEXTURE_GEN_S:
+ {
+ struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
+ if (texUnit) {
+ GLuint newenabled = texUnit->TexGenEnabled & ~S_BIT;
+ if (state)
+ newenabled |= S_BIT;
+ if (texUnit->TexGenEnabled == newenabled)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ texUnit->TexGenEnabled = newenabled;
+ }
+ }
+ break;
+ case GL_TEXTURE_GEN_T:
+ {
+ struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
+ if (texUnit) {
+ GLuint newenabled = texUnit->TexGenEnabled & ~T_BIT;
+ if (state)
+ newenabled |= T_BIT;
+ if (texUnit->TexGenEnabled == newenabled)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ texUnit->TexGenEnabled = newenabled;
+ }
+ }
+ break;
+
+#if FEATURE_ES1
+ case GL_TEXTURE_GEN_STR_OES:
+ /* disable S, T, and R at the same time */
+ {
+ struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
+ if (texUnit) {
+ GLuint newenabled =
+ texUnit->TexGenEnabled & ~STR_BITS;
+ if (state)
+ newenabled |= STR_BITS;
+ if (texUnit->TexGenEnabled == newenabled)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ texUnit->TexGenEnabled = newenabled;
+ }
+ }
+ break;
+#endif
+
+ /*
+ * CLIENT STATE!!!
+ */
+ case GL_VERTEX_ARRAY:
+ case GL_NORMAL_ARRAY:
+ case GL_COLOR_ARRAY:
+ case GL_INDEX_ARRAY:
+ case GL_TEXTURE_COORD_ARRAY:
+ case GL_EDGE_FLAG_ARRAY:
+ case GL_FOG_COORDINATE_ARRAY_EXT:
+ case GL_SECONDARY_COLOR_ARRAY_EXT:
+ case GL_POINT_SIZE_ARRAY_OES:
+ client_state( ctx, cap, state );
+ return;
+
+ /* GL_SGI_texture_color_table */
+ case GL_TEXTURE_COLOR_TABLE_SGI:
+ CHECK_EXTENSION(SGI_texture_color_table, cap);
+ if (ctx->Texture.Unit[ctx->Texture.CurrentUnit].ColorTableEnabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ ctx->Texture.Unit[ctx->Texture.CurrentUnit].ColorTableEnabled = state;
+ break;
+
+ /* GL_ARB_texture_cube_map */
+ case GL_TEXTURE_CUBE_MAP_ARB:
+ CHECK_EXTENSION(ARB_texture_cube_map, cap);
+ if (!enable_texture(ctx, state, TEXTURE_CUBE_BIT)) {
+ return;
+ }
+ break;
+
+ /* GL_EXT_secondary_color */
+ case GL_COLOR_SUM_EXT:
+ CHECK_EXTENSION2(EXT_secondary_color, ARB_vertex_program, cap);
+ if (ctx->Fog.ColorSumEnabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_FOG);
+ ctx->Fog.ColorSumEnabled = state;
+ break;
+
+ /* GL_ARB_multisample */
+ case GL_MULTISAMPLE_ARB:
+ if (ctx->Multisample.Enabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
+ ctx->Multisample.Enabled = state;
+ break;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE_ARB:
+ if (ctx->Multisample.SampleAlphaToCoverage == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
+ ctx->Multisample.SampleAlphaToCoverage = state;
+ break;
+ case GL_SAMPLE_ALPHA_TO_ONE_ARB:
+ if (ctx->Multisample.SampleAlphaToOne == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
+ ctx->Multisample.SampleAlphaToOne = state;
+ break;
+ case GL_SAMPLE_COVERAGE_ARB:
+ if (ctx->Multisample.SampleCoverage == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
+ ctx->Multisample.SampleCoverage = state;
+ break;
+ case GL_SAMPLE_COVERAGE_INVERT_ARB:
+ if (ctx->Multisample.SampleCoverageInvert == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
+ ctx->Multisample.SampleCoverageInvert = state;
+ break;
+
+ /* GL_IBM_rasterpos_clip */
+ case GL_RASTER_POSITION_UNCLIPPED_IBM:
+ CHECK_EXTENSION(IBM_rasterpos_clip, cap);
+ if (ctx->Transform.RasterPositionUnclipped == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
+ ctx->Transform.RasterPositionUnclipped = state;
+ break;
+
+ /* GL_NV_point_sprite */
+ case GL_POINT_SPRITE_NV:
+ CHECK_EXTENSION2(NV_point_sprite, ARB_point_sprite, cap);
+ if (ctx->Point.PointSprite == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_POINT);
+ ctx->Point.PointSprite = state;
+ break;
+
+#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
+ case GL_VERTEX_PROGRAM_ARB:
+ CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap);
+ if (ctx->VertexProgram.Enabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+ ctx->VertexProgram.Enabled = state;
+ break;
+ case GL_VERTEX_PROGRAM_POINT_SIZE_ARB:
+ CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap);
+ if (ctx->VertexProgram.PointSizeEnabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+ ctx->VertexProgram.PointSizeEnabled = state;
+ break;
+ case GL_VERTEX_PROGRAM_TWO_SIDE_ARB:
+ CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap);
+ if (ctx->VertexProgram.TwoSideEnabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+ ctx->VertexProgram.TwoSideEnabled = state;
+ break;
+#endif
+#if FEATURE_NV_vertex_program
+ case GL_MAP1_VERTEX_ATTRIB0_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB1_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB2_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB3_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB4_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB5_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB6_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB7_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB8_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB9_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB10_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB11_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB12_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB13_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB14_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB15_4_NV:
+ CHECK_EXTENSION(NV_vertex_program, cap);
+ {
+ const GLuint map = (GLuint) (cap - GL_MAP1_VERTEX_ATTRIB0_4_NV);
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map1Attrib[map] = state;
+ }
+ break;
+ case GL_MAP2_VERTEX_ATTRIB0_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB1_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB2_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB3_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB4_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB5_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB6_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB7_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB8_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB9_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB10_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB11_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB12_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB13_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB14_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB15_4_NV:
+ CHECK_EXTENSION(NV_vertex_program, cap);
+ {
+ const GLuint map = (GLuint) (cap - GL_MAP2_VERTEX_ATTRIB0_4_NV);
+ FLUSH_VERTICES(ctx, _NEW_EVAL);
+ ctx->Eval.Map2Attrib[map] = state;
+ }
+ break;
+#endif /* FEATURE_NV_vertex_program */
+
+#if FEATURE_NV_fragment_program
+ case GL_FRAGMENT_PROGRAM_NV:
+ CHECK_EXTENSION(NV_fragment_program, cap);
+ if (ctx->FragmentProgram.Enabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+ ctx->FragmentProgram.Enabled = state;
+ break;
+#endif /* FEATURE_NV_fragment_program */
+
+ /* GL_NV_texture_rectangle */
+ case GL_TEXTURE_RECTANGLE_NV:
+ CHECK_EXTENSION(NV_texture_rectangle, cap);
+ if (!enable_texture(ctx, state, TEXTURE_RECT_BIT)) {
+ return;
+ }
+ break;
+
+ /* GL_EXT_stencil_two_side */
+ case GL_STENCIL_TEST_TWO_SIDE_EXT:
+ CHECK_EXTENSION(EXT_stencil_two_side, cap);
+ if (ctx->Stencil.TestTwoSide == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+ ctx->Stencil.TestTwoSide = state;
+ if (state) {
+ ctx->Stencil._BackFace = 2;
+ ctx->_TriangleCaps |= DD_TRI_TWOSTENCIL;
+ } else {
+ ctx->Stencil._BackFace = 1;
+ ctx->_TriangleCaps &= ~DD_TRI_TWOSTENCIL;
+ }
+ break;
+
+#if FEATURE_ARB_fragment_program
+ case GL_FRAGMENT_PROGRAM_ARB:
+ CHECK_EXTENSION(ARB_fragment_program, cap);
+ if (ctx->FragmentProgram.Enabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+ ctx->FragmentProgram.Enabled = state;
+ break;
+#endif /* FEATURE_ARB_fragment_program */
+
+ /* GL_EXT_depth_bounds_test */
+ case GL_DEPTH_BOUNDS_TEST_EXT:
+ CHECK_EXTENSION(EXT_depth_bounds_test, cap);
+ if (ctx->Depth.BoundsTest == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_DEPTH);
+ ctx->Depth.BoundsTest = state;
+ break;
+
+ case GL_DEPTH_CLAMP:
+ if (ctx->Transform.DepthClamp == state)
+ return;
+ CHECK_EXTENSION(ARB_depth_clamp, cap);
+ FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
+ ctx->Transform.DepthClamp = state;
+ break;
+
+#if FEATURE_ATI_fragment_shader
+ case GL_FRAGMENT_SHADER_ATI:
+ CHECK_EXTENSION(ATI_fragment_shader, cap);
+ if (ctx->ATIFragmentShader.Enabled == state)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+ ctx->ATIFragmentShader.Enabled = state;
+ break;
+#endif
+
+ /* GL_MESA_texture_array */
+ case GL_TEXTURE_1D_ARRAY_EXT:
+ CHECK_EXTENSION(MESA_texture_array, cap);
+ if (!enable_texture(ctx, state, TEXTURE_1D_ARRAY_BIT)) {
+ return;
+ }
+ break;
+
+ case GL_TEXTURE_2D_ARRAY_EXT:
+ CHECK_EXTENSION(MESA_texture_array, cap);
+ if (!enable_texture(ctx, state, TEXTURE_2D_ARRAY_BIT)) {
+ return;
+ }
+ break;
+
+ case GL_TEXTURE_CUBE_MAP_SEAMLESS:
+ CHECK_EXTENSION(ARB_seamless_cube_map, cap);
+ ctx->Texture.CubeMapSeamless = state;
+ break;
+
+#if FEATURE_EXT_transform_feedback
+ case GL_RASTERIZER_DISCARD:
+ CHECK_EXTENSION(EXT_transform_feedback, cap);
+ if (ctx->TransformFeedback.RasterDiscard != state) {
+ ctx->TransformFeedback.RasterDiscard = state;
+ FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
+ }
+ break;
+#endif
+
+ /* GL 3.1 primitive restart. Note: this enum is different from
+ * GL_PRIMITIVE_RESTART_NV (which is client state).
+ */
+ case GL_PRIMITIVE_RESTART:
+ if (ctx->VersionMajor * 10 + ctx->VersionMinor < 31) {
+ goto invalid_enum_error;
+ }
+ if (ctx->Array.PrimitiveRestart != state) {
+ FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
+ ctx->Array.PrimitiveRestart = state;
+ }
+ break;
+
+ /* GL3.0 - GL_framebuffer_sRGB */
+ case GL_FRAMEBUFFER_SRGB_EXT:
+ CHECK_EXTENSION(EXT_framebuffer_sRGB, cap);
+ FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+ ctx->Color.sRGBEnabled = state;
+ break;
+
+ default:
+ goto invalid_enum_error;
+ }
+
+ if (ctx->Driver.Enable) {
+ ctx->Driver.Enable( ctx, cap, state );
+ }
+
+ return;
+
+invalid_enum_error:
+ _mesa_error(ctx, GL_INVALID_ENUM, "gl%s(0x%x)",
+ state ? "Enable" : "Disable", cap);
+}
+
+
+/**
+ * Enable GL capability. Called by glEnable()
+ * \param cap state to enable.
+ */
+void GLAPIENTRY
+_mesa_Enable( GLenum cap )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ _mesa_set_enable( ctx, cap, GL_TRUE );
+}
+
+
+/**
+ * Disable GL capability. Called by glDisable()
+ * \param cap state to disable.
+ */
+void GLAPIENTRY
+_mesa_Disable( GLenum cap )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ _mesa_set_enable( ctx, cap, GL_FALSE );
+}
+
+
+
+/**
+ * Enable/disable an indexed state var.
+ */
+void
+_mesa_set_enablei(struct gl_context *ctx, GLenum cap, GLuint index, GLboolean state)
+{
+ ASSERT(state == 0 || state == 1);
+ switch (cap) {
+ case GL_BLEND:
+ if (!ctx->Extensions.EXT_draw_buffers2) {
+ goto invalid_enum_error;
+ }
+ if (index >= ctx->Const.MaxDrawBuffers) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%u)",
+ state ? "glEnableIndexed" : "glDisableIndexed", index);
+ return;
+ }
+ if (((ctx->Color.BlendEnabled >> index) & 1) != state) {
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ if (state)
+ ctx->Color.BlendEnabled |= (1 << index);
+ else
+ ctx->Color.BlendEnabled &= ~(1 << index);
+ }
+ break;
+ default:
+ goto invalid_enum_error;
+ }
+ return;
+
+invalid_enum_error:
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(cap=%s)",
+ state ? "glEnablei" : "glDisablei",
+ _mesa_lookup_enum_by_nr(cap));
+}
+
+
+void GLAPIENTRY
+_mesa_DisableIndexed( GLenum cap, GLuint index )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+ _mesa_set_enablei(ctx, cap, index, GL_FALSE);
+}
+
+
+void GLAPIENTRY
+_mesa_EnableIndexed( GLenum cap, GLuint index )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+ _mesa_set_enablei(ctx, cap, index, GL_TRUE);
+}
+
+
+GLboolean GLAPIENTRY
+_mesa_IsEnabledIndexed( GLenum cap, GLuint index )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ switch (cap) {
+ case GL_BLEND:
+ if (index >= ctx->Const.MaxDrawBuffers) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glIsEnabledIndexed(index=%u)",
+ index);
+ return GL_FALSE;
+ }
+ return (ctx->Color.BlendEnabled >> index) & 1;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glIsEnabledIndexed(cap=%s)",
+ _mesa_lookup_enum_by_nr(cap));
+ return GL_FALSE;
+ }
+}
+
+
+
+
+#undef CHECK_EXTENSION
+#define CHECK_EXTENSION(EXTNAME) \
+ if (!ctx->Extensions.EXTNAME) { \
+ goto invalid_enum_error; \
+ }
+
+#undef CHECK_EXTENSION2
+#define CHECK_EXTENSION2(EXT1, EXT2) \
+ if (!ctx->Extensions.EXT1 && !ctx->Extensions.EXT2) { \
+ goto invalid_enum_error; \
+ }
+
+
+/**
+ * Helper function to determine whether a texture target is enabled.
+ */
+static GLboolean
+is_texture_enabled(struct gl_context *ctx, GLbitfield bit)
+{
+ const struct gl_texture_unit *const texUnit =
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+ return (texUnit->Enabled & bit) ? GL_TRUE : GL_FALSE;
+}
+
+
+/**
+ * Return simple enable/disable state.
+ *
+ * \param cap state variable to query.
+ *
+ * Returns the state of the specified capability from the current GL context.
+ * For the capabilities associated with extensions verifies that those
+ * extensions are effectively present before reporting.
+ */
+GLboolean GLAPIENTRY
+_mesa_IsEnabled( GLenum cap )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ switch (cap) {
+ case GL_ALPHA_TEST:
+ return ctx->Color.AlphaEnabled;
+ case GL_AUTO_NORMAL:
+ return ctx->Eval.AutoNormal;
+ case GL_BLEND:
+ return ctx->Color.BlendEnabled & 1; /* return state for buffer[0] */
+ case GL_CLIP_PLANE0:
+ case GL_CLIP_PLANE1:
+ case GL_CLIP_PLANE2:
+ case GL_CLIP_PLANE3:
+ case GL_CLIP_PLANE4:
+ case GL_CLIP_PLANE5:
+ return (ctx->Transform.ClipPlanesEnabled >> (cap - GL_CLIP_PLANE0)) & 1;
+ case GL_COLOR_MATERIAL:
+ return ctx->Light.ColorMaterialEnabled;
+ case GL_CULL_FACE:
+ return ctx->Polygon.CullFlag;
+ case GL_DEPTH_TEST:
+ return ctx->Depth.Test;
+ case GL_DITHER:
+ return ctx->Color.DitherFlag;
+ case GL_FOG:
+ return ctx->Fog.Enabled;
+ case GL_LIGHTING:
+ return ctx->Light.Enabled;
+ case GL_LIGHT0:
+ case GL_LIGHT1:
+ case GL_LIGHT2:
+ case GL_LIGHT3:
+ case GL_LIGHT4:
+ case GL_LIGHT5:
+ case GL_LIGHT6:
+ case GL_LIGHT7:
+ return ctx->Light.Light[cap-GL_LIGHT0].Enabled;
+ case GL_LINE_SMOOTH:
+ return ctx->Line.SmoothFlag;
+ case GL_LINE_STIPPLE:
+ return ctx->Line.StippleFlag;
+ case GL_INDEX_LOGIC_OP:
+ return ctx->Color.IndexLogicOpEnabled;
+ case GL_COLOR_LOGIC_OP:
+ return ctx->Color.ColorLogicOpEnabled;
+ case GL_MAP1_COLOR_4:
+ return ctx->Eval.Map1Color4;
+ case GL_MAP1_INDEX:
+ return ctx->Eval.Map1Index;
+ case GL_MAP1_NORMAL:
+ return ctx->Eval.Map1Normal;
+ case GL_MAP1_TEXTURE_COORD_1:
+ return ctx->Eval.Map1TextureCoord1;
+ case GL_MAP1_TEXTURE_COORD_2:
+ return ctx->Eval.Map1TextureCoord2;
+ case GL_MAP1_TEXTURE_COORD_3:
+ return ctx->Eval.Map1TextureCoord3;
+ case GL_MAP1_TEXTURE_COORD_4:
+ return ctx->Eval.Map1TextureCoord4;
+ case GL_MAP1_VERTEX_3:
+ return ctx->Eval.Map1Vertex3;
+ case GL_MAP1_VERTEX_4:
+ return ctx->Eval.Map1Vertex4;
+ case GL_MAP2_COLOR_4:
+ return ctx->Eval.Map2Color4;
+ case GL_MAP2_INDEX:
+ return ctx->Eval.Map2Index;
+ case GL_MAP2_NORMAL:
+ return ctx->Eval.Map2Normal;
+ case GL_MAP2_TEXTURE_COORD_1:
+ return ctx->Eval.Map2TextureCoord1;
+ case GL_MAP2_TEXTURE_COORD_2:
+ return ctx->Eval.Map2TextureCoord2;
+ case GL_MAP2_TEXTURE_COORD_3:
+ return ctx->Eval.Map2TextureCoord3;
+ case GL_MAP2_TEXTURE_COORD_4:
+ return ctx->Eval.Map2TextureCoord4;
+ case GL_MAP2_VERTEX_3:
+ return ctx->Eval.Map2Vertex3;
+ case GL_MAP2_VERTEX_4:
+ return ctx->Eval.Map2Vertex4;
+ case GL_NORMALIZE:
+ return ctx->Transform.Normalize;
+ case GL_POINT_SMOOTH:
+ return ctx->Point.SmoothFlag;
+ case GL_POLYGON_SMOOTH:
+ return ctx->Polygon.SmoothFlag;
+ case GL_POLYGON_STIPPLE:
+ return ctx->Polygon.StippleFlag;
+ case GL_POLYGON_OFFSET_POINT:
+ return ctx->Polygon.OffsetPoint;
+ case GL_POLYGON_OFFSET_LINE:
+ return ctx->Polygon.OffsetLine;
+ case GL_POLYGON_OFFSET_FILL:
+ /*case GL_POLYGON_OFFSET_EXT:*/
+ return ctx->Polygon.OffsetFill;
+ case GL_RESCALE_NORMAL_EXT:
+ return ctx->Transform.RescaleNormals;
+ case GL_SCISSOR_TEST:
+ return ctx->Scissor.Enabled;
+ case GL_SHARED_TEXTURE_PALETTE_EXT:
+ return ctx->Texture.SharedPalette;
+ case GL_STENCIL_TEST:
+ return ctx->Stencil.Enabled;
+ case GL_TEXTURE_1D:
+ return is_texture_enabled(ctx, TEXTURE_1D_BIT);
+ case GL_TEXTURE_2D:
+ return is_texture_enabled(ctx, TEXTURE_2D_BIT);
+ case GL_TEXTURE_3D:
+ return is_texture_enabled(ctx, TEXTURE_3D_BIT);
+ case GL_TEXTURE_GEN_Q:
+ {
+ const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
+ if (texUnit) {
+ return (texUnit->TexGenEnabled & Q_BIT) ? GL_TRUE : GL_FALSE;
+ }
+ }
+ return GL_FALSE;
+ case GL_TEXTURE_GEN_R:
+ {
+ const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
+ if (texUnit) {
+ return (texUnit->TexGenEnabled & R_BIT) ? GL_TRUE : GL_FALSE;
+ }
+ }
+ return GL_FALSE;
+ case GL_TEXTURE_GEN_S:
+ {
+ const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
+ if (texUnit) {
+ return (texUnit->TexGenEnabled & S_BIT) ? GL_TRUE : GL_FALSE;
+ }
+ }
+ return GL_FALSE;
+ case GL_TEXTURE_GEN_T:
+ {
+ const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
+ if (texUnit) {
+ return (texUnit->TexGenEnabled & T_BIT) ? GL_TRUE : GL_FALSE;
+ }
+ }
+ return GL_FALSE;
+#if FEATURE_ES1
+ case GL_TEXTURE_GEN_STR_OES:
+ {
+ const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
+ if (texUnit) {
+ return (texUnit->TexGenEnabled & STR_BITS) == STR_BITS ? GL_TRUE : GL_FALSE;
+ }
+ }
+#endif
+
+ /*
+ * CLIENT STATE!!!
+ */
+ case GL_VERTEX_ARRAY:
+ return (ctx->Array.ArrayObj->Vertex.Enabled != 0);
+ case GL_NORMAL_ARRAY:
+ return (ctx->Array.ArrayObj->Normal.Enabled != 0);
+ case GL_COLOR_ARRAY:
+ return (ctx->Array.ArrayObj->Color.Enabled != 0);
+ case GL_INDEX_ARRAY:
+ return (ctx->Array.ArrayObj->Index.Enabled != 0);
+ case GL_TEXTURE_COORD_ARRAY:
+ return (ctx->Array.ArrayObj->TexCoord[ctx->Array.ActiveTexture].Enabled != 0);
+ case GL_EDGE_FLAG_ARRAY:
+ return (ctx->Array.ArrayObj->EdgeFlag.Enabled != 0);
+ case GL_FOG_COORDINATE_ARRAY_EXT:
+ CHECK_EXTENSION(EXT_fog_coord);
+ return (ctx->Array.ArrayObj->FogCoord.Enabled != 0);
+ case GL_SECONDARY_COLOR_ARRAY_EXT:
+ CHECK_EXTENSION(EXT_secondary_color);
+ return (ctx->Array.ArrayObj->SecondaryColor.Enabled != 0);
+#if FEATURE_point_size_array
+ case GL_POINT_SIZE_ARRAY_OES:
+ return (ctx->Array.ArrayObj->PointSize.Enabled != 0);
+#endif
+
+ /* GL_SGI_texture_color_table */
+ case GL_TEXTURE_COLOR_TABLE_SGI:
+ CHECK_EXTENSION(SGI_texture_color_table);
+ return ctx->Texture.Unit[ctx->Texture.CurrentUnit].ColorTableEnabled;
+
+ /* GL_ARB_texture_cube_map */
+ case GL_TEXTURE_CUBE_MAP_ARB:
+ CHECK_EXTENSION(ARB_texture_cube_map);
+ return is_texture_enabled(ctx, TEXTURE_CUBE_BIT);
+
+ /* GL_EXT_secondary_color */
+ case GL_COLOR_SUM_EXT:
+ CHECK_EXTENSION2(EXT_secondary_color, ARB_vertex_program);
+ return ctx->Fog.ColorSumEnabled;
+
+ /* GL_ARB_multisample */
+ case GL_MULTISAMPLE_ARB:
+ return ctx->Multisample.Enabled;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE_ARB:
+ return ctx->Multisample.SampleAlphaToCoverage;
+ case GL_SAMPLE_ALPHA_TO_ONE_ARB:
+ return ctx->Multisample.SampleAlphaToOne;
+ case GL_SAMPLE_COVERAGE_ARB:
+ return ctx->Multisample.SampleCoverage;
+ case GL_SAMPLE_COVERAGE_INVERT_ARB:
+ return ctx->Multisample.SampleCoverageInvert;
+
+ /* GL_IBM_rasterpos_clip */
+ case GL_RASTER_POSITION_UNCLIPPED_IBM:
+ CHECK_EXTENSION(IBM_rasterpos_clip);
+ return ctx->Transform.RasterPositionUnclipped;
+
+ /* GL_NV_point_sprite */
+ case GL_POINT_SPRITE_NV:
+ CHECK_EXTENSION2(NV_point_sprite, ARB_point_sprite)
+ return ctx->Point.PointSprite;
+
+#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
+ case GL_VERTEX_PROGRAM_ARB:
+ CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program);
+ return ctx->VertexProgram.Enabled;
+ case GL_VERTEX_PROGRAM_POINT_SIZE_ARB:
+ CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program);
+ return ctx->VertexProgram.PointSizeEnabled;
+ case GL_VERTEX_PROGRAM_TWO_SIDE_ARB:
+ CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program);
+ return ctx->VertexProgram.TwoSideEnabled;
+#endif
+#if FEATURE_NV_vertex_program
+ case GL_VERTEX_ATTRIB_ARRAY0_NV:
+ case GL_VERTEX_ATTRIB_ARRAY1_NV:
+ case GL_VERTEX_ATTRIB_ARRAY2_NV:
+ case GL_VERTEX_ATTRIB_ARRAY3_NV:
+ case GL_VERTEX_ATTRIB_ARRAY4_NV:
+ case GL_VERTEX_ATTRIB_ARRAY5_NV:
+ case GL_VERTEX_ATTRIB_ARRAY6_NV:
+ case GL_VERTEX_ATTRIB_ARRAY7_NV:
+ case GL_VERTEX_ATTRIB_ARRAY8_NV:
+ case GL_VERTEX_ATTRIB_ARRAY9_NV:
+ case GL_VERTEX_ATTRIB_ARRAY10_NV:
+ case GL_VERTEX_ATTRIB_ARRAY11_NV:
+ case GL_VERTEX_ATTRIB_ARRAY12_NV:
+ case GL_VERTEX_ATTRIB_ARRAY13_NV:
+ case GL_VERTEX_ATTRIB_ARRAY14_NV:
+ case GL_VERTEX_ATTRIB_ARRAY15_NV:
+ CHECK_EXTENSION(NV_vertex_program);
+ {
+ GLint n = (GLint) cap - GL_VERTEX_ATTRIB_ARRAY0_NV;
+ ASSERT(n < Elements(ctx->Array.ArrayObj->VertexAttrib));
+ return (ctx->Array.ArrayObj->VertexAttrib[n].Enabled != 0);
+ }
+ case GL_MAP1_VERTEX_ATTRIB0_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB1_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB2_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB3_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB4_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB5_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB6_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB7_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB8_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB9_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB10_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB11_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB12_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB13_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB14_4_NV:
+ case GL_MAP1_VERTEX_ATTRIB15_4_NV:
+ CHECK_EXTENSION(NV_vertex_program);
+ {
+ const GLuint map = (GLuint) (cap - GL_MAP1_VERTEX_ATTRIB0_4_NV);
+ return ctx->Eval.Map1Attrib[map];
+ }
+ case GL_MAP2_VERTEX_ATTRIB0_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB1_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB2_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB3_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB4_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB5_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB6_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB7_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB8_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB9_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB10_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB11_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB12_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB13_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB14_4_NV:
+ case GL_MAP2_VERTEX_ATTRIB15_4_NV:
+ CHECK_EXTENSION(NV_vertex_program);
+ {
+ const GLuint map = (GLuint) (cap - GL_MAP2_VERTEX_ATTRIB0_4_NV);
+ return ctx->Eval.Map2Attrib[map];
+ }
+#endif /* FEATURE_NV_vertex_program */
+
+#if FEATURE_NV_fragment_program
+ case GL_FRAGMENT_PROGRAM_NV:
+ CHECK_EXTENSION(NV_fragment_program);
+ return ctx->FragmentProgram.Enabled;
+#endif /* FEATURE_NV_fragment_program */
+
+ /* GL_NV_texture_rectangle */
+ case GL_TEXTURE_RECTANGLE_NV:
+ CHECK_EXTENSION(NV_texture_rectangle);
+ return is_texture_enabled(ctx, TEXTURE_RECT_BIT);
+
+ /* GL_EXT_stencil_two_side */
+ case GL_STENCIL_TEST_TWO_SIDE_EXT:
+ CHECK_EXTENSION(EXT_stencil_two_side);
+ return ctx->Stencil.TestTwoSide;
+
+#if FEATURE_ARB_fragment_program
+ case GL_FRAGMENT_PROGRAM_ARB:
+ return ctx->FragmentProgram.Enabled;
+#endif /* FEATURE_ARB_fragment_program */
+
+ /* GL_EXT_depth_bounds_test */
+ case GL_DEPTH_BOUNDS_TEST_EXT:
+ CHECK_EXTENSION(EXT_depth_bounds_test);
+ return ctx->Depth.BoundsTest;
+
+ /* GL_ARB_depth_clamp */
+ case GL_DEPTH_CLAMP:
+ CHECK_EXTENSION(ARB_depth_clamp);
+ return ctx->Transform.DepthClamp;
+
+#if FEATURE_ATI_fragment_shader
+ case GL_FRAGMENT_SHADER_ATI:
+ CHECK_EXTENSION(ATI_fragment_shader);
+ return ctx->ATIFragmentShader.Enabled;
+#endif /* FEATURE_ATI_fragment_shader */
+
+ case GL_TEXTURE_CUBE_MAP_SEAMLESS:
+ CHECK_EXTENSION(ARB_seamless_cube_map);
+ return ctx->Texture.CubeMapSeamless;
+
+#if FEATURE_EXT_transform_feedback
+ case GL_RASTERIZER_DISCARD:
+ CHECK_EXTENSION(EXT_transform_feedback);
+ return ctx->TransformFeedback.RasterDiscard;
+#endif
+
+ /* GL_NV_primitive_restart */
+ case GL_PRIMITIVE_RESTART_NV:
+ if (!ctx->Extensions.NV_primitive_restart) {
+ goto invalid_enum_error;
+ }
+ return ctx->Array.PrimitiveRestart;
+
+ /* GL 3.1 primitive restart */
+ case GL_PRIMITIVE_RESTART:
+ if (ctx->VersionMajor * 10 + ctx->VersionMinor < 31) {
+ goto invalid_enum_error;
+ }
+ return ctx->Array.PrimitiveRestart;
+
+ /* GL3.0 - GL_framebuffer_sRGB */
+ case GL_FRAMEBUFFER_SRGB_EXT:
+ CHECK_EXTENSION(EXT_framebuffer_sRGB);
+ return ctx->Color.sRGBEnabled;
+
+ default:
+ goto invalid_enum_error;
+ }
+
+ return GL_FALSE;
+
+invalid_enum_error:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glIsEnabled(0x%x)", (int) cap);
+ return GL_FALSE;
+}
diff --git a/mesalib/src/mesa/main/fbobject.c b/mesalib/src/mesa/main/fbobject.c index 97cbd3c61..b2ff4dc29 100644 --- a/mesalib/src/mesa/main/fbobject.c +++ b/mesalib/src/mesa/main/fbobject.c @@ -1,2487 +1,2494 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -/* - * GL_EXT/ARB_framebuffer_object extensions - * - * Authors: - * Brian Paul - */ - - -#include "buffers.h" -#include "context.h" -#include "enums.h" -#include "fbobject.h" -#include "formats.h" -#include "framebuffer.h" -#include "hash.h" -#include "macros.h" -#include "mfeatures.h" -#include "mtypes.h" -#include "renderbuffer.h" -#include "state.h" -#include "teximage.h" -#include "texobj.h" - - -/** Set this to 1 to help debug FBO incompleteness problems */ -#define DEBUG_FBO 0 - -/** Set this to 1 to debug/log glBlitFramebuffer() calls */ -#define DEBUG_BLIT 0 - - -/** - * Notes: - * - * None of the GL_EXT_framebuffer_object functions are compiled into - * display lists. - */ - - - -/* - * When glGenRender/FramebuffersEXT() is called we insert pointers to - * these placeholder objects into the hash table. - * Later, when the object ID is first bound, we replace the placeholder - * with the real frame/renderbuffer. - */ -static struct gl_framebuffer DummyFramebuffer; -static struct gl_renderbuffer DummyRenderbuffer; - -/* We bind this framebuffer when applications pass a NULL - * drawable/surface in make current. */ -static struct gl_framebuffer IncompleteFramebuffer; - - -#define IS_CUBE_FACE(TARGET) \ - ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \ - (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) - - -static void -delete_dummy_renderbuffer(struct gl_renderbuffer *rb) -{ - /* no op */ -} - -static void -delete_dummy_framebuffer(struct gl_framebuffer *fb) -{ - /* no op */ -} - - -void -_mesa_init_fbobjects(struct gl_context *ctx) -{ - _glthread_INIT_MUTEX(DummyFramebuffer.Mutex); - _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex); - _glthread_INIT_MUTEX(IncompleteFramebuffer.Mutex); - DummyFramebuffer.Delete = delete_dummy_framebuffer; - DummyRenderbuffer.Delete = delete_dummy_renderbuffer; - IncompleteFramebuffer.Delete = delete_dummy_framebuffer; -} - -struct gl_framebuffer * -_mesa_get_incomplete_framebuffer(void) -{ - return &IncompleteFramebuffer; -} - -/** - * Helper routine for getting a gl_renderbuffer. - */ -struct gl_renderbuffer * -_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id) -{ - struct gl_renderbuffer *rb; - - if (id == 0) - return NULL; - - rb = (struct gl_renderbuffer *) - _mesa_HashLookup(ctx->Shared->RenderBuffers, id); - return rb; -} - - -/** - * Helper routine for getting a gl_framebuffer. - */ -struct gl_framebuffer * -_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id) -{ - struct gl_framebuffer *fb; - - if (id == 0) - return NULL; - - fb = (struct gl_framebuffer *) - _mesa_HashLookup(ctx->Shared->FrameBuffers, id); - return fb; -} - - -/** - * Mark the given framebuffer as invalid. This will force the - * test for framebuffer completeness to be done before the framebuffer - * is used. - */ -static void -invalidate_framebuffer(struct gl_framebuffer *fb) -{ - fb->_Status = 0; /* "indeterminate" */ -} - - -/** - * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding - * gl_renderbuffer_attachment object. - * This function is only used for user-created FB objects, not the - * default / window-system FB object. - * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to - * the depth buffer attachment point. - */ -struct gl_renderbuffer_attachment * -_mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, - GLenum attachment) -{ - GLuint i; - - assert(fb->Name > 0); - - switch (attachment) { - case GL_COLOR_ATTACHMENT0_EXT: - case GL_COLOR_ATTACHMENT1_EXT: - case GL_COLOR_ATTACHMENT2_EXT: - case GL_COLOR_ATTACHMENT3_EXT: - case GL_COLOR_ATTACHMENT4_EXT: - case GL_COLOR_ATTACHMENT5_EXT: - case GL_COLOR_ATTACHMENT6_EXT: - case GL_COLOR_ATTACHMENT7_EXT: - case GL_COLOR_ATTACHMENT8_EXT: - case GL_COLOR_ATTACHMENT9_EXT: - case GL_COLOR_ATTACHMENT10_EXT: - case GL_COLOR_ATTACHMENT11_EXT: - case GL_COLOR_ATTACHMENT12_EXT: - case GL_COLOR_ATTACHMENT13_EXT: - case GL_COLOR_ATTACHMENT14_EXT: - case GL_COLOR_ATTACHMENT15_EXT: - i = attachment - GL_COLOR_ATTACHMENT0_EXT; - if (i >= ctx->Const.MaxColorAttachments) { - return NULL; - } - return &fb->Attachment[BUFFER_COLOR0 + i]; - case GL_DEPTH_STENCIL_ATTACHMENT: - /* fall-through */ - case GL_DEPTH_BUFFER: - /* fall-through / new in GL 3.0 */ - case GL_DEPTH_ATTACHMENT_EXT: - return &fb->Attachment[BUFFER_DEPTH]; - case GL_STENCIL_BUFFER: - /* fall-through / new in GL 3.0 */ - case GL_STENCIL_ATTACHMENT_EXT: - return &fb->Attachment[BUFFER_STENCIL]; - default: - return NULL; - } -} - - -/** - * As above, but only used for getting attachments of the default / - * window-system framebuffer (not user-created framebuffer objects). - */ -static struct gl_renderbuffer_attachment * -_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, - GLenum attachment) -{ - assert(fb->Name == 0); - - switch (attachment) { - case GL_FRONT_LEFT: - return &fb->Attachment[BUFFER_FRONT_LEFT]; - case GL_FRONT_RIGHT: - return &fb->Attachment[BUFFER_FRONT_RIGHT]; - case GL_BACK_LEFT: - return &fb->Attachment[BUFFER_BACK_LEFT]; - case GL_BACK_RIGHT: - return &fb->Attachment[BUFFER_BACK_RIGHT]; - case GL_AUX0: - if (fb->Visual.numAuxBuffers == 1) { - return &fb->Attachment[BUFFER_AUX0]; - } - return NULL; - case GL_DEPTH_BUFFER: - /* fall-through / new in GL 3.0 */ - case GL_DEPTH_ATTACHMENT_EXT: - return &fb->Attachment[BUFFER_DEPTH]; - case GL_STENCIL_BUFFER: - /* fall-through / new in GL 3.0 */ - case GL_STENCIL_ATTACHMENT_EXT: - return &fb->Attachment[BUFFER_STENCIL]; - default: - return NULL; - } -} - - - -/** - * Remove any texture or renderbuffer attached to the given attachment - * point. Update reference counts, etc. - */ -void -_mesa_remove_attachment(struct gl_context *ctx, - struct gl_renderbuffer_attachment *att) -{ - if (att->Type == GL_TEXTURE) { - ASSERT(att->Texture); - if (ctx->Driver.FinishRenderTexture) { - /* tell driver that we're done rendering to this texture. */ - ctx->Driver.FinishRenderTexture(ctx, att); - } - _mesa_reference_texobj(&att->Texture, NULL); /* unbind */ - ASSERT(!att->Texture); - } - if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) { - ASSERT(!att->Texture); - _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */ - ASSERT(!att->Renderbuffer); - } - att->Type = GL_NONE; - att->Complete = GL_TRUE; -} - - -/** - * Bind a texture object to an attachment point. - * The previous binding, if any, will be removed first. - */ -void -_mesa_set_texture_attachment(struct gl_context *ctx, - struct gl_framebuffer *fb, - struct gl_renderbuffer_attachment *att, - struct gl_texture_object *texObj, - GLenum texTarget, GLuint level, GLuint zoffset) -{ - if (att->Texture == texObj) { - /* re-attaching same texture */ - ASSERT(att->Type == GL_TEXTURE); - if (ctx->Driver.FinishRenderTexture) - ctx->Driver.FinishRenderTexture(ctx, att); - } - else { - /* new attachment */ - if (ctx->Driver.FinishRenderTexture && att->Texture) - ctx->Driver.FinishRenderTexture(ctx, att); - _mesa_remove_attachment(ctx, att); - att->Type = GL_TEXTURE; - assert(!att->Texture); - _mesa_reference_texobj(&att->Texture, texObj); - } - - /* always update these fields */ - att->TextureLevel = level; - att->CubeMapFace = _mesa_tex_target_to_face(texTarget); - att->Zoffset = zoffset; - att->Complete = GL_FALSE; - - if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { - ctx->Driver.RenderTexture(ctx, fb, att); - } - - invalidate_framebuffer(fb); -} - - -/** - * Bind a renderbuffer to an attachment point. - * The previous binding, if any, will be removed first. - */ -void -_mesa_set_renderbuffer_attachment(struct gl_context *ctx, - struct gl_renderbuffer_attachment *att, - struct gl_renderbuffer *rb) -{ - /* XXX check if re-doing same attachment, exit early */ - _mesa_remove_attachment(ctx, att); - att->Type = GL_RENDERBUFFER_EXT; - att->Texture = NULL; /* just to be safe */ - att->Complete = GL_FALSE; - _mesa_reference_renderbuffer(&att->Renderbuffer, rb); -} - - -/** - * Fallback for ctx->Driver.FramebufferRenderbuffer() - * Attach a renderbuffer object to a framebuffer object. - */ -void -_mesa_framebuffer_renderbuffer(struct gl_context *ctx, - struct gl_framebuffer *fb, - GLenum attachment, struct gl_renderbuffer *rb) -{ - struct gl_renderbuffer_attachment *att; - - _glthread_LOCK_MUTEX(fb->Mutex); - - att = _mesa_get_attachment(ctx, fb, attachment); - ASSERT(att); - if (rb) { - _mesa_set_renderbuffer_attachment(ctx, att, rb); - if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { - /* do stencil attachment here (depth already done above) */ - att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT); - assert(att); - _mesa_set_renderbuffer_attachment(ctx, att, rb); - } - } - else { - _mesa_remove_attachment(ctx, att); - } - - invalidate_framebuffer(fb); - - _glthread_UNLOCK_MUTEX(fb->Mutex); -} - - -/** - * Fallback for ctx->Driver.ValidateFramebuffer() - * Check if the renderbuffer's formats are supported by the software - * renderer. - * Drivers should probably override this. - */ -void -_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) -{ - gl_buffer_index buf; - for (buf = 0; buf < BUFFER_COUNT; buf++) { - const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer; - if (rb) { - switch (rb->_BaseFormat) { - case GL_ALPHA: - case GL_LUMINANCE_ALPHA: - case GL_LUMINANCE: - case GL_INTENSITY: - case GL_RED: - case GL_RG: - fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; - return; - default: - /* render buffer format is supported by software rendering */ - ; - } - } - } -} - - -/** - * For debug only. - */ -static void -att_incomplete(const char *msg) -{ -#if DEBUG_FBO - _mesa_debug(NULL, "attachment incomplete: %s\n", msg); -#else - (void) msg; -#endif -} - - -/** - * For debug only. - */ -static void -fbo_incomplete(const char *msg, int index) -{ -#if DEBUG_FBO - _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); -#else - (void) msg; - (void) index; -#endif -} - - -/** - * Is the given base format a legal format for a color renderbuffer? - */ -GLboolean -_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat) -{ - switch (baseFormat) { - case GL_RGB: - case GL_RGBA: - return GL_TRUE; - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - case GL_INTENSITY: - case GL_ALPHA: - return ctx->Extensions.ARB_framebuffer_object; - case GL_RED: - case GL_RG: - return ctx->Extensions.ARB_texture_rg; - default: - return GL_FALSE; - } -} - - -/** - * Is the given base format a legal format for a depth/stencil renderbuffer? - */ -static GLboolean -is_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat) -{ - switch (baseFormat) { - case GL_DEPTH_COMPONENT: - case GL_DEPTH_STENCIL_EXT: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Test if an attachment point is complete and update its Complete field. - * \param format if GL_COLOR, this is a color attachment point, - * if GL_DEPTH, this is a depth component attachment point, - * if GL_STENCIL, this is a stencil component attachment point. - */ -static void -test_attachment_completeness(const struct gl_context *ctx, GLenum format, - struct gl_renderbuffer_attachment *att) -{ - assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL); - - /* assume complete */ - att->Complete = GL_TRUE; - - /* Look for reasons why the attachment might be incomplete */ - if (att->Type == GL_TEXTURE) { - const struct gl_texture_object *texObj = att->Texture; - struct gl_texture_image *texImage; - GLenum baseFormat; - - if (!texObj) { - att_incomplete("no texobj"); - att->Complete = GL_FALSE; - return; - } - - texImage = texObj->Image[att->CubeMapFace][att->TextureLevel]; - if (!texImage) { - att_incomplete("no teximage"); - att->Complete = GL_FALSE; - return; - } - if (texImage->Width < 1 || texImage->Height < 1) { - att_incomplete("teximage width/height=0"); - printf("texobj = %u\n", texObj->Name); - printf("level = %d\n", att->TextureLevel); - att->Complete = GL_FALSE; - return; - } - if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) { - att_incomplete("bad z offset"); - att->Complete = GL_FALSE; - return; - } - - baseFormat = _mesa_get_format_base_format(texImage->TexFormat); - - if (format == GL_COLOR) { - if (!_mesa_is_legal_color_format(ctx, baseFormat)) { - att_incomplete("bad format"); - att->Complete = GL_FALSE; - return; - } - if (_mesa_is_format_compressed(texImage->TexFormat)) { - att_incomplete("compressed internalformat"); - att->Complete = GL_FALSE; - return; - } - } - else if (format == GL_DEPTH) { - if (baseFormat == GL_DEPTH_COMPONENT) { - /* OK */ - } - else if (ctx->Extensions.EXT_packed_depth_stencil && - ctx->Extensions.ARB_depth_texture && - baseFormat == GL_DEPTH_STENCIL_EXT) { - /* OK */ - } - else { - att->Complete = GL_FALSE; - att_incomplete("bad depth format"); - return; - } - } - else { - ASSERT(format == GL_STENCIL); - if (ctx->Extensions.EXT_packed_depth_stencil && - ctx->Extensions.ARB_depth_texture && - baseFormat == GL_DEPTH_STENCIL_EXT) { - /* OK */ - } - else { - /* no such thing as stencil-only textures */ - att_incomplete("illegal stencil texture"); - att->Complete = GL_FALSE; - return; - } - } - } - else if (att->Type == GL_RENDERBUFFER_EXT) { - const GLenum baseFormat = - _mesa_get_format_base_format(att->Renderbuffer->Format); - - ASSERT(att->Renderbuffer); - if (!att->Renderbuffer->InternalFormat || - att->Renderbuffer->Width < 1 || - att->Renderbuffer->Height < 1) { - att_incomplete("0x0 renderbuffer"); - att->Complete = GL_FALSE; - return; - } - if (format == GL_COLOR) { - if (!_mesa_is_legal_color_format(ctx, baseFormat)) { - att_incomplete("bad renderbuffer color format"); - att->Complete = GL_FALSE; - return; - } - } - else if (format == GL_DEPTH) { - if (baseFormat == GL_DEPTH_COMPONENT) { - /* OK */ - } - else if (ctx->Extensions.EXT_packed_depth_stencil && - baseFormat == GL_DEPTH_STENCIL_EXT) { - /* OK */ - } - else { - att_incomplete("bad renderbuffer depth format"); - att->Complete = GL_FALSE; - return; - } - } - else { - assert(format == GL_STENCIL); - if (baseFormat == GL_STENCIL_INDEX) { - /* OK */ - } - else if (ctx->Extensions.EXT_packed_depth_stencil && - baseFormat == GL_DEPTH_STENCIL_EXT) { - /* OK */ - } - else { - att->Complete = GL_FALSE; - att_incomplete("bad renderbuffer stencil format"); - return; - } - } - } - else { - ASSERT(att->Type == GL_NONE); - /* complete */ - return; - } -} - - -/** - * Test if the given framebuffer object is complete and update its - * Status field with the results. - * Calls the ctx->Driver.ValidateFramebuffer() function to allow the - * driver to make hardware-specific validation/completeness checks. - * Also update the framebuffer's Width and Height fields if the - * framebuffer is complete. - */ -void -_mesa_test_framebuffer_completeness(struct gl_context *ctx, - struct gl_framebuffer *fb) -{ - GLuint numImages; - GLenum intFormat = GL_NONE; /* color buffers' internal format */ - GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0; - GLint numSamples = -1; - GLint i; - GLuint j; - - assert(fb->Name != 0); - - numImages = 0; - fb->Width = 0; - fb->Height = 0; - - /* Start at -2 to more easily loop over all attachment points. - * -2: depth buffer - * -1: stencil buffer - * >=0: color buffer - */ - for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { - struct gl_renderbuffer_attachment *att; - GLenum f; - gl_format mesaFormat; - - /* - * XXX for ARB_fbo, only check color buffers that are named by - * GL_READ_BUFFER and GL_DRAW_BUFFERi. - */ - - /* check for attachment completeness - */ - if (i == -2) { - att = &fb->Attachment[BUFFER_DEPTH]; - test_attachment_completeness(ctx, GL_DEPTH, att); - if (!att->Complete) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; - fbo_incomplete("depth attachment incomplete", -1); - return; - } - } - else if (i == -1) { - att = &fb->Attachment[BUFFER_STENCIL]; - test_attachment_completeness(ctx, GL_STENCIL, att); - if (!att->Complete) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; - fbo_incomplete("stencil attachment incomplete", -1); - return; - } - } - else { - att = &fb->Attachment[BUFFER_COLOR0 + i]; - test_attachment_completeness(ctx, GL_COLOR, att); - if (!att->Complete) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; - fbo_incomplete("color attachment incomplete", i); - return; - } - } - - /* get width, height, format of the renderbuffer/texture - */ - if (att->Type == GL_TEXTURE) { - const struct gl_texture_image *texImg - = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; - minWidth = MIN2(minWidth, texImg->Width); - maxWidth = MAX2(maxWidth, texImg->Width); - minHeight = MIN2(minHeight, texImg->Height); - maxHeight = MAX2(maxHeight, texImg->Height); - f = texImg->_BaseFormat; - mesaFormat = texImg->TexFormat; - numImages++; - if (!_mesa_is_legal_color_format(ctx, f) && - !is_legal_depth_format(ctx, f)) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; - fbo_incomplete("texture attachment incomplete", -1); - return; - } - } - else if (att->Type == GL_RENDERBUFFER_EXT) { - minWidth = MIN2(minWidth, att->Renderbuffer->Width); - maxWidth = MAX2(minWidth, att->Renderbuffer->Width); - minHeight = MIN2(minHeight, att->Renderbuffer->Height); - maxHeight = MAX2(minHeight, att->Renderbuffer->Height); - f = att->Renderbuffer->InternalFormat; - mesaFormat = att->Renderbuffer->Format; - numImages++; - } - else { - assert(att->Type == GL_NONE); - continue; - } - - if (numSamples < 0) { - /* first buffer */ - numSamples = att->Renderbuffer->NumSamples; - } - - /* check if integer color */ - fb->_IntegerColor = _mesa_is_format_integer_color(mesaFormat); - - /* Error-check width, height, format, samples - */ - if (numImages == 1) { - /* save format, num samples */ - if (i >= 0) { - intFormat = f; - } - } - else { - if (!ctx->Extensions.ARB_framebuffer_object) { - /* check that width, height, format are same */ - if (minWidth != maxWidth || minHeight != maxHeight) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; - fbo_incomplete("width or height mismatch", -1); - return; - } - /* check that all color buffer have same format */ - if (intFormat != GL_NONE && f != intFormat) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; - fbo_incomplete("format mismatch", -1); - return; - } - } - if (att->Renderbuffer && - att->Renderbuffer->NumSamples != numSamples) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; - fbo_incomplete("inconsistant number of samples", i); - return; - } - - } - } - -#if FEATURE_GL - if (ctx->API == API_OPENGL) { - /* Check that all DrawBuffers are present */ - for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { - if (fb->ColorDrawBuffer[j] != GL_NONE) { - const struct gl_renderbuffer_attachment *att - = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]); - assert(att); - if (att->Type == GL_NONE) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; - fbo_incomplete("missing drawbuffer", j); - return; - } - } - } - - /* Check that the ReadBuffer is present */ - if (fb->ColorReadBuffer != GL_NONE) { - const struct gl_renderbuffer_attachment *att - = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer); - assert(att); - if (att->Type == GL_NONE) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; - fbo_incomplete("missing readbuffer", -1); - return; - } - } - } -#else - (void) j; -#endif - - if (numImages == 0) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; - fbo_incomplete("no attachments", -1); - return; - } - - /* Provisionally set status = COMPLETE ... */ - fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; - - /* ... but the driver may say the FB is incomplete. - * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED - * if anything. - */ - if (ctx->Driver.ValidateFramebuffer) { - ctx->Driver.ValidateFramebuffer(ctx, fb); - if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { - fbo_incomplete("driver marked FBO as incomplete", -1); - } - } - - if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) { - /* - * Note that if ARB_framebuffer_object is supported and the attached - * renderbuffers/textures are different sizes, the framebuffer - * width/height will be set to the smallest width/height. - */ - fb->Width = minWidth; - fb->Height = minHeight; - - /* finally, update the visual info for the framebuffer */ - _mesa_update_framebuffer_visual(ctx, fb); - } -} - - -GLboolean GLAPIENTRY -_mesa_IsRenderbufferEXT(GLuint renderbuffer) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - if (renderbuffer) { - struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); - if (rb != NULL && rb != &DummyRenderbuffer) - return GL_TRUE; - } - return GL_FALSE; -} - - -void GLAPIENTRY -_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) -{ - struct gl_renderbuffer *newRb; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (target != GL_RENDERBUFFER_EXT) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)"); - return; - } - - /* No need to flush here since the render buffer binding has no - * effect on rendering state. - */ - - if (renderbuffer) { - newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer); - if (newRb == &DummyRenderbuffer) { - /* ID was reserved, but no real renderbuffer object made yet */ - newRb = NULL; - } - else if (!newRb && ctx->Extensions.ARB_framebuffer_object) { - /* All RB IDs must be Gen'd */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)"); - return; - } - - if (!newRb) { - /* create new renderbuffer object */ - newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); - if (!newRb) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); - return; - } - ASSERT(newRb->AllocStorage); - _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); - newRb->RefCount = 1; /* referenced by hash table */ - } - } - else { - newRb = NULL; - } - - ASSERT(newRb != &DummyRenderbuffer); - - _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); -} - - -/** - * If the given renderbuffer is anywhere attached to the framebuffer, detach - * the renderbuffer. - * This is used when a renderbuffer object is deleted. - * The spec calls for unbinding. - */ -static void -detach_renderbuffer(struct gl_context *ctx, - struct gl_framebuffer *fb, - struct gl_renderbuffer *rb) -{ - GLuint i; - for (i = 0; i < BUFFER_COUNT; i++) { - if (fb->Attachment[i].Renderbuffer == rb) { - _mesa_remove_attachment(ctx, &fb->Attachment[i]); - } - } - invalidate_framebuffer(fb); -} - - -void GLAPIENTRY -_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) -{ - GLint i; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - for (i = 0; i < n; i++) { - if (renderbuffers[i] > 0) { - struct gl_renderbuffer *rb; - rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]); - if (rb) { - /* check if deleting currently bound renderbuffer object */ - if (rb == ctx->CurrentRenderbuffer) { - /* bind default */ - ASSERT(rb->RefCount >= 2); - _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); - } - - if (ctx->DrawBuffer->Name) { - detach_renderbuffer(ctx, ctx->DrawBuffer, rb); - } - if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) { - detach_renderbuffer(ctx, ctx->ReadBuffer, rb); - } - - /* Remove from hash table immediately, to free the ID. - * But the object will not be freed until it's no longer - * referenced anywhere else. - */ - _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); - - if (rb != &DummyRenderbuffer) { - /* no longer referenced by hash table */ - _mesa_reference_renderbuffer(&rb, NULL); - } - } - } - } -} - - -void GLAPIENTRY -_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) -{ - GET_CURRENT_CONTEXT(ctx); - GLuint first; - GLint i; - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)"); - return; - } - - if (!renderbuffers) - return; - - first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); - - for (i = 0; i < n; i++) { - GLuint name = first + i; - renderbuffers[i] = name; - /* insert dummy placeholder into hash table */ - _glthread_LOCK_MUTEX(ctx->Shared->Mutex); - _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer); - _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); - } -} - - -/** - * Given an internal format token for a render buffer, return the - * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, - * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE, - * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc). - * - * This is similar to _mesa_base_tex_format() but the set of valid - * internal formats is different. - * - * Note that even if a format is determined to be legal here, validation - * of the FBO may fail if the format is not supported by the driver/GPU. - * - * \param internalFormat as passed to glRenderbufferStorage() - * \return the base internal format, or 0 if internalFormat is illegal - */ -GLenum -_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) -{ - /* - * Notes: some formats such as alpha, luminance, etc. were added - * with GL_ARB_framebuffer_object. - */ - switch (internalFormat) { - case GL_ALPHA: - case GL_ALPHA4: - case GL_ALPHA8: - case GL_ALPHA12: - case GL_ALPHA16: - return ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; - case GL_LUMINANCE: - case GL_LUMINANCE4: - case GL_LUMINANCE8: - case GL_LUMINANCE12: - case GL_LUMINANCE16: - return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; - case GL_LUMINANCE_ALPHA: - case GL_LUMINANCE4_ALPHA4: - case GL_LUMINANCE6_ALPHA2: - case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE12_ALPHA4: - case GL_LUMINANCE12_ALPHA12: - case GL_LUMINANCE16_ALPHA16: - return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; - case GL_INTENSITY: - case GL_INTENSITY4: - case GL_INTENSITY8: - case GL_INTENSITY12: - case GL_INTENSITY16: - return ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; - case GL_RGB: - case GL_R3_G3_B2: - case GL_RGB4: - case GL_RGB5: - case GL_RGB8: - case GL_RGB10: - case GL_RGB12: - case GL_RGB16: - case GL_SRGB8_EXT: - return GL_RGB; - case GL_RGBA: - case GL_RGBA2: - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGBA8: - case GL_RGB10_A2: - case GL_RGBA12: - case GL_RGBA16: - case GL_RGBA16_SNORM: - case GL_SRGB8_ALPHA8_EXT: - return GL_RGBA; - case GL_STENCIL_INDEX: - case GL_STENCIL_INDEX1_EXT: - case GL_STENCIL_INDEX4_EXT: - case GL_STENCIL_INDEX8_EXT: - case GL_STENCIL_INDEX16_EXT: - return GL_STENCIL_INDEX; - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT24: - case GL_DEPTH_COMPONENT32: - return GL_DEPTH_COMPONENT; - case GL_DEPTH_STENCIL_EXT: - case GL_DEPTH24_STENCIL8_EXT: - if (ctx->Extensions.EXT_packed_depth_stencil) - return GL_DEPTH_STENCIL_EXT; - else - return 0; - case GL_RED: - case GL_R8: - case GL_R16: - return ctx->Extensions.ARB_texture_rg ? GL_RED : 0; - case GL_RG: - case GL_RG8: - case GL_RG16: - return ctx->Extensions.ARB_texture_rg ? GL_RG : 0; - /* XXX add floating point and integer formats eventually */ - default: - return 0; - } -} - - -/** sentinal value, see below */ -#define NO_SAMPLES 1000 - - -/** - * Helper function used by _mesa_RenderbufferStorageEXT() and - * _mesa_RenderbufferStorageMultisample(). - * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT(). - */ -static void -renderbuffer_storage(GLenum target, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei samples) -{ - const char *func = samples == NO_SAMPLES ? - "glRenderbufferStorage" : "RenderbufferStorageMultisample"; - struct gl_renderbuffer *rb; - GLenum baseFormat; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (target != GL_RENDERBUFFER_EXT) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); - return; - } - - baseFormat = _mesa_base_fbo_format(ctx, internalFormat); - if (baseFormat == 0) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func); - return; - } - - if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func); - return; - } - - if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func); - return; - } - - if (samples == NO_SAMPLES) { - /* NumSamples == 0 indicates non-multisampling */ - samples = 0; - } - else if (samples > (GLsizei) ctx->Const.MaxSamples) { - /* note: driver may choose to use more samples than what's requested */ - _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func); - return; - } - - rb = ctx->CurrentRenderbuffer; - if (!rb) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); - return; - } - - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - if (rb->InternalFormat == internalFormat && - rb->Width == (GLuint) width && - rb->Height == (GLuint) height) { - /* no change in allocation needed */ - return; - } - - /* These MUST get set by the AllocStorage func */ - rb->Format = MESA_FORMAT_NONE; - rb->NumSamples = samples; - - /* Now allocate the storage */ - ASSERT(rb->AllocStorage); - if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { - /* No error - check/set fields now */ - assert(rb->Format != MESA_FORMAT_NONE); - assert(rb->Width == (GLuint) width); - assert(rb->Height == (GLuint) height); - rb->InternalFormat = internalFormat; - rb->_BaseFormat = baseFormat; - assert(rb->_BaseFormat != 0); - } - else { - /* Probably ran out of memory - clear the fields */ - rb->Width = 0; - rb->Height = 0; - rb->Format = MESA_FORMAT_NONE; - rb->InternalFormat = GL_NONE; - rb->_BaseFormat = GL_NONE; - rb->NumSamples = 0; - } - - /* - test_framebuffer_completeness(ctx, fb); - */ - /* XXX if this renderbuffer is attached anywhere, invalidate attachment - * points??? - */ -} - - -#if FEATURE_OES_EGL_image -void GLAPIENTRY -_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) -{ - struct gl_renderbuffer *rb; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!ctx->Extensions.OES_EGL_image) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glEGLImageTargetRenderbufferStorageOES(unsupported)"); - return; - } - - if (target != GL_RENDERBUFFER) { - _mesa_error(ctx, GL_INVALID_ENUM, - "EGLImageTargetRenderbufferStorageOES"); - return; - } - - rb = ctx->CurrentRenderbuffer; - if (!rb) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "EGLImageTargetRenderbufferStorageOES"); - return; - } - - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image); -} -#endif - - -/** - * Helper function for _mesa_GetRenderbufferParameterivEXT() and - * _mesa_GetFramebufferAttachmentParameterivEXT() - * We have to be careful to respect the base format. For example, if a - * renderbuffer/texture was created with internalFormat=GL_RGB but the - * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE - * we need to return zero. - */ -static GLint -get_component_bits(GLenum pname, GLenum baseFormat, gl_format format) -{ - switch (pname) { - case GL_RENDERBUFFER_RED_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: - if (baseFormat == GL_RGB || baseFormat == GL_RGBA || - baseFormat == GL_RG || baseFormat == GL_RED) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_GREEN_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: - if (baseFormat == GL_RGB || baseFormat == GL_RGBA || baseFormat == GL_RG) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_BLUE_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: - if (baseFormat == GL_RGB || baseFormat == GL_RGBA) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_ALPHA_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: - if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA || - baseFormat == GL_LUMINANCE_ALPHA) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_DEPTH_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: - if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_STENCIL_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: - if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL) - return _mesa_get_format_bits(format, pname); - else - return 0; - default: - return 0; - } -} - - - -void GLAPIENTRY -_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, - GLsizei width, GLsizei height) -{ - /* GL_ARB_fbo says calling this function is equivalent to calling - * glRenderbufferStorageMultisample() with samples=0. We pass in - * a token value here just for error reporting purposes. - */ - renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES); -} - - -void GLAPIENTRY -_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples, - GLenum internalFormat, - GLsizei width, GLsizei height) -{ - renderbuffer_storage(target, internalFormat, width, height, samples); -} - - -/** - * OpenGL ES version of glRenderBufferStorage. - */ -void GLAPIENTRY -_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, - GLsizei width, GLsizei height) -{ - switch (internalFormat) { - case GL_RGB565: - /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */ - /* choose a closest format */ - internalFormat = GL_RGB5; - break; - default: - break; - } - - renderbuffer_storage(target, internalFormat, width, height, 0); -} - - -void GLAPIENTRY -_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) -{ - struct gl_renderbuffer *rb; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (target != GL_RENDERBUFFER_EXT) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetRenderbufferParameterivEXT(target)"); - return; - } - - rb = ctx->CurrentRenderbuffer; - if (!rb) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetRenderbufferParameterivEXT"); - return; - } - - /* No need to flush here since we're just quering state which is - * not effected by rendering. - */ - - switch (pname) { - case GL_RENDERBUFFER_WIDTH_EXT: - *params = rb->Width; - return; - case GL_RENDERBUFFER_HEIGHT_EXT: - *params = rb->Height; - return; - case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: - *params = rb->InternalFormat; - return; - case GL_RENDERBUFFER_RED_SIZE_EXT: - case GL_RENDERBUFFER_GREEN_SIZE_EXT: - case GL_RENDERBUFFER_BLUE_SIZE_EXT: - case GL_RENDERBUFFER_ALPHA_SIZE_EXT: - case GL_RENDERBUFFER_DEPTH_SIZE_EXT: - case GL_RENDERBUFFER_STENCIL_SIZE_EXT: - *params = get_component_bits(pname, rb->_BaseFormat, rb->Format); - break; - case GL_RENDERBUFFER_SAMPLES: - if (ctx->Extensions.ARB_framebuffer_object) { - *params = rb->NumSamples; - break; - } - /* fallthrough */ - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetRenderbufferParameterivEXT(target)"); - return; - } -} - - -GLboolean GLAPIENTRY -_mesa_IsFramebufferEXT(GLuint framebuffer) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - if (framebuffer) { - struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer); - if (rb != NULL && rb != &DummyFramebuffer) - return GL_TRUE; - } - return GL_FALSE; -} - - -/** - * Check if any of the attachments of the given framebuffer are textures - * (render to texture). Call ctx->Driver.RenderTexture() for such - * attachments. - */ -static void -check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) -{ - GLuint i; - ASSERT(ctx->Driver.RenderTexture); - - if (fb->Name == 0) - return; /* can't render to texture with winsys framebuffers */ - - for (i = 0; i < BUFFER_COUNT; i++) { - struct gl_renderbuffer_attachment *att = fb->Attachment + i; - struct gl_texture_object *texObj = att->Texture; - if (texObj - && texObj->Image[att->CubeMapFace][att->TextureLevel]) { - ctx->Driver.RenderTexture(ctx, fb, att); - } - } -} - - -/** - * Examine all the framebuffer's attachments to see if any are textures. - * If so, call ctx->Driver.FinishRenderTexture() for each texture to - * notify the device driver that the texture image may have changed. - */ -static void -check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) -{ - if (fb->Name == 0) - return; /* can't render to texture with winsys framebuffers */ - - if (ctx->Driver.FinishRenderTexture) { - GLuint i; - for (i = 0; i < BUFFER_COUNT; i++) { - struct gl_renderbuffer_attachment *att = fb->Attachment + i; - if (att->Texture && att->Renderbuffer) { - ctx->Driver.FinishRenderTexture(ctx, att); - } - } - } -} - - -void GLAPIENTRY -_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) -{ - struct gl_framebuffer *newDrawFb, *newReadFb; - struct gl_framebuffer *oldDrawFb, *oldReadFb; - GLboolean bindReadBuf, bindDrawBuf; - GET_CURRENT_CONTEXT(ctx); - -#ifdef DEBUG - if (ctx->Extensions.ARB_framebuffer_object) { - ASSERT(ctx->Extensions.EXT_framebuffer_object); - ASSERT(ctx->Extensions.EXT_framebuffer_blit); - } -#endif - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!ctx->Extensions.EXT_framebuffer_object) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBindFramebufferEXT(unsupported)"); - return; - } - - switch (target) { -#if FEATURE_EXT_framebuffer_blit - case GL_DRAW_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); - return; - } - bindDrawBuf = GL_TRUE; - bindReadBuf = GL_FALSE; - break; - case GL_READ_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); - return; - } - bindDrawBuf = GL_FALSE; - bindReadBuf = GL_TRUE; - break; -#endif - case GL_FRAMEBUFFER_EXT: - bindDrawBuf = GL_TRUE; - bindReadBuf = GL_TRUE; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); - return; - } - - if (framebuffer) { - /* Binding a user-created framebuffer object */ - newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer); - if (newDrawFb == &DummyFramebuffer) { - /* ID was reserved, but no real framebuffer object made yet */ - newDrawFb = NULL; - } - else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) { - /* All FBO IDs must be Gen'd */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)"); - return; - } - - if (!newDrawFb) { - /* create new framebuffer object */ - newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); - if (!newDrawFb) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); - return; - } - _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb); - } - newReadFb = newDrawFb; - } - else { - /* Binding the window system framebuffer (which was originally set - * with MakeCurrent). - */ - newDrawFb = ctx->WinSysDrawBuffer; - newReadFb = ctx->WinSysReadBuffer; - } - - ASSERT(newDrawFb); - ASSERT(newDrawFb != &DummyFramebuffer); - - /* save pointers to current/old framebuffers */ - oldDrawFb = ctx->DrawBuffer; - oldReadFb = ctx->ReadBuffer; - - /* check if really changing bindings */ - if (oldDrawFb == newDrawFb) - bindDrawBuf = GL_FALSE; - if (oldReadFb == newReadFb) - bindReadBuf = GL_FALSE; - - /* - * OK, now bind the new Draw/Read framebuffers, if they're changing. - * - * We also check if we're beginning and/or ending render-to-texture. - * When a framebuffer with texture attachments is unbound, call - * ctx->Driver.FinishRenderTexture(). - * When a framebuffer with texture attachments is bound, call - * ctx->Driver.RenderTexture(). - * - * Note that if the ReadBuffer has texture attachments we don't consider - * that a render-to-texture case. - */ - if (bindReadBuf) { - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - /* check if old readbuffer was render-to-texture */ - check_end_texture_render(ctx, oldReadFb); - - _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb); - } - - if (bindDrawBuf) { - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - /* check if old read/draw buffers were render-to-texture */ - if (!bindReadBuf) - check_end_texture_render(ctx, oldReadFb); - - if (oldDrawFb != oldReadFb) - check_end_texture_render(ctx, oldDrawFb); - - /* check if newly bound framebuffer has any texture attachments */ - check_begin_texture_render(ctx, newDrawFb); - - _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb); - } - - if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) { - ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb); - } -} - - -void GLAPIENTRY -_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) -{ - GLint i; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - for (i = 0; i < n; i++) { - if (framebuffers[i] > 0) { - struct gl_framebuffer *fb; - fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]); - if (fb) { - ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); - - /* check if deleting currently bound framebuffer object */ - if (ctx->Extensions.EXT_framebuffer_blit) { - /* separate draw/read binding points */ - if (fb == ctx->DrawBuffer) { - /* bind default */ - ASSERT(fb->RefCount >= 2); - _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); - } - if (fb == ctx->ReadBuffer) { - /* bind default */ - ASSERT(fb->RefCount >= 2); - _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); - } - } - else { - /* only one binding point for read/draw buffers */ - if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) { - /* bind default */ - ASSERT(fb->RefCount >= 2); - _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - } - } - - /* remove from hash table immediately, to free the ID */ - _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); - - if (fb != &DummyFramebuffer) { - /* But the object will not be freed until it's no longer - * bound in any context. - */ - _mesa_reference_framebuffer(&fb, NULL); - } - } - } - } -} - - -void GLAPIENTRY -_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers) -{ - GET_CURRENT_CONTEXT(ctx); - GLuint first; - GLint i; - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); - return; - } - - if (!framebuffers) - return; - - first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); - - for (i = 0; i < n; i++) { - GLuint name = first + i; - framebuffers[i] = name; - /* insert dummy placeholder into hash table */ - _glthread_LOCK_MUTEX(ctx->Shared->Mutex); - _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); - _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); - } -} - - - -GLenum GLAPIENTRY -_mesa_CheckFramebufferStatusEXT(GLenum target) -{ - struct gl_framebuffer *buffer; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); - - switch (target) { -#if FEATURE_EXT_framebuffer_blit - case GL_DRAW_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); - return 0; - } - buffer = ctx->DrawBuffer; - break; - case GL_READ_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); - return 0; - } - buffer = ctx->ReadBuffer; - break; -#endif - case GL_FRAMEBUFFER_EXT: - buffer = ctx->DrawBuffer; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); - return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */ - } - - if (buffer->Name == 0) { - /* The window system / default framebuffer is always complete */ - return GL_FRAMEBUFFER_COMPLETE_EXT; - } - - /* No need to flush here */ - - if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) { - _mesa_test_framebuffer_completeness(ctx, buffer); - } - - return buffer->_Status; -} - - - -/** - * Common code called by glFramebufferTexture1D/2D/3DEXT(). - */ -static void -framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, - GLenum attachment, GLenum textarget, GLuint texture, - GLint level, GLint zoffset) -{ - struct gl_renderbuffer_attachment *att; - struct gl_texture_object *texObj = NULL; - struct gl_framebuffer *fb; - GLboolean error = GL_FALSE; - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - switch (target) { - case GL_READ_FRAMEBUFFER_EXT: - error = !ctx->Extensions.EXT_framebuffer_blit; - fb = ctx->ReadBuffer; - break; - case GL_DRAW_FRAMEBUFFER_EXT: - error = !ctx->Extensions.EXT_framebuffer_blit; - /* fall-through */ - case GL_FRAMEBUFFER_EXT: - fb = ctx->DrawBuffer; - break; - default: - error = GL_TRUE; - } - - if (error) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture%sEXT(target=0x%x)", caller, target); - return; - } - - ASSERT(fb); - - /* check framebuffer binding */ - if (fb->Name == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture%sEXT", caller); - return; - } - - - /* The textarget, level, and zoffset parameters are only validated if - * texture is non-zero. - */ - if (texture) { - GLboolean err = GL_TRUE; - - texObj = _mesa_lookup_texture(ctx, texture); - if (texObj != NULL) { - if (textarget == 0) { - /* XXX what's the purpose of this? */ - err = (texObj->Target != GL_TEXTURE_3D) && - (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && - (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT); - } - else { - err = (texObj->Target == GL_TEXTURE_CUBE_MAP) - ? !IS_CUBE_FACE(textarget) - : (texObj->Target != textarget); - } - } - else { - /* can't render to a non-existant texture */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture%sEXT(non existant texture)", - caller); - return; - } - - if (err) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture%sEXT(texture target mismatch)", - caller); - return; - } - - if (texObj->Target == GL_TEXTURE_3D) { - const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); - if (zoffset < 0 || zoffset >= maxSize) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture%sEXT(zoffset)", caller); - return; - } - } - else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || - (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) { - if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture%sEXT(layer)", caller); - return; - } - } - - if ((level < 0) || - (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture%sEXT(level)", caller); - return; - } - } - - att = _mesa_get_attachment(ctx, fb, attachment); - if (att == NULL) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture%sEXT(attachment)", caller); - return; - } - - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - _glthread_LOCK_MUTEX(fb->Mutex); - if (texObj) { - _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, - level, zoffset); - /* Set the render-to-texture flag. We'll check this flag in - * glTexImage() and friends to determine if we need to revalidate - * any FBOs that might be rendering into this texture. - * This flag never gets cleared since it's non-trivial to determine - * when all FBOs might be done rendering to this texture. That's OK - * though since it's uncommon to render to a texture then repeatedly - * call glTexImage() to change images in the texture. - */ - texObj->_RenderToTexture = GL_TRUE; - } - else { - _mesa_remove_attachment(ctx, att); - } - - invalidate_framebuffer(fb); - - _glthread_UNLOCK_MUTEX(fb->Mutex); -} - - - -void GLAPIENTRY -_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, GLint level) -{ - GET_CURRENT_CONTEXT(ctx); - - if ((texture != 0) && (textarget != GL_TEXTURE_1D)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture1DEXT(textarget)"); - return; - } - - framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, - level, 0); -} - - -void GLAPIENTRY -_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, GLint level) -{ - GET_CURRENT_CONTEXT(ctx); - - if ((texture != 0) && - (textarget != GL_TEXTURE_2D) && - (textarget != GL_TEXTURE_RECTANGLE_ARB) && - (!IS_CUBE_FACE(textarget))) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture2DEXT(textarget=0x%x)", textarget); - return; - } - - framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, - level, 0); -} - - -void GLAPIENTRY -_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, - GLint level, GLint zoffset) -{ - GET_CURRENT_CONTEXT(ctx); - - if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture3DEXT(textarget)"); - return; - } - - framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, - level, zoffset); -} - - -void GLAPIENTRY -_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment, - GLuint texture, GLint level, GLint layer) -{ - GET_CURRENT_CONTEXT(ctx); - - framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, - level, layer); -} - - -void GLAPIENTRY -_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, - GLenum renderbufferTarget, - GLuint renderbuffer) -{ - struct gl_renderbuffer_attachment *att; - struct gl_framebuffer *fb; - struct gl_renderbuffer *rb; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - switch (target) { -#if FEATURE_EXT_framebuffer_blit - case GL_DRAW_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbufferEXT(target)"); - return; - } - fb = ctx->DrawBuffer; - break; - case GL_READ_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbufferEXT(target)"); - return; - } - fb = ctx->ReadBuffer; - break; -#endif - case GL_FRAMEBUFFER_EXT: - fb = ctx->DrawBuffer; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbufferEXT(target)"); - return; - } - - if (renderbufferTarget != GL_RENDERBUFFER_EXT) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbufferEXT(renderbufferTarget)"); - return; - } - - if (fb->Name == 0) { - /* Can't attach new renderbuffers to a window system framebuffer */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); - return; - } - - att = _mesa_get_attachment(ctx, fb, attachment); - if (att == NULL) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbufferEXT(invalid attachment %s)", - _mesa_lookup_enum_by_nr(attachment)); - return; - } - - if (renderbuffer) { - rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); - if (!rb) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferRenderbufferEXT(non-existant" - " renderbuffer %u)", renderbuffer); - return; - } - else if (rb == &DummyRenderbuffer) { - /* This is what NVIDIA does */ - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferRenderbufferEXT(renderbuffer %u)", - renderbuffer); - return; - } - } - else { - /* remove renderbuffer attachment */ - rb = NULL; - } - - if (attachment == GL_DEPTH_STENCIL_ATTACHMENT && - rb && rb->Format != MESA_FORMAT_NONE) { - /* make sure the renderbuffer is a depth/stencil format */ - const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); - if (baseFormat != GL_DEPTH_STENCIL) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferRenderbufferEXT(renderbuffer" - " is not DEPTH_STENCIL format)"); - return; - } - } - - - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - assert(ctx->Driver.FramebufferRenderbuffer); - ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); - - /* Some subsequent GL commands may depend on the framebuffer's visual - * after the binding is updated. Update visual info now. - */ - _mesa_update_framebuffer_visual(ctx, fb); -} - - -void GLAPIENTRY -_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, - GLenum pname, GLint *params) -{ - const struct gl_renderbuffer_attachment *att; - struct gl_framebuffer *buffer; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - switch (target) { -#if FEATURE_EXT_framebuffer_blit - case GL_DRAW_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(target)"); - return; - } - buffer = ctx->DrawBuffer; - break; - case GL_READ_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(target)"); - return; - } - buffer = ctx->ReadBuffer; - break; -#endif - case GL_FRAMEBUFFER_EXT: - buffer = ctx->DrawBuffer; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(target)"); - return; - } - - if (buffer->Name == 0) { - /* the default / window-system FBO */ - att = _mesa_get_fb0_attachment(ctx, buffer, attachment); - } - else { - /* user-created framebuffer FBO */ - att = _mesa_get_attachment(ctx, buffer, attachment); - } - - if (att == NULL) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(attachment)"); - return; - } - - if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { - /* the depth and stencil attachments must point to the same buffer */ - const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt; - depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT); - stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT); - if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL" - " attachments differ)"); - return; - } - } - - /* No need to flush here */ - - switch (pname) { - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: - *params = buffer->Name == 0 ? GL_FRAMEBUFFER_DEFAULT : att->Type; - return; - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: - if (att->Type == GL_RENDERBUFFER_EXT) { - *params = att->Renderbuffer->Name; - } - else if (att->Type == GL_TEXTURE) { - *params = att->Texture->Name; - } - else { - assert(att->Type == GL_NONE); - *params = 0; - } - return; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: - if (att->Type == GL_TEXTURE) { - *params = att->TextureLevel; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - } - return; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: - if (att->Type == GL_TEXTURE) { - if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) { - *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; - } - else { - *params = 0; - } - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - } - return; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: - if (att->Type == GL_TEXTURE) { - if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) { - *params = att->Zoffset; - } - else { - *params = 0; - } - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - } - return; - case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: - if (!ctx->Extensions.ARB_framebuffer_object) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - } - else { - if (ctx->Extensions.EXT_framebuffer_sRGB && ctx->Const.sRGBCapable) { - *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format); - } - else { - /* According to ARB_framebuffer_sRGB, we should return LINEAR - * if the sRGB conversion is unsupported. */ - *params = GL_LINEAR; - } - } - return; - case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: - if (!ctx->Extensions.ARB_framebuffer_object) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - return; - } - else { - gl_format format = att->Renderbuffer->Format; - if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) { - /* special cases */ - *params = GL_INDEX; - } - else { - *params = _mesa_get_format_datatype(format); - } - } - return; - case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: - if (!ctx->Extensions.ARB_framebuffer_object) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - } - else if (att->Texture) { - const struct gl_texture_image *texImage = - _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target, - att->TextureLevel); - if (texImage) { - *params = get_component_bits(pname, texImage->_BaseFormat, - texImage->TexFormat); - } - else { - *params = 0; - } - } - else if (att->Renderbuffer) { - *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat, - att->Renderbuffer->Format); - } - else { - *params = 0; - } - return; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - return; - } -} - - -void GLAPIENTRY -_mesa_GenerateMipmapEXT(GLenum target) -{ - struct gl_texture_object *texObj; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - switch (target) { - case GL_TEXTURE_1D: - case GL_TEXTURE_2D: - case GL_TEXTURE_3D: - case GL_TEXTURE_CUBE_MAP: - /* OK, legal value */ - break; - default: - /* XXX need to implement GL_TEXTURE_1D_ARRAY and GL_TEXTURE_2D_ARRAY */ - _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)"); - return; - } - - texObj = _mesa_get_current_tex_object(ctx, target); - - if (texObj->BaseLevel >= texObj->MaxLevel) { - /* nothing to do */ - return; - } - - if (texObj->Target == GL_TEXTURE_CUBE_MAP && - !_mesa_cube_complete(texObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGenerateMipmap(incomplete cube map)"); - return; - } - - _mesa_lock_texture(ctx, texObj); - if (target == GL_TEXTURE_CUBE_MAP) { - GLuint face; - for (face = 0; face < 6; face++) - ctx->Driver.GenerateMipmap(ctx, - GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face, - texObj); - } - else { - ctx->Driver.GenerateMipmap(ctx, target, texObj); - } - _mesa_unlock_texture(ctx, texObj); -} - - -#if FEATURE_EXT_framebuffer_blit - -static const struct gl_renderbuffer_attachment * -find_attachment(const struct gl_framebuffer *fb, - const struct gl_renderbuffer *rb) -{ - GLuint i; - for (i = 0; i < Elements(fb->Attachment); i++) { - if (fb->Attachment[i].Renderbuffer == rb) - return &fb->Attachment[i]; - } - return NULL; -} - - - -/** - * Blit rectangular region, optionally from one framebuffer to another. - * - * Note, if the src buffer is multisampled and the dest is not, this is - * when the samples must be resolved to a single color. - */ -void GLAPIENTRY -_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter) -{ - const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT | - GL_DEPTH_BUFFER_BIT | - GL_STENCIL_BUFFER_BIT); - const struct gl_framebuffer *readFb, *drawFb; - const struct gl_renderbuffer *colorReadRb, *colorDrawRb; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - if (ctx->NewState) { - _mesa_update_state(ctx); - } - - readFb = ctx->ReadBuffer; - drawFb = ctx->DrawBuffer; - - if (!readFb || !drawFb) { - /* This will normally never happen but someday we may want to - * support MakeCurrent() with no drawables. - */ - return; - } - - /* check for complete framebuffers */ - if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || - readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { - _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, - "glBlitFramebufferEXT(incomplete draw/read buffers)"); - return; - } - - if (filter != GL_NEAREST && filter != GL_LINEAR) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)"); - return; - } - - if (mask & ~legalMaskBits) { - _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)"); - return; - } - - /* depth/stencil must be blitted with nearest filtering */ - if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) - && filter != GL_NEAREST) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter"); - return; - } - - /* get color read/draw renderbuffers */ - if (mask & GL_COLOR_BUFFER_BIT) { - colorReadRb = readFb->_ColorReadBuffer; - colorDrawRb = drawFb->_ColorDrawBuffers[0]; - } - else { - colorReadRb = colorDrawRb = NULL; - } - - if (mask & GL_STENCIL_BUFFER_BIT) { - struct gl_renderbuffer *readRb = readFb->_StencilBuffer; - struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer; - if (!readRb || - !drawRb || - _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) != - _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(stencil buffer size mismatch"); - return; - } - } - - if (mask & GL_DEPTH_BUFFER_BIT) { - struct gl_renderbuffer *readRb = readFb->_DepthBuffer; - struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer; - if (!readRb || - !drawRb || - _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) != - _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(depth buffer size mismatch"); - return; - } - } - - if (readFb->Visual.samples > 0 && - drawFb->Visual.samples > 0 && - readFb->Visual.samples != drawFb->Visual.samples) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(mismatched samples"); - return; - } - - /* extra checks for multisample copies... */ - if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) { - /* src and dest region sizes must be the same */ - if (srcX1 - srcX0 != dstX1 - dstX0 || - srcY1 - srcY0 != dstY1 - dstY0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(bad src/dst multisample region sizes"); - return; - } - - /* color formats must match */ - if (colorReadRb && - colorDrawRb && - colorReadRb->Format != colorDrawRb->Format) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(bad src/dst multisample pixel formats"); - return; - } - } - - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT"); - return; - } - - /* Debug code */ - if (DEBUG_BLIT) { - printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d," - " 0x%x, 0x%x)\n", - srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, - mask, filter); - if (colorReadRb) { - const struct gl_renderbuffer_attachment *att; - - att = find_attachment(readFb, colorReadRb); - printf(" Src FBO %u RB %u (%dx%d) ", - readFb->Name, colorReadRb->Name, - colorReadRb->Width, colorReadRb->Height); - if (att && att->Texture) { - printf("Tex %u tgt 0x%x level %u face %u", - att->Texture->Name, - att->Texture->Target, - att->TextureLevel, - att->CubeMapFace); - } - printf("\n"); - - att = find_attachment(drawFb, colorDrawRb); - printf(" Dst FBO %u RB %u (%dx%d) ", - drawFb->Name, colorDrawRb->Name, - colorDrawRb->Width, colorDrawRb->Height); - if (att && att->Texture) { - printf("Tex %u tgt 0x%x level %u face %u", - att->Texture->Name, - att->Texture->Target, - att->TextureLevel, - att->CubeMapFace); - } - printf("\n"); - } - } - - ASSERT(ctx->Driver.BlitFramebuffer); - ctx->Driver.BlitFramebuffer(ctx, - srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, - mask, filter); -} -#endif /* FEATURE_EXT_framebuffer_blit */ - -#if FEATURE_ARB_geometry_shader4 -void GLAPIENTRY -_mesa_FramebufferTextureARB(GLenum target, GLenum attachment, - GLuint texture, GLint level) -{ - GET_CURRENT_CONTEXT(ctx); - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTextureARB " - "not implemented!"); -} - -void GLAPIENTRY -_mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment, - GLuint texture, GLint level, GLenum face) -{ - GET_CURRENT_CONTEXT(ctx); - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTextureFaceARB " - "not implemented!"); -} -#endif /* FEATURE_ARB_geometry_shader4 */ +/*
+ * Mesa 3-D graphics library
+ * Version: 7.1
+ *
+ * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
+ * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * GL_EXT/ARB_framebuffer_object extensions
+ *
+ * Authors:
+ * Brian Paul
+ */
+
+
+#include "buffers.h"
+#include "context.h"
+#include "enums.h"
+#include "fbobject.h"
+#include "formats.h"
+#include "framebuffer.h"
+#include "hash.h"
+#include "macros.h"
+#include "mfeatures.h"
+#include "mtypes.h"
+#include "renderbuffer.h"
+#include "state.h"
+#include "teximage.h"
+#include "texobj.h"
+
+
+/** Set this to 1 to help debug FBO incompleteness problems */
+#define DEBUG_FBO 0
+
+/** Set this to 1 to debug/log glBlitFramebuffer() calls */
+#define DEBUG_BLIT 0
+
+
+/**
+ * Notes:
+ *
+ * None of the GL_EXT_framebuffer_object functions are compiled into
+ * display lists.
+ */
+
+
+
+/*
+ * When glGenRender/FramebuffersEXT() is called we insert pointers to
+ * these placeholder objects into the hash table.
+ * Later, when the object ID is first bound, we replace the placeholder
+ * with the real frame/renderbuffer.
+ */
+static struct gl_framebuffer DummyFramebuffer;
+static struct gl_renderbuffer DummyRenderbuffer;
+
+/* We bind this framebuffer when applications pass a NULL
+ * drawable/surface in make current. */
+static struct gl_framebuffer IncompleteFramebuffer;
+
+
+#define IS_CUBE_FACE(TARGET) \
+ ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
+ (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
+
+
+static void
+delete_dummy_renderbuffer(struct gl_renderbuffer *rb)
+{
+ /* no op */
+}
+
+static void
+delete_dummy_framebuffer(struct gl_framebuffer *fb)
+{
+ /* no op */
+}
+
+
+void
+_mesa_init_fbobjects(struct gl_context *ctx)
+{
+ _glthread_INIT_MUTEX(DummyFramebuffer.Mutex);
+ _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex);
+ _glthread_INIT_MUTEX(IncompleteFramebuffer.Mutex);
+ DummyFramebuffer.Delete = delete_dummy_framebuffer;
+ DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
+ IncompleteFramebuffer.Delete = delete_dummy_framebuffer;
+}
+
+struct gl_framebuffer *
+_mesa_get_incomplete_framebuffer(void)
+{
+ return &IncompleteFramebuffer;
+}
+
+/**
+ * Helper routine for getting a gl_renderbuffer.
+ */
+struct gl_renderbuffer *
+_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id)
+{
+ struct gl_renderbuffer *rb;
+
+ if (id == 0)
+ return NULL;
+
+ rb = (struct gl_renderbuffer *)
+ _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
+ return rb;
+}
+
+
+/**
+ * Helper routine for getting a gl_framebuffer.
+ */
+struct gl_framebuffer *
+_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id)
+{
+ struct gl_framebuffer *fb;
+
+ if (id == 0)
+ return NULL;
+
+ fb = (struct gl_framebuffer *)
+ _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
+ return fb;
+}
+
+
+/**
+ * Mark the given framebuffer as invalid. This will force the
+ * test for framebuffer completeness to be done before the framebuffer
+ * is used.
+ */
+static void
+invalidate_framebuffer(struct gl_framebuffer *fb)
+{
+ fb->_Status = 0; /* "indeterminate" */
+}
+
+
+/**
+ * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
+ * gl_renderbuffer_attachment object.
+ * This function is only used for user-created FB objects, not the
+ * default / window-system FB object.
+ * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
+ * the depth buffer attachment point.
+ */
+struct gl_renderbuffer_attachment *
+_mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
+ GLenum attachment)
+{
+ GLuint i;
+
+ assert(fb->Name > 0);
+
+ switch (attachment) {
+ case GL_COLOR_ATTACHMENT0_EXT:
+ case GL_COLOR_ATTACHMENT1_EXT:
+ case GL_COLOR_ATTACHMENT2_EXT:
+ case GL_COLOR_ATTACHMENT3_EXT:
+ case GL_COLOR_ATTACHMENT4_EXT:
+ case GL_COLOR_ATTACHMENT5_EXT:
+ case GL_COLOR_ATTACHMENT6_EXT:
+ case GL_COLOR_ATTACHMENT7_EXT:
+ case GL_COLOR_ATTACHMENT8_EXT:
+ case GL_COLOR_ATTACHMENT9_EXT:
+ case GL_COLOR_ATTACHMENT10_EXT:
+ case GL_COLOR_ATTACHMENT11_EXT:
+ case GL_COLOR_ATTACHMENT12_EXT:
+ case GL_COLOR_ATTACHMENT13_EXT:
+ case GL_COLOR_ATTACHMENT14_EXT:
+ case GL_COLOR_ATTACHMENT15_EXT:
+ i = attachment - GL_COLOR_ATTACHMENT0_EXT;
+ if (i >= ctx->Const.MaxColorAttachments) {
+ return NULL;
+ }
+ return &fb->Attachment[BUFFER_COLOR0 + i];
+ case GL_DEPTH_STENCIL_ATTACHMENT:
+ /* fall-through */
+ case GL_DEPTH_BUFFER:
+ /* fall-through / new in GL 3.0 */
+ case GL_DEPTH_ATTACHMENT_EXT:
+ return &fb->Attachment[BUFFER_DEPTH];
+ case GL_STENCIL_BUFFER:
+ /* fall-through / new in GL 3.0 */
+ case GL_STENCIL_ATTACHMENT_EXT:
+ return &fb->Attachment[BUFFER_STENCIL];
+ default:
+ return NULL;
+ }
+}
+
+
+/**
+ * As above, but only used for getting attachments of the default /
+ * window-system framebuffer (not user-created framebuffer objects).
+ */
+static struct gl_renderbuffer_attachment *
+_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
+ GLenum attachment)
+{
+ assert(fb->Name == 0);
+
+ switch (attachment) {
+ case GL_FRONT_LEFT:
+ return &fb->Attachment[BUFFER_FRONT_LEFT];
+ case GL_FRONT_RIGHT:
+ return &fb->Attachment[BUFFER_FRONT_RIGHT];
+ case GL_BACK_LEFT:
+ return &fb->Attachment[BUFFER_BACK_LEFT];
+ case GL_BACK_RIGHT:
+ return &fb->Attachment[BUFFER_BACK_RIGHT];
+ case GL_AUX0:
+ if (fb->Visual.numAuxBuffers == 1) {
+ return &fb->Attachment[BUFFER_AUX0];
+ }
+ return NULL;
+ case GL_DEPTH_BUFFER:
+ /* fall-through / new in GL 3.0 */
+ case GL_DEPTH_ATTACHMENT_EXT:
+ return &fb->Attachment[BUFFER_DEPTH];
+ case GL_STENCIL_BUFFER:
+ /* fall-through / new in GL 3.0 */
+ case GL_STENCIL_ATTACHMENT_EXT:
+ return &fb->Attachment[BUFFER_STENCIL];
+ default:
+ return NULL;
+ }
+}
+
+
+
+/**
+ * Remove any texture or renderbuffer attached to the given attachment
+ * point. Update reference counts, etc.
+ */
+void
+_mesa_remove_attachment(struct gl_context *ctx,
+ struct gl_renderbuffer_attachment *att)
+{
+ if (att->Type == GL_TEXTURE) {
+ ASSERT(att->Texture);
+ if (ctx->Driver.FinishRenderTexture) {
+ /* tell driver that we're done rendering to this texture. */
+ ctx->Driver.FinishRenderTexture(ctx, att);
+ }
+ _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
+ ASSERT(!att->Texture);
+ }
+ if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
+ ASSERT(!att->Texture);
+ _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
+ ASSERT(!att->Renderbuffer);
+ }
+ att->Type = GL_NONE;
+ att->Complete = GL_TRUE;
+}
+
+
+/**
+ * Bind a texture object to an attachment point.
+ * The previous binding, if any, will be removed first.
+ */
+void
+_mesa_set_texture_attachment(struct gl_context *ctx,
+ struct gl_framebuffer *fb,
+ struct gl_renderbuffer_attachment *att,
+ struct gl_texture_object *texObj,
+ GLenum texTarget, GLuint level, GLuint zoffset)
+{
+ if (att->Texture == texObj) {
+ /* re-attaching same texture */
+ ASSERT(att->Type == GL_TEXTURE);
+ if (ctx->Driver.FinishRenderTexture)
+ ctx->Driver.FinishRenderTexture(ctx, att);
+ }
+ else {
+ /* new attachment */
+ if (ctx->Driver.FinishRenderTexture && att->Texture)
+ ctx->Driver.FinishRenderTexture(ctx, att);
+ _mesa_remove_attachment(ctx, att);
+ att->Type = GL_TEXTURE;
+ assert(!att->Texture);
+ _mesa_reference_texobj(&att->Texture, texObj);
+ }
+
+ /* always update these fields */
+ att->TextureLevel = level;
+ att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
+ att->Zoffset = zoffset;
+ att->Complete = GL_FALSE;
+
+ if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
+ ctx->Driver.RenderTexture(ctx, fb, att);
+ }
+
+ invalidate_framebuffer(fb);
+}
+
+
+/**
+ * Bind a renderbuffer to an attachment point.
+ * The previous binding, if any, will be removed first.
+ */
+void
+_mesa_set_renderbuffer_attachment(struct gl_context *ctx,
+ struct gl_renderbuffer_attachment *att,
+ struct gl_renderbuffer *rb)
+{
+ /* XXX check if re-doing same attachment, exit early */
+ _mesa_remove_attachment(ctx, att);
+ att->Type = GL_RENDERBUFFER_EXT;
+ att->Texture = NULL; /* just to be safe */
+ att->Complete = GL_FALSE;
+ _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
+}
+
+
+/**
+ * Fallback for ctx->Driver.FramebufferRenderbuffer()
+ * Attach a renderbuffer object to a framebuffer object.
+ */
+void
+_mesa_framebuffer_renderbuffer(struct gl_context *ctx,
+ struct gl_framebuffer *fb,
+ GLenum attachment, struct gl_renderbuffer *rb)
+{
+ struct gl_renderbuffer_attachment *att;
+
+ _glthread_LOCK_MUTEX(fb->Mutex);
+
+ att = _mesa_get_attachment(ctx, fb, attachment);
+ ASSERT(att);
+ if (rb) {
+ _mesa_set_renderbuffer_attachment(ctx, att, rb);
+ if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
+ /* do stencil attachment here (depth already done above) */
+ att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
+ assert(att);
+ _mesa_set_renderbuffer_attachment(ctx, att, rb);
+ }
+ }
+ else {
+ _mesa_remove_attachment(ctx, att);
+ }
+
+ invalidate_framebuffer(fb);
+
+ _glthread_UNLOCK_MUTEX(fb->Mutex);
+}
+
+
+/**
+ * Fallback for ctx->Driver.ValidateFramebuffer()
+ * Check if the renderbuffer's formats are supported by the software
+ * renderer.
+ * Drivers should probably override this.
+ */
+void
+_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
+{
+ gl_buffer_index buf;
+ for (buf = 0; buf < BUFFER_COUNT; buf++) {
+ const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer;
+ if (rb) {
+ switch (rb->_BaseFormat) {
+ case GL_ALPHA:
+ case GL_LUMINANCE_ALPHA:
+ case GL_LUMINANCE:
+ case GL_INTENSITY:
+ case GL_RED:
+ case GL_RG:
+ fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
+ return;
+ default:
+ /* render buffer format is supported by software rendering */
+ ;
+ }
+ }
+ }
+}
+
+
+/**
+ * For debug only.
+ */
+static void
+att_incomplete(const char *msg)
+{
+#if DEBUG_FBO
+ _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
+#else
+ (void) msg;
+#endif
+}
+
+
+/**
+ * For debug only.
+ */
+static void
+fbo_incomplete(const char *msg, int index)
+{
+#if DEBUG_FBO
+ _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
+#else
+ (void) msg;
+ (void) index;
+#endif
+}
+
+
+/**
+ * Is the given base format a legal format for a color renderbuffer?
+ */
+GLboolean
+_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat)
+{
+ switch (baseFormat) {
+ case GL_RGB:
+ case GL_RGBA:
+ return GL_TRUE;
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ case GL_INTENSITY:
+ case GL_ALPHA:
+ return ctx->Extensions.ARB_framebuffer_object;
+ case GL_RED:
+ case GL_RG:
+ return ctx->Extensions.ARB_texture_rg;
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Is the given base format a legal format for a depth/stencil renderbuffer?
+ */
+static GLboolean
+is_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat)
+{
+ switch (baseFormat) {
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_STENCIL_EXT:
+ return GL_TRUE;
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Test if an attachment point is complete and update its Complete field.
+ * \param format if GL_COLOR, this is a color attachment point,
+ * if GL_DEPTH, this is a depth component attachment point,
+ * if GL_STENCIL, this is a stencil component attachment point.
+ */
+static void
+test_attachment_completeness(const struct gl_context *ctx, GLenum format,
+ struct gl_renderbuffer_attachment *att)
+{
+ assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
+
+ /* assume complete */
+ att->Complete = GL_TRUE;
+
+ /* Look for reasons why the attachment might be incomplete */
+ if (att->Type == GL_TEXTURE) {
+ const struct gl_texture_object *texObj = att->Texture;
+ struct gl_texture_image *texImage;
+ GLenum baseFormat;
+
+ if (!texObj) {
+ att_incomplete("no texobj");
+ att->Complete = GL_FALSE;
+ return;
+ }
+
+ texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
+ if (!texImage) {
+ att_incomplete("no teximage");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ if (texImage->Width < 1 || texImage->Height < 1) {
+ att_incomplete("teximage width/height=0");
+ printf("texobj = %u\n", texObj->Name);
+ printf("level = %d\n", att->TextureLevel);
+ att->Complete = GL_FALSE;
+ return;
+ }
+ if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
+ att_incomplete("bad z offset");
+ att->Complete = GL_FALSE;
+ return;
+ }
+
+ baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
+
+ if (format == GL_COLOR) {
+ if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
+ att_incomplete("bad format");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ if (_mesa_is_format_compressed(texImage->TexFormat)) {
+ att_incomplete("compressed internalformat");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ }
+ else if (format == GL_DEPTH) {
+ if (baseFormat == GL_DEPTH_COMPONENT) {
+ /* OK */
+ }
+ else if (ctx->Extensions.EXT_packed_depth_stencil &&
+ ctx->Extensions.ARB_depth_texture &&
+ baseFormat == GL_DEPTH_STENCIL_EXT) {
+ /* OK */
+ }
+ else {
+ att->Complete = GL_FALSE;
+ att_incomplete("bad depth format");
+ return;
+ }
+ }
+ else {
+ ASSERT(format == GL_STENCIL);
+ if (ctx->Extensions.EXT_packed_depth_stencil &&
+ ctx->Extensions.ARB_depth_texture &&
+ baseFormat == GL_DEPTH_STENCIL_EXT) {
+ /* OK */
+ }
+ else {
+ /* no such thing as stencil-only textures */
+ att_incomplete("illegal stencil texture");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ }
+ }
+ else if (att->Type == GL_RENDERBUFFER_EXT) {
+ const GLenum baseFormat =
+ _mesa_get_format_base_format(att->Renderbuffer->Format);
+
+ ASSERT(att->Renderbuffer);
+ if (!att->Renderbuffer->InternalFormat ||
+ att->Renderbuffer->Width < 1 ||
+ att->Renderbuffer->Height < 1) {
+ att_incomplete("0x0 renderbuffer");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ if (format == GL_COLOR) {
+ if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
+ att_incomplete("bad renderbuffer color format");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ }
+ else if (format == GL_DEPTH) {
+ if (baseFormat == GL_DEPTH_COMPONENT) {
+ /* OK */
+ }
+ else if (ctx->Extensions.EXT_packed_depth_stencil &&
+ baseFormat == GL_DEPTH_STENCIL_EXT) {
+ /* OK */
+ }
+ else {
+ att_incomplete("bad renderbuffer depth format");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ }
+ else {
+ assert(format == GL_STENCIL);
+ if (baseFormat == GL_STENCIL_INDEX) {
+ /* OK */
+ }
+ else if (ctx->Extensions.EXT_packed_depth_stencil &&
+ baseFormat == GL_DEPTH_STENCIL_EXT) {
+ /* OK */
+ }
+ else {
+ att->Complete = GL_FALSE;
+ att_incomplete("bad renderbuffer stencil format");
+ return;
+ }
+ }
+ }
+ else {
+ ASSERT(att->Type == GL_NONE);
+ /* complete */
+ return;
+ }
+}
+
+
+/**
+ * Test if the given framebuffer object is complete and update its
+ * Status field with the results.
+ * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
+ * driver to make hardware-specific validation/completeness checks.
+ * Also update the framebuffer's Width and Height fields if the
+ * framebuffer is complete.
+ */
+void
+_mesa_test_framebuffer_completeness(struct gl_context *ctx,
+ struct gl_framebuffer *fb)
+{
+ GLuint numImages;
+ GLenum intFormat = GL_NONE; /* color buffers' internal format */
+ GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
+ GLint numSamples = -1;
+ GLint i;
+ GLuint j;
+
+ assert(fb->Name != 0);
+
+ numImages = 0;
+ fb->Width = 0;
+ fb->Height = 0;
+
+ /* Start at -2 to more easily loop over all attachment points.
+ * -2: depth buffer
+ * -1: stencil buffer
+ * >=0: color buffer
+ */
+ for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
+ struct gl_renderbuffer_attachment *att;
+ GLenum f;
+ gl_format mesaFormat;
+
+ /*
+ * XXX for ARB_fbo, only check color buffers that are named by
+ * GL_READ_BUFFER and GL_DRAW_BUFFERi.
+ */
+
+ /* check for attachment completeness
+ */
+ if (i == -2) {
+ att = &fb->Attachment[BUFFER_DEPTH];
+ test_attachment_completeness(ctx, GL_DEPTH, att);
+ if (!att->Complete) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
+ fbo_incomplete("depth attachment incomplete", -1);
+ return;
+ }
+ }
+ else if (i == -1) {
+ att = &fb->Attachment[BUFFER_STENCIL];
+ test_attachment_completeness(ctx, GL_STENCIL, att);
+ if (!att->Complete) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
+ fbo_incomplete("stencil attachment incomplete", -1);
+ return;
+ }
+ }
+ else {
+ att = &fb->Attachment[BUFFER_COLOR0 + i];
+ test_attachment_completeness(ctx, GL_COLOR, att);
+ if (!att->Complete) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
+ fbo_incomplete("color attachment incomplete", i);
+ return;
+ }
+ }
+
+ /* get width, height, format of the renderbuffer/texture
+ */
+ if (att->Type == GL_TEXTURE) {
+ const struct gl_texture_image *texImg
+ = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
+ minWidth = MIN2(minWidth, texImg->Width);
+ maxWidth = MAX2(maxWidth, texImg->Width);
+ minHeight = MIN2(minHeight, texImg->Height);
+ maxHeight = MAX2(maxHeight, texImg->Height);
+ f = texImg->_BaseFormat;
+ mesaFormat = texImg->TexFormat;
+ numImages++;
+ if (!_mesa_is_legal_color_format(ctx, f) &&
+ !is_legal_depth_format(ctx, f)) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
+ fbo_incomplete("texture attachment incomplete", -1);
+ return;
+ }
+ }
+ else if (att->Type == GL_RENDERBUFFER_EXT) {
+ minWidth = MIN2(minWidth, att->Renderbuffer->Width);
+ maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
+ minHeight = MIN2(minHeight, att->Renderbuffer->Height);
+ maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
+ f = att->Renderbuffer->InternalFormat;
+ mesaFormat = att->Renderbuffer->Format;
+ numImages++;
+ }
+ else {
+ assert(att->Type == GL_NONE);
+ continue;
+ }
+
+ if (numSamples < 0) {
+ /* first buffer */
+ numSamples = att->Renderbuffer->NumSamples;
+ }
+
+ /* check if integer color */
+ fb->_IntegerColor = _mesa_is_format_integer_color(mesaFormat);
+
+ /* Error-check width, height, format, samples
+ */
+ if (numImages == 1) {
+ /* save format, num samples */
+ if (i >= 0) {
+ intFormat = f;
+ }
+ }
+ else {
+ if (!ctx->Extensions.ARB_framebuffer_object) {
+ /* check that width, height, format are same */
+ if (minWidth != maxWidth || minHeight != maxHeight) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
+ fbo_incomplete("width or height mismatch", -1);
+ return;
+ }
+ /* check that all color buffer have same format */
+ if (intFormat != GL_NONE && f != intFormat) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
+ fbo_incomplete("format mismatch", -1);
+ return;
+ }
+ }
+ if (att->Renderbuffer &&
+ att->Renderbuffer->NumSamples != numSamples) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
+ fbo_incomplete("inconsistant number of samples", i);
+ return;
+ }
+
+ }
+ }
+
+#if FEATURE_GL
+ if (ctx->API == API_OPENGL) {
+ /* Check that all DrawBuffers are present */
+ for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
+ if (fb->ColorDrawBuffer[j] != GL_NONE) {
+ const struct gl_renderbuffer_attachment *att
+ = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
+ assert(att);
+ if (att->Type == GL_NONE) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
+ fbo_incomplete("missing drawbuffer", j);
+ return;
+ }
+ }
+ }
+
+ /* Check that the ReadBuffer is present */
+ if (fb->ColorReadBuffer != GL_NONE) {
+ const struct gl_renderbuffer_attachment *att
+ = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
+ assert(att);
+ if (att->Type == GL_NONE) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
+ fbo_incomplete("missing readbuffer", -1);
+ return;
+ }
+ }
+ }
+#else
+ (void) j;
+#endif
+
+ if (numImages == 0) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
+ fbo_incomplete("no attachments", -1);
+ return;
+ }
+
+ /* Provisionally set status = COMPLETE ... */
+ fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
+
+ /* ... but the driver may say the FB is incomplete.
+ * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
+ * if anything.
+ */
+ if (ctx->Driver.ValidateFramebuffer) {
+ ctx->Driver.ValidateFramebuffer(ctx, fb);
+ if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ fbo_incomplete("driver marked FBO as incomplete", -1);
+ }
+ }
+
+ if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
+ /*
+ * Note that if ARB_framebuffer_object is supported and the attached
+ * renderbuffers/textures are different sizes, the framebuffer
+ * width/height will be set to the smallest width/height.
+ */
+ fb->Width = minWidth;
+ fb->Height = minHeight;
+
+ /* finally, update the visual info for the framebuffer */
+ _mesa_update_framebuffer_visual(ctx, fb);
+ }
+}
+
+
+GLboolean GLAPIENTRY
+_mesa_IsRenderbufferEXT(GLuint renderbuffer)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
+ if (renderbuffer) {
+ struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
+ if (rb != NULL && rb != &DummyRenderbuffer)
+ return GL_TRUE;
+ }
+ return GL_FALSE;
+}
+
+
+void GLAPIENTRY
+_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
+{
+ struct gl_renderbuffer *newRb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (target != GL_RENDERBUFFER_EXT) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
+ return;
+ }
+
+ /* No need to flush here since the render buffer binding has no
+ * effect on rendering state.
+ */
+
+ if (renderbuffer) {
+ newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
+ if (newRb == &DummyRenderbuffer) {
+ /* ID was reserved, but no real renderbuffer object made yet */
+ newRb = NULL;
+ }
+ else if (!newRb && ctx->Extensions.ARB_framebuffer_object) {
+ /* All RB IDs must be Gen'd */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
+ return;
+ }
+
+ if (!newRb) {
+ /* create new renderbuffer object */
+ newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
+ if (!newRb) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
+ return;
+ }
+ ASSERT(newRb->AllocStorage);
+ _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
+ newRb->RefCount = 1; /* referenced by hash table */
+ }
+ }
+ else {
+ newRb = NULL;
+ }
+
+ ASSERT(newRb != &DummyRenderbuffer);
+
+ _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
+}
+
+
+/**
+ * If the given renderbuffer is anywhere attached to the framebuffer, detach
+ * the renderbuffer.
+ * This is used when a renderbuffer object is deleted.
+ * The spec calls for unbinding.
+ */
+static void
+detach_renderbuffer(struct gl_context *ctx,
+ struct gl_framebuffer *fb,
+ struct gl_renderbuffer *rb)
+{
+ GLuint i;
+ for (i = 0; i < BUFFER_COUNT; i++) {
+ if (fb->Attachment[i].Renderbuffer == rb) {
+ _mesa_remove_attachment(ctx, &fb->Attachment[i]);
+ }
+ }
+ invalidate_framebuffer(fb);
+}
+
+
+void GLAPIENTRY
+_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
+{
+ GLint i;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+ FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
+ for (i = 0; i < n; i++) {
+ if (renderbuffers[i] > 0) {
+ struct gl_renderbuffer *rb;
+ rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
+ if (rb) {
+ /* check if deleting currently bound renderbuffer object */
+ if (rb == ctx->CurrentRenderbuffer) {
+ /* bind default */
+ ASSERT(rb->RefCount >= 2);
+ _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+ }
+
+ if (ctx->DrawBuffer->Name) {
+ detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
+ }
+ if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) {
+ detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
+ }
+
+ /* Remove from hash table immediately, to free the ID.
+ * But the object will not be freed until it's no longer
+ * referenced anywhere else.
+ */
+ _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
+
+ if (rb != &DummyRenderbuffer) {
+ /* no longer referenced by hash table */
+ _mesa_reference_renderbuffer(&rb, NULL);
+ }
+ }
+ }
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLuint first;
+ GLint i;
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (n < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
+ return;
+ }
+
+ if (!renderbuffers)
+ return;
+
+ first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
+
+ for (i = 0; i < n; i++) {
+ GLuint name = first + i;
+ renderbuffers[i] = name;
+ /* insert dummy placeholder into hash table */
+ _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+ _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
+ _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+ }
+}
+
+
+/**
+ * Given an internal format token for a render buffer, return the
+ * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX,
+ * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE,
+ * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc).
+ *
+ * This is similar to _mesa_base_tex_format() but the set of valid
+ * internal formats is different.
+ *
+ * Note that even if a format is determined to be legal here, validation
+ * of the FBO may fail if the format is not supported by the driver/GPU.
+ *
+ * \param internalFormat as passed to glRenderbufferStorage()
+ * \return the base internal format, or 0 if internalFormat is illegal
+ */
+GLenum
+_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat)
+{
+ /*
+ * Notes: some formats such as alpha, luminance, etc. were added
+ * with GL_ARB_framebuffer_object.
+ */
+ switch (internalFormat) {
+ case GL_ALPHA:
+ case GL_ALPHA4:
+ case GL_ALPHA8:
+ case GL_ALPHA12:
+ case GL_ALPHA16:
+ return ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
+ case GL_LUMINANCE:
+ case GL_LUMINANCE4:
+ case GL_LUMINANCE8:
+ case GL_LUMINANCE12:
+ case GL_LUMINANCE16:
+ return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
+ case GL_LUMINANCE_ALPHA:
+ case GL_LUMINANCE4_ALPHA4:
+ case GL_LUMINANCE6_ALPHA2:
+ case GL_LUMINANCE8_ALPHA8:
+ case GL_LUMINANCE12_ALPHA4:
+ case GL_LUMINANCE12_ALPHA12:
+ case GL_LUMINANCE16_ALPHA16:
+ return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
+ case GL_INTENSITY:
+ case GL_INTENSITY4:
+ case GL_INTENSITY8:
+ case GL_INTENSITY12:
+ case GL_INTENSITY16:
+ return ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
+ case GL_RGB:
+ case GL_R3_G3_B2:
+ case GL_RGB4:
+ case GL_RGB5:
+ case GL_RGB8:
+ case GL_RGB10:
+ case GL_RGB12:
+ case GL_RGB16:
+ case GL_SRGB8_EXT:
+ return GL_RGB;
+ case GL_RGBA:
+ case GL_RGBA2:
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGBA8:
+ case GL_RGB10_A2:
+ case GL_RGBA12:
+ case GL_RGBA16:
+ case GL_RGBA16_SNORM:
+ case GL_SRGB8_ALPHA8_EXT:
+ return GL_RGBA;
+ case GL_STENCIL_INDEX:
+ case GL_STENCIL_INDEX1_EXT:
+ case GL_STENCIL_INDEX4_EXT:
+ case GL_STENCIL_INDEX8_EXT:
+ case GL_STENCIL_INDEX16_EXT:
+ return GL_STENCIL_INDEX;
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_COMPONENT16:
+ case GL_DEPTH_COMPONENT24:
+ case GL_DEPTH_COMPONENT32:
+ return GL_DEPTH_COMPONENT;
+ case GL_DEPTH_STENCIL_EXT:
+ case GL_DEPTH24_STENCIL8_EXT:
+ if (ctx->Extensions.EXT_packed_depth_stencil)
+ return GL_DEPTH_STENCIL_EXT;
+ else
+ return 0;
+ case GL_RED:
+ case GL_R8:
+ case GL_R16:
+ return ctx->Extensions.ARB_texture_rg ? GL_RED : 0;
+ case GL_RG:
+ case GL_RG8:
+ case GL_RG16:
+ return ctx->Extensions.ARB_texture_rg ? GL_RG : 0;
+ /* XXX add floating point and integer formats eventually */
+ default:
+ return 0;
+ }
+}
+
+
+/** sentinal value, see below */
+#define NO_SAMPLES 1000
+
+
+/**
+ * Helper function used by _mesa_RenderbufferStorageEXT() and
+ * _mesa_RenderbufferStorageMultisample().
+ * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT().
+ */
+static void
+renderbuffer_storage(GLenum target, GLenum internalFormat,
+ GLsizei width, GLsizei height, GLsizei samples)
+{
+ const char *func = samples == NO_SAMPLES ?
+ "glRenderbufferStorage" : "RenderbufferStorageMultisample";
+ struct gl_renderbuffer *rb;
+ GLenum baseFormat;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (target != GL_RENDERBUFFER_EXT) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
+ return;
+ }
+
+ baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
+ if (baseFormat == 0) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func);
+ return;
+ }
+
+ if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
+ return;
+ }
+
+ if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
+ return;
+ }
+
+ if (samples == NO_SAMPLES) {
+ /* NumSamples == 0 indicates non-multisampling */
+ samples = 0;
+ }
+ else if (samples > (GLsizei) ctx->Const.MaxSamples) {
+ /* note: driver may choose to use more samples than what's requested */
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func);
+ return;
+ }
+
+ rb = ctx->CurrentRenderbuffer;
+ if (!rb) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
+ if (rb->InternalFormat == internalFormat &&
+ rb->Width == (GLuint) width &&
+ rb->Height == (GLuint) height) {
+ /* no change in allocation needed */
+ return;
+ }
+
+ /* These MUST get set by the AllocStorage func */
+ rb->Format = MESA_FORMAT_NONE;
+ rb->NumSamples = samples;
+
+ /* Now allocate the storage */
+ ASSERT(rb->AllocStorage);
+ if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
+ /* No error - check/set fields now */
+ assert(rb->Format != MESA_FORMAT_NONE);
+ assert(rb->Width == (GLuint) width);
+ assert(rb->Height == (GLuint) height);
+ rb->InternalFormat = internalFormat;
+ rb->_BaseFormat = baseFormat;
+ assert(rb->_BaseFormat != 0);
+ }
+ else {
+ /* Probably ran out of memory - clear the fields */
+ rb->Width = 0;
+ rb->Height = 0;
+ rb->Format = MESA_FORMAT_NONE;
+ rb->InternalFormat = GL_NONE;
+ rb->_BaseFormat = GL_NONE;
+ rb->NumSamples = 0;
+ }
+
+ /*
+ test_framebuffer_completeness(ctx, fb);
+ */
+ /* XXX if this renderbuffer is attached anywhere, invalidate attachment
+ * points???
+ */
+}
+
+
+#if FEATURE_OES_EGL_image
+void GLAPIENTRY
+_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
+{
+ struct gl_renderbuffer *rb;
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (!ctx->Extensions.OES_EGL_image) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glEGLImageTargetRenderbufferStorageOES(unsupported)");
+ return;
+ }
+
+ if (target != GL_RENDERBUFFER) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "EGLImageTargetRenderbufferStorageOES");
+ return;
+ }
+
+ rb = ctx->CurrentRenderbuffer;
+ if (!rb) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "EGLImageTargetRenderbufferStorageOES");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
+ ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
+}
+#endif
+
+
+/**
+ * Helper function for _mesa_GetRenderbufferParameterivEXT() and
+ * _mesa_GetFramebufferAttachmentParameterivEXT()
+ * We have to be careful to respect the base format. For example, if a
+ * renderbuffer/texture was created with internalFormat=GL_RGB but the
+ * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
+ * we need to return zero.
+ */
+static GLint
+get_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
+{
+ switch (pname) {
+ case GL_RENDERBUFFER_RED_SIZE_EXT:
+ case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
+ if (baseFormat == GL_RGB || baseFormat == GL_RGBA ||
+ baseFormat == GL_RG || baseFormat == GL_RED)
+ return _mesa_get_format_bits(format, pname);
+ else
+ return 0;
+ case GL_RENDERBUFFER_GREEN_SIZE_EXT:
+ case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
+ if (baseFormat == GL_RGB || baseFormat == GL_RGBA || baseFormat == GL_RG)
+ return _mesa_get_format_bits(format, pname);
+ else
+ return 0;
+ case GL_RENDERBUFFER_BLUE_SIZE_EXT:
+ case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
+ if (baseFormat == GL_RGB || baseFormat == GL_RGBA)
+ return _mesa_get_format_bits(format, pname);
+ else
+ return 0;
+ case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
+ case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
+ if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA ||
+ baseFormat == GL_LUMINANCE_ALPHA)
+ return _mesa_get_format_bits(format, pname);
+ else
+ return 0;
+ case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
+ case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
+ if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL)
+ return _mesa_get_format_bits(format, pname);
+ else
+ return 0;
+ case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
+ case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
+ if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL)
+ return _mesa_get_format_bits(format, pname);
+ else
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+
+
+void GLAPIENTRY
+_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
+ GLsizei width, GLsizei height)
+{
+ /* GL_ARB_fbo says calling this function is equivalent to calling
+ * glRenderbufferStorageMultisample() with samples=0. We pass in
+ * a token value here just for error reporting purposes.
+ */
+ renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
+}
+
+
+void GLAPIENTRY
+_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
+ GLenum internalFormat,
+ GLsizei width, GLsizei height)
+{
+ renderbuffer_storage(target, internalFormat, width, height, samples);
+}
+
+
+/**
+ * OpenGL ES version of glRenderBufferStorage.
+ */
+void GLAPIENTRY
+_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
+ GLsizei width, GLsizei height)
+{
+ switch (internalFormat) {
+ case GL_RGB565:
+ /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
+ /* choose a closest format */
+ internalFormat = GL_RGB5;
+ break;
+ default:
+ break;
+ }
+
+ renderbuffer_storage(target, internalFormat, width, height, 0);
+}
+
+
+void GLAPIENTRY
+_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
+{
+ struct gl_renderbuffer *rb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (target != GL_RENDERBUFFER_EXT) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetRenderbufferParameterivEXT(target)");
+ return;
+ }
+
+ rb = ctx->CurrentRenderbuffer;
+ if (!rb) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetRenderbufferParameterivEXT");
+ return;
+ }
+
+ /* No need to flush here since we're just quering state which is
+ * not effected by rendering.
+ */
+
+ switch (pname) {
+ case GL_RENDERBUFFER_WIDTH_EXT:
+ *params = rb->Width;
+ return;
+ case GL_RENDERBUFFER_HEIGHT_EXT:
+ *params = rb->Height;
+ return;
+ case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
+ *params = rb->InternalFormat;
+ return;
+ case GL_RENDERBUFFER_RED_SIZE_EXT:
+ case GL_RENDERBUFFER_GREEN_SIZE_EXT:
+ case GL_RENDERBUFFER_BLUE_SIZE_EXT:
+ case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
+ case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
+ case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
+ *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
+ break;
+ case GL_RENDERBUFFER_SAMPLES:
+ if (ctx->Extensions.ARB_framebuffer_object) {
+ *params = rb->NumSamples;
+ break;
+ }
+ /* fallthrough */
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetRenderbufferParameterivEXT(target)");
+ return;
+ }
+}
+
+
+GLboolean GLAPIENTRY
+_mesa_IsFramebufferEXT(GLuint framebuffer)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
+ if (framebuffer) {
+ struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
+ if (rb != NULL && rb != &DummyFramebuffer)
+ return GL_TRUE;
+ }
+ return GL_FALSE;
+}
+
+
+/**
+ * Check if any of the attachments of the given framebuffer are textures
+ * (render to texture). Call ctx->Driver.RenderTexture() for such
+ * attachments.
+ */
+static void
+check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
+{
+ GLuint i;
+ ASSERT(ctx->Driver.RenderTexture);
+
+ if (fb->Name == 0)
+ return; /* can't render to texture with winsys framebuffers */
+
+ for (i = 0; i < BUFFER_COUNT; i++) {
+ struct gl_renderbuffer_attachment *att = fb->Attachment + i;
+ struct gl_texture_object *texObj = att->Texture;
+ if (texObj
+ && texObj->Image[att->CubeMapFace][att->TextureLevel]) {
+ ctx->Driver.RenderTexture(ctx, fb, att);
+ }
+ }
+}
+
+
+/**
+ * Examine all the framebuffer's attachments to see if any are textures.
+ * If so, call ctx->Driver.FinishRenderTexture() for each texture to
+ * notify the device driver that the texture image may have changed.
+ */
+static void
+check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
+{
+ if (fb->Name == 0)
+ return; /* can't render to texture with winsys framebuffers */
+
+ if (ctx->Driver.FinishRenderTexture) {
+ GLuint i;
+ for (i = 0; i < BUFFER_COUNT; i++) {
+ struct gl_renderbuffer_attachment *att = fb->Attachment + i;
+ if (att->Texture && att->Renderbuffer) {
+ ctx->Driver.FinishRenderTexture(ctx, att);
+ }
+ }
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
+{
+ struct gl_framebuffer *newDrawFb, *newReadFb;
+ struct gl_framebuffer *oldDrawFb, *oldReadFb;
+ GLboolean bindReadBuf, bindDrawBuf;
+ GET_CURRENT_CONTEXT(ctx);
+
+#ifdef DEBUG
+ if (ctx->Extensions.ARB_framebuffer_object) {
+ ASSERT(ctx->Extensions.EXT_framebuffer_object);
+ ASSERT(ctx->Extensions.EXT_framebuffer_blit);
+ }
+#endif
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (!ctx->Extensions.EXT_framebuffer_object) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindFramebufferEXT(unsupported)");
+ return;
+ }
+
+ switch (target) {
+#if FEATURE_EXT_framebuffer_blit
+ case GL_DRAW_FRAMEBUFFER_EXT:
+ if (!ctx->Extensions.EXT_framebuffer_blit) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
+ return;
+ }
+ bindDrawBuf = GL_TRUE;
+ bindReadBuf = GL_FALSE;
+ break;
+ case GL_READ_FRAMEBUFFER_EXT:
+ if (!ctx->Extensions.EXT_framebuffer_blit) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
+ return;
+ }
+ bindDrawBuf = GL_FALSE;
+ bindReadBuf = GL_TRUE;
+ break;
+#endif
+ case GL_FRAMEBUFFER_EXT:
+ bindDrawBuf = GL_TRUE;
+ bindReadBuf = GL_TRUE;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
+ return;
+ }
+
+ if (framebuffer) {
+ /* Binding a user-created framebuffer object */
+ newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
+ if (newDrawFb == &DummyFramebuffer) {
+ /* ID was reserved, but no real framebuffer object made yet */
+ newDrawFb = NULL;
+ }
+ else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) {
+ /* All FBO IDs must be Gen'd */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
+ return;
+ }
+
+ if (!newDrawFb) {
+ /* create new framebuffer object */
+ newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
+ if (!newDrawFb) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
+ return;
+ }
+ _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
+ }
+ newReadFb = newDrawFb;
+ }
+ else {
+ /* Binding the window system framebuffer (which was originally set
+ * with MakeCurrent).
+ */
+ newDrawFb = ctx->WinSysDrawBuffer;
+ newReadFb = ctx->WinSysReadBuffer;
+ }
+
+ ASSERT(newDrawFb);
+ ASSERT(newDrawFb != &DummyFramebuffer);
+
+ /* save pointers to current/old framebuffers */
+ oldDrawFb = ctx->DrawBuffer;
+ oldReadFb = ctx->ReadBuffer;
+
+ /* check if really changing bindings */
+ if (oldDrawFb == newDrawFb)
+ bindDrawBuf = GL_FALSE;
+ if (oldReadFb == newReadFb)
+ bindReadBuf = GL_FALSE;
+
+ /*
+ * OK, now bind the new Draw/Read framebuffers, if they're changing.
+ *
+ * We also check if we're beginning and/or ending render-to-texture.
+ * When a framebuffer with texture attachments is unbound, call
+ * ctx->Driver.FinishRenderTexture().
+ * When a framebuffer with texture attachments is bound, call
+ * ctx->Driver.RenderTexture().
+ *
+ * Note that if the ReadBuffer has texture attachments we don't consider
+ * that a render-to-texture case.
+ */
+ if (bindReadBuf) {
+ FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
+ /* check if old readbuffer was render-to-texture */
+ check_end_texture_render(ctx, oldReadFb);
+
+ _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
+ }
+
+ if (bindDrawBuf) {
+ FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
+ /* check if old read/draw buffers were render-to-texture */
+ if (!bindReadBuf)
+ check_end_texture_render(ctx, oldReadFb);
+
+ if (oldDrawFb != oldReadFb)
+ check_end_texture_render(ctx, oldDrawFb);
+
+ /* check if newly bound framebuffer has any texture attachments */
+ check_begin_texture_render(ctx, newDrawFb);
+
+ _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
+ }
+
+ if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
+ ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
+{
+ GLint i;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+ FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
+ for (i = 0; i < n; i++) {
+ if (framebuffers[i] > 0) {
+ struct gl_framebuffer *fb;
+ fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
+ if (fb) {
+ ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
+
+ /* check if deleting currently bound framebuffer object */
+ if (ctx->Extensions.EXT_framebuffer_blit) {
+ /* separate draw/read binding points */
+ if (fb == ctx->DrawBuffer) {
+ /* bind default */
+ ASSERT(fb->RefCount >= 2);
+ _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
+ }
+ if (fb == ctx->ReadBuffer) {
+ /* bind default */
+ ASSERT(fb->RefCount >= 2);
+ _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
+ }
+ }
+ else {
+ /* only one binding point for read/draw buffers */
+ if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
+ /* bind default */
+ ASSERT(fb->RefCount >= 2);
+ _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ }
+ }
+
+ /* remove from hash table immediately, to free the ID */
+ _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
+
+ if (fb != &DummyFramebuffer) {
+ /* But the object will not be freed until it's no longer
+ * bound in any context.
+ */
+ _mesa_reference_framebuffer(&fb, NULL);
+ }
+ }
+ }
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLuint first;
+ GLint i;
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (n < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
+ return;
+ }
+
+ if (!framebuffers)
+ return;
+
+ first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
+
+ for (i = 0; i < n; i++) {
+ GLuint name = first + i;
+ framebuffers[i] = name;
+ /* insert dummy placeholder into hash table */
+ _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+ _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
+ _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+ }
+}
+
+
+
+GLenum GLAPIENTRY
+_mesa_CheckFramebufferStatusEXT(GLenum target)
+{
+ struct gl_framebuffer *buffer;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
+
+ switch (target) {
+#if FEATURE_EXT_framebuffer_blit
+ case GL_DRAW_FRAMEBUFFER_EXT:
+ if (!ctx->Extensions.EXT_framebuffer_blit) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
+ return 0;
+ }
+ buffer = ctx->DrawBuffer;
+ break;
+ case GL_READ_FRAMEBUFFER_EXT:
+ if (!ctx->Extensions.EXT_framebuffer_blit) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
+ return 0;
+ }
+ buffer = ctx->ReadBuffer;
+ break;
+#endif
+ case GL_FRAMEBUFFER_EXT:
+ buffer = ctx->DrawBuffer;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
+ return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
+ }
+
+ if (buffer->Name == 0) {
+ /* The window system / default framebuffer is always complete */
+ return GL_FRAMEBUFFER_COMPLETE_EXT;
+ }
+
+ /* No need to flush here */
+
+ if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
+ _mesa_test_framebuffer_completeness(ctx, buffer);
+ }
+
+ return buffer->_Status;
+}
+
+
+
+/**
+ * Common code called by glFramebufferTexture1D/2D/3DEXT().
+ */
+static void
+framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target,
+ GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level, GLint zoffset)
+{
+ struct gl_renderbuffer_attachment *att;
+ struct gl_texture_object *texObj = NULL;
+ struct gl_framebuffer *fb;
+ GLboolean error = GL_FALSE;
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ switch (target) {
+ case GL_READ_FRAMEBUFFER_EXT:
+ error = !ctx->Extensions.EXT_framebuffer_blit;
+ fb = ctx->ReadBuffer;
+ break;
+ case GL_DRAW_FRAMEBUFFER_EXT:
+ error = !ctx->Extensions.EXT_framebuffer_blit;
+ /* fall-through */
+ case GL_FRAMEBUFFER_EXT:
+ fb = ctx->DrawBuffer;
+ break;
+ default:
+ error = GL_TRUE;
+ }
+
+ if (error) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
+ return;
+ }
+
+ ASSERT(fb);
+
+ /* check framebuffer binding */
+ if (fb->Name == 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glFramebufferTexture%sEXT", caller);
+ return;
+ }
+
+
+ /* The textarget, level, and zoffset parameters are only validated if
+ * texture is non-zero.
+ */
+ if (texture) {
+ GLboolean err = GL_TRUE;
+
+ texObj = _mesa_lookup_texture(ctx, texture);
+ if (texObj != NULL) {
+ if (textarget == 0) {
+ /* XXX what's the purpose of this? */
+ err = (texObj->Target != GL_TEXTURE_3D) &&
+ (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
+ (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
+ }
+ else {
+ err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
+ ? !IS_CUBE_FACE(textarget)
+ : (texObj->Target != textarget);
+ }
+ }
+ else {
+ /* can't render to a non-existant texture */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glFramebufferTexture%sEXT(non existant texture)",
+ caller);
+ return;
+ }
+
+ if (err) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glFramebufferTexture%sEXT(texture target mismatch)",
+ caller);
+ return;
+ }
+
+ if (texObj->Target == GL_TEXTURE_3D) {
+ const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
+ if (zoffset < 0 || zoffset >= maxSize) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glFramebufferTexture%sEXT(zoffset)", caller);
+ return;
+ }
+ }
+ else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
+ (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
+ if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glFramebufferTexture%sEXT(layer)", caller);
+ return;
+ }
+ }
+
+ if ((level < 0) ||
+ (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glFramebufferTexture%sEXT(level)", caller);
+ return;
+ }
+ }
+
+ att = _mesa_get_attachment(ctx, fb, attachment);
+ if (att == NULL) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferTexture%sEXT(attachment)", caller);
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
+ _glthread_LOCK_MUTEX(fb->Mutex);
+ if (texObj) {
+ _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
+ level, zoffset);
+ /* Set the render-to-texture flag. We'll check this flag in
+ * glTexImage() and friends to determine if we need to revalidate
+ * any FBOs that might be rendering into this texture.
+ * This flag never gets cleared since it's non-trivial to determine
+ * when all FBOs might be done rendering to this texture. That's OK
+ * though since it's uncommon to render to a texture then repeatedly
+ * call glTexImage() to change images in the texture.
+ */
+ texObj->_RenderToTexture = GL_TRUE;
+ }
+ else {
+ _mesa_remove_attachment(ctx, att);
+ }
+
+ invalidate_framebuffer(fb);
+
+ _glthread_UNLOCK_MUTEX(fb->Mutex);
+}
+
+
+
+void GLAPIENTRY
+_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
+ GLenum textarget, GLuint texture, GLint level)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferTexture1DEXT(textarget)");
+ return;
+ }
+
+ framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
+ level, 0);
+}
+
+
+void GLAPIENTRY
+_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
+ GLenum textarget, GLuint texture, GLint level)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ((texture != 0) &&
+ (textarget != GL_TEXTURE_2D) &&
+ (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
+ (!IS_CUBE_FACE(textarget))) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glFramebufferTexture2DEXT(textarget=0x%x)", textarget);
+ return;
+ }
+
+ framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
+ level, 0);
+}
+
+
+void GLAPIENTRY
+_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
+ GLenum textarget, GLuint texture,
+ GLint level, GLint zoffset)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferTexture3DEXT(textarget)");
+ return;
+ }
+
+ framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
+ level, zoffset);
+}
+
+
+void GLAPIENTRY
+_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
+ GLuint texture, GLint level, GLint layer)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
+ level, layer);
+}
+
+
+void GLAPIENTRY
+_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
+ GLenum renderbufferTarget,
+ GLuint renderbuffer)
+{
+ struct gl_renderbuffer_attachment *att;
+ struct gl_framebuffer *fb;
+ struct gl_renderbuffer *rb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ switch (target) {
+#if FEATURE_EXT_framebuffer_blit
+ case GL_DRAW_FRAMEBUFFER_EXT:
+ if (!ctx->Extensions.EXT_framebuffer_blit) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferRenderbufferEXT(target)");
+ return;
+ }
+ fb = ctx->DrawBuffer;
+ break;
+ case GL_READ_FRAMEBUFFER_EXT:
+ if (!ctx->Extensions.EXT_framebuffer_blit) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferRenderbufferEXT(target)");
+ return;
+ }
+ fb = ctx->ReadBuffer;
+ break;
+#endif
+ case GL_FRAMEBUFFER_EXT:
+ fb = ctx->DrawBuffer;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferRenderbufferEXT(target)");
+ return;
+ }
+
+ if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferRenderbufferEXT(renderbufferTarget)");
+ return;
+ }
+
+ if (fb->Name == 0) {
+ /* Can't attach new renderbuffers to a window system framebuffer */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
+ return;
+ }
+
+ att = _mesa_get_attachment(ctx, fb, attachment);
+ if (att == NULL) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferRenderbufferEXT(invalid attachment %s)",
+ _mesa_lookup_enum_by_nr(attachment));
+ return;
+ }
+
+ if (renderbuffer) {
+ rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
+ if (!rb) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glFramebufferRenderbufferEXT(non-existant"
+ " renderbuffer %u)", renderbuffer);
+ return;
+ }
+ else if (rb == &DummyRenderbuffer) {
+ /* This is what NVIDIA does */
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glFramebufferRenderbufferEXT(renderbuffer %u)",
+ renderbuffer);
+ return;
+ }
+ }
+ else {
+ /* remove renderbuffer attachment */
+ rb = NULL;
+ }
+
+ if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
+ rb && rb->Format != MESA_FORMAT_NONE) {
+ /* make sure the renderbuffer is a depth/stencil format */
+ const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
+ if (baseFormat != GL_DEPTH_STENCIL) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glFramebufferRenderbufferEXT(renderbuffer"
+ " is not DEPTH_STENCIL format)");
+ return;
+ }
+ }
+
+
+ FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
+ assert(ctx->Driver.FramebufferRenderbuffer);
+ ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
+
+ /* Some subsequent GL commands may depend on the framebuffer's visual
+ * after the binding is updated. Update visual info now.
+ */
+ _mesa_update_framebuffer_visual(ctx, fb);
+}
+
+
+void GLAPIENTRY
+_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
+ GLenum pname, GLint *params)
+{
+ const struct gl_renderbuffer_attachment *att;
+ struct gl_framebuffer *buffer;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ switch (target) {
+#if FEATURE_EXT_framebuffer_blit
+ case GL_DRAW_FRAMEBUFFER_EXT:
+ if (!ctx->Extensions.EXT_framebuffer_blit) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferAttachmentParameterivEXT(target)");
+ return;
+ }
+ buffer = ctx->DrawBuffer;
+ break;
+ case GL_READ_FRAMEBUFFER_EXT:
+ if (!ctx->Extensions.EXT_framebuffer_blit) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferAttachmentParameterivEXT(target)");
+ return;
+ }
+ buffer = ctx->ReadBuffer;
+ break;
+#endif
+ case GL_FRAMEBUFFER_EXT:
+ buffer = ctx->DrawBuffer;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferAttachmentParameterivEXT(target)");
+ return;
+ }
+
+ if (buffer->Name == 0) {
+ /* the default / window-system FBO */
+ att = _mesa_get_fb0_attachment(ctx, buffer, attachment);
+ }
+ else {
+ /* user-created framebuffer FBO */
+ att = _mesa_get_attachment(ctx, buffer, attachment);
+ }
+
+ if (att == NULL) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferAttachmentParameterivEXT(attachment)");
+ return;
+ }
+
+ if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
+ /* the depth and stencil attachments must point to the same buffer */
+ const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
+ depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
+ stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
+ if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
+ " attachments differ)");
+ return;
+ }
+ }
+
+ /* No need to flush here */
+
+ switch (pname) {
+ case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
+ *params = buffer->Name == 0 ? GL_FRAMEBUFFER_DEFAULT : att->Type;
+ return;
+ case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
+ if (att->Type == GL_RENDERBUFFER_EXT) {
+ *params = att->Renderbuffer->Name;
+ }
+ else if (att->Type == GL_TEXTURE) {
+ *params = att->Texture->Name;
+ }
+ else {
+ assert(att->Type == GL_NONE);
+ *params = 0;
+ }
+ return;
+ case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
+ if (att->Type == GL_TEXTURE) {
+ *params = att->TextureLevel;
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferAttachmentParameterivEXT(pname)");
+ }
+ return;
+ case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
+ if (att->Type == GL_TEXTURE) {
+ if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
+ *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
+ }
+ else {
+ *params = 0;
+ }
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferAttachmentParameterivEXT(pname)");
+ }
+ return;
+ case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
+ if (att->Type == GL_TEXTURE) {
+ if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
+ *params = att->Zoffset;
+ }
+ else {
+ *params = 0;
+ }
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferAttachmentParameterivEXT(pname)");
+ }
+ return;
+ case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
+ if (!ctx->Extensions.ARB_framebuffer_object) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferAttachmentParameterivEXT(pname)");
+ }
+ else {
+ if (ctx->Extensions.EXT_framebuffer_sRGB && ctx->Const.sRGBCapable) {
+ *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format);
+ }
+ else {
+ /* According to ARB_framebuffer_sRGB, we should return LINEAR
+ * if the sRGB conversion is unsupported. */
+ *params = GL_LINEAR;
+ }
+ }
+ return;
+ case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
+ if (!ctx->Extensions.ARB_framebuffer_object) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferAttachmentParameterivEXT(pname)");
+ return;
+ }
+ else {
+ gl_format format = att->Renderbuffer->Format;
+ if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) {
+ /* special cases */
+ *params = GL_INDEX;
+ }
+ else {
+ *params = _mesa_get_format_datatype(format);
+ }
+ }
+ return;
+ case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
+ case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
+ case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
+ case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
+ case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
+ case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
+ if (!ctx->Extensions.ARB_framebuffer_object) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferAttachmentParameterivEXT(pname)");
+ }
+ else if (att->Texture) {
+ const struct gl_texture_image *texImage =
+ _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
+ att->TextureLevel);
+ if (texImage) {
+ *params = get_component_bits(pname, texImage->_BaseFormat,
+ texImage->TexFormat);
+ }
+ else {
+ *params = 0;
+ }
+ }
+ else if (att->Renderbuffer) {
+ *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
+ att->Renderbuffer->Format);
+ }
+ else {
+ *params = 0;
+ }
+ return;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferAttachmentParameterivEXT(pname)");
+ return;
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GenerateMipmapEXT(GLenum target)
+{
+ struct gl_texture_object *texObj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+ FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
+ switch (target) {
+ case GL_TEXTURE_1D:
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_3D:
+ case GL_TEXTURE_CUBE_MAP:
+ /* OK, legal value */
+ break;
+ default:
+ /* XXX need to implement GL_TEXTURE_1D_ARRAY and GL_TEXTURE_2D_ARRAY */
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
+ return;
+ }
+
+ texObj = _mesa_get_current_tex_object(ctx, target);
+
+ if (texObj->BaseLevel >= texObj->MaxLevel) {
+ /* nothing to do */
+ return;
+ }
+
+ if (texObj->Target == GL_TEXTURE_CUBE_MAP &&
+ !_mesa_cube_complete(texObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGenerateMipmap(incomplete cube map)");
+ return;
+ }
+
+ _mesa_lock_texture(ctx, texObj);
+ if (target == GL_TEXTURE_CUBE_MAP) {
+ GLuint face;
+ for (face = 0; face < 6; face++)
+ ctx->Driver.GenerateMipmap(ctx,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
+ texObj);
+ }
+ else {
+ ctx->Driver.GenerateMipmap(ctx, target, texObj);
+ }
+ _mesa_unlock_texture(ctx, texObj);
+}
+
+
+#if FEATURE_EXT_framebuffer_blit
+
+static const struct gl_renderbuffer_attachment *
+find_attachment(const struct gl_framebuffer *fb,
+ const struct gl_renderbuffer *rb)
+{
+ GLuint i;
+ for (i = 0; i < Elements(fb->Attachment); i++) {
+ if (fb->Attachment[i].Renderbuffer == rb)
+ return &fb->Attachment[i];
+ }
+ return NULL;
+}
+
+
+
+/**
+ * Blit rectangular region, optionally from one framebuffer to another.
+ *
+ * Note, if the src buffer is multisampled and the dest is not, this is
+ * when the samples must be resolved to a single color.
+ */
+void GLAPIENTRY
+_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter)
+{
+ const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
+ GL_DEPTH_BUFFER_BIT |
+ GL_STENCIL_BUFFER_BIT);
+ const struct gl_framebuffer *readFb, *drawFb;
+ const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+ FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx,
+ "glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)\n",
+ srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ mask, _mesa_lookup_enum_by_nr(filter));
+
+ if (ctx->NewState) {
+ _mesa_update_state(ctx);
+ }
+
+ readFb = ctx->ReadBuffer;
+ drawFb = ctx->DrawBuffer;
+
+ if (!readFb || !drawFb) {
+ /* This will normally never happen but someday we may want to
+ * support MakeCurrent() with no drawables.
+ */
+ return;
+ }
+
+ /* check for complete framebuffers */
+ if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
+ readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
+ "glBlitFramebufferEXT(incomplete draw/read buffers)");
+ return;
+ }
+
+ if (filter != GL_NEAREST && filter != GL_LINEAR) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
+ return;
+ }
+
+ if (mask & ~legalMaskBits) {
+ _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
+ return;
+ }
+
+ /* depth/stencil must be blitted with nearest filtering */
+ if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
+ && filter != GL_NEAREST) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
+ return;
+ }
+
+ /* get color read/draw renderbuffers */
+ if (mask & GL_COLOR_BUFFER_BIT) {
+ colorReadRb = readFb->_ColorReadBuffer;
+ colorDrawRb = drawFb->_ColorDrawBuffers[0];
+ }
+ else {
+ colorReadRb = colorDrawRb = NULL;
+ }
+
+ if (mask & GL_STENCIL_BUFFER_BIT) {
+ struct gl_renderbuffer *readRb = readFb->_StencilBuffer;
+ struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer;
+ if (!readRb ||
+ !drawRb ||
+ _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
+ _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBlitFramebufferEXT(stencil buffer size mismatch");
+ return;
+ }
+ }
+
+ if (mask & GL_DEPTH_BUFFER_BIT) {
+ struct gl_renderbuffer *readRb = readFb->_DepthBuffer;
+ struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer;
+ if (!readRb ||
+ !drawRb ||
+ _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
+ _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBlitFramebufferEXT(depth buffer size mismatch");
+ return;
+ }
+ }
+
+ if (readFb->Visual.samples > 0 &&
+ drawFb->Visual.samples > 0 &&
+ readFb->Visual.samples != drawFb->Visual.samples) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBlitFramebufferEXT(mismatched samples");
+ return;
+ }
+
+ /* extra checks for multisample copies... */
+ if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
+ /* src and dest region sizes must be the same */
+ if (srcX1 - srcX0 != dstX1 - dstX0 ||
+ srcY1 - srcY0 != dstY1 - dstY0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBlitFramebufferEXT(bad src/dst multisample region sizes");
+ return;
+ }
+
+ /* color formats must match */
+ if (colorReadRb &&
+ colorDrawRb &&
+ colorReadRb->Format != colorDrawRb->Format) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBlitFramebufferEXT(bad src/dst multisample pixel formats");
+ return;
+ }
+ }
+
+ if (!ctx->Extensions.EXT_framebuffer_blit) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
+ return;
+ }
+
+ /* Debug code */
+ if (DEBUG_BLIT) {
+ printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d,"
+ " 0x%x, 0x%x)\n",
+ srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ mask, filter);
+ if (colorReadRb) {
+ const struct gl_renderbuffer_attachment *att;
+
+ att = find_attachment(readFb, colorReadRb);
+ printf(" Src FBO %u RB %u (%dx%d) ",
+ readFb->Name, colorReadRb->Name,
+ colorReadRb->Width, colorReadRb->Height);
+ if (att && att->Texture) {
+ printf("Tex %u tgt 0x%x level %u face %u",
+ att->Texture->Name,
+ att->Texture->Target,
+ att->TextureLevel,
+ att->CubeMapFace);
+ }
+ printf("\n");
+
+ att = find_attachment(drawFb, colorDrawRb);
+ printf(" Dst FBO %u RB %u (%dx%d) ",
+ drawFb->Name, colorDrawRb->Name,
+ colorDrawRb->Width, colorDrawRb->Height);
+ if (att && att->Texture) {
+ printf("Tex %u tgt 0x%x level %u face %u",
+ att->Texture->Name,
+ att->Texture->Target,
+ att->TextureLevel,
+ att->CubeMapFace);
+ }
+ printf("\n");
+ }
+ }
+
+ ASSERT(ctx->Driver.BlitFramebuffer);
+ ctx->Driver.BlitFramebuffer(ctx,
+ srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ mask, filter);
+}
+#endif /* FEATURE_EXT_framebuffer_blit */
+
+#if FEATURE_ARB_geometry_shader4
+void GLAPIENTRY
+_mesa_FramebufferTextureARB(GLenum target, GLenum attachment,
+ GLuint texture, GLint level)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glFramebufferTextureARB "
+ "not implemented!");
+}
+
+void GLAPIENTRY
+_mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment,
+ GLuint texture, GLint level, GLenum face)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glFramebufferTextureFaceARB "
+ "not implemented!");
+}
+#endif /* FEATURE_ARB_geometry_shader4 */
diff --git a/mesalib/src/mesa/main/formats.c b/mesalib/src/mesa/main/formats.c index b24b66c92..5c9b3068e 100644 --- a/mesalib/src/mesa/main/formats.c +++ b/mesalib/src/mesa/main/formats.c @@ -1372,7 +1372,11 @@ _mesa_format_to_type_and_comps(gl_format format, *comps = 4;
return;
- case MESA_FORMAT_AL44: /* XXX this isn't plain GL_UNSIGNED_BYTE */
+ case MESA_FORMAT_AL44:
+ *datatype = MESA_UNSIGNED_BYTE_4_4;
+ *comps = 2;
+ return;
+
case MESA_FORMAT_AL88:
case MESA_FORMAT_AL88_REV:
case MESA_FORMAT_RG88:
diff --git a/mesalib/src/mesa/main/formats.h b/mesalib/src/mesa/main/formats.h index fbd2e1eb5..cd7e0e25e 100644 --- a/mesalib/src/mesa/main/formats.h +++ b/mesalib/src/mesa/main/formats.h @@ -35,6 +35,9 @@ #include <GL/gl.h>
+/* OpenGL doesn't have GL_UNSIGNED_BYTE_4_4, so we must define our own type
+ * for GL_LUMINANCE4_ALPHA4. */
+#define MESA_UNSIGNED_BYTE_4_4 (GL_UNSIGNED_BYTE<<1)
/**
diff --git a/mesalib/src/mesa/main/image.c b/mesalib/src/mesa/main/image.c index fa9e8b9bb..444f21ed5 100644 --- a/mesalib/src/mesa/main/image.c +++ b/mesalib/src/mesa/main/image.c @@ -68,6 +68,7 @@ _mesa_type_is_packed(GLenum type) switch (type) {
case GL_UNSIGNED_BYTE_3_3_2:
case GL_UNSIGNED_BYTE_2_3_3_REV:
+ case MESA_UNSIGNED_BYTE_4_4:
case GL_UNSIGNED_SHORT_5_6_5:
case GL_UNSIGNED_SHORT_5_6_5_REV:
case GL_UNSIGNED_SHORT_4_4_4_4:
@@ -194,6 +195,8 @@ _mesa_sizeof_packed_type( GLenum type ) return sizeof(GLubyte);
case GL_UNSIGNED_BYTE_2_3_3_REV:
return sizeof(GLubyte);
+ case MESA_UNSIGNED_BYTE_4_4:
+ return sizeof(GLubyte);
case GL_UNSIGNED_SHORT_5_6_5:
return sizeof(GLushort);
case GL_UNSIGNED_SHORT_5_6_5_REV:
@@ -1581,8 +1584,8 @@ _mesa_clip_drawpixels(const struct gl_context *ctx, * scissor box is ignored, and we use the bounds of the current readbuffer
* surface.
*
- * \return GL_TRUE if image is ready for drawing or
- * GL_FALSE if image was completely clipped away (draw nothing)
+ * \return GL_TRUE if region to read is in bounds
+ * GL_FALSE if region is completely out of bounds (nothing to read)
*/
GLboolean
_mesa_clip_readpixels(const struct gl_context *ctx,
diff --git a/mesalib/src/mesa/main/imports.c b/mesalib/src/mesa/main/imports.c index dcd8cf537..f98098230 100644 --- a/mesalib/src/mesa/main/imports.c +++ b/mesalib/src/mesa/main/imports.c @@ -942,7 +942,7 @@ _mesa_problem( const struct gl_context *ctx, const char *fmtString, ... ) va_end( args );
fprintf(stderr, "Mesa %s implementation error: %s\n", MESA_VERSION_STRING, str);
- fprintf(stderr, "Please report at bugzilla.freedesktop.org\n");
+ fprintf(stderr, "Please report at bugs.freedesktop.org\n");
}
diff --git a/mesalib/src/mesa/main/mipmap.c b/mesalib/src/mesa/main/mipmap.c index d27179e86..3d7ab6b35 100644 --- a/mesalib/src/mesa/main/mipmap.c +++ b/mesalib/src/mesa/main/mipmap.c @@ -612,6 +612,28 @@ do_row(GLenum datatype, GLuint comps, GLint srcWidth, dst[i] = (blue << 5) | (green << 2) | red;
}
}
+
+ else if (datatype == MESA_UNSIGNED_BYTE_4_4 && comps == 2) {
+ GLuint i, j, k;
+ const GLubyte *rowA = (const GLubyte *) srcRowA;
+ const GLubyte *rowB = (const GLubyte *) srcRowB;
+ GLubyte *dst = (GLubyte *) dstRow;
+ for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+ i++, j += colStride, k += colStride) {
+ const GLint rowAr0 = rowA[j] & 0xf;
+ const GLint rowAr1 = rowA[k] & 0xf;
+ const GLint rowBr0 = rowB[j] & 0xf;
+ const GLint rowBr1 = rowB[k] & 0xf;
+ const GLint rowAg0 = (rowA[j] >> 4) & 0xf;
+ const GLint rowAg1 = (rowA[k] >> 4) & 0xf;
+ const GLint rowBg0 = (rowB[j] >> 4) & 0xf;
+ const GLint rowBg1 = (rowB[k] >> 4) & 0xf;
+ const GLint r = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
+ const GLint g = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
+ dst[i] = (g << 4) | r;
+ }
+ }
+
else {
_mesa_problem(NULL, "bad format in do_row()");
}
@@ -1078,7 +1100,7 @@ do_row_3D(GLenum datatype, GLuint comps, GLint srcWidth, }
}
else if ((datatype == GL_UNSIGNED_BYTE_3_3_2) && (comps == 3)) {
- DECLARE_ROW_POINTERS0(GLushort);
+ DECLARE_ROW_POINTERS0(GLubyte);
for (i = j = 0, k = k0; i < (GLuint) dstWidth;
i++, j += colStride, k += colStride) {
@@ -1115,6 +1137,34 @@ do_row_3D(GLenum datatype, GLuint comps, GLint srcWidth, dst[i] = (b << 5) | (g << 2) | r;
}
}
+ else if (datatype == MESA_UNSIGNED_BYTE_4_4 && comps == 2) {
+ DECLARE_ROW_POINTERS0(GLubyte);
+
+ for (i = j = 0, k = k0; i < (GLuint) dstWidth;
+ i++, j += colStride, k += colStride) {
+ const GLint rowAr0 = rowA[j] & 0xf;
+ const GLint rowAr1 = rowA[k] & 0xf;
+ const GLint rowBr0 = rowB[j] & 0xf;
+ const GLint rowBr1 = rowB[k] & 0xf;
+ const GLint rowCr0 = rowC[j] & 0xf;
+ const GLint rowCr1 = rowC[k] & 0xf;
+ const GLint rowDr0 = rowD[j] & 0xf;
+ const GLint rowDr1 = rowD[k] & 0xf;
+ const GLint rowAg0 = (rowA[j] >> 4) & 0xf;
+ const GLint rowAg1 = (rowA[k] >> 4) & 0xf;
+ const GLint rowBg0 = (rowB[j] >> 4) & 0xf;
+ const GLint rowBg1 = (rowB[k] >> 4) & 0xf;
+ const GLint rowCg0 = (rowC[j] >> 4) & 0xf;
+ const GLint rowCg1 = (rowC[k] >> 4) & 0xf;
+ const GLint rowDg0 = (rowD[j] >> 4) & 0xf;
+ const GLint rowDg1 = (rowD[k] >> 4) & 0xf;
+ const GLint r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
+ rowCr0, rowCr1, rowDr0, rowDr1);
+ const GLint g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
+ rowCg0, rowCg1, rowDg0, rowDg1);
+ dst[i] = (g << 4) | r;
+ }
+ }
else {
_mesa_problem(NULL, "bad format in do_row()");
}
diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h index 714d63afc..d2888fa80 100644 --- a/mesalib/src/mesa/main/mtypes.h +++ b/mesalib/src/mesa/main/mtypes.h @@ -3295,9 +3295,6 @@ struct gl_context GLboolean FirstTimeCurrent;
/*@}*/
- /** Dither disable via MESA_NO_DITHER env var */
- GLboolean NoDither;
-
/** software compression/decompression supported or not */
GLboolean Mesa_DXTn;
diff --git a/mesalib/src/mesa/main/readpix.c b/mesalib/src/mesa/main/readpix.c index 9887fd816..3f424600c 100644 --- a/mesalib/src/mesa/main/readpix.c +++ b/mesalib/src/mesa/main/readpix.c @@ -26,6 +26,7 @@ #include "imports.h"
#include "bufferobj.h"
#include "context.h"
+#include "enums.h"
#include "readpix.h"
#include "framebuffer.h"
#include "formats.h"
@@ -173,6 +174,13 @@ _mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, FLUSH_CURRENT(ctx, 0);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n",
+ width, height,
+ _mesa_lookup_enum_by_nr(format),
+ _mesa_lookup_enum_by_nr(type),
+ pixels);
+
if (width < 0 || height < 0) {
_mesa_error( ctx, GL_INVALID_VALUE,
"glReadPixels(width=%d height=%d)", width, height );
diff --git a/mesalib/src/mesa/main/texgetimage.c b/mesalib/src/mesa/main/texgetimage.c index 36bd02a6c..c3f7d3c32 100644 --- a/mesalib/src/mesa/main/texgetimage.c +++ b/mesalib/src/mesa/main/texgetimage.c @@ -805,8 +805,8 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format, * \return GL_TRUE if any error, GL_FALSE if no errors.
*/
static GLboolean
-getcompressedteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
- GLvoid *img)
+getcompressedteximage_error_check(struct gl_context *ctx, GLenum target,
+ GLint level, GLvoid *img)
{
struct gl_texture_object *texObj;
struct gl_texture_image *texImage;
|