From f81bb3160c5f39d8f7ad329e99865af88f02b96a Mon Sep 17 00:00:00 2001 From: marha Date: Thu, 10 Mar 2011 09:49:29 +0000 Subject: xserver mesa git update 10 Mar 2011 --- mesalib/src/mesa/SConscript | 1 + mesalib/src/mesa/main/extensions.c | 4 + mesalib/src/mesa/main/formats.c | 40 + mesalib/src/mesa/main/formats.h | 8 + mesalib/src/mesa/main/glheader.h | 330 +- mesalib/src/mesa/main/image.c | 3770 +++++++------- mesalib/src/mesa/main/mipmap.c | 9 +- mesalib/src/mesa/main/mtypes.h | 2 + mesalib/src/mesa/main/texcompress.c | 19 + mesalib/src/mesa/main/texcompress_rgtc.c | 68 +- mesalib/src/mesa/main/texcompress_rgtc.h | 17 + mesalib/src/mesa/main/texfetch.c | 28 + mesalib/src/mesa/main/texformat.c | 29 + mesalib/src/mesa/main/teximage.c | 22 + mesalib/src/mesa/main/texstore.c | 9 +- mesalib/src/mesa/sources.mak | 743 +-- mesalib/src/mesa/state_tracker/st_cb_flush.c | 329 +- mesalib/src/mesa/state_tracker/st_cb_syncobj.c | 122 + mesalib/src/mesa/state_tracker/st_cb_syncobj.h | 38 + mesalib/src/mesa/state_tracker/st_context.c | 2 + mesalib/src/mesa/state_tracker/st_draw.c | 6 +- mesalib/src/mesa/state_tracker/st_extensions.c | 25 + mesalib/src/mesa/state_tracker/st_format.c | 54 +- mesalib/src/mesa/state_tracker/st_gen_mipmap.c | 10 +- mesalib/src/mesa/swrast/s_texfilter.c | 6625 ++++++++++++------------ mesalib/src/mesa/vbo/vbo_exec_array.c | 13 +- 26 files changed, 6415 insertions(+), 5908 deletions(-) create mode 100644 mesalib/src/mesa/state_tracker/st_cb_syncobj.c create mode 100644 mesalib/src/mesa/state_tracker/st_cb_syncobj.h (limited to 'mesalib/src/mesa') diff --git a/mesalib/src/mesa/SConscript b/mesalib/src/mesa/SConscript index 7e8bb2486..f797d62dc 100644 --- a/mesalib/src/mesa/SConscript +++ b/mesalib/src/mesa/SConscript @@ -197,6 +197,7 @@ statetracker_sources = [ 'state_tracker/st_cb_queryobj.c', 'state_tracker/st_cb_rasterpos.c', 'state_tracker/st_cb_readpixels.c', + 'state_tracker/st_cb_syncobj.c', 'state_tracker/st_cb_strings.c', 'state_tracker/st_cb_texture.c', 'state_tracker/st_cb_viewport.c', diff --git a/mesalib/src/mesa/main/extensions.c b/mesalib/src/mesa/main/extensions.c index 3840cdc5d..68740e24c 100644 --- a/mesalib/src/mesa/main/extensions.c +++ b/mesalib/src/mesa/main/extensions.c @@ -181,6 +181,7 @@ static const struct extension extension_table[] = { { "GL_EXT_texture3D", o(EXT_texture3D), GL }, { "GL_EXT_texture_array", o(EXT_texture_array), GL }, { "GL_EXT_texture_compression_dxt1", o(EXT_texture_compression_s3tc), GL | ES1 | ES2 }, + { "GL_EXT_texture_compression_latc", o(EXT_texture_compression_latc), GL }, { "GL_EXT_texture_compression_rgtc", o(ARB_texture_compression_rgtc), GL }, { "GL_EXT_texture_compression_s3tc", o(EXT_texture_compression_s3tc), GL }, { "GL_EXT_texture_cube_map", o(ARB_texture_cube_map), GL }, @@ -258,6 +259,7 @@ static const struct extension extension_table[] = { { "GL_ATI_envmap_bumpmap", o(ATI_envmap_bumpmap), GL }, { "GL_ATI_fragment_shader", o(ATI_fragment_shader), GL }, { "GL_ATI_separate_stencil", o(ATI_separate_stencil), GL }, + { "GL_ATI_texture_compression_3dc", o(ATI_texture_compression_3dc), GL }, { "GL_ATI_texture_env_combine3", o(ATI_texture_env_combine3), GL }, { "GL_ATI_texture_mirror_once", o(ATI_texture_mirror_once), GL }, { "GL_IBM_multimode_draw_arrays", o(IBM_multimode_draw_arrays), GL }, @@ -448,6 +450,7 @@ _mesa_enable_sw_extensions(struct gl_context *ctx) #if FEATURE_ATI_fragment_shader ctx->Extensions.ATI_fragment_shader = GL_TRUE; #endif + ctx->Extensions.ATI_texture_compression_3dc = GL_TRUE; ctx->Extensions.ATI_texture_env_combine3 = GL_TRUE; ctx->Extensions.ATI_texture_mirror_once = GL_TRUE; ctx->Extensions.ATI_separate_stencil = GL_TRUE; @@ -483,6 +486,7 @@ _mesa_enable_sw_extensions(struct gl_context *ctx) ctx->Extensions.EXT_stencil_wrap = GL_TRUE; ctx->Extensions.EXT_stencil_two_side = GL_TRUE; ctx->Extensions.EXT_texture_array = GL_TRUE; + ctx->Extensions.EXT_texture_compression_latc = GL_TRUE; ctx->Extensions.EXT_texture_env_add = GL_TRUE; ctx->Extensions.EXT_texture_env_combine = GL_TRUE; ctx->Extensions.EXT_texture_env_dot3 = GL_TRUE; diff --git a/mesalib/src/mesa/main/formats.c b/mesalib/src/mesa/main/formats.c index 947db84a6..db10c9b4c 100644 --- a/mesalib/src/mesa/main/formats.c +++ b/mesalib/src/mesa/main/formats.c @@ -927,6 +927,42 @@ static struct gl_format_info format_info[MESA_FORMAT_COUNT] = 0, 0, 0, 0, 0, 4, 4, 16 /* 16 bytes per 4x4 block */ }, + { + MESA_FORMAT_L_LATC1, + "MESA_FORMAT_L_LATC1", + GL_LUMINANCE, + GL_UNSIGNED_NORMALIZED, + 0, 0, 0, 0, + 4, 0, 0, 0, 0, + 4, 4, 8 /* 8 bytes per 4x4 block */ + }, + { + MESA_FORMAT_SIGNED_L_LATC1, + "MESA_FORMAT_SIGNED_L_LATC1", + GL_LUMINANCE, + GL_SIGNED_NORMALIZED, + 0, 0, 0, 0, + 4, 0, 0, 0, 0, + 4, 4, 8 /* 8 bytes per 4x4 block */ + }, + { + MESA_FORMAT_LA_LATC2, + "MESA_FORMAT_LA_LATC2", + GL_LUMINANCE_ALPHA, + GL_UNSIGNED_NORMALIZED, + 0, 0, 0, 4, + 4, 0, 0, 0, 0, + 4, 4, 16 /* 16 bytes per 4x4 block */ + }, + { + MESA_FORMAT_SIGNED_LA_LATC2, + "MESA_FORMAT_SIGNED_LA_LATC2", + GL_LUMINANCE_ALPHA, + GL_SIGNED_NORMALIZED, + 0, 0, 0, 4, + 4, 0, 0, 0, 0, + 4, 4, 16 /* 16 bytes per 4x4 block */ + }, }; @@ -1570,6 +1606,10 @@ _mesa_format_to_type_and_comps(gl_format format, case MESA_FORMAT_SIGNED_RED_RGTC1: case MESA_FORMAT_RG_RGTC2: case MESA_FORMAT_SIGNED_RG_RGTC2: + case MESA_FORMAT_L_LATC1: + case MESA_FORMAT_SIGNED_L_LATC1: + case MESA_FORMAT_LA_LATC2: + case MESA_FORMAT_SIGNED_LA_LATC2: /* XXX generate error instead? */ *datatype = GL_UNSIGNED_BYTE; *comps = 0; diff --git a/mesalib/src/mesa/main/formats.h b/mesalib/src/mesa/main/formats.h index e21967e2b..04a18930b 100644 --- a/mesalib/src/mesa/main/formats.h +++ b/mesalib/src/mesa/main/formats.h @@ -185,6 +185,14 @@ typedef enum MESA_FORMAT_RG_RGTC2, MESA_FORMAT_SIGNED_RG_RGTC2, /*@}*/ + + /*@{*/ + MESA_FORMAT_L_LATC1, + MESA_FORMAT_SIGNED_L_LATC1, + MESA_FORMAT_LA_LATC2, + MESA_FORMAT_SIGNED_LA_LATC2, + /*@}*/ + MESA_FORMAT_COUNT } gl_format; diff --git a/mesalib/src/mesa/main/glheader.h b/mesalib/src/mesa/main/glheader.h index 5ca44deb0..0df811986 100644 --- a/mesalib/src/mesa/main/glheader.h +++ b/mesalib/src/mesa/main/glheader.h @@ -1,163 +1,167 @@ -/* - * Mesa 3-D graphics library - * Version: 7.5 - * - * Copyright (C) 1999-2008 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. - */ - - -/** - * \file glheader.h - * Wrapper for GL/gl.h and GL/glext.h - */ - - -#ifndef GLHEADER_H -#define GLHEADER_H - - -#ifdef WGLAPI -#undef WGLAPI -#endif - - -#if !defined(OPENSTEP) && (defined(__WIN32__) && !defined(__CYGWIN__)) && !defined(BUILD_FOR_SNAP) -# if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(BUILD_GL32) /* tag specify we're building mesa as a DLL */ -# define WGLAPI __declspec(dllexport) -# elif (defined(_MSC_VER) || defined(__MINGW32__)) && defined(_DLL) /* tag specifying we're building for DLL runtime support */ -# define WGLAPI __declspec(dllimport) -# else /* for use with static link lib build of Win32 edition only */ -# define WGLAPI __declspec(dllimport) -# endif /* _STATIC_MESA support */ -#endif /* WIN32 / CYGWIN bracket */ - - -#define GL_GLEXT_PROTOTYPES -#include "GL/gl.h" -#include "GL/glext.h" - - -/** - * GL_FIXED is defined in glext.h version 64 but these typedefs aren't (yet). - */ -typedef int GLfixed; -typedef int GLclampx; - - -#ifndef GL_OES_EGL_image -typedef void *GLeglImageOES; -#endif - - -#ifndef GL_OES_point_size_array -#define GL_POINT_SIZE_ARRAY_OES 0x8B9C -#define GL_POINT_SIZE_ARRAY_TYPE_OES 0x898A -#define GL_POINT_SIZE_ARRAY_STRIDE_OES 0x898B -#define GL_POINT_SIZE_ARRAY_POINTER_OES 0x898C -#define GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES 0x8B9F -#endif - - -#ifndef GL_OES_draw_texture -#define GL_TEXTURE_CROP_RECT_OES 0x8B9D -#endif - - -#ifndef GL_PROGRAM_BINARY_LENGTH_OES -#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741 -#endif - -/* GLES 2.0 tokens */ -#ifndef GL_RGB565 -#define GL_RGB565 0x8D62 -#endif - -#ifndef GL_TEXTURE_GEN_STR_OES -#define GL_TEXTURE_GEN_STR_OES 0x8D60 -#endif - -#ifndef GL_OES_compressed_paletted_texture -#define GL_PALETTE4_RGB8_OES 0x8B90 -#define GL_PALETTE4_RGBA8_OES 0x8B91 -#define GL_PALETTE4_R5_G6_B5_OES 0x8B92 -#define GL_PALETTE4_RGBA4_OES 0x8B93 -#define GL_PALETTE4_RGB5_A1_OES 0x8B94 -#define GL_PALETTE8_RGB8_OES 0x8B95 -#define GL_PALETTE8_RGBA8_OES 0x8B96 -#define GL_PALETTE8_R5_G6_B5_OES 0x8B97 -#define GL_PALETTE8_RGBA4_OES 0x8B98 -#define GL_PALETTE8_RGB5_A1_OES 0x8B99 -#endif - -#ifndef GL_OES_matrix_get -#define GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES 0x898D -#define GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES 0x898E -#define GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES 0x898F -#endif - -#ifndef GL_ES_VERSION_2_0 -#define GL_SHADER_BINARY_FORMATS 0x8DF8 -#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 -#define GL_SHADER_COMPILER 0x8DFA -#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB -#define GL_MAX_VARYING_VECTORS 0x8DFC -#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD -#endif - - - -/** - * Internal token to represent a GLSL shader program (a collection of - * one or more shaders that get linked together). Note that GLSL - * shaders and shader programs share one name space (one hash table) - * so we need a value that's different from any of the - * GL_VERTEX/FRAGMENT/GEOMETRY_PROGRAM tokens. - */ -#define GL_SHADER_PROGRAM_MESA 0x9999 - - -/** - * Internal token for geometry programs. - * Use the value for GL_GEOMETRY_PROGRAM_NV for now. - */ -#define MESA_GEOMETRY_PROGRAM 0x8c26 - -/* Several fields of struct gl_config can take these as values. Since - * GLX header files may not be available everywhere they need to be used, - * redefine them here. - */ -#define GLX_NONE 0x8000 -#define GLX_SLOW_CONFIG 0x8001 -#define GLX_TRUE_COLOR 0x8002 -#define GLX_DIRECT_COLOR 0x8003 -#define GLX_PSEUDO_COLOR 0x8004 -#define GLX_STATIC_COLOR 0x8005 -#define GLX_GRAY_SCALE 0x8006 -#define GLX_STATIC_GRAY 0x8007 -#define GLX_TRANSPARENT_RGB 0x8008 -#define GLX_TRANSPARENT_INDEX 0x8009 -#define GLX_NON_CONFORMANT_CONFIG 0x800D -#define GLX_SWAP_EXCHANGE_OML 0x8061 -#define GLX_SWAP_COPY_OML 0x8062 -#define GLX_SWAP_UNDEFINED_OML 0x8063 - -#define GLX_DONT_CARE 0xFFFFFFFF - -#endif /* GLHEADER_H */ +/* + * Mesa 3-D graphics library + * Version: 7.5 + * + * Copyright (C) 1999-2008 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. + */ + + +/** + * \file glheader.h + * Wrapper for GL/gl.h and GL/glext.h + */ + + +#ifndef GLHEADER_H +#define GLHEADER_H + + +#ifdef WGLAPI +#undef WGLAPI +#endif + + +#if !defined(OPENSTEP) && (defined(__WIN32__) && !defined(__CYGWIN__)) && !defined(BUILD_FOR_SNAP) +# if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(BUILD_GL32) /* tag specify we're building mesa as a DLL */ +# define WGLAPI __declspec(dllexport) +# elif (defined(_MSC_VER) || defined(__MINGW32__)) && defined(_DLL) /* tag specifying we're building for DLL runtime support */ +# define WGLAPI __declspec(dllimport) +# else /* for use with static link lib build of Win32 edition only */ +# define WGLAPI __declspec(dllimport) +# endif /* _STATIC_MESA support */ +#endif /* WIN32 / CYGWIN bracket */ + + +#define GL_GLEXT_PROTOTYPES +#include "GL/gl.h" +#include "GL/glext.h" + + +/** + * GL_FIXED is defined in glext.h version 64 but these typedefs aren't (yet). + */ +typedef int GLfixed; +typedef int GLclampx; + + +#ifndef GL_OES_EGL_image +typedef void *GLeglImageOES; +#endif + + +#ifndef GL_OES_point_size_array +#define GL_POINT_SIZE_ARRAY_OES 0x8B9C +#define GL_POINT_SIZE_ARRAY_TYPE_OES 0x898A +#define GL_POINT_SIZE_ARRAY_STRIDE_OES 0x898B +#define GL_POINT_SIZE_ARRAY_POINTER_OES 0x898C +#define GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES 0x8B9F +#endif + + +#ifndef GL_OES_draw_texture +#define GL_TEXTURE_CROP_RECT_OES 0x8B9D +#endif + + +#ifndef GL_PROGRAM_BINARY_LENGTH_OES +#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741 +#endif + +/* GLES 2.0 tokens */ +#ifndef GL_RGB565 +#define GL_RGB565 0x8D62 +#endif + +#ifndef GL_TEXTURE_GEN_STR_OES +#define GL_TEXTURE_GEN_STR_OES 0x8D60 +#endif + +#ifndef GL_OES_compressed_paletted_texture +#define GL_PALETTE4_RGB8_OES 0x8B90 +#define GL_PALETTE4_RGBA8_OES 0x8B91 +#define GL_PALETTE4_R5_G6_B5_OES 0x8B92 +#define GL_PALETTE4_RGBA4_OES 0x8B93 +#define GL_PALETTE4_RGB5_A1_OES 0x8B94 +#define GL_PALETTE8_RGB8_OES 0x8B95 +#define GL_PALETTE8_RGBA8_OES 0x8B96 +#define GL_PALETTE8_R5_G6_B5_OES 0x8B97 +#define GL_PALETTE8_RGBA4_OES 0x8B98 +#define GL_PALETTE8_RGB5_A1_OES 0x8B99 +#endif + +#ifndef GL_OES_matrix_get +#define GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES 0x898D +#define GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES 0x898E +#define GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES 0x898F +#endif + +#ifndef GL_ES_VERSION_2_0 +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#endif + +#ifndef GL_ATI_texture_compression_3dc +#define GL_ATI_texture_compression_3dc 1 +#define GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI 0x8837 +#endif + + +/** + * Internal token to represent a GLSL shader program (a collection of + * one or more shaders that get linked together). Note that GLSL + * shaders and shader programs share one name space (one hash table) + * so we need a value that's different from any of the + * GL_VERTEX/FRAGMENT/GEOMETRY_PROGRAM tokens. + */ +#define GL_SHADER_PROGRAM_MESA 0x9999 + + +/** + * Internal token for geometry programs. + * Use the value for GL_GEOMETRY_PROGRAM_NV for now. + */ +#define MESA_GEOMETRY_PROGRAM 0x8c26 + +/* Several fields of struct gl_config can take these as values. Since + * GLX header files may not be available everywhere they need to be used, + * redefine them here. + */ +#define GLX_NONE 0x8000 +#define GLX_SLOW_CONFIG 0x8001 +#define GLX_TRUE_COLOR 0x8002 +#define GLX_DIRECT_COLOR 0x8003 +#define GLX_PSEUDO_COLOR 0x8004 +#define GLX_STATIC_COLOR 0x8005 +#define GLX_GRAY_SCALE 0x8006 +#define GLX_STATIC_GRAY 0x8007 +#define GLX_TRANSPARENT_RGB 0x8008 +#define GLX_TRANSPARENT_INDEX 0x8009 +#define GLX_NON_CONFORMANT_CONFIG 0x800D +#define GLX_SWAP_EXCHANGE_OML 0x8061 +#define GLX_SWAP_COPY_OML 0x8062 +#define GLX_SWAP_UNDEFINED_OML 0x8063 + +#define GLX_DONT_CARE 0xFFFFFFFF + +#endif /* GLHEADER_H */ diff --git a/mesalib/src/mesa/main/image.c b/mesalib/src/mesa/main/image.c index 444f21ed5..bbde3800e 100644 --- a/mesalib/src/mesa/main/image.c +++ b/mesalib/src/mesa/main/image.c @@ -1,1879 +1,1891 @@ -/* - * Mesa 3-D graphics library - * Version: 7.5 - * - * Copyright (C) 1999-2008 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. - */ - - -/** - * \file image.c - * Image handling. - */ - - -#include "glheader.h" -#include "colormac.h" -#include "image.h" -#include "imports.h" -#include "macros.h" -#include "mfeatures.h" -#include "mtypes.h" - - -/** - * NOTE: - * Normally, BYTE_TO_FLOAT(0) returns 0.00392 That causes problems when - * we later convert the float to a packed integer value (such as for - * GL_RGB5_A1) because we'll wind up with a non-zero value. - * - * We redefine the macros here so zero is handled correctly. - */ -#undef BYTE_TO_FLOAT -#define BYTE_TO_FLOAT(B) ((B) == 0 ? 0.0F : ((2.0F * (B) + 1.0F) * (1.0F/255.0F))) - -#undef SHORT_TO_FLOAT -#define SHORT_TO_FLOAT(S) ((S) == 0 ? 0.0F : ((2.0F * (S) + 1.0F) * (1.0F/65535.0F))) - - - -/** Compute ceiling of integer quotient of A divided by B. */ -#define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 ) - - -/** - * \return GL_TRUE if type is packed pixel type, GL_FALSE otherwise. - */ -GLboolean -_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: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - case GL_UNSIGNED_SHORT_8_8_MESA: - case GL_UNSIGNED_SHORT_8_8_REV_MESA: - case GL_UNSIGNED_INT_24_8_EXT: - return GL_TRUE; - } - - return GL_FALSE; -} - - - -/** - * Flip the order of the 2 bytes in each word in the given array. - * - * \param p array. - * \param n number of words. - */ -void -_mesa_swap2( GLushort *p, GLuint n ) -{ - GLuint i; - for (i = 0; i < n; i++) { - p[i] = (p[i] >> 8) | ((p[i] << 8) & 0xff00); - } -} - - - -/* - * Flip the order of the 4 bytes in each word in the given array. - */ -void -_mesa_swap4( GLuint *p, GLuint n ) -{ - GLuint i, a, b; - for (i = 0; i < n; i++) { - b = p[i]; - a = (b >> 24) - | ((b >> 8) & 0xff00) - | ((b << 8) & 0xff0000) - | ((b << 24) & 0xff000000); - p[i] = a; - } -} - - -/** - * Get the size of a GL data type. - * - * \param type GL data type. - * - * \return the size, in bytes, of the given data type, 0 if a GL_BITMAP, or -1 - * if an invalid type enum. - */ -GLint -_mesa_sizeof_type( GLenum type ) -{ - switch (type) { - case GL_BITMAP: - return 0; - case GL_UNSIGNED_BYTE: - return sizeof(GLubyte); - case GL_BYTE: - return sizeof(GLbyte); - case GL_UNSIGNED_SHORT: - return sizeof(GLushort); - case GL_SHORT: - return sizeof(GLshort); - case GL_UNSIGNED_INT: - return sizeof(GLuint); - case GL_INT: - return sizeof(GLint); - case GL_FLOAT: - return sizeof(GLfloat); - case GL_DOUBLE: - return sizeof(GLdouble); - case GL_HALF_FLOAT_ARB: - return sizeof(GLhalfARB); - case GL_FIXED: - return sizeof(GLfixed); - default: - return -1; - } -} - - -/** - * Same as _mesa_sizeof_type() but also accepting the packed pixel - * format data types. - */ -GLint -_mesa_sizeof_packed_type( GLenum type ) -{ - switch (type) { - case GL_BITMAP: - return 0; - case GL_UNSIGNED_BYTE: - return sizeof(GLubyte); - case GL_BYTE: - return sizeof(GLbyte); - case GL_UNSIGNED_SHORT: - return sizeof(GLushort); - case GL_SHORT: - return sizeof(GLshort); - case GL_UNSIGNED_INT: - return sizeof(GLuint); - case GL_INT: - return sizeof(GLint); - case GL_HALF_FLOAT_ARB: - return sizeof(GLhalfARB); - case GL_FLOAT: - return sizeof(GLfloat); - case GL_UNSIGNED_BYTE_3_3_2: - 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: - return sizeof(GLushort); - case GL_UNSIGNED_SHORT_4_4_4_4: - return sizeof(GLushort); - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - return sizeof(GLushort); - case GL_UNSIGNED_SHORT_5_5_5_1: - return sizeof(GLushort); - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - return sizeof(GLushort); - case GL_UNSIGNED_INT_8_8_8_8: - return sizeof(GLuint); - case GL_UNSIGNED_INT_8_8_8_8_REV: - return sizeof(GLuint); - case GL_UNSIGNED_INT_10_10_10_2: - return sizeof(GLuint); - case GL_UNSIGNED_INT_2_10_10_10_REV: - return sizeof(GLuint); - case GL_UNSIGNED_SHORT_8_8_MESA: - case GL_UNSIGNED_SHORT_8_8_REV_MESA: - return sizeof(GLushort); - case GL_UNSIGNED_INT_24_8_EXT: - return sizeof(GLuint); - default: - return -1; - } -} - - -/** - * Get the number of components in a pixel format. - * - * \param format pixel format. - * - * \return the number of components in the given format, or -1 if a bad format. - */ -GLint -_mesa_components_in_format( GLenum format ) -{ - switch (format) { - case GL_COLOR_INDEX: - case GL_COLOR_INDEX1_EXT: - case GL_COLOR_INDEX2_EXT: - case GL_COLOR_INDEX4_EXT: - case GL_COLOR_INDEX8_EXT: - case GL_COLOR_INDEX12_EXT: - case GL_COLOR_INDEX16_EXT: - case GL_STENCIL_INDEX: - case GL_DEPTH_COMPONENT: - case GL_RED: - case GL_RED_INTEGER_EXT: - case GL_GREEN: - case GL_GREEN_INTEGER_EXT: - case GL_BLUE: - case GL_BLUE_INTEGER_EXT: - case GL_ALPHA: - case GL_ALPHA_INTEGER_EXT: - case GL_LUMINANCE: - case GL_LUMINANCE_INTEGER_EXT: - case GL_INTENSITY: - return 1; - case GL_LUMINANCE_ALPHA: - case GL_LUMINANCE_ALPHA_INTEGER_EXT: - case GL_RG: - return 2; - case GL_RGB: - case GL_RGB_INTEGER_EXT: - return 3; - case GL_RGBA: - case GL_RGBA_INTEGER_EXT: - return 4; - case GL_BGR: - return 3; - case GL_BGRA: - return 4; - case GL_ABGR_EXT: - return 4; - case GL_YCBCR_MESA: - return 2; - case GL_DEPTH_STENCIL_EXT: - return 2; - case GL_DUDV_ATI: - case GL_DU8DV8_ATI: - return 2; - default: - return -1; - } -} - - -/** - * Get the bytes per pixel of pixel format type pair. - * - * \param format pixel format. - * \param type pixel type. - * - * \return bytes per pixel, or -1 if a bad format or type was given. - */ -GLint -_mesa_bytes_per_pixel( GLenum format, GLenum type ) -{ - GLint comps = _mesa_components_in_format( format ); - if (comps < 0) - return -1; - - switch (type) { - case GL_BITMAP: - return 0; /* special case */ - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return comps * sizeof(GLubyte); - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return comps * sizeof(GLshort); - case GL_INT: - case GL_UNSIGNED_INT: - return comps * sizeof(GLint); - case GL_FLOAT: - return comps * sizeof(GLfloat); - case GL_HALF_FLOAT_ARB: - return comps * sizeof(GLhalfARB); - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - if (format == GL_RGB || format == GL_BGR || - format == GL_RGB_INTEGER_EXT || format == GL_BGR_INTEGER_EXT) - return sizeof(GLubyte); - else - return -1; /* error */ - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - if (format == GL_RGB || format == GL_BGR || - format == GL_RGB_INTEGER_EXT || format == GL_BGR_INTEGER_EXT) - return sizeof(GLushort); - else - return -1; /* error */ - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - if (format == GL_RGBA || format == GL_BGRA || format == GL_ABGR_EXT || - format == GL_RGBA_INTEGER_EXT || format == GL_BGRA_INTEGER_EXT) - return sizeof(GLushort); - else - return -1; - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - if (format == GL_RGBA || format == GL_BGRA || format == GL_ABGR_EXT || - format == GL_RGBA_INTEGER_EXT || format == GL_BGRA_INTEGER_EXT) - return sizeof(GLuint); - else - return -1; - case GL_UNSIGNED_SHORT_8_8_MESA: - case GL_UNSIGNED_SHORT_8_8_REV_MESA: - if (format == GL_YCBCR_MESA) - return sizeof(GLushort); - else - return -1; - case GL_UNSIGNED_INT_24_8_EXT: - if (format == GL_DEPTH_STENCIL_EXT) - return sizeof(GLuint); - else - return -1; - default: - return -1; - } -} - - -/** - * Test for a legal pixel format and type. - * - * \param format pixel format. - * \param type pixel type. - * - * \return GL_TRUE if the given pixel format and type are legal, or GL_FALSE - * otherwise. - */ -GLboolean -_mesa_is_legal_format_and_type(const struct gl_context *ctx, - GLenum format, GLenum type) -{ - switch (format) { - case GL_COLOR_INDEX: - case GL_STENCIL_INDEX: - switch (type) { - case GL_BITMAP: - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - return GL_TRUE; - case GL_HALF_FLOAT_ARB: - return ctx->Extensions.ARB_half_float_pixel; - default: - return GL_FALSE; - } - case GL_RED: - case GL_GREEN: - case GL_BLUE: - case GL_ALPHA: -#if 0 /* not legal! see table 3.6 of the 1.5 spec */ - case GL_INTENSITY: -#endif - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - case GL_DEPTH_COMPONENT: - switch (type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - return GL_TRUE; - case GL_HALF_FLOAT_ARB: - return ctx->Extensions.ARB_half_float_pixel; - default: - return GL_FALSE; - } - case GL_RG: - if (!ctx->Extensions.ARB_texture_rg) - return GL_FALSE; - - switch (type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - return GL_TRUE; - case GL_HALF_FLOAT_ARB: - return ctx->Extensions.ARB_half_float_pixel; - default: - return GL_FALSE; - } - case GL_RGB: - switch (type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - return GL_TRUE; - case GL_HALF_FLOAT_ARB: - return ctx->Extensions.ARB_half_float_pixel; - default: - return GL_FALSE; - } - case GL_BGR: - switch (type) { - /* NOTE: no packed types are supported with BGR. That's - * intentional, according to the GL spec. - */ - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - return GL_TRUE; - case GL_HALF_FLOAT_ARB: - return ctx->Extensions.ARB_half_float_pixel; - default: - return GL_FALSE; - } - case GL_RGBA: - case GL_BGRA: - case GL_ABGR_EXT: - switch (type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - return GL_TRUE; - case GL_HALF_FLOAT_ARB: - return ctx->Extensions.ARB_half_float_pixel; - default: - return GL_FALSE; - } - case GL_YCBCR_MESA: - if (type == GL_UNSIGNED_SHORT_8_8_MESA || - type == GL_UNSIGNED_SHORT_8_8_REV_MESA) - return GL_TRUE; - else - return GL_FALSE; - case GL_DEPTH_STENCIL_EXT: - if (ctx->Extensions.EXT_packed_depth_stencil - && type == GL_UNSIGNED_INT_24_8_EXT) - return GL_TRUE; - else - return GL_FALSE; - case GL_DUDV_ATI: - case GL_DU8DV8_ATI: - switch (type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - return GL_TRUE; - default: - return GL_FALSE; - } - - /* integer-valued formats */ - case GL_RED_INTEGER_EXT: - case GL_GREEN_INTEGER_EXT: - case GL_BLUE_INTEGER_EXT: - case GL_ALPHA_INTEGER_EXT: - switch (type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - return ctx->Extensions.EXT_texture_integer; - default: - return GL_FALSE; - } - - case GL_RGB_INTEGER_EXT: - switch (type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - return ctx->Extensions.EXT_texture_integer; - default: - return GL_FALSE; - } - - case GL_BGR_INTEGER_EXT: - switch (type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - /* NOTE: no packed formats w/ BGR format */ - return ctx->Extensions.EXT_texture_integer; - default: - return GL_FALSE; - } - - case GL_RGBA_INTEGER_EXT: - case GL_BGRA_INTEGER_EXT: - switch (type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - return ctx->Extensions.EXT_texture_integer; - default: - return GL_FALSE; - } - - case GL_LUMINANCE_INTEGER_EXT: - case GL_LUMINANCE_ALPHA_INTEGER_EXT: - switch (type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - return ctx->Extensions.EXT_texture_integer; - default: - return GL_FALSE; - } - - default: - ; /* fall-through */ - } - return GL_FALSE; -} - - -/** - * Test if the given image format is a color/RGBA format (i.e., not color - * index, depth, stencil, etc). - * \param format the image format value (may by an internal texture format) - * \return GL_TRUE if its a color/RGBA format, GL_FALSE otherwise. - */ -GLboolean -_mesa_is_color_format(GLenum format) -{ - switch (format) { - case GL_RED: - case GL_GREEN: - case GL_BLUE: - case GL_ALPHA: - case GL_ALPHA4: - case GL_ALPHA8: - case GL_ALPHA12: - case GL_ALPHA16: - case 1: - case GL_LUMINANCE: - case GL_LUMINANCE4: - case GL_LUMINANCE8: - case GL_LUMINANCE12: - case GL_LUMINANCE16: - case 2: - 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: - case GL_INTENSITY: - case GL_INTENSITY4: - case GL_INTENSITY8: - case GL_INTENSITY12: - case GL_INTENSITY16: - case GL_R8: - case GL_R16: - case GL_RG: - case GL_RG8: - case GL_RG16: - case 3: - case GL_RGB: - case GL_BGR: - case GL_R3_G3_B2: - case GL_RGB4: - case GL_RGB5: - case GL_RGB8: - case GL_RGB10: - case GL_RGB12: - case GL_RGB16: - case 4: - case GL_ABGR_EXT: - case GL_RGBA: - case GL_BGRA: - case GL_RGBA2: - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGBA8: - case GL_RGB10_A2: - case GL_RGBA12: - case GL_RGBA16: - /* float texture formats */ - case GL_ALPHA16F_ARB: - case GL_ALPHA32F_ARB: - case GL_LUMINANCE16F_ARB: - case GL_LUMINANCE32F_ARB: - case GL_LUMINANCE_ALPHA16F_ARB: - case GL_LUMINANCE_ALPHA32F_ARB: - case GL_INTENSITY16F_ARB: - case GL_INTENSITY32F_ARB: - case GL_R16F: - case GL_R32F: - case GL_RG16F: - case GL_RG32F: - case GL_RGB16F_ARB: - case GL_RGB32F_ARB: - case GL_RGBA16F_ARB: - case GL_RGBA32F_ARB: - /* compressed formats */ - case GL_COMPRESSED_ALPHA: - case GL_COMPRESSED_LUMINANCE: - case GL_COMPRESSED_LUMINANCE_ALPHA: - case GL_COMPRESSED_INTENSITY: - case GL_COMPRESSED_RED: - case GL_COMPRESSED_RG: - case GL_COMPRESSED_RGB: - case GL_COMPRESSED_RGBA: - case GL_RGB_S3TC: - case GL_RGB4_S3TC: - case GL_RGBA_S3TC: - case GL_RGBA4_S3TC: - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - case GL_COMPRESSED_RGB_FXT1_3DFX: - case GL_COMPRESSED_RGBA_FXT1_3DFX: -#if FEATURE_EXT_texture_sRGB - case GL_SRGB_EXT: - case GL_SRGB8_EXT: - case GL_SRGB_ALPHA_EXT: - case GL_SRGB8_ALPHA8_EXT: - case GL_SLUMINANCE_ALPHA_EXT: - case GL_SLUMINANCE8_ALPHA8_EXT: - case GL_SLUMINANCE_EXT: - case GL_SLUMINANCE8_EXT: - case GL_COMPRESSED_SRGB_EXT: - case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_SRGB_ALPHA_EXT: - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: - case GL_COMPRESSED_SLUMINANCE_EXT: - case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT: -#endif /* FEATURE_EXT_texture_sRGB */ - case GL_COMPRESSED_RED_RGTC1: - case GL_COMPRESSED_SIGNED_RED_RGTC1: - case GL_COMPRESSED_RG_RGTC2: - case GL_COMPRESSED_SIGNED_RG_RGTC2: - /* signed, normalized texture formats */ - case GL_RGBA_SNORM: - case GL_RGBA8_SNORM: - /* generic integer formats */ - case GL_RED_INTEGER_EXT: - case GL_GREEN_INTEGER_EXT: - case GL_BLUE_INTEGER_EXT: - case GL_ALPHA_INTEGER_EXT: - case GL_RGB_INTEGER_EXT: - case GL_RGBA_INTEGER_EXT: - case GL_BGR_INTEGER_EXT: - case GL_BGRA_INTEGER_EXT: - case GL_LUMINANCE_INTEGER_EXT: - case GL_LUMINANCE_ALPHA_INTEGER_EXT: - /* sized integer formats */ - case GL_RGBA32UI_EXT: - case GL_RGB32UI_EXT: - case GL_ALPHA32UI_EXT: - case GL_INTENSITY32UI_EXT: - case GL_LUMINANCE32UI_EXT: - case GL_LUMINANCE_ALPHA32UI_EXT: - case GL_RGBA16UI_EXT: - case GL_RGB16UI_EXT: - case GL_ALPHA16UI_EXT: - case GL_INTENSITY16UI_EXT: - case GL_LUMINANCE16UI_EXT: - case GL_LUMINANCE_ALPHA16UI_EXT: - case GL_RGBA8UI_EXT: - case GL_RGB8UI_EXT: - case GL_ALPHA8UI_EXT: - case GL_INTENSITY8UI_EXT: - case GL_LUMINANCE8UI_EXT: - case GL_LUMINANCE_ALPHA8UI_EXT: - case GL_RGBA32I_EXT: - case GL_RGB32I_EXT: - case GL_ALPHA32I_EXT: - case GL_INTENSITY32I_EXT: - case GL_LUMINANCE32I_EXT: - case GL_LUMINANCE_ALPHA32I_EXT: - case GL_RGBA16I_EXT: - case GL_RGB16I_EXT: - case GL_ALPHA16I_EXT: - case GL_INTENSITY16I_EXT: - case GL_LUMINANCE16I_EXT: - case GL_LUMINANCE_ALPHA16I_EXT: - case GL_RGBA8I_EXT: - case GL_RGB8I_EXT: - case GL_ALPHA8I_EXT: - case GL_INTENSITY8I_EXT: - case GL_LUMINANCE8I_EXT: - case GL_LUMINANCE_ALPHA8I_EXT: - return GL_TRUE; - case GL_YCBCR_MESA: /* not considered to be RGB */ - /* fall-through */ - default: - return GL_FALSE; - } -} - - -/** - * Test if the given image format is a color index format. - */ -GLboolean -_mesa_is_index_format(GLenum format) -{ - switch (format) { - case GL_COLOR_INDEX: - case GL_COLOR_INDEX1_EXT: - case GL_COLOR_INDEX2_EXT: - case GL_COLOR_INDEX4_EXT: - case GL_COLOR_INDEX8_EXT: - case GL_COLOR_INDEX12_EXT: - case GL_COLOR_INDEX16_EXT: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Test if the given image format is a depth component format. - */ -GLboolean -_mesa_is_depth_format(GLenum format) -{ - switch (format) { - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT24: - case GL_DEPTH_COMPONENT32: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Test if the given image format is a stencil format. - */ -GLboolean -_mesa_is_stencil_format(GLenum format) -{ - switch (format) { - case GL_STENCIL_INDEX: - case GL_DEPTH_STENCIL: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Test if the given image format is a YCbCr format. - */ -GLboolean -_mesa_is_ycbcr_format(GLenum format) -{ - switch (format) { - case GL_YCBCR_MESA: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Test if the given image format is a depth+stencil format. - */ -GLboolean -_mesa_is_depthstencil_format(GLenum format) -{ - switch (format) { - case GL_DEPTH24_STENCIL8_EXT: - case GL_DEPTH_STENCIL_EXT: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Test if the given image format is a depth or stencil format. - */ -GLboolean -_mesa_is_depth_or_stencil_format(GLenum format) -{ - switch (format) { - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT24: - case GL_DEPTH_COMPONENT32: - case GL_STENCIL_INDEX: - case GL_STENCIL_INDEX1_EXT: - case GL_STENCIL_INDEX4_EXT: - case GL_STENCIL_INDEX8_EXT: - case GL_STENCIL_INDEX16_EXT: - case GL_DEPTH_STENCIL_EXT: - case GL_DEPTH24_STENCIL8_EXT: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Test if the given image format is a dudv format. - */ -GLboolean -_mesa_is_dudv_format(GLenum format) -{ - switch (format) { - case GL_DUDV_ATI: - case GL_DU8DV8_ATI: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Test if the given format is an integer (non-normalized) format. - */ -GLboolean -_mesa_is_integer_format(GLenum format) -{ - switch (format) { - /* generic integer formats */ - case GL_RED_INTEGER_EXT: - case GL_GREEN_INTEGER_EXT: - case GL_BLUE_INTEGER_EXT: - case GL_ALPHA_INTEGER_EXT: - case GL_RGB_INTEGER_EXT: - case GL_RGBA_INTEGER_EXT: - case GL_BGR_INTEGER_EXT: - case GL_BGRA_INTEGER_EXT: - case GL_LUMINANCE_INTEGER_EXT: - case GL_LUMINANCE_ALPHA_INTEGER_EXT: - /* specific integer formats */ - case GL_RGBA32UI_EXT: - case GL_RGB32UI_EXT: - case GL_ALPHA32UI_EXT: - case GL_INTENSITY32UI_EXT: - case GL_LUMINANCE32UI_EXT: - case GL_LUMINANCE_ALPHA32UI_EXT: - case GL_RGBA16UI_EXT: - case GL_RGB16UI_EXT: - case GL_ALPHA16UI_EXT: - case GL_INTENSITY16UI_EXT: - case GL_LUMINANCE16UI_EXT: - case GL_LUMINANCE_ALPHA16UI_EXT: - case GL_RGBA8UI_EXT: - case GL_RGB8UI_EXT: - case GL_ALPHA8UI_EXT: - case GL_INTENSITY8UI_EXT: - case GL_LUMINANCE8UI_EXT: - case GL_LUMINANCE_ALPHA8UI_EXT: - case GL_RGBA32I_EXT: - case GL_RGB32I_EXT: - case GL_ALPHA32I_EXT: - case GL_INTENSITY32I_EXT: - case GL_LUMINANCE32I_EXT: - case GL_LUMINANCE_ALPHA32I_EXT: - case GL_RGBA16I_EXT: - case GL_RGB16I_EXT: - case GL_ALPHA16I_EXT: - case GL_INTENSITY16I_EXT: - case GL_LUMINANCE16I_EXT: - case GL_LUMINANCE_ALPHA16I_EXT: - case GL_RGBA8I_EXT: - case GL_RGB8I_EXT: - case GL_ALPHA8I_EXT: - case GL_INTENSITY8I_EXT: - case GL_LUMINANCE8I_EXT: - case GL_LUMINANCE_ALPHA8I_EXT: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Test if an image format is a supported compressed format. - * \param format the internal format token provided by the user. - * \return GL_TRUE if compressed, GL_FALSE if uncompressed - */ -GLboolean -_mesa_is_compressed_format(struct gl_context *ctx, GLenum format) -{ - switch (format) { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - return ctx->Extensions.EXT_texture_compression_s3tc; - case GL_RGB_S3TC: - case GL_RGB4_S3TC: - case GL_RGBA_S3TC: - case GL_RGBA4_S3TC: - return ctx->Extensions.S3_s3tc; - case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: - return ctx->Extensions.EXT_texture_sRGB - && ctx->Extensions.EXT_texture_compression_s3tc; - case GL_COMPRESSED_RGB_FXT1_3DFX: - case GL_COMPRESSED_RGBA_FXT1_3DFX: - return ctx->Extensions.TDFX_texture_compression_FXT1; - case GL_COMPRESSED_RED_RGTC1: - case GL_COMPRESSED_SIGNED_RED_RGTC1: - case GL_COMPRESSED_RG_RGTC2: - case GL_COMPRESSED_SIGNED_RG_RGTC2: - return ctx->Extensions.ARB_texture_compression_rgtc; - default: - return GL_FALSE; - } -} - - -/** - * Return the address of a specific pixel in an image (1D, 2D or 3D). - * - * Pixel unpacking/packing parameters are observed according to \p packing. - * - * \param dimensions either 1, 2 or 3 to indicate dimensionality of image - * \param image starting address of image data - * \param width the image width - * \param height theimage height - * \param format the pixel format - * \param type the pixel data type - * \param packing the pixelstore attributes - * \param img which image in the volume (0 for 1D or 2D images) - * \param row row of pixel in the image (0 for 1D images) - * \param column column of pixel in the image - * - * \return address of pixel on success, or NULL on error. - * - * \sa gl_pixelstore_attrib. - */ -GLvoid * -_mesa_image_address( GLuint dimensions, - const struct gl_pixelstore_attrib *packing, - const GLvoid *image, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - GLint img, GLint row, GLint column ) -{ - GLint alignment; /* 1, 2 or 4 */ - GLint pixels_per_row; - GLint rows_per_image; - GLint skiprows; - GLint skippixels; - GLint skipimages; /* for 3-D volume images */ - GLubyte *pixel_addr; - - ASSERT(dimensions >= 1 && dimensions <= 3); - - alignment = packing->Alignment; - if (packing->RowLength > 0) { - pixels_per_row = packing->RowLength; - } - else { - pixels_per_row = width; - } - if (packing->ImageHeight > 0) { - rows_per_image = packing->ImageHeight; - } - else { - rows_per_image = height; - } - - skippixels = packing->SkipPixels; - /* Note: SKIP_ROWS _is_ used for 1D images */ - skiprows = packing->SkipRows; - /* Note: SKIP_IMAGES is only used for 3D images */ - skipimages = (dimensions == 3) ? packing->SkipImages : 0; - - if (type == GL_BITMAP) { - /* BITMAP data */ - GLint comp_per_pixel; /* components per pixel */ - GLint bytes_per_comp; /* bytes per component */ - GLint bytes_per_row; - GLint bytes_per_image; - - /* Compute bytes per component */ - bytes_per_comp = _mesa_sizeof_packed_type( type ); - if (bytes_per_comp < 0) { - return NULL; - } - - /* Compute number of components per pixel */ - comp_per_pixel = _mesa_components_in_format( format ); - if (comp_per_pixel < 0) { - return NULL; - } - - bytes_per_row = alignment - * CEILING( comp_per_pixel*pixels_per_row, 8*alignment ); - - bytes_per_image = bytes_per_row * rows_per_image; - - pixel_addr = (GLubyte *) image - + (skipimages + img) * bytes_per_image - + (skiprows + row) * bytes_per_row - + (skippixels + column) / 8; - } - else { - /* Non-BITMAP data */ - GLint bytes_per_pixel, bytes_per_row, remainder, bytes_per_image; - GLint topOfImage; - - bytes_per_pixel = _mesa_bytes_per_pixel( format, type ); - - /* The pixel type and format should have been error checked earlier */ - assert(bytes_per_pixel > 0); - - bytes_per_row = pixels_per_row * bytes_per_pixel; - remainder = bytes_per_row % alignment; - if (remainder > 0) - bytes_per_row += (alignment - remainder); - - ASSERT(bytes_per_row % alignment == 0); - - bytes_per_image = bytes_per_row * rows_per_image; - - if (packing->Invert) { - /* set pixel_addr to the last row */ - topOfImage = bytes_per_row * (height - 1); - bytes_per_row = -bytes_per_row; - } - else { - topOfImage = 0; - } - - /* compute final pixel address */ - pixel_addr = (GLubyte *) image - + (skipimages + img) * bytes_per_image - + topOfImage - + (skiprows + row) * bytes_per_row - + (skippixels + column) * bytes_per_pixel; - } - - return (GLvoid *) pixel_addr; -} - - -GLvoid * -_mesa_image_address1d( const struct gl_pixelstore_attrib *packing, - const GLvoid *image, - GLsizei width, - GLenum format, GLenum type, - GLint column ) -{ - return _mesa_image_address(1, packing, image, width, 1, - format, type, 0, 0, column); -} - - -GLvoid * -_mesa_image_address2d( const struct gl_pixelstore_attrib *packing, - const GLvoid *image, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - GLint row, GLint column ) -{ - return _mesa_image_address(2, packing, image, width, height, - format, type, 0, row, column); -} - - -GLvoid * -_mesa_image_address3d( const struct gl_pixelstore_attrib *packing, - const GLvoid *image, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - GLint img, GLint row, GLint column ) -{ - return _mesa_image_address(3, packing, image, width, height, - format, type, img, row, column); -} - - - -/** - * Compute the stride (in bytes) between image rows. - * - * \param packing the pixelstore attributes - * \param width image width. - * \param format pixel format. - * \param type pixel data type. - * - * \return the stride in bytes for the given parameters, or -1 if error - */ -GLint -_mesa_image_row_stride( const struct gl_pixelstore_attrib *packing, - GLint width, GLenum format, GLenum type ) -{ - GLint bytesPerRow, remainder; - - ASSERT(packing); - - if (type == GL_BITMAP) { - if (packing->RowLength == 0) { - bytesPerRow = (width + 7) / 8; - } - else { - bytesPerRow = (packing->RowLength + 7) / 8; - } - } - else { - /* Non-BITMAP data */ - const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type); - if (bytesPerPixel <= 0) - return -1; /* error */ - if (packing->RowLength == 0) { - bytesPerRow = bytesPerPixel * width; - } - else { - bytesPerRow = bytesPerPixel * packing->RowLength; - } - } - - remainder = bytesPerRow % packing->Alignment; - if (remainder > 0) { - bytesPerRow += (packing->Alignment - remainder); - } - - if (packing->Invert) { - /* negate the bytes per row (negative row stride) */ - bytesPerRow = -bytesPerRow; - } - - return bytesPerRow; -} - - -/* - * Compute the stride between images in a 3D texture (in bytes) for the given - * pixel packing parameters and image width, format and type. - */ -GLint -_mesa_image_image_stride( const struct gl_pixelstore_attrib *packing, - GLint width, GLint height, - GLenum format, GLenum type ) -{ - GLint bytesPerRow, bytesPerImage, remainder; - - ASSERT(packing); - - if (type == GL_BITMAP) { - if (packing->RowLength == 0) { - bytesPerRow = (width + 7) / 8; - } - else { - bytesPerRow = (packing->RowLength + 7) / 8; - } - } - else { - const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type); - - if (bytesPerPixel <= 0) - return -1; /* error */ - if (packing->RowLength == 0) { - bytesPerRow = bytesPerPixel * width; - } - else { - bytesPerRow = bytesPerPixel * packing->RowLength; - } - } - - remainder = bytesPerRow % packing->Alignment; - if (remainder > 0) - bytesPerRow += (packing->Alignment - remainder); - - if (packing->ImageHeight == 0) - bytesPerImage = bytesPerRow * height; - else - bytesPerImage = bytesPerRow * packing->ImageHeight; - - return bytesPerImage; -} - - - -/** - * "Expand" a bitmap from 1-bit per pixel to 8-bits per pixel. - * This is typically used to convert a bitmap into a GLubyte/pixel texture. - * "On" bits will set texels to \p onValue. - * "Off" bits will not modify texels. - * \param width src bitmap width in pixels - * \param height src bitmap height in pixels - * \param unpack bitmap unpacking state - * \param bitmap the src bitmap data - * \param destBuffer start of dest buffer - * \param destStride row stride in dest buffer - * \param onValue if bit is 1, set destBuffer pixel to this value - */ -void -_mesa_expand_bitmap(GLsizei width, GLsizei height, - const struct gl_pixelstore_attrib *unpack, - const GLubyte *bitmap, - GLubyte *destBuffer, GLint destStride, - GLubyte onValue) -{ - const GLubyte *srcRow = (const GLubyte *) - _mesa_image_address2d(unpack, bitmap, width, height, - GL_COLOR_INDEX, GL_BITMAP, 0, 0); - const GLint srcStride = _mesa_image_row_stride(unpack, width, - GL_COLOR_INDEX, GL_BITMAP); - GLint row, col; - -#define SET_PIXEL(COL, ROW) \ - destBuffer[(ROW) * destStride + (COL)] = onValue; - - for (row = 0; row < height; row++) { - const GLubyte *src = srcRow; - - if (unpack->LsbFirst) { - /* Lsb first */ - GLubyte mask = 1U << (unpack->SkipPixels & 0x7); - for (col = 0; col < width; col++) { - - if (*src & mask) { - SET_PIXEL(col, row); - } - - if (mask == 128U) { - src++; - mask = 1U; - } - else { - mask = mask << 1; - } - } - - /* get ready for next row */ - if (mask != 1) - src++; - } - else { - /* Msb first */ - GLubyte mask = 128U >> (unpack->SkipPixels & 0x7); - for (col = 0; col < width; col++) { - - if (*src & mask) { - SET_PIXEL(col, row); - } - - if (mask == 1U) { - src++; - mask = 128U; - } - else { - mask = mask >> 1; - } - } - - /* get ready for next row */ - if (mask != 128) - src++; - } - - srcRow += srcStride; - } /* row */ - -#undef SET_PIXEL -} - - - - -/** - * Convert an array of RGBA colors from one datatype to another. - * NOTE: src may equal dst. In that case, we use a temporary buffer. - */ -void -_mesa_convert_colors(GLenum srcType, const GLvoid *src, - GLenum dstType, GLvoid *dst, - GLuint count, const GLubyte mask[]) -{ - GLuint tempBuffer[MAX_WIDTH][4]; - const GLboolean useTemp = (src == dst); - - ASSERT(srcType != dstType); - - switch (srcType) { - case GL_UNSIGNED_BYTE: - if (dstType == GL_UNSIGNED_SHORT) { - const GLubyte (*src1)[4] = (const GLubyte (*)[4]) src; - GLushort (*dst2)[4] = (GLushort (*)[4]) (useTemp ? tempBuffer : dst); - GLuint i; - for (i = 0; i < count; i++) { - if (!mask || mask[i]) { - dst2[i][RCOMP] = UBYTE_TO_USHORT(src1[i][RCOMP]); - dst2[i][GCOMP] = UBYTE_TO_USHORT(src1[i][GCOMP]); - dst2[i][BCOMP] = UBYTE_TO_USHORT(src1[i][BCOMP]); - dst2[i][ACOMP] = UBYTE_TO_USHORT(src1[i][ACOMP]); - } - } - if (useTemp) - memcpy(dst, tempBuffer, count * 4 * sizeof(GLushort)); - } - else { - const GLubyte (*src1)[4] = (const GLubyte (*)[4]) src; - GLfloat (*dst4)[4] = (GLfloat (*)[4]) (useTemp ? tempBuffer : dst); - GLuint i; - ASSERT(dstType == GL_FLOAT); - for (i = 0; i < count; i++) { - if (!mask || mask[i]) { - dst4[i][RCOMP] = UBYTE_TO_FLOAT(src1[i][RCOMP]); - dst4[i][GCOMP] = UBYTE_TO_FLOAT(src1[i][GCOMP]); - dst4[i][BCOMP] = UBYTE_TO_FLOAT(src1[i][BCOMP]); - dst4[i][ACOMP] = UBYTE_TO_FLOAT(src1[i][ACOMP]); - } - } - if (useTemp) - memcpy(dst, tempBuffer, count * 4 * sizeof(GLfloat)); - } - break; - case GL_UNSIGNED_SHORT: - if (dstType == GL_UNSIGNED_BYTE) { - const GLushort (*src2)[4] = (const GLushort (*)[4]) src; - GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst); - GLuint i; - for (i = 0; i < count; i++) { - if (!mask || mask[i]) { - dst1[i][RCOMP] = USHORT_TO_UBYTE(src2[i][RCOMP]); - dst1[i][GCOMP] = USHORT_TO_UBYTE(src2[i][GCOMP]); - dst1[i][BCOMP] = USHORT_TO_UBYTE(src2[i][BCOMP]); - dst1[i][ACOMP] = USHORT_TO_UBYTE(src2[i][ACOMP]); - } - } - if (useTemp) - memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte)); - } - else { - const GLushort (*src2)[4] = (const GLushort (*)[4]) src; - GLfloat (*dst4)[4] = (GLfloat (*)[4]) (useTemp ? tempBuffer : dst); - GLuint i; - ASSERT(dstType == GL_FLOAT); - for (i = 0; i < count; i++) { - if (!mask || mask[i]) { - dst4[i][RCOMP] = USHORT_TO_FLOAT(src2[i][RCOMP]); - dst4[i][GCOMP] = USHORT_TO_FLOAT(src2[i][GCOMP]); - dst4[i][BCOMP] = USHORT_TO_FLOAT(src2[i][BCOMP]); - dst4[i][ACOMP] = USHORT_TO_FLOAT(src2[i][ACOMP]); - } - } - if (useTemp) - memcpy(dst, tempBuffer, count * 4 * sizeof(GLfloat)); - } - break; - case GL_FLOAT: - if (dstType == GL_UNSIGNED_BYTE) { - const GLfloat (*src4)[4] = (const GLfloat (*)[4]) src; - GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst); - GLuint i; - for (i = 0; i < count; i++) { - if (!mask || mask[i]) { - UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][RCOMP], src4[i][RCOMP]); - UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][GCOMP], src4[i][GCOMP]); - UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][BCOMP], src4[i][BCOMP]); - UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][ACOMP], src4[i][ACOMP]); - } - } - if (useTemp) - memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte)); - } - else { - const GLfloat (*src4)[4] = (const GLfloat (*)[4]) src; - GLushort (*dst2)[4] = (GLushort (*)[4]) (useTemp ? tempBuffer : dst); - GLuint i; - ASSERT(dstType == GL_UNSIGNED_SHORT); - for (i = 0; i < count; i++) { - if (!mask || mask[i]) { - UNCLAMPED_FLOAT_TO_USHORT(dst2[i][RCOMP], src4[i][RCOMP]); - UNCLAMPED_FLOAT_TO_USHORT(dst2[i][GCOMP], src4[i][GCOMP]); - UNCLAMPED_FLOAT_TO_USHORT(dst2[i][BCOMP], src4[i][BCOMP]); - UNCLAMPED_FLOAT_TO_USHORT(dst2[i][ACOMP], src4[i][ACOMP]); - } - } - if (useTemp) - memcpy(dst, tempBuffer, count * 4 * sizeof(GLushort)); - } - break; - default: - _mesa_problem(NULL, "Invalid datatype in _mesa_convert_colors"); - } -} - - - - -/** - * Perform basic clipping for glDrawPixels. The image's position and size - * and the unpack SkipPixels and SkipRows are adjusted so that the image - * region is entirely within the window and scissor bounds. - * NOTE: this will only work when glPixelZoom is (1, 1) or (1, -1). - * If Pixel.ZoomY is -1, *destY will be changed to be the first row which - * we'll actually write. Beforehand, *destY-1 is the first drawing row. - * - * \return GL_TRUE if image is ready for drawing or - * GL_FALSE if image was completely clipped away (draw nothing) - */ -GLboolean -_mesa_clip_drawpixels(const struct gl_context *ctx, - GLint *destX, GLint *destY, - GLsizei *width, GLsizei *height, - struct gl_pixelstore_attrib *unpack) -{ - const struct gl_framebuffer *buffer = ctx->DrawBuffer; - - if (unpack->RowLength == 0) { - unpack->RowLength = *width; - } - - ASSERT(ctx->Pixel.ZoomX == 1.0F); - ASSERT(ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F); - - /* left clipping */ - if (*destX < buffer->_Xmin) { - unpack->SkipPixels += (buffer->_Xmin - *destX); - *width -= (buffer->_Xmin - *destX); - *destX = buffer->_Xmin; - } - /* right clipping */ - if (*destX + *width > buffer->_Xmax) - *width -= (*destX + *width - buffer->_Xmax); - - if (*width <= 0) - return GL_FALSE; - - if (ctx->Pixel.ZoomY == 1.0F) { - /* bottom clipping */ - if (*destY < buffer->_Ymin) { - unpack->SkipRows += (buffer->_Ymin - *destY); - *height -= (buffer->_Ymin - *destY); - *destY = buffer->_Ymin; - } - /* top clipping */ - if (*destY + *height > buffer->_Ymax) - *height -= (*destY + *height - buffer->_Ymax); - } - else { /* upside down */ - /* top clipping */ - if (*destY > buffer->_Ymax) { - unpack->SkipRows += (*destY - buffer->_Ymax); - *height -= (*destY - buffer->_Ymax); - *destY = buffer->_Ymax; - } - /* bottom clipping */ - if (*destY - *height < buffer->_Ymin) - *height -= (buffer->_Ymin - (*destY - *height)); - /* adjust destY so it's the first row to write to */ - (*destY)--; - } - - if (*height <= 0) - return GL_FALSE; - - return GL_TRUE; -} - - -/** - * Perform clipping for glReadPixels. The image's window position - * and size, and the pack skipPixels, skipRows and rowLength are adjusted - * so that the image region is entirely within the window bounds. - * Note: this is different from _mesa_clip_drawpixels() in that the - * scissor box is ignored, and we use the bounds of the current readbuffer - * surface. - * - * \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, - GLint *srcX, GLint *srcY, - GLsizei *width, GLsizei *height, - struct gl_pixelstore_attrib *pack) -{ - const struct gl_framebuffer *buffer = ctx->ReadBuffer; - - if (pack->RowLength == 0) { - pack->RowLength = *width; - } - - /* left clipping */ - if (*srcX < 0) { - pack->SkipPixels += (0 - *srcX); - *width -= (0 - *srcX); - *srcX = 0; - } - /* right clipping */ - if (*srcX + *width > (GLsizei) buffer->Width) - *width -= (*srcX + *width - buffer->Width); - - if (*width <= 0) - return GL_FALSE; - - /* bottom clipping */ - if (*srcY < 0) { - pack->SkipRows += (0 - *srcY); - *height -= (0 - *srcY); - *srcY = 0; - } - /* top clipping */ - if (*srcY + *height > (GLsizei) buffer->Height) - *height -= (*srcY + *height - buffer->Height); - - if (*height <= 0) - return GL_FALSE; - - return GL_TRUE; -} - - -/** - * Do clipping for a glCopyTexSubImage call. - * The framebuffer source region might extend outside the framebuffer - * bounds. Clip the source region against the framebuffer bounds and - * adjust the texture/dest position and size accordingly. - * - * \return GL_FALSE if region is totally clipped, GL_TRUE otherwise. - */ -GLboolean -_mesa_clip_copytexsubimage(const struct gl_context *ctx, - GLint *destX, GLint *destY, - GLint *srcX, GLint *srcY, - GLsizei *width, GLsizei *height) -{ - const struct gl_framebuffer *fb = ctx->ReadBuffer; - const GLint srcX0 = *srcX, srcY0 = *srcY; - - if (_mesa_clip_to_region(0, 0, fb->Width, fb->Height, - srcX, srcY, width, height)) { - *destX = *destX + *srcX - srcX0; - *destY = *destY + *srcY - srcY0; - - return GL_TRUE; - } - else { - return GL_FALSE; - } -} - - - -/** - * Clip the rectangle defined by (x, y, width, height) against the bounds - * specified by [xmin, xmax) and [ymin, ymax). - * \return GL_FALSE if rect is totally clipped, GL_TRUE otherwise. - */ -GLboolean -_mesa_clip_to_region(GLint xmin, GLint ymin, - GLint xmax, GLint ymax, - GLint *x, GLint *y, - GLsizei *width, GLsizei *height ) -{ - /* left clipping */ - if (*x < xmin) { - *width -= (xmin - *x); - *x = xmin; - } - - /* right clipping */ - if (*x + *width > xmax) - *width -= (*x + *width - xmax); - - if (*width <= 0) - return GL_FALSE; - - /* bottom (or top) clipping */ - if (*y < ymin) { - *height -= (ymin - *y); - *y = ymin; - } - - /* top (or bottom) clipping */ - if (*y + *height > ymax) - *height -= (*y + *height - ymax); - - if (*height <= 0) - return GL_FALSE; - - return GL_TRUE; -} - - -/** - * Clip dst coords against Xmax (or Ymax). - */ -static INLINE void -clip_right_or_top(GLint *srcX0, GLint *srcX1, - GLint *dstX0, GLint *dstX1, - GLint maxValue) -{ - GLfloat t, bias; - - if (*dstX1 > maxValue) { - /* X1 outside right edge */ - ASSERT(*dstX0 < maxValue); /* X0 should be inside right edge */ - t = (GLfloat) (maxValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0); - /* chop off [t, 1] part */ - ASSERT(t >= 0.0 && t <= 1.0); - *dstX1 = maxValue; - bias = (*srcX0 < *srcX1) ? 0.5F : -0.5F; - *srcX1 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias); - } - else if (*dstX0 > maxValue) { - /* X0 outside right edge */ - ASSERT(*dstX1 < maxValue); /* X1 should be inside right edge */ - t = (GLfloat) (maxValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1); - /* chop off [t, 1] part */ - ASSERT(t >= 0.0 && t <= 1.0); - *dstX0 = maxValue; - bias = (*srcX0 < *srcX1) ? -0.5F : 0.5F; - *srcX0 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias); - } -} - - -/** - * Clip dst coords against Xmin (or Ymin). - */ -static INLINE void -clip_left_or_bottom(GLint *srcX0, GLint *srcX1, - GLint *dstX0, GLint *dstX1, - GLint minValue) -{ - GLfloat t, bias; - - if (*dstX0 < minValue) { - /* X0 outside left edge */ - ASSERT(*dstX1 > minValue); /* X1 should be inside left edge */ - t = (GLfloat) (minValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0); - /* chop off [0, t] part */ - ASSERT(t >= 0.0 && t <= 1.0); - *dstX0 = minValue; - bias = (*srcX0 < *srcX1) ? 0.5F : -0.5F; /* flipped??? */ - *srcX0 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias); - } - else if (*dstX1 < minValue) { - /* X1 outside left edge */ - ASSERT(*dstX0 > minValue); /* X0 should be inside left edge */ - t = (GLfloat) (minValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1); - /* chop off [0, t] part */ - ASSERT(t >= 0.0 && t <= 1.0); - *dstX1 = minValue; - bias = (*srcX0 < *srcX1) ? 0.5F : -0.5F; - *srcX1 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias); - } -} - - -/** - * Do clipping of blit src/dest rectangles. - * The dest rect is clipped against both the buffer bounds and scissor bounds. - * The src rect is just clipped against the buffer bounds. - * - * When either the src or dest rect is clipped, the other is also clipped - * proportionately! - * - * Note that X0 need not be less than X1 (same for Y) for either the source - * and dest rects. That makes the clipping a little trickier. - * - * \return GL_TRUE if anything is left to draw, GL_FALSE if totally clipped - */ -GLboolean -_mesa_clip_blit(struct gl_context *ctx, - GLint *srcX0, GLint *srcY0, GLint *srcX1, GLint *srcY1, - GLint *dstX0, GLint *dstY0, GLint *dstX1, GLint *dstY1) -{ - const GLint srcXmin = 0; - const GLint srcXmax = ctx->ReadBuffer->Width; - const GLint srcYmin = 0; - const GLint srcYmax = ctx->ReadBuffer->Height; - - /* these include scissor bounds */ - const GLint dstXmin = ctx->DrawBuffer->_Xmin; - const GLint dstXmax = ctx->DrawBuffer->_Xmax; - const GLint dstYmin = ctx->DrawBuffer->_Ymin; - const GLint dstYmax = ctx->DrawBuffer->_Ymax; - - /* - printf("PreClipX: src: %d .. %d dst: %d .. %d\n", - *srcX0, *srcX1, *dstX0, *dstX1); - printf("PreClipY: src: %d .. %d dst: %d .. %d\n", - *srcY0, *srcY1, *dstY0, *dstY1); - */ - - /* trivial rejection tests */ - if (*dstX0 == *dstX1) - return GL_FALSE; /* no width */ - if (*dstX0 <= dstXmin && *dstX1 <= dstXmin) - return GL_FALSE; /* totally out (left) of bounds */ - if (*dstX0 >= dstXmax && *dstX1 >= dstXmax) - return GL_FALSE; /* totally out (right) of bounds */ - - if (*dstY0 == *dstY1) - return GL_FALSE; - if (*dstY0 <= dstYmin && *dstY1 <= dstYmin) - return GL_FALSE; - if (*dstY0 >= dstYmax && *dstY1 >= dstYmax) - return GL_FALSE; - - if (*srcX0 == *srcX1) - return GL_FALSE; - if (*srcX0 <= srcXmin && *srcX1 <= srcXmin) - return GL_FALSE; - if (*srcX0 >= srcXmax && *srcX1 >= srcXmax) - return GL_FALSE; - - if (*srcY0 == *srcY1) - return GL_FALSE; - if (*srcY0 <= srcYmin && *srcY1 <= srcYmin) - return GL_FALSE; - if (*srcY0 >= srcYmax && *srcY1 >= srcYmax) - return GL_FALSE; - - /* - * dest clip - */ - clip_right_or_top(srcX0, srcX1, dstX0, dstX1, dstXmax); - clip_right_or_top(srcY0, srcY1, dstY0, dstY1, dstYmax); - clip_left_or_bottom(srcX0, srcX1, dstX0, dstX1, dstXmin); - clip_left_or_bottom(srcY0, srcY1, dstY0, dstY1, dstYmin); - - /* - * src clip (just swap src/dst values from above) - */ - clip_right_or_top(dstX0, dstX1, srcX0, srcX1, srcXmax); - clip_right_or_top(dstY0, dstY1, srcY0, srcY1, srcYmax); - clip_left_or_bottom(dstX0, dstX1, srcX0, srcX1, srcXmin); - clip_left_or_bottom(dstY0, dstY1, srcY0, srcY1, srcYmin); - - /* - printf("PostClipX: src: %d .. %d dst: %d .. %d\n", - *srcX0, *srcX1, *dstX0, *dstX1); - printf("PostClipY: src: %d .. %d dst: %d .. %d\n", - *srcY0, *srcY1, *dstY0, *dstY1); - */ - - ASSERT(*dstX0 >= dstXmin); - ASSERT(*dstX0 <= dstXmax); - ASSERT(*dstX1 >= dstXmin); - ASSERT(*dstX1 <= dstXmax); - - ASSERT(*dstY0 >= dstYmin); - ASSERT(*dstY0 <= dstYmax); - ASSERT(*dstY1 >= dstYmin); - ASSERT(*dstY1 <= dstYmax); - - ASSERT(*srcX0 >= srcXmin); - ASSERT(*srcX0 <= srcXmax); - ASSERT(*srcX1 >= srcXmin); - ASSERT(*srcX1 <= srcXmax); - - ASSERT(*srcY0 >= srcYmin); - ASSERT(*srcY0 <= srcYmax); - ASSERT(*srcY1 >= srcYmin); - ASSERT(*srcY1 <= srcYmax); - - return GL_TRUE; -} +/* + * Mesa 3-D graphics library + * Version: 7.5 + * + * Copyright (C) 1999-2008 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. + */ + + +/** + * \file image.c + * Image handling. + */ + + +#include "glheader.h" +#include "colormac.h" +#include "image.h" +#include "imports.h" +#include "macros.h" +#include "mfeatures.h" +#include "mtypes.h" + + +/** + * NOTE: + * Normally, BYTE_TO_FLOAT(0) returns 0.00392 That causes problems when + * we later convert the float to a packed integer value (such as for + * GL_RGB5_A1) because we'll wind up with a non-zero value. + * + * We redefine the macros here so zero is handled correctly. + */ +#undef BYTE_TO_FLOAT +#define BYTE_TO_FLOAT(B) ((B) == 0 ? 0.0F : ((2.0F * (B) + 1.0F) * (1.0F/255.0F))) + +#undef SHORT_TO_FLOAT +#define SHORT_TO_FLOAT(S) ((S) == 0 ? 0.0F : ((2.0F * (S) + 1.0F) * (1.0F/65535.0F))) + + + +/** Compute ceiling of integer quotient of A divided by B. */ +#define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 ) + + +/** + * \return GL_TRUE if type is packed pixel type, GL_FALSE otherwise. + */ +GLboolean +_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: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + case GL_UNSIGNED_SHORT_8_8_MESA: + case GL_UNSIGNED_SHORT_8_8_REV_MESA: + case GL_UNSIGNED_INT_24_8_EXT: + return GL_TRUE; + } + + return GL_FALSE; +} + + + +/** + * Flip the order of the 2 bytes in each word in the given array. + * + * \param p array. + * \param n number of words. + */ +void +_mesa_swap2( GLushort *p, GLuint n ) +{ + GLuint i; + for (i = 0; i < n; i++) { + p[i] = (p[i] >> 8) | ((p[i] << 8) & 0xff00); + } +} + + + +/* + * Flip the order of the 4 bytes in each word in the given array. + */ +void +_mesa_swap4( GLuint *p, GLuint n ) +{ + GLuint i, a, b; + for (i = 0; i < n; i++) { + b = p[i]; + a = (b >> 24) + | ((b >> 8) & 0xff00) + | ((b << 8) & 0xff0000) + | ((b << 24) & 0xff000000); + p[i] = a; + } +} + + +/** + * Get the size of a GL data type. + * + * \param type GL data type. + * + * \return the size, in bytes, of the given data type, 0 if a GL_BITMAP, or -1 + * if an invalid type enum. + */ +GLint +_mesa_sizeof_type( GLenum type ) +{ + switch (type) { + case GL_BITMAP: + return 0; + case GL_UNSIGNED_BYTE: + return sizeof(GLubyte); + case GL_BYTE: + return sizeof(GLbyte); + case GL_UNSIGNED_SHORT: + return sizeof(GLushort); + case GL_SHORT: + return sizeof(GLshort); + case GL_UNSIGNED_INT: + return sizeof(GLuint); + case GL_INT: + return sizeof(GLint); + case GL_FLOAT: + return sizeof(GLfloat); + case GL_DOUBLE: + return sizeof(GLdouble); + case GL_HALF_FLOAT_ARB: + return sizeof(GLhalfARB); + case GL_FIXED: + return sizeof(GLfixed); + default: + return -1; + } +} + + +/** + * Same as _mesa_sizeof_type() but also accepting the packed pixel + * format data types. + */ +GLint +_mesa_sizeof_packed_type( GLenum type ) +{ + switch (type) { + case GL_BITMAP: + return 0; + case GL_UNSIGNED_BYTE: + return sizeof(GLubyte); + case GL_BYTE: + return sizeof(GLbyte); + case GL_UNSIGNED_SHORT: + return sizeof(GLushort); + case GL_SHORT: + return sizeof(GLshort); + case GL_UNSIGNED_INT: + return sizeof(GLuint); + case GL_INT: + return sizeof(GLint); + case GL_HALF_FLOAT_ARB: + return sizeof(GLhalfARB); + case GL_FLOAT: + return sizeof(GLfloat); + case GL_UNSIGNED_BYTE_3_3_2: + 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: + return sizeof(GLushort); + case GL_UNSIGNED_SHORT_4_4_4_4: + return sizeof(GLushort); + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + return sizeof(GLushort); + case GL_UNSIGNED_SHORT_5_5_5_1: + return sizeof(GLushort); + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + return sizeof(GLushort); + case GL_UNSIGNED_INT_8_8_8_8: + return sizeof(GLuint); + case GL_UNSIGNED_INT_8_8_8_8_REV: + return sizeof(GLuint); + case GL_UNSIGNED_INT_10_10_10_2: + return sizeof(GLuint); + case GL_UNSIGNED_INT_2_10_10_10_REV: + return sizeof(GLuint); + case GL_UNSIGNED_SHORT_8_8_MESA: + case GL_UNSIGNED_SHORT_8_8_REV_MESA: + return sizeof(GLushort); + case GL_UNSIGNED_INT_24_8_EXT: + return sizeof(GLuint); + default: + return -1; + } +} + + +/** + * Get the number of components in a pixel format. + * + * \param format pixel format. + * + * \return the number of components in the given format, or -1 if a bad format. + */ +GLint +_mesa_components_in_format( GLenum format ) +{ + switch (format) { + case GL_COLOR_INDEX: + case GL_COLOR_INDEX1_EXT: + case GL_COLOR_INDEX2_EXT: + case GL_COLOR_INDEX4_EXT: + case GL_COLOR_INDEX8_EXT: + case GL_COLOR_INDEX12_EXT: + case GL_COLOR_INDEX16_EXT: + case GL_STENCIL_INDEX: + case GL_DEPTH_COMPONENT: + case GL_RED: + case GL_RED_INTEGER_EXT: + case GL_GREEN: + case GL_GREEN_INTEGER_EXT: + case GL_BLUE: + case GL_BLUE_INTEGER_EXT: + case GL_ALPHA: + case GL_ALPHA_INTEGER_EXT: + case GL_LUMINANCE: + case GL_LUMINANCE_INTEGER_EXT: + case GL_INTENSITY: + return 1; + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE_ALPHA_INTEGER_EXT: + case GL_RG: + return 2; + case GL_RGB: + case GL_RGB_INTEGER_EXT: + return 3; + case GL_RGBA: + case GL_RGBA_INTEGER_EXT: + return 4; + case GL_BGR: + return 3; + case GL_BGRA: + return 4; + case GL_ABGR_EXT: + return 4; + case GL_YCBCR_MESA: + return 2; + case GL_DEPTH_STENCIL_EXT: + return 2; + case GL_DUDV_ATI: + case GL_DU8DV8_ATI: + return 2; + default: + return -1; + } +} + + +/** + * Get the bytes per pixel of pixel format type pair. + * + * \param format pixel format. + * \param type pixel type. + * + * \return bytes per pixel, or -1 if a bad format or type was given. + */ +GLint +_mesa_bytes_per_pixel( GLenum format, GLenum type ) +{ + GLint comps = _mesa_components_in_format( format ); + if (comps < 0) + return -1; + + switch (type) { + case GL_BITMAP: + return 0; /* special case */ + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return comps * sizeof(GLubyte); + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return comps * sizeof(GLshort); + case GL_INT: + case GL_UNSIGNED_INT: + return comps * sizeof(GLint); + case GL_FLOAT: + return comps * sizeof(GLfloat); + case GL_HALF_FLOAT_ARB: + return comps * sizeof(GLhalfARB); + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + if (format == GL_RGB || format == GL_BGR || + format == GL_RGB_INTEGER_EXT || format == GL_BGR_INTEGER_EXT) + return sizeof(GLubyte); + else + return -1; /* error */ + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + if (format == GL_RGB || format == GL_BGR || + format == GL_RGB_INTEGER_EXT || format == GL_BGR_INTEGER_EXT) + return sizeof(GLushort); + else + return -1; /* error */ + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + if (format == GL_RGBA || format == GL_BGRA || format == GL_ABGR_EXT || + format == GL_RGBA_INTEGER_EXT || format == GL_BGRA_INTEGER_EXT) + return sizeof(GLushort); + else + return -1; + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + if (format == GL_RGBA || format == GL_BGRA || format == GL_ABGR_EXT || + format == GL_RGBA_INTEGER_EXT || format == GL_BGRA_INTEGER_EXT) + return sizeof(GLuint); + else + return -1; + case GL_UNSIGNED_SHORT_8_8_MESA: + case GL_UNSIGNED_SHORT_8_8_REV_MESA: + if (format == GL_YCBCR_MESA) + return sizeof(GLushort); + else + return -1; + case GL_UNSIGNED_INT_24_8_EXT: + if (format == GL_DEPTH_STENCIL_EXT) + return sizeof(GLuint); + else + return -1; + default: + return -1; + } +} + + +/** + * Test for a legal pixel format and type. + * + * \param format pixel format. + * \param type pixel type. + * + * \return GL_TRUE if the given pixel format and type are legal, or GL_FALSE + * otherwise. + */ +GLboolean +_mesa_is_legal_format_and_type(const struct gl_context *ctx, + GLenum format, GLenum type) +{ + switch (format) { + case GL_COLOR_INDEX: + case GL_STENCIL_INDEX: + switch (type) { + case GL_BITMAP: + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + return GL_TRUE; + case GL_HALF_FLOAT_ARB: + return ctx->Extensions.ARB_half_float_pixel; + default: + return GL_FALSE; + } + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: +#if 0 /* not legal! see table 3.6 of the 1.5 spec */ + case GL_INTENSITY: +#endif + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_DEPTH_COMPONENT: + switch (type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + return GL_TRUE; + case GL_HALF_FLOAT_ARB: + return ctx->Extensions.ARB_half_float_pixel; + default: + return GL_FALSE; + } + case GL_RG: + if (!ctx->Extensions.ARB_texture_rg) + return GL_FALSE; + + switch (type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + return GL_TRUE; + case GL_HALF_FLOAT_ARB: + return ctx->Extensions.ARB_half_float_pixel; + default: + return GL_FALSE; + } + case GL_RGB: + switch (type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + return GL_TRUE; + case GL_HALF_FLOAT_ARB: + return ctx->Extensions.ARB_half_float_pixel; + default: + return GL_FALSE; + } + case GL_BGR: + switch (type) { + /* NOTE: no packed types are supported with BGR. That's + * intentional, according to the GL spec. + */ + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + return GL_TRUE; + case GL_HALF_FLOAT_ARB: + return ctx->Extensions.ARB_half_float_pixel; + default: + return GL_FALSE; + } + case GL_RGBA: + case GL_BGRA: + case GL_ABGR_EXT: + switch (type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + return GL_TRUE; + case GL_HALF_FLOAT_ARB: + return ctx->Extensions.ARB_half_float_pixel; + default: + return GL_FALSE; + } + case GL_YCBCR_MESA: + if (type == GL_UNSIGNED_SHORT_8_8_MESA || + type == GL_UNSIGNED_SHORT_8_8_REV_MESA) + return GL_TRUE; + else + return GL_FALSE; + case GL_DEPTH_STENCIL_EXT: + if (ctx->Extensions.EXT_packed_depth_stencil + && type == GL_UNSIGNED_INT_24_8_EXT) + return GL_TRUE; + else + return GL_FALSE; + case GL_DUDV_ATI: + case GL_DU8DV8_ATI: + switch (type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + return GL_TRUE; + default: + return GL_FALSE; + } + + /* integer-valued formats */ + case GL_RED_INTEGER_EXT: + case GL_GREEN_INTEGER_EXT: + case GL_BLUE_INTEGER_EXT: + case GL_ALPHA_INTEGER_EXT: + switch (type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + return ctx->Extensions.EXT_texture_integer; + default: + return GL_FALSE; + } + + case GL_RGB_INTEGER_EXT: + switch (type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + return ctx->Extensions.EXT_texture_integer; + default: + return GL_FALSE; + } + + case GL_BGR_INTEGER_EXT: + switch (type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + /* NOTE: no packed formats w/ BGR format */ + return ctx->Extensions.EXT_texture_integer; + default: + return GL_FALSE; + } + + case GL_RGBA_INTEGER_EXT: + case GL_BGRA_INTEGER_EXT: + switch (type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + return ctx->Extensions.EXT_texture_integer; + default: + return GL_FALSE; + } + + case GL_LUMINANCE_INTEGER_EXT: + case GL_LUMINANCE_ALPHA_INTEGER_EXT: + switch (type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + return ctx->Extensions.EXT_texture_integer; + default: + return GL_FALSE; + } + + default: + ; /* fall-through */ + } + return GL_FALSE; +} + + +/** + * Test if the given image format is a color/RGBA format (i.e., not color + * index, depth, stencil, etc). + * \param format the image format value (may by an internal texture format) + * \return GL_TRUE if its a color/RGBA format, GL_FALSE otherwise. + */ +GLboolean +_mesa_is_color_format(GLenum format) +{ + switch (format) { + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_ALPHA4: + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16: + case 1: + case GL_LUMINANCE: + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + case 2: + 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: + case GL_INTENSITY: + case GL_INTENSITY4: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + case GL_R8: + case GL_R16: + case GL_RG: + case GL_RG8: + case GL_RG16: + case 3: + case GL_RGB: + case GL_BGR: + case GL_R3_G3_B2: + case GL_RGB4: + case GL_RGB5: + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + case 4: + case GL_ABGR_EXT: + case GL_RGBA: + case GL_BGRA: + case GL_RGBA2: + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGBA8: + case GL_RGB10_A2: + case GL_RGBA12: + case GL_RGBA16: + /* float texture formats */ + case GL_ALPHA16F_ARB: + case GL_ALPHA32F_ARB: + case GL_LUMINANCE16F_ARB: + case GL_LUMINANCE32F_ARB: + case GL_LUMINANCE_ALPHA16F_ARB: + case GL_LUMINANCE_ALPHA32F_ARB: + case GL_INTENSITY16F_ARB: + case GL_INTENSITY32F_ARB: + case GL_R16F: + case GL_R32F: + case GL_RG16F: + case GL_RG32F: + case GL_RGB16F_ARB: + case GL_RGB32F_ARB: + case GL_RGBA16F_ARB: + case GL_RGBA32F_ARB: + /* compressed formats */ + case GL_COMPRESSED_ALPHA: + case GL_COMPRESSED_LUMINANCE: + case GL_COMPRESSED_LUMINANCE_ALPHA: + case GL_COMPRESSED_INTENSITY: + case GL_COMPRESSED_RED: + case GL_COMPRESSED_RG: + case GL_COMPRESSED_RGB: + case GL_COMPRESSED_RGBA: + case GL_RGB_S3TC: + case GL_RGB4_S3TC: + case GL_RGBA_S3TC: + case GL_RGBA4_S3TC: + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + case GL_COMPRESSED_RGB_FXT1_3DFX: + case GL_COMPRESSED_RGBA_FXT1_3DFX: +#if FEATURE_EXT_texture_sRGB + case GL_SRGB_EXT: + case GL_SRGB8_EXT: + case GL_SRGB_ALPHA_EXT: + case GL_SRGB8_ALPHA8_EXT: + case GL_SLUMINANCE_ALPHA_EXT: + case GL_SLUMINANCE8_ALPHA8_EXT: + case GL_SLUMINANCE_EXT: + case GL_SLUMINANCE8_EXT: + case GL_COMPRESSED_SRGB_EXT: + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + case GL_COMPRESSED_SLUMINANCE_EXT: + case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT: +#endif /* FEATURE_EXT_texture_sRGB */ + case GL_COMPRESSED_RED_RGTC1: + case GL_COMPRESSED_SIGNED_RED_RGTC1: + case GL_COMPRESSED_RG_RGTC2: + case GL_COMPRESSED_SIGNED_RG_RGTC2: + case GL_COMPRESSED_LUMINANCE_LATC1_EXT: + case GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT: + case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: + case GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT: + case GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI: + /* signed, normalized texture formats */ + case GL_RGBA_SNORM: + case GL_RGBA8_SNORM: + /* generic integer formats */ + case GL_RED_INTEGER_EXT: + case GL_GREEN_INTEGER_EXT: + case GL_BLUE_INTEGER_EXT: + case GL_ALPHA_INTEGER_EXT: + case GL_RGB_INTEGER_EXT: + case GL_RGBA_INTEGER_EXT: + case GL_BGR_INTEGER_EXT: + case GL_BGRA_INTEGER_EXT: + case GL_LUMINANCE_INTEGER_EXT: + case GL_LUMINANCE_ALPHA_INTEGER_EXT: + /* sized integer formats */ + case GL_RGBA32UI_EXT: + case GL_RGB32UI_EXT: + case GL_ALPHA32UI_EXT: + case GL_INTENSITY32UI_EXT: + case GL_LUMINANCE32UI_EXT: + case GL_LUMINANCE_ALPHA32UI_EXT: + case GL_RGBA16UI_EXT: + case GL_RGB16UI_EXT: + case GL_ALPHA16UI_EXT: + case GL_INTENSITY16UI_EXT: + case GL_LUMINANCE16UI_EXT: + case GL_LUMINANCE_ALPHA16UI_EXT: + case GL_RGBA8UI_EXT: + case GL_RGB8UI_EXT: + case GL_ALPHA8UI_EXT: + case GL_INTENSITY8UI_EXT: + case GL_LUMINANCE8UI_EXT: + case GL_LUMINANCE_ALPHA8UI_EXT: + case GL_RGBA32I_EXT: + case GL_RGB32I_EXT: + case GL_ALPHA32I_EXT: + case GL_INTENSITY32I_EXT: + case GL_LUMINANCE32I_EXT: + case GL_LUMINANCE_ALPHA32I_EXT: + case GL_RGBA16I_EXT: + case GL_RGB16I_EXT: + case GL_ALPHA16I_EXT: + case GL_INTENSITY16I_EXT: + case GL_LUMINANCE16I_EXT: + case GL_LUMINANCE_ALPHA16I_EXT: + case GL_RGBA8I_EXT: + case GL_RGB8I_EXT: + case GL_ALPHA8I_EXT: + case GL_INTENSITY8I_EXT: + case GL_LUMINANCE8I_EXT: + case GL_LUMINANCE_ALPHA8I_EXT: + return GL_TRUE; + case GL_YCBCR_MESA: /* not considered to be RGB */ + /* fall-through */ + default: + return GL_FALSE; + } +} + + +/** + * Test if the given image format is a color index format. + */ +GLboolean +_mesa_is_index_format(GLenum format) +{ + switch (format) { + case GL_COLOR_INDEX: + case GL_COLOR_INDEX1_EXT: + case GL_COLOR_INDEX2_EXT: + case GL_COLOR_INDEX4_EXT: + case GL_COLOR_INDEX8_EXT: + case GL_COLOR_INDEX12_EXT: + case GL_COLOR_INDEX16_EXT: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Test if the given image format is a depth component format. + */ +GLboolean +_mesa_is_depth_format(GLenum format) +{ + switch (format) { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH_COMPONENT32: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Test if the given image format is a stencil format. + */ +GLboolean +_mesa_is_stencil_format(GLenum format) +{ + switch (format) { + case GL_STENCIL_INDEX: + case GL_DEPTH_STENCIL: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Test if the given image format is a YCbCr format. + */ +GLboolean +_mesa_is_ycbcr_format(GLenum format) +{ + switch (format) { + case GL_YCBCR_MESA: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Test if the given image format is a depth+stencil format. + */ +GLboolean +_mesa_is_depthstencil_format(GLenum format) +{ + switch (format) { + case GL_DEPTH24_STENCIL8_EXT: + case GL_DEPTH_STENCIL_EXT: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Test if the given image format is a depth or stencil format. + */ +GLboolean +_mesa_is_depth_or_stencil_format(GLenum format) +{ + switch (format) { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH_COMPONENT32: + case GL_STENCIL_INDEX: + case GL_STENCIL_INDEX1_EXT: + case GL_STENCIL_INDEX4_EXT: + case GL_STENCIL_INDEX8_EXT: + case GL_STENCIL_INDEX16_EXT: + case GL_DEPTH_STENCIL_EXT: + case GL_DEPTH24_STENCIL8_EXT: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Test if the given image format is a dudv format. + */ +GLboolean +_mesa_is_dudv_format(GLenum format) +{ + switch (format) { + case GL_DUDV_ATI: + case GL_DU8DV8_ATI: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Test if the given format is an integer (non-normalized) format. + */ +GLboolean +_mesa_is_integer_format(GLenum format) +{ + switch (format) { + /* generic integer formats */ + case GL_RED_INTEGER_EXT: + case GL_GREEN_INTEGER_EXT: + case GL_BLUE_INTEGER_EXT: + case GL_ALPHA_INTEGER_EXT: + case GL_RGB_INTEGER_EXT: + case GL_RGBA_INTEGER_EXT: + case GL_BGR_INTEGER_EXT: + case GL_BGRA_INTEGER_EXT: + case GL_LUMINANCE_INTEGER_EXT: + case GL_LUMINANCE_ALPHA_INTEGER_EXT: + /* specific integer formats */ + case GL_RGBA32UI_EXT: + case GL_RGB32UI_EXT: + case GL_ALPHA32UI_EXT: + case GL_INTENSITY32UI_EXT: + case GL_LUMINANCE32UI_EXT: + case GL_LUMINANCE_ALPHA32UI_EXT: + case GL_RGBA16UI_EXT: + case GL_RGB16UI_EXT: + case GL_ALPHA16UI_EXT: + case GL_INTENSITY16UI_EXT: + case GL_LUMINANCE16UI_EXT: + case GL_LUMINANCE_ALPHA16UI_EXT: + case GL_RGBA8UI_EXT: + case GL_RGB8UI_EXT: + case GL_ALPHA8UI_EXT: + case GL_INTENSITY8UI_EXT: + case GL_LUMINANCE8UI_EXT: + case GL_LUMINANCE_ALPHA8UI_EXT: + case GL_RGBA32I_EXT: + case GL_RGB32I_EXT: + case GL_ALPHA32I_EXT: + case GL_INTENSITY32I_EXT: + case GL_LUMINANCE32I_EXT: + case GL_LUMINANCE_ALPHA32I_EXT: + case GL_RGBA16I_EXT: + case GL_RGB16I_EXT: + case GL_ALPHA16I_EXT: + case GL_INTENSITY16I_EXT: + case GL_LUMINANCE16I_EXT: + case GL_LUMINANCE_ALPHA16I_EXT: + case GL_RGBA8I_EXT: + case GL_RGB8I_EXT: + case GL_ALPHA8I_EXT: + case GL_INTENSITY8I_EXT: + case GL_LUMINANCE8I_EXT: + case GL_LUMINANCE_ALPHA8I_EXT: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Test if an image format is a supported compressed format. + * \param format the internal format token provided by the user. + * \return GL_TRUE if compressed, GL_FALSE if uncompressed + */ +GLboolean +_mesa_is_compressed_format(struct gl_context *ctx, GLenum format) +{ + switch (format) { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + return ctx->Extensions.EXT_texture_compression_s3tc; + case GL_RGB_S3TC: + case GL_RGB4_S3TC: + case GL_RGBA_S3TC: + case GL_RGBA4_S3TC: + return ctx->Extensions.S3_s3tc; + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + return ctx->Extensions.EXT_texture_sRGB + && ctx->Extensions.EXT_texture_compression_s3tc; + case GL_COMPRESSED_RGB_FXT1_3DFX: + case GL_COMPRESSED_RGBA_FXT1_3DFX: + return ctx->Extensions.TDFX_texture_compression_FXT1; + case GL_COMPRESSED_RED_RGTC1: + case GL_COMPRESSED_SIGNED_RED_RGTC1: + case GL_COMPRESSED_RG_RGTC2: + case GL_COMPRESSED_SIGNED_RG_RGTC2: + return ctx->Extensions.ARB_texture_compression_rgtc; + case GL_COMPRESSED_LUMINANCE_LATC1_EXT: + case GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT: + case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: + case GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT: + return ctx->Extensions.EXT_texture_compression_latc; + case GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI: + return ctx->Extensions.ATI_texture_compression_3dc; + default: + return GL_FALSE; + } +} + + +/** + * Return the address of a specific pixel in an image (1D, 2D or 3D). + * + * Pixel unpacking/packing parameters are observed according to \p packing. + * + * \param dimensions either 1, 2 or 3 to indicate dimensionality of image + * \param image starting address of image data + * \param width the image width + * \param height theimage height + * \param format the pixel format + * \param type the pixel data type + * \param packing the pixelstore attributes + * \param img which image in the volume (0 for 1D or 2D images) + * \param row row of pixel in the image (0 for 1D images) + * \param column column of pixel in the image + * + * \return address of pixel on success, or NULL on error. + * + * \sa gl_pixelstore_attrib. + */ +GLvoid * +_mesa_image_address( GLuint dimensions, + const struct gl_pixelstore_attrib *packing, + const GLvoid *image, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + GLint img, GLint row, GLint column ) +{ + GLint alignment; /* 1, 2 or 4 */ + GLint pixels_per_row; + GLint rows_per_image; + GLint skiprows; + GLint skippixels; + GLint skipimages; /* for 3-D volume images */ + GLubyte *pixel_addr; + + ASSERT(dimensions >= 1 && dimensions <= 3); + + alignment = packing->Alignment; + if (packing->RowLength > 0) { + pixels_per_row = packing->RowLength; + } + else { + pixels_per_row = width; + } + if (packing->ImageHeight > 0) { + rows_per_image = packing->ImageHeight; + } + else { + rows_per_image = height; + } + + skippixels = packing->SkipPixels; + /* Note: SKIP_ROWS _is_ used for 1D images */ + skiprows = packing->SkipRows; + /* Note: SKIP_IMAGES is only used for 3D images */ + skipimages = (dimensions == 3) ? packing->SkipImages : 0; + + if (type == GL_BITMAP) { + /* BITMAP data */ + GLint comp_per_pixel; /* components per pixel */ + GLint bytes_per_comp; /* bytes per component */ + GLint bytes_per_row; + GLint bytes_per_image; + + /* Compute bytes per component */ + bytes_per_comp = _mesa_sizeof_packed_type( type ); + if (bytes_per_comp < 0) { + return NULL; + } + + /* Compute number of components per pixel */ + comp_per_pixel = _mesa_components_in_format( format ); + if (comp_per_pixel < 0) { + return NULL; + } + + bytes_per_row = alignment + * CEILING( comp_per_pixel*pixels_per_row, 8*alignment ); + + bytes_per_image = bytes_per_row * rows_per_image; + + pixel_addr = (GLubyte *) image + + (skipimages + img) * bytes_per_image + + (skiprows + row) * bytes_per_row + + (skippixels + column) / 8; + } + else { + /* Non-BITMAP data */ + GLint bytes_per_pixel, bytes_per_row, remainder, bytes_per_image; + GLint topOfImage; + + bytes_per_pixel = _mesa_bytes_per_pixel( format, type ); + + /* The pixel type and format should have been error checked earlier */ + assert(bytes_per_pixel > 0); + + bytes_per_row = pixels_per_row * bytes_per_pixel; + remainder = bytes_per_row % alignment; + if (remainder > 0) + bytes_per_row += (alignment - remainder); + + ASSERT(bytes_per_row % alignment == 0); + + bytes_per_image = bytes_per_row * rows_per_image; + + if (packing->Invert) { + /* set pixel_addr to the last row */ + topOfImage = bytes_per_row * (height - 1); + bytes_per_row = -bytes_per_row; + } + else { + topOfImage = 0; + } + + /* compute final pixel address */ + pixel_addr = (GLubyte *) image + + (skipimages + img) * bytes_per_image + + topOfImage + + (skiprows + row) * bytes_per_row + + (skippixels + column) * bytes_per_pixel; + } + + return (GLvoid *) pixel_addr; +} + + +GLvoid * +_mesa_image_address1d( const struct gl_pixelstore_attrib *packing, + const GLvoid *image, + GLsizei width, + GLenum format, GLenum type, + GLint column ) +{ + return _mesa_image_address(1, packing, image, width, 1, + format, type, 0, 0, column); +} + + +GLvoid * +_mesa_image_address2d( const struct gl_pixelstore_attrib *packing, + const GLvoid *image, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + GLint row, GLint column ) +{ + return _mesa_image_address(2, packing, image, width, height, + format, type, 0, row, column); +} + + +GLvoid * +_mesa_image_address3d( const struct gl_pixelstore_attrib *packing, + const GLvoid *image, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + GLint img, GLint row, GLint column ) +{ + return _mesa_image_address(3, packing, image, width, height, + format, type, img, row, column); +} + + + +/** + * Compute the stride (in bytes) between image rows. + * + * \param packing the pixelstore attributes + * \param width image width. + * \param format pixel format. + * \param type pixel data type. + * + * \return the stride in bytes for the given parameters, or -1 if error + */ +GLint +_mesa_image_row_stride( const struct gl_pixelstore_attrib *packing, + GLint width, GLenum format, GLenum type ) +{ + GLint bytesPerRow, remainder; + + ASSERT(packing); + + if (type == GL_BITMAP) { + if (packing->RowLength == 0) { + bytesPerRow = (width + 7) / 8; + } + else { + bytesPerRow = (packing->RowLength + 7) / 8; + } + } + else { + /* Non-BITMAP data */ + const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type); + if (bytesPerPixel <= 0) + return -1; /* error */ + if (packing->RowLength == 0) { + bytesPerRow = bytesPerPixel * width; + } + else { + bytesPerRow = bytesPerPixel * packing->RowLength; + } + } + + remainder = bytesPerRow % packing->Alignment; + if (remainder > 0) { + bytesPerRow += (packing->Alignment - remainder); + } + + if (packing->Invert) { + /* negate the bytes per row (negative row stride) */ + bytesPerRow = -bytesPerRow; + } + + return bytesPerRow; +} + + +/* + * Compute the stride between images in a 3D texture (in bytes) for the given + * pixel packing parameters and image width, format and type. + */ +GLint +_mesa_image_image_stride( const struct gl_pixelstore_attrib *packing, + GLint width, GLint height, + GLenum format, GLenum type ) +{ + GLint bytesPerRow, bytesPerImage, remainder; + + ASSERT(packing); + + if (type == GL_BITMAP) { + if (packing->RowLength == 0) { + bytesPerRow = (width + 7) / 8; + } + else { + bytesPerRow = (packing->RowLength + 7) / 8; + } + } + else { + const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type); + + if (bytesPerPixel <= 0) + return -1; /* error */ + if (packing->RowLength == 0) { + bytesPerRow = bytesPerPixel * width; + } + else { + bytesPerRow = bytesPerPixel * packing->RowLength; + } + } + + remainder = bytesPerRow % packing->Alignment; + if (remainder > 0) + bytesPerRow += (packing->Alignment - remainder); + + if (packing->ImageHeight == 0) + bytesPerImage = bytesPerRow * height; + else + bytesPerImage = bytesPerRow * packing->ImageHeight; + + return bytesPerImage; +} + + + +/** + * "Expand" a bitmap from 1-bit per pixel to 8-bits per pixel. + * This is typically used to convert a bitmap into a GLubyte/pixel texture. + * "On" bits will set texels to \p onValue. + * "Off" bits will not modify texels. + * \param width src bitmap width in pixels + * \param height src bitmap height in pixels + * \param unpack bitmap unpacking state + * \param bitmap the src bitmap data + * \param destBuffer start of dest buffer + * \param destStride row stride in dest buffer + * \param onValue if bit is 1, set destBuffer pixel to this value + */ +void +_mesa_expand_bitmap(GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap, + GLubyte *destBuffer, GLint destStride, + GLubyte onValue) +{ + const GLubyte *srcRow = (const GLubyte *) + _mesa_image_address2d(unpack, bitmap, width, height, + GL_COLOR_INDEX, GL_BITMAP, 0, 0); + const GLint srcStride = _mesa_image_row_stride(unpack, width, + GL_COLOR_INDEX, GL_BITMAP); + GLint row, col; + +#define SET_PIXEL(COL, ROW) \ + destBuffer[(ROW) * destStride + (COL)] = onValue; + + for (row = 0; row < height; row++) { + const GLubyte *src = srcRow; + + if (unpack->LsbFirst) { + /* Lsb first */ + GLubyte mask = 1U << (unpack->SkipPixels & 0x7); + for (col = 0; col < width; col++) { + + if (*src & mask) { + SET_PIXEL(col, row); + } + + if (mask == 128U) { + src++; + mask = 1U; + } + else { + mask = mask << 1; + } + } + + /* get ready for next row */ + if (mask != 1) + src++; + } + else { + /* Msb first */ + GLubyte mask = 128U >> (unpack->SkipPixels & 0x7); + for (col = 0; col < width; col++) { + + if (*src & mask) { + SET_PIXEL(col, row); + } + + if (mask == 1U) { + src++; + mask = 128U; + } + else { + mask = mask >> 1; + } + } + + /* get ready for next row */ + if (mask != 128) + src++; + } + + srcRow += srcStride; + } /* row */ + +#undef SET_PIXEL +} + + + + +/** + * Convert an array of RGBA colors from one datatype to another. + * NOTE: src may equal dst. In that case, we use a temporary buffer. + */ +void +_mesa_convert_colors(GLenum srcType, const GLvoid *src, + GLenum dstType, GLvoid *dst, + GLuint count, const GLubyte mask[]) +{ + GLuint tempBuffer[MAX_WIDTH][4]; + const GLboolean useTemp = (src == dst); + + ASSERT(srcType != dstType); + + switch (srcType) { + case GL_UNSIGNED_BYTE: + if (dstType == GL_UNSIGNED_SHORT) { + const GLubyte (*src1)[4] = (const GLubyte (*)[4]) src; + GLushort (*dst2)[4] = (GLushort (*)[4]) (useTemp ? tempBuffer : dst); + GLuint i; + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst2[i][RCOMP] = UBYTE_TO_USHORT(src1[i][RCOMP]); + dst2[i][GCOMP] = UBYTE_TO_USHORT(src1[i][GCOMP]); + dst2[i][BCOMP] = UBYTE_TO_USHORT(src1[i][BCOMP]); + dst2[i][ACOMP] = UBYTE_TO_USHORT(src1[i][ACOMP]); + } + } + if (useTemp) + memcpy(dst, tempBuffer, count * 4 * sizeof(GLushort)); + } + else { + const GLubyte (*src1)[4] = (const GLubyte (*)[4]) src; + GLfloat (*dst4)[4] = (GLfloat (*)[4]) (useTemp ? tempBuffer : dst); + GLuint i; + ASSERT(dstType == GL_FLOAT); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst4[i][RCOMP] = UBYTE_TO_FLOAT(src1[i][RCOMP]); + dst4[i][GCOMP] = UBYTE_TO_FLOAT(src1[i][GCOMP]); + dst4[i][BCOMP] = UBYTE_TO_FLOAT(src1[i][BCOMP]); + dst4[i][ACOMP] = UBYTE_TO_FLOAT(src1[i][ACOMP]); + } + } + if (useTemp) + memcpy(dst, tempBuffer, count * 4 * sizeof(GLfloat)); + } + break; + case GL_UNSIGNED_SHORT: + if (dstType == GL_UNSIGNED_BYTE) { + const GLushort (*src2)[4] = (const GLushort (*)[4]) src; + GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst); + GLuint i; + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst1[i][RCOMP] = USHORT_TO_UBYTE(src2[i][RCOMP]); + dst1[i][GCOMP] = USHORT_TO_UBYTE(src2[i][GCOMP]); + dst1[i][BCOMP] = USHORT_TO_UBYTE(src2[i][BCOMP]); + dst1[i][ACOMP] = USHORT_TO_UBYTE(src2[i][ACOMP]); + } + } + if (useTemp) + memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte)); + } + else { + const GLushort (*src2)[4] = (const GLushort (*)[4]) src; + GLfloat (*dst4)[4] = (GLfloat (*)[4]) (useTemp ? tempBuffer : dst); + GLuint i; + ASSERT(dstType == GL_FLOAT); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst4[i][RCOMP] = USHORT_TO_FLOAT(src2[i][RCOMP]); + dst4[i][GCOMP] = USHORT_TO_FLOAT(src2[i][GCOMP]); + dst4[i][BCOMP] = USHORT_TO_FLOAT(src2[i][BCOMP]); + dst4[i][ACOMP] = USHORT_TO_FLOAT(src2[i][ACOMP]); + } + } + if (useTemp) + memcpy(dst, tempBuffer, count * 4 * sizeof(GLfloat)); + } + break; + case GL_FLOAT: + if (dstType == GL_UNSIGNED_BYTE) { + const GLfloat (*src4)[4] = (const GLfloat (*)[4]) src; + GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst); + GLuint i; + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][RCOMP], src4[i][RCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][GCOMP], src4[i][GCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][BCOMP], src4[i][BCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][ACOMP], src4[i][ACOMP]); + } + } + if (useTemp) + memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte)); + } + else { + const GLfloat (*src4)[4] = (const GLfloat (*)[4]) src; + GLushort (*dst2)[4] = (GLushort (*)[4]) (useTemp ? tempBuffer : dst); + GLuint i; + ASSERT(dstType == GL_UNSIGNED_SHORT); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + UNCLAMPED_FLOAT_TO_USHORT(dst2[i][RCOMP], src4[i][RCOMP]); + UNCLAMPED_FLOAT_TO_USHORT(dst2[i][GCOMP], src4[i][GCOMP]); + UNCLAMPED_FLOAT_TO_USHORT(dst2[i][BCOMP], src4[i][BCOMP]); + UNCLAMPED_FLOAT_TO_USHORT(dst2[i][ACOMP], src4[i][ACOMP]); + } + } + if (useTemp) + memcpy(dst, tempBuffer, count * 4 * sizeof(GLushort)); + } + break; + default: + _mesa_problem(NULL, "Invalid datatype in _mesa_convert_colors"); + } +} + + + + +/** + * Perform basic clipping for glDrawPixels. The image's position and size + * and the unpack SkipPixels and SkipRows are adjusted so that the image + * region is entirely within the window and scissor bounds. + * NOTE: this will only work when glPixelZoom is (1, 1) or (1, -1). + * If Pixel.ZoomY is -1, *destY will be changed to be the first row which + * we'll actually write. Beforehand, *destY-1 is the first drawing row. + * + * \return GL_TRUE if image is ready for drawing or + * GL_FALSE if image was completely clipped away (draw nothing) + */ +GLboolean +_mesa_clip_drawpixels(const struct gl_context *ctx, + GLint *destX, GLint *destY, + GLsizei *width, GLsizei *height, + struct gl_pixelstore_attrib *unpack) +{ + const struct gl_framebuffer *buffer = ctx->DrawBuffer; + + if (unpack->RowLength == 0) { + unpack->RowLength = *width; + } + + ASSERT(ctx->Pixel.ZoomX == 1.0F); + ASSERT(ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F); + + /* left clipping */ + if (*destX < buffer->_Xmin) { + unpack->SkipPixels += (buffer->_Xmin - *destX); + *width -= (buffer->_Xmin - *destX); + *destX = buffer->_Xmin; + } + /* right clipping */ + if (*destX + *width > buffer->_Xmax) + *width -= (*destX + *width - buffer->_Xmax); + + if (*width <= 0) + return GL_FALSE; + + if (ctx->Pixel.ZoomY == 1.0F) { + /* bottom clipping */ + if (*destY < buffer->_Ymin) { + unpack->SkipRows += (buffer->_Ymin - *destY); + *height -= (buffer->_Ymin - *destY); + *destY = buffer->_Ymin; + } + /* top clipping */ + if (*destY + *height > buffer->_Ymax) + *height -= (*destY + *height - buffer->_Ymax); + } + else { /* upside down */ + /* top clipping */ + if (*destY > buffer->_Ymax) { + unpack->SkipRows += (*destY - buffer->_Ymax); + *height -= (*destY - buffer->_Ymax); + *destY = buffer->_Ymax; + } + /* bottom clipping */ + if (*destY - *height < buffer->_Ymin) + *height -= (buffer->_Ymin - (*destY - *height)); + /* adjust destY so it's the first row to write to */ + (*destY)--; + } + + if (*height <= 0) + return GL_FALSE; + + return GL_TRUE; +} + + +/** + * Perform clipping for glReadPixels. The image's window position + * and size, and the pack skipPixels, skipRows and rowLength are adjusted + * so that the image region is entirely within the window bounds. + * Note: this is different from _mesa_clip_drawpixels() in that the + * scissor box is ignored, and we use the bounds of the current readbuffer + * surface. + * + * \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, + GLint *srcX, GLint *srcY, + GLsizei *width, GLsizei *height, + struct gl_pixelstore_attrib *pack) +{ + const struct gl_framebuffer *buffer = ctx->ReadBuffer; + + if (pack->RowLength == 0) { + pack->RowLength = *width; + } + + /* left clipping */ + if (*srcX < 0) { + pack->SkipPixels += (0 - *srcX); + *width -= (0 - *srcX); + *srcX = 0; + } + /* right clipping */ + if (*srcX + *width > (GLsizei) buffer->Width) + *width -= (*srcX + *width - buffer->Width); + + if (*width <= 0) + return GL_FALSE; + + /* bottom clipping */ + if (*srcY < 0) { + pack->SkipRows += (0 - *srcY); + *height -= (0 - *srcY); + *srcY = 0; + } + /* top clipping */ + if (*srcY + *height > (GLsizei) buffer->Height) + *height -= (*srcY + *height - buffer->Height); + + if (*height <= 0) + return GL_FALSE; + + return GL_TRUE; +} + + +/** + * Do clipping for a glCopyTexSubImage call. + * The framebuffer source region might extend outside the framebuffer + * bounds. Clip the source region against the framebuffer bounds and + * adjust the texture/dest position and size accordingly. + * + * \return GL_FALSE if region is totally clipped, GL_TRUE otherwise. + */ +GLboolean +_mesa_clip_copytexsubimage(const struct gl_context *ctx, + GLint *destX, GLint *destY, + GLint *srcX, GLint *srcY, + GLsizei *width, GLsizei *height) +{ + const struct gl_framebuffer *fb = ctx->ReadBuffer; + const GLint srcX0 = *srcX, srcY0 = *srcY; + + if (_mesa_clip_to_region(0, 0, fb->Width, fb->Height, + srcX, srcY, width, height)) { + *destX = *destX + *srcX - srcX0; + *destY = *destY + *srcY - srcY0; + + return GL_TRUE; + } + else { + return GL_FALSE; + } +} + + + +/** + * Clip the rectangle defined by (x, y, width, height) against the bounds + * specified by [xmin, xmax) and [ymin, ymax). + * \return GL_FALSE if rect is totally clipped, GL_TRUE otherwise. + */ +GLboolean +_mesa_clip_to_region(GLint xmin, GLint ymin, + GLint xmax, GLint ymax, + GLint *x, GLint *y, + GLsizei *width, GLsizei *height ) +{ + /* left clipping */ + if (*x < xmin) { + *width -= (xmin - *x); + *x = xmin; + } + + /* right clipping */ + if (*x + *width > xmax) + *width -= (*x + *width - xmax); + + if (*width <= 0) + return GL_FALSE; + + /* bottom (or top) clipping */ + if (*y < ymin) { + *height -= (ymin - *y); + *y = ymin; + } + + /* top (or bottom) clipping */ + if (*y + *height > ymax) + *height -= (*y + *height - ymax); + + if (*height <= 0) + return GL_FALSE; + + return GL_TRUE; +} + + +/** + * Clip dst coords against Xmax (or Ymax). + */ +static INLINE void +clip_right_or_top(GLint *srcX0, GLint *srcX1, + GLint *dstX0, GLint *dstX1, + GLint maxValue) +{ + GLfloat t, bias; + + if (*dstX1 > maxValue) { + /* X1 outside right edge */ + ASSERT(*dstX0 < maxValue); /* X0 should be inside right edge */ + t = (GLfloat) (maxValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0); + /* chop off [t, 1] part */ + ASSERT(t >= 0.0 && t <= 1.0); + *dstX1 = maxValue; + bias = (*srcX0 < *srcX1) ? 0.5F : -0.5F; + *srcX1 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias); + } + else if (*dstX0 > maxValue) { + /* X0 outside right edge */ + ASSERT(*dstX1 < maxValue); /* X1 should be inside right edge */ + t = (GLfloat) (maxValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1); + /* chop off [t, 1] part */ + ASSERT(t >= 0.0 && t <= 1.0); + *dstX0 = maxValue; + bias = (*srcX0 < *srcX1) ? -0.5F : 0.5F; + *srcX0 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias); + } +} + + +/** + * Clip dst coords against Xmin (or Ymin). + */ +static INLINE void +clip_left_or_bottom(GLint *srcX0, GLint *srcX1, + GLint *dstX0, GLint *dstX1, + GLint minValue) +{ + GLfloat t, bias; + + if (*dstX0 < minValue) { + /* X0 outside left edge */ + ASSERT(*dstX1 > minValue); /* X1 should be inside left edge */ + t = (GLfloat) (minValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0); + /* chop off [0, t] part */ + ASSERT(t >= 0.0 && t <= 1.0); + *dstX0 = minValue; + bias = (*srcX0 < *srcX1) ? 0.5F : -0.5F; /* flipped??? */ + *srcX0 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias); + } + else if (*dstX1 < minValue) { + /* X1 outside left edge */ + ASSERT(*dstX0 > minValue); /* X0 should be inside left edge */ + t = (GLfloat) (minValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1); + /* chop off [0, t] part */ + ASSERT(t >= 0.0 && t <= 1.0); + *dstX1 = minValue; + bias = (*srcX0 < *srcX1) ? 0.5F : -0.5F; + *srcX1 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias); + } +} + + +/** + * Do clipping of blit src/dest rectangles. + * The dest rect is clipped against both the buffer bounds and scissor bounds. + * The src rect is just clipped against the buffer bounds. + * + * When either the src or dest rect is clipped, the other is also clipped + * proportionately! + * + * Note that X0 need not be less than X1 (same for Y) for either the source + * and dest rects. That makes the clipping a little trickier. + * + * \return GL_TRUE if anything is left to draw, GL_FALSE if totally clipped + */ +GLboolean +_mesa_clip_blit(struct gl_context *ctx, + GLint *srcX0, GLint *srcY0, GLint *srcX1, GLint *srcY1, + GLint *dstX0, GLint *dstY0, GLint *dstX1, GLint *dstY1) +{ + const GLint srcXmin = 0; + const GLint srcXmax = ctx->ReadBuffer->Width; + const GLint srcYmin = 0; + const GLint srcYmax = ctx->ReadBuffer->Height; + + /* these include scissor bounds */ + const GLint dstXmin = ctx->DrawBuffer->_Xmin; + const GLint dstXmax = ctx->DrawBuffer->_Xmax; + const GLint dstYmin = ctx->DrawBuffer->_Ymin; + const GLint dstYmax = ctx->DrawBuffer->_Ymax; + + /* + printf("PreClipX: src: %d .. %d dst: %d .. %d\n", + *srcX0, *srcX1, *dstX0, *dstX1); + printf("PreClipY: src: %d .. %d dst: %d .. %d\n", + *srcY0, *srcY1, *dstY0, *dstY1); + */ + + /* trivial rejection tests */ + if (*dstX0 == *dstX1) + return GL_FALSE; /* no width */ + if (*dstX0 <= dstXmin && *dstX1 <= dstXmin) + return GL_FALSE; /* totally out (left) of bounds */ + if (*dstX0 >= dstXmax && *dstX1 >= dstXmax) + return GL_FALSE; /* totally out (right) of bounds */ + + if (*dstY0 == *dstY1) + return GL_FALSE; + if (*dstY0 <= dstYmin && *dstY1 <= dstYmin) + return GL_FALSE; + if (*dstY0 >= dstYmax && *dstY1 >= dstYmax) + return GL_FALSE; + + if (*srcX0 == *srcX1) + return GL_FALSE; + if (*srcX0 <= srcXmin && *srcX1 <= srcXmin) + return GL_FALSE; + if (*srcX0 >= srcXmax && *srcX1 >= srcXmax) + return GL_FALSE; + + if (*srcY0 == *srcY1) + return GL_FALSE; + if (*srcY0 <= srcYmin && *srcY1 <= srcYmin) + return GL_FALSE; + if (*srcY0 >= srcYmax && *srcY1 >= srcYmax) + return GL_FALSE; + + /* + * dest clip + */ + clip_right_or_top(srcX0, srcX1, dstX0, dstX1, dstXmax); + clip_right_or_top(srcY0, srcY1, dstY0, dstY1, dstYmax); + clip_left_or_bottom(srcX0, srcX1, dstX0, dstX1, dstXmin); + clip_left_or_bottom(srcY0, srcY1, dstY0, dstY1, dstYmin); + + /* + * src clip (just swap src/dst values from above) + */ + clip_right_or_top(dstX0, dstX1, srcX0, srcX1, srcXmax); + clip_right_or_top(dstY0, dstY1, srcY0, srcY1, srcYmax); + clip_left_or_bottom(dstX0, dstX1, srcX0, srcX1, srcXmin); + clip_left_or_bottom(dstY0, dstY1, srcY0, srcY1, srcYmin); + + /* + printf("PostClipX: src: %d .. %d dst: %d .. %d\n", + *srcX0, *srcX1, *dstX0, *dstX1); + printf("PostClipY: src: %d .. %d dst: %d .. %d\n", + *srcY0, *srcY1, *dstY0, *dstY1); + */ + + ASSERT(*dstX0 >= dstXmin); + ASSERT(*dstX0 <= dstXmax); + ASSERT(*dstX1 >= dstXmin); + ASSERT(*dstX1 <= dstXmax); + + ASSERT(*dstY0 >= dstYmin); + ASSERT(*dstY0 <= dstYmax); + ASSERT(*dstY1 >= dstYmin); + ASSERT(*dstY1 <= dstYmax); + + ASSERT(*srcX0 >= srcXmin); + ASSERT(*srcX0 <= srcXmax); + ASSERT(*srcX1 >= srcXmin); + ASSERT(*srcX1 <= srcXmax); + + ASSERT(*srcY0 >= srcYmin); + ASSERT(*srcY0 <= srcYmax); + ASSERT(*srcY1 >= srcYmin); + ASSERT(*srcY1 <= srcYmax); + + return GL_TRUE; +} diff --git a/mesalib/src/mesa/main/mipmap.c b/mesalib/src/mesa/main/mipmap.c index 0727e1818..e594160ad 100644 --- a/mesalib/src/mesa/main/mipmap.c +++ b/mesalib/src/mesa/main/mipmap.c @@ -1764,8 +1764,13 @@ _mesa_generate_mipmap(struct gl_context *ctx, GLenum target, } else if (srcImage->_BaseFormat == GL_RGBA) { convertFormat = MESA_FORMAT_RGBA8888; components = 4; - } - else { + } else if (srcImage->_BaseFormat == GL_LUMINANCE) { + convertFormat = MESA_FORMAT_L8; + components = 1; + } else if (srcImage->_BaseFormat == GL_LUMINANCE_ALPHA) { + convertFormat = MESA_FORMAT_AL88; + components = 2; + } else { _mesa_problem(ctx, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps"); return; } diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h index 49ecea59d..695d93652 100644 --- a/mesalib/src/mesa/main/mtypes.h +++ b/mesalib/src/mesa/main/mtypes.h @@ -2802,6 +2802,7 @@ struct gl_extensions GLboolean EXT_texture_object; GLboolean EXT_texture3D; GLboolean EXT_texture_array; + GLboolean EXT_texture_compression_latc; GLboolean EXT_texture_compression_s3tc; GLboolean EXT_texture_env_add; GLboolean EXT_texture_env_combine; @@ -2827,6 +2828,7 @@ struct gl_extensions GLboolean APPLE_vertex_array_object; GLboolean APPLE_object_purgeable; GLboolean ATI_envmap_bumpmap; + GLboolean ATI_texture_compression_3dc; GLboolean ATI_texture_mirror_once; GLboolean ATI_texture_env_combine3; GLboolean ATI_fragment_shader; diff --git a/mesalib/src/mesa/main/texcompress.c b/mesalib/src/mesa/main/texcompress.c index 82d02ed0e..d820ae927 100644 --- a/mesalib/src/mesa/main/texcompress.c +++ b/mesalib/src/mesa/main/texcompress.c @@ -173,6 +173,16 @@ _mesa_glenum_to_compressed_format(GLenum format) case GL_COMPRESSED_SIGNED_RG_RGTC2: return MESA_FORMAT_SIGNED_RG_RGTC2; + case GL_COMPRESSED_LUMINANCE_LATC1_EXT: + return MESA_FORMAT_L_LATC1; + case GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT: + return MESA_FORMAT_SIGNED_L_LATC1; + case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: + case GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI: + return MESA_FORMAT_LA_LATC2; + case GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT: + return MESA_FORMAT_SIGNED_LA_LATC2; + default: return MESA_FORMAT_NONE; } @@ -229,6 +239,15 @@ _mesa_compressed_format_to_glenum(struct gl_context *ctx, GLuint mesaFormat) case MESA_FORMAT_SIGNED_RG_RGTC2: return GL_COMPRESSED_SIGNED_RG_RGTC2; + case MESA_FORMAT_L_LATC1: + return GL_COMPRESSED_LUMINANCE_LATC1_EXT; + case MESA_FORMAT_SIGNED_L_LATC1: + return GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT; + case MESA_FORMAT_LA_LATC2: + return GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT; + case MESA_FORMAT_SIGNED_LA_LATC2: + return GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT; + default: _mesa_problem(ctx, "Unexpected mesa texture format in" " _mesa_compressed_format_to_glenum()"); diff --git a/mesalib/src/mesa/main/texcompress_rgtc.c b/mesalib/src/mesa/main/texcompress_rgtc.c index 26dca2d76..c50df19c5 100644 --- a/mesalib/src/mesa/main/texcompress_rgtc.c +++ b/mesalib/src/mesa/main/texcompress_rgtc.c @@ -98,7 +98,8 @@ _mesa_texstore_red_rgtc1(TEXSTORE_PARAMS) GLubyte srcpixels[4][4]; GLubyte *blkaddr; GLint dstRowDiff; - ASSERT(dstFormat == MESA_FORMAT_RED_RGTC1); + ASSERT(dstFormat == MESA_FORMAT_RED_RGTC1 || + dstFormat == MESA_FORMAT_L_LATC1); ASSERT(dstXoffset % 4 == 0); ASSERT(dstYoffset % 4 == 0); ASSERT(dstZoffset % 4 == 0); @@ -153,7 +154,8 @@ _mesa_texstore_signed_red_rgtc1(TEXSTORE_PARAMS) GLbyte srcpixels[4][4]; GLbyte *blkaddr; GLint dstRowDiff; - ASSERT(dstFormat == MESA_FORMAT_SIGNED_RED_RGTC1); + ASSERT(dstFormat == MESA_FORMAT_SIGNED_RED_RGTC1 || + dstFormat == MESA_FORMAT_SIGNED_L_LATC1); ASSERT(dstXoffset % 4 == 0); ASSERT(dstYoffset % 4 == 0); ASSERT(dstZoffset % 4 == 0); @@ -208,7 +210,8 @@ _mesa_texstore_rg_rgtc2(TEXSTORE_PARAMS) GLubyte *blkaddr; GLint dstRowDiff; - ASSERT(dstFormat == MESA_FORMAT_RG_RGTC2); + ASSERT(dstFormat == MESA_FORMAT_RG_RGTC2 || + dstFormat == MESA_FORMAT_LA_LATC2); ASSERT(dstXoffset % 4 == 0); ASSERT(dstYoffset % 4 == 0); ASSERT(dstZoffset % 4 == 0); @@ -269,7 +272,8 @@ _mesa_texstore_signed_rg_rgtc2(TEXSTORE_PARAMS) GLbyte *blkaddr; GLint dstRowDiff; - ASSERT(dstFormat == MESA_FORMAT_SIGNED_RG_RGTC2); + ASSERT(dstFormat == MESA_FORMAT_SIGNED_RG_RGTC2 || + dstFormat == MESA_FORMAT_SIGNED_LA_LATC2); ASSERT(dstXoffset % 4 == 0); ASSERT(dstYoffset % 4 == 0); ASSERT(dstZoffset % 4 == 0); @@ -374,6 +378,62 @@ _mesa_fetch_texel_2d_f_signed_rg_rgtc2(const struct gl_texture_image *texImage, texel[ACOMP] = 1.0; } +void +_mesa_fetch_texel_2d_f_l_latc1(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel) +{ + GLubyte red; + unsigned_fetch_texel_rgtc(texImage->RowStride, (GLubyte *)(texImage->Data), + i, j, &red, 1); + texel[RCOMP] = + texel[GCOMP] = + texel[BCOMP] = UBYTE_TO_FLOAT(red); + texel[ACOMP] = 1.0; +} + +void +_mesa_fetch_texel_2d_f_signed_l_latc1(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel) +{ + GLbyte red; + signed_fetch_texel_rgtc(texImage->RowStride, (GLbyte *)(texImage->Data), + i, j, &red, 1); + texel[RCOMP] = + texel[GCOMP] = + texel[BCOMP] = BYTE_TO_FLOAT_TEX(red); + texel[ACOMP] = 1.0; +} + +void +_mesa_fetch_texel_2d_f_la_latc2(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel) +{ + GLubyte red, green; + unsigned_fetch_texel_rgtc(texImage->RowStride, (GLubyte *)(texImage->Data), + i, j, &red, 2); + unsigned_fetch_texel_rgtc(texImage->RowStride, (GLubyte *)(texImage->Data) + 8, + i, j, &green, 2); + texel[RCOMP] = + texel[GCOMP] = + texel[BCOMP] = UBYTE_TO_FLOAT(red); + texel[ACOMP] = UBYTE_TO_FLOAT(green); +} + +void +_mesa_fetch_texel_2d_f_signed_la_latc2(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel) +{ + GLbyte red, green; + signed_fetch_texel_rgtc(texImage->RowStride, (GLbyte *)(texImage->Data), + i, j, &red, 2); + signed_fetch_texel_rgtc(texImage->RowStride, (GLbyte *)(texImage->Data) + 8, + i, j, &green, 2); + texel[RCOMP] = + texel[GCOMP] = + texel[BCOMP] = BYTE_TO_FLOAT_TEX(red); + texel[ACOMP] = BYTE_TO_FLOAT_TEX(green); +} + #define TAG(x) unsigned_##x #define TYPE GLubyte diff --git a/mesalib/src/mesa/main/texcompress_rgtc.h b/mesalib/src/mesa/main/texcompress_rgtc.h index 424edc458..18766770d 100644 --- a/mesalib/src/mesa/main/texcompress_rgtc.h +++ b/mesalib/src/mesa/main/texcompress_rgtc.h @@ -57,4 +57,21 @@ _mesa_fetch_texel_2d_f_rg_rgtc2(const struct gl_texture_image *texImage, extern void _mesa_fetch_texel_2d_f_signed_rg_rgtc2(const struct gl_texture_image *texImage, GLint i, GLint j, GLint k, GLfloat *texel); + +extern void +_mesa_fetch_texel_2d_f_l_latc1(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel); + +extern void +_mesa_fetch_texel_2d_f_signed_l_latc1(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel); + +extern void +_mesa_fetch_texel_2d_f_la_latc2(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel); + +extern void +_mesa_fetch_texel_2d_f_signed_la_latc2(const struct gl_texture_image *texImage, + GLint i, GLint j, GLint k, GLfloat *texel); + #endif diff --git a/mesalib/src/mesa/main/texfetch.c b/mesalib/src/mesa/main/texfetch.c index 550597e1c..988a7e054 100644 --- a/mesalib/src/mesa/main/texfetch.c +++ b/mesalib/src/mesa/main/texfetch.c @@ -786,6 +786,34 @@ texfetch_funcs[MESA_FORMAT_COUNT] = NULL, NULL }, + { + MESA_FORMAT_L_LATC1, + NULL, + _mesa_fetch_texel_2d_f_l_latc1, + NULL, + NULL + }, + { + MESA_FORMAT_SIGNED_L_LATC1, + NULL, + _mesa_fetch_texel_2d_f_signed_l_latc1, + NULL, + NULL + }, + { + MESA_FORMAT_LA_LATC2, + NULL, + _mesa_fetch_texel_2d_f_la_latc2, + NULL, + NULL + }, + { + MESA_FORMAT_SIGNED_LA_LATC2, + NULL, + _mesa_fetch_texel_2d_f_signed_la_latc2, + NULL, + NULL + }, }; diff --git a/mesalib/src/mesa/main/texformat.c b/mesalib/src/mesa/main/texformat.c index 72025cf82..5eabf2aa5 100644 --- a/mesalib/src/mesa/main/texformat.c +++ b/mesalib/src/mesa/main/texformat.c @@ -621,6 +621,35 @@ _mesa_choose_tex_format( struct gl_context *ctx, GLint internalFormat, } } + if (ctx->Extensions.EXT_texture_compression_latc) { + switch (internalFormat) { + case GL_COMPRESSED_LUMINANCE_LATC1_EXT: + RETURN_IF_SUPPORTED(MESA_FORMAT_L_LATC1); + break; + case GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT: + RETURN_IF_SUPPORTED(MESA_FORMAT_SIGNED_L_LATC1); + break; + case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: + RETURN_IF_SUPPORTED(MESA_FORMAT_LA_LATC2); + break; + case GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT: + RETURN_IF_SUPPORTED(MESA_FORMAT_SIGNED_LA_LATC2); + break; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.ATI_texture_compression_3dc) { + switch (internalFormat) { + case GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI: + RETURN_IF_SUPPORTED(MESA_FORMAT_LA_LATC2); + break; + default: + ; /* fallthrough */ + } + } + _mesa_problem(ctx, "unexpected format in _mesa_choose_tex_format()"); return MESA_FORMAT_NONE; } diff --git a/mesalib/src/mesa/main/teximage.c b/mesalib/src/mesa/main/teximage.c index d4ae6dd69..2a3037f61 100644 --- a/mesalib/src/mesa/main/teximage.c +++ b/mesalib/src/mesa/main/teximage.c @@ -509,6 +509,28 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) } } + if (ctx->Extensions.EXT_texture_compression_latc) { + switch (internalFormat) { + case GL_COMPRESSED_LUMINANCE_LATC1_EXT: + case GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT: + return GL_LUMINANCE; + case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: + case GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT: + return GL_LUMINANCE_ALPHA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.ATI_texture_compression_3dc) { + switch (internalFormat) { + case GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI: + return GL_LUMINANCE_ALPHA; + default: + ; /* fallthrough */ + } + } + return -1; /* error */ } diff --git a/mesalib/src/mesa/main/texstore.c b/mesalib/src/mesa/main/texstore.c index cd30fa021..760cdfa85 100644 --- a/mesalib/src/mesa/main/texstore.c +++ b/mesalib/src/mesa/main/texstore.c @@ -4135,7 +4135,14 @@ texstore_funcs[MESA_FORMAT_COUNT] = { MESA_FORMAT_RED_RGTC1, _mesa_texstore_red_rgtc1 }, { MESA_FORMAT_SIGNED_RED_RGTC1, _mesa_texstore_signed_red_rgtc1 }, { MESA_FORMAT_RG_RGTC2, _mesa_texstore_rg_rgtc2 }, - { MESA_FORMAT_SIGNED_RG_RGTC2, _mesa_texstore_signed_rg_rgtc2 } + { MESA_FORMAT_SIGNED_RG_RGTC2, _mesa_texstore_signed_rg_rgtc2 }, + + /* Re-use the R/RG texstore functions. + * The code is generic enough to handle LATC too. */ + { MESA_FORMAT_L_LATC1, _mesa_texstore_red_rgtc1 }, + { MESA_FORMAT_SIGNED_L_LATC1, _mesa_texstore_signed_red_rgtc1 }, + { MESA_FORMAT_LA_LATC2, _mesa_texstore_rg_rgtc2 }, + { MESA_FORMAT_SIGNED_LA_LATC2, _mesa_texstore_signed_rg_rgtc2 } }; diff --git a/mesalib/src/mesa/sources.mak b/mesalib/src/mesa/sources.mak index e1598869c..95330947a 100644 --- a/mesalib/src/mesa/sources.mak +++ b/mesalib/src/mesa/sources.mak @@ -1,371 +1,372 @@ -### Lists of source files, included by Makefiles - -# this is part of MAIN_SOURCES -MAIN_ES_SOURCES = \ - main/api_exec_es1.c \ - main/api_exec_es2.c - -MAIN_SOURCES = \ - main/api_arrayelt.c \ - main/api_exec.c \ - main/api_loopback.c \ - main/api_noop.c \ - main/api_validate.c \ - main/accum.c \ - main/arbprogram.c \ - main/atifragshader.c \ - main/attrib.c \ - main/arrayobj.c \ - main/blend.c \ - main/bufferobj.c \ - main/buffers.c \ - main/clear.c \ - main/clip.c \ - main/colortab.c \ - main/condrender.c \ - main/context.c \ - main/convolve.c \ - main/cpuinfo.c \ - main/debug.c \ - main/depth.c \ - main/depthstencil.c \ - main/dlist.c \ - main/dlopen.c \ - main/drawpix.c \ - main/drawtex.c \ - main/enable.c \ - main/enums.c \ - main/eval.c \ - main/execmem.c \ - main/extensions.c \ - main/fbobject.c \ - main/feedback.c \ - main/ffvertex_prog.c \ - main/fog.c \ - main/formats.c \ - main/framebuffer.c \ - main/get.c \ - main/getstring.c \ - main/hash.c \ - main/hint.c \ - main/histogram.c \ - main/image.c \ - main/imports.c \ - main/light.c \ - main/lines.c \ - main/matrix.c \ - main/mipmap.c \ - main/mm.c \ - main/multisample.c \ - main/nvprogram.c \ - main/pack.c \ - main/pbo.c \ - main/pixel.c \ - main/pixelstore.c \ - main/pixeltransfer.c \ - main/points.c \ - main/polygon.c \ - main/queryobj.c \ - main/querymatrix.c \ - main/rastpos.c \ - main/readpix.c \ - main/remap.c \ - main/renderbuffer.c \ - main/scissor.c \ - main/shaderapi.c \ - main/shaderobj.c \ - main/shared.c \ - main/state.c \ - main/stencil.c \ - main/syncobj.c \ - main/texcompress.c \ - main/texcompress_rgtc.c \ - main/texcompress_s3tc.c \ - main/texcompress_fxt1.c \ - main/texenv.c \ - main/texenvprogram.c \ - main/texfetch.c \ - main/texformat.c \ - main/texgen.c \ - main/texgetimage.c \ - main/teximage.c \ - main/texobj.c \ - main/texpal.c \ - main/texparam.c \ - main/texrender.c \ - main/texstate.c \ - main/texstore.c \ - main/transformfeedback.c \ - main/uniforms.c \ - main/varray.c \ - main/version.c \ - main/viewport.c \ - main/vtxfmt.c \ - $(MAIN_ES_SOURCES) - -MATH_SOURCES = \ - math/m_debug_clip.c \ - math/m_debug_norm.c \ - math/m_debug_xform.c \ - math/m_eval.c \ - math/m_matrix.c \ - math/m_translate.c \ - math/m_vector.c - -MATH_XFORM_SOURCES = \ - math/m_xform.c - -SWRAST_SOURCES = \ - swrast/s_aaline.c \ - swrast/s_aatriangle.c \ - swrast/s_accum.c \ - swrast/s_alpha.c \ - swrast/s_atifragshader.c \ - swrast/s_bitmap.c \ - swrast/s_blend.c \ - swrast/s_blit.c \ - swrast/s_clear.c \ - swrast/s_copypix.c \ - swrast/s_context.c \ - swrast/s_depth.c \ - swrast/s_drawpix.c \ - swrast/s_feedback.c \ - swrast/s_fog.c \ - swrast/s_fragprog.c \ - swrast/s_lines.c \ - swrast/s_logic.c \ - swrast/s_masking.c \ - swrast/s_points.c \ - swrast/s_readpix.c \ - swrast/s_span.c \ - swrast/s_stencil.c \ - swrast/s_texcombine.c \ - swrast/s_texfilter.c \ - swrast/s_triangle.c \ - swrast/s_zoom.c - -SWRAST_SETUP_SOURCES = \ - swrast_setup/ss_context.c \ - swrast_setup/ss_triangle.c - -TNL_SOURCES = \ - tnl/t_context.c \ - tnl/t_pipeline.c \ - tnl/t_draw.c \ - tnl/t_rasterpos.c \ - tnl/t_vb_program.c \ - tnl/t_vb_render.c \ - tnl/t_vb_texgen.c \ - tnl/t_vb_texmat.c \ - tnl/t_vb_vertex.c \ - tnl/t_vb_fog.c \ - tnl/t_vb_light.c \ - tnl/t_vb_normals.c \ - tnl/t_vb_points.c \ - tnl/t_vp_build.c \ - tnl/t_vertex.c \ - tnl/t_vertex_sse.c \ - tnl/t_vertex_generic.c - -VBO_SOURCES = \ - vbo/vbo_context.c \ - vbo/vbo_exec.c \ - vbo/vbo_exec_api.c \ - vbo/vbo_exec_array.c \ - vbo/vbo_exec_draw.c \ - vbo/vbo_exec_eval.c \ - vbo/vbo_rebase.c \ - vbo/vbo_split.c \ - vbo/vbo_split_copy.c \ - vbo/vbo_split_inplace.c \ - vbo/vbo_save.c \ - vbo/vbo_save_api.c \ - vbo/vbo_save_draw.c \ - vbo/vbo_save_loopback.c - -STATETRACKER_SOURCES = \ - state_tracker/st_atom.c \ - state_tracker/st_atom_blend.c \ - state_tracker/st_atom_clip.c \ - state_tracker/st_atom_constbuf.c \ - state_tracker/st_atom_depth.c \ - state_tracker/st_atom_framebuffer.c \ - state_tracker/st_atom_msaa.c \ - state_tracker/st_atom_pixeltransfer.c \ - state_tracker/st_atom_sampler.c \ - state_tracker/st_atom_scissor.c \ - state_tracker/st_atom_shader.c \ - state_tracker/st_atom_rasterizer.c \ - state_tracker/st_atom_stipple.c \ - state_tracker/st_atom_texture.c \ - state_tracker/st_atom_viewport.c \ - state_tracker/st_cb_accum.c \ - state_tracker/st_cb_bitmap.c \ - state_tracker/st_cb_blit.c \ - state_tracker/st_cb_bufferobjects.c \ - state_tracker/st_cb_clear.c \ - state_tracker/st_cb_condrender.c \ - state_tracker/st_cb_flush.c \ - state_tracker/st_cb_drawpixels.c \ - state_tracker/st_cb_drawtex.c \ - state_tracker/st_cb_eglimage.c \ - state_tracker/st_cb_fbo.c \ - state_tracker/st_cb_feedback.c \ - state_tracker/st_cb_program.c \ - state_tracker/st_cb_queryobj.c \ - state_tracker/st_cb_rasterpos.c \ - state_tracker/st_cb_readpixels.c \ - state_tracker/st_cb_strings.c \ - state_tracker/st_cb_texture.c \ - state_tracker/st_cb_viewport.c \ - state_tracker/st_cb_xformfb.c \ - state_tracker/st_context.c \ - state_tracker/st_debug.c \ - state_tracker/st_draw.c \ - state_tracker/st_draw_feedback.c \ - state_tracker/st_extensions.c \ - state_tracker/st_format.c \ - state_tracker/st_gen_mipmap.c \ - state_tracker/st_manager.c \ - state_tracker/st_mesa_to_tgsi.c \ - state_tracker/st_program.c \ - state_tracker/st_texture.c - -PROGRAM_SOURCES = \ - program/arbprogparse.c \ - program/hash_table.c \ - program/lex.yy.c \ - program/nvfragparse.c \ - program/nvvertparse.c \ - program/program.c \ - program/program_parse.tab.c \ - program/program_parse_extra.c \ - program/prog_cache.c \ - program/prog_execute.c \ - program/prog_instruction.c \ - program/prog_noise.c \ - program/prog_optimize.c \ - program/prog_parameter.c \ - program/prog_parameter_layout.c \ - program/prog_print.c \ - program/prog_statevars.c \ - program/prog_uniform.c \ - program/programopt.c \ - program/register_allocate.c \ - program/symbol_table.c - - -SHADER_CXX_SOURCES = \ - program/ir_to_mesa.cpp \ - program/sampler.cpp - -ASM_C_SOURCES = \ - x86/common_x86.c \ - x86/x86_xform.c \ - x86/3dnow.c \ - x86/sse.c \ - x86/rtasm/x86sse.c \ - sparc/sparc.c \ - ppc/common_ppc.c \ - x86-64/x86-64.c - -X86_SOURCES = \ - x86/common_x86_asm.S \ - x86/x86_xform2.S \ - x86/x86_xform3.S \ - x86/x86_xform4.S \ - x86/x86_cliptest.S \ - x86/mmx_blend.S \ - x86/3dnow_xform1.S \ - x86/3dnow_xform2.S \ - x86/3dnow_xform3.S \ - x86/3dnow_xform4.S \ - x86/3dnow_normal.S \ - x86/sse_xform1.S \ - x86/sse_xform2.S \ - x86/sse_xform3.S \ - x86/sse_xform4.S \ - x86/sse_normal.S \ - x86/read_rgba_span_x86.S - -X86-64_SOURCES = \ - x86-64/xform4.S - -SPARC_SOURCES = \ - sparc/clip.S \ - sparc/norm.S \ - sparc/xform.S - -COMMON_DRIVER_SOURCES = \ - drivers/common/driverfuncs.c \ - drivers/common/meta.c - - -# Sources for building non-Gallium drivers -MESA_SOURCES = \ - $(MAIN_SOURCES) \ - $(MATH_SOURCES) \ - $(MATH_XFORM_SOURCES) \ - $(VBO_SOURCES) \ - $(TNL_SOURCES) \ - $(PROGRAM_SOURCES) \ - $(SWRAST_SOURCES) \ - $(SWRAST_SETUP_SOURCES) \ - $(COMMON_DRIVER_SOURCES)\ - $(ASM_C_SOURCES) - -MESA_CXX_SOURCES = \ - $(SHADER_CXX_SOURCES) - -# Sources for building Gallium drivers -MESA_GALLIUM_SOURCES = \ - $(MAIN_SOURCES) \ - $(MATH_SOURCES) \ - $(VBO_SOURCES) \ - $(STATETRACKER_SOURCES) \ - $(PROGRAM_SOURCES) \ - ppc/common_ppc.c \ - x86/common_x86.c - -MESA_GALLIUM_CXX_SOURCES = \ - $(SHADER_CXX_SOURCES) - -# All the core C sources, for dependency checking -ALL_SOURCES = \ - $(MESA_SOURCES) \ - $(MESA_CXX_SOURCES) \ - $(MESA_ASM_SOURCES) \ - $(STATETRACKER_SOURCES) - - -### Object files - -MESA_OBJECTS = \ - $(MESA_SOURCES:.c=.o) \ - $(MESA_CXX_SOURCES:.cpp=.o) \ - $(MESA_ASM_SOURCES:.S=.o) - -MESA_GALLIUM_OBJECTS = \ - $(MESA_GALLIUM_SOURCES:.c=.o) \ - $(MESA_GALLIUM_CXX_SOURCES:.cpp=.o) \ - $(MESA_ASM_SOURCES:.S=.o) - - -COMMON_DRIVER_OBJECTS = $(COMMON_DRIVER_SOURCES:.c=.o) - - -### Other archives/libraries - -GLSL_LIBS = \ - $(TOP)/src/glsl/libglsl.a - - -### Include directories - -INCLUDE_DIRS = \ - -I$(TOP)/include \ - -I$(TOP)/src/glsl \ - -I$(TOP)/src/mesa \ - -I$(TOP)/src/mapi \ - -I$(TOP)/src/gallium/include \ - -I$(TOP)/src/gallium/auxiliary +### Lists of source files, included by Makefiles + +# this is part of MAIN_SOURCES +MAIN_ES_SOURCES = \ + main/api_exec_es1.c \ + main/api_exec_es2.c + +MAIN_SOURCES = \ + main/api_arrayelt.c \ + main/api_exec.c \ + main/api_loopback.c \ + main/api_noop.c \ + main/api_validate.c \ + main/accum.c \ + main/arbprogram.c \ + main/atifragshader.c \ + main/attrib.c \ + main/arrayobj.c \ + main/blend.c \ + main/bufferobj.c \ + main/buffers.c \ + main/clear.c \ + main/clip.c \ + main/colortab.c \ + main/condrender.c \ + main/context.c \ + main/convolve.c \ + main/cpuinfo.c \ + main/debug.c \ + main/depth.c \ + main/depthstencil.c \ + main/dlist.c \ + main/dlopen.c \ + main/drawpix.c \ + main/drawtex.c \ + main/enable.c \ + main/enums.c \ + main/eval.c \ + main/execmem.c \ + main/extensions.c \ + main/fbobject.c \ + main/feedback.c \ + main/ffvertex_prog.c \ + main/fog.c \ + main/formats.c \ + main/framebuffer.c \ + main/get.c \ + main/getstring.c \ + main/hash.c \ + main/hint.c \ + main/histogram.c \ + main/image.c \ + main/imports.c \ + main/light.c \ + main/lines.c \ + main/matrix.c \ + main/mipmap.c \ + main/mm.c \ + main/multisample.c \ + main/nvprogram.c \ + main/pack.c \ + main/pbo.c \ + main/pixel.c \ + main/pixelstore.c \ + main/pixeltransfer.c \ + main/points.c \ + main/polygon.c \ + main/queryobj.c \ + main/querymatrix.c \ + main/rastpos.c \ + main/readpix.c \ + main/remap.c \ + main/renderbuffer.c \ + main/scissor.c \ + main/shaderapi.c \ + main/shaderobj.c \ + main/shared.c \ + main/state.c \ + main/stencil.c \ + main/syncobj.c \ + main/texcompress.c \ + main/texcompress_rgtc.c \ + main/texcompress_s3tc.c \ + main/texcompress_fxt1.c \ + main/texenv.c \ + main/texenvprogram.c \ + main/texfetch.c \ + main/texformat.c \ + main/texgen.c \ + main/texgetimage.c \ + main/teximage.c \ + main/texobj.c \ + main/texpal.c \ + main/texparam.c \ + main/texrender.c \ + main/texstate.c \ + main/texstore.c \ + main/transformfeedback.c \ + main/uniforms.c \ + main/varray.c \ + main/version.c \ + main/viewport.c \ + main/vtxfmt.c \ + $(MAIN_ES_SOURCES) + +MATH_SOURCES = \ + math/m_debug_clip.c \ + math/m_debug_norm.c \ + math/m_debug_xform.c \ + math/m_eval.c \ + math/m_matrix.c \ + math/m_translate.c \ + math/m_vector.c + +MATH_XFORM_SOURCES = \ + math/m_xform.c + +SWRAST_SOURCES = \ + swrast/s_aaline.c \ + swrast/s_aatriangle.c \ + swrast/s_accum.c \ + swrast/s_alpha.c \ + swrast/s_atifragshader.c \ + swrast/s_bitmap.c \ + swrast/s_blend.c \ + swrast/s_blit.c \ + swrast/s_clear.c \ + swrast/s_copypix.c \ + swrast/s_context.c \ + swrast/s_depth.c \ + swrast/s_drawpix.c \ + swrast/s_feedback.c \ + swrast/s_fog.c \ + swrast/s_fragprog.c \ + swrast/s_lines.c \ + swrast/s_logic.c \ + swrast/s_masking.c \ + swrast/s_points.c \ + swrast/s_readpix.c \ + swrast/s_span.c \ + swrast/s_stencil.c \ + swrast/s_texcombine.c \ + swrast/s_texfilter.c \ + swrast/s_triangle.c \ + swrast/s_zoom.c + +SWRAST_SETUP_SOURCES = \ + swrast_setup/ss_context.c \ + swrast_setup/ss_triangle.c + +TNL_SOURCES = \ + tnl/t_context.c \ + tnl/t_pipeline.c \ + tnl/t_draw.c \ + tnl/t_rasterpos.c \ + tnl/t_vb_program.c \ + tnl/t_vb_render.c \ + tnl/t_vb_texgen.c \ + tnl/t_vb_texmat.c \ + tnl/t_vb_vertex.c \ + tnl/t_vb_fog.c \ + tnl/t_vb_light.c \ + tnl/t_vb_normals.c \ + tnl/t_vb_points.c \ + tnl/t_vp_build.c \ + tnl/t_vertex.c \ + tnl/t_vertex_sse.c \ + tnl/t_vertex_generic.c + +VBO_SOURCES = \ + vbo/vbo_context.c \ + vbo/vbo_exec.c \ + vbo/vbo_exec_api.c \ + vbo/vbo_exec_array.c \ + vbo/vbo_exec_draw.c \ + vbo/vbo_exec_eval.c \ + vbo/vbo_rebase.c \ + vbo/vbo_split.c \ + vbo/vbo_split_copy.c \ + vbo/vbo_split_inplace.c \ + vbo/vbo_save.c \ + vbo/vbo_save_api.c \ + vbo/vbo_save_draw.c \ + vbo/vbo_save_loopback.c + +STATETRACKER_SOURCES = \ + state_tracker/st_atom.c \ + state_tracker/st_atom_blend.c \ + state_tracker/st_atom_clip.c \ + state_tracker/st_atom_constbuf.c \ + state_tracker/st_atom_depth.c \ + state_tracker/st_atom_framebuffer.c \ + state_tracker/st_atom_msaa.c \ + state_tracker/st_atom_pixeltransfer.c \ + state_tracker/st_atom_sampler.c \ + state_tracker/st_atom_scissor.c \ + state_tracker/st_atom_shader.c \ + state_tracker/st_atom_rasterizer.c \ + state_tracker/st_atom_stipple.c \ + state_tracker/st_atom_texture.c \ + state_tracker/st_atom_viewport.c \ + state_tracker/st_cb_accum.c \ + state_tracker/st_cb_bitmap.c \ + state_tracker/st_cb_blit.c \ + state_tracker/st_cb_bufferobjects.c \ + state_tracker/st_cb_clear.c \ + state_tracker/st_cb_condrender.c \ + state_tracker/st_cb_flush.c \ + state_tracker/st_cb_drawpixels.c \ + state_tracker/st_cb_drawtex.c \ + state_tracker/st_cb_eglimage.c \ + state_tracker/st_cb_fbo.c \ + state_tracker/st_cb_feedback.c \ + state_tracker/st_cb_program.c \ + state_tracker/st_cb_queryobj.c \ + state_tracker/st_cb_rasterpos.c \ + state_tracker/st_cb_readpixels.c \ + state_tracker/st_cb_syncobj.c \ + state_tracker/st_cb_strings.c \ + state_tracker/st_cb_texture.c \ + state_tracker/st_cb_viewport.c \ + state_tracker/st_cb_xformfb.c \ + state_tracker/st_context.c \ + state_tracker/st_debug.c \ + state_tracker/st_draw.c \ + state_tracker/st_draw_feedback.c \ + state_tracker/st_extensions.c \ + state_tracker/st_format.c \ + state_tracker/st_gen_mipmap.c \ + state_tracker/st_manager.c \ + state_tracker/st_mesa_to_tgsi.c \ + state_tracker/st_program.c \ + state_tracker/st_texture.c + +PROGRAM_SOURCES = \ + program/arbprogparse.c \ + program/hash_table.c \ + program/lex.yy.c \ + program/nvfragparse.c \ + program/nvvertparse.c \ + program/program.c \ + program/program_parse.tab.c \ + program/program_parse_extra.c \ + program/prog_cache.c \ + program/prog_execute.c \ + program/prog_instruction.c \ + program/prog_noise.c \ + program/prog_optimize.c \ + program/prog_parameter.c \ + program/prog_parameter_layout.c \ + program/prog_print.c \ + program/prog_statevars.c \ + program/prog_uniform.c \ + program/programopt.c \ + program/register_allocate.c \ + program/symbol_table.c + + +SHADER_CXX_SOURCES = \ + program/ir_to_mesa.cpp \ + program/sampler.cpp + +ASM_C_SOURCES = \ + x86/common_x86.c \ + x86/x86_xform.c \ + x86/3dnow.c \ + x86/sse.c \ + x86/rtasm/x86sse.c \ + sparc/sparc.c \ + ppc/common_ppc.c \ + x86-64/x86-64.c + +X86_SOURCES = \ + x86/common_x86_asm.S \ + x86/x86_xform2.S \ + x86/x86_xform3.S \ + x86/x86_xform4.S \ + x86/x86_cliptest.S \ + x86/mmx_blend.S \ + x86/3dnow_xform1.S \ + x86/3dnow_xform2.S \ + x86/3dnow_xform3.S \ + x86/3dnow_xform4.S \ + x86/3dnow_normal.S \ + x86/sse_xform1.S \ + x86/sse_xform2.S \ + x86/sse_xform3.S \ + x86/sse_xform4.S \ + x86/sse_normal.S \ + x86/read_rgba_span_x86.S + +X86-64_SOURCES = \ + x86-64/xform4.S + +SPARC_SOURCES = \ + sparc/clip.S \ + sparc/norm.S \ + sparc/xform.S + +COMMON_DRIVER_SOURCES = \ + drivers/common/driverfuncs.c \ + drivers/common/meta.c + + +# Sources for building non-Gallium drivers +MESA_SOURCES = \ + $(MAIN_SOURCES) \ + $(MATH_SOURCES) \ + $(MATH_XFORM_SOURCES) \ + $(VBO_SOURCES) \ + $(TNL_SOURCES) \ + $(PROGRAM_SOURCES) \ + $(SWRAST_SOURCES) \ + $(SWRAST_SETUP_SOURCES) \ + $(COMMON_DRIVER_SOURCES)\ + $(ASM_C_SOURCES) + +MESA_CXX_SOURCES = \ + $(SHADER_CXX_SOURCES) + +# Sources for building Gallium drivers +MESA_GALLIUM_SOURCES = \ + $(MAIN_SOURCES) \ + $(MATH_SOURCES) \ + $(VBO_SOURCES) \ + $(STATETRACKER_SOURCES) \ + $(PROGRAM_SOURCES) \ + ppc/common_ppc.c \ + x86/common_x86.c + +MESA_GALLIUM_CXX_SOURCES = \ + $(SHADER_CXX_SOURCES) + +# All the core C sources, for dependency checking +ALL_SOURCES = \ + $(MESA_SOURCES) \ + $(MESA_CXX_SOURCES) \ + $(MESA_ASM_SOURCES) \ + $(STATETRACKER_SOURCES) + + +### Object files + +MESA_OBJECTS = \ + $(MESA_SOURCES:.c=.o) \ + $(MESA_CXX_SOURCES:.cpp=.o) \ + $(MESA_ASM_SOURCES:.S=.o) + +MESA_GALLIUM_OBJECTS = \ + $(MESA_GALLIUM_SOURCES:.c=.o) \ + $(MESA_GALLIUM_CXX_SOURCES:.cpp=.o) \ + $(MESA_ASM_SOURCES:.S=.o) + + +COMMON_DRIVER_OBJECTS = $(COMMON_DRIVER_SOURCES:.c=.o) + + +### Other archives/libraries + +GLSL_LIBS = \ + $(TOP)/src/glsl/libglsl.a + + +### Include directories + +INCLUDE_DIRS = \ + -I$(TOP)/include \ + -I$(TOP)/src/glsl \ + -I$(TOP)/src/mesa \ + -I$(TOP)/src/mapi \ + -I$(TOP)/src/gallium/include \ + -I$(TOP)/src/gallium/auxiliary diff --git a/mesalib/src/mesa/state_tracker/st_cb_flush.c b/mesalib/src/mesa/state_tracker/st_cb_flush.c index 31189f360..35ab00f6d 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_flush.c +++ b/mesalib/src/mesa/state_tracker/st_cb_flush.c @@ -1,164 +1,165 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * 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, sub license, 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 (including the - * next paragraph) 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 NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. - * - **************************************************************************/ - - /* - * Authors: - * Keith Whitwell - * Brian Paul - */ - -#include "main/glheader.h" -#include "main/macros.h" -#include "main/context.h" -#include "st_context.h" -#include "st_cb_bitmap.h" -#include "st_cb_flush.h" -#include "st_cb_clear.h" -#include "st_cb_fbo.h" -#include "st_manager.h" -#include "pipe/p_context.h" -#include "pipe/p_defines.h" -#include "pipe/p_screen.h" -#include "util/u_gen_mipmap.h" -#include "util/u_blit.h" - - -/** Check if we have a front color buffer and if it's been drawn to. */ -static INLINE GLboolean -is_front_buffer_dirty(struct st_context *st) -{ - struct gl_framebuffer *fb = st->ctx->DrawBuffer; - struct st_renderbuffer *strb - = st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer); - return strb && strb->defined; -} - - -/** - * Tell the screen to display the front color buffer on-screen. - */ -static void -display_front_buffer(struct st_context *st) -{ - struct gl_framebuffer *fb = st->ctx->DrawBuffer; - struct st_renderbuffer *strb - = st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer); - - if (strb) { - /* Hook for copying "fake" frontbuffer if necessary: - */ - st_manager_flush_frontbuffer(st); - } -} - - -void st_flush( struct st_context *st, uint pipeFlushFlags, - struct pipe_fence_handle **fence ) -{ - FLUSH_CURRENT(st->ctx, 0); - - /* Release any vertex buffers that might potentially be accessed in - * successive frames: - */ - st_flush_bitmap(st); - st_flush_clear(st); - util_blit_flush(st->blit); - util_gen_mipmap_flush(st->gen_mipmap); - - st->pipe->flush( st->pipe, pipeFlushFlags, fence ); -} - - -/** - * Flush, and wait for completion. - */ -void st_finish( struct st_context *st ) -{ - struct pipe_fence_handle *fence = NULL; - - st_flush(st, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence); - - if(fence) { - st->pipe->screen->fence_finish(st->pipe->screen, fence, 0); - st->pipe->screen->fence_reference(st->pipe->screen, &fence, NULL); - } -} - - - -/** - * Called via ctx->Driver.Flush() - */ -static void st_glFlush(struct gl_context *ctx) -{ - struct st_context *st = st_context(ctx); - - /* Don't call st_finish() here. It is not the state tracker's - * responsibilty to inject sleeps in the hope of avoiding buffer - * synchronization issues. Calling finish() here will just hide - * problems that need to be fixed elsewhere. - */ - st_flush(st, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); - - if (is_front_buffer_dirty(st)) { - display_front_buffer(st); - } -} - - -/** - * Called via ctx->Driver.Finish() - */ -static void st_glFinish(struct gl_context *ctx) -{ - struct st_context *st = st_context(ctx); - - st_finish(st); - - if (is_front_buffer_dirty(st)) { - display_front_buffer(st); - } -} - - -void st_init_flush_functions(struct dd_function_table *functions) -{ - functions->Flush = st_glFlush; - functions->Finish = st_glFinish; - - /* Windows opengl32.dll calls glFinish prior to every swapbuffers. - * This is unnecessary and degrades performance. Luckily we have some - * scope to work around this, as the externally-visible behaviour of - * Finish() is identical to Flush() in all cases - no differences in - * rendering or ReadPixels are visible if we opt not to wait here. - * - * Only set this up on windows to avoid suprise elsewhere. - */ -#ifdef PIPE_OS_WINDOWS - functions->Finish = st_glFlush; -#endif -} +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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, sub license, 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 (including the + * next paragraph) 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell + * Brian Paul + */ + +#include "main/glheader.h" +#include "main/macros.h" +#include "main/context.h" +#include "st_context.h" +#include "st_cb_bitmap.h" +#include "st_cb_flush.h" +#include "st_cb_clear.h" +#include "st_cb_fbo.h" +#include "st_manager.h" +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_screen.h" +#include "util/u_gen_mipmap.h" +#include "util/u_blit.h" + + +/** Check if we have a front color buffer and if it's been drawn to. */ +static INLINE GLboolean +is_front_buffer_dirty(struct st_context *st) +{ + struct gl_framebuffer *fb = st->ctx->DrawBuffer; + struct st_renderbuffer *strb + = st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer); + return strb && strb->defined; +} + + +/** + * Tell the screen to display the front color buffer on-screen. + */ +static void +display_front_buffer(struct st_context *st) +{ + struct gl_framebuffer *fb = st->ctx->DrawBuffer; + struct st_renderbuffer *strb + = st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer); + + if (strb) { + /* Hook for copying "fake" frontbuffer if necessary: + */ + st_manager_flush_frontbuffer(st); + } +} + + +void st_flush( struct st_context *st, uint pipeFlushFlags, + struct pipe_fence_handle **fence ) +{ + FLUSH_CURRENT(st->ctx, 0); + + /* Release any vertex buffers that might potentially be accessed in + * successive frames: + */ + st_flush_bitmap(st); + st_flush_clear(st); + util_blit_flush(st->blit); + util_gen_mipmap_flush(st->gen_mipmap); + + st->pipe->flush( st->pipe, pipeFlushFlags, fence ); +} + + +/** + * Flush, and wait for completion. + */ +void st_finish( struct st_context *st ) +{ + struct pipe_fence_handle *fence = NULL; + + st_flush(st, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence); + + if(fence) { + st->pipe->screen->fence_finish(st->pipe->screen, fence, 0, + PIPE_TIMEOUT_INFINITE); + st->pipe->screen->fence_reference(st->pipe->screen, &fence, NULL); + } +} + + + +/** + * Called via ctx->Driver.Flush() + */ +static void st_glFlush(struct gl_context *ctx) +{ + struct st_context *st = st_context(ctx); + + /* Don't call st_finish() here. It is not the state tracker's + * responsibilty to inject sleeps in the hope of avoiding buffer + * synchronization issues. Calling finish() here will just hide + * problems that need to be fixed elsewhere. + */ + st_flush(st, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); + + if (is_front_buffer_dirty(st)) { + display_front_buffer(st); + } +} + + +/** + * Called via ctx->Driver.Finish() + */ +static void st_glFinish(struct gl_context *ctx) +{ + struct st_context *st = st_context(ctx); + + st_finish(st); + + if (is_front_buffer_dirty(st)) { + display_front_buffer(st); + } +} + + +void st_init_flush_functions(struct dd_function_table *functions) +{ + functions->Flush = st_glFlush; + functions->Finish = st_glFinish; + + /* Windows opengl32.dll calls glFinish prior to every swapbuffers. + * This is unnecessary and degrades performance. Luckily we have some + * scope to work around this, as the externally-visible behaviour of + * Finish() is identical to Flush() in all cases - no differences in + * rendering or ReadPixels are visible if we opt not to wait here. + * + * Only set this up on windows to avoid suprise elsewhere. + */ +#ifdef PIPE_OS_WINDOWS + functions->Finish = st_glFlush; +#endif +} diff --git a/mesalib/src/mesa/state_tracker/st_cb_syncobj.c b/mesalib/src/mesa/state_tracker/st_cb_syncobj.c new file mode 100644 index 000000000..85aad08cc --- /dev/null +++ b/mesalib/src/mesa/state_tracker/st_cb_syncobj.c @@ -0,0 +1,122 @@ +/************************************************************************** + * + * Copyright 2011 Marek Olšák + * 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, sub license, 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 (including the + * next paragraph) 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL AUTHORS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + + /* + * Authors: + * Marek Olšák + */ + +#include "main/glheader.h" +#include "main/macros.h" +#include "pipe/p_context.h" +#include "pipe/p_screen.h" +#include "st_context.h" +#include "st_cb_syncobj.h" + +struct st_sync_object { + struct gl_sync_object b; + + struct pipe_fence_handle *fence; +}; + + +static struct gl_sync_object * st_new_sync_object(struct gl_context *ctx, + GLenum type) +{ + if (type == GL_SYNC_FENCE) + return (struct gl_sync_object*)CALLOC_STRUCT(st_sync_object); + else + return NULL; +} + +static void st_delete_sync_object(struct gl_context *ctx, + struct gl_sync_object *obj) +{ + struct pipe_screen *screen = st_context(ctx)->pipe->screen; + struct st_sync_object *so = (struct st_sync_object*)obj; + + screen->fence_reference(screen, &so->fence, NULL); + FREE(so); +} + +static void st_fence_sync(struct gl_context *ctx, struct gl_sync_object *obj, + GLenum condition, GLbitfield flags) +{ + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_sync_object *so = (struct st_sync_object*)obj; + + assert(condition == GL_SYNC_GPU_COMMANDS_COMPLETE && flags == 0); + assert(so->fence == NULL); + + pipe->flush(pipe, 0, &so->fence); +} + +static void st_check_sync(struct gl_context *ctx, struct gl_sync_object *obj) +{ + struct pipe_screen *screen = st_context(ctx)->pipe->screen; + struct st_sync_object *so = (struct st_sync_object*)obj; + + if (so->fence && screen->fence_signalled(screen, so->fence, 0) == 0) { + screen->fence_reference(screen, &so->fence, NULL); + so->b.StatusFlag = GL_TRUE; + } +} + +static void st_client_wait_sync(struct gl_context *ctx, + struct gl_sync_object *obj, + GLbitfield flags, GLuint64 timeout) +{ + struct pipe_screen *screen = st_context(ctx)->pipe->screen; + struct st_sync_object *so = (struct st_sync_object*)obj; + + /* We don't care about GL_SYNC_FLUSH_COMMANDS_BIT, because flush is + * already called when creating a fence. */ + + if (so->fence && + screen->fence_finish(screen, so->fence, 0, timeout) == 0) { + screen->fence_reference(screen, &so->fence, NULL); + so->b.StatusFlag = GL_TRUE; + } +} + +static void st_server_wait_sync(struct gl_context *ctx, + struct gl_sync_object *obj, + GLbitfield flags, GLuint64 timeout) +{ + /* NO-OP. + * Neither Gallium nor DRM interfaces support blocking on the GPU. */ +} + +void st_init_syncobj_functions(struct dd_function_table *functions) +{ + functions->NewSyncObject = st_new_sync_object; + functions->FenceSync = st_fence_sync; + functions->DeleteSyncObject = st_delete_sync_object; + functions->CheckSync = st_check_sync; + functions->ClientWaitSync = st_client_wait_sync; + functions->ServerWaitSync = st_server_wait_sync; +} diff --git a/mesalib/src/mesa/state_tracker/st_cb_syncobj.h b/mesalib/src/mesa/state_tracker/st_cb_syncobj.h new file mode 100644 index 000000000..c25468478 --- /dev/null +++ b/mesalib/src/mesa/state_tracker/st_cb_syncobj.h @@ -0,0 +1,38 @@ +/************************************************************************** + * + * Copyright 2011 Marek Olšák + * 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, sub license, 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 (including the + * next paragraph) 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL AUTHORS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef ST_CB_SYNCOBJ_H +#define ST_CB_SYNCOBJ_H + + +struct dd_function_table; + +extern void +st_init_syncobj_functions(struct dd_function_table *functions); + + +#endif /* ST_CB_SYNCOBJ_H */ diff --git a/mesalib/src/mesa/state_tracker/st_context.c b/mesalib/src/mesa/state_tracker/st_context.c index 7a19f35bb..60972e07d 100644 --- a/mesalib/src/mesa/state_tracker/st_context.c +++ b/mesalib/src/mesa/state_tracker/st_context.c @@ -51,6 +51,7 @@ #include "st_cb_texture.h" #include "st_cb_xformfb.h" #include "st_cb_flush.h" +#include "st_cb_syncobj.h" #include "st_cb_strings.h" #include "st_cb_viewport.h" #include "st_atom.h" @@ -292,6 +293,7 @@ void st_init_driver_functions(struct dd_function_table *functions) st_init_viewport_functions(functions); st_init_xformfb_functions(functions); + st_init_syncobj_functions(functions); functions->UpdateState = st_invalidate_state; } diff --git a/mesalib/src/mesa/state_tracker/st_draw.c b/mesalib/src/mesa/state_tracker/st_draw.c index d6e67b7fb..40afa4362 100644 --- a/mesalib/src/mesa/state_tracker/st_draw.c +++ b/mesalib/src/mesa/state_tracker/st_draw.c @@ -429,7 +429,7 @@ setup_non_interleaved_attribs(struct gl_context *ctx, vbuffer[attr].buffer_offset = 0; /* Track user vertex buffers. */ - pipe_resource_reference(&st->user_vb[attr], vbuffer->buffer); + pipe_resource_reference(&st->user_vb[attr], vbuffer[attr].buffer); st->user_vb_stride[attr] = stride; st->num_user_vbs = MAX2(st->num_user_vbs, attr+1); } @@ -632,10 +632,8 @@ st_draw_vbo(struct gl_context *ctx, struct pipe_index_buffer ibuffer; struct pipe_draw_info info; unsigned i, num_instances = 1; - GLboolean new_array = GL_TRUE; - /* Fix this (Bug 34378): GLboolean new_array = - st->dirty.st && (st->dirty.mesa & (_NEW_ARRAY | _NEW_PROGRAM)) != 0;*/ + st->dirty.st && (st->dirty.mesa & (_NEW_ARRAY | _NEW_PROGRAM)) != 0; /* Mesa core state should have been validated already */ assert(ctx->NewState == 0x0); diff --git a/mesalib/src/mesa/state_tracker/st_extensions.c b/mesalib/src/mesa/state_tracker/st_extensions.c index 6bbf68acc..aaa1658f4 100644 --- a/mesalib/src/mesa/state_tracker/st_extensions.c +++ b/mesalib/src/mesa/state_tracker/st_extensions.c @@ -432,6 +432,27 @@ void st_init_extensions(struct st_context *st) ctx->Extensions.ARB_texture_compression_rgtc = GL_TRUE; } + if (screen->is_format_supported(screen, PIPE_FORMAT_LATC1_UNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW, 0) && + screen->is_format_supported(screen, PIPE_FORMAT_LATC1_SNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW, 0) && + screen->is_format_supported(screen, PIPE_FORMAT_LATC2_UNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW, 0) && + screen->is_format_supported(screen, PIPE_FORMAT_LATC2_SNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW, 0)) { + ctx->Extensions.EXT_texture_compression_latc = GL_TRUE; + } + + if (screen->is_format_supported(screen, PIPE_FORMAT_LATC2_UNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW, 0)) { + ctx->Extensions.ATI_texture_compression_3dc = GL_TRUE; + } + /* ycbcr support */ if (screen->is_format_supported(screen, PIPE_FORMAT_UYVY, PIPE_TEXTURE_2D, 0, @@ -497,4 +518,8 @@ void st_init_extensions(struct st_context *st) if (screen->get_param(screen, PIPE_CAP_VERTEX_ELEMENT_INSTANCE_DIVISOR)) { ctx->Extensions.ARB_instanced_arrays = GL_TRUE; } + + if (screen->fence_finish) { + ctx->Extensions.ARB_sync = GL_TRUE; + } } diff --git a/mesalib/src/mesa/state_tracker/st_format.c b/mesalib/src/mesa/state_tracker/st_format.c index 22a1450cf..6b89bae7d 100644 --- a/mesalib/src/mesa/state_tracker/st_format.c +++ b/mesalib/src/mesa/state_tracker/st_format.c @@ -249,6 +249,16 @@ st_mesa_format_to_pipe_format(gl_format mesaFormat) return PIPE_FORMAT_RGTC2_UNORM; case MESA_FORMAT_SIGNED_RG_RGTC2: return PIPE_FORMAT_RGTC2_SNORM; + + case MESA_FORMAT_L_LATC1: + return PIPE_FORMAT_LATC1_UNORM; + case MESA_FORMAT_SIGNED_L_LATC1: + return PIPE_FORMAT_LATC1_SNORM; + case MESA_FORMAT_LA_LATC2: + return PIPE_FORMAT_LATC2_UNORM; + case MESA_FORMAT_SIGNED_LA_LATC2: + return PIPE_FORMAT_LATC2_SNORM; + default: assert(0); return PIPE_FORMAT_NONE; @@ -397,6 +407,15 @@ st_pipe_format_to_mesa_format(enum pipe_format format) case PIPE_FORMAT_RGTC2_SNORM: return MESA_FORMAT_SIGNED_RG_RGTC2; + case PIPE_FORMAT_LATC1_UNORM: + return MESA_FORMAT_L_LATC1; + case PIPE_FORMAT_LATC1_SNORM: + return MESA_FORMAT_SIGNED_L_LATC1; + case PIPE_FORMAT_LATC2_UNORM: + return MESA_FORMAT_LA_LATC2; + case PIPE_FORMAT_LATC2_SNORM: + return MESA_FORMAT_SIGNED_LA_LATC2; + default: assert(0); return MESA_FORMAT_NONE; @@ -612,7 +631,6 @@ st_choose_format(struct pipe_screen *screen, GLenum internalFormat, case GL_LUMINANCE: case GL_LUMINANCE4: case GL_LUMINANCE8: - case GL_COMPRESSED_LUMINANCE: if (screen->is_format_supported( screen, PIPE_FORMAT_L8_UNORM, target, sample_count, bindings, geom_flags )) return PIPE_FORMAT_L8_UNORM; @@ -630,7 +648,6 @@ st_choose_format(struct pipe_screen *screen, GLenum internalFormat, case GL_LUMINANCE_ALPHA: case GL_LUMINANCE6_ALPHA2: case GL_LUMINANCE8_ALPHA8: - case GL_COMPRESSED_LUMINANCE_ALPHA: if (screen->is_format_supported( screen, PIPE_FORMAT_L8A8_UNORM, target, sample_count, bindings, geom_flags )) return PIPE_FORMAT_L8A8_UNORM; @@ -901,6 +918,39 @@ st_choose_format(struct pipe_screen *screen, GLenum internalFormat, return PIPE_FORMAT_RGTC2_SNORM; return PIPE_FORMAT_NONE; + case GL_COMPRESSED_LUMINANCE: + case GL_COMPRESSED_LUMINANCE_LATC1_EXT: + if (screen->is_format_supported(screen, PIPE_FORMAT_LATC1_UNORM, target, + sample_count, bindings, geom_flags)) + return PIPE_FORMAT_LATC1_UNORM; + if (screen->is_format_supported(screen, PIPE_FORMAT_L8_UNORM, target, + sample_count, bindings, geom_flags)) + return PIPE_FORMAT_L8_UNORM; + return PIPE_FORMAT_NONE; + + case GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT: + if (screen->is_format_supported(screen, PIPE_FORMAT_LATC1_SNORM, target, + sample_count, bindings, geom_flags)) + return PIPE_FORMAT_LATC1_SNORM; + return PIPE_FORMAT_NONE; + + case GL_COMPRESSED_LUMINANCE_ALPHA: + case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: + case GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI: + if (screen->is_format_supported(screen, PIPE_FORMAT_LATC2_UNORM, target, + sample_count, bindings, geom_flags)) + return PIPE_FORMAT_LATC2_UNORM; + if (screen->is_format_supported(screen, PIPE_FORMAT_L8A8_UNORM, target, + sample_count, bindings, geom_flags)) + return PIPE_FORMAT_L8A8_UNORM; + return PIPE_FORMAT_NONE; + + case GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT: + if (screen->is_format_supported(screen, PIPE_FORMAT_LATC2_SNORM, target, + sample_count, bindings, geom_flags)) + return PIPE_FORMAT_LATC2_SNORM; + return PIPE_FORMAT_NONE; + /* signed/unsigned integer formats. * XXX Mesa only has formats for RGBA signed/unsigned integer formats. * If/when new formats are added this code should be updated. diff --git a/mesalib/src/mesa/state_tracker/st_gen_mipmap.c b/mesalib/src/mesa/state_tracker/st_gen_mipmap.c index a12a32e11..899161e78 100644 --- a/mesalib/src/mesa/state_tracker/st_gen_mipmap.c +++ b/mesalib/src/mesa/state_tracker/st_gen_mipmap.c @@ -204,12 +204,10 @@ fallback_generate_mipmap(struct gl_context *ctx, GLenum target, _mesa_is_format_compressed(texObj->Image[face][baseLevel]->TexFormat); if (compressed) { - if (texObj->Image[face][baseLevel]->TexFormat == MESA_FORMAT_SIGNED_RED_RGTC1 || - texObj->Image[face][baseLevel]->TexFormat == MESA_FORMAT_SIGNED_RG_RGTC2) - datatype = GL_FLOAT; - else - datatype = GL_UNSIGNED_BYTE; - + GLenum type = + _mesa_get_format_datatype(texObj->Image[face][baseLevel]->TexFormat); + + datatype = type == GL_UNSIGNED_NORMALIZED ? GL_UNSIGNED_BYTE : GL_FLOAT; comps = 4; } else { diff --git a/mesalib/src/mesa/swrast/s_texfilter.c b/mesalib/src/mesa/swrast/s_texfilter.c index 503f5b732..42785400c 100644 --- a/mesalib/src/mesa/swrast/s_texfilter.c +++ b/mesalib/src/mesa/swrast/s_texfilter.c @@ -1,3311 +1,3314 @@ -/* - * Mesa 3-D graphics library - * Version: 7.3 - * - * Copyright (C) 1999-2008 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 "main/glheader.h" -#include "main/context.h" -#include "main/colormac.h" -#include "main/imports.h" - -#include "s_context.h" -#include "s_texfilter.h" - - -/* - * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes - * see 1-pixel bands of improperly weighted linear-filtered textures. - * The tests/texwrap.c demo is a good test. - * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0. - * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x). - */ -#define FRAC(f) ((f) - IFLOOR(f)) - - - -/** - * Linear interpolation macro - */ -#define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) ) - - -/** - * Do 2D/biliner interpolation of float values. - * v00, v10, v01 and v11 are typically four texture samples in a square/box. - * a and b are the horizontal and vertical interpolants. - * It's important that this function is inlined when compiled with - * optimization! If we find that's not true on some systems, convert - * to a macro. - */ -static INLINE GLfloat -lerp_2d(GLfloat a, GLfloat b, - GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11) -{ - const GLfloat temp0 = LERP(a, v00, v10); - const GLfloat temp1 = LERP(a, v01, v11); - return LERP(b, temp0, temp1); -} - - -/** - * Do 3D/trilinear interpolation of float values. - * \sa lerp_2d - */ -static INLINE GLfloat -lerp_3d(GLfloat a, GLfloat b, GLfloat c, - GLfloat v000, GLfloat v100, GLfloat v010, GLfloat v110, - GLfloat v001, GLfloat v101, GLfloat v011, GLfloat v111) -{ - const GLfloat temp00 = LERP(a, v000, v100); - const GLfloat temp10 = LERP(a, v010, v110); - const GLfloat temp01 = LERP(a, v001, v101); - const GLfloat temp11 = LERP(a, v011, v111); - const GLfloat temp0 = LERP(b, temp00, temp10); - const GLfloat temp1 = LERP(b, temp01, temp11); - return LERP(c, temp0, temp1); -} - - -/** - * Do linear interpolation of colors. - */ -static INLINE void -lerp_rgba(GLfloat result[4], GLfloat t, const GLfloat a[4], const GLfloat b[4]) -{ - result[0] = LERP(t, a[0], b[0]); - result[1] = LERP(t, a[1], b[1]); - result[2] = LERP(t, a[2], b[2]); - result[3] = LERP(t, a[3], b[3]); -} - - -/** - * Do bilinear interpolation of colors. - */ -static INLINE void -lerp_rgba_2d(GLfloat result[4], GLfloat a, GLfloat b, - const GLfloat t00[4], const GLfloat t10[4], - const GLfloat t01[4], const GLfloat t11[4]) -{ - result[0] = lerp_2d(a, b, t00[0], t10[0], t01[0], t11[0]); - result[1] = lerp_2d(a, b, t00[1], t10[1], t01[1], t11[1]); - result[2] = lerp_2d(a, b, t00[2], t10[2], t01[2], t11[2]); - result[3] = lerp_2d(a, b, t00[3], t10[3], t01[3], t11[3]); -} - - -/** - * Do trilinear interpolation of colors. - */ -static INLINE void -lerp_rgba_3d(GLfloat result[4], GLfloat a, GLfloat b, GLfloat c, - const GLfloat t000[4], const GLfloat t100[4], - const GLfloat t010[4], const GLfloat t110[4], - const GLfloat t001[4], const GLfloat t101[4], - const GLfloat t011[4], const GLfloat t111[4]) -{ - GLuint k; - /* compiler should unroll these short loops */ - for (k = 0; k < 4; k++) { - result[k] = lerp_3d(a, b, c, t000[k], t100[k], t010[k], t110[k], - t001[k], t101[k], t011[k], t111[k]); - } -} - - -/** - * Used for GL_REPEAT wrap mode. Using A % B doesn't produce the - * right results for A<0. Casting to A to be unsigned only works if B - * is a power of two. Adding a bias to A (which is a multiple of B) - * avoids the problems with A < 0 (for reasonable A) without using a - * conditional. - */ -#define REMAINDER(A, B) (((A) + (B) * 1024) % (B)) - - -/** - * Used to compute texel locations for linear sampling. - * Input: - * wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER - * s = texcoord in [0,1] - * size = width (or height or depth) of texture - * Output: - * i0, i1 = returns two nearest texel indexes - * weight = returns blend factor between texels - */ -static INLINE void -linear_texel_locations(GLenum wrapMode, - const struct gl_texture_image *img, - GLint size, GLfloat s, - GLint *i0, GLint *i1, GLfloat *weight) -{ - GLfloat u; - switch (wrapMode) { - case GL_REPEAT: - u = s * size - 0.5F; - if (img->_IsPowerOfTwo) { - *i0 = IFLOOR(u) & (size - 1); - *i1 = (*i0 + 1) & (size - 1); - } - else { - *i0 = REMAINDER(IFLOOR(u), size); - *i1 = REMAINDER(*i0 + 1, size); - } - break; - case GL_CLAMP_TO_EDGE: - if (s <= 0.0F) - u = 0.0F; - else if (s >= 1.0F) - u = (GLfloat) size; - else - u = s * size; - u -= 0.5F; - *i0 = IFLOOR(u); - *i1 = *i0 + 1; - if (*i0 < 0) - *i0 = 0; - if (*i1 >= (GLint) size) - *i1 = size - 1; - break; - case GL_CLAMP_TO_BORDER: - { - const GLfloat min = -1.0F / (2.0F * size); - const GLfloat max = 1.0F - min; - if (s <= min) - u = min * size; - else if (s >= max) - u = max * size; - else - u = s * size; - u -= 0.5F; - *i0 = IFLOOR(u); - *i1 = *i0 + 1; - } - break; - case GL_MIRRORED_REPEAT: - { - const GLint flr = IFLOOR(s); - if (flr & 1) - u = 1.0F - (s - (GLfloat) flr); - else - u = s - (GLfloat) flr; - u = (u * size) - 0.5F; - *i0 = IFLOOR(u); - *i1 = *i0 + 1; - if (*i0 < 0) - *i0 = 0; - if (*i1 >= (GLint) size) - *i1 = size - 1; - } - break; - case GL_MIRROR_CLAMP_EXT: - u = FABSF(s); - if (u >= 1.0F) - u = (GLfloat) size; - else - u *= size; - u -= 0.5F; - *i0 = IFLOOR(u); - *i1 = *i0 + 1; - break; - case GL_MIRROR_CLAMP_TO_EDGE_EXT: - u = FABSF(s); - if (u >= 1.0F) - u = (GLfloat) size; - else - u *= size; - u -= 0.5F; - *i0 = IFLOOR(u); - *i1 = *i0 + 1; - if (*i0 < 0) - *i0 = 0; - if (*i1 >= (GLint) size) - *i1 = size - 1; - break; - case GL_MIRROR_CLAMP_TO_BORDER_EXT: - { - const GLfloat min = -1.0F / (2.0F * size); - const GLfloat max = 1.0F - min; - u = FABSF(s); - if (u <= min) - u = min * size; - else if (u >= max) - u = max * size; - else - u *= size; - u -= 0.5F; - *i0 = IFLOOR(u); - *i1 = *i0 + 1; - } - break; - case GL_CLAMP: - if (s <= 0.0F) - u = 0.0F; - else if (s >= 1.0F) - u = (GLfloat) size; - else - u = s * size; - u -= 0.5F; - *i0 = IFLOOR(u); - *i1 = *i0 + 1; - break; - default: - _mesa_problem(NULL, "Bad wrap mode"); - u = 0.0F; - } - *weight = FRAC(u); -} - - -/** - * Used to compute texel location for nearest sampling. - */ -static INLINE GLint -nearest_texel_location(GLenum wrapMode, - const struct gl_texture_image *img, - GLint size, GLfloat s) -{ - GLint i; - - switch (wrapMode) { - case GL_REPEAT: - /* s limited to [0,1) */ - /* i limited to [0,size-1] */ - i = IFLOOR(s * size); - if (img->_IsPowerOfTwo) - i &= (size - 1); - else - i = REMAINDER(i, size); - return i; - case GL_CLAMP_TO_EDGE: - { - /* s limited to [min,max] */ - /* i limited to [0, size-1] */ - const GLfloat min = 1.0F / (2.0F * size); - const GLfloat max = 1.0F - min; - if (s < min) - i = 0; - else if (s > max) - i = size - 1; - else - i = IFLOOR(s * size); - } - return i; - case GL_CLAMP_TO_BORDER: - { - /* s limited to [min,max] */ - /* i limited to [-1, size] */ - const GLfloat min = -1.0F / (2.0F * size); - const GLfloat max = 1.0F - min; - if (s <= min) - i = -1; - else if (s >= max) - i = size; - else - i = IFLOOR(s * size); - } - return i; - case GL_MIRRORED_REPEAT: - { - const GLfloat min = 1.0F / (2.0F * size); - const GLfloat max = 1.0F - min; - const GLint flr = IFLOOR(s); - GLfloat u; - if (flr & 1) - u = 1.0F - (s - (GLfloat) flr); - else - u = s - (GLfloat) flr; - if (u < min) - i = 0; - else if (u > max) - i = size - 1; - else - i = IFLOOR(u * size); - } - return i; - case GL_MIRROR_CLAMP_EXT: - { - /* s limited to [0,1] */ - /* i limited to [0,size-1] */ - const GLfloat u = FABSF(s); - if (u <= 0.0F) - i = 0; - else if (u >= 1.0F) - i = size - 1; - else - i = IFLOOR(u * size); - } - return i; - case GL_MIRROR_CLAMP_TO_EDGE_EXT: - { - /* s limited to [min,max] */ - /* i limited to [0, size-1] */ - const GLfloat min = 1.0F / (2.0F * size); - const GLfloat max = 1.0F - min; - const GLfloat u = FABSF(s); - if (u < min) - i = 0; - else if (u > max) - i = size - 1; - else - i = IFLOOR(u * size); - } - return i; - case GL_MIRROR_CLAMP_TO_BORDER_EXT: - { - /* s limited to [min,max] */ - /* i limited to [0, size-1] */ - const GLfloat min = -1.0F / (2.0F * size); - const GLfloat max = 1.0F - min; - const GLfloat u = FABSF(s); - if (u < min) - i = -1; - else if (u > max) - i = size; - else - i = IFLOOR(u * size); - } - return i; - case GL_CLAMP: - /* s limited to [0,1] */ - /* i limited to [0,size-1] */ - if (s <= 0.0F) - i = 0; - else if (s >= 1.0F) - i = size - 1; - else - i = IFLOOR(s * size); - return i; - default: - _mesa_problem(NULL, "Bad wrap mode"); - return 0; - } -} - - -/* Power of two image sizes only */ -static INLINE void -linear_repeat_texel_location(GLuint size, GLfloat s, - GLint *i0, GLint *i1, GLfloat *weight) -{ - GLfloat u = s * size - 0.5F; - *i0 = IFLOOR(u) & (size - 1); - *i1 = (*i0 + 1) & (size - 1); - *weight = FRAC(u); -} - - -/** - * Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode. - */ -static INLINE GLint -clamp_rect_coord_nearest(GLenum wrapMode, GLfloat coord, GLint max) -{ - switch (wrapMode) { - case GL_CLAMP: - return IFLOOR( CLAMP(coord, 0.0F, max - 1) ); - case GL_CLAMP_TO_EDGE: - return IFLOOR( CLAMP(coord, 0.5F, max - 0.5F) ); - case GL_CLAMP_TO_BORDER: - return IFLOOR( CLAMP(coord, -0.5F, max + 0.5F) ); - default: - _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_nearest"); - return 0; - } -} - - -/** - * As above, but GL_LINEAR filtering. - */ -static INLINE void -clamp_rect_coord_linear(GLenum wrapMode, GLfloat coord, GLint max, - GLint *i0out, GLint *i1out, GLfloat *weight) -{ - GLfloat fcol; - GLint i0, i1; - switch (wrapMode) { - case GL_CLAMP: - /* Not exactly what the spec says, but it matches NVIDIA output */ - fcol = CLAMP(coord - 0.5F, 0.0F, max - 1); - i0 = IFLOOR(fcol); - i1 = i0 + 1; - break; - case GL_CLAMP_TO_EDGE: - fcol = CLAMP(coord, 0.5F, max - 0.5F); - fcol -= 0.5F; - i0 = IFLOOR(fcol); - i1 = i0 + 1; - if (i1 > max - 1) - i1 = max - 1; - break; - case GL_CLAMP_TO_BORDER: - fcol = CLAMP(coord, -0.5F, max + 0.5F); - fcol -= 0.5F; - i0 = IFLOOR(fcol); - i1 = i0 + 1; - break; - default: - _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_linear"); - i0 = i1 = 0; - fcol = 0.0F; - } - *i0out = i0; - *i1out = i1; - *weight = FRAC(fcol); -} - - -/** - * Compute slice/image to use for 1D or 2D array texture. - */ -static INLINE GLint -tex_array_slice(GLfloat coord, GLsizei size) -{ - GLint slice = IFLOOR(coord + 0.5f); - slice = CLAMP(slice, 0, size - 1); - return slice; -} - - -/** - * Compute nearest integer texcoords for given texobj and coordinate. - * NOTE: only used for depth texture sampling. - */ -static INLINE void -nearest_texcoord(const struct gl_texture_object *texObj, - GLuint level, - const GLfloat texcoord[4], - GLint *i, GLint *j, GLint *k) -{ - const struct gl_texture_image *img = texObj->Image[0][level]; - const GLint width = img->Width; - const GLint height = img->Height; - const GLint depth = img->Depth; - - switch (texObj->Target) { - case GL_TEXTURE_RECTANGLE_ARB: - *i = clamp_rect_coord_nearest(texObj->WrapS, texcoord[0], width); - *j = clamp_rect_coord_nearest(texObj->WrapT, texcoord[1], height); - *k = 0; - break; - case GL_TEXTURE_1D: - *i = nearest_texel_location(texObj->WrapS, img, width, texcoord[0]); - *j = 0; - *k = 0; - break; - case GL_TEXTURE_2D: - *i = nearest_texel_location(texObj->WrapS, img, width, texcoord[0]); - *j = nearest_texel_location(texObj->WrapT, img, height, texcoord[1]); - *k = 0; - break; - case GL_TEXTURE_1D_ARRAY_EXT: - *i = nearest_texel_location(texObj->WrapS, img, width, texcoord[0]); - *j = tex_array_slice(texcoord[1], height); - *k = 0; - break; - case GL_TEXTURE_2D_ARRAY_EXT: - *i = nearest_texel_location(texObj->WrapS, img, width, texcoord[0]); - *j = nearest_texel_location(texObj->WrapT, img, height, texcoord[1]); - *k = tex_array_slice(texcoord[2], depth); - break; - default: - *i = *j = *k = 0; - } -} - - -/** - * Compute linear integer texcoords for given texobj and coordinate. - * NOTE: only used for depth texture sampling. - */ -static INLINE void -linear_texcoord(const struct gl_texture_object *texObj, - GLuint level, - const GLfloat texcoord[4], - GLint *i0, GLint *i1, GLint *j0, GLint *j1, GLint *slice, - GLfloat *wi, GLfloat *wj) -{ - const struct gl_texture_image *img = texObj->Image[0][level]; - const GLint width = img->Width; - const GLint height = img->Height; - const GLint depth = img->Depth; - - switch (texObj->Target) { - case GL_TEXTURE_RECTANGLE_ARB: - clamp_rect_coord_linear(texObj->WrapS, texcoord[0], - width, i0, i1, wi); - clamp_rect_coord_linear(texObj->WrapT, texcoord[1], - height, j0, j1, wj); - *slice = 0; - break; - - case GL_TEXTURE_1D: - case GL_TEXTURE_2D: - linear_texel_locations(texObj->WrapS, img, width, - texcoord[0], i0, i1, wi); - linear_texel_locations(texObj->WrapT, img, height, - texcoord[1], j0, j1, wj); - *slice = 0; - break; - - case GL_TEXTURE_1D_ARRAY_EXT: - linear_texel_locations(texObj->WrapS, img, width, - texcoord[0], i0, i1, wi); - *j0 = tex_array_slice(texcoord[1], height); - *j1 = *j0; - *slice = 0; - break; - - case GL_TEXTURE_2D_ARRAY_EXT: - linear_texel_locations(texObj->WrapS, img, width, - texcoord[0], i0, i1, wi); - linear_texel_locations(texObj->WrapT, img, height, - texcoord[1], j0, j1, wj); - *slice = tex_array_slice(texcoord[2], depth); - break; - - default: - *slice = 0; - } -} - - - -/** - * For linear interpolation between mipmap levels N and N+1, this function - * computes N. - */ -static INLINE GLint -linear_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda) -{ - if (lambda < 0.0F) - return tObj->BaseLevel; - else if (lambda > tObj->_MaxLambda) - return (GLint) (tObj->BaseLevel + tObj->_MaxLambda); - else - return (GLint) (tObj->BaseLevel + lambda); -} - - -/** - * Compute the nearest mipmap level to take texels from. - */ -static INLINE GLint -nearest_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda) -{ - GLfloat l; - GLint level; - if (lambda <= 0.5F) - l = 0.0F; - else if (lambda > tObj->_MaxLambda + 0.4999F) - l = tObj->_MaxLambda + 0.4999F; - else - l = lambda; - level = (GLint) (tObj->BaseLevel + l + 0.5F); - if (level > tObj->_MaxLevel) - level = tObj->_MaxLevel; - return level; -} - - - -/* - * Bitflags for texture border color sampling. - */ -#define I0BIT 1 -#define I1BIT 2 -#define J0BIT 4 -#define J1BIT 8 -#define K0BIT 16 -#define K1BIT 32 - - - -/** - * The lambda[] array values are always monotonic. Either the whole span - * will be minified, magnified, or split between the two. This function - * determines the subranges in [0, n-1] that are to be minified or magnified. - */ -static INLINE void -compute_min_mag_ranges(const struct gl_texture_object *tObj, - GLuint n, const GLfloat lambda[], - GLuint *minStart, GLuint *minEnd, - GLuint *magStart, GLuint *magEnd) -{ - GLfloat minMagThresh; - - /* we shouldn't be here if minfilter == magfilter */ - ASSERT(tObj->MinFilter != tObj->MagFilter); - - /* This bit comes from the OpenGL spec: */ - if (tObj->MagFilter == GL_LINEAR - && (tObj->MinFilter == GL_NEAREST_MIPMAP_NEAREST || - tObj->MinFilter == GL_NEAREST_MIPMAP_LINEAR)) { - minMagThresh = 0.5F; - } - else { - minMagThresh = 0.0F; - } - -#if 0 - /* DEBUG CODE: Verify that lambda[] is monotonic. - * We can't really use this because the inaccuracy in the LOG2 function - * causes this test to fail, yet the resulting texturing is correct. - */ - if (n > 1) { - GLuint i; - printf("lambda delta = %g\n", lambda[0] - lambda[n-1]); - if (lambda[0] >= lambda[n-1]) { /* decreasing */ - for (i = 0; i < n - 1; i++) { - ASSERT((GLint) (lambda[i] * 10) >= (GLint) (lambda[i+1] * 10)); - } - } - else { /* increasing */ - for (i = 0; i < n - 1; i++) { - ASSERT((GLint) (lambda[i] * 10) <= (GLint) (lambda[i+1] * 10)); - } - } - } -#endif /* DEBUG */ - - if (lambda[0] <= minMagThresh && (n <= 1 || lambda[n-1] <= minMagThresh)) { - /* magnification for whole span */ - *magStart = 0; - *magEnd = n; - *minStart = *minEnd = 0; - } - else if (lambda[0] > minMagThresh && (n <=1 || lambda[n-1] > minMagThresh)) { - /* minification for whole span */ - *minStart = 0; - *minEnd = n; - *magStart = *magEnd = 0; - } - else { - /* a mix of minification and magnification */ - GLuint i; - if (lambda[0] > minMagThresh) { - /* start with minification */ - for (i = 1; i < n; i++) { - if (lambda[i] <= minMagThresh) - break; - } - *minStart = 0; - *minEnd = i; - *magStart = i; - *magEnd = n; - } - else { - /* start with magnification */ - for (i = 1; i < n; i++) { - if (lambda[i] > minMagThresh) - break; - } - *magStart = 0; - *magEnd = i; - *minStart = i; - *minEnd = n; - } - } - -#if 0 - /* Verify the min/mag Start/End values - * We don't use this either (see above) - */ - { - GLint i; - for (i = 0; i < n; i++) { - if (lambda[i] > minMagThresh) { - /* minification */ - ASSERT(i >= *minStart); - ASSERT(i < *minEnd); - } - else { - /* magnification */ - ASSERT(i >= *magStart); - ASSERT(i < *magEnd); - } - } - } -#endif -} - - -/** - * When we sample the border color, it must be interpreted according to - * the base texture format. Ex: if the texture base format it GL_ALPHA, - * we return (0,0,0,BorderAlpha). - */ -static INLINE void -get_border_color(const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - GLfloat rgba[4]) -{ - switch (img->_BaseFormat) { - case GL_RGB: - rgba[0] = tObj->BorderColor.f[0]; - rgba[1] = tObj->BorderColor.f[1]; - rgba[2] = tObj->BorderColor.f[2]; - rgba[3] = 1.0F; - break; - case GL_ALPHA: - rgba[0] = rgba[1] = rgba[2] = 0.0; - rgba[3] = tObj->BorderColor.f[3]; - break; - case GL_LUMINANCE: - rgba[0] = rgba[1] = rgba[2] = tObj->BorderColor.f[0]; - rgba[3] = 1.0; - break; - case GL_LUMINANCE_ALPHA: - rgba[0] = rgba[1] = rgba[2] = tObj->BorderColor.f[0]; - rgba[3] = tObj->BorderColor.f[3]; - break; - case GL_INTENSITY: - rgba[0] = rgba[1] = rgba[2] = rgba[3] = tObj->BorderColor.f[0]; - break; - default: - COPY_4V(rgba, tObj->BorderColor.f); - } -} - - -/**********************************************************************/ -/* 1-D Texture Sampling Functions */ -/**********************************************************************/ - -/** - * Return the texture sample for coordinate (s) using GL_NEAREST filter. - */ -static INLINE void -sample_1d_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], GLfloat rgba[4]) -{ - const GLint width = img->Width2; /* without border, power of two */ - GLint i; - i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); - /* skip over the border, if any */ - i += img->Border; - if (i < 0 || i >= (GLint) img->Width) { - /* Need this test for GL_CLAMP_TO_BORDER mode */ - get_border_color(tObj, img, rgba); - } - else { - img->FetchTexelf(img, i, 0, 0, rgba); - } -} - - -/** - * Return the texture sample for coordinate (s) using GL_LINEAR filter. - */ -static INLINE void -sample_1d_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], GLfloat rgba[4]) -{ - const GLint width = img->Width2; - GLint i0, i1; - GLbitfield useBorderColor = 0x0; - GLfloat a; - GLfloat t0[4], t1[4]; /* texels */ - - linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); - - if (img->Border) { - i0 += img->Border; - i1 += img->Border; - } - else { - if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; - if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; - } - - /* fetch texel colors */ - if (useBorderColor & I0BIT) { - get_border_color(tObj, img, t0); - } - else { - img->FetchTexelf(img, i0, 0, 0, t0); - } - if (useBorderColor & I1BIT) { - get_border_color(tObj, img, t1); - } - else { - img->FetchTexelf(img, i1, 0, 0, t1); - } - - lerp_rgba(rgba, a, t0, t1); -} - - -static void -sample_1d_nearest_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_1d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); - } -} - - -static void -sample_1d_linear_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_1d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); - } -} - - -static void -sample_1d_nearest_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; - const GLfloat f = FRAC(lambda[i]); - sample_1d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_1d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -static void -sample_1d_linear_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; - const GLfloat f = FRAC(lambda[i]); - sample_1d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_1d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -/** Sample 1D texture, nearest filtering for both min/magnification */ -static void -sample_nearest_1d( struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4] ) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_1d_nearest(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 1D texture, linear filtering for both min/magnification */ -static void -sample_linear_1d( struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4] ) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_1d_linear(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 1D texture, using lambda to choose between min/magnification */ -static void -sample_lambda_1d( struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4] ) -{ - GLuint minStart, minEnd; /* texels with minification */ - GLuint magStart, magEnd; /* texels with magnification */ - GLuint i; - - ASSERT(lambda != NULL); - compute_min_mag_ranges(tObj, n, lambda, - &minStart, &minEnd, &magStart, &magEnd); - - if (minStart < minEnd) { - /* do the minified texels */ - const GLuint m = minEnd - minStart; - switch (tObj->MinFilter) { - case GL_NEAREST: - for (i = minStart; i < minEnd; i++) - sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = minStart; i < minEnd; i++) - sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_NEAREST_MIPMAP_NEAREST: - sample_1d_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_NEAREST: - sample_1d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_NEAREST_MIPMAP_LINEAR: - sample_1d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_LINEAR: - sample_1d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - default: - _mesa_problem(ctx, "Bad min filter in sample_1d_texture"); - return; - } - } - - if (magStart < magEnd) { - /* do the magnified texels */ - switch (tObj->MagFilter) { - case GL_NEAREST: - for (i = magStart; i < magEnd; i++) - sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = magStart; i < magEnd; i++) - sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - default: - _mesa_problem(ctx, "Bad mag filter in sample_1d_texture"); - return; - } - } -} - - -/**********************************************************************/ -/* 2-D Texture Sampling Functions */ -/**********************************************************************/ - - -/** - * Return the texture sample for coordinate (s,t) using GL_NEAREST filter. - */ -static INLINE void -sample_2d_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[]) -{ - const GLint width = img->Width2; /* without border, power of two */ - const GLint height = img->Height2; /* without border, power of two */ - GLint i, j; - (void) ctx; - - i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); - j = nearest_texel_location(tObj->WrapT, img, height, texcoord[1]); - - /* skip over the border, if any */ - i += img->Border; - j += img->Border; - - if (i < 0 || i >= (GLint) img->Width || j < 0 || j >= (GLint) img->Height) { - /* Need this test for GL_CLAMP_TO_BORDER mode */ - get_border_color(tObj, img, rgba); - } - else { - img->FetchTexelf(img, i, j, 0, rgba); - } -} - - -/** - * Return the texture sample for coordinate (s,t) using GL_LINEAR filter. - * New sampling code contributed by Lynn Quam . - */ -static INLINE void -sample_2d_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[]) -{ - const GLint width = img->Width2; - const GLint height = img->Height2; - GLint i0, j0, i1, j1; - GLbitfield useBorderColor = 0x0; - GLfloat a, b; - GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */ - - linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); - linear_texel_locations(tObj->WrapT, img, height, texcoord[1], &j0, &j1, &b); - - if (img->Border) { - i0 += img->Border; - i1 += img->Border; - j0 += img->Border; - j1 += img->Border; - } - else { - if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; - if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; - if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; - if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; - } - - /* fetch four texel colors */ - if (useBorderColor & (I0BIT | J0BIT)) { - get_border_color(tObj, img, t00); - } - else { - img->FetchTexelf(img, i0, j0, 0, t00); - } - if (useBorderColor & (I1BIT | J0BIT)) { - get_border_color(tObj, img, t10); - } - else { - img->FetchTexelf(img, i1, j0, 0, t10); - } - if (useBorderColor & (I0BIT | J1BIT)) { - get_border_color(tObj, img, t01); - } - else { - img->FetchTexelf(img, i0, j1, 0, t01); - } - if (useBorderColor & (I1BIT | J1BIT)) { - get_border_color(tObj, img, t11); - } - else { - img->FetchTexelf(img, i1, j1, 0, t11); - } - - lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11); -} - - -/** - * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT. - * We don't have to worry about the texture border. - */ -static INLINE void -sample_2d_linear_repeat(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[]) -{ - const GLint width = img->Width2; - const GLint height = img->Height2; - GLint i0, j0, i1, j1; - GLfloat wi, wj; - GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */ - - (void) ctx; - - ASSERT(tObj->WrapS == GL_REPEAT); - ASSERT(tObj->WrapT == GL_REPEAT); - ASSERT(img->Border == 0); - ASSERT(img->_BaseFormat != GL_COLOR_INDEX); - ASSERT(img->_IsPowerOfTwo); - - linear_repeat_texel_location(width, texcoord[0], &i0, &i1, &wi); - linear_repeat_texel_location(height, texcoord[1], &j0, &j1, &wj); - - img->FetchTexelf(img, i0, j0, 0, t00); - img->FetchTexelf(img, i1, j0, 0, t10); - img->FetchTexelf(img, i0, j1, 0, t01); - img->FetchTexelf(img, i1, j1, 0, t11); - - lerp_rgba_2d(rgba, wi, wj, t00, t10, t01, t11); -} - - -static void -sample_2d_nearest_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_2d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); - } -} - - -static void -sample_2d_linear_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_2d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); - } -} - - -static void -sample_2d_nearest_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_2d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_2d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_2d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -static void -sample_2d_linear_mipmap_linear( struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4] ) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_2d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_2d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_2d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -static void -sample_2d_linear_mipmap_linear_repeat(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - ASSERT(tObj->WrapS == GL_REPEAT); - ASSERT(tObj->WrapT == GL_REPEAT); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][level ], - texcoord[i], t0); - sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][level+1], - texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -/** Sample 2D texture, nearest filtering for both min/magnification */ -static void -sample_nearest_2d(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_2d_nearest(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 2D texture, linear filtering for both min/magnification */ -static void -sample_linear_2d(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - if (tObj->WrapS == GL_REPEAT && - tObj->WrapT == GL_REPEAT && - image->_IsPowerOfTwo && - image->Border == 0) { - for (i = 0; i < n; i++) { - sample_2d_linear_repeat(ctx, tObj, image, texcoords[i], rgba[i]); - } - } - else { - for (i = 0; i < n; i++) { - sample_2d_linear(ctx, tObj, image, texcoords[i], rgba[i]); - } - } -} - - -/** - * Optimized 2-D texture sampling: - * S and T wrap mode == GL_REPEAT - * GL_NEAREST min/mag filter - * No border, - * RowStride == Width, - * Format = GL_RGB - */ -static void -opt_sample_rgb_2d(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel]; - const GLfloat width = (GLfloat) img->Width; - const GLfloat height = (GLfloat) img->Height; - const GLint colMask = img->Width - 1; - const GLint rowMask = img->Height - 1; - const GLint shift = img->WidthLog2; - GLuint k; - (void) ctx; - (void) lambda; - ASSERT(tObj->WrapS==GL_REPEAT); - ASSERT(tObj->WrapT==GL_REPEAT); - ASSERT(img->Border==0); - ASSERT(img->TexFormat == MESA_FORMAT_RGB888); - ASSERT(img->_IsPowerOfTwo); - - for (k=0; kData) + 3*pos; - rgba[k][RCOMP] = UBYTE_TO_FLOAT(texel[2]); - rgba[k][GCOMP] = UBYTE_TO_FLOAT(texel[1]); - rgba[k][BCOMP] = UBYTE_TO_FLOAT(texel[0]); - rgba[k][ACOMP] = 1.0F; - } -} - - -/** - * Optimized 2-D texture sampling: - * S and T wrap mode == GL_REPEAT - * GL_NEAREST min/mag filter - * No border - * RowStride == Width, - * Format = GL_RGBA - */ -static void -opt_sample_rgba_2d(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel]; - const GLfloat width = (GLfloat) img->Width; - const GLfloat height = (GLfloat) img->Height; - const GLint colMask = img->Width - 1; - const GLint rowMask = img->Height - 1; - const GLint shift = img->WidthLog2; - GLuint i; - (void) ctx; - (void) lambda; - ASSERT(tObj->WrapS==GL_REPEAT); - ASSERT(tObj->WrapT==GL_REPEAT); - ASSERT(img->Border==0); - ASSERT(img->TexFormat == MESA_FORMAT_RGBA8888); - ASSERT(img->_IsPowerOfTwo); - - for (i = 0; i < n; i++) { - const GLint col = IFLOOR(texcoords[i][0] * width) & colMask; - const GLint row = IFLOOR(texcoords[i][1] * height) & rowMask; - const GLint pos = (row << shift) | col; - const GLuint texel = *((GLuint *) img->Data + pos); - rgba[i][RCOMP] = UBYTE_TO_FLOAT( (texel >> 24) ); - rgba[i][GCOMP] = UBYTE_TO_FLOAT( (texel >> 16) & 0xff ); - rgba[i][BCOMP] = UBYTE_TO_FLOAT( (texel >> 8) & 0xff ); - rgba[i][ACOMP] = UBYTE_TO_FLOAT( (texel ) & 0xff ); - } -} - - -/** Sample 2D texture, using lambda to choose between min/magnification */ -static void -sample_lambda_2d(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel]; - GLuint minStart, minEnd; /* texels with minification */ - GLuint magStart, magEnd; /* texels with magnification */ - - const GLboolean repeatNoBorderPOT = (tObj->WrapS == GL_REPEAT) - && (tObj->WrapT == GL_REPEAT) - && (tImg->Border == 0 && (tImg->Width == tImg->RowStride)) - && (tImg->_BaseFormat != GL_COLOR_INDEX) - && tImg->_IsPowerOfTwo; - - ASSERT(lambda != NULL); - compute_min_mag_ranges(tObj, n, lambda, - &minStart, &minEnd, &magStart, &magEnd); - - if (minStart < minEnd) { - /* do the minified texels */ - const GLuint m = minEnd - minStart; - switch (tObj->MinFilter) { - case GL_NEAREST: - if (repeatNoBorderPOT) { - switch (tImg->TexFormat) { - case MESA_FORMAT_RGB888: - opt_sample_rgb_2d(ctx, tObj, m, texcoords + minStart, - NULL, rgba + minStart); - break; - case MESA_FORMAT_RGBA8888: - opt_sample_rgba_2d(ctx, tObj, m, texcoords + minStart, - NULL, rgba + minStart); - break; - default: - sample_nearest_2d(ctx, tObj, m, texcoords + minStart, - NULL, rgba + minStart ); - } - } - else { - sample_nearest_2d(ctx, tObj, m, texcoords + minStart, - NULL, rgba + minStart); - } - break; - case GL_LINEAR: - sample_linear_2d(ctx, tObj, m, texcoords + minStart, - NULL, rgba + minStart); - break; - case GL_NEAREST_MIPMAP_NEAREST: - sample_2d_nearest_mipmap_nearest(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_NEAREST: - sample_2d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_NEAREST_MIPMAP_LINEAR: - sample_2d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_LINEAR: - if (repeatNoBorderPOT) - sample_2d_linear_mipmap_linear_repeat(ctx, tObj, m, - texcoords + minStart, lambda + minStart, rgba + minStart); - else - sample_2d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - default: - _mesa_problem(ctx, "Bad min filter in sample_2d_texture"); - return; - } - } - - if (magStart < magEnd) { - /* do the magnified texels */ - const GLuint m = magEnd - magStart; - - switch (tObj->MagFilter) { - case GL_NEAREST: - if (repeatNoBorderPOT) { - switch (tImg->TexFormat) { - case MESA_FORMAT_RGB888: - opt_sample_rgb_2d(ctx, tObj, m, texcoords + magStart, - NULL, rgba + magStart); - break; - case MESA_FORMAT_RGBA8888: - opt_sample_rgba_2d(ctx, tObj, m, texcoords + magStart, - NULL, rgba + magStart); - break; - default: - sample_nearest_2d(ctx, tObj, m, texcoords + magStart, - NULL, rgba + magStart ); - } - } - else { - sample_nearest_2d(ctx, tObj, m, texcoords + magStart, - NULL, rgba + magStart); - } - break; - case GL_LINEAR: - sample_linear_2d(ctx, tObj, m, texcoords + magStart, - NULL, rgba + magStart); - break; - default: - _mesa_problem(ctx, "Bad mag filter in sample_lambda_2d"); - } - } -} - - - -/**********************************************************************/ -/* 3-D Texture Sampling Functions */ -/**********************************************************************/ - -/** - * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. - */ -static INLINE void -sample_3d_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[4]) -{ - const GLint width = img->Width2; /* without border, power of two */ - const GLint height = img->Height2; /* without border, power of two */ - const GLint depth = img->Depth2; /* without border, power of two */ - GLint i, j, k; - (void) ctx; - - i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); - j = nearest_texel_location(tObj->WrapT, img, height, texcoord[1]); - k = nearest_texel_location(tObj->WrapR, img, depth, texcoord[2]); - - if (i < 0 || i >= (GLint) img->Width || - j < 0 || j >= (GLint) img->Height || - k < 0 || k >= (GLint) img->Depth) { - /* Need this test for GL_CLAMP_TO_BORDER mode */ - get_border_color(tObj, img, rgba); - } - else { - img->FetchTexelf(img, i, j, k, rgba); - } -} - - -/** - * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. - */ -static void -sample_3d_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[4]) -{ - const GLint width = img->Width2; - const GLint height = img->Height2; - const GLint depth = img->Depth2; - GLint i0, j0, k0, i1, j1, k1; - GLbitfield useBorderColor = 0x0; - GLfloat a, b, c; - GLfloat t000[4], t010[4], t001[4], t011[4]; - GLfloat t100[4], t110[4], t101[4], t111[4]; - - linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); - linear_texel_locations(tObj->WrapT, img, height, texcoord[1], &j0, &j1, &b); - linear_texel_locations(tObj->WrapR, img, depth, texcoord[2], &k0, &k1, &c); - - if (img->Border) { - i0 += img->Border; - i1 += img->Border; - j0 += img->Border; - j1 += img->Border; - k0 += img->Border; - k1 += img->Border; - } - else { - /* check if sampling texture border color */ - if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; - if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; - if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; - if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; - if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT; - if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT; - } - - /* Fetch texels */ - if (useBorderColor & (I0BIT | J0BIT | K0BIT)) { - get_border_color(tObj, img, t000); - } - else { - img->FetchTexelf(img, i0, j0, k0, t000); - } - if (useBorderColor & (I1BIT | J0BIT | K0BIT)) { - get_border_color(tObj, img, t100); - } - else { - img->FetchTexelf(img, i1, j0, k0, t100); - } - if (useBorderColor & (I0BIT | J1BIT | K0BIT)) { - get_border_color(tObj, img, t010); - } - else { - img->FetchTexelf(img, i0, j1, k0, t010); - } - if (useBorderColor & (I1BIT | J1BIT | K0BIT)) { - get_border_color(tObj, img, t110); - } - else { - img->FetchTexelf(img, i1, j1, k0, t110); - } - - if (useBorderColor & (I0BIT | J0BIT | K1BIT)) { - get_border_color(tObj, img, t001); - } - else { - img->FetchTexelf(img, i0, j0, k1, t001); - } - if (useBorderColor & (I1BIT | J0BIT | K1BIT)) { - get_border_color(tObj, img, t101); - } - else { - img->FetchTexelf(img, i1, j0, k1, t101); - } - if (useBorderColor & (I0BIT | J1BIT | K1BIT)) { - get_border_color(tObj, img, t011); - } - else { - img->FetchTexelf(img, i0, j1, k1, t011); - } - if (useBorderColor & (I1BIT | J1BIT | K1BIT)) { - get_border_color(tObj, img, t111); - } - else { - img->FetchTexelf(img, i1, j1, k1, t111); - } - - /* trilinear interpolation of samples */ - lerp_rgba_3d(rgba, a, b, c, t000, t100, t010, t110, t001, t101, t011, t111); -} - - -static void -sample_3d_nearest_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4] ) -{ - GLuint i; - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_3d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); - } -} - - -static void -sample_3d_linear_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_3d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); - } -} - - -static void -sample_3d_nearest_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_3d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_3d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -static void -sample_3d_linear_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_3d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_3d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -/** Sample 3D texture, nearest filtering for both min/magnification */ -static void -sample_nearest_3d(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_3d_nearest(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 3D texture, linear filtering for both min/magnification */ -static void -sample_linear_3d(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_3d_linear(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 3D texture, using lambda to choose between min/magnification */ -static void -sample_lambda_3d(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint minStart, minEnd; /* texels with minification */ - GLuint magStart, magEnd; /* texels with magnification */ - GLuint i; - - ASSERT(lambda != NULL); - compute_min_mag_ranges(tObj, n, lambda, - &minStart, &minEnd, &magStart, &magEnd); - - if (minStart < minEnd) { - /* do the minified texels */ - GLuint m = minEnd - minStart; - switch (tObj->MinFilter) { - case GL_NEAREST: - for (i = minStart; i < minEnd; i++) - sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = minStart; i < minEnd; i++) - sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_NEAREST_MIPMAP_NEAREST: - sample_3d_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_NEAREST: - sample_3d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_NEAREST_MIPMAP_LINEAR: - sample_3d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_LINEAR: - sample_3d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - default: - _mesa_problem(ctx, "Bad min filter in sample_3d_texture"); - return; - } - } - - if (magStart < magEnd) { - /* do the magnified texels */ - switch (tObj->MagFilter) { - case GL_NEAREST: - for (i = magStart; i < magEnd; i++) - sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = magStart; i < magEnd; i++) - sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - default: - _mesa_problem(ctx, "Bad mag filter in sample_3d_texture"); - return; - } - } -} - - -/**********************************************************************/ -/* Texture Cube Map Sampling Functions */ -/**********************************************************************/ - -/** - * Choose one of six sides of a texture cube map given the texture - * coord (rx,ry,rz). Return pointer to corresponding array of texture - * images. - */ -static const struct gl_texture_image ** -choose_cube_face(const struct gl_texture_object *texObj, - const GLfloat texcoord[4], GLfloat newCoord[4]) -{ - /* - major axis - direction target sc tc ma - ---------- ------------------------------- --- --- --- - +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx - -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx - +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry - -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry - +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz - -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz - */ - const GLfloat rx = texcoord[0]; - const GLfloat ry = texcoord[1]; - const GLfloat rz = texcoord[2]; - const GLfloat arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz); - GLuint face; - GLfloat sc, tc, ma; - - if (arx >= ary && arx >= arz) { - if (rx >= 0.0F) { - face = FACE_POS_X; - sc = -rz; - tc = -ry; - ma = arx; - } - else { - face = FACE_NEG_X; - sc = rz; - tc = -ry; - ma = arx; - } - } - else if (ary >= arx && ary >= arz) { - if (ry >= 0.0F) { - face = FACE_POS_Y; - sc = rx; - tc = rz; - ma = ary; - } - else { - face = FACE_NEG_Y; - sc = rx; - tc = -rz; - ma = ary; - } - } - else { - if (rz > 0.0F) { - face = FACE_POS_Z; - sc = rx; - tc = -ry; - ma = arz; - } - else { - face = FACE_NEG_Z; - sc = -rx; - tc = -ry; - ma = arz; - } - } - - { - const float ima = 1.0F / ma; - newCoord[0] = ( sc * ima + 1.0F ) * 0.5F; - newCoord[1] = ( tc * ima + 1.0F ) * 0.5F; - } - - return (const struct gl_texture_image **) texObj->Image[face]; -} - - -static void -sample_nearest_cube(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint i; - (void) lambda; - for (i = 0; i < n; i++) { - const struct gl_texture_image **images; - GLfloat newCoord[4]; - images = choose_cube_face(tObj, texcoords[i], newCoord); - sample_2d_nearest(ctx, tObj, images[tObj->BaseLevel], - newCoord, rgba[i]); - } -} - - -static void -sample_linear_cube(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - (void) lambda; - for (i = 0; i < n; i++) { - const struct gl_texture_image **images; - GLfloat newCoord[4]; - images = choose_cube_face(tObj, texcoords[i], newCoord); - sample_2d_linear(ctx, tObj, images[tObj->BaseLevel], - newCoord, rgba[i]); - } -} - - -static void -sample_cube_nearest_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - const struct gl_texture_image **images; - GLfloat newCoord[4]; - GLint level; - images = choose_cube_face(tObj, texcoord[i], newCoord); - - /* XXX we actually need to recompute lambda here based on the newCoords. - * But we would need the texcoords of adjacent fragments to compute that - * properly, and we don't have those here. - * For now, do an approximation: subtracting 1 from the chosen mipmap - * level seems to work in some test cases. - * The same adjustment is done in the next few functions. - */ - level = nearest_mipmap_level(tObj, lambda[i]); - level = MAX2(level - 1, 0); - - sample_2d_nearest(ctx, tObj, images[level], newCoord, rgba[i]); - } -} - - -static void -sample_cube_linear_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - const struct gl_texture_image **images; - GLfloat newCoord[4]; - GLint level = nearest_mipmap_level(tObj, lambda[i]); - level = MAX2(level - 1, 0); /* see comment above */ - images = choose_cube_face(tObj, texcoord[i], newCoord); - sample_2d_linear(ctx, tObj, images[level], newCoord, rgba[i]); - } -} - - -static void -sample_cube_nearest_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - const struct gl_texture_image **images; - GLfloat newCoord[4]; - GLint level = linear_mipmap_level(tObj, lambda[i]); - level = MAX2(level - 1, 0); /* see comment above */ - images = choose_cube_face(tObj, texcoord[i], newCoord); - if (level >= tObj->_MaxLevel) { - sample_2d_nearest(ctx, tObj, images[tObj->_MaxLevel], - newCoord, rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_2d_nearest(ctx, tObj, images[level ], newCoord, t0); - sample_2d_nearest(ctx, tObj, images[level+1], newCoord, t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -static void -sample_cube_linear_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - const struct gl_texture_image **images; - GLfloat newCoord[4]; - GLint level = linear_mipmap_level(tObj, lambda[i]); - level = MAX2(level - 1, 0); /* see comment above */ - images = choose_cube_face(tObj, texcoord[i], newCoord); - if (level >= tObj->_MaxLevel) { - sample_2d_linear(ctx, tObj, images[tObj->_MaxLevel], - newCoord, rgba[i]); - } - else { - GLfloat t0[4], t1[4]; - const GLfloat f = FRAC(lambda[i]); - sample_2d_linear(ctx, tObj, images[level ], newCoord, t0); - sample_2d_linear(ctx, tObj, images[level+1], newCoord, t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -/** Sample cube texture, using lambda to choose between min/magnification */ -static void -sample_lambda_cube(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint minStart, minEnd; /* texels with minification */ - GLuint magStart, magEnd; /* texels with magnification */ - - ASSERT(lambda != NULL); - compute_min_mag_ranges(tObj, n, lambda, - &minStart, &minEnd, &magStart, &magEnd); - - if (minStart < minEnd) { - /* do the minified texels */ - const GLuint m = minEnd - minStart; - switch (tObj->MinFilter) { - case GL_NEAREST: - sample_nearest_cube(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR: - sample_linear_cube(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_NEAREST_MIPMAP_NEAREST: - sample_cube_nearest_mipmap_nearest(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_NEAREST: - sample_cube_linear_mipmap_nearest(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_NEAREST_MIPMAP_LINEAR: - sample_cube_nearest_mipmap_linear(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_LINEAR: - sample_cube_linear_mipmap_linear(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - default: - _mesa_problem(ctx, "Bad min filter in sample_lambda_cube"); - } - } - - if (magStart < magEnd) { - /* do the magnified texels */ - const GLuint m = magEnd - magStart; - switch (tObj->MagFilter) { - case GL_NEAREST: - sample_nearest_cube(ctx, tObj, m, texcoords + magStart, - lambda + magStart, rgba + magStart); - break; - case GL_LINEAR: - sample_linear_cube(ctx, tObj, m, texcoords + magStart, - lambda + magStart, rgba + magStart); - break; - default: - _mesa_problem(ctx, "Bad mag filter in sample_lambda_cube"); - } - } -} - - -/**********************************************************************/ -/* Texture Rectangle Sampling Functions */ -/**********************************************************************/ - - -static void -sample_nearest_rect(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - const struct gl_texture_image *img = tObj->Image[0][0]; - const GLint width = img->Width; - const GLint height = img->Height; - GLuint i; - - (void) ctx; - (void) lambda; - - ASSERT(tObj->WrapS == GL_CLAMP || - tObj->WrapS == GL_CLAMP_TO_EDGE || - tObj->WrapS == GL_CLAMP_TO_BORDER); - ASSERT(tObj->WrapT == GL_CLAMP || - tObj->WrapT == GL_CLAMP_TO_EDGE || - tObj->WrapT == GL_CLAMP_TO_BORDER); - ASSERT(img->_BaseFormat != GL_COLOR_INDEX); - - for (i = 0; i < n; i++) { - GLint row, col; - col = clamp_rect_coord_nearest(tObj->WrapS, texcoords[i][0], width); - row = clamp_rect_coord_nearest(tObj->WrapT, texcoords[i][1], height); - if (col < 0 || col >= width || row < 0 || row >= height) - get_border_color(tObj, img, rgba[i]); - else - img->FetchTexelf(img, col, row, 0, rgba[i]); - } -} - - -static void -sample_linear_rect(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - const struct gl_texture_image *img = tObj->Image[0][0]; - const GLint width = img->Width; - const GLint height = img->Height; - GLuint i; - - (void) ctx; - (void) lambda; - - ASSERT(tObj->WrapS == GL_CLAMP || - tObj->WrapS == GL_CLAMP_TO_EDGE || - tObj->WrapS == GL_CLAMP_TO_BORDER); - ASSERT(tObj->WrapT == GL_CLAMP || - tObj->WrapT == GL_CLAMP_TO_EDGE || - tObj->WrapT == GL_CLAMP_TO_BORDER); - ASSERT(img->_BaseFormat != GL_COLOR_INDEX); - - for (i = 0; i < n; i++) { - GLint i0, j0, i1, j1; - GLfloat t00[4], t01[4], t10[4], t11[4]; - GLfloat a, b; - GLbitfield useBorderColor = 0x0; - - clamp_rect_coord_linear(tObj->WrapS, texcoords[i][0], width, - &i0, &i1, &a); - clamp_rect_coord_linear(tObj->WrapT, texcoords[i][1], height, - &j0, &j1, &b); - - /* compute integer rows/columns */ - if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; - if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; - if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; - if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; - - /* get four texel samples */ - if (useBorderColor & (I0BIT | J0BIT)) - get_border_color(tObj, img, t00); - else - img->FetchTexelf(img, i0, j0, 0, t00); - - if (useBorderColor & (I1BIT | J0BIT)) - get_border_color(tObj, img, t10); - else - img->FetchTexelf(img, i1, j0, 0, t10); - - if (useBorderColor & (I0BIT | J1BIT)) - get_border_color(tObj, img, t01); - else - img->FetchTexelf(img, i0, j1, 0, t01); - - if (useBorderColor & (I1BIT | J1BIT)) - get_border_color(tObj, img, t11); - else - img->FetchTexelf(img, i1, j1, 0, t11); - - lerp_rgba_2d(rgba[i], a, b, t00, t10, t01, t11); - } -} - - -/** Sample Rect texture, using lambda to choose between min/magnification */ -static void -sample_lambda_rect(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint minStart, minEnd, magStart, magEnd; - - /* We only need lambda to decide between minification and magnification. - * There is no mipmapping with rectangular textures. - */ - compute_min_mag_ranges(tObj, n, lambda, - &minStart, &minEnd, &magStart, &magEnd); - - if (minStart < minEnd) { - if (tObj->MinFilter == GL_NEAREST) { - sample_nearest_rect(ctx, tObj, minEnd - minStart, - texcoords + minStart, NULL, rgba + minStart); - } - else { - sample_linear_rect(ctx, tObj, minEnd - minStart, - texcoords + minStart, NULL, rgba + minStart); - } - } - if (magStart < magEnd) { - if (tObj->MagFilter == GL_NEAREST) { - sample_nearest_rect(ctx, tObj, magEnd - magStart, - texcoords + magStart, NULL, rgba + magStart); - } - else { - sample_linear_rect(ctx, tObj, magEnd - magStart, - texcoords + magStart, NULL, rgba + magStart); - } - } -} - - -/**********************************************************************/ -/* 2D Texture Array Sampling Functions */ -/**********************************************************************/ - -/** - * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. - */ -static void -sample_2d_array_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[4]) -{ - const GLint width = img->Width2; /* without border, power of two */ - const GLint height = img->Height2; /* without border, power of two */ - const GLint depth = img->Depth; - GLint i, j; - GLint array; - (void) ctx; - - i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); - j = nearest_texel_location(tObj->WrapT, img, height, texcoord[1]); - array = tex_array_slice(texcoord[2], depth); - - if (i < 0 || i >= (GLint) img->Width || - j < 0 || j >= (GLint) img->Height || - array < 0 || array >= (GLint) img->Depth) { - /* Need this test for GL_CLAMP_TO_BORDER mode */ - get_border_color(tObj, img, rgba); - } - else { - img->FetchTexelf(img, i, j, array, rgba); - } -} - - -/** - * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. - */ -static void -sample_2d_array_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[4]) -{ - const GLint width = img->Width2; - const GLint height = img->Height2; - const GLint depth = img->Depth; - GLint i0, j0, i1, j1; - GLint array; - GLbitfield useBorderColor = 0x0; - GLfloat a, b; - GLfloat t00[4], t01[4], t10[4], t11[4]; - - linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); - linear_texel_locations(tObj->WrapT, img, height, texcoord[1], &j0, &j1, &b); - array = tex_array_slice(texcoord[2], depth); - - if (array < 0 || array >= depth) { - COPY_4V(rgba, tObj->BorderColor.f); - } - else { - if (img->Border) { - i0 += img->Border; - i1 += img->Border; - j0 += img->Border; - j1 += img->Border; - } - else { - /* check if sampling texture border color */ - if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; - if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; - if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; - if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; - } - - /* Fetch texels */ - if (useBorderColor & (I0BIT | J0BIT)) { - get_border_color(tObj, img, t00); - } - else { - img->FetchTexelf(img, i0, j0, array, t00); - } - if (useBorderColor & (I1BIT | J0BIT)) { - get_border_color(tObj, img, t10); - } - else { - img->FetchTexelf(img, i1, j0, array, t10); - } - if (useBorderColor & (I0BIT | J1BIT)) { - get_border_color(tObj, img, t01); - } - else { - img->FetchTexelf(img, i0, j1, array, t01); - } - if (useBorderColor & (I1BIT | J1BIT)) { - get_border_color(tObj, img, t11); - } - else { - img->FetchTexelf(img, i1, j1, array, t11); - } - - /* trilinear interpolation of samples */ - lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11); - } -} - - -static void -sample_2d_array_nearest_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], - rgba[i]); - } -} - - -static void -sample_2d_array_linear_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_2d_array_linear(ctx, tObj, tObj->Image[0][level], - texcoord[i], rgba[i]); - } -} - - -static void -sample_2d_array_nearest_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level ], - texcoord[i], t0); - sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level+1], - texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -static void -sample_2d_array_linear_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_2d_array_linear(ctx, tObj, tObj->Image[0][level ], - texcoord[i], t0); - sample_2d_array_linear(ctx, tObj, tObj->Image[0][level+1], - texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -/** Sample 2D Array texture, nearest filtering for both min/magnification */ -static void -sample_nearest_2d_array(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_2d_array_nearest(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - - -/** Sample 2D Array texture, linear filtering for both min/magnification */ -static void -sample_linear_2d_array(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_2d_array_linear(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 2D Array texture, using lambda to choose between min/magnification */ -static void -sample_lambda_2d_array(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint minStart, minEnd; /* texels with minification */ - GLuint magStart, magEnd; /* texels with magnification */ - GLuint i; - - ASSERT(lambda != NULL); - compute_min_mag_ranges(tObj, n, lambda, - &minStart, &minEnd, &magStart, &magEnd); - - if (minStart < minEnd) { - /* do the minified texels */ - GLuint m = minEnd - minStart; - switch (tObj->MinFilter) { - case GL_NEAREST: - for (i = minStart; i < minEnd; i++) - sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = minStart; i < minEnd; i++) - sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_NEAREST_MIPMAP_NEAREST: - sample_2d_array_nearest_mipmap_nearest(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, - rgba + minStart); - break; - case GL_LINEAR_MIPMAP_NEAREST: - sample_2d_array_linear_mipmap_nearest(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, - rgba + minStart); - break; - case GL_NEAREST_MIPMAP_LINEAR: - sample_2d_array_nearest_mipmap_linear(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, - rgba + minStart); - break; - case GL_LINEAR_MIPMAP_LINEAR: - sample_2d_array_linear_mipmap_linear(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, - rgba + minStart); - break; - default: - _mesa_problem(ctx, "Bad min filter in sample_2d_array_texture"); - return; - } - } - - if (magStart < magEnd) { - /* do the magnified texels */ - switch (tObj->MagFilter) { - case GL_NEAREST: - for (i = magStart; i < magEnd; i++) - sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = magStart; i < magEnd; i++) - sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - default: - _mesa_problem(ctx, "Bad mag filter in sample_2d_array_texture"); - return; - } - } -} - - - - -/**********************************************************************/ -/* 1D Texture Array Sampling Functions */ -/**********************************************************************/ - -/** - * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. - */ -static void -sample_1d_array_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[4]) -{ - const GLint width = img->Width2; /* without border, power of two */ - const GLint height = img->Height; - GLint i; - GLint array; - (void) ctx; - - i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); - array = tex_array_slice(texcoord[1], height); - - if (i < 0 || i >= (GLint) img->Width || - array < 0 || array >= (GLint) img->Height) { - /* Need this test for GL_CLAMP_TO_BORDER mode */ - get_border_color(tObj, img, rgba); - } - else { - img->FetchTexelf(img, i, array, 0, rgba); - } -} - - -/** - * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. - */ -static void -sample_1d_array_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[4]) -{ - const GLint width = img->Width2; - const GLint height = img->Height; - GLint i0, i1; - GLint array; - GLbitfield useBorderColor = 0x0; - GLfloat a; - GLfloat t0[4], t1[4]; - - linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); - array = tex_array_slice(texcoord[1], height); - - if (img->Border) { - i0 += img->Border; - i1 += img->Border; - } - else { - /* check if sampling texture border color */ - if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; - if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; - } - - if (array < 0 || array >= height) useBorderColor |= K0BIT; - - /* Fetch texels */ - if (useBorderColor & (I0BIT | K0BIT)) { - get_border_color(tObj, img, t0); - } - else { - img->FetchTexelf(img, i0, array, 0, t0); - } - if (useBorderColor & (I1BIT | K0BIT)) { - get_border_color(tObj, img, t1); - } - else { - img->FetchTexelf(img, i1, array, 0, t1); - } - - /* bilinear interpolation of samples */ - lerp_rgba(rgba, a, t0, t1); -} - - -static void -sample_1d_array_nearest_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], - rgba[i]); - } -} - - -static void -sample_1d_array_linear_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_1d_array_linear(ctx, tObj, tObj->Image[0][level], - texcoord[i], rgba[i]); - } -} - - -static void -sample_1d_array_nearest_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -static void -sample_1d_array_linear_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_1d_array_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_1d_array_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -/** Sample 1D Array texture, nearest filtering for both min/magnification */ -static void -sample_nearest_1d_array(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_1d_array_nearest(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 1D Array texture, linear filtering for both min/magnification */ -static void -sample_linear_1d_array(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_1d_array_linear(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 1D Array texture, using lambda to choose between min/magnification */ -static void -sample_lambda_1d_array(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint minStart, minEnd; /* texels with minification */ - GLuint magStart, magEnd; /* texels with magnification */ - GLuint i; - - ASSERT(lambda != NULL); - compute_min_mag_ranges(tObj, n, lambda, - &minStart, &minEnd, &magStart, &magEnd); - - if (minStart < minEnd) { - /* do the minified texels */ - GLuint m = minEnd - minStart; - switch (tObj->MinFilter) { - case GL_NEAREST: - for (i = minStart; i < minEnd; i++) - sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = minStart; i < minEnd; i++) - sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_NEAREST_MIPMAP_NEAREST: - sample_1d_array_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_NEAREST: - sample_1d_array_linear_mipmap_nearest(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, - rgba + minStart); - break; - case GL_NEAREST_MIPMAP_LINEAR: - sample_1d_array_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_LINEAR: - sample_1d_array_linear_mipmap_linear(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, - rgba + minStart); - break; - default: - _mesa_problem(ctx, "Bad min filter in sample_1d_array_texture"); - return; - } - } - - if (magStart < magEnd) { - /* do the magnified texels */ - switch (tObj->MagFilter) { - case GL_NEAREST: - for (i = magStart; i < magEnd; i++) - sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = magStart; i < magEnd; i++) - sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - default: - _mesa_problem(ctx, "Bad mag filter in sample_1d_array_texture"); - return; - } - } -} - - -/** - * Compare texcoord against depth sample. Return 1.0 or the ambient value. - */ -static INLINE GLfloat -shadow_compare(GLenum function, GLfloat coord, GLfloat depthSample, - GLfloat ambient) -{ - switch (function) { - case GL_LEQUAL: - return (coord <= depthSample) ? 1.0F : ambient; - case GL_GEQUAL: - return (coord >= depthSample) ? 1.0F : ambient; - case GL_LESS: - return (coord < depthSample) ? 1.0F : ambient; - case GL_GREATER: - return (coord > depthSample) ? 1.0F : ambient; - case GL_EQUAL: - return (coord == depthSample) ? 1.0F : ambient; - case GL_NOTEQUAL: - return (coord != depthSample) ? 1.0F : ambient; - case GL_ALWAYS: - return 1.0F; - case GL_NEVER: - return ambient; - case GL_NONE: - return depthSample; - default: - _mesa_problem(NULL, "Bad compare func in shadow_compare"); - return ambient; - } -} - - -/** - * Compare texcoord against four depth samples. - */ -static INLINE GLfloat -shadow_compare4(GLenum function, GLfloat coord, - GLfloat depth00, GLfloat depth01, - GLfloat depth10, GLfloat depth11, - GLfloat ambient, GLfloat wi, GLfloat wj) -{ - const GLfloat d = (1.0F - (GLfloat) ambient) * 0.25F; - GLfloat luminance = 1.0F; - - switch (function) { - case GL_LEQUAL: - if (depth00 <= coord) luminance -= d; - if (depth01 <= coord) luminance -= d; - if (depth10 <= coord) luminance -= d; - if (depth11 <= coord) luminance -= d; - return luminance; - case GL_GEQUAL: - if (depth00 >= coord) luminance -= d; - if (depth01 >= coord) luminance -= d; - if (depth10 >= coord) luminance -= d; - if (depth11 >= coord) luminance -= d; - return luminance; - case GL_LESS: - if (depth00 < coord) luminance -= d; - if (depth01 < coord) luminance -= d; - if (depth10 < coord) luminance -= d; - if (depth11 < coord) luminance -= d; - return luminance; - case GL_GREATER: - if (depth00 > coord) luminance -= d; - if (depth01 > coord) luminance -= d; - if (depth10 > coord) luminance -= d; - if (depth11 > coord) luminance -= d; - return luminance; - case GL_EQUAL: - if (depth00 == coord) luminance -= d; - if (depth01 == coord) luminance -= d; - if (depth10 == coord) luminance -= d; - if (depth11 == coord) luminance -= d; - return luminance; - case GL_NOTEQUAL: - if (depth00 != coord) luminance -= d; - if (depth01 != coord) luminance -= d; - if (depth10 != coord) luminance -= d; - if (depth11 != coord) luminance -= d; - return luminance; - case GL_ALWAYS: - return 0.0; - case GL_NEVER: - return ambient; - case GL_NONE: - /* ordinary bilinear filtering */ - return lerp_2d(wi, wj, depth00, depth10, depth01, depth11); - default: - _mesa_problem(NULL, "Bad compare func in sample_depth_texture"); - return 0.0F; - } -} - - -/** - * Choose the mipmap level to use when sampling from a depth texture. - */ -static int -choose_depth_texture_level(const struct gl_texture_object *tObj, GLfloat lambda) -{ - GLint level; - - if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) { - /* no mipmapping - use base level */ - level = tObj->BaseLevel; - } - else { - /* choose mipmap level */ - lambda = CLAMP(lambda, tObj->MinLod, tObj->MaxLod); - level = (GLint) lambda; - level = CLAMP(level, tObj->BaseLevel, tObj->_MaxLevel); - } - - return level; -} - - -/** - * Sample a shadow/depth texture. This function is incomplete. It doesn't - * check for minification vs. magnification, etc. - */ -static void -sample_depth_texture( struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat texel[][4] ) -{ - const GLint level = choose_depth_texture_level(tObj, lambda[0]); - const struct gl_texture_image *img = tObj->Image[0][level]; - const GLint width = img->Width; - const GLint height = img->Height; - const GLint depth = img->Depth; - const GLuint compare_coord = (tObj->Target == GL_TEXTURE_2D_ARRAY_EXT) - ? 3 : 2; - GLfloat ambient; - GLenum function; - GLfloat result; - - ASSERT(img->_BaseFormat == GL_DEPTH_COMPONENT || - img->_BaseFormat == GL_DEPTH_STENCIL_EXT); - - ASSERT(tObj->Target == GL_TEXTURE_1D || - tObj->Target == GL_TEXTURE_2D || - tObj->Target == GL_TEXTURE_RECTANGLE_NV || - tObj->Target == GL_TEXTURE_1D_ARRAY_EXT || - tObj->Target == GL_TEXTURE_2D_ARRAY_EXT); - - ambient = tObj->CompareFailValue; - - /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */ - - function = (tObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) ? - tObj->CompareFunc : GL_NONE; - - if (tObj->MagFilter == GL_NEAREST) { - GLuint i; - for (i = 0; i < n; i++) { - GLfloat depthSample; - GLint col, row, slice; - - nearest_texcoord(tObj, level, texcoords[i], &col, &row, &slice); - - if (col >= 0 && row >= 0 && col < width && row < height && - slice >= 0 && slice < depth) { - img->FetchTexelf(img, col, row, slice, &depthSample); - } - else { - depthSample = tObj->BorderColor.f[0]; - } - - result = shadow_compare(function, texcoords[i][compare_coord], - depthSample, ambient); - - switch (tObj->DepthMode) { - case GL_LUMINANCE: - ASSIGN_4V(texel[i], result, result, result, 1.0F); - break; - case GL_INTENSITY: - ASSIGN_4V(texel[i], result, result, result, result); - break; - case GL_ALPHA: - ASSIGN_4V(texel[i], 0.0F, 0.0F, 0.0F, result); - break; - case GL_RED: - ASSIGN_4V(texel[i], result, 0.0F, 0.0F, 1.0F); - break; - default: - _mesa_problem(ctx, "Bad depth texture mode"); - } - } - } - else { - GLuint i; - ASSERT(tObj->MagFilter == GL_LINEAR); - for (i = 0; i < n; i++) { - GLfloat depth00, depth01, depth10, depth11; - GLint i0, i1, j0, j1; - GLint slice; - GLfloat wi, wj; - GLuint useBorderTexel; - - linear_texcoord(tObj, level, texcoords[i], &i0, &i1, &j0, &j1, &slice, - &wi, &wj); - - useBorderTexel = 0; - if (img->Border) { - i0 += img->Border; - i1 += img->Border; - if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) { - j0 += img->Border; - j1 += img->Border; - } - } - else { - if (i0 < 0 || i0 >= (GLint) width) useBorderTexel |= I0BIT; - if (i1 < 0 || i1 >= (GLint) width) useBorderTexel |= I1BIT; - if (j0 < 0 || j0 >= (GLint) height) useBorderTexel |= J0BIT; - if (j1 < 0 || j1 >= (GLint) height) useBorderTexel |= J1BIT; - } - - if (slice < 0 || slice >= (GLint) depth) { - depth00 = tObj->BorderColor.f[0]; - depth01 = tObj->BorderColor.f[0]; - depth10 = tObj->BorderColor.f[0]; - depth11 = tObj->BorderColor.f[0]; - } - else { - /* get four depth samples from the texture */ - if (useBorderTexel & (I0BIT | J0BIT)) { - depth00 = tObj->BorderColor.f[0]; - } - else { - img->FetchTexelf(img, i0, j0, slice, &depth00); - } - if (useBorderTexel & (I1BIT | J0BIT)) { - depth10 = tObj->BorderColor.f[0]; - } - else { - img->FetchTexelf(img, i1, j0, slice, &depth10); - } - - if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) { - if (useBorderTexel & (I0BIT | J1BIT)) { - depth01 = tObj->BorderColor.f[0]; - } - else { - img->FetchTexelf(img, i0, j1, slice, &depth01); - } - if (useBorderTexel & (I1BIT | J1BIT)) { - depth11 = tObj->BorderColor.f[0]; - } - else { - img->FetchTexelf(img, i1, j1, slice, &depth11); - } - } - else { - depth01 = depth00; - depth11 = depth10; - } - } - - result = shadow_compare4(function, texcoords[i][compare_coord], - depth00, depth01, depth10, depth11, - ambient, wi, wj); - - switch (tObj->DepthMode) { - case GL_LUMINANCE: - ASSIGN_4V(texel[i], result, result, result, 1.0F); - break; - case GL_INTENSITY: - ASSIGN_4V(texel[i], result, result, result, result); - break; - case GL_ALPHA: - ASSIGN_4V(texel[i], 0.0F, 0.0F, 0.0F, result); - break; - default: - _mesa_problem(ctx, "Bad depth texture mode"); - } - - } /* for */ - } /* if filter */ -} - - -/** - * We use this function when a texture object is in an "incomplete" state. - * When a fragment program attempts to sample an incomplete texture we - * return black (see issue 23 in GL_ARB_fragment_program spec). - * Note: fragment programs don't observe the texture enable/disable flags. - */ -static void -null_sample_func( struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint i; - (void) ctx; - (void) tObj; - (void) texcoords; - (void) lambda; - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = 0; - rgba[i][GCOMP] = 0; - rgba[i][BCOMP] = 0; - rgba[i][ACOMP] = 1.0; - } -} - - -/** - * Choose the texture sampling function for the given texture object. - */ -texture_sample_func -_swrast_choose_texture_sample_func( struct gl_context *ctx, - const struct gl_texture_object *t ) -{ - if (!t || !t->_Complete) { - return &null_sample_func; - } - else { - const GLboolean needLambda = (GLboolean) (t->MinFilter != t->MagFilter); - const GLenum format = t->Image[0][t->BaseLevel]->_BaseFormat; - - switch (t->Target) { - case GL_TEXTURE_1D: - if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) { - return &sample_depth_texture; - } - else if (needLambda) { - return &sample_lambda_1d; - } - else if (t->MinFilter == GL_LINEAR) { - return &sample_linear_1d; - } - else { - ASSERT(t->MinFilter == GL_NEAREST); - return &sample_nearest_1d; - } - case GL_TEXTURE_2D: - if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) { - return &sample_depth_texture; - } - else if (needLambda) { - return &sample_lambda_2d; - } - else if (t->MinFilter == GL_LINEAR) { - return &sample_linear_2d; - } - else { - /* check for a few optimized cases */ - const struct gl_texture_image *img = t->Image[0][t->BaseLevel]; - ASSERT(t->MinFilter == GL_NEAREST); - if (t->WrapS == GL_REPEAT && - t->WrapT == GL_REPEAT && - img->_IsPowerOfTwo && - img->Border == 0 && - img->TexFormat == MESA_FORMAT_RGB888) { - return &opt_sample_rgb_2d; - } - else if (t->WrapS == GL_REPEAT && - t->WrapT == GL_REPEAT && - img->_IsPowerOfTwo && - img->Border == 0 && - img->TexFormat == MESA_FORMAT_RGBA8888) { - return &opt_sample_rgba_2d; - } - else { - return &sample_nearest_2d; - } - } - case GL_TEXTURE_3D: - if (needLambda) { - return &sample_lambda_3d; - } - else if (t->MinFilter == GL_LINEAR) { - return &sample_linear_3d; - } - else { - ASSERT(t->MinFilter == GL_NEAREST); - return &sample_nearest_3d; - } - case GL_TEXTURE_CUBE_MAP: - if (needLambda) { - return &sample_lambda_cube; - } - else if (t->MinFilter == GL_LINEAR) { - return &sample_linear_cube; - } - else { - ASSERT(t->MinFilter == GL_NEAREST); - return &sample_nearest_cube; - } - case GL_TEXTURE_RECTANGLE_NV: - if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) { - return &sample_depth_texture; - } - else if (needLambda) { - return &sample_lambda_rect; - } - else if (t->MinFilter == GL_LINEAR) { - return &sample_linear_rect; - } - else { - ASSERT(t->MinFilter == GL_NEAREST); - return &sample_nearest_rect; - } - case GL_TEXTURE_1D_ARRAY_EXT: - if (needLambda) { - return &sample_lambda_1d_array; - } - else if (t->MinFilter == GL_LINEAR) { - return &sample_linear_1d_array; - } - else { - ASSERT(t->MinFilter == GL_NEAREST); - return &sample_nearest_1d_array; - } - case GL_TEXTURE_2D_ARRAY_EXT: - if (needLambda) { - return &sample_lambda_2d_array; - } - else if (t->MinFilter == GL_LINEAR) { - return &sample_linear_2d_array; - } - else { - ASSERT(t->MinFilter == GL_NEAREST); - return &sample_nearest_2d_array; - } - default: - _mesa_problem(ctx, - "invalid target in _swrast_choose_texture_sample_func"); - return &null_sample_func; - } - } -} +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2008 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 "main/glheader.h" +#include "main/context.h" +#include "main/colormac.h" +#include "main/imports.h" + +#include "s_context.h" +#include "s_texfilter.h" + + +/* + * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes + * see 1-pixel bands of improperly weighted linear-filtered textures. + * The tests/texwrap.c demo is a good test. + * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0. + * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x). + */ +#define FRAC(f) ((f) - IFLOOR(f)) + + + +/** + * Linear interpolation macro + */ +#define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) ) + + +/** + * Do 2D/biliner interpolation of float values. + * v00, v10, v01 and v11 are typically four texture samples in a square/box. + * a and b are the horizontal and vertical interpolants. + * It's important that this function is inlined when compiled with + * optimization! If we find that's not true on some systems, convert + * to a macro. + */ +static INLINE GLfloat +lerp_2d(GLfloat a, GLfloat b, + GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11) +{ + const GLfloat temp0 = LERP(a, v00, v10); + const GLfloat temp1 = LERP(a, v01, v11); + return LERP(b, temp0, temp1); +} + + +/** + * Do 3D/trilinear interpolation of float values. + * \sa lerp_2d + */ +static INLINE GLfloat +lerp_3d(GLfloat a, GLfloat b, GLfloat c, + GLfloat v000, GLfloat v100, GLfloat v010, GLfloat v110, + GLfloat v001, GLfloat v101, GLfloat v011, GLfloat v111) +{ + const GLfloat temp00 = LERP(a, v000, v100); + const GLfloat temp10 = LERP(a, v010, v110); + const GLfloat temp01 = LERP(a, v001, v101); + const GLfloat temp11 = LERP(a, v011, v111); + const GLfloat temp0 = LERP(b, temp00, temp10); + const GLfloat temp1 = LERP(b, temp01, temp11); + return LERP(c, temp0, temp1); +} + + +/** + * Do linear interpolation of colors. + */ +static INLINE void +lerp_rgba(GLfloat result[4], GLfloat t, const GLfloat a[4], const GLfloat b[4]) +{ + result[0] = LERP(t, a[0], b[0]); + result[1] = LERP(t, a[1], b[1]); + result[2] = LERP(t, a[2], b[2]); + result[3] = LERP(t, a[3], b[3]); +} + + +/** + * Do bilinear interpolation of colors. + */ +static INLINE void +lerp_rgba_2d(GLfloat result[4], GLfloat a, GLfloat b, + const GLfloat t00[4], const GLfloat t10[4], + const GLfloat t01[4], const GLfloat t11[4]) +{ + result[0] = lerp_2d(a, b, t00[0], t10[0], t01[0], t11[0]); + result[1] = lerp_2d(a, b, t00[1], t10[1], t01[1], t11[1]); + result[2] = lerp_2d(a, b, t00[2], t10[2], t01[2], t11[2]); + result[3] = lerp_2d(a, b, t00[3], t10[3], t01[3], t11[3]); +} + + +/** + * Do trilinear interpolation of colors. + */ +static INLINE void +lerp_rgba_3d(GLfloat result[4], GLfloat a, GLfloat b, GLfloat c, + const GLfloat t000[4], const GLfloat t100[4], + const GLfloat t010[4], const GLfloat t110[4], + const GLfloat t001[4], const GLfloat t101[4], + const GLfloat t011[4], const GLfloat t111[4]) +{ + GLuint k; + /* compiler should unroll these short loops */ + for (k = 0; k < 4; k++) { + result[k] = lerp_3d(a, b, c, t000[k], t100[k], t010[k], t110[k], + t001[k], t101[k], t011[k], t111[k]); + } +} + + +/** + * Used for GL_REPEAT wrap mode. Using A % B doesn't produce the + * right results for A<0. Casting to A to be unsigned only works if B + * is a power of two. Adding a bias to A (which is a multiple of B) + * avoids the problems with A < 0 (for reasonable A) without using a + * conditional. + */ +#define REMAINDER(A, B) (((A) + (B) * 1024) % (B)) + + +/** + * Used to compute texel locations for linear sampling. + * Input: + * wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER + * s = texcoord in [0,1] + * size = width (or height or depth) of texture + * Output: + * i0, i1 = returns two nearest texel indexes + * weight = returns blend factor between texels + */ +static INLINE void +linear_texel_locations(GLenum wrapMode, + const struct gl_texture_image *img, + GLint size, GLfloat s, + GLint *i0, GLint *i1, GLfloat *weight) +{ + GLfloat u; + switch (wrapMode) { + case GL_REPEAT: + u = s * size - 0.5F; + if (img->_IsPowerOfTwo) { + *i0 = IFLOOR(u) & (size - 1); + *i1 = (*i0 + 1) & (size - 1); + } + else { + *i0 = REMAINDER(IFLOOR(u), size); + *i1 = REMAINDER(*i0 + 1, size); + } + break; + case GL_CLAMP_TO_EDGE: + if (s <= 0.0F) + u = 0.0F; + else if (s >= 1.0F) + u = (GLfloat) size; + else + u = s * size; + u -= 0.5F; + *i0 = IFLOOR(u); + *i1 = *i0 + 1; + if (*i0 < 0) + *i0 = 0; + if (*i1 >= (GLint) size) + *i1 = size - 1; + break; + case GL_CLAMP_TO_BORDER: + { + const GLfloat min = -1.0F / (2.0F * size); + const GLfloat max = 1.0F - min; + if (s <= min) + u = min * size; + else if (s >= max) + u = max * size; + else + u = s * size; + u -= 0.5F; + *i0 = IFLOOR(u); + *i1 = *i0 + 1; + } + break; + case GL_MIRRORED_REPEAT: + { + const GLint flr = IFLOOR(s); + if (flr & 1) + u = 1.0F - (s - (GLfloat) flr); + else + u = s - (GLfloat) flr; + u = (u * size) - 0.5F; + *i0 = IFLOOR(u); + *i1 = *i0 + 1; + if (*i0 < 0) + *i0 = 0; + if (*i1 >= (GLint) size) + *i1 = size - 1; + } + break; + case GL_MIRROR_CLAMP_EXT: + u = FABSF(s); + if (u >= 1.0F) + u = (GLfloat) size; + else + u *= size; + u -= 0.5F; + *i0 = IFLOOR(u); + *i1 = *i0 + 1; + break; + case GL_MIRROR_CLAMP_TO_EDGE_EXT: + u = FABSF(s); + if (u >= 1.0F) + u = (GLfloat) size; + else + u *= size; + u -= 0.5F; + *i0 = IFLOOR(u); + *i1 = *i0 + 1; + if (*i0 < 0) + *i0 = 0; + if (*i1 >= (GLint) size) + *i1 = size - 1; + break; + case GL_MIRROR_CLAMP_TO_BORDER_EXT: + { + const GLfloat min = -1.0F / (2.0F * size); + const GLfloat max = 1.0F - min; + u = FABSF(s); + if (u <= min) + u = min * size; + else if (u >= max) + u = max * size; + else + u *= size; + u -= 0.5F; + *i0 = IFLOOR(u); + *i1 = *i0 + 1; + } + break; + case GL_CLAMP: + if (s <= 0.0F) + u = 0.0F; + else if (s >= 1.0F) + u = (GLfloat) size; + else + u = s * size; + u -= 0.5F; + *i0 = IFLOOR(u); + *i1 = *i0 + 1; + break; + default: + _mesa_problem(NULL, "Bad wrap mode"); + u = 0.0F; + } + *weight = FRAC(u); +} + + +/** + * Used to compute texel location for nearest sampling. + */ +static INLINE GLint +nearest_texel_location(GLenum wrapMode, + const struct gl_texture_image *img, + GLint size, GLfloat s) +{ + GLint i; + + switch (wrapMode) { + case GL_REPEAT: + /* s limited to [0,1) */ + /* i limited to [0,size-1] */ + i = IFLOOR(s * size); + if (img->_IsPowerOfTwo) + i &= (size - 1); + else + i = REMAINDER(i, size); + return i; + case GL_CLAMP_TO_EDGE: + { + /* s limited to [min,max] */ + /* i limited to [0, size-1] */ + const GLfloat min = 1.0F / (2.0F * size); + const GLfloat max = 1.0F - min; + if (s < min) + i = 0; + else if (s > max) + i = size - 1; + else + i = IFLOOR(s * size); + } + return i; + case GL_CLAMP_TO_BORDER: + { + /* s limited to [min,max] */ + /* i limited to [-1, size] */ + const GLfloat min = -1.0F / (2.0F * size); + const GLfloat max = 1.0F - min; + if (s <= min) + i = -1; + else if (s >= max) + i = size; + else + i = IFLOOR(s * size); + } + return i; + case GL_MIRRORED_REPEAT: + { + const GLfloat min = 1.0F / (2.0F * size); + const GLfloat max = 1.0F - min; + const GLint flr = IFLOOR(s); + GLfloat u; + if (flr & 1) + u = 1.0F - (s - (GLfloat) flr); + else + u = s - (GLfloat) flr; + if (u < min) + i = 0; + else if (u > max) + i = size - 1; + else + i = IFLOOR(u * size); + } + return i; + case GL_MIRROR_CLAMP_EXT: + { + /* s limited to [0,1] */ + /* i limited to [0,size-1] */ + const GLfloat u = FABSF(s); + if (u <= 0.0F) + i = 0; + else if (u >= 1.0F) + i = size - 1; + else + i = IFLOOR(u * size); + } + return i; + case GL_MIRROR_CLAMP_TO_EDGE_EXT: + { + /* s limited to [min,max] */ + /* i limited to [0, size-1] */ + const GLfloat min = 1.0F / (2.0F * size); + const GLfloat max = 1.0F - min; + const GLfloat u = FABSF(s); + if (u < min) + i = 0; + else if (u > max) + i = size - 1; + else + i = IFLOOR(u * size); + } + return i; + case GL_MIRROR_CLAMP_TO_BORDER_EXT: + { + /* s limited to [min,max] */ + /* i limited to [0, size-1] */ + const GLfloat min = -1.0F / (2.0F * size); + const GLfloat max = 1.0F - min; + const GLfloat u = FABSF(s); + if (u < min) + i = -1; + else if (u > max) + i = size; + else + i = IFLOOR(u * size); + } + return i; + case GL_CLAMP: + /* s limited to [0,1] */ + /* i limited to [0,size-1] */ + if (s <= 0.0F) + i = 0; + else if (s >= 1.0F) + i = size - 1; + else + i = IFLOOR(s * size); + return i; + default: + _mesa_problem(NULL, "Bad wrap mode"); + return 0; + } +} + + +/* Power of two image sizes only */ +static INLINE void +linear_repeat_texel_location(GLuint size, GLfloat s, + GLint *i0, GLint *i1, GLfloat *weight) +{ + GLfloat u = s * size - 0.5F; + *i0 = IFLOOR(u) & (size - 1); + *i1 = (*i0 + 1) & (size - 1); + *weight = FRAC(u); +} + + +/** + * Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode. + */ +static INLINE GLint +clamp_rect_coord_nearest(GLenum wrapMode, GLfloat coord, GLint max) +{ + switch (wrapMode) { + case GL_CLAMP: + return IFLOOR( CLAMP(coord, 0.0F, max - 1) ); + case GL_CLAMP_TO_EDGE: + return IFLOOR( CLAMP(coord, 0.5F, max - 0.5F) ); + case GL_CLAMP_TO_BORDER: + return IFLOOR( CLAMP(coord, -0.5F, max + 0.5F) ); + default: + _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_nearest"); + return 0; + } +} + + +/** + * As above, but GL_LINEAR filtering. + */ +static INLINE void +clamp_rect_coord_linear(GLenum wrapMode, GLfloat coord, GLint max, + GLint *i0out, GLint *i1out, GLfloat *weight) +{ + GLfloat fcol; + GLint i0, i1; + switch (wrapMode) { + case GL_CLAMP: + /* Not exactly what the spec says, but it matches NVIDIA output */ + fcol = CLAMP(coord - 0.5F, 0.0F, max - 1); + i0 = IFLOOR(fcol); + i1 = i0 + 1; + break; + case GL_CLAMP_TO_EDGE: + fcol = CLAMP(coord, 0.5F, max - 0.5F); + fcol -= 0.5F; + i0 = IFLOOR(fcol); + i1 = i0 + 1; + if (i1 > max - 1) + i1 = max - 1; + break; + case GL_CLAMP_TO_BORDER: + fcol = CLAMP(coord, -0.5F, max + 0.5F); + fcol -= 0.5F; + i0 = IFLOOR(fcol); + i1 = i0 + 1; + break; + default: + _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_linear"); + i0 = i1 = 0; + fcol = 0.0F; + } + *i0out = i0; + *i1out = i1; + *weight = FRAC(fcol); +} + + +/** + * Compute slice/image to use for 1D or 2D array texture. + */ +static INLINE GLint +tex_array_slice(GLfloat coord, GLsizei size) +{ + GLint slice = IFLOOR(coord + 0.5f); + slice = CLAMP(slice, 0, size - 1); + return slice; +} + + +/** + * Compute nearest integer texcoords for given texobj and coordinate. + * NOTE: only used for depth texture sampling. + */ +static INLINE void +nearest_texcoord(const struct gl_texture_object *texObj, + GLuint level, + const GLfloat texcoord[4], + GLint *i, GLint *j, GLint *k) +{ + const struct gl_texture_image *img = texObj->Image[0][level]; + const GLint width = img->Width; + const GLint height = img->Height; + const GLint depth = img->Depth; + + switch (texObj->Target) { + case GL_TEXTURE_RECTANGLE_ARB: + *i = clamp_rect_coord_nearest(texObj->WrapS, texcoord[0], width); + *j = clamp_rect_coord_nearest(texObj->WrapT, texcoord[1], height); + *k = 0; + break; + case GL_TEXTURE_1D: + *i = nearest_texel_location(texObj->WrapS, img, width, texcoord[0]); + *j = 0; + *k = 0; + break; + case GL_TEXTURE_2D: + *i = nearest_texel_location(texObj->WrapS, img, width, texcoord[0]); + *j = nearest_texel_location(texObj->WrapT, img, height, texcoord[1]); + *k = 0; + break; + case GL_TEXTURE_1D_ARRAY_EXT: + *i = nearest_texel_location(texObj->WrapS, img, width, texcoord[0]); + *j = tex_array_slice(texcoord[1], height); + *k = 0; + break; + case GL_TEXTURE_2D_ARRAY_EXT: + *i = nearest_texel_location(texObj->WrapS, img, width, texcoord[0]); + *j = nearest_texel_location(texObj->WrapT, img, height, texcoord[1]); + *k = tex_array_slice(texcoord[2], depth); + break; + default: + *i = *j = *k = 0; + } +} + + +/** + * Compute linear integer texcoords for given texobj and coordinate. + * NOTE: only used for depth texture sampling. + */ +static INLINE void +linear_texcoord(const struct gl_texture_object *texObj, + GLuint level, + const GLfloat texcoord[4], + GLint *i0, GLint *i1, GLint *j0, GLint *j1, GLint *slice, + GLfloat *wi, GLfloat *wj) +{ + const struct gl_texture_image *img = texObj->Image[0][level]; + const GLint width = img->Width; + const GLint height = img->Height; + const GLint depth = img->Depth; + + switch (texObj->Target) { + case GL_TEXTURE_RECTANGLE_ARB: + clamp_rect_coord_linear(texObj->WrapS, texcoord[0], + width, i0, i1, wi); + clamp_rect_coord_linear(texObj->WrapT, texcoord[1], + height, j0, j1, wj); + *slice = 0; + break; + + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + linear_texel_locations(texObj->WrapS, img, width, + texcoord[0], i0, i1, wi); + linear_texel_locations(texObj->WrapT, img, height, + texcoord[1], j0, j1, wj); + *slice = 0; + break; + + case GL_TEXTURE_1D_ARRAY_EXT: + linear_texel_locations(texObj->WrapS, img, width, + texcoord[0], i0, i1, wi); + *j0 = tex_array_slice(texcoord[1], height); + *j1 = *j0; + *slice = 0; + break; + + case GL_TEXTURE_2D_ARRAY_EXT: + linear_texel_locations(texObj->WrapS, img, width, + texcoord[0], i0, i1, wi); + linear_texel_locations(texObj->WrapT, img, height, + texcoord[1], j0, j1, wj); + *slice = tex_array_slice(texcoord[2], depth); + break; + + default: + *slice = 0; + } +} + + + +/** + * For linear interpolation between mipmap levels N and N+1, this function + * computes N. + */ +static INLINE GLint +linear_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda) +{ + if (lambda < 0.0F) + return tObj->BaseLevel; + else if (lambda > tObj->_MaxLambda) + return (GLint) (tObj->BaseLevel + tObj->_MaxLambda); + else + return (GLint) (tObj->BaseLevel + lambda); +} + + +/** + * Compute the nearest mipmap level to take texels from. + */ +static INLINE GLint +nearest_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda) +{ + GLfloat l; + GLint level; + if (lambda <= 0.5F) + l = 0.0F; + else if (lambda > tObj->_MaxLambda + 0.4999F) + l = tObj->_MaxLambda + 0.4999F; + else + l = lambda; + level = (GLint) (tObj->BaseLevel + l + 0.5F); + if (level > tObj->_MaxLevel) + level = tObj->_MaxLevel; + return level; +} + + + +/* + * Bitflags for texture border color sampling. + */ +#define I0BIT 1 +#define I1BIT 2 +#define J0BIT 4 +#define J1BIT 8 +#define K0BIT 16 +#define K1BIT 32 + + + +/** + * The lambda[] array values are always monotonic. Either the whole span + * will be minified, magnified, or split between the two. This function + * determines the subranges in [0, n-1] that are to be minified or magnified. + */ +static INLINE void +compute_min_mag_ranges(const struct gl_texture_object *tObj, + GLuint n, const GLfloat lambda[], + GLuint *minStart, GLuint *minEnd, + GLuint *magStart, GLuint *magEnd) +{ + GLfloat minMagThresh; + + /* we shouldn't be here if minfilter == magfilter */ + ASSERT(tObj->MinFilter != tObj->MagFilter); + + /* This bit comes from the OpenGL spec: */ + if (tObj->MagFilter == GL_LINEAR + && (tObj->MinFilter == GL_NEAREST_MIPMAP_NEAREST || + tObj->MinFilter == GL_NEAREST_MIPMAP_LINEAR)) { + minMagThresh = 0.5F; + } + else { + minMagThresh = 0.0F; + } + +#if 0 + /* DEBUG CODE: Verify that lambda[] is monotonic. + * We can't really use this because the inaccuracy in the LOG2 function + * causes this test to fail, yet the resulting texturing is correct. + */ + if (n > 1) { + GLuint i; + printf("lambda delta = %g\n", lambda[0] - lambda[n-1]); + if (lambda[0] >= lambda[n-1]) { /* decreasing */ + for (i = 0; i < n - 1; i++) { + ASSERT((GLint) (lambda[i] * 10) >= (GLint) (lambda[i+1] * 10)); + } + } + else { /* increasing */ + for (i = 0; i < n - 1; i++) { + ASSERT((GLint) (lambda[i] * 10) <= (GLint) (lambda[i+1] * 10)); + } + } + } +#endif /* DEBUG */ + + if (lambda[0] <= minMagThresh && (n <= 1 || lambda[n-1] <= minMagThresh)) { + /* magnification for whole span */ + *magStart = 0; + *magEnd = n; + *minStart = *minEnd = 0; + } + else if (lambda[0] > minMagThresh && (n <=1 || lambda[n-1] > minMagThresh)) { + /* minification for whole span */ + *minStart = 0; + *minEnd = n; + *magStart = *magEnd = 0; + } + else { + /* a mix of minification and magnification */ + GLuint i; + if (lambda[0] > minMagThresh) { + /* start with minification */ + for (i = 1; i < n; i++) { + if (lambda[i] <= minMagThresh) + break; + } + *minStart = 0; + *minEnd = i; + *magStart = i; + *magEnd = n; + } + else { + /* start with magnification */ + for (i = 1; i < n; i++) { + if (lambda[i] > minMagThresh) + break; + } + *magStart = 0; + *magEnd = i; + *minStart = i; + *minEnd = n; + } + } + +#if 0 + /* Verify the min/mag Start/End values + * We don't use this either (see above) + */ + { + GLint i; + for (i = 0; i < n; i++) { + if (lambda[i] > minMagThresh) { + /* minification */ + ASSERT(i >= *minStart); + ASSERT(i < *minEnd); + } + else { + /* magnification */ + ASSERT(i >= *magStart); + ASSERT(i < *magEnd); + } + } + } +#endif +} + + +/** + * When we sample the border color, it must be interpreted according to + * the base texture format. Ex: if the texture base format it GL_ALPHA, + * we return (0,0,0,BorderAlpha). + */ +static INLINE void +get_border_color(const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + GLfloat rgba[4]) +{ + switch (img->_BaseFormat) { + case GL_RGB: + rgba[0] = tObj->BorderColor.f[0]; + rgba[1] = tObj->BorderColor.f[1]; + rgba[2] = tObj->BorderColor.f[2]; + rgba[3] = 1.0F; + break; + case GL_ALPHA: + rgba[0] = rgba[1] = rgba[2] = 0.0; + rgba[3] = tObj->BorderColor.f[3]; + break; + case GL_LUMINANCE: + rgba[0] = rgba[1] = rgba[2] = tObj->BorderColor.f[0]; + rgba[3] = 1.0; + break; + case GL_LUMINANCE_ALPHA: + rgba[0] = rgba[1] = rgba[2] = tObj->BorderColor.f[0]; + rgba[3] = tObj->BorderColor.f[3]; + break; + case GL_INTENSITY: + rgba[0] = rgba[1] = rgba[2] = rgba[3] = tObj->BorderColor.f[0]; + break; + default: + COPY_4V(rgba, tObj->BorderColor.f); + } +} + + +/**********************************************************************/ +/* 1-D Texture Sampling Functions */ +/**********************************************************************/ + +/** + * Return the texture sample for coordinate (s) using GL_NEAREST filter. + */ +static INLINE void +sample_1d_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], GLfloat rgba[4]) +{ + const GLint width = img->Width2; /* without border, power of two */ + GLint i; + i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); + /* skip over the border, if any */ + i += img->Border; + if (i < 0 || i >= (GLint) img->Width) { + /* Need this test for GL_CLAMP_TO_BORDER mode */ + get_border_color(tObj, img, rgba); + } + else { + img->FetchTexelf(img, i, 0, 0, rgba); + } +} + + +/** + * Return the texture sample for coordinate (s) using GL_LINEAR filter. + */ +static INLINE void +sample_1d_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], GLfloat rgba[4]) +{ + const GLint width = img->Width2; + GLint i0, i1; + GLbitfield useBorderColor = 0x0; + GLfloat a; + GLfloat t0[4], t1[4]; /* texels */ + + linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); + + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + } + else { + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + } + + /* fetch texel colors */ + if (useBorderColor & I0BIT) { + get_border_color(tObj, img, t0); + } + else { + img->FetchTexelf(img, i0, 0, 0, t0); + } + if (useBorderColor & I1BIT) { + get_border_color(tObj, img, t1); + } + else { + img->FetchTexelf(img, i1, 0, 0, t1); + } + + lerp_rgba(rgba, a, t0, t1); +} + + +static void +sample_1d_nearest_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_1d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); + } +} + + +static void +sample_1d_linear_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_1d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); + } +} + + +static void +sample_1d_nearest_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; + const GLfloat f = FRAC(lambda[i]); + sample_1d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_1d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +static void +sample_1d_linear_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; + const GLfloat f = FRAC(lambda[i]); + sample_1d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_1d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +/** Sample 1D texture, nearest filtering for both min/magnification */ +static void +sample_nearest_1d( struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4] ) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_1d_nearest(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 1D texture, linear filtering for both min/magnification */ +static void +sample_linear_1d( struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4] ) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_1d_linear(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 1D texture, using lambda to choose between min/magnification */ +static void +sample_lambda_1d( struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4] ) +{ + GLuint minStart, minEnd; /* texels with minification */ + GLuint magStart, magEnd; /* texels with magnification */ + GLuint i; + + ASSERT(lambda != NULL); + compute_min_mag_ranges(tObj, n, lambda, + &minStart, &minEnd, &magStart, &magEnd); + + if (minStart < minEnd) { + /* do the minified texels */ + const GLuint m = minEnd - minStart; + switch (tObj->MinFilter) { + case GL_NEAREST: + for (i = minStart; i < minEnd; i++) + sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = minStart; i < minEnd; i++) + sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_1d_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_1d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_1d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_LINEAR: + sample_1d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + default: + _mesa_problem(ctx, "Bad min filter in sample_1d_texture"); + return; + } + } + + if (magStart < magEnd) { + /* do the magnified texels */ + switch (tObj->MagFilter) { + case GL_NEAREST: + for (i = magStart; i < magEnd; i++) + sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = magStart; i < magEnd; i++) + sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + default: + _mesa_problem(ctx, "Bad mag filter in sample_1d_texture"); + return; + } + } +} + + +/**********************************************************************/ +/* 2-D Texture Sampling Functions */ +/**********************************************************************/ + + +/** + * Return the texture sample for coordinate (s,t) using GL_NEAREST filter. + */ +static INLINE void +sample_2d_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[]) +{ + const GLint width = img->Width2; /* without border, power of two */ + const GLint height = img->Height2; /* without border, power of two */ + GLint i, j; + (void) ctx; + + i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); + j = nearest_texel_location(tObj->WrapT, img, height, texcoord[1]); + + /* skip over the border, if any */ + i += img->Border; + j += img->Border; + + if (i < 0 || i >= (GLint) img->Width || j < 0 || j >= (GLint) img->Height) { + /* Need this test for GL_CLAMP_TO_BORDER mode */ + get_border_color(tObj, img, rgba); + } + else { + img->FetchTexelf(img, i, j, 0, rgba); + } +} + + +/** + * Return the texture sample for coordinate (s,t) using GL_LINEAR filter. + * New sampling code contributed by Lynn Quam . + */ +static INLINE void +sample_2d_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[]) +{ + const GLint width = img->Width2; + const GLint height = img->Height2; + GLint i0, j0, i1, j1; + GLbitfield useBorderColor = 0x0; + GLfloat a, b; + GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */ + + linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); + linear_texel_locations(tObj->WrapT, img, height, texcoord[1], &j0, &j1, &b); + + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + j0 += img->Border; + j1 += img->Border; + } + else { + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; + if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; + } + + /* fetch four texel colors */ + if (useBorderColor & (I0BIT | J0BIT)) { + get_border_color(tObj, img, t00); + } + else { + img->FetchTexelf(img, i0, j0, 0, t00); + } + if (useBorderColor & (I1BIT | J0BIT)) { + get_border_color(tObj, img, t10); + } + else { + img->FetchTexelf(img, i1, j0, 0, t10); + } + if (useBorderColor & (I0BIT | J1BIT)) { + get_border_color(tObj, img, t01); + } + else { + img->FetchTexelf(img, i0, j1, 0, t01); + } + if (useBorderColor & (I1BIT | J1BIT)) { + get_border_color(tObj, img, t11); + } + else { + img->FetchTexelf(img, i1, j1, 0, t11); + } + + lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11); +} + + +/** + * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT. + * We don't have to worry about the texture border. + */ +static INLINE void +sample_2d_linear_repeat(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[]) +{ + const GLint width = img->Width2; + const GLint height = img->Height2; + GLint i0, j0, i1, j1; + GLfloat wi, wj; + GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */ + + (void) ctx; + + ASSERT(tObj->WrapS == GL_REPEAT); + ASSERT(tObj->WrapT == GL_REPEAT); + ASSERT(img->Border == 0); + ASSERT(img->_BaseFormat != GL_COLOR_INDEX); + ASSERT(img->_IsPowerOfTwo); + + linear_repeat_texel_location(width, texcoord[0], &i0, &i1, &wi); + linear_repeat_texel_location(height, texcoord[1], &j0, &j1, &wj); + + img->FetchTexelf(img, i0, j0, 0, t00); + img->FetchTexelf(img, i1, j0, 0, t10); + img->FetchTexelf(img, i0, j1, 0, t01); + img->FetchTexelf(img, i1, j1, 0, t11); + + lerp_rgba_2d(rgba, wi, wj, t00, t10, t01, t11); +} + + +static void +sample_2d_nearest_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_2d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); + } +} + + +static void +sample_2d_linear_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_2d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); + } +} + + +static void +sample_2d_nearest_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_2d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_2d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_2d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +static void +sample_2d_linear_mipmap_linear( struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4] ) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_2d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_2d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_2d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +static void +sample_2d_linear_mipmap_linear_repeat(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + ASSERT(tObj->WrapS == GL_REPEAT); + ASSERT(tObj->WrapT == GL_REPEAT); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][level ], + texcoord[i], t0); + sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][level+1], + texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +/** Sample 2D texture, nearest filtering for both min/magnification */ +static void +sample_nearest_2d(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_2d_nearest(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 2D texture, linear filtering for both min/magnification */ +static void +sample_linear_2d(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + if (tObj->WrapS == GL_REPEAT && + tObj->WrapT == GL_REPEAT && + image->_IsPowerOfTwo && + image->Border == 0) { + for (i = 0; i < n; i++) { + sample_2d_linear_repeat(ctx, tObj, image, texcoords[i], rgba[i]); + } + } + else { + for (i = 0; i < n; i++) { + sample_2d_linear(ctx, tObj, image, texcoords[i], rgba[i]); + } + } +} + + +/** + * Optimized 2-D texture sampling: + * S and T wrap mode == GL_REPEAT + * GL_NEAREST min/mag filter + * No border, + * RowStride == Width, + * Format = GL_RGB + */ +static void +opt_sample_rgb_2d(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel]; + const GLfloat width = (GLfloat) img->Width; + const GLfloat height = (GLfloat) img->Height; + const GLint colMask = img->Width - 1; + const GLint rowMask = img->Height - 1; + const GLint shift = img->WidthLog2; + GLuint k; + (void) ctx; + (void) lambda; + ASSERT(tObj->WrapS==GL_REPEAT); + ASSERT(tObj->WrapT==GL_REPEAT); + ASSERT(img->Border==0); + ASSERT(img->TexFormat == MESA_FORMAT_RGB888); + ASSERT(img->_IsPowerOfTwo); + + for (k=0; kData) + 3*pos; + rgba[k][RCOMP] = UBYTE_TO_FLOAT(texel[2]); + rgba[k][GCOMP] = UBYTE_TO_FLOAT(texel[1]); + rgba[k][BCOMP] = UBYTE_TO_FLOAT(texel[0]); + rgba[k][ACOMP] = 1.0F; + } +} + + +/** + * Optimized 2-D texture sampling: + * S and T wrap mode == GL_REPEAT + * GL_NEAREST min/mag filter + * No border + * RowStride == Width, + * Format = GL_RGBA + */ +static void +opt_sample_rgba_2d(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel]; + const GLfloat width = (GLfloat) img->Width; + const GLfloat height = (GLfloat) img->Height; + const GLint colMask = img->Width - 1; + const GLint rowMask = img->Height - 1; + const GLint shift = img->WidthLog2; + GLuint i; + (void) ctx; + (void) lambda; + ASSERT(tObj->WrapS==GL_REPEAT); + ASSERT(tObj->WrapT==GL_REPEAT); + ASSERT(img->Border==0); + ASSERT(img->TexFormat == MESA_FORMAT_RGBA8888); + ASSERT(img->_IsPowerOfTwo); + + for (i = 0; i < n; i++) { + const GLint col = IFLOOR(texcoords[i][0] * width) & colMask; + const GLint row = IFLOOR(texcoords[i][1] * height) & rowMask; + const GLint pos = (row << shift) | col; + const GLuint texel = *((GLuint *) img->Data + pos); + rgba[i][RCOMP] = UBYTE_TO_FLOAT( (texel >> 24) ); + rgba[i][GCOMP] = UBYTE_TO_FLOAT( (texel >> 16) & 0xff ); + rgba[i][BCOMP] = UBYTE_TO_FLOAT( (texel >> 8) & 0xff ); + rgba[i][ACOMP] = UBYTE_TO_FLOAT( (texel ) & 0xff ); + } +} + + +/** Sample 2D texture, using lambda to choose between min/magnification */ +static void +sample_lambda_2d(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel]; + GLuint minStart, minEnd; /* texels with minification */ + GLuint magStart, magEnd; /* texels with magnification */ + + const GLboolean repeatNoBorderPOT = (tObj->WrapS == GL_REPEAT) + && (tObj->WrapT == GL_REPEAT) + && (tImg->Border == 0 && (tImg->Width == tImg->RowStride)) + && (tImg->_BaseFormat != GL_COLOR_INDEX) + && tImg->_IsPowerOfTwo; + + ASSERT(lambda != NULL); + compute_min_mag_ranges(tObj, n, lambda, + &minStart, &minEnd, &magStart, &magEnd); + + if (minStart < minEnd) { + /* do the minified texels */ + const GLuint m = minEnd - minStart; + switch (tObj->MinFilter) { + case GL_NEAREST: + if (repeatNoBorderPOT) { + switch (tImg->TexFormat) { + case MESA_FORMAT_RGB888: + opt_sample_rgb_2d(ctx, tObj, m, texcoords + minStart, + NULL, rgba + minStart); + break; + case MESA_FORMAT_RGBA8888: + opt_sample_rgba_2d(ctx, tObj, m, texcoords + minStart, + NULL, rgba + minStart); + break; + default: + sample_nearest_2d(ctx, tObj, m, texcoords + minStart, + NULL, rgba + minStart ); + } + } + else { + sample_nearest_2d(ctx, tObj, m, texcoords + minStart, + NULL, rgba + minStart); + } + break; + case GL_LINEAR: + sample_linear_2d(ctx, tObj, m, texcoords + minStart, + NULL, rgba + minStart); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_2d_nearest_mipmap_nearest(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_2d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_2d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_LINEAR: + if (repeatNoBorderPOT) + sample_2d_linear_mipmap_linear_repeat(ctx, tObj, m, + texcoords + minStart, lambda + minStart, rgba + minStart); + else + sample_2d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + default: + _mesa_problem(ctx, "Bad min filter in sample_2d_texture"); + return; + } + } + + if (magStart < magEnd) { + /* do the magnified texels */ + const GLuint m = magEnd - magStart; + + switch (tObj->MagFilter) { + case GL_NEAREST: + if (repeatNoBorderPOT) { + switch (tImg->TexFormat) { + case MESA_FORMAT_RGB888: + opt_sample_rgb_2d(ctx, tObj, m, texcoords + magStart, + NULL, rgba + magStart); + break; + case MESA_FORMAT_RGBA8888: + opt_sample_rgba_2d(ctx, tObj, m, texcoords + magStart, + NULL, rgba + magStart); + break; + default: + sample_nearest_2d(ctx, tObj, m, texcoords + magStart, + NULL, rgba + magStart ); + } + } + else { + sample_nearest_2d(ctx, tObj, m, texcoords + magStart, + NULL, rgba + magStart); + } + break; + case GL_LINEAR: + sample_linear_2d(ctx, tObj, m, texcoords + magStart, + NULL, rgba + magStart); + break; + default: + _mesa_problem(ctx, "Bad mag filter in sample_lambda_2d"); + } + } +} + + + +/**********************************************************************/ +/* 3-D Texture Sampling Functions */ +/**********************************************************************/ + +/** + * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. + */ +static INLINE void +sample_3d_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[4]) +{ + const GLint width = img->Width2; /* without border, power of two */ + const GLint height = img->Height2; /* without border, power of two */ + const GLint depth = img->Depth2; /* without border, power of two */ + GLint i, j, k; + (void) ctx; + + i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); + j = nearest_texel_location(tObj->WrapT, img, height, texcoord[1]); + k = nearest_texel_location(tObj->WrapR, img, depth, texcoord[2]); + + if (i < 0 || i >= (GLint) img->Width || + j < 0 || j >= (GLint) img->Height || + k < 0 || k >= (GLint) img->Depth) { + /* Need this test for GL_CLAMP_TO_BORDER mode */ + get_border_color(tObj, img, rgba); + } + else { + img->FetchTexelf(img, i, j, k, rgba); + } +} + + +/** + * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. + */ +static void +sample_3d_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[4]) +{ + const GLint width = img->Width2; + const GLint height = img->Height2; + const GLint depth = img->Depth2; + GLint i0, j0, k0, i1, j1, k1; + GLbitfield useBorderColor = 0x0; + GLfloat a, b, c; + GLfloat t000[4], t010[4], t001[4], t011[4]; + GLfloat t100[4], t110[4], t101[4], t111[4]; + + linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); + linear_texel_locations(tObj->WrapT, img, height, texcoord[1], &j0, &j1, &b); + linear_texel_locations(tObj->WrapR, img, depth, texcoord[2], &k0, &k1, &c); + + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + j0 += img->Border; + j1 += img->Border; + k0 += img->Border; + k1 += img->Border; + } + else { + /* check if sampling texture border color */ + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; + if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; + if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT; + if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT; + } + + /* Fetch texels */ + if (useBorderColor & (I0BIT | J0BIT | K0BIT)) { + get_border_color(tObj, img, t000); + } + else { + img->FetchTexelf(img, i0, j0, k0, t000); + } + if (useBorderColor & (I1BIT | J0BIT | K0BIT)) { + get_border_color(tObj, img, t100); + } + else { + img->FetchTexelf(img, i1, j0, k0, t100); + } + if (useBorderColor & (I0BIT | J1BIT | K0BIT)) { + get_border_color(tObj, img, t010); + } + else { + img->FetchTexelf(img, i0, j1, k0, t010); + } + if (useBorderColor & (I1BIT | J1BIT | K0BIT)) { + get_border_color(tObj, img, t110); + } + else { + img->FetchTexelf(img, i1, j1, k0, t110); + } + + if (useBorderColor & (I0BIT | J0BIT | K1BIT)) { + get_border_color(tObj, img, t001); + } + else { + img->FetchTexelf(img, i0, j0, k1, t001); + } + if (useBorderColor & (I1BIT | J0BIT | K1BIT)) { + get_border_color(tObj, img, t101); + } + else { + img->FetchTexelf(img, i1, j0, k1, t101); + } + if (useBorderColor & (I0BIT | J1BIT | K1BIT)) { + get_border_color(tObj, img, t011); + } + else { + img->FetchTexelf(img, i0, j1, k1, t011); + } + if (useBorderColor & (I1BIT | J1BIT | K1BIT)) { + get_border_color(tObj, img, t111); + } + else { + img->FetchTexelf(img, i1, j1, k1, t111); + } + + /* trilinear interpolation of samples */ + lerp_rgba_3d(rgba, a, b, c, t000, t100, t010, t110, t001, t101, t011, t111); +} + + +static void +sample_3d_nearest_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4] ) +{ + GLuint i; + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_3d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); + } +} + + +static void +sample_3d_linear_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_3d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); + } +} + + +static void +sample_3d_nearest_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_3d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_3d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +static void +sample_3d_linear_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_3d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_3d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +/** Sample 3D texture, nearest filtering for both min/magnification */ +static void +sample_nearest_3d(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_3d_nearest(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 3D texture, linear filtering for both min/magnification */ +static void +sample_linear_3d(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_3d_linear(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 3D texture, using lambda to choose between min/magnification */ +static void +sample_lambda_3d(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint minStart, minEnd; /* texels with minification */ + GLuint magStart, magEnd; /* texels with magnification */ + GLuint i; + + ASSERT(lambda != NULL); + compute_min_mag_ranges(tObj, n, lambda, + &minStart, &minEnd, &magStart, &magEnd); + + if (minStart < minEnd) { + /* do the minified texels */ + GLuint m = minEnd - minStart; + switch (tObj->MinFilter) { + case GL_NEAREST: + for (i = minStart; i < minEnd; i++) + sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = minStart; i < minEnd; i++) + sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_3d_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_3d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_3d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_LINEAR: + sample_3d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + default: + _mesa_problem(ctx, "Bad min filter in sample_3d_texture"); + return; + } + } + + if (magStart < magEnd) { + /* do the magnified texels */ + switch (tObj->MagFilter) { + case GL_NEAREST: + for (i = magStart; i < magEnd; i++) + sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = magStart; i < magEnd; i++) + sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + default: + _mesa_problem(ctx, "Bad mag filter in sample_3d_texture"); + return; + } + } +} + + +/**********************************************************************/ +/* Texture Cube Map Sampling Functions */ +/**********************************************************************/ + +/** + * Choose one of six sides of a texture cube map given the texture + * coord (rx,ry,rz). Return pointer to corresponding array of texture + * images. + */ +static const struct gl_texture_image ** +choose_cube_face(const struct gl_texture_object *texObj, + const GLfloat texcoord[4], GLfloat newCoord[4]) +{ + /* + major axis + direction target sc tc ma + ---------- ------------------------------- --- --- --- + +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx + -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx + +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry + -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry + +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz + -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz + */ + const GLfloat rx = texcoord[0]; + const GLfloat ry = texcoord[1]; + const GLfloat rz = texcoord[2]; + const GLfloat arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz); + GLuint face; + GLfloat sc, tc, ma; + + if (arx >= ary && arx >= arz) { + if (rx >= 0.0F) { + face = FACE_POS_X; + sc = -rz; + tc = -ry; + ma = arx; + } + else { + face = FACE_NEG_X; + sc = rz; + tc = -ry; + ma = arx; + } + } + else if (ary >= arx && ary >= arz) { + if (ry >= 0.0F) { + face = FACE_POS_Y; + sc = rx; + tc = rz; + ma = ary; + } + else { + face = FACE_NEG_Y; + sc = rx; + tc = -rz; + ma = ary; + } + } + else { + if (rz > 0.0F) { + face = FACE_POS_Z; + sc = rx; + tc = -ry; + ma = arz; + } + else { + face = FACE_NEG_Z; + sc = -rx; + tc = -ry; + ma = arz; + } + } + + { + const float ima = 1.0F / ma; + newCoord[0] = ( sc * ima + 1.0F ) * 0.5F; + newCoord[1] = ( tc * ima + 1.0F ) * 0.5F; + } + + return (const struct gl_texture_image **) texObj->Image[face]; +} + + +static void +sample_nearest_cube(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint i; + (void) lambda; + for (i = 0; i < n; i++) { + const struct gl_texture_image **images; + GLfloat newCoord[4]; + images = choose_cube_face(tObj, texcoords[i], newCoord); + sample_2d_nearest(ctx, tObj, images[tObj->BaseLevel], + newCoord, rgba[i]); + } +} + + +static void +sample_linear_cube(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + (void) lambda; + for (i = 0; i < n; i++) { + const struct gl_texture_image **images; + GLfloat newCoord[4]; + images = choose_cube_face(tObj, texcoords[i], newCoord); + sample_2d_linear(ctx, tObj, images[tObj->BaseLevel], + newCoord, rgba[i]); + } +} + + +static void +sample_cube_nearest_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + const struct gl_texture_image **images; + GLfloat newCoord[4]; + GLint level; + images = choose_cube_face(tObj, texcoord[i], newCoord); + + /* XXX we actually need to recompute lambda here based on the newCoords. + * But we would need the texcoords of adjacent fragments to compute that + * properly, and we don't have those here. + * For now, do an approximation: subtracting 1 from the chosen mipmap + * level seems to work in some test cases. + * The same adjustment is done in the next few functions. + */ + level = nearest_mipmap_level(tObj, lambda[i]); + level = MAX2(level - 1, 0); + + sample_2d_nearest(ctx, tObj, images[level], newCoord, rgba[i]); + } +} + + +static void +sample_cube_linear_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + const struct gl_texture_image **images; + GLfloat newCoord[4]; + GLint level = nearest_mipmap_level(tObj, lambda[i]); + level = MAX2(level - 1, 0); /* see comment above */ + images = choose_cube_face(tObj, texcoord[i], newCoord); + sample_2d_linear(ctx, tObj, images[level], newCoord, rgba[i]); + } +} + + +static void +sample_cube_nearest_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + const struct gl_texture_image **images; + GLfloat newCoord[4]; + GLint level = linear_mipmap_level(tObj, lambda[i]); + level = MAX2(level - 1, 0); /* see comment above */ + images = choose_cube_face(tObj, texcoord[i], newCoord); + if (level >= tObj->_MaxLevel) { + sample_2d_nearest(ctx, tObj, images[tObj->_MaxLevel], + newCoord, rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_2d_nearest(ctx, tObj, images[level ], newCoord, t0); + sample_2d_nearest(ctx, tObj, images[level+1], newCoord, t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +static void +sample_cube_linear_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + const struct gl_texture_image **images; + GLfloat newCoord[4]; + GLint level = linear_mipmap_level(tObj, lambda[i]); + level = MAX2(level - 1, 0); /* see comment above */ + images = choose_cube_face(tObj, texcoord[i], newCoord); + if (level >= tObj->_MaxLevel) { + sample_2d_linear(ctx, tObj, images[tObj->_MaxLevel], + newCoord, rgba[i]); + } + else { + GLfloat t0[4], t1[4]; + const GLfloat f = FRAC(lambda[i]); + sample_2d_linear(ctx, tObj, images[level ], newCoord, t0); + sample_2d_linear(ctx, tObj, images[level+1], newCoord, t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +/** Sample cube texture, using lambda to choose between min/magnification */ +static void +sample_lambda_cube(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint minStart, minEnd; /* texels with minification */ + GLuint magStart, magEnd; /* texels with magnification */ + + ASSERT(lambda != NULL); + compute_min_mag_ranges(tObj, n, lambda, + &minStart, &minEnd, &magStart, &magEnd); + + if (minStart < minEnd) { + /* do the minified texels */ + const GLuint m = minEnd - minStart; + switch (tObj->MinFilter) { + case GL_NEAREST: + sample_nearest_cube(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR: + sample_linear_cube(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_cube_nearest_mipmap_nearest(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_cube_linear_mipmap_nearest(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_cube_nearest_mipmap_linear(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_LINEAR: + sample_cube_linear_mipmap_linear(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + default: + _mesa_problem(ctx, "Bad min filter in sample_lambda_cube"); + } + } + + if (magStart < magEnd) { + /* do the magnified texels */ + const GLuint m = magEnd - magStart; + switch (tObj->MagFilter) { + case GL_NEAREST: + sample_nearest_cube(ctx, tObj, m, texcoords + magStart, + lambda + magStart, rgba + magStart); + break; + case GL_LINEAR: + sample_linear_cube(ctx, tObj, m, texcoords + magStart, + lambda + magStart, rgba + magStart); + break; + default: + _mesa_problem(ctx, "Bad mag filter in sample_lambda_cube"); + } + } +} + + +/**********************************************************************/ +/* Texture Rectangle Sampling Functions */ +/**********************************************************************/ + + +static void +sample_nearest_rect(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + const struct gl_texture_image *img = tObj->Image[0][0]; + const GLint width = img->Width; + const GLint height = img->Height; + GLuint i; + + (void) ctx; + (void) lambda; + + ASSERT(tObj->WrapS == GL_CLAMP || + tObj->WrapS == GL_CLAMP_TO_EDGE || + tObj->WrapS == GL_CLAMP_TO_BORDER); + ASSERT(tObj->WrapT == GL_CLAMP || + tObj->WrapT == GL_CLAMP_TO_EDGE || + tObj->WrapT == GL_CLAMP_TO_BORDER); + ASSERT(img->_BaseFormat != GL_COLOR_INDEX); + + for (i = 0; i < n; i++) { + GLint row, col; + col = clamp_rect_coord_nearest(tObj->WrapS, texcoords[i][0], width); + row = clamp_rect_coord_nearest(tObj->WrapT, texcoords[i][1], height); + if (col < 0 || col >= width || row < 0 || row >= height) + get_border_color(tObj, img, rgba[i]); + else + img->FetchTexelf(img, col, row, 0, rgba[i]); + } +} + + +static void +sample_linear_rect(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + const struct gl_texture_image *img = tObj->Image[0][0]; + const GLint width = img->Width; + const GLint height = img->Height; + GLuint i; + + (void) ctx; + (void) lambda; + + ASSERT(tObj->WrapS == GL_CLAMP || + tObj->WrapS == GL_CLAMP_TO_EDGE || + tObj->WrapS == GL_CLAMP_TO_BORDER); + ASSERT(tObj->WrapT == GL_CLAMP || + tObj->WrapT == GL_CLAMP_TO_EDGE || + tObj->WrapT == GL_CLAMP_TO_BORDER); + ASSERT(img->_BaseFormat != GL_COLOR_INDEX); + + for (i = 0; i < n; i++) { + GLint i0, j0, i1, j1; + GLfloat t00[4], t01[4], t10[4], t11[4]; + GLfloat a, b; + GLbitfield useBorderColor = 0x0; + + clamp_rect_coord_linear(tObj->WrapS, texcoords[i][0], width, + &i0, &i1, &a); + clamp_rect_coord_linear(tObj->WrapT, texcoords[i][1], height, + &j0, &j1, &b); + + /* compute integer rows/columns */ + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; + if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; + + /* get four texel samples */ + if (useBorderColor & (I0BIT | J0BIT)) + get_border_color(tObj, img, t00); + else + img->FetchTexelf(img, i0, j0, 0, t00); + + if (useBorderColor & (I1BIT | J0BIT)) + get_border_color(tObj, img, t10); + else + img->FetchTexelf(img, i1, j0, 0, t10); + + if (useBorderColor & (I0BIT | J1BIT)) + get_border_color(tObj, img, t01); + else + img->FetchTexelf(img, i0, j1, 0, t01); + + if (useBorderColor & (I1BIT | J1BIT)) + get_border_color(tObj, img, t11); + else + img->FetchTexelf(img, i1, j1, 0, t11); + + lerp_rgba_2d(rgba[i], a, b, t00, t10, t01, t11); + } +} + + +/** Sample Rect texture, using lambda to choose between min/magnification */ +static void +sample_lambda_rect(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint minStart, minEnd, magStart, magEnd; + + /* We only need lambda to decide between minification and magnification. + * There is no mipmapping with rectangular textures. + */ + compute_min_mag_ranges(tObj, n, lambda, + &minStart, &minEnd, &magStart, &magEnd); + + if (minStart < minEnd) { + if (tObj->MinFilter == GL_NEAREST) { + sample_nearest_rect(ctx, tObj, minEnd - minStart, + texcoords + minStart, NULL, rgba + minStart); + } + else { + sample_linear_rect(ctx, tObj, minEnd - minStart, + texcoords + minStart, NULL, rgba + minStart); + } + } + if (magStart < magEnd) { + if (tObj->MagFilter == GL_NEAREST) { + sample_nearest_rect(ctx, tObj, magEnd - magStart, + texcoords + magStart, NULL, rgba + magStart); + } + else { + sample_linear_rect(ctx, tObj, magEnd - magStart, + texcoords + magStart, NULL, rgba + magStart); + } + } +} + + +/**********************************************************************/ +/* 2D Texture Array Sampling Functions */ +/**********************************************************************/ + +/** + * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. + */ +static void +sample_2d_array_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[4]) +{ + const GLint width = img->Width2; /* without border, power of two */ + const GLint height = img->Height2; /* without border, power of two */ + const GLint depth = img->Depth; + GLint i, j; + GLint array; + (void) ctx; + + i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); + j = nearest_texel_location(tObj->WrapT, img, height, texcoord[1]); + array = tex_array_slice(texcoord[2], depth); + + if (i < 0 || i >= (GLint) img->Width || + j < 0 || j >= (GLint) img->Height || + array < 0 || array >= (GLint) img->Depth) { + /* Need this test for GL_CLAMP_TO_BORDER mode */ + get_border_color(tObj, img, rgba); + } + else { + img->FetchTexelf(img, i, j, array, rgba); + } +} + + +/** + * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. + */ +static void +sample_2d_array_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[4]) +{ + const GLint width = img->Width2; + const GLint height = img->Height2; + const GLint depth = img->Depth; + GLint i0, j0, i1, j1; + GLint array; + GLbitfield useBorderColor = 0x0; + GLfloat a, b; + GLfloat t00[4], t01[4], t10[4], t11[4]; + + linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); + linear_texel_locations(tObj->WrapT, img, height, texcoord[1], &j0, &j1, &b); + array = tex_array_slice(texcoord[2], depth); + + if (array < 0 || array >= depth) { + COPY_4V(rgba, tObj->BorderColor.f); + } + else { + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + j0 += img->Border; + j1 += img->Border; + } + else { + /* check if sampling texture border color */ + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; + if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; + } + + /* Fetch texels */ + if (useBorderColor & (I0BIT | J0BIT)) { + get_border_color(tObj, img, t00); + } + else { + img->FetchTexelf(img, i0, j0, array, t00); + } + if (useBorderColor & (I1BIT | J0BIT)) { + get_border_color(tObj, img, t10); + } + else { + img->FetchTexelf(img, i1, j0, array, t10); + } + if (useBorderColor & (I0BIT | J1BIT)) { + get_border_color(tObj, img, t01); + } + else { + img->FetchTexelf(img, i0, j1, array, t01); + } + if (useBorderColor & (I1BIT | J1BIT)) { + get_border_color(tObj, img, t11); + } + else { + img->FetchTexelf(img, i1, j1, array, t11); + } + + /* trilinear interpolation of samples */ + lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11); + } +} + + +static void +sample_2d_array_nearest_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], + rgba[i]); + } +} + + +static void +sample_2d_array_linear_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_2d_array_linear(ctx, tObj, tObj->Image[0][level], + texcoord[i], rgba[i]); + } +} + + +static void +sample_2d_array_nearest_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level ], + texcoord[i], t0); + sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level+1], + texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +static void +sample_2d_array_linear_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_2d_array_linear(ctx, tObj, tObj->Image[0][level ], + texcoord[i], t0); + sample_2d_array_linear(ctx, tObj, tObj->Image[0][level+1], + texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +/** Sample 2D Array texture, nearest filtering for both min/magnification */ +static void +sample_nearest_2d_array(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_2d_array_nearest(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + + +/** Sample 2D Array texture, linear filtering for both min/magnification */ +static void +sample_linear_2d_array(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_2d_array_linear(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 2D Array texture, using lambda to choose between min/magnification */ +static void +sample_lambda_2d_array(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint minStart, minEnd; /* texels with minification */ + GLuint magStart, magEnd; /* texels with magnification */ + GLuint i; + + ASSERT(lambda != NULL); + compute_min_mag_ranges(tObj, n, lambda, + &minStart, &minEnd, &magStart, &magEnd); + + if (minStart < minEnd) { + /* do the minified texels */ + GLuint m = minEnd - minStart; + switch (tObj->MinFilter) { + case GL_NEAREST: + for (i = minStart; i < minEnd; i++) + sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = minStart; i < minEnd; i++) + sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_2d_array_nearest_mipmap_nearest(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, + rgba + minStart); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_2d_array_linear_mipmap_nearest(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, + rgba + minStart); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_2d_array_nearest_mipmap_linear(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, + rgba + minStart); + break; + case GL_LINEAR_MIPMAP_LINEAR: + sample_2d_array_linear_mipmap_linear(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, + rgba + minStart); + break; + default: + _mesa_problem(ctx, "Bad min filter in sample_2d_array_texture"); + return; + } + } + + if (magStart < magEnd) { + /* do the magnified texels */ + switch (tObj->MagFilter) { + case GL_NEAREST: + for (i = magStart; i < magEnd; i++) + sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = magStart; i < magEnd; i++) + sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + default: + _mesa_problem(ctx, "Bad mag filter in sample_2d_array_texture"); + return; + } + } +} + + + + +/**********************************************************************/ +/* 1D Texture Array Sampling Functions */ +/**********************************************************************/ + +/** + * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. + */ +static void +sample_1d_array_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[4]) +{ + const GLint width = img->Width2; /* without border, power of two */ + const GLint height = img->Height; + GLint i; + GLint array; + (void) ctx; + + i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]); + array = tex_array_slice(texcoord[1], height); + + if (i < 0 || i >= (GLint) img->Width || + array < 0 || array >= (GLint) img->Height) { + /* Need this test for GL_CLAMP_TO_BORDER mode */ + get_border_color(tObj, img, rgba); + } + else { + img->FetchTexelf(img, i, array, 0, rgba); + } +} + + +/** + * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. + */ +static void +sample_1d_array_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[4]) +{ + const GLint width = img->Width2; + const GLint height = img->Height; + GLint i0, i1; + GLint array; + GLbitfield useBorderColor = 0x0; + GLfloat a; + GLfloat t0[4], t1[4]; + + linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a); + array = tex_array_slice(texcoord[1], height); + + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + } + else { + /* check if sampling texture border color */ + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + } + + if (array < 0 || array >= height) useBorderColor |= K0BIT; + + /* Fetch texels */ + if (useBorderColor & (I0BIT | K0BIT)) { + get_border_color(tObj, img, t0); + } + else { + img->FetchTexelf(img, i0, array, 0, t0); + } + if (useBorderColor & (I1BIT | K0BIT)) { + get_border_color(tObj, img, t1); + } + else { + img->FetchTexelf(img, i1, array, 0, t1); + } + + /* bilinear interpolation of samples */ + lerp_rgba(rgba, a, t0, t1); +} + + +static void +sample_1d_array_nearest_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], + rgba[i]); + } +} + + +static void +sample_1d_array_linear_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_1d_array_linear(ctx, tObj, tObj->Image[0][level], + texcoord[i], rgba[i]); + } +} + + +static void +sample_1d_array_nearest_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +static void +sample_1d_array_linear_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_1d_array_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_1d_array_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +/** Sample 1D Array texture, nearest filtering for both min/magnification */ +static void +sample_nearest_1d_array(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_1d_array_nearest(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 1D Array texture, linear filtering for both min/magnification */ +static void +sample_linear_1d_array(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_1d_array_linear(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 1D Array texture, using lambda to choose between min/magnification */ +static void +sample_lambda_1d_array(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint minStart, minEnd; /* texels with minification */ + GLuint magStart, magEnd; /* texels with magnification */ + GLuint i; + + ASSERT(lambda != NULL); + compute_min_mag_ranges(tObj, n, lambda, + &minStart, &minEnd, &magStart, &magEnd); + + if (minStart < minEnd) { + /* do the minified texels */ + GLuint m = minEnd - minStart; + switch (tObj->MinFilter) { + case GL_NEAREST: + for (i = minStart; i < minEnd; i++) + sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = minStart; i < minEnd; i++) + sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_1d_array_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_1d_array_linear_mipmap_nearest(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, + rgba + minStart); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_1d_array_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_LINEAR: + sample_1d_array_linear_mipmap_linear(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, + rgba + minStart); + break; + default: + _mesa_problem(ctx, "Bad min filter in sample_1d_array_texture"); + return; + } + } + + if (magStart < magEnd) { + /* do the magnified texels */ + switch (tObj->MagFilter) { + case GL_NEAREST: + for (i = magStart; i < magEnd; i++) + sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = magStart; i < magEnd; i++) + sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + default: + _mesa_problem(ctx, "Bad mag filter in sample_1d_array_texture"); + return; + } + } +} + + +/** + * Compare texcoord against depth sample. Return 1.0 or the ambient value. + */ +static INLINE GLfloat +shadow_compare(GLenum function, GLfloat coord, GLfloat depthSample, + GLfloat ambient) +{ + switch (function) { + case GL_LEQUAL: + return (coord <= depthSample) ? 1.0F : ambient; + case GL_GEQUAL: + return (coord >= depthSample) ? 1.0F : ambient; + case GL_LESS: + return (coord < depthSample) ? 1.0F : ambient; + case GL_GREATER: + return (coord > depthSample) ? 1.0F : ambient; + case GL_EQUAL: + return (coord == depthSample) ? 1.0F : ambient; + case GL_NOTEQUAL: + return (coord != depthSample) ? 1.0F : ambient; + case GL_ALWAYS: + return 1.0F; + case GL_NEVER: + return ambient; + case GL_NONE: + return depthSample; + default: + _mesa_problem(NULL, "Bad compare func in shadow_compare"); + return ambient; + } +} + + +/** + * Compare texcoord against four depth samples. + */ +static INLINE GLfloat +shadow_compare4(GLenum function, GLfloat coord, + GLfloat depth00, GLfloat depth01, + GLfloat depth10, GLfloat depth11, + GLfloat ambient, GLfloat wi, GLfloat wj) +{ + const GLfloat d = (1.0F - (GLfloat) ambient) * 0.25F; + GLfloat luminance = 1.0F; + + switch (function) { + case GL_LEQUAL: + if (coord > depth00) luminance -= d; + if (coord > depth01) luminance -= d; + if (coord > depth10) luminance -= d; + if (coord > depth11) luminance -= d; + return luminance; + case GL_GEQUAL: + if (coord < depth00) luminance -= d; + if (coord < depth01) luminance -= d; + if (coord < depth10) luminance -= d; + if (coord < depth11) luminance -= d; + return luminance; + case GL_LESS: + if (coord >= depth00) luminance -= d; + if (coord >= depth01) luminance -= d; + if (coord >= depth10) luminance -= d; + if (coord >= depth11) luminance -= d; + return luminance; + case GL_GREATER: + if (coord <= depth00) luminance -= d; + if (coord <= depth01) luminance -= d; + if (coord <= depth10) luminance -= d; + if (coord <= depth11) luminance -= d; + return luminance; + case GL_EQUAL: + if (coord != depth00) luminance -= d; + if (coord != depth01) luminance -= d; + if (coord != depth10) luminance -= d; + if (coord != depth11) luminance -= d; + return luminance; + case GL_NOTEQUAL: + if (coord == depth00) luminance -= d; + if (coord == depth01) luminance -= d; + if (coord == depth10) luminance -= d; + if (coord == depth11) luminance -= d; + return luminance; + case GL_ALWAYS: + return 1.0F; + case GL_NEVER: + return ambient; + case GL_NONE: + /* ordinary bilinear filtering */ + return lerp_2d(wi, wj, depth00, depth10, depth01, depth11); + default: + _mesa_problem(NULL, "Bad compare func in sample_compare4"); + return ambient; + } +} + + +/** + * Choose the mipmap level to use when sampling from a depth texture. + */ +static int +choose_depth_texture_level(const struct gl_texture_object *tObj, GLfloat lambda) +{ + GLint level; + + if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) { + /* no mipmapping - use base level */ + level = tObj->BaseLevel; + } + else { + /* choose mipmap level */ + lambda = CLAMP(lambda, tObj->MinLod, tObj->MaxLod); + level = (GLint) lambda; + level = CLAMP(level, tObj->BaseLevel, tObj->_MaxLevel); + } + + return level; +} + + +/** + * Sample a shadow/depth texture. This function is incomplete. It doesn't + * check for minification vs. magnification, etc. + */ +static void +sample_depth_texture( struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat texel[][4] ) +{ + const GLint level = choose_depth_texture_level(tObj, lambda[0]); + const struct gl_texture_image *img = tObj->Image[0][level]; + const GLint width = img->Width; + const GLint height = img->Height; + const GLint depth = img->Depth; + const GLuint compare_coord = (tObj->Target == GL_TEXTURE_2D_ARRAY_EXT) + ? 3 : 2; + GLfloat ambient; + GLenum function; + GLfloat result; + + ASSERT(img->_BaseFormat == GL_DEPTH_COMPONENT || + img->_BaseFormat == GL_DEPTH_STENCIL_EXT); + + ASSERT(tObj->Target == GL_TEXTURE_1D || + tObj->Target == GL_TEXTURE_2D || + tObj->Target == GL_TEXTURE_RECTANGLE_NV || + tObj->Target == GL_TEXTURE_1D_ARRAY_EXT || + tObj->Target == GL_TEXTURE_2D_ARRAY_EXT); + + ambient = tObj->CompareFailValue; + + /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */ + + function = (tObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) ? + tObj->CompareFunc : GL_NONE; + + if (tObj->MagFilter == GL_NEAREST) { + GLuint i; + for (i = 0; i < n; i++) { + GLfloat depthSample, depthRef; + GLint col, row, slice; + + nearest_texcoord(tObj, level, texcoords[i], &col, &row, &slice); + + if (col >= 0 && row >= 0 && col < width && row < height && + slice >= 0 && slice < depth) { + img->FetchTexelf(img, col, row, slice, &depthSample); + } + else { + depthSample = tObj->BorderColor.f[0]; + } + + depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F); + + result = shadow_compare(function, depthRef, depthSample, ambient); + + switch (tObj->DepthMode) { + case GL_LUMINANCE: + ASSIGN_4V(texel[i], result, result, result, 1.0F); + break; + case GL_INTENSITY: + ASSIGN_4V(texel[i], result, result, result, result); + break; + case GL_ALPHA: + ASSIGN_4V(texel[i], 0.0F, 0.0F, 0.0F, result); + break; + case GL_RED: + ASSIGN_4V(texel[i], result, 0.0F, 0.0F, 1.0F); + break; + default: + _mesa_problem(ctx, "Bad depth texture mode"); + } + } + } + else { + GLuint i; + ASSERT(tObj->MagFilter == GL_LINEAR); + for (i = 0; i < n; i++) { + GLfloat depth00, depth01, depth10, depth11, depthRef; + GLint i0, i1, j0, j1; + GLint slice; + GLfloat wi, wj; + GLuint useBorderTexel; + + linear_texcoord(tObj, level, texcoords[i], &i0, &i1, &j0, &j1, &slice, + &wi, &wj); + + useBorderTexel = 0; + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) { + j0 += img->Border; + j1 += img->Border; + } + } + else { + if (i0 < 0 || i0 >= (GLint) width) useBorderTexel |= I0BIT; + if (i1 < 0 || i1 >= (GLint) width) useBorderTexel |= I1BIT; + if (j0 < 0 || j0 >= (GLint) height) useBorderTexel |= J0BIT; + if (j1 < 0 || j1 >= (GLint) height) useBorderTexel |= J1BIT; + } + + if (slice < 0 || slice >= (GLint) depth) { + depth00 = tObj->BorderColor.f[0]; + depth01 = tObj->BorderColor.f[0]; + depth10 = tObj->BorderColor.f[0]; + depth11 = tObj->BorderColor.f[0]; + } + else { + /* get four depth samples from the texture */ + if (useBorderTexel & (I0BIT | J0BIT)) { + depth00 = tObj->BorderColor.f[0]; + } + else { + img->FetchTexelf(img, i0, j0, slice, &depth00); + } + if (useBorderTexel & (I1BIT | J0BIT)) { + depth10 = tObj->BorderColor.f[0]; + } + else { + img->FetchTexelf(img, i1, j0, slice, &depth10); + } + + if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) { + if (useBorderTexel & (I0BIT | J1BIT)) { + depth01 = tObj->BorderColor.f[0]; + } + else { + img->FetchTexelf(img, i0, j1, slice, &depth01); + } + if (useBorderTexel & (I1BIT | J1BIT)) { + depth11 = tObj->BorderColor.f[0]; + } + else { + img->FetchTexelf(img, i1, j1, slice, &depth11); + } + } + else { + depth01 = depth00; + depth11 = depth10; + } + } + + depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F); + + result = shadow_compare4(function, depthRef, + depth00, depth01, depth10, depth11, + ambient, wi, wj); + + switch (tObj->DepthMode) { + case GL_LUMINANCE: + ASSIGN_4V(texel[i], result, result, result, 1.0F); + break; + case GL_INTENSITY: + ASSIGN_4V(texel[i], result, result, result, result); + break; + case GL_ALPHA: + ASSIGN_4V(texel[i], 0.0F, 0.0F, 0.0F, result); + break; + default: + _mesa_problem(ctx, "Bad depth texture mode"); + } + + } /* for */ + } /* if filter */ +} + + +/** + * We use this function when a texture object is in an "incomplete" state. + * When a fragment program attempts to sample an incomplete texture we + * return black (see issue 23 in GL_ARB_fragment_program spec). + * Note: fragment programs don't observe the texture enable/disable flags. + */ +static void +null_sample_func( struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint i; + (void) ctx; + (void) tObj; + (void) texcoords; + (void) lambda; + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = 0; + rgba[i][GCOMP] = 0; + rgba[i][BCOMP] = 0; + rgba[i][ACOMP] = 1.0; + } +} + + +/** + * Choose the texture sampling function for the given texture object. + */ +texture_sample_func +_swrast_choose_texture_sample_func( struct gl_context *ctx, + const struct gl_texture_object *t ) +{ + if (!t || !t->_Complete) { + return &null_sample_func; + } + else { + const GLboolean needLambda = (GLboolean) (t->MinFilter != t->MagFilter); + const GLenum format = t->Image[0][t->BaseLevel]->_BaseFormat; + + switch (t->Target) { + case GL_TEXTURE_1D: + if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) { + return &sample_depth_texture; + } + else if (needLambda) { + return &sample_lambda_1d; + } + else if (t->MinFilter == GL_LINEAR) { + return &sample_linear_1d; + } + else { + ASSERT(t->MinFilter == GL_NEAREST); + return &sample_nearest_1d; + } + case GL_TEXTURE_2D: + if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) { + return &sample_depth_texture; + } + else if (needLambda) { + return &sample_lambda_2d; + } + else if (t->MinFilter == GL_LINEAR) { + return &sample_linear_2d; + } + else { + /* check for a few optimized cases */ + const struct gl_texture_image *img = t->Image[0][t->BaseLevel]; + ASSERT(t->MinFilter == GL_NEAREST); + if (t->WrapS == GL_REPEAT && + t->WrapT == GL_REPEAT && + img->_IsPowerOfTwo && + img->Border == 0 && + img->TexFormat == MESA_FORMAT_RGB888) { + return &opt_sample_rgb_2d; + } + else if (t->WrapS == GL_REPEAT && + t->WrapT == GL_REPEAT && + img->_IsPowerOfTwo && + img->Border == 0 && + img->TexFormat == MESA_FORMAT_RGBA8888) { + return &opt_sample_rgba_2d; + } + else { + return &sample_nearest_2d; + } + } + case GL_TEXTURE_3D: + if (needLambda) { + return &sample_lambda_3d; + } + else if (t->MinFilter == GL_LINEAR) { + return &sample_linear_3d; + } + else { + ASSERT(t->MinFilter == GL_NEAREST); + return &sample_nearest_3d; + } + case GL_TEXTURE_CUBE_MAP: + if (needLambda) { + return &sample_lambda_cube; + } + else if (t->MinFilter == GL_LINEAR) { + return &sample_linear_cube; + } + else { + ASSERT(t->MinFilter == GL_NEAREST); + return &sample_nearest_cube; + } + case GL_TEXTURE_RECTANGLE_NV: + if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) { + return &sample_depth_texture; + } + else if (needLambda) { + return &sample_lambda_rect; + } + else if (t->MinFilter == GL_LINEAR) { + return &sample_linear_rect; + } + else { + ASSERT(t->MinFilter == GL_NEAREST); + return &sample_nearest_rect; + } + case GL_TEXTURE_1D_ARRAY_EXT: + if (needLambda) { + return &sample_lambda_1d_array; + } + else if (t->MinFilter == GL_LINEAR) { + return &sample_linear_1d_array; + } + else { + ASSERT(t->MinFilter == GL_NEAREST); + return &sample_nearest_1d_array; + } + case GL_TEXTURE_2D_ARRAY_EXT: + if (needLambda) { + return &sample_lambda_2d_array; + } + else if (t->MinFilter == GL_LINEAR) { + return &sample_linear_2d_array; + } + else { + ASSERT(t->MinFilter == GL_NEAREST); + return &sample_nearest_2d_array; + } + default: + _mesa_problem(ctx, + "invalid target in _swrast_choose_texture_sample_func"); + return &null_sample_func; + } + } +} diff --git a/mesalib/src/mesa/vbo/vbo_exec_array.c b/mesalib/src/mesa/vbo/vbo_exec_array.c index 5818b134d..98d6badc4 100644 --- a/mesalib/src/mesa/vbo/vbo_exec_array.c +++ b/mesalib/src/mesa/vbo/vbo_exec_array.c @@ -461,6 +461,14 @@ recalculate_input_bindings(struct gl_context *ctx) inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->generic_currval[i]; const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i); } + + /* There is no need to make _NEW_ARRAY dirty here for the TnL program, + * because it already takes care of invalidating the state necessary + * to revalidate vertex arrays. Not marking the state as dirty also + * improves performance (quite significantly in some apps). + */ + if (!ctx->VertexProgram._MaintainTnlProgram) + ctx->NewState |= _NEW_ARRAY; break; case VP_NV: @@ -486,6 +494,8 @@ recalculate_input_bindings(struct gl_context *ctx) inputs[i] = &vbo->generic_currval[i - VERT_ATTRIB_GENERIC0]; const_inputs |= 1 << i; } + + ctx->NewState |= _NEW_ARRAY; break; case VP_ARB: @@ -521,8 +531,9 @@ recalculate_input_bindings(struct gl_context *ctx) inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->generic_currval[i]; const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i); } - } + + ctx->NewState |= _NEW_ARRAY; break; } -- cgit v1.2.3