From a18769801e521ccb5a409c377ac0a6a1141f5776 Mon Sep 17 00:00:00 2001 From: marha Date: Tue, 1 Mar 2011 07:17:23 +0000 Subject: pixman mesa git update 1 Mar 2011 --- mesalib/src/glsl/ast_to_hir.cpp | 8 +- mesalib/src/glsl/builtin_types.h | 602 +- mesalib/src/glsl/glsl_parser_extras.cpp | 5 + mesalib/src/glsl/glsl_parser_extras.h | 2 + mesalib/src/glsl/glsl_types.cpp | 12 + mesalib/src/glsl/glsl_types.h | 2 + mesalib/src/mesa/SConscript | 2 + mesalib/src/mesa/drivers/common/meta.c | 5703 ++++++++--------- mesalib/src/mesa/main/attrib.c | 3121 +++++---- mesalib/src/mesa/main/bufferobj.c | 242 - mesalib/src/mesa/main/bufferobj.h | 339 +- mesalib/src/mesa/main/colortab.c | 1755 +++--- mesalib/src/mesa/main/dlist.c | 1 + mesalib/src/mesa/main/drawpix.c | 607 +- mesalib/src/mesa/main/enable.c | 2988 +++++---- mesalib/src/mesa/main/extensions.c | 5 +- mesalib/src/mesa/main/fbobject.c | 4932 +++++++-------- mesalib/src/mesa/main/framebuffer.c | 5 +- mesalib/src/mesa/main/get.c | 5060 ++++++++------- mesalib/src/mesa/main/mtypes.h | 6722 ++++++++++---------- mesalib/src/mesa/main/pbo.c | 372 ++ mesalib/src/mesa/main/pbo.h | 92 + mesalib/src/mesa/main/pixel.c | 1400 ++-- mesalib/src/mesa/main/polygon.c | 644 +- mesalib/src/mesa/main/readpix.c | 487 +- mesalib/src/mesa/main/texcompress_rgtc.c | 727 +-- mesalib/src/mesa/main/texcompress_rgtc_tmp.h | 376 ++ mesalib/src/mesa/main/texgetimage.c | 1835 +++--- mesalib/src/mesa/main/teximage.c | 7004 +++++++++++---------- mesalib/src/mesa/main/texstate.c | 1685 +++-- mesalib/src/mesa/main/texstore.c | 89 +- mesalib/src/mesa/main/texstore.h | 18 - mesalib/src/mesa/sources.mak | 1 + mesalib/src/mesa/state_tracker/st_cb_bitmap.c | 1 + mesalib/src/mesa/state_tracker/st_cb_drawpixels.c | 2975 ++++----- mesalib/src/mesa/state_tracker/st_cb_readpixels.c | 1121 ++-- mesalib/src/mesa/state_tracker/st_cb_texture.c | 1 + mesalib/src/mesa/swrast/s_bitmap.c | 445 +- mesalib/src/mesa/swrast/s_drawpix.c | 1505 ++--- mesalib/src/mesa/swrast/s_readpix.c | 1016 +-- mesalib/src/mesa/swrast/s_texcombine.c | 1479 +++-- mesalib/src/mesa/vbo/vbo_exec_array.c | 1 + 42 files changed, 27491 insertions(+), 27896 deletions(-) create mode 100644 mesalib/src/mesa/main/pbo.c create mode 100644 mesalib/src/mesa/main/pbo.h create mode 100644 mesalib/src/mesa/main/texcompress_rgtc_tmp.h (limited to 'mesalib/src') diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index bef099cca..fd1f0b49f 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -3445,11 +3445,9 @@ ast_struct_specifier::hir(exec_list *instructions, if (!state->symbols->add_type(name, t)) { _mesa_glsl_error(& loc, state, "struct `%s' previously defined", name); } else { - - const glsl_type **s = (const glsl_type **) - realloc(state->user_structures, - sizeof(state->user_structures[0]) * - (state->num_user_structures + 1)); + const glsl_type **s = reralloc(state, state->user_structures, + const glsl_type *, + state->num_user_structures + 1); if (s != NULL) { s[state->num_user_structures] = t; state->user_structures = s; diff --git a/mesalib/src/glsl/builtin_types.h b/mesalib/src/glsl/builtin_types.h index 1d00d65ee..58b9a8127 100644 --- a/mesalib/src/glsl/builtin_types.h +++ b/mesalib/src/glsl/builtin_types.h @@ -1,300 +1,302 @@ -/* - * Copyright © 2009 Intel Corporation - * - * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS 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. - */ - -const glsl_type glsl_type::_error_type = - glsl_type(GL_INVALID_ENUM, GLSL_TYPE_ERROR, 0, 0, ""); - -const glsl_type glsl_type::_void_type = - glsl_type(GL_INVALID_ENUM, GLSL_TYPE_VOID, 0, 0, "void"); - -const glsl_type *const glsl_type::error_type = & glsl_type::_error_type; -const glsl_type *const glsl_type::void_type = & glsl_type::_void_type; - -/** \name Core built-in types - * - * These types exist in all versions of GLSL. - */ -/*@{*/ - -const glsl_type glsl_type::builtin_core_types[] = { - glsl_type(GL_BOOL, GLSL_TYPE_BOOL, 1, 1, "bool"), - glsl_type(GL_BOOL_VEC2, GLSL_TYPE_BOOL, 2, 1, "bvec2"), - glsl_type(GL_BOOL_VEC3, GLSL_TYPE_BOOL, 3, 1, "bvec3"), - glsl_type(GL_BOOL_VEC4, GLSL_TYPE_BOOL, 4, 1, "bvec4"), - glsl_type(GL_INT, GLSL_TYPE_INT, 1, 1, "int"), - glsl_type(GL_INT_VEC2, GLSL_TYPE_INT, 2, 1, "ivec2"), - glsl_type(GL_INT_VEC3, GLSL_TYPE_INT, 3, 1, "ivec3"), - glsl_type(GL_INT_VEC4, GLSL_TYPE_INT, 4, 1, "ivec4"), - glsl_type(GL_FLOAT, GLSL_TYPE_FLOAT, 1, 1, "float"), - glsl_type(GL_FLOAT_VEC2, GLSL_TYPE_FLOAT, 2, 1, "vec2"), - glsl_type(GL_FLOAT_VEC3, GLSL_TYPE_FLOAT, 3, 1, "vec3"), - glsl_type(GL_FLOAT_VEC4, GLSL_TYPE_FLOAT, 4, 1, "vec4"), - glsl_type(GL_FLOAT_MAT2, GLSL_TYPE_FLOAT, 2, 2, "mat2"), - glsl_type(GL_FLOAT_MAT3, GLSL_TYPE_FLOAT, 3, 3, "mat3"), - glsl_type(GL_FLOAT_MAT4, GLSL_TYPE_FLOAT, 4, 4, "mat4"), - glsl_type(GL_SAMPLER_2D, GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_FLOAT, - "sampler2D"), - glsl_type(GL_SAMPLER_CUBE, GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_FLOAT, - "samplerCube"), -}; - -const glsl_type *const glsl_type::bool_type = & builtin_core_types[0]; -const glsl_type *const glsl_type::int_type = & builtin_core_types[4]; -const glsl_type *const glsl_type::ivec4_type = & builtin_core_types[7]; -const glsl_type *const glsl_type::float_type = & builtin_core_types[8]; -const glsl_type *const glsl_type::vec2_type = & builtin_core_types[9]; -const glsl_type *const glsl_type::vec3_type = & builtin_core_types[10]; -const glsl_type *const glsl_type::vec4_type = & builtin_core_types[11]; -const glsl_type *const glsl_type::mat2_type = & builtin_core_types[12]; -const glsl_type *const glsl_type::mat3_type = & builtin_core_types[13]; -const glsl_type *const glsl_type::mat4_type = & builtin_core_types[14]; -/*@}*/ - -/** \name GLSL structures that have not been deprecated. - */ -/*@{*/ - -static const struct glsl_struct_field gl_DepthRangeParameters_fields[] = { - { glsl_type::float_type, "near" }, - { glsl_type::float_type, "far" }, - { glsl_type::float_type, "diff" }, -}; - -const glsl_type glsl_type::builtin_structure_types[] = { - glsl_type(gl_DepthRangeParameters_fields, - Elements(gl_DepthRangeParameters_fields), - "gl_DepthRangeParameters"), -}; -/*@}*/ - -/** \name GLSL 1.00 / 1.10 structures that are deprecated in GLSL 1.30 - */ -/*@{*/ - -static const struct glsl_struct_field gl_PointParameters_fields[] = { - { glsl_type::float_type, "size" }, - { glsl_type::float_type, "sizeMin" }, - { glsl_type::float_type, "sizeMax" }, - { glsl_type::float_type, "fadeThresholdSize" }, - { glsl_type::float_type, "distanceConstantAttenuation" }, - { glsl_type::float_type, "distanceLinearAttenuation" }, - { glsl_type::float_type, "distanceQuadraticAttenuation" }, -}; - -static const struct glsl_struct_field gl_MaterialParameters_fields[] = { - { glsl_type::vec4_type, "emission" }, - { glsl_type::vec4_type, "ambient" }, - { glsl_type::vec4_type, "diffuse" }, - { glsl_type::vec4_type, "specular" }, - { glsl_type::float_type, "shininess" }, -}; - -static const struct glsl_struct_field gl_LightSourceParameters_fields[] = { - { glsl_type::vec4_type, "ambient" }, - { glsl_type::vec4_type, "diffuse" }, - { glsl_type::vec4_type, "specular" }, - { glsl_type::vec4_type, "position" }, - { glsl_type::vec4_type, "halfVector" }, - { glsl_type::vec3_type, "spotDirection" }, - { glsl_type::float_type, "spotExponent" }, - { glsl_type::float_type, "spotCutoff" }, - { glsl_type::float_type, "spotCosCutoff" }, - { glsl_type::float_type, "constantAttenuation" }, - { glsl_type::float_type, "linearAttenuation" }, - { glsl_type::float_type, "quadraticAttenuation" }, -}; - -static const struct glsl_struct_field gl_LightModelParameters_fields[] = { - { glsl_type::vec4_type, "ambient" }, -}; - -static const struct glsl_struct_field gl_LightModelProducts_fields[] = { - { glsl_type::vec4_type, "sceneColor" }, -}; - -static const struct glsl_struct_field gl_LightProducts_fields[] = { - { glsl_type::vec4_type, "ambient" }, - { glsl_type::vec4_type, "diffuse" }, - { glsl_type::vec4_type, "specular" }, -}; - -static const struct glsl_struct_field gl_FogParameters_fields[] = { - { glsl_type::vec4_type, "color" }, - { glsl_type::float_type, "density" }, - { glsl_type::float_type, "start" }, - { glsl_type::float_type, "end" }, - { glsl_type::float_type, "scale" }, -}; - -const glsl_type glsl_type::builtin_110_deprecated_structure_types[] = { - glsl_type(gl_PointParameters_fields, - Elements(gl_PointParameters_fields), - "gl_PointParameters"), - glsl_type(gl_MaterialParameters_fields, - Elements(gl_MaterialParameters_fields), - "gl_MaterialParameters"), - glsl_type(gl_LightSourceParameters_fields, - Elements(gl_LightSourceParameters_fields), - "gl_LightSourceParameters"), - glsl_type(gl_LightModelParameters_fields, - Elements(gl_LightModelParameters_fields), - "gl_LightModelParameters"), - glsl_type(gl_LightModelProducts_fields, - Elements(gl_LightModelProducts_fields), - "gl_LightModelProducts"), - glsl_type(gl_LightProducts_fields, - Elements(gl_LightProducts_fields), - "gl_LightProducts"), - glsl_type(gl_FogParameters_fields, - Elements(gl_FogParameters_fields), - "gl_FogParameters"), -}; -/*@}*/ - -/** \name Types in GLSL 1.10 (but not GLSL ES 1.00) - */ -/*@{*/ -const glsl_type glsl_type::builtin_110_types[] = { - glsl_type(GL_SAMPLER_1D, GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_FLOAT, - "sampler1D"), - glsl_type(GL_SAMPLER_1D_SHADOW, GLSL_SAMPLER_DIM_1D, 1, 0, GLSL_TYPE_FLOAT, - "sampler1DShadow"), - glsl_type(GL_SAMPLER_2D_SHADOW, GLSL_SAMPLER_DIM_2D, 1, 0, GLSL_TYPE_FLOAT, - "sampler2DShadow"), - glsl_type(GL_SAMPLER_3D, GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_FLOAT, - "sampler3D"), -}; -/*@}*/ - -/** \name Types added in GLSL 1.20 - */ -/*@{*/ - -const glsl_type glsl_type::builtin_120_types[] = { - glsl_type(GL_FLOAT_MAT2x3, GLSL_TYPE_FLOAT, 3, 2, "mat2x3"), - glsl_type(GL_FLOAT_MAT2x4, GLSL_TYPE_FLOAT, 4, 2, "mat2x4"), - glsl_type(GL_FLOAT_MAT3x2, GLSL_TYPE_FLOAT, 2, 3, "mat3x2"), - glsl_type(GL_FLOAT_MAT3x4, GLSL_TYPE_FLOAT, 4, 3, "mat3x4"), - glsl_type(GL_FLOAT_MAT4x2, GLSL_TYPE_FLOAT, 2, 4, "mat4x2"), - glsl_type(GL_FLOAT_MAT4x3, GLSL_TYPE_FLOAT, 3, 4, "mat4x3"), -}; -const glsl_type *const glsl_type::mat2x3_type = & builtin_120_types[0]; -const glsl_type *const glsl_type::mat2x4_type = & builtin_120_types[1]; -const glsl_type *const glsl_type::mat3x2_type = & builtin_120_types[2]; -const glsl_type *const glsl_type::mat3x4_type = & builtin_120_types[3]; -const glsl_type *const glsl_type::mat4x2_type = & builtin_120_types[4]; -const glsl_type *const glsl_type::mat4x3_type = & builtin_120_types[5]; -/*@}*/ - -/** \name Types added in GLSL 1.30 - */ -/*@{*/ - -const glsl_type glsl_type::builtin_130_types[] = { - glsl_type(GL_UNSIGNED_INT, GLSL_TYPE_UINT, 1, 1, "uint"), - glsl_type(GL_UNSIGNED_INT_VEC2, GLSL_TYPE_UINT, 2, 1, "uvec2"), - glsl_type(GL_UNSIGNED_INT_VEC3, GLSL_TYPE_UINT, 3, 1, "uvec3"), - glsl_type(GL_UNSIGNED_INT_VEC4, GLSL_TYPE_UINT, 4, 1, "uvec4"), - - /* 1D and 2D texture arrays - several of these are included only in - * builtin_EXT_texture_array_types. - */ - glsl_type(GL_INT_SAMPLER_1D_ARRAY, - GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_INT, "isampler1DArray"), - glsl_type(GL_UNSIGNED_INT_SAMPLER_1D_ARRAY, - GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_UINT, "usampler1DArray"), - glsl_type(GL_INT_SAMPLER_2D_ARRAY, - GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_INT, "isampler2DArray"), - glsl_type(GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, - GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_UINT, "usampler2DArray"), - - /* cube shadow samplers */ - glsl_type(GL_SAMPLER_CUBE_SHADOW, - GLSL_SAMPLER_DIM_CUBE, 1, 0, GLSL_TYPE_FLOAT, "samplerCubeShadow"), - - /* signed and unsigned integer samplers */ - glsl_type(GL_INT_SAMPLER_1D, - GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_INT, "isampler1D"), - glsl_type(GL_UNSIGNED_INT_SAMPLER_1D, - GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_UINT, "usampler1D"), - glsl_type(GL_INT_SAMPLER_2D, - GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_INT, "isampler2D"), - glsl_type(GL_UNSIGNED_INT_SAMPLER_2D, - GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_UINT, "usampler2D"), - glsl_type(GL_INT_SAMPLER_3D, - GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_INT, "isampler3D"), - glsl_type(GL_UNSIGNED_INT_SAMPLER_3D, - GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_UINT, "usampler3D"), - glsl_type(GL_INT_SAMPLER_CUBE, - GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_INT, "isamplerCube"), - glsl_type(GL_INT_SAMPLER_CUBE, - GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_UINT, "usamplerCube"), -}; - -const glsl_type *const glsl_type::uint_type = & builtin_130_types[0]; -const glsl_type *const glsl_type::uvec2_type = & builtin_130_types[1]; -const glsl_type *const glsl_type::uvec3_type = & builtin_130_types[2]; -const glsl_type *const glsl_type::uvec4_type = & builtin_130_types[3]; -/*@}*/ - -/** \name Sampler types added by GL_ARB_texture_rectangle - */ -/*@{*/ - -const glsl_type glsl_type::builtin_ARB_texture_rectangle_types[] = { - glsl_type(GL_SAMPLER_2D_RECT, - GLSL_SAMPLER_DIM_RECT, 0, 0, GLSL_TYPE_FLOAT, "sampler2DRect"), - glsl_type(GL_SAMPLER_2D_RECT_SHADOW, - GLSL_SAMPLER_DIM_RECT, 1, 0, GLSL_TYPE_FLOAT, "sampler2DRectShadow"), -}; -/*@}*/ - -/** \name Sampler types added by GL_EXT_texture_array - */ -/*@{*/ - -const glsl_type glsl_type::builtin_EXT_texture_array_types[] = { - glsl_type(GL_SAMPLER_1D_ARRAY, - GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_FLOAT, "sampler1DArray"), - glsl_type(GL_SAMPLER_2D_ARRAY, - GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_FLOAT, "sampler2DArray"), - glsl_type(GL_SAMPLER_1D_ARRAY_SHADOW, - GLSL_SAMPLER_DIM_1D, 1, 1, GLSL_TYPE_FLOAT, "sampler1DArrayShadow"), - glsl_type(GL_SAMPLER_2D_ARRAY_SHADOW, - GLSL_SAMPLER_DIM_2D, 1, 1, GLSL_TYPE_FLOAT, "sampler2DArrayShadow"), -}; -/*@}*/ - -/** \name Sampler types added by GL_EXT_texture_buffer_object - */ -/*@{*/ - -const glsl_type glsl_type::builtin_EXT_texture_buffer_object_types[] = { - glsl_type(GL_SAMPLER_BUFFER, - GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_FLOAT, "samplerBuffer"), - glsl_type(GL_INT_SAMPLER_BUFFER, - GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_INT, "isamplerBuffer"), - glsl_type(GL_UNSIGNED_INT_SAMPLER_BUFFER, - GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_UINT, "usamplerBuffer"), -}; -/*@}*/ +/* + * Copyright © 2009 Intel Corporation + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + */ + +const glsl_type glsl_type::_error_type = + glsl_type(GL_INVALID_ENUM, GLSL_TYPE_ERROR, 0, 0, ""); + +const glsl_type glsl_type::_void_type = + glsl_type(GL_INVALID_ENUM, GLSL_TYPE_VOID, 0, 0, "void"); + +const glsl_type glsl_type::_sampler3D_type = + glsl_type(GL_SAMPLER_3D, GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_FLOAT, + "sampler3D"); + +const glsl_type *const glsl_type::error_type = & glsl_type::_error_type; +const glsl_type *const glsl_type::void_type = & glsl_type::_void_type; + +/** \name Core built-in types + * + * These types exist in all versions of GLSL. + */ +/*@{*/ + +const glsl_type glsl_type::builtin_core_types[] = { + glsl_type(GL_BOOL, GLSL_TYPE_BOOL, 1, 1, "bool"), + glsl_type(GL_BOOL_VEC2, GLSL_TYPE_BOOL, 2, 1, "bvec2"), + glsl_type(GL_BOOL_VEC3, GLSL_TYPE_BOOL, 3, 1, "bvec3"), + glsl_type(GL_BOOL_VEC4, GLSL_TYPE_BOOL, 4, 1, "bvec4"), + glsl_type(GL_INT, GLSL_TYPE_INT, 1, 1, "int"), + glsl_type(GL_INT_VEC2, GLSL_TYPE_INT, 2, 1, "ivec2"), + glsl_type(GL_INT_VEC3, GLSL_TYPE_INT, 3, 1, "ivec3"), + glsl_type(GL_INT_VEC4, GLSL_TYPE_INT, 4, 1, "ivec4"), + glsl_type(GL_FLOAT, GLSL_TYPE_FLOAT, 1, 1, "float"), + glsl_type(GL_FLOAT_VEC2, GLSL_TYPE_FLOAT, 2, 1, "vec2"), + glsl_type(GL_FLOAT_VEC3, GLSL_TYPE_FLOAT, 3, 1, "vec3"), + glsl_type(GL_FLOAT_VEC4, GLSL_TYPE_FLOAT, 4, 1, "vec4"), + glsl_type(GL_FLOAT_MAT2, GLSL_TYPE_FLOAT, 2, 2, "mat2"), + glsl_type(GL_FLOAT_MAT3, GLSL_TYPE_FLOAT, 3, 3, "mat3"), + glsl_type(GL_FLOAT_MAT4, GLSL_TYPE_FLOAT, 4, 4, "mat4"), + glsl_type(GL_SAMPLER_2D, GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_FLOAT, + "sampler2D"), + glsl_type(GL_SAMPLER_CUBE, GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_FLOAT, + "samplerCube"), +}; + +const glsl_type *const glsl_type::bool_type = & builtin_core_types[0]; +const glsl_type *const glsl_type::int_type = & builtin_core_types[4]; +const glsl_type *const glsl_type::ivec4_type = & builtin_core_types[7]; +const glsl_type *const glsl_type::float_type = & builtin_core_types[8]; +const glsl_type *const glsl_type::vec2_type = & builtin_core_types[9]; +const glsl_type *const glsl_type::vec3_type = & builtin_core_types[10]; +const glsl_type *const glsl_type::vec4_type = & builtin_core_types[11]; +const glsl_type *const glsl_type::mat2_type = & builtin_core_types[12]; +const glsl_type *const glsl_type::mat3_type = & builtin_core_types[13]; +const glsl_type *const glsl_type::mat4_type = & builtin_core_types[14]; +/*@}*/ + +/** \name GLSL structures that have not been deprecated. + */ +/*@{*/ + +static const struct glsl_struct_field gl_DepthRangeParameters_fields[] = { + { glsl_type::float_type, "near" }, + { glsl_type::float_type, "far" }, + { glsl_type::float_type, "diff" }, +}; + +const glsl_type glsl_type::builtin_structure_types[] = { + glsl_type(gl_DepthRangeParameters_fields, + Elements(gl_DepthRangeParameters_fields), + "gl_DepthRangeParameters"), +}; +/*@}*/ + +/** \name GLSL 1.00 / 1.10 structures that are deprecated in GLSL 1.30 + */ +/*@{*/ + +static const struct glsl_struct_field gl_PointParameters_fields[] = { + { glsl_type::float_type, "size" }, + { glsl_type::float_type, "sizeMin" }, + { glsl_type::float_type, "sizeMax" }, + { glsl_type::float_type, "fadeThresholdSize" }, + { glsl_type::float_type, "distanceConstantAttenuation" }, + { glsl_type::float_type, "distanceLinearAttenuation" }, + { glsl_type::float_type, "distanceQuadraticAttenuation" }, +}; + +static const struct glsl_struct_field gl_MaterialParameters_fields[] = { + { glsl_type::vec4_type, "emission" }, + { glsl_type::vec4_type, "ambient" }, + { glsl_type::vec4_type, "diffuse" }, + { glsl_type::vec4_type, "specular" }, + { glsl_type::float_type, "shininess" }, +}; + +static const struct glsl_struct_field gl_LightSourceParameters_fields[] = { + { glsl_type::vec4_type, "ambient" }, + { glsl_type::vec4_type, "diffuse" }, + { glsl_type::vec4_type, "specular" }, + { glsl_type::vec4_type, "position" }, + { glsl_type::vec4_type, "halfVector" }, + { glsl_type::vec3_type, "spotDirection" }, + { glsl_type::float_type, "spotExponent" }, + { glsl_type::float_type, "spotCutoff" }, + { glsl_type::float_type, "spotCosCutoff" }, + { glsl_type::float_type, "constantAttenuation" }, + { glsl_type::float_type, "linearAttenuation" }, + { glsl_type::float_type, "quadraticAttenuation" }, +}; + +static const struct glsl_struct_field gl_LightModelParameters_fields[] = { + { glsl_type::vec4_type, "ambient" }, +}; + +static const struct glsl_struct_field gl_LightModelProducts_fields[] = { + { glsl_type::vec4_type, "sceneColor" }, +}; + +static const struct glsl_struct_field gl_LightProducts_fields[] = { + { glsl_type::vec4_type, "ambient" }, + { glsl_type::vec4_type, "diffuse" }, + { glsl_type::vec4_type, "specular" }, +}; + +static const struct glsl_struct_field gl_FogParameters_fields[] = { + { glsl_type::vec4_type, "color" }, + { glsl_type::float_type, "density" }, + { glsl_type::float_type, "start" }, + { glsl_type::float_type, "end" }, + { glsl_type::float_type, "scale" }, +}; + +const glsl_type glsl_type::builtin_110_deprecated_structure_types[] = { + glsl_type(gl_PointParameters_fields, + Elements(gl_PointParameters_fields), + "gl_PointParameters"), + glsl_type(gl_MaterialParameters_fields, + Elements(gl_MaterialParameters_fields), + "gl_MaterialParameters"), + glsl_type(gl_LightSourceParameters_fields, + Elements(gl_LightSourceParameters_fields), + "gl_LightSourceParameters"), + glsl_type(gl_LightModelParameters_fields, + Elements(gl_LightModelParameters_fields), + "gl_LightModelParameters"), + glsl_type(gl_LightModelProducts_fields, + Elements(gl_LightModelProducts_fields), + "gl_LightModelProducts"), + glsl_type(gl_LightProducts_fields, + Elements(gl_LightProducts_fields), + "gl_LightProducts"), + glsl_type(gl_FogParameters_fields, + Elements(gl_FogParameters_fields), + "gl_FogParameters"), +}; +/*@}*/ + +/** \name Types in GLSL 1.10 (but not GLSL ES 1.00) + */ +/*@{*/ +const glsl_type glsl_type::builtin_110_types[] = { + glsl_type(GL_SAMPLER_1D, GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_FLOAT, + "sampler1D"), + glsl_type(GL_SAMPLER_1D_SHADOW, GLSL_SAMPLER_DIM_1D, 1, 0, GLSL_TYPE_FLOAT, + "sampler1DShadow"), + glsl_type(GL_SAMPLER_2D_SHADOW, GLSL_SAMPLER_DIM_2D, 1, 0, GLSL_TYPE_FLOAT, + "sampler2DShadow"), +}; +/*@}*/ + +/** \name Types added in GLSL 1.20 + */ +/*@{*/ + +const glsl_type glsl_type::builtin_120_types[] = { + glsl_type(GL_FLOAT_MAT2x3, GLSL_TYPE_FLOAT, 3, 2, "mat2x3"), + glsl_type(GL_FLOAT_MAT2x4, GLSL_TYPE_FLOAT, 4, 2, "mat2x4"), + glsl_type(GL_FLOAT_MAT3x2, GLSL_TYPE_FLOAT, 2, 3, "mat3x2"), + glsl_type(GL_FLOAT_MAT3x4, GLSL_TYPE_FLOAT, 4, 3, "mat3x4"), + glsl_type(GL_FLOAT_MAT4x2, GLSL_TYPE_FLOAT, 2, 4, "mat4x2"), + glsl_type(GL_FLOAT_MAT4x3, GLSL_TYPE_FLOAT, 3, 4, "mat4x3"), +}; +const glsl_type *const glsl_type::mat2x3_type = & builtin_120_types[0]; +const glsl_type *const glsl_type::mat2x4_type = & builtin_120_types[1]; +const glsl_type *const glsl_type::mat3x2_type = & builtin_120_types[2]; +const glsl_type *const glsl_type::mat3x4_type = & builtin_120_types[3]; +const glsl_type *const glsl_type::mat4x2_type = & builtin_120_types[4]; +const glsl_type *const glsl_type::mat4x3_type = & builtin_120_types[5]; +/*@}*/ + +/** \name Types added in GLSL 1.30 + */ +/*@{*/ + +const glsl_type glsl_type::builtin_130_types[] = { + glsl_type(GL_UNSIGNED_INT, GLSL_TYPE_UINT, 1, 1, "uint"), + glsl_type(GL_UNSIGNED_INT_VEC2, GLSL_TYPE_UINT, 2, 1, "uvec2"), + glsl_type(GL_UNSIGNED_INT_VEC3, GLSL_TYPE_UINT, 3, 1, "uvec3"), + glsl_type(GL_UNSIGNED_INT_VEC4, GLSL_TYPE_UINT, 4, 1, "uvec4"), + + /* 1D and 2D texture arrays - several of these are included only in + * builtin_EXT_texture_array_types. + */ + glsl_type(GL_INT_SAMPLER_1D_ARRAY, + GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_INT, "isampler1DArray"), + glsl_type(GL_UNSIGNED_INT_SAMPLER_1D_ARRAY, + GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_UINT, "usampler1DArray"), + glsl_type(GL_INT_SAMPLER_2D_ARRAY, + GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_INT, "isampler2DArray"), + glsl_type(GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, + GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_UINT, "usampler2DArray"), + + /* cube shadow samplers */ + glsl_type(GL_SAMPLER_CUBE_SHADOW, + GLSL_SAMPLER_DIM_CUBE, 1, 0, GLSL_TYPE_FLOAT, "samplerCubeShadow"), + + /* signed and unsigned integer samplers */ + glsl_type(GL_INT_SAMPLER_1D, + GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_INT, "isampler1D"), + glsl_type(GL_UNSIGNED_INT_SAMPLER_1D, + GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_UINT, "usampler1D"), + glsl_type(GL_INT_SAMPLER_2D, + GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_INT, "isampler2D"), + glsl_type(GL_UNSIGNED_INT_SAMPLER_2D, + GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_UINT, "usampler2D"), + glsl_type(GL_INT_SAMPLER_3D, + GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_INT, "isampler3D"), + glsl_type(GL_UNSIGNED_INT_SAMPLER_3D, + GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_UINT, "usampler3D"), + glsl_type(GL_INT_SAMPLER_CUBE, + GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_INT, "isamplerCube"), + glsl_type(GL_INT_SAMPLER_CUBE, + GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_UINT, "usamplerCube"), +}; + +const glsl_type *const glsl_type::uint_type = & builtin_130_types[0]; +const glsl_type *const glsl_type::uvec2_type = & builtin_130_types[1]; +const glsl_type *const glsl_type::uvec3_type = & builtin_130_types[2]; +const glsl_type *const glsl_type::uvec4_type = & builtin_130_types[3]; +/*@}*/ + +/** \name Sampler types added by GL_ARB_texture_rectangle + */ +/*@{*/ + +const glsl_type glsl_type::builtin_ARB_texture_rectangle_types[] = { + glsl_type(GL_SAMPLER_2D_RECT, + GLSL_SAMPLER_DIM_RECT, 0, 0, GLSL_TYPE_FLOAT, "sampler2DRect"), + glsl_type(GL_SAMPLER_2D_RECT_SHADOW, + GLSL_SAMPLER_DIM_RECT, 1, 0, GLSL_TYPE_FLOAT, "sampler2DRectShadow"), +}; +/*@}*/ + +/** \name Sampler types added by GL_EXT_texture_array + */ +/*@{*/ + +const glsl_type glsl_type::builtin_EXT_texture_array_types[] = { + glsl_type(GL_SAMPLER_1D_ARRAY, + GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_FLOAT, "sampler1DArray"), + glsl_type(GL_SAMPLER_2D_ARRAY, + GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_FLOAT, "sampler2DArray"), + glsl_type(GL_SAMPLER_1D_ARRAY_SHADOW, + GLSL_SAMPLER_DIM_1D, 1, 1, GLSL_TYPE_FLOAT, "sampler1DArrayShadow"), + glsl_type(GL_SAMPLER_2D_ARRAY_SHADOW, + GLSL_SAMPLER_DIM_2D, 1, 1, GLSL_TYPE_FLOAT, "sampler2DArrayShadow"), +}; +/*@}*/ + +/** \name Sampler types added by GL_EXT_texture_buffer_object + */ +/*@{*/ + +const glsl_type glsl_type::builtin_EXT_texture_buffer_object_types[] = { + glsl_type(GL_SAMPLER_BUFFER, + GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_FLOAT, "samplerBuffer"), + glsl_type(GL_INT_SAMPLER_BUFFER, + GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_INT, "isamplerBuffer"), + glsl_type(GL_UNSIGNED_INT_SAMPLER_BUFFER, + GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_UINT, "usamplerBuffer"), +}; +/*@}*/ diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp index d7a37aef4..e8c60936f 100644 --- a/mesalib/src/glsl/glsl_parser_extras.cpp +++ b/mesalib/src/glsl/glsl_parser_extras.cpp @@ -256,6 +256,11 @@ _mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp, state->AMD_conservative_depth_enable = (ext_mode != extension_disable); state->AMD_conservative_depth_warn = (ext_mode == extension_warn); unsupported = !state->extensions->AMD_conservative_depth; + } else if (strcmp(name, "GL_OES_texture_3D") == 0 && state->es_shader) { + state->OES_texture_3D_enable = (ext_mode != extension_disable); + state->OES_texture_3D_warn = (ext_mode == extension_warn); + + unsupported = !state->extensions->EXT_texture3D; } else { unsupported = true; } diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h index 10cb673c6..b5c016fb3 100644 --- a/mesalib/src/glsl/glsl_parser_extras.h +++ b/mesalib/src/glsl/glsl_parser_extras.h @@ -172,6 +172,8 @@ struct _mesa_glsl_parse_state { unsigned ARB_shader_stencil_export_warn:1; unsigned AMD_conservative_depth_enable:1; unsigned AMD_conservative_depth_warn:1; + unsigned OES_texture_3D_enable:1; + unsigned OES_texture_3D_warn:1; /*@}*/ /** Extensions supported by the OpenGL implementation. */ diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp index 76b4f3e4c..78d10bd93 100644 --- a/mesalib/src/glsl/glsl_types.cpp +++ b/mesalib/src/glsl/glsl_types.cpp @@ -131,6 +131,7 @@ glsl_type::generate_110_types(glsl_symbol_table *symtab) add_types_to_symbol_table(symtab, builtin_110_types, Elements(builtin_110_types), false); + add_types_to_symbol_table(symtab, &_sampler3D_type, 1, false); add_types_to_symbol_table(symtab, builtin_110_deprecated_structure_types, Elements(builtin_110_deprecated_structure_types), false); @@ -178,6 +179,13 @@ glsl_type::generate_EXT_texture_array_types(glsl_symbol_table *symtab, } +void +glsl_type::generate_OES_texture_3D_types(glsl_symbol_table *symtab, bool warn) +{ + add_types_to_symbol_table(symtab, &_sampler3D_type, 1, warn); +} + + void _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state) { @@ -204,6 +212,10 @@ _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state) glsl_type::generate_ARB_texture_rectangle_types(state->symbols, state->ARB_texture_rectangle_warn); } + if (state->OES_texture_3D_enable && state->language_version == 100) { + glsl_type::generate_OES_texture_3D_types(state->symbols, + state->OES_texture_3D_warn); + } if (state->EXT_texture_array_enable && state->language_version < 130) { // These are already included in 130; don't create twice. diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h index 61bf5e0cf..3c2672c01 100644 --- a/mesalib/src/glsl/glsl_types.h +++ b/mesalib/src/glsl/glsl_types.h @@ -427,6 +427,7 @@ private: /*@{*/ static const glsl_type _error_type; static const glsl_type _void_type; + static const glsl_type _sampler3D_type; static const glsl_type builtin_core_types[]; static const glsl_type builtin_structure_types[]; static const glsl_type builtin_110_deprecated_structure_types[]; @@ -453,6 +454,7 @@ private: static void generate_130_types(glsl_symbol_table *); static void generate_ARB_texture_rectangle_types(glsl_symbol_table *, bool); static void generate_EXT_texture_array_types(glsl_symbol_table *, bool); + static void generate_OES_texture_3D_types(glsl_symbol_table *, bool); /*@}*/ /** diff --git a/mesalib/src/mesa/SConscript b/mesalib/src/mesa/SConscript index ea04fb1a0..d65750b93 100644 --- a/mesalib/src/mesa/SConscript +++ b/mesalib/src/mesa/SConscript @@ -87,6 +87,7 @@ main_sources = [ 'main/multisample.c', 'main/nvprogram.c', 'main/pack.c', + 'main/pbo.c', 'main/pixel.c', 'main/pixelstore.c', 'main/pixeltransfer.c', @@ -106,6 +107,7 @@ main_sources = [ 'main/stencil.c', 'main/syncobj.c', 'main/texcompress.c', + 'main/texcompress_rgtc.c', 'main/texcompress_s3tc.c', 'main/texcompress_fxt1.c', 'main/texenv.c', diff --git a/mesalib/src/mesa/drivers/common/meta.c b/mesalib/src/mesa/drivers/common/meta.c index 9c0507bc2..2b00e8979 100644 --- a/mesalib/src/mesa/drivers/common/meta.c +++ b/mesalib/src/mesa/drivers/common/meta.c @@ -1,2851 +1,2852 @@ -/* - * Mesa 3-D graphics library - * Version: 7.6 - * - * 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. - */ - -/** - * Meta operations. Some GL operations can be expressed in terms of - * other GL operations. For example, glBlitFramebuffer() can be done - * with texture mapping and glClear() can be done with polygon rendering. - * - * \author Brian Paul - */ - - -#include "main/glheader.h" -#include "main/mtypes.h" -#include "main/imports.h" -#include "main/arbprogram.h" -#include "main/arrayobj.h" -#include "main/blend.h" -#include "main/bufferobj.h" -#include "main/buffers.h" -#include "main/colortab.h" -#include "main/depth.h" -#include "main/enable.h" -#include "main/fbobject.h" -#include "main/formats.h" -#include "main/image.h" -#include "main/macros.h" -#include "main/matrix.h" -#include "main/mipmap.h" -#include "main/polygon.h" -#include "main/readpix.h" -#include "main/scissor.h" -#include "main/shaderapi.h" -#include "main/shaderobj.h" -#include "main/state.h" -#include "main/stencil.h" -#include "main/texobj.h" -#include "main/texenv.h" -#include "main/teximage.h" -#include "main/texparam.h" -#include "main/texstate.h" -#include "main/varray.h" -#include "main/viewport.h" -#include "program/program.h" -#include "swrast/swrast.h" -#include "drivers/common/meta.h" - - -/** Return offset in bytes of the field within a vertex struct */ -#define OFFSET(FIELD) ((void *) offsetof(struct vertex, FIELD)) - - -/** - * Flags passed to _mesa_meta_begin(). - */ -/*@{*/ -#define META_ALL ~0x0 -#define META_ALPHA_TEST 0x1 -#define META_BLEND 0x2 /**< includes logicop */ -#define META_COLOR_MASK 0x4 -#define META_DEPTH_TEST 0x8 -#define META_FOG 0x10 -#define META_PIXEL_STORE 0x20 -#define META_PIXEL_TRANSFER 0x40 -#define META_RASTERIZATION 0x80 -#define META_SCISSOR 0x100 -#define META_SHADER 0x200 -#define META_STENCIL_TEST 0x400 -#define META_TRANSFORM 0x800 /**< modelview, projection, clip planes */ -#define META_TEXTURE 0x1000 -#define META_VERTEX 0x2000 -#define META_VIEWPORT 0x4000 -/*@}*/ - - -/** - * State which we may save/restore across meta ops. - * XXX this may be incomplete... - */ -struct save_state -{ - GLbitfield SavedState; /**< bitmask of META_* flags */ - - /** META_ALPHA_TEST */ - GLboolean AlphaEnabled; - GLenum AlphaFunc; - GLclampf AlphaRef; - - /** META_BLEND */ - GLbitfield BlendEnabled; - GLboolean ColorLogicOpEnabled; - - /** META_COLOR_MASK */ - GLubyte ColorMask[MAX_DRAW_BUFFERS][4]; - - /** META_DEPTH_TEST */ - struct gl_depthbuffer_attrib Depth; - - /** META_FOG */ - GLboolean Fog; - - /** META_PIXEL_STORE */ - struct gl_pixelstore_attrib Pack, Unpack; - - /** META_PIXEL_TRANSFER */ - GLfloat RedBias, RedScale; - GLfloat GreenBias, GreenScale; - GLfloat BlueBias, BlueScale; - GLfloat AlphaBias, AlphaScale; - GLfloat DepthBias, DepthScale; - GLboolean MapColorFlag; - - /** META_RASTERIZATION */ - GLenum FrontPolygonMode, BackPolygonMode; - GLboolean PolygonOffset; - GLboolean PolygonSmooth; - GLboolean PolygonStipple; - GLboolean PolygonCull; - - /** META_SCISSOR */ - struct gl_scissor_attrib Scissor; - - /** META_SHADER */ - GLboolean VertexProgramEnabled; - struct gl_vertex_program *VertexProgram; - GLboolean FragmentProgramEnabled; - struct gl_fragment_program *FragmentProgram; - struct gl_shader_program *VertexShader; - struct gl_shader_program *GeometryShader; - struct gl_shader_program *FragmentShader; - struct gl_shader_program *ActiveShader; - - /** META_STENCIL_TEST */ - struct gl_stencil_attrib Stencil; - - /** META_TRANSFORM */ - GLenum MatrixMode; - GLfloat ModelviewMatrix[16]; - GLfloat ProjectionMatrix[16]; - GLfloat TextureMatrix[16]; - GLbitfield ClipPlanesEnabled; - - /** META_TEXTURE */ - GLuint ActiveUnit; - GLuint ClientActiveUnit; - /** for unit[0] only */ - struct gl_texture_object *CurrentTexture[NUM_TEXTURE_TARGETS]; - /** mask of TEXTURE_2D_BIT, etc */ - GLbitfield TexEnabled[MAX_TEXTURE_UNITS]; - GLbitfield TexGenEnabled[MAX_TEXTURE_UNITS]; - GLuint EnvMode; /* unit[0] only */ - - /** META_VERTEX */ - struct gl_array_object *ArrayObj; - struct gl_buffer_object *ArrayBufferObj; - - /** META_VIEWPORT */ - GLint ViewportX, ViewportY, ViewportW, ViewportH; - GLclampd DepthNear, DepthFar; - - /** Miscellaneous (always disabled) */ - GLboolean Lighting; -}; - - -/** - * Temporary texture used for glBlitFramebuffer, glDrawPixels, etc. - * This is currently shared by all the meta ops. But we could create a - * separate one for each of glDrawPixel, glBlitFramebuffer, glCopyPixels, etc. - */ -struct temp_texture -{ - GLuint TexObj; - GLenum Target; /**< GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE */ - GLsizei MinSize; /**< Min texture size to allocate */ - GLsizei MaxSize; /**< Max possible texture size */ - GLboolean NPOT; /**< Non-power of two size OK? */ - GLsizei Width, Height; /**< Current texture size */ - GLenum IntFormat; - GLfloat Sright, Ttop; /**< right, top texcoords */ -}; - - -/** - * State for glBlitFramebufer() - */ -struct blit_state -{ - GLuint ArrayObj; - GLuint VBO; - GLuint DepthFP; -}; - - -/** - * State for glClear() - */ -struct clear_state -{ - GLuint ArrayObj; - GLuint VBO; -}; - - -/** - * State for glCopyPixels() - */ -struct copypix_state -{ - GLuint ArrayObj; - GLuint VBO; -}; - - -/** - * State for glDrawPixels() - */ -struct drawpix_state -{ - GLuint ArrayObj; - - GLuint StencilFP; /**< Fragment program for drawing stencil images */ - GLuint DepthFP; /**< Fragment program for drawing depth images */ -}; - - -/** - * State for glBitmap() - */ -struct bitmap_state -{ - GLuint ArrayObj; - GLuint VBO; - struct temp_texture Tex; /**< separate texture from other meta ops */ -}; - - -/** - * State for _mesa_meta_generate_mipmap() - */ -struct gen_mipmap_state -{ - GLuint ArrayObj; - GLuint VBO; - GLuint FBO; -}; - -#define MAX_META_OPS_DEPTH 2 -/** - * All per-context meta state. - */ -struct gl_meta_state -{ - /** Stack of state saved during meta-ops */ - struct save_state Save[MAX_META_OPS_DEPTH]; - /** Save stack depth */ - GLuint SaveStackDepth; - - struct temp_texture TempTex; - - struct blit_state Blit; /**< For _mesa_meta_BlitFramebuffer() */ - struct clear_state Clear; /**< For _mesa_meta_Clear() */ - struct copypix_state CopyPix; /**< For _mesa_meta_CopyPixels() */ - struct drawpix_state DrawPix; /**< For _mesa_meta_DrawPixels() */ - struct bitmap_state Bitmap; /**< For _mesa_meta_Bitmap() */ - struct gen_mipmap_state Mipmap; /**< For _mesa_meta_GenerateMipmap() */ -}; - - -/** - * Initialize meta-ops for a context. - * To be called once during context creation. - */ -void -_mesa_meta_init(struct gl_context *ctx) -{ - ASSERT(!ctx->Meta); - - ctx->Meta = CALLOC_STRUCT(gl_meta_state); -} - - -/** - * Free context meta-op state. - * To be called once during context destruction. - */ -void -_mesa_meta_free(struct gl_context *ctx) -{ - /* Note: Any textures, VBOs, etc, that we allocate should get - * freed by the normal context destruction code. But this would be - * the place to free other meta data someday. - */ - free(ctx->Meta); - ctx->Meta = NULL; -} - - -/** - * Enter meta state. This is like a light-weight version of glPushAttrib - * but it also resets most GL state back to default values. - * - * \param state bitmask of META_* flags indicating which attribute groups - * to save and reset to their defaults - */ -static void -_mesa_meta_begin(struct gl_context *ctx, GLbitfield state) -{ - struct save_state *save; - - /* hope MAX_META_OPS_DEPTH is large enough */ - assert(ctx->Meta->SaveStackDepth < MAX_META_OPS_DEPTH); - - save = &ctx->Meta->Save[ctx->Meta->SaveStackDepth++]; - memset(save, 0, sizeof(*save)); - save->SavedState = state; - - if (state & META_ALPHA_TEST) { - save->AlphaEnabled = ctx->Color.AlphaEnabled; - save->AlphaFunc = ctx->Color.AlphaFunc; - save->AlphaRef = ctx->Color.AlphaRef; - if (ctx->Color.AlphaEnabled) - _mesa_set_enable(ctx, GL_ALPHA_TEST, GL_FALSE); - } - - if (state & META_BLEND) { - save->BlendEnabled = ctx->Color.BlendEnabled; - if (ctx->Color.BlendEnabled) { - if (ctx->Extensions.EXT_draw_buffers2) { - GLuint i; - for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { - _mesa_set_enablei(ctx, GL_BLEND, i, GL_FALSE); - } - } - else { - _mesa_set_enable(ctx, GL_BLEND, GL_FALSE); - } - } - save->ColorLogicOpEnabled = ctx->Color.ColorLogicOpEnabled; - if (ctx->Color.ColorLogicOpEnabled) - _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, GL_FALSE); - } - - if (state & META_COLOR_MASK) { - memcpy(save->ColorMask, ctx->Color.ColorMask, - sizeof(ctx->Color.ColorMask)); - if (!ctx->Color.ColorMask[0][0] || - !ctx->Color.ColorMask[0][1] || - !ctx->Color.ColorMask[0][2] || - !ctx->Color.ColorMask[0][3]) - _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - } - - if (state & META_DEPTH_TEST) { - save->Depth = ctx->Depth; /* struct copy */ - if (ctx->Depth.Test) - _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE); - } - - if (state & META_FOG) { - save->Fog = ctx->Fog.Enabled; - if (ctx->Fog.Enabled) - _mesa_set_enable(ctx, GL_FOG, GL_FALSE); - } - - if (state & META_PIXEL_STORE) { - save->Pack = ctx->Pack; - save->Unpack = ctx->Unpack; - ctx->Pack = ctx->DefaultPacking; - ctx->Unpack = ctx->DefaultPacking; - } - - if (state & META_PIXEL_TRANSFER) { - save->RedScale = ctx->Pixel.RedScale; - save->RedBias = ctx->Pixel.RedBias; - save->GreenScale = ctx->Pixel.GreenScale; - save->GreenBias = ctx->Pixel.GreenBias; - save->BlueScale = ctx->Pixel.BlueScale; - save->BlueBias = ctx->Pixel.BlueBias; - save->AlphaScale = ctx->Pixel.AlphaScale; - save->AlphaBias = ctx->Pixel.AlphaBias; - save->MapColorFlag = ctx->Pixel.MapColorFlag; - ctx->Pixel.RedScale = 1.0F; - ctx->Pixel.RedBias = 0.0F; - ctx->Pixel.GreenScale = 1.0F; - ctx->Pixel.GreenBias = 0.0F; - ctx->Pixel.BlueScale = 1.0F; - ctx->Pixel.BlueBias = 0.0F; - ctx->Pixel.AlphaScale = 1.0F; - ctx->Pixel.AlphaBias = 0.0F; - ctx->Pixel.MapColorFlag = GL_FALSE; - /* XXX more state */ - ctx->NewState |=_NEW_PIXEL; - } - - if (state & META_RASTERIZATION) { - save->FrontPolygonMode = ctx->Polygon.FrontMode; - save->BackPolygonMode = ctx->Polygon.BackMode; - save->PolygonOffset = ctx->Polygon.OffsetFill; - save->PolygonSmooth = ctx->Polygon.SmoothFlag; - save->PolygonStipple = ctx->Polygon.StippleFlag; - save->PolygonCull = ctx->Polygon.CullFlag; - _mesa_PolygonMode(GL_FRONT_AND_BACK, GL_FILL); - _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, GL_FALSE); - _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, GL_FALSE); - _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, GL_FALSE); - _mesa_set_enable(ctx, GL_CULL_FACE, GL_FALSE); - } - - if (state & META_SCISSOR) { - save->Scissor = ctx->Scissor; /* struct copy */ - _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_FALSE); - } - - if (state & META_SHADER) { - if (ctx->Extensions.ARB_vertex_program) { - save->VertexProgramEnabled = ctx->VertexProgram.Enabled; - _mesa_reference_vertprog(ctx, &save->VertexProgram, - ctx->VertexProgram.Current); - _mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB, GL_FALSE); - } - - if (ctx->Extensions.ARB_fragment_program) { - save->FragmentProgramEnabled = ctx->FragmentProgram.Enabled; - _mesa_reference_fragprog(ctx, &save->FragmentProgram, - ctx->FragmentProgram.Current); - _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_FALSE); - } - - if (ctx->Extensions.ARB_shader_objects) { - _mesa_reference_shader_program(ctx, &save->VertexShader, - ctx->Shader.CurrentVertexProgram); - _mesa_reference_shader_program(ctx, &save->GeometryShader, - ctx->Shader.CurrentGeometryProgram); - _mesa_reference_shader_program(ctx, &save->FragmentShader, - ctx->Shader.CurrentFragmentProgram); - _mesa_reference_shader_program(ctx, &save->ActiveShader, - ctx->Shader.CurrentFragmentProgram); - - _mesa_UseProgramObjectARB(0); - } - } - - if (state & META_STENCIL_TEST) { - save->Stencil = ctx->Stencil; /* struct copy */ - if (ctx->Stencil.Enabled) - _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_FALSE); - /* NOTE: other stencil state not reset */ - } - - if (state & META_TEXTURE) { - GLuint u, tgt; - - save->ActiveUnit = ctx->Texture.CurrentUnit; - save->ClientActiveUnit = ctx->Array.ActiveTexture; - save->EnvMode = ctx->Texture.Unit[0].EnvMode; - - /* Disable all texture units */ - for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { - save->TexEnabled[u] = ctx->Texture.Unit[u].Enabled; - save->TexGenEnabled[u] = ctx->Texture.Unit[u].TexGenEnabled; - if (ctx->Texture.Unit[u].Enabled || - ctx->Texture.Unit[u].TexGenEnabled) { - _mesa_ActiveTextureARB(GL_TEXTURE0 + u); - _mesa_set_enable(ctx, GL_TEXTURE_1D, GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_2D, GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_3D, GL_FALSE); - if (ctx->Extensions.ARB_texture_cube_map) - _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE, GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, GL_FALSE); - } - } - - /* save current texture objects for unit[0] only */ - for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { - _mesa_reference_texobj(&save->CurrentTexture[tgt], - ctx->Texture.Unit[0].CurrentTex[tgt]); - } - - /* set defaults for unit[0] */ - _mesa_ActiveTextureARB(GL_TEXTURE0); - _mesa_ClientActiveTextureARB(GL_TEXTURE0); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - } - - if (state & META_TRANSFORM) { - GLuint activeTexture = ctx->Texture.CurrentUnit; - memcpy(save->ModelviewMatrix, ctx->ModelviewMatrixStack.Top->m, - 16 * sizeof(GLfloat)); - memcpy(save->ProjectionMatrix, ctx->ProjectionMatrixStack.Top->m, - 16 * sizeof(GLfloat)); - memcpy(save->TextureMatrix, ctx->TextureMatrixStack[0].Top->m, - 16 * sizeof(GLfloat)); - save->MatrixMode = ctx->Transform.MatrixMode; - /* set 1:1 vertex:pixel coordinate transform */ - _mesa_ActiveTextureARB(GL_TEXTURE0); - _mesa_MatrixMode(GL_TEXTURE); - _mesa_LoadIdentity(); - _mesa_ActiveTextureARB(GL_TEXTURE0 + activeTexture); - _mesa_MatrixMode(GL_MODELVIEW); - _mesa_LoadIdentity(); - _mesa_MatrixMode(GL_PROJECTION); - _mesa_LoadIdentity(); - _mesa_Ortho(0.0, ctx->DrawBuffer->Width, - 0.0, ctx->DrawBuffer->Height, - -1.0, 1.0); - save->ClipPlanesEnabled = ctx->Transform.ClipPlanesEnabled; - if (ctx->Transform.ClipPlanesEnabled) { - GLuint i; - for (i = 0; i < ctx->Const.MaxClipPlanes; i++) { - _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_FALSE); - } - } - } - - if (state & META_VERTEX) { - /* save vertex array object state */ - _mesa_reference_array_object(ctx, &save->ArrayObj, - ctx->Array.ArrayObj); - _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj, - ctx->Array.ArrayBufferObj); - /* set some default state? */ - } - - if (state & META_VIEWPORT) { - /* save viewport state */ - save->ViewportX = ctx->Viewport.X; - save->ViewportY = ctx->Viewport.Y; - save->ViewportW = ctx->Viewport.Width; - save->ViewportH = ctx->Viewport.Height; - /* set viewport to match window size */ - if (ctx->Viewport.X != 0 || - ctx->Viewport.Y != 0 || - ctx->Viewport.Width != ctx->DrawBuffer->Width || - ctx->Viewport.Height != ctx->DrawBuffer->Height) { - _mesa_set_viewport(ctx, 0, 0, - ctx->DrawBuffer->Width, ctx->DrawBuffer->Height); - } - /* save depth range state */ - save->DepthNear = ctx->Viewport.Near; - save->DepthFar = ctx->Viewport.Far; - /* set depth range to default */ - _mesa_DepthRange(0.0, 1.0); - } - - /* misc */ - { - save->Lighting = ctx->Light.Enabled; - if (ctx->Light.Enabled) - _mesa_set_enable(ctx, GL_LIGHTING, GL_FALSE); - } -} - - -/** - * Leave meta state. This is like a light-weight version of glPopAttrib(). - */ -static void -_mesa_meta_end(struct gl_context *ctx) -{ - struct save_state *save = &ctx->Meta->Save[--ctx->Meta->SaveStackDepth]; - const GLbitfield state = save->SavedState; - - if (state & META_ALPHA_TEST) { - if (ctx->Color.AlphaEnabled != save->AlphaEnabled) - _mesa_set_enable(ctx, GL_ALPHA_TEST, save->AlphaEnabled); - _mesa_AlphaFunc(save->AlphaFunc, save->AlphaRef); - } - - if (state & META_BLEND) { - if (ctx->Color.BlendEnabled != save->BlendEnabled) { - if (ctx->Extensions.EXT_draw_buffers2) { - GLuint i; - for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { - _mesa_set_enablei(ctx, GL_BLEND, i, (save->BlendEnabled >> i) & 1); - } - } - else { - _mesa_set_enable(ctx, GL_BLEND, (save->BlendEnabled & 1)); - } - } - if (ctx->Color.ColorLogicOpEnabled != save->ColorLogicOpEnabled) - _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, save->ColorLogicOpEnabled); - } - - if (state & META_COLOR_MASK) { - GLuint i; - for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { - if (!TEST_EQ_4V(ctx->Color.ColorMask[i], save->ColorMask[i])) { - if (i == 0) { - _mesa_ColorMask(save->ColorMask[i][0], save->ColorMask[i][1], - save->ColorMask[i][2], save->ColorMask[i][3]); - } - else { - _mesa_ColorMaskIndexed(i, - save->ColorMask[i][0], - save->ColorMask[i][1], - save->ColorMask[i][2], - save->ColorMask[i][3]); - } - } - } - } - - if (state & META_DEPTH_TEST) { - if (ctx->Depth.Test != save->Depth.Test) - _mesa_set_enable(ctx, GL_DEPTH_TEST, save->Depth.Test); - _mesa_DepthFunc(save->Depth.Func); - _mesa_DepthMask(save->Depth.Mask); - } - - if (state & META_FOG) { - _mesa_set_enable(ctx, GL_FOG, save->Fog); - } - - if (state & META_PIXEL_STORE) { - ctx->Pack = save->Pack; - ctx->Unpack = save->Unpack; - } - - if (state & META_PIXEL_TRANSFER) { - ctx->Pixel.RedScale = save->RedScale; - ctx->Pixel.RedBias = save->RedBias; - ctx->Pixel.GreenScale = save->GreenScale; - ctx->Pixel.GreenBias = save->GreenBias; - ctx->Pixel.BlueScale = save->BlueScale; - ctx->Pixel.BlueBias = save->BlueBias; - ctx->Pixel.AlphaScale = save->AlphaScale; - ctx->Pixel.AlphaBias = save->AlphaBias; - ctx->Pixel.MapColorFlag = save->MapColorFlag; - /* XXX more state */ - ctx->NewState |=_NEW_PIXEL; - } - - if (state & META_RASTERIZATION) { - _mesa_PolygonMode(GL_FRONT, save->FrontPolygonMode); - _mesa_PolygonMode(GL_BACK, save->BackPolygonMode); - _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, save->PolygonStipple); - _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, save->PolygonOffset); - _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, save->PolygonSmooth); - _mesa_set_enable(ctx, GL_CULL_FACE, save->PolygonCull); - } - - if (state & META_SCISSOR) { - _mesa_set_enable(ctx, GL_SCISSOR_TEST, save->Scissor.Enabled); - _mesa_Scissor(save->Scissor.X, save->Scissor.Y, - save->Scissor.Width, save->Scissor.Height); - } - - if (state & META_SHADER) { - if (ctx->Extensions.ARB_vertex_program) { - _mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB, - save->VertexProgramEnabled); - _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, - save->VertexProgram); - _mesa_reference_vertprog(ctx, &save->VertexProgram, NULL); - } - - if (ctx->Extensions.ARB_fragment_program) { - _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, - save->FragmentProgramEnabled); - _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, - save->FragmentProgram); - _mesa_reference_fragprog(ctx, &save->FragmentProgram, NULL); - } - - if (ctx->Extensions.ARB_vertex_shader) - _mesa_use_shader_program(ctx, GL_VERTEX_SHADER, save->VertexShader); - - if (ctx->Extensions.ARB_geometry_shader4) - _mesa_use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, - save->GeometryShader); - - if (ctx->Extensions.ARB_fragment_shader) - _mesa_use_shader_program(ctx, GL_FRAGMENT_SHADER, - save->FragmentShader); - - _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, - save->ActiveShader); - } - - if (state & META_STENCIL_TEST) { - const struct gl_stencil_attrib *stencil = &save->Stencil; - - _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled); - _mesa_ClearStencil(stencil->Clear); - if (ctx->Extensions.EXT_stencil_two_side) { - _mesa_set_enable(ctx, GL_STENCIL_TEST_TWO_SIDE_EXT, - stencil->TestTwoSide); - _mesa_ActiveStencilFaceEXT(stencil->ActiveFace - ? GL_BACK : GL_FRONT); - } - /* front state */ - _mesa_StencilFuncSeparate(GL_FRONT, - stencil->Function[0], - stencil->Ref[0], - stencil->ValueMask[0]); - _mesa_StencilMaskSeparate(GL_FRONT, stencil->WriteMask[0]); - _mesa_StencilOpSeparate(GL_FRONT, stencil->FailFunc[0], - stencil->ZFailFunc[0], - stencil->ZPassFunc[0]); - /* back state */ - _mesa_StencilFuncSeparate(GL_BACK, - stencil->Function[1], - stencil->Ref[1], - stencil->ValueMask[1]); - _mesa_StencilMaskSeparate(GL_BACK, stencil->WriteMask[1]); - _mesa_StencilOpSeparate(GL_BACK, stencil->FailFunc[1], - stencil->ZFailFunc[1], - stencil->ZPassFunc[1]); - } - - if (state & META_TEXTURE) { - GLuint u, tgt; - - ASSERT(ctx->Texture.CurrentUnit == 0); - - /* restore texenv for unit[0] */ - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, save->EnvMode); - - /* restore texture objects for unit[0] only */ - for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { - _mesa_reference_texobj(&ctx->Texture.Unit[0].CurrentTex[tgt], - save->CurrentTexture[tgt]); - _mesa_reference_texobj(&save->CurrentTexture[tgt], NULL); - } - - /* Re-enable textures, texgen */ - for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { - if (save->TexEnabled[u]) { - _mesa_ActiveTextureARB(GL_TEXTURE0 + u); - - if (save->TexEnabled[u] & TEXTURE_1D_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_1D, GL_TRUE); - if (save->TexEnabled[u] & TEXTURE_2D_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_2D, GL_TRUE); - if (save->TexEnabled[u] & TEXTURE_3D_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_3D, GL_TRUE); - if (save->TexEnabled[u] & TEXTURE_CUBE_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, GL_TRUE); - if (save->TexEnabled[u] & TEXTURE_RECT_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE, GL_TRUE); - } - - if (save->TexGenEnabled[u]) { - _mesa_ActiveTextureARB(GL_TEXTURE0 + u); - - if (save->TexGenEnabled[u] & S_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, GL_TRUE); - if (save->TexGenEnabled[u] & T_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, GL_TRUE); - if (save->TexGenEnabled[u] & R_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, GL_TRUE); - if (save->TexGenEnabled[u] & Q_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, GL_TRUE); - } - } - - /* restore current unit state */ - _mesa_ActiveTextureARB(GL_TEXTURE0 + save->ActiveUnit); - _mesa_ClientActiveTextureARB(GL_TEXTURE0 + save->ClientActiveUnit); - } - - if (state & META_TRANSFORM) { - GLuint activeTexture = ctx->Texture.CurrentUnit; - _mesa_ActiveTextureARB(GL_TEXTURE0); - _mesa_MatrixMode(GL_TEXTURE); - _mesa_LoadMatrixf(save->TextureMatrix); - _mesa_ActiveTextureARB(GL_TEXTURE0 + activeTexture); - - _mesa_MatrixMode(GL_MODELVIEW); - _mesa_LoadMatrixf(save->ModelviewMatrix); - - _mesa_MatrixMode(GL_PROJECTION); - _mesa_LoadMatrixf(save->ProjectionMatrix); - - _mesa_MatrixMode(save->MatrixMode); - - if (save->ClipPlanesEnabled) { - GLuint i; - for (i = 0; i < ctx->Const.MaxClipPlanes; i++) { - if (save->ClipPlanesEnabled & (1 << i)) { - _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_TRUE); - } - } - } - } - - if (state & META_VERTEX) { - /* restore vertex buffer object */ - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, save->ArrayBufferObj->Name); - _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj, NULL); - - /* restore vertex array object */ - _mesa_BindVertexArray(save->ArrayObj->Name); - _mesa_reference_array_object(ctx, &save->ArrayObj, NULL); - } - - if (state & META_VIEWPORT) { - if (save->ViewportX != ctx->Viewport.X || - save->ViewportY != ctx->Viewport.Y || - save->ViewportW != ctx->Viewport.Width || - save->ViewportH != ctx->Viewport.Height) { - _mesa_set_viewport(ctx, save->ViewportX, save->ViewportY, - save->ViewportW, save->ViewportH); - } - _mesa_DepthRange(save->DepthNear, save->DepthFar); - } - - /* misc */ - if (save->Lighting) { - _mesa_set_enable(ctx, GL_LIGHTING, GL_TRUE); - } -} - - -/** - * Convert Z from a normalized value in the range [0, 1] to an object-space - * Z coordinate in [-1, +1] so that drawing at the new Z position with the - * default/identity ortho projection results in the original Z value. - * Used by the meta-Clear, Draw/CopyPixels and Bitmap functions where the Z - * value comes from the clear value or raster position. - */ -static INLINE GLfloat -invert_z(GLfloat normZ) -{ - GLfloat objZ = 1.0 - 2.0 * normZ; - return objZ; -} - - -/** - * One-time init for a temp_texture object. - * Choose tex target, compute max tex size, etc. - */ -static void -init_temp_texture(struct gl_context *ctx, struct temp_texture *tex) -{ - /* prefer texture rectangle */ - if (ctx->Extensions.NV_texture_rectangle) { - tex->Target = GL_TEXTURE_RECTANGLE; - tex->MaxSize = ctx->Const.MaxTextureRectSize; - tex->NPOT = GL_TRUE; - } - else { - /* use 2D texture, NPOT if possible */ - tex->Target = GL_TEXTURE_2D; - tex->MaxSize = 1 << (ctx->Const.MaxTextureLevels - 1); - tex->NPOT = ctx->Extensions.ARB_texture_non_power_of_two; - } - tex->MinSize = 16; /* 16 x 16 at least */ - assert(tex->MaxSize > 0); - - _mesa_GenTextures(1, &tex->TexObj); -} - - -/** - * Return pointer to temp_texture info for non-bitmap ops. - * This does some one-time init if needed. - */ -static struct temp_texture * -get_temp_texture(struct gl_context *ctx) -{ - struct temp_texture *tex = &ctx->Meta->TempTex; - - if (!tex->TexObj) { - init_temp_texture(ctx, tex); - } - - return tex; -} - - -/** - * Return pointer to temp_texture info for _mesa_meta_bitmap(). - * We use a separate texture for bitmaps to reduce texture - * allocation/deallocation. - */ -static struct temp_texture * -get_bitmap_temp_texture(struct gl_context *ctx) -{ - struct temp_texture *tex = &ctx->Meta->Bitmap.Tex; - - if (!tex->TexObj) { - init_temp_texture(ctx, tex); - } - - return tex; -} - - -/** - * Compute the width/height of texture needed to draw an image of the - * given size. Return a flag indicating whether the current texture - * can be re-used (glTexSubImage2D) or if a new texture needs to be - * allocated (glTexImage2D). - * Also, compute s/t texcoords for drawing. - * - * \return GL_TRUE if new texture is needed, GL_FALSE otherwise - */ -static GLboolean -alloc_texture(struct temp_texture *tex, - GLsizei width, GLsizei height, GLenum intFormat) -{ - GLboolean newTex = GL_FALSE; - - ASSERT(width <= tex->MaxSize); - ASSERT(height <= tex->MaxSize); - - if (width > tex->Width || - height > tex->Height || - intFormat != tex->IntFormat) { - /* alloc new texture (larger or different format) */ - - if (tex->NPOT) { - /* use non-power of two size */ - tex->Width = MAX2(tex->MinSize, width); - tex->Height = MAX2(tex->MinSize, height); - } - else { - /* find power of two size */ - GLsizei w, h; - w = h = tex->MinSize; - while (w < width) - w *= 2; - while (h < height) - h *= 2; - tex->Width = w; - tex->Height = h; - } - - tex->IntFormat = intFormat; - - newTex = GL_TRUE; - } - - /* compute texcoords */ - if (tex->Target == GL_TEXTURE_RECTANGLE) { - tex->Sright = (GLfloat) width; - tex->Ttop = (GLfloat) height; - } - else { - tex->Sright = (GLfloat) width / tex->Width; - tex->Ttop = (GLfloat) height / tex->Height; - } - - return newTex; -} - - -/** - * Setup/load texture for glCopyPixels or glBlitFramebuffer. - */ -static void -setup_copypix_texture(struct temp_texture *tex, - GLboolean newTex, - GLint srcX, GLint srcY, - GLsizei width, GLsizei height, GLenum intFormat, - GLenum filter) -{ - _mesa_BindTexture(tex->Target, tex->TexObj); - _mesa_TexParameteri(tex->Target, GL_TEXTURE_MIN_FILTER, filter); - _mesa_TexParameteri(tex->Target, GL_TEXTURE_MAG_FILTER, filter); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - - /* copy framebuffer image to texture */ - if (newTex) { - /* create new tex image */ - if (tex->Width == width && tex->Height == height) { - /* create new tex with framebuffer data */ - _mesa_CopyTexImage2D(tex->Target, 0, tex->IntFormat, - srcX, srcY, width, height, 0); - } - else { - /* create empty texture */ - _mesa_TexImage2D(tex->Target, 0, tex->IntFormat, - tex->Width, tex->Height, 0, - intFormat, GL_UNSIGNED_BYTE, NULL); - /* load image */ - _mesa_CopyTexSubImage2D(tex->Target, 0, - 0, 0, srcX, srcY, width, height); - } - } - else { - /* replace existing tex image */ - _mesa_CopyTexSubImage2D(tex->Target, 0, - 0, 0, srcX, srcY, width, height); - } -} - - -/** - * Setup/load texture for glDrawPixels. - */ -static void -setup_drawpix_texture(struct gl_context *ctx, - struct temp_texture *tex, - GLboolean newTex, - GLenum texIntFormat, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - const GLvoid *pixels) -{ - _mesa_BindTexture(tex->Target, tex->TexObj); - _mesa_TexParameteri(tex->Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - _mesa_TexParameteri(tex->Target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - - /* copy pixel data to texture */ - if (newTex) { - /* create new tex image */ - if (tex->Width == width && tex->Height == height) { - /* create new tex and load image data */ - _mesa_TexImage2D(tex->Target, 0, tex->IntFormat, - tex->Width, tex->Height, 0, format, type, pixels); - } - else { - struct gl_buffer_object *save_unpack_obj = NULL; - - _mesa_reference_buffer_object(ctx, &save_unpack_obj, - ctx->Unpack.BufferObj); - _mesa_BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); - /* create empty texture */ - _mesa_TexImage2D(tex->Target, 0, tex->IntFormat, - tex->Width, tex->Height, 0, format, type, NULL); - if (save_unpack_obj != NULL) - _mesa_BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, - save_unpack_obj->Name); - /* load image */ - _mesa_TexSubImage2D(tex->Target, 0, - 0, 0, width, height, format, type, pixels); - } - } - else { - /* replace existing tex image */ - _mesa_TexSubImage2D(tex->Target, 0, - 0, 0, width, height, format, type, pixels); - } -} - - - -/** - * One-time init for drawing depth pixels. - */ -static void -init_blit_depth_pixels(struct gl_context *ctx) -{ - static const char *program = - "!!ARBfp1.0\n" - "TEX result.depth, fragment.texcoord[0], texture[0], %s; \n" - "END \n"; - char program2[200]; - struct blit_state *blit = &ctx->Meta->Blit; - struct temp_texture *tex = get_temp_texture(ctx); - const char *texTarget; - - assert(blit->DepthFP == 0); - - /* replace %s with "RECT" or "2D" */ - assert(strlen(program) + 4 < sizeof(program2)); - if (tex->Target == GL_TEXTURE_RECTANGLE) - texTarget = "RECT"; - else - texTarget = "2D"; - _mesa_snprintf(program2, sizeof(program2), program, texTarget); - - _mesa_GenPrograms(1, &blit->DepthFP); - _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, blit->DepthFP); - _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, - strlen(program2), (const GLubyte *) program2); -} - - -/** - * Try to do a glBlitFramebuffer using no-copy texturing. - * We can do this when the src renderbuffer is actually a texture. - * But if the src buffer == dst buffer we cannot do this. - * - * \return new buffer mask indicating the buffers left to blit using the - * normal path. - */ -static GLbitfield -blitframebuffer_texture(struct gl_context *ctx, - GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter) -{ - if (mask & GL_COLOR_BUFFER_BIT) { - const struct gl_framebuffer *drawFb = ctx->DrawBuffer; - const struct gl_framebuffer *readFb = ctx->ReadBuffer; - const struct gl_renderbuffer_attachment *drawAtt = - &drawFb->Attachment[drawFb->_ColorDrawBufferIndexes[0]]; - const struct gl_renderbuffer_attachment *readAtt = - &readFb->Attachment[readFb->_ColorReadBufferIndex]; - - if (readAtt && readAtt->Texture) { - const struct gl_texture_object *texObj = readAtt->Texture; - const GLuint srcLevel = readAtt->TextureLevel; - const GLenum minFilterSave = texObj->MinFilter; - const GLenum magFilterSave = texObj->MagFilter; - const GLint baseLevelSave = texObj->BaseLevel; - const GLint maxLevelSave = texObj->MaxLevel; - const GLenum wrapSSave = texObj->WrapS; - const GLenum wrapTSave = texObj->WrapT; - const GLenum target = texObj->Target; - - if (drawAtt->Texture == readAtt->Texture) { - /* Can't use same texture as both the source and dest. We need - * to handle overlapping blits and besides, some hw may not - * support this. - */ - return mask; - } - - if (target != GL_TEXTURE_2D && target != GL_TEXTURE_RECTANGLE_ARB) { - /* Can't handle other texture types at this time */ - return mask; - } - - /* - printf("Blit from texture!\n"); - printf(" srcAtt %p dstAtt %p\n", readAtt, drawAtt); - printf(" srcTex %p dstText %p\n", texObj, drawAtt->Texture); - */ - - /* Prepare src texture state */ - _mesa_BindTexture(target, texObj->Name); - _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter); - _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter); - if (target != GL_TEXTURE_RECTANGLE_ARB) { - _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, srcLevel); - _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel); - } - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - _mesa_set_enable(ctx, target, GL_TRUE); - - /* Prepare vertex data (the VBO was previously created and bound) */ - { - struct vertex { - GLfloat x, y, s, t; - }; - struct vertex verts[4]; - GLfloat s0, t0, s1, t1; - - if (target == GL_TEXTURE_2D) { - const struct gl_texture_image *texImage - = _mesa_select_tex_image(ctx, texObj, target, srcLevel); - s0 = srcX0 / (float) texImage->Width; - s1 = srcX1 / (float) texImage->Width; - t0 = srcY0 / (float) texImage->Height; - t1 = srcY1 / (float) texImage->Height; - } - else { - assert(target == GL_TEXTURE_RECTANGLE_ARB); - s0 = srcX0; - s1 = srcX1; - t0 = srcY0; - t1 = srcY1; - } - - verts[0].x = (GLfloat) dstX0; - verts[0].y = (GLfloat) dstY0; - verts[1].x = (GLfloat) dstX1; - verts[1].y = (GLfloat) dstY0; - verts[2].x = (GLfloat) dstX1; - verts[2].y = (GLfloat) dstY1; - verts[3].x = (GLfloat) dstX0; - verts[3].y = (GLfloat) dstY1; - - verts[0].s = s0; - verts[0].t = t0; - verts[1].s = s1; - verts[1].t = t0; - verts[2].s = s1; - verts[2].t = t1; - verts[3].s = s0; - verts[3].t = t1; - - _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); - } - - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - - /* Restore texture object state, the texture binding will - * be restored by _mesa_meta_end(). - */ - _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilterSave); - _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilterSave); - if (target != GL_TEXTURE_RECTANGLE_ARB) { - _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, baseLevelSave); - _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); - } - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, wrapSSave); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, wrapTSave); - - /* Done with color buffer */ - mask &= ~GL_COLOR_BUFFER_BIT; - } - } - - return mask; -} - - -/** - * Meta implementation of ctx->Driver.BlitFramebuffer() in terms - * of texture mapping and polygon rendering. - */ -void -_mesa_meta_BlitFramebuffer(struct gl_context *ctx, - GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter) -{ - struct blit_state *blit = &ctx->Meta->Blit; - struct temp_texture *tex = get_temp_texture(ctx); - const GLsizei maxTexSize = tex->MaxSize; - const GLint srcX = MIN2(srcX0, srcX1); - const GLint srcY = MIN2(srcY0, srcY1); - const GLint srcW = abs(srcX1 - srcX0); - const GLint srcH = abs(srcY1 - srcY0); - const GLboolean srcFlipX = srcX1 < srcX0; - const GLboolean srcFlipY = srcY1 < srcY0; - struct vertex { - GLfloat x, y, s, t; - }; - struct vertex verts[4]; - GLboolean newTex; - - if (srcW > maxTexSize || srcH > maxTexSize) { - /* XXX avoid this fallback */ - _swrast_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, mask, filter); - return; - } - - if (srcFlipX) { - GLint tmp = dstX0; - dstX0 = dstX1; - dstX1 = tmp; - } - - if (srcFlipY) { - GLint tmp = dstY0; - dstY0 = dstY1; - dstY1 = tmp; - } - - /* only scissor effects blit so save/clear all other relevant state */ - _mesa_meta_begin(ctx, ~META_SCISSOR); - - if (blit->ArrayObj == 0) { - /* one-time setup */ - - /* create vertex array object */ - _mesa_GenVertexArrays(1, &blit->ArrayObj); - _mesa_BindVertexArray(blit->ArrayObj); - - /* create vertex array buffer */ - _mesa_GenBuffersARB(1, &blit->VBO); - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, blit->VBO); - _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), - NULL, GL_DYNAMIC_DRAW_ARB); - - /* setup vertex arrays */ - _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); - _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); - _mesa_EnableClientState(GL_VERTEX_ARRAY); - _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); - } - else { - _mesa_BindVertexArray(blit->ArrayObj); - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, blit->VBO); - } - - /* Try faster, direct texture approach first */ - mask = blitframebuffer_texture(ctx, srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, mask, filter); - if (mask == 0x0) { - _mesa_meta_end(ctx); - return; - } - - /* Continue with "normal" approach which involves copying the src rect - * into a temporary texture and is "blitted" by drawing a textured quad. - */ - - newTex = alloc_texture(tex, srcW, srcH, GL_RGBA); - - /* vertex positions/texcoords (after texture allocation!) */ - { - verts[0].x = (GLfloat) dstX0; - verts[0].y = (GLfloat) dstY0; - verts[1].x = (GLfloat) dstX1; - verts[1].y = (GLfloat) dstY0; - verts[2].x = (GLfloat) dstX1; - verts[2].y = (GLfloat) dstY1; - verts[3].x = (GLfloat) dstX0; - verts[3].y = (GLfloat) dstY1; - - verts[0].s = 0.0F; - verts[0].t = 0.0F; - verts[1].s = tex->Sright; - verts[1].t = 0.0F; - verts[2].s = tex->Sright; - verts[2].t = tex->Ttop; - verts[3].s = 0.0F; - verts[3].t = tex->Ttop; - - /* upload new vertex data */ - _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); - } - - _mesa_set_enable(ctx, tex->Target, GL_TRUE); - - if (mask & GL_COLOR_BUFFER_BIT) { - setup_copypix_texture(tex, newTex, srcX, srcY, srcW, srcH, - GL_RGBA, filter); - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - mask &= ~GL_COLOR_BUFFER_BIT; - } - - if (mask & GL_DEPTH_BUFFER_BIT) { - GLuint *tmp = (GLuint *) malloc(srcW * srcH * sizeof(GLuint)); - if (tmp) { - if (!blit->DepthFP) - init_blit_depth_pixels(ctx); - - /* maybe change tex format here */ - newTex = alloc_texture(tex, srcW, srcH, GL_DEPTH_COMPONENT); - - _mesa_ReadPixels(srcX, srcY, srcW, srcH, - GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, tmp); - - setup_drawpix_texture(ctx, tex, newTex, GL_DEPTH_COMPONENT, srcW, srcH, - GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, tmp); - - _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, blit->DepthFP); - _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); - _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE); - _mesa_DepthFunc(GL_ALWAYS); - _mesa_DepthMask(GL_TRUE); - - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - mask &= ~GL_DEPTH_BUFFER_BIT; - - free(tmp); - } - } - - if (mask & GL_STENCIL_BUFFER_BIT) { - /* XXX can't easily do stencil */ - } - - _mesa_set_enable(ctx, tex->Target, GL_FALSE); - - _mesa_meta_end(ctx); - - if (mask) { - _swrast_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, mask, filter); - } -} - - -/** - * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering. - */ -void -_mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers) -{ - struct clear_state *clear = &ctx->Meta->Clear; - struct vertex { - GLfloat x, y, z, r, g, b, a; - }; - struct vertex verts[4]; - /* save all state but scissor, pixel pack/unpack */ - GLbitfield metaSave = META_ALL - META_SCISSOR - META_PIXEL_STORE; - const GLuint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; - - if (buffers & BUFFER_BITS_COLOR) { - /* if clearing color buffers, don't save/restore colormask */ - metaSave -= META_COLOR_MASK; - } - - _mesa_meta_begin(ctx, metaSave); - - if (clear->ArrayObj == 0) { - /* one-time setup */ - - /* create vertex array object */ - _mesa_GenVertexArrays(1, &clear->ArrayObj); - _mesa_BindVertexArray(clear->ArrayObj); - - /* create vertex array buffer */ - _mesa_GenBuffersARB(1, &clear->VBO); - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, clear->VBO); - - /* setup vertex arrays */ - _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); - _mesa_ColorPointer(4, GL_FLOAT, sizeof(struct vertex), OFFSET(r)); - _mesa_EnableClientState(GL_VERTEX_ARRAY); - _mesa_EnableClientState(GL_COLOR_ARRAY); - } - else { - _mesa_BindVertexArray(clear->ArrayObj); - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, clear->VBO); - } - - /* GL_COLOR_BUFFER_BIT */ - if (buffers & BUFFER_BITS_COLOR) { - /* leave colormask, glDrawBuffer state as-is */ - } - else { - ASSERT(metaSave & META_COLOR_MASK); - _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - } - - /* GL_DEPTH_BUFFER_BIT */ - if (buffers & BUFFER_BIT_DEPTH) { - _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE); - _mesa_DepthFunc(GL_ALWAYS); - _mesa_DepthMask(GL_TRUE); - } - else { - assert(!ctx->Depth.Test); - } - - /* GL_STENCIL_BUFFER_BIT */ - if (buffers & BUFFER_BIT_STENCIL) { - _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_TRUE); - _mesa_StencilOpSeparate(GL_FRONT_AND_BACK, - GL_REPLACE, GL_REPLACE, GL_REPLACE); - _mesa_StencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS, - ctx->Stencil.Clear & stencilMax, - ctx->Stencil.WriteMask[0]); - } - else { - assert(!ctx->Stencil.Enabled); - } - - /* vertex positions/colors */ - { - const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin; - const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin; - const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax; - const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax; - const GLfloat z = invert_z(ctx->Depth.Clear); - GLuint i; - - verts[0].x = x0; - verts[0].y = y0; - verts[0].z = z; - verts[1].x = x1; - verts[1].y = y0; - verts[1].z = z; - verts[2].x = x1; - verts[2].y = y1; - verts[2].z = z; - verts[3].x = x0; - verts[3].y = y1; - verts[3].z = z; - - /* vertex colors */ - for (i = 0; i < 4; i++) { - verts[i].r = ctx->Color.ClearColor[0]; - verts[i].g = ctx->Color.ClearColor[1]; - verts[i].b = ctx->Color.ClearColor[2]; - verts[i].a = ctx->Color.ClearColor[3]; - } - - /* upload new vertex data */ - _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts, - GL_DYNAMIC_DRAW_ARB); - } - - /* draw quad */ - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - - _mesa_meta_end(ctx); -} - - -/** - * Meta implementation of ctx->Driver.CopyPixels() in terms - * of texture mapping and polygon rendering. - */ -void -_mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY, - GLsizei width, GLsizei height, - GLint dstX, GLint dstY, GLenum type) -{ - struct copypix_state *copypix = &ctx->Meta->CopyPix; - struct temp_texture *tex = get_temp_texture(ctx); - struct vertex { - GLfloat x, y, z, s, t; - }; - struct vertex verts[4]; - GLboolean newTex; - GLenum intFormat = GL_RGBA; - - if (type != GL_COLOR || - ctx->_ImageTransferState || - ctx->Fog.Enabled || - width > tex->MaxSize || - height > tex->MaxSize) { - /* XXX avoid this fallback */ - _swrast_CopyPixels(ctx, srcX, srcY, width, height, dstX, dstY, type); - return; - } - - /* Most GL state applies to glCopyPixels, but a there's a few things - * we need to override: - */ - _mesa_meta_begin(ctx, (META_RASTERIZATION | - META_SHADER | - META_TEXTURE | - META_TRANSFORM | - META_VERTEX | - META_VIEWPORT)); - - if (copypix->ArrayObj == 0) { - /* one-time setup */ - - /* create vertex array object */ - _mesa_GenVertexArrays(1, ©pix->ArrayObj); - _mesa_BindVertexArray(copypix->ArrayObj); - - /* create vertex array buffer */ - _mesa_GenBuffersARB(1, ©pix->VBO); - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, copypix->VBO); - _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), - NULL, GL_DYNAMIC_DRAW_ARB); - - /* setup vertex arrays */ - _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); - _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); - _mesa_EnableClientState(GL_VERTEX_ARRAY); - _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); - } - else { - _mesa_BindVertexArray(copypix->ArrayObj); - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, copypix->VBO); - } - - newTex = alloc_texture(tex, width, height, intFormat); - - /* vertex positions, texcoords (after texture allocation!) */ - { - const GLfloat dstX0 = (GLfloat) dstX; - const GLfloat dstY0 = (GLfloat) dstY; - const GLfloat dstX1 = dstX + width * ctx->Pixel.ZoomX; - const GLfloat dstY1 = dstY + height * ctx->Pixel.ZoomY; - const GLfloat z = invert_z(ctx->Current.RasterPos[2]); - - verts[0].x = dstX0; - verts[0].y = dstY0; - verts[0].z = z; - verts[0].s = 0.0F; - verts[0].t = 0.0F; - verts[1].x = dstX1; - verts[1].y = dstY0; - verts[1].z = z; - verts[1].s = tex->Sright; - verts[1].t = 0.0F; - verts[2].x = dstX1; - verts[2].y = dstY1; - verts[2].z = z; - verts[2].s = tex->Sright; - verts[2].t = tex->Ttop; - verts[3].x = dstX0; - verts[3].y = dstY1; - verts[3].z = z; - verts[3].s = 0.0F; - verts[3].t = tex->Ttop; - - /* upload new vertex data */ - _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); - } - - /* Alloc/setup texture */ - setup_copypix_texture(tex, newTex, srcX, srcY, width, height, - GL_RGBA, GL_NEAREST); - - _mesa_set_enable(ctx, tex->Target, GL_TRUE); - - /* draw textured quad */ - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - - _mesa_set_enable(ctx, tex->Target, GL_FALSE); - - _mesa_meta_end(ctx); -} - - - -/** - * When the glDrawPixels() image size is greater than the max rectangle - * texture size we use this function to break the glDrawPixels() image - * into tiles which fit into the max texture size. - */ -static void -tiled_draw_pixels(struct gl_context *ctx, - GLint tileSize, - GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *pixels) -{ - struct gl_pixelstore_attrib tileUnpack = *unpack; - GLint i, j; - - if (tileUnpack.RowLength == 0) - tileUnpack.RowLength = width; - - for (i = 0; i < width; i += tileSize) { - const GLint tileWidth = MIN2(tileSize, width - i); - const GLint tileX = (GLint) (x + i * ctx->Pixel.ZoomX); - - tileUnpack.SkipPixels = unpack->SkipPixels + i; - - for (j = 0; j < height; j += tileSize) { - const GLint tileHeight = MIN2(tileSize, height - j); - const GLint tileY = (GLint) (y + j * ctx->Pixel.ZoomY); - - tileUnpack.SkipRows = unpack->SkipRows + j; - - _mesa_meta_DrawPixels(ctx, tileX, tileY, tileWidth, tileHeight, - format, type, &tileUnpack, pixels); - } - } -} - - -/** - * One-time init for drawing stencil pixels. - */ -static void -init_draw_stencil_pixels(struct gl_context *ctx) -{ - /* This program is run eight times, once for each stencil bit. - * The stencil values to draw are found in an 8-bit alpha texture. - * We read the texture/stencil value and test if bit 'b' is set. - * If the bit is not set, use KIL to kill the fragment. - * Finally, we use the stencil test to update the stencil buffer. - * - * The basic algorithm for checking if a bit is set is: - * if (is_odd(value / (1 << bit))) - * result is one (or non-zero). - * else - * result is zero. - * The program parameter contains three values: - * parm.x = 255 / (1 << bit) - * parm.y = 0.5 - * parm.z = 0.0 - */ - static const char *program = - "!!ARBfp1.0\n" - "PARAM parm = program.local[0]; \n" - "TEMP t; \n" - "TEX t, fragment.texcoord[0], texture[0], %s; \n" /* NOTE %s here! */ - "# t = t * 255 / bit \n" - "MUL t.x, t.a, parm.x; \n" - "# t = (int) t \n" - "FRC t.y, t.x; \n" - "SUB t.x, t.x, t.y; \n" - "# t = t * 0.5 \n" - "MUL t.x, t.x, parm.y; \n" - "# t = fract(t.x) \n" - "FRC t.x, t.x; # if t.x != 0, then the bit is set \n" - "# t.x = (t.x == 0 ? 1 : 0) \n" - "SGE t.x, -t.x, parm.z; \n" - "KIL -t.x; \n" - "# for debug only \n" - "#MOV result.color, t.x; \n" - "END \n"; - char program2[1000]; - struct drawpix_state *drawpix = &ctx->Meta->DrawPix; - struct temp_texture *tex = get_temp_texture(ctx); - const char *texTarget; - - assert(drawpix->StencilFP == 0); - - /* replace %s with "RECT" or "2D" */ - assert(strlen(program) + 4 < sizeof(program2)); - if (tex->Target == GL_TEXTURE_RECTANGLE) - texTarget = "RECT"; - else - texTarget = "2D"; - _mesa_snprintf(program2, sizeof(program2), program, texTarget); - - _mesa_GenPrograms(1, &drawpix->StencilFP); - _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, drawpix->StencilFP); - _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, - strlen(program2), (const GLubyte *) program2); -} - - -/** - * One-time init for drawing depth pixels. - */ -static void -init_draw_depth_pixels(struct gl_context *ctx) -{ - static const char *program = - "!!ARBfp1.0\n" - "PARAM color = program.local[0]; \n" - "TEX result.depth, fragment.texcoord[0], texture[0], %s; \n" - "MOV result.color, color; \n" - "END \n"; - char program2[200]; - struct drawpix_state *drawpix = &ctx->Meta->DrawPix; - struct temp_texture *tex = get_temp_texture(ctx); - const char *texTarget; - - assert(drawpix->DepthFP == 0); - - /* replace %s with "RECT" or "2D" */ - assert(strlen(program) + 4 < sizeof(program2)); - if (tex->Target == GL_TEXTURE_RECTANGLE) - texTarget = "RECT"; - else - texTarget = "2D"; - _mesa_snprintf(program2, sizeof(program2), program, texTarget); - - _mesa_GenPrograms(1, &drawpix->DepthFP); - _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, drawpix->DepthFP); - _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, - strlen(program2), (const GLubyte *) program2); -} - - -/** - * Meta implementation of ctx->Driver.DrawPixels() in terms - * of texture mapping and polygon rendering. - */ -void -_mesa_meta_DrawPixels(struct gl_context *ctx, - GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *pixels) -{ - struct drawpix_state *drawpix = &ctx->Meta->DrawPix; - struct temp_texture *tex = get_temp_texture(ctx); - const struct gl_pixelstore_attrib unpackSave = ctx->Unpack; - const GLuint origStencilMask = ctx->Stencil.WriteMask[0]; - struct vertex { - GLfloat x, y, z, s, t; - }; - struct vertex verts[4]; - GLenum texIntFormat; - GLboolean fallback, newTex; - GLbitfield metaExtraSave = 0x0; - GLuint vbo; - - /* - * Determine if we can do the glDrawPixels with texture mapping. - */ - fallback = GL_FALSE; - if (ctx->_ImageTransferState || - ctx->Fog.Enabled) { - fallback = GL_TRUE; - } - - if (_mesa_is_color_format(format)) { - /* use more compact format when possible */ - /* XXX disable special case for GL_LUMINANCE for now to work around - * apparent i965 driver bug (see bug #23670). - */ - if (/*format == GL_LUMINANCE ||*/ format == GL_LUMINANCE_ALPHA) - texIntFormat = format; - else - texIntFormat = GL_RGBA; - } - else if (_mesa_is_stencil_format(format)) { - if (ctx->Extensions.ARB_fragment_program && - ctx->Pixel.IndexShift == 0 && - ctx->Pixel.IndexOffset == 0 && - type == GL_UNSIGNED_BYTE) { - /* We'll store stencil as alpha. This only works for GLubyte - * image data because of how incoming values are mapped to alpha - * in [0,1]. - */ - texIntFormat = GL_ALPHA; - metaExtraSave = (META_COLOR_MASK | - META_DEPTH_TEST | - META_SHADER | - META_STENCIL_TEST); - } - else { - fallback = GL_TRUE; - } - } - else if (_mesa_is_depth_format(format)) { - if (ctx->Extensions.ARB_depth_texture && - ctx->Extensions.ARB_fragment_program) { - texIntFormat = GL_DEPTH_COMPONENT; - metaExtraSave = (META_SHADER); - } - else { - fallback = GL_TRUE; - } - } - else { - fallback = GL_TRUE; - } - - if (fallback) { - _swrast_DrawPixels(ctx, x, y, width, height, - format, type, unpack, pixels); - return; - } - - /* - * Check image size against max texture size, draw as tiles if needed. - */ - if (width > tex->MaxSize || height > tex->MaxSize) { - tiled_draw_pixels(ctx, tex->MaxSize, x, y, width, height, - format, type, unpack, pixels); - return; - } - - /* Most GL state applies to glDrawPixels (like blending, stencil, etc), - * but a there's a few things we need to override: - */ - _mesa_meta_begin(ctx, (META_RASTERIZATION | - META_SHADER | - META_TEXTURE | - META_TRANSFORM | - META_VERTEX | - META_VIEWPORT | - metaExtraSave)); - - newTex = alloc_texture(tex, width, height, texIntFormat); - - /* vertex positions, texcoords (after texture allocation!) */ - { - const GLfloat x0 = (GLfloat) x; - const GLfloat y0 = (GLfloat) y; - const GLfloat x1 = x + width * ctx->Pixel.ZoomX; - const GLfloat y1 = y + height * ctx->Pixel.ZoomY; - const GLfloat z = invert_z(ctx->Current.RasterPos[2]); - - verts[0].x = x0; - verts[0].y = y0; - verts[0].z = z; - verts[0].s = 0.0F; - verts[0].t = 0.0F; - verts[1].x = x1; - verts[1].y = y0; - verts[1].z = z; - verts[1].s = tex->Sright; - verts[1].t = 0.0F; - verts[2].x = x1; - verts[2].y = y1; - verts[2].z = z; - verts[2].s = tex->Sright; - verts[2].t = tex->Ttop; - verts[3].x = x0; - verts[3].y = y1; - verts[3].z = z; - verts[3].s = 0.0F; - verts[3].t = tex->Ttop; - } - - if (drawpix->ArrayObj == 0) { - /* one-time setup: create vertex array object */ - _mesa_GenVertexArrays(1, &drawpix->ArrayObj); - } - _mesa_BindVertexArray(drawpix->ArrayObj); - - /* create vertex array buffer */ - _mesa_GenBuffersARB(1, &vbo); - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, vbo); - _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), - verts, GL_DYNAMIC_DRAW_ARB); - - /* setup vertex arrays */ - _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); - _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); - _mesa_EnableClientState(GL_VERTEX_ARRAY); - _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); - - /* set given unpack params */ - ctx->Unpack = *unpack; - - _mesa_set_enable(ctx, tex->Target, GL_TRUE); - - if (_mesa_is_stencil_format(format)) { - /* Drawing stencil */ - GLint bit; - - if (!drawpix->StencilFP) - init_draw_stencil_pixels(ctx); - - setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, - GL_ALPHA, type, pixels); - - _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - - _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_TRUE); - - /* set all stencil bits to 0 */ - _mesa_StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); - _mesa_StencilFunc(GL_ALWAYS, 0, 255); - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - - /* set stencil bits to 1 where needed */ - _mesa_StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - - _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, drawpix->StencilFP); - _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); - - for (bit = 0; bit < ctx->DrawBuffer->Visual.stencilBits; bit++) { - const GLuint mask = 1 << bit; - if (mask & origStencilMask) { - _mesa_StencilFunc(GL_ALWAYS, mask, mask); - _mesa_StencilMask(mask); - - _mesa_ProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, - 255.0 / mask, 0.5, 0.0, 0.0); - - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - } - } - else if (_mesa_is_depth_format(format)) { - /* Drawing depth */ - if (!drawpix->DepthFP) - init_draw_depth_pixels(ctx); - - _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, drawpix->DepthFP); - _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); - - /* polygon color = current raster color */ - _mesa_ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, - ctx->Current.RasterColor); - - setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, - format, type, pixels); - - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - else { - /* Drawing RGBA */ - setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, - format, type, pixels); - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - - _mesa_set_enable(ctx, tex->Target, GL_FALSE); - - _mesa_DeleteBuffersARB(1, &vbo); - - /* restore unpack params */ - ctx->Unpack = unpackSave; - - _mesa_meta_end(ctx); -} - -static GLboolean -alpha_test_raster_color(struct gl_context *ctx) -{ - GLfloat alpha = ctx->Current.RasterColor[ACOMP]; - GLfloat ref = ctx->Color.AlphaRef; - - switch (ctx->Color.AlphaFunc) { - case GL_NEVER: - return GL_FALSE; - case GL_LESS: - return alpha < ref; - case GL_EQUAL: - return alpha == ref; - case GL_LEQUAL: - return alpha <= ref; - case GL_GREATER: - return alpha > ref; - case GL_NOTEQUAL: - return alpha != ref; - case GL_GEQUAL: - return alpha >= ref; - case GL_ALWAYS: - return GL_TRUE; - default: - assert(0); - return GL_FALSE; - } -} - -/** - * Do glBitmap with a alpha texture quad. Use the alpha test to cull - * the 'off' bits. A bitmap cache as in the gallium/mesa state - * tracker would improve performance a lot. - */ -void -_mesa_meta_Bitmap(struct gl_context *ctx, - GLint x, GLint y, GLsizei width, GLsizei height, - const struct gl_pixelstore_attrib *unpack, - const GLubyte *bitmap1) -{ - struct bitmap_state *bitmap = &ctx->Meta->Bitmap; - struct temp_texture *tex = get_bitmap_temp_texture(ctx); - const GLenum texIntFormat = GL_ALPHA; - const struct gl_pixelstore_attrib unpackSave = *unpack; - GLubyte fg, bg; - struct vertex { - GLfloat x, y, z, s, t, r, g, b, a; - }; - struct vertex verts[4]; - GLboolean newTex; - GLubyte *bitmap8; - - /* - * Check if swrast fallback is needed. - */ - if (ctx->_ImageTransferState || - ctx->FragmentProgram._Enabled || - ctx->Fog.Enabled || - ctx->Texture._EnabledUnits || - width > tex->MaxSize || - height > tex->MaxSize) { - _swrast_Bitmap(ctx, x, y, width, height, unpack, bitmap1); - return; - } - - if (ctx->Color.AlphaEnabled && !alpha_test_raster_color(ctx)) - return; - - /* Most GL state applies to glBitmap (like blending, stencil, etc), - * but a there's a few things we need to override: - */ - _mesa_meta_begin(ctx, (META_ALPHA_TEST | - META_PIXEL_STORE | - META_RASTERIZATION | - META_SHADER | - META_TEXTURE | - META_TRANSFORM | - META_VERTEX | - META_VIEWPORT)); - - if (bitmap->ArrayObj == 0) { - /* one-time setup */ - - /* create vertex array object */ - _mesa_GenVertexArraysAPPLE(1, &bitmap->ArrayObj); - _mesa_BindVertexArrayAPPLE(bitmap->ArrayObj); - - /* create vertex array buffer */ - _mesa_GenBuffersARB(1, &bitmap->VBO); - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, bitmap->VBO); - _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), - NULL, GL_DYNAMIC_DRAW_ARB); - - /* setup vertex arrays */ - _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); - _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); - _mesa_ColorPointer(4, GL_FLOAT, sizeof(struct vertex), OFFSET(r)); - _mesa_EnableClientState(GL_VERTEX_ARRAY); - _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); - _mesa_EnableClientState(GL_COLOR_ARRAY); - } - else { - _mesa_BindVertexArray(bitmap->ArrayObj); - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, bitmap->VBO); - } - - newTex = alloc_texture(tex, width, height, texIntFormat); - - /* vertex positions, texcoords, colors (after texture allocation!) */ - { - const GLfloat x0 = (GLfloat) x; - const GLfloat y0 = (GLfloat) y; - const GLfloat x1 = (GLfloat) (x + width); - const GLfloat y1 = (GLfloat) (y + height); - const GLfloat z = invert_z(ctx->Current.RasterPos[2]); - GLuint i; - - verts[0].x = x0; - verts[0].y = y0; - verts[0].z = z; - verts[0].s = 0.0F; - verts[0].t = 0.0F; - verts[1].x = x1; - verts[1].y = y0; - verts[1].z = z; - verts[1].s = tex->Sright; - verts[1].t = 0.0F; - verts[2].x = x1; - verts[2].y = y1; - verts[2].z = z; - verts[2].s = tex->Sright; - verts[2].t = tex->Ttop; - verts[3].x = x0; - verts[3].y = y1; - verts[3].z = z; - verts[3].s = 0.0F; - verts[3].t = tex->Ttop; - - for (i = 0; i < 4; i++) { - verts[i].r = ctx->Current.RasterColor[0]; - verts[i].g = ctx->Current.RasterColor[1]; - verts[i].b = ctx->Current.RasterColor[2]; - verts[i].a = ctx->Current.RasterColor[3]; - } - - /* upload new vertex data */ - _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); - } - - /* choose different foreground/background alpha values */ - CLAMPED_FLOAT_TO_UBYTE(fg, ctx->Current.RasterColor[ACOMP]); - bg = (fg > 127 ? 0 : 255); - - bitmap1 = _mesa_map_pbo_source(ctx, &unpackSave, bitmap1); - if (!bitmap1) { - _mesa_meta_end(ctx); - return; - } - - bitmap8 = (GLubyte *) malloc(width * height); - if (bitmap8) { - memset(bitmap8, bg, width * height); - _mesa_expand_bitmap(width, height, &unpackSave, bitmap1, - bitmap8, width, fg); - - _mesa_set_enable(ctx, tex->Target, GL_TRUE); - - _mesa_set_enable(ctx, GL_ALPHA_TEST, GL_TRUE); - _mesa_AlphaFunc(GL_NOTEQUAL, UBYTE_TO_FLOAT(bg)); - - setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, - GL_ALPHA, GL_UNSIGNED_BYTE, bitmap8); - - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - - _mesa_set_enable(ctx, tex->Target, GL_FALSE); - - free(bitmap8); - } - - _mesa_unmap_pbo_source(ctx, &unpackSave); - - _mesa_meta_end(ctx); -} - - -/** - * Check if the call to _mesa_meta_GenerateMipmap() will require a - * software fallback. The fallback path will require that the texture - * images are mapped. - * \return GL_TRUE if a fallback is needed, GL_FALSE otherwise - */ -GLboolean -_mesa_meta_check_generate_mipmap_fallback(struct gl_context *ctx, GLenum target, - struct gl_texture_object *texObj) -{ - const GLuint fboSave = ctx->DrawBuffer->Name; - struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap; - struct gl_texture_image *baseImage; - GLuint srcLevel; - GLenum status; - - /* check for fallbacks */ - if (!ctx->Extensions.EXT_framebuffer_object || - target == GL_TEXTURE_3D) { - return GL_TRUE; - } - - srcLevel = texObj->BaseLevel; - baseImage = _mesa_select_tex_image(ctx, texObj, target, srcLevel); - if (!baseImage || _mesa_is_format_compressed(baseImage->TexFormat)) { - return GL_TRUE; - } - - /* - * Test that we can actually render in the texture's format. - */ - if (!mipmap->FBO) - _mesa_GenFramebuffersEXT(1, &mipmap->FBO); - _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mipmap->FBO); - - if (target == GL_TEXTURE_1D) { - _mesa_FramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - target, texObj->Name, srcLevel); - } -#if 0 - /* other work is needed to enable 3D mipmap generation */ - else if (target == GL_TEXTURE_3D) { - GLint zoffset = 0; - _mesa_FramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - target, texObj->Name, srcLevel, zoffset); - } -#endif - else { - /* 2D / cube */ - _mesa_FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - target, texObj->Name, srcLevel); - } - - status = _mesa_CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - - _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboSave); - - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { - return GL_TRUE; - } - - return GL_FALSE; -} - - -/** - * Called via ctx->Driver.GenerateMipmap() - * Note: texture borders and 3D texture support not yet complete. - */ -void -_mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, - struct gl_texture_object *texObj) -{ - struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap; - struct vertex { - GLfloat x, y, s, t, r; - }; - struct vertex verts[4]; - const GLuint baseLevel = texObj->BaseLevel; - const GLuint maxLevel = texObj->MaxLevel; - const GLenum minFilterSave = texObj->MinFilter; - const GLenum magFilterSave = texObj->MagFilter; - const GLint maxLevelSave = texObj->MaxLevel; - const GLboolean genMipmapSave = texObj->GenerateMipmap; - const GLenum wrapSSave = texObj->WrapS; - const GLenum wrapTSave = texObj->WrapT; - const GLenum wrapRSave = texObj->WrapR; - const GLuint fboSave = ctx->DrawBuffer->Name; - const GLuint original_active_unit = ctx->Texture.CurrentUnit; - GLenum faceTarget; - GLuint dstLevel; - GLuint border = 0; - - if (_mesa_meta_check_generate_mipmap_fallback(ctx, target, texObj)) { - _mesa_generate_mipmap(ctx, target, texObj); - return; - } - - if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && - target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) { - faceTarget = target; - target = GL_TEXTURE_CUBE_MAP; - } - else { - faceTarget = target; - } - - _mesa_meta_begin(ctx, META_ALL); - - if (original_active_unit != 0) - _mesa_BindTexture(target, texObj->Name); - - if (mipmap->ArrayObj == 0) { - /* one-time setup */ - - /* create vertex array object */ - _mesa_GenVertexArraysAPPLE(1, &mipmap->ArrayObj); - _mesa_BindVertexArrayAPPLE(mipmap->ArrayObj); - - /* create vertex array buffer */ - _mesa_GenBuffersARB(1, &mipmap->VBO); - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, mipmap->VBO); - _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), - NULL, GL_DYNAMIC_DRAW_ARB); - - /* setup vertex arrays */ - _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); - _mesa_TexCoordPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); - _mesa_EnableClientState(GL_VERTEX_ARRAY); - _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); - } - else { - _mesa_BindVertexArray(mipmap->ArrayObj); - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, mipmap->VBO); - } - - if (!mipmap->FBO) { - _mesa_GenFramebuffersEXT(1, &mipmap->FBO); - } - _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mipmap->FBO); - - _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - _mesa_set_enable(ctx, target, GL_TRUE); - - /* setup texcoords once (XXX what about border?) */ - switch (faceTarget) { - case GL_TEXTURE_1D: - case GL_TEXTURE_2D: - verts[0].s = 0.0F; - verts[0].t = 0.0F; - verts[0].r = 0.0F; - verts[1].s = 1.0F; - verts[1].t = 0.0F; - verts[1].r = 0.0F; - verts[2].s = 1.0F; - verts[2].t = 1.0F; - verts[2].r = 0.0F; - verts[3].s = 0.0F; - verts[3].t = 1.0F; - verts[3].r = 0.0F; - break; - case GL_TEXTURE_3D: - abort(); - break; - default: - /* cube face */ - { - static const GLfloat st[4][2] = { - {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f} - }; - GLuint i; - - /* loop over quad verts */ - for (i = 0; i < 4; i++) { - /* Compute sc = +/-scale and tc = +/-scale. - * Not +/-1 to avoid cube face selection ambiguity near the edges, - * though that can still sometimes happen with this scale factor... - */ - const GLfloat scale = 0.9999f; - const GLfloat sc = (2.0f * st[i][0] - 1.0f) * scale; - const GLfloat tc = (2.0f * st[i][1] - 1.0f) * scale; - - switch (faceTarget) { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - verts[i].s = 1.0f; - verts[i].t = -tc; - verts[i].r = -sc; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - verts[i].s = -1.0f; - verts[i].t = -tc; - verts[i].r = sc; - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - verts[i].s = sc; - verts[i].t = 1.0f; - verts[i].r = tc; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - verts[i].s = sc; - verts[i].t = -1.0f; - verts[i].r = -tc; - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - verts[i].s = sc; - verts[i].t = -tc; - verts[i].r = 1.0f; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - verts[i].s = -sc; - verts[i].t = -tc; - verts[i].r = -1.0f; - break; - default: - assert(0); - } - } - } - } - - _mesa_set_enable(ctx, target, GL_TRUE); - - /* setup vertex positions */ - { - verts[0].x = 0.0F; - verts[0].y = 0.0F; - verts[1].x = 1.0F; - verts[1].y = 0.0F; - verts[2].x = 1.0F; - verts[2].y = 1.0F; - verts[3].x = 0.0F; - verts[3].y = 1.0F; - - /* upload new vertex data */ - _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); - } - - /* setup projection matrix */ - _mesa_MatrixMode(GL_PROJECTION); - _mesa_LoadIdentity(); - _mesa_Ortho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); - - /* texture is already locked, unlock now */ - _mesa_unlock_texture(ctx, texObj); - - for (dstLevel = baseLevel + 1; dstLevel <= maxLevel; dstLevel++) { - const struct gl_texture_image *srcImage; - const GLuint srcLevel = dstLevel - 1; - GLsizei srcWidth, srcHeight, srcDepth; - GLsizei dstWidth, dstHeight, dstDepth; - GLenum status; - - srcImage = _mesa_select_tex_image(ctx, texObj, faceTarget, srcLevel); - assert(srcImage->Border == 0); /* XXX we can fix this */ - - /* src size w/out border */ - srcWidth = srcImage->Width - 2 * border; - srcHeight = srcImage->Height - 2 * border; - srcDepth = srcImage->Depth - 2 * border; - - /* new dst size w/ border */ - dstWidth = MAX2(1, srcWidth / 2) + 2 * border; - dstHeight = MAX2(1, srcHeight / 2) + 2 * border; - dstDepth = MAX2(1, srcDepth / 2) + 2 * border; - - if (dstWidth == srcImage->Width && - dstHeight == srcImage->Height && - dstDepth == srcImage->Depth) { - /* all done */ - break; - } - - /* Set MaxLevel large enough to hold the new level when we allocate it */ - _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, dstLevel); - - /* Create empty dest image */ - if (target == GL_TEXTURE_1D) { - _mesa_TexImage1D(target, dstLevel, srcImage->InternalFormat, - dstWidth, border, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } - else if (target == GL_TEXTURE_3D) { - _mesa_TexImage3D(target, dstLevel, srcImage->InternalFormat, - dstWidth, dstHeight, dstDepth, border, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } - else { - /* 2D or cube */ - _mesa_TexImage2D(faceTarget, dstLevel, srcImage->InternalFormat, - dstWidth, dstHeight, border, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - if (target == GL_TEXTURE_CUBE_MAP) { - /* If texturing from a cube, we need to make sure all src faces - * have been defined (even if we're not sampling from them.) - * Otherwise the texture object will be 'incomplete' and - * texturing from it will not be allowed. - */ - GLuint face; - for (face = 0; face < 6; face++) { - if (!texObj->Image[face][srcLevel] || - texObj->Image[face][srcLevel]->Width != srcWidth) { - _mesa_TexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, - srcLevel, srcImage->InternalFormat, - srcWidth, srcHeight, border, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } - } - } - } - - /* limit minification to src level */ - _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel); - - /* Set to draw into the current dstLevel */ - if (target == GL_TEXTURE_1D) { - _mesa_FramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - target, - texObj->Name, - dstLevel); - } - else if (target == GL_TEXTURE_3D) { - GLint zoffset = 0; /* XXX unfinished */ - _mesa_FramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - target, - texObj->Name, - dstLevel, zoffset); - } - else { - /* 2D / cube */ - _mesa_FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - faceTarget, - texObj->Name, - dstLevel); - } - - _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - - /* sanity check */ - status = _mesa_CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { - abort(); - break; - } - - assert(dstWidth == ctx->DrawBuffer->Width); - assert(dstHeight == ctx->DrawBuffer->Height); - - /* setup viewport */ - _mesa_set_viewport(ctx, 0, 0, dstWidth, dstHeight); - - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - - _mesa_lock_texture(ctx, texObj); /* relock */ - - _mesa_meta_end(ctx); - - _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilterSave); - _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilterSave); - _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); - _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, wrapSSave); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, wrapTSave); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_R, wrapRSave); - - _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboSave); -} - - -/** - * Determine the GL data type to use for the temporary image read with - * ReadPixels() and passed to Tex[Sub]Image(). - */ -static GLenum -get_temp_image_type(struct gl_context *ctx, GLenum baseFormat) -{ - switch (baseFormat) { - case GL_RGBA: - case GL_RGB: - case GL_ALPHA: - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - case GL_INTENSITY: - if (ctx->DrawBuffer->Visual.redBits <= 8) - return GL_UNSIGNED_BYTE; - else if (ctx->DrawBuffer->Visual.redBits <= 8) - return GL_UNSIGNED_SHORT; - else - return GL_FLOAT; - case GL_DEPTH_COMPONENT: - return GL_UNSIGNED_INT; - case GL_DEPTH_STENCIL: - return GL_UNSIGNED_INT_24_8; - default: - _mesa_problem(ctx, "Unexpected format in get_temp_image_type()"); - return 0; - } -} - - -/** - * Helper for _mesa_meta_CopyTexImage1/2D() functions. - * Have to be careful with locking and meta state for pixel transfer. - */ -static void -copy_tex_image(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, - GLenum internalFormat, GLint x, GLint y, - GLsizei width, GLsizei height, GLint border) -{ - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - GLenum format, type; - GLint bpp; - void *buf; - - texObj = _mesa_get_current_tex_object(ctx, target); - texImage = _mesa_get_tex_image(ctx, texObj, target, level); - - /* Choose format/type for temporary image buffer */ - format = _mesa_base_tex_format(ctx, internalFormat); - type = get_temp_image_type(ctx, format); - bpp = _mesa_bytes_per_pixel(format, type); - if (bpp <= 0) { - _mesa_problem(ctx, "Bad bpp in meta copy_tex_image()"); - return; - } - - /* - * Alloc image buffer (XXX could use a PBO) - */ - buf = malloc(width * height * bpp); - if (!buf) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims); - return; - } - - _mesa_unlock_texture(ctx, texObj); /* need to unlock first */ - - /* - * Read image from framebuffer (disable pixel transfer ops) - */ - _mesa_meta_begin(ctx, META_PIXEL_STORE | META_PIXEL_TRANSFER); - ctx->Driver.ReadPixels(ctx, x, y, width, height, - format, type, &ctx->Pack, buf); - _mesa_meta_end(ctx); - - if (texImage->Data) { - ctx->Driver.FreeTexImageData(ctx, texImage); - } - - /* The texture's format was already chosen in _mesa_CopyTexImage() */ - ASSERT(texImage->TexFormat != MESA_FORMAT_NONE); - - /* - * Store texture data (with pixel transfer ops) - */ - _mesa_meta_begin(ctx, META_PIXEL_STORE); - - _mesa_update_state(ctx); /* to update pixel transfer state */ - - if (target == GL_TEXTURE_1D) { - ctx->Driver.TexImage1D(ctx, target, level, internalFormat, - width, border, format, type, - buf, &ctx->Unpack, texObj, texImage); - } - else { - ctx->Driver.TexImage2D(ctx, target, level, internalFormat, - width, height, border, format, type, - buf, &ctx->Unpack, texObj, texImage); - } - _mesa_meta_end(ctx); - - _mesa_lock_texture(ctx, texObj); /* re-lock */ - - free(buf); -} - - -void -_mesa_meta_CopyTexImage1D(struct gl_context *ctx, GLenum target, GLint level, - GLenum internalFormat, GLint x, GLint y, - GLsizei width, GLint border) -{ - copy_tex_image(ctx, 1, target, level, internalFormat, x, y, - width, 1, border); -} - - -void -_mesa_meta_CopyTexImage2D(struct gl_context *ctx, GLenum target, GLint level, - GLenum internalFormat, GLint x, GLint y, - GLsizei width, GLsizei height, GLint border) -{ - copy_tex_image(ctx, 2, target, level, internalFormat, x, y, - width, height, border); -} - - - -/** - * Helper for _mesa_meta_CopyTexSubImage1/2/3D() functions. - * Have to be careful with locking and meta state for pixel transfer. - */ -static void -copy_tex_sub_image(struct gl_context *ctx, - GLuint dims, GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLint x, GLint y, - GLsizei width, GLsizei height) -{ - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - GLenum format, type; - GLint bpp; - void *buf; - - texObj = _mesa_get_current_tex_object(ctx, target); - texImage = _mesa_select_tex_image(ctx, texObj, target, level); - - /* Choose format/type for temporary image buffer */ - format = _mesa_get_format_base_format(texImage->TexFormat); - type = get_temp_image_type(ctx, format); - bpp = _mesa_bytes_per_pixel(format, type); - if (bpp <= 0) { - _mesa_problem(ctx, "Bad bpp in meta copy_tex_sub_image()"); - return; - } - - /* - * Alloc image buffer (XXX could use a PBO) - */ - buf = malloc(width * height * bpp); - if (!buf) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage%uD", dims); - return; - } - - _mesa_unlock_texture(ctx, texObj); /* need to unlock first */ - - /* - * Read image from framebuffer (disable pixel transfer ops) - */ - _mesa_meta_begin(ctx, META_PIXEL_STORE | META_PIXEL_TRANSFER); - ctx->Driver.ReadPixels(ctx, x, y, width, height, - format, type, &ctx->Pack, buf); - _mesa_meta_end(ctx); - - _mesa_update_state(ctx); /* to update pixel transfer state */ - - /* - * Store texture data (with pixel transfer ops) - */ - _mesa_meta_begin(ctx, META_PIXEL_STORE); - if (target == GL_TEXTURE_1D) { - ctx->Driver.TexSubImage1D(ctx, target, level, xoffset, - width, format, type, buf, - &ctx->Unpack, texObj, texImage); - } - else if (target == GL_TEXTURE_3D) { - ctx->Driver.TexSubImage3D(ctx, target, level, xoffset, yoffset, zoffset, - width, height, 1, format, type, buf, - &ctx->Unpack, texObj, texImage); - } - else { - ctx->Driver.TexSubImage2D(ctx, target, level, xoffset, yoffset, - width, height, format, type, buf, - &ctx->Unpack, texObj, texImage); - } - _mesa_meta_end(ctx); - - _mesa_lock_texture(ctx, texObj); /* re-lock */ - - free(buf); -} - - -void -_mesa_meta_CopyTexSubImage1D(struct gl_context *ctx, GLenum target, GLint level, - GLint xoffset, - GLint x, GLint y, GLsizei width) -{ - copy_tex_sub_image(ctx, 1, target, level, xoffset, 0, 0, - x, y, width, 1); -} - - -void -_mesa_meta_CopyTexSubImage2D(struct gl_context *ctx, GLenum target, GLint level, - GLint xoffset, GLint yoffset, - GLint x, GLint y, - GLsizei width, GLsizei height) -{ - copy_tex_sub_image(ctx, 2, target, level, xoffset, yoffset, 0, - x, y, width, height); -} - - -void -_mesa_meta_CopyTexSubImage3D(struct gl_context *ctx, GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLint x, GLint y, - GLsizei width, GLsizei height) -{ - copy_tex_sub_image(ctx, 3, target, level, xoffset, yoffset, zoffset, - x, y, width, height); -} - - -void -_mesa_meta_CopyColorTable(struct gl_context *ctx, - GLenum target, GLenum internalformat, - GLint x, GLint y, GLsizei width) -{ - GLfloat *buf; - - buf = (GLfloat *) malloc(width * 4 * sizeof(GLfloat)); - if (!buf) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyColorTable"); - return; - } - - /* - * Read image from framebuffer (disable pixel transfer ops) - */ - _mesa_meta_begin(ctx, META_PIXEL_STORE | META_PIXEL_TRANSFER); - ctx->Driver.ReadPixels(ctx, x, y, width, 1, - GL_RGBA, GL_FLOAT, &ctx->Pack, buf); - - _mesa_ColorTable(target, internalformat, width, GL_RGBA, GL_FLOAT, buf); - - _mesa_meta_end(ctx); - - free(buf); -} - - -void -_mesa_meta_CopyColorSubTable(struct gl_context *ctx,GLenum target, GLsizei start, - GLint x, GLint y, GLsizei width) -{ - GLfloat *buf; - - buf = (GLfloat *) malloc(width * 4 * sizeof(GLfloat)); - if (!buf) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyColorSubTable"); - return; - } - - /* - * Read image from framebuffer (disable pixel transfer ops) - */ - _mesa_meta_begin(ctx, META_PIXEL_STORE | META_PIXEL_TRANSFER); - ctx->Driver.ReadPixels(ctx, x, y, width, 1, - GL_RGBA, GL_FLOAT, &ctx->Pack, buf); - - _mesa_ColorSubTable(target, start, width, GL_RGBA, GL_FLOAT, buf); - - _mesa_meta_end(ctx); - - free(buf); -} +/* + * Mesa 3-D graphics library + * Version: 7.6 + * + * 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. + */ + +/** + * Meta operations. Some GL operations can be expressed in terms of + * other GL operations. For example, glBlitFramebuffer() can be done + * with texture mapping and glClear() can be done with polygon rendering. + * + * \author Brian Paul + */ + + +#include "main/glheader.h" +#include "main/mtypes.h" +#include "main/imports.h" +#include "main/arbprogram.h" +#include "main/arrayobj.h" +#include "main/blend.h" +#include "main/bufferobj.h" +#include "main/buffers.h" +#include "main/colortab.h" +#include "main/depth.h" +#include "main/enable.h" +#include "main/fbobject.h" +#include "main/formats.h" +#include "main/image.h" +#include "main/macros.h" +#include "main/matrix.h" +#include "main/mipmap.h" +#include "main/pbo.h" +#include "main/polygon.h" +#include "main/readpix.h" +#include "main/scissor.h" +#include "main/shaderapi.h" +#include "main/shaderobj.h" +#include "main/state.h" +#include "main/stencil.h" +#include "main/texobj.h" +#include "main/texenv.h" +#include "main/teximage.h" +#include "main/texparam.h" +#include "main/texstate.h" +#include "main/varray.h" +#include "main/viewport.h" +#include "program/program.h" +#include "swrast/swrast.h" +#include "drivers/common/meta.h" + + +/** Return offset in bytes of the field within a vertex struct */ +#define OFFSET(FIELD) ((void *) offsetof(struct vertex, FIELD)) + + +/** + * Flags passed to _mesa_meta_begin(). + */ +/*@{*/ +#define META_ALL ~0x0 +#define META_ALPHA_TEST 0x1 +#define META_BLEND 0x2 /**< includes logicop */ +#define META_COLOR_MASK 0x4 +#define META_DEPTH_TEST 0x8 +#define META_FOG 0x10 +#define META_PIXEL_STORE 0x20 +#define META_PIXEL_TRANSFER 0x40 +#define META_RASTERIZATION 0x80 +#define META_SCISSOR 0x100 +#define META_SHADER 0x200 +#define META_STENCIL_TEST 0x400 +#define META_TRANSFORM 0x800 /**< modelview, projection, clip planes */ +#define META_TEXTURE 0x1000 +#define META_VERTEX 0x2000 +#define META_VIEWPORT 0x4000 +/*@}*/ + + +/** + * State which we may save/restore across meta ops. + * XXX this may be incomplete... + */ +struct save_state +{ + GLbitfield SavedState; /**< bitmask of META_* flags */ + + /** META_ALPHA_TEST */ + GLboolean AlphaEnabled; + GLenum AlphaFunc; + GLclampf AlphaRef; + + /** META_BLEND */ + GLbitfield BlendEnabled; + GLboolean ColorLogicOpEnabled; + + /** META_COLOR_MASK */ + GLubyte ColorMask[MAX_DRAW_BUFFERS][4]; + + /** META_DEPTH_TEST */ + struct gl_depthbuffer_attrib Depth; + + /** META_FOG */ + GLboolean Fog; + + /** META_PIXEL_STORE */ + struct gl_pixelstore_attrib Pack, Unpack; + + /** META_PIXEL_TRANSFER */ + GLfloat RedBias, RedScale; + GLfloat GreenBias, GreenScale; + GLfloat BlueBias, BlueScale; + GLfloat AlphaBias, AlphaScale; + GLfloat DepthBias, DepthScale; + GLboolean MapColorFlag; + + /** META_RASTERIZATION */ + GLenum FrontPolygonMode, BackPolygonMode; + GLboolean PolygonOffset; + GLboolean PolygonSmooth; + GLboolean PolygonStipple; + GLboolean PolygonCull; + + /** META_SCISSOR */ + struct gl_scissor_attrib Scissor; + + /** META_SHADER */ + GLboolean VertexProgramEnabled; + struct gl_vertex_program *VertexProgram; + GLboolean FragmentProgramEnabled; + struct gl_fragment_program *FragmentProgram; + struct gl_shader_program *VertexShader; + struct gl_shader_program *GeometryShader; + struct gl_shader_program *FragmentShader; + struct gl_shader_program *ActiveShader; + + /** META_STENCIL_TEST */ + struct gl_stencil_attrib Stencil; + + /** META_TRANSFORM */ + GLenum MatrixMode; + GLfloat ModelviewMatrix[16]; + GLfloat ProjectionMatrix[16]; + GLfloat TextureMatrix[16]; + GLbitfield ClipPlanesEnabled; + + /** META_TEXTURE */ + GLuint ActiveUnit; + GLuint ClientActiveUnit; + /** for unit[0] only */ + struct gl_texture_object *CurrentTexture[NUM_TEXTURE_TARGETS]; + /** mask of TEXTURE_2D_BIT, etc */ + GLbitfield TexEnabled[MAX_TEXTURE_UNITS]; + GLbitfield TexGenEnabled[MAX_TEXTURE_UNITS]; + GLuint EnvMode; /* unit[0] only */ + + /** META_VERTEX */ + struct gl_array_object *ArrayObj; + struct gl_buffer_object *ArrayBufferObj; + + /** META_VIEWPORT */ + GLint ViewportX, ViewportY, ViewportW, ViewportH; + GLclampd DepthNear, DepthFar; + + /** Miscellaneous (always disabled) */ + GLboolean Lighting; +}; + + +/** + * Temporary texture used for glBlitFramebuffer, glDrawPixels, etc. + * This is currently shared by all the meta ops. But we could create a + * separate one for each of glDrawPixel, glBlitFramebuffer, glCopyPixels, etc. + */ +struct temp_texture +{ + GLuint TexObj; + GLenum Target; /**< GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE */ + GLsizei MinSize; /**< Min texture size to allocate */ + GLsizei MaxSize; /**< Max possible texture size */ + GLboolean NPOT; /**< Non-power of two size OK? */ + GLsizei Width, Height; /**< Current texture size */ + GLenum IntFormat; + GLfloat Sright, Ttop; /**< right, top texcoords */ +}; + + +/** + * State for glBlitFramebufer() + */ +struct blit_state +{ + GLuint ArrayObj; + GLuint VBO; + GLuint DepthFP; +}; + + +/** + * State for glClear() + */ +struct clear_state +{ + GLuint ArrayObj; + GLuint VBO; +}; + + +/** + * State for glCopyPixels() + */ +struct copypix_state +{ + GLuint ArrayObj; + GLuint VBO; +}; + + +/** + * State for glDrawPixels() + */ +struct drawpix_state +{ + GLuint ArrayObj; + + GLuint StencilFP; /**< Fragment program for drawing stencil images */ + GLuint DepthFP; /**< Fragment program for drawing depth images */ +}; + + +/** + * State for glBitmap() + */ +struct bitmap_state +{ + GLuint ArrayObj; + GLuint VBO; + struct temp_texture Tex; /**< separate texture from other meta ops */ +}; + + +/** + * State for _mesa_meta_generate_mipmap() + */ +struct gen_mipmap_state +{ + GLuint ArrayObj; + GLuint VBO; + GLuint FBO; +}; + +#define MAX_META_OPS_DEPTH 2 +/** + * All per-context meta state. + */ +struct gl_meta_state +{ + /** Stack of state saved during meta-ops */ + struct save_state Save[MAX_META_OPS_DEPTH]; + /** Save stack depth */ + GLuint SaveStackDepth; + + struct temp_texture TempTex; + + struct blit_state Blit; /**< For _mesa_meta_BlitFramebuffer() */ + struct clear_state Clear; /**< For _mesa_meta_Clear() */ + struct copypix_state CopyPix; /**< For _mesa_meta_CopyPixels() */ + struct drawpix_state DrawPix; /**< For _mesa_meta_DrawPixels() */ + struct bitmap_state Bitmap; /**< For _mesa_meta_Bitmap() */ + struct gen_mipmap_state Mipmap; /**< For _mesa_meta_GenerateMipmap() */ +}; + + +/** + * Initialize meta-ops for a context. + * To be called once during context creation. + */ +void +_mesa_meta_init(struct gl_context *ctx) +{ + ASSERT(!ctx->Meta); + + ctx->Meta = CALLOC_STRUCT(gl_meta_state); +} + + +/** + * Free context meta-op state. + * To be called once during context destruction. + */ +void +_mesa_meta_free(struct gl_context *ctx) +{ + /* Note: Any textures, VBOs, etc, that we allocate should get + * freed by the normal context destruction code. But this would be + * the place to free other meta data someday. + */ + free(ctx->Meta); + ctx->Meta = NULL; +} + + +/** + * Enter meta state. This is like a light-weight version of glPushAttrib + * but it also resets most GL state back to default values. + * + * \param state bitmask of META_* flags indicating which attribute groups + * to save and reset to their defaults + */ +static void +_mesa_meta_begin(struct gl_context *ctx, GLbitfield state) +{ + struct save_state *save; + + /* hope MAX_META_OPS_DEPTH is large enough */ + assert(ctx->Meta->SaveStackDepth < MAX_META_OPS_DEPTH); + + save = &ctx->Meta->Save[ctx->Meta->SaveStackDepth++]; + memset(save, 0, sizeof(*save)); + save->SavedState = state; + + if (state & META_ALPHA_TEST) { + save->AlphaEnabled = ctx->Color.AlphaEnabled; + save->AlphaFunc = ctx->Color.AlphaFunc; + save->AlphaRef = ctx->Color.AlphaRef; + if (ctx->Color.AlphaEnabled) + _mesa_set_enable(ctx, GL_ALPHA_TEST, GL_FALSE); + } + + if (state & META_BLEND) { + save->BlendEnabled = ctx->Color.BlendEnabled; + if (ctx->Color.BlendEnabled) { + if (ctx->Extensions.EXT_draw_buffers2) { + GLuint i; + for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { + _mesa_set_enablei(ctx, GL_BLEND, i, GL_FALSE); + } + } + else { + _mesa_set_enable(ctx, GL_BLEND, GL_FALSE); + } + } + save->ColorLogicOpEnabled = ctx->Color.ColorLogicOpEnabled; + if (ctx->Color.ColorLogicOpEnabled) + _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, GL_FALSE); + } + + if (state & META_COLOR_MASK) { + memcpy(save->ColorMask, ctx->Color.ColorMask, + sizeof(ctx->Color.ColorMask)); + if (!ctx->Color.ColorMask[0][0] || + !ctx->Color.ColorMask[0][1] || + !ctx->Color.ColorMask[0][2] || + !ctx->Color.ColorMask[0][3]) + _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } + + if (state & META_DEPTH_TEST) { + save->Depth = ctx->Depth; /* struct copy */ + if (ctx->Depth.Test) + _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE); + } + + if (state & META_FOG) { + save->Fog = ctx->Fog.Enabled; + if (ctx->Fog.Enabled) + _mesa_set_enable(ctx, GL_FOG, GL_FALSE); + } + + if (state & META_PIXEL_STORE) { + save->Pack = ctx->Pack; + save->Unpack = ctx->Unpack; + ctx->Pack = ctx->DefaultPacking; + ctx->Unpack = ctx->DefaultPacking; + } + + if (state & META_PIXEL_TRANSFER) { + save->RedScale = ctx->Pixel.RedScale; + save->RedBias = ctx->Pixel.RedBias; + save->GreenScale = ctx->Pixel.GreenScale; + save->GreenBias = ctx->Pixel.GreenBias; + save->BlueScale = ctx->Pixel.BlueScale; + save->BlueBias = ctx->Pixel.BlueBias; + save->AlphaScale = ctx->Pixel.AlphaScale; + save->AlphaBias = ctx->Pixel.AlphaBias; + save->MapColorFlag = ctx->Pixel.MapColorFlag; + ctx->Pixel.RedScale = 1.0F; + ctx->Pixel.RedBias = 0.0F; + ctx->Pixel.GreenScale = 1.0F; + ctx->Pixel.GreenBias = 0.0F; + ctx->Pixel.BlueScale = 1.0F; + ctx->Pixel.BlueBias = 0.0F; + ctx->Pixel.AlphaScale = 1.0F; + ctx->Pixel.AlphaBias = 0.0F; + ctx->Pixel.MapColorFlag = GL_FALSE; + /* XXX more state */ + ctx->NewState |=_NEW_PIXEL; + } + + if (state & META_RASTERIZATION) { + save->FrontPolygonMode = ctx->Polygon.FrontMode; + save->BackPolygonMode = ctx->Polygon.BackMode; + save->PolygonOffset = ctx->Polygon.OffsetFill; + save->PolygonSmooth = ctx->Polygon.SmoothFlag; + save->PolygonStipple = ctx->Polygon.StippleFlag; + save->PolygonCull = ctx->Polygon.CullFlag; + _mesa_PolygonMode(GL_FRONT_AND_BACK, GL_FILL); + _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, GL_FALSE); + _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, GL_FALSE); + _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, GL_FALSE); + _mesa_set_enable(ctx, GL_CULL_FACE, GL_FALSE); + } + + if (state & META_SCISSOR) { + save->Scissor = ctx->Scissor; /* struct copy */ + _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_FALSE); + } + + if (state & META_SHADER) { + if (ctx->Extensions.ARB_vertex_program) { + save->VertexProgramEnabled = ctx->VertexProgram.Enabled; + _mesa_reference_vertprog(ctx, &save->VertexProgram, + ctx->VertexProgram.Current); + _mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB, GL_FALSE); + } + + if (ctx->Extensions.ARB_fragment_program) { + save->FragmentProgramEnabled = ctx->FragmentProgram.Enabled; + _mesa_reference_fragprog(ctx, &save->FragmentProgram, + ctx->FragmentProgram.Current); + _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_FALSE); + } + + if (ctx->Extensions.ARB_shader_objects) { + _mesa_reference_shader_program(ctx, &save->VertexShader, + ctx->Shader.CurrentVertexProgram); + _mesa_reference_shader_program(ctx, &save->GeometryShader, + ctx->Shader.CurrentGeometryProgram); + _mesa_reference_shader_program(ctx, &save->FragmentShader, + ctx->Shader.CurrentFragmentProgram); + _mesa_reference_shader_program(ctx, &save->ActiveShader, + ctx->Shader.CurrentFragmentProgram); + + _mesa_UseProgramObjectARB(0); + } + } + + if (state & META_STENCIL_TEST) { + save->Stencil = ctx->Stencil; /* struct copy */ + if (ctx->Stencil.Enabled) + _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_FALSE); + /* NOTE: other stencil state not reset */ + } + + if (state & META_TEXTURE) { + GLuint u, tgt; + + save->ActiveUnit = ctx->Texture.CurrentUnit; + save->ClientActiveUnit = ctx->Array.ActiveTexture; + save->EnvMode = ctx->Texture.Unit[0].EnvMode; + + /* Disable all texture units */ + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + save->TexEnabled[u] = ctx->Texture.Unit[u].Enabled; + save->TexGenEnabled[u] = ctx->Texture.Unit[u].TexGenEnabled; + if (ctx->Texture.Unit[u].Enabled || + ctx->Texture.Unit[u].TexGenEnabled) { + _mesa_ActiveTextureARB(GL_TEXTURE0 + u); + _mesa_set_enable(ctx, GL_TEXTURE_1D, GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_2D, GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_3D, GL_FALSE); + if (ctx->Extensions.ARB_texture_cube_map) + _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE, GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, GL_FALSE); + } + } + + /* save current texture objects for unit[0] only */ + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + _mesa_reference_texobj(&save->CurrentTexture[tgt], + ctx->Texture.Unit[0].CurrentTex[tgt]); + } + + /* set defaults for unit[0] */ + _mesa_ActiveTextureARB(GL_TEXTURE0); + _mesa_ClientActiveTextureARB(GL_TEXTURE0); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + + if (state & META_TRANSFORM) { + GLuint activeTexture = ctx->Texture.CurrentUnit; + memcpy(save->ModelviewMatrix, ctx->ModelviewMatrixStack.Top->m, + 16 * sizeof(GLfloat)); + memcpy(save->ProjectionMatrix, ctx->ProjectionMatrixStack.Top->m, + 16 * sizeof(GLfloat)); + memcpy(save->TextureMatrix, ctx->TextureMatrixStack[0].Top->m, + 16 * sizeof(GLfloat)); + save->MatrixMode = ctx->Transform.MatrixMode; + /* set 1:1 vertex:pixel coordinate transform */ + _mesa_ActiveTextureARB(GL_TEXTURE0); + _mesa_MatrixMode(GL_TEXTURE); + _mesa_LoadIdentity(); + _mesa_ActiveTextureARB(GL_TEXTURE0 + activeTexture); + _mesa_MatrixMode(GL_MODELVIEW); + _mesa_LoadIdentity(); + _mesa_MatrixMode(GL_PROJECTION); + _mesa_LoadIdentity(); + _mesa_Ortho(0.0, ctx->DrawBuffer->Width, + 0.0, ctx->DrawBuffer->Height, + -1.0, 1.0); + save->ClipPlanesEnabled = ctx->Transform.ClipPlanesEnabled; + if (ctx->Transform.ClipPlanesEnabled) { + GLuint i; + for (i = 0; i < ctx->Const.MaxClipPlanes; i++) { + _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_FALSE); + } + } + } + + if (state & META_VERTEX) { + /* save vertex array object state */ + _mesa_reference_array_object(ctx, &save->ArrayObj, + ctx->Array.ArrayObj); + _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj, + ctx->Array.ArrayBufferObj); + /* set some default state? */ + } + + if (state & META_VIEWPORT) { + /* save viewport state */ + save->ViewportX = ctx->Viewport.X; + save->ViewportY = ctx->Viewport.Y; + save->ViewportW = ctx->Viewport.Width; + save->ViewportH = ctx->Viewport.Height; + /* set viewport to match window size */ + if (ctx->Viewport.X != 0 || + ctx->Viewport.Y != 0 || + ctx->Viewport.Width != ctx->DrawBuffer->Width || + ctx->Viewport.Height != ctx->DrawBuffer->Height) { + _mesa_set_viewport(ctx, 0, 0, + ctx->DrawBuffer->Width, ctx->DrawBuffer->Height); + } + /* save depth range state */ + save->DepthNear = ctx->Viewport.Near; + save->DepthFar = ctx->Viewport.Far; + /* set depth range to default */ + _mesa_DepthRange(0.0, 1.0); + } + + /* misc */ + { + save->Lighting = ctx->Light.Enabled; + if (ctx->Light.Enabled) + _mesa_set_enable(ctx, GL_LIGHTING, GL_FALSE); + } +} + + +/** + * Leave meta state. This is like a light-weight version of glPopAttrib(). + */ +static void +_mesa_meta_end(struct gl_context *ctx) +{ + struct save_state *save = &ctx->Meta->Save[--ctx->Meta->SaveStackDepth]; + const GLbitfield state = save->SavedState; + + if (state & META_ALPHA_TEST) { + if (ctx->Color.AlphaEnabled != save->AlphaEnabled) + _mesa_set_enable(ctx, GL_ALPHA_TEST, save->AlphaEnabled); + _mesa_AlphaFunc(save->AlphaFunc, save->AlphaRef); + } + + if (state & META_BLEND) { + if (ctx->Color.BlendEnabled != save->BlendEnabled) { + if (ctx->Extensions.EXT_draw_buffers2) { + GLuint i; + for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { + _mesa_set_enablei(ctx, GL_BLEND, i, (save->BlendEnabled >> i) & 1); + } + } + else { + _mesa_set_enable(ctx, GL_BLEND, (save->BlendEnabled & 1)); + } + } + if (ctx->Color.ColorLogicOpEnabled != save->ColorLogicOpEnabled) + _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, save->ColorLogicOpEnabled); + } + + if (state & META_COLOR_MASK) { + GLuint i; + for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { + if (!TEST_EQ_4V(ctx->Color.ColorMask[i], save->ColorMask[i])) { + if (i == 0) { + _mesa_ColorMask(save->ColorMask[i][0], save->ColorMask[i][1], + save->ColorMask[i][2], save->ColorMask[i][3]); + } + else { + _mesa_ColorMaskIndexed(i, + save->ColorMask[i][0], + save->ColorMask[i][1], + save->ColorMask[i][2], + save->ColorMask[i][3]); + } + } + } + } + + if (state & META_DEPTH_TEST) { + if (ctx->Depth.Test != save->Depth.Test) + _mesa_set_enable(ctx, GL_DEPTH_TEST, save->Depth.Test); + _mesa_DepthFunc(save->Depth.Func); + _mesa_DepthMask(save->Depth.Mask); + } + + if (state & META_FOG) { + _mesa_set_enable(ctx, GL_FOG, save->Fog); + } + + if (state & META_PIXEL_STORE) { + ctx->Pack = save->Pack; + ctx->Unpack = save->Unpack; + } + + if (state & META_PIXEL_TRANSFER) { + ctx->Pixel.RedScale = save->RedScale; + ctx->Pixel.RedBias = save->RedBias; + ctx->Pixel.GreenScale = save->GreenScale; + ctx->Pixel.GreenBias = save->GreenBias; + ctx->Pixel.BlueScale = save->BlueScale; + ctx->Pixel.BlueBias = save->BlueBias; + ctx->Pixel.AlphaScale = save->AlphaScale; + ctx->Pixel.AlphaBias = save->AlphaBias; + ctx->Pixel.MapColorFlag = save->MapColorFlag; + /* XXX more state */ + ctx->NewState |=_NEW_PIXEL; + } + + if (state & META_RASTERIZATION) { + _mesa_PolygonMode(GL_FRONT, save->FrontPolygonMode); + _mesa_PolygonMode(GL_BACK, save->BackPolygonMode); + _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, save->PolygonStipple); + _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, save->PolygonOffset); + _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, save->PolygonSmooth); + _mesa_set_enable(ctx, GL_CULL_FACE, save->PolygonCull); + } + + if (state & META_SCISSOR) { + _mesa_set_enable(ctx, GL_SCISSOR_TEST, save->Scissor.Enabled); + _mesa_Scissor(save->Scissor.X, save->Scissor.Y, + save->Scissor.Width, save->Scissor.Height); + } + + if (state & META_SHADER) { + if (ctx->Extensions.ARB_vertex_program) { + _mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB, + save->VertexProgramEnabled); + _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, + save->VertexProgram); + _mesa_reference_vertprog(ctx, &save->VertexProgram, NULL); + } + + if (ctx->Extensions.ARB_fragment_program) { + _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, + save->FragmentProgramEnabled); + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, + save->FragmentProgram); + _mesa_reference_fragprog(ctx, &save->FragmentProgram, NULL); + } + + if (ctx->Extensions.ARB_vertex_shader) + _mesa_use_shader_program(ctx, GL_VERTEX_SHADER, save->VertexShader); + + if (ctx->Extensions.ARB_geometry_shader4) + _mesa_use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, + save->GeometryShader); + + if (ctx->Extensions.ARB_fragment_shader) + _mesa_use_shader_program(ctx, GL_FRAGMENT_SHADER, + save->FragmentShader); + + _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, + save->ActiveShader); + } + + if (state & META_STENCIL_TEST) { + const struct gl_stencil_attrib *stencil = &save->Stencil; + + _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled); + _mesa_ClearStencil(stencil->Clear); + if (ctx->Extensions.EXT_stencil_two_side) { + _mesa_set_enable(ctx, GL_STENCIL_TEST_TWO_SIDE_EXT, + stencil->TestTwoSide); + _mesa_ActiveStencilFaceEXT(stencil->ActiveFace + ? GL_BACK : GL_FRONT); + } + /* front state */ + _mesa_StencilFuncSeparate(GL_FRONT, + stencil->Function[0], + stencil->Ref[0], + stencil->ValueMask[0]); + _mesa_StencilMaskSeparate(GL_FRONT, stencil->WriteMask[0]); + _mesa_StencilOpSeparate(GL_FRONT, stencil->FailFunc[0], + stencil->ZFailFunc[0], + stencil->ZPassFunc[0]); + /* back state */ + _mesa_StencilFuncSeparate(GL_BACK, + stencil->Function[1], + stencil->Ref[1], + stencil->ValueMask[1]); + _mesa_StencilMaskSeparate(GL_BACK, stencil->WriteMask[1]); + _mesa_StencilOpSeparate(GL_BACK, stencil->FailFunc[1], + stencil->ZFailFunc[1], + stencil->ZPassFunc[1]); + } + + if (state & META_TEXTURE) { + GLuint u, tgt; + + ASSERT(ctx->Texture.CurrentUnit == 0); + + /* restore texenv for unit[0] */ + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, save->EnvMode); + + /* restore texture objects for unit[0] only */ + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + _mesa_reference_texobj(&ctx->Texture.Unit[0].CurrentTex[tgt], + save->CurrentTexture[tgt]); + _mesa_reference_texobj(&save->CurrentTexture[tgt], NULL); + } + + /* Re-enable textures, texgen */ + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + if (save->TexEnabled[u]) { + _mesa_ActiveTextureARB(GL_TEXTURE0 + u); + + if (save->TexEnabled[u] & TEXTURE_1D_BIT) + _mesa_set_enable(ctx, GL_TEXTURE_1D, GL_TRUE); + if (save->TexEnabled[u] & TEXTURE_2D_BIT) + _mesa_set_enable(ctx, GL_TEXTURE_2D, GL_TRUE); + if (save->TexEnabled[u] & TEXTURE_3D_BIT) + _mesa_set_enable(ctx, GL_TEXTURE_3D, GL_TRUE); + if (save->TexEnabled[u] & TEXTURE_CUBE_BIT) + _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, GL_TRUE); + if (save->TexEnabled[u] & TEXTURE_RECT_BIT) + _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE, GL_TRUE); + } + + if (save->TexGenEnabled[u]) { + _mesa_ActiveTextureARB(GL_TEXTURE0 + u); + + if (save->TexGenEnabled[u] & S_BIT) + _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, GL_TRUE); + if (save->TexGenEnabled[u] & T_BIT) + _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, GL_TRUE); + if (save->TexGenEnabled[u] & R_BIT) + _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, GL_TRUE); + if (save->TexGenEnabled[u] & Q_BIT) + _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, GL_TRUE); + } + } + + /* restore current unit state */ + _mesa_ActiveTextureARB(GL_TEXTURE0 + save->ActiveUnit); + _mesa_ClientActiveTextureARB(GL_TEXTURE0 + save->ClientActiveUnit); + } + + if (state & META_TRANSFORM) { + GLuint activeTexture = ctx->Texture.CurrentUnit; + _mesa_ActiveTextureARB(GL_TEXTURE0); + _mesa_MatrixMode(GL_TEXTURE); + _mesa_LoadMatrixf(save->TextureMatrix); + _mesa_ActiveTextureARB(GL_TEXTURE0 + activeTexture); + + _mesa_MatrixMode(GL_MODELVIEW); + _mesa_LoadMatrixf(save->ModelviewMatrix); + + _mesa_MatrixMode(GL_PROJECTION); + _mesa_LoadMatrixf(save->ProjectionMatrix); + + _mesa_MatrixMode(save->MatrixMode); + + if (save->ClipPlanesEnabled) { + GLuint i; + for (i = 0; i < ctx->Const.MaxClipPlanes; i++) { + if (save->ClipPlanesEnabled & (1 << i)) { + _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_TRUE); + } + } + } + } + + if (state & META_VERTEX) { + /* restore vertex buffer object */ + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, save->ArrayBufferObj->Name); + _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj, NULL); + + /* restore vertex array object */ + _mesa_BindVertexArray(save->ArrayObj->Name); + _mesa_reference_array_object(ctx, &save->ArrayObj, NULL); + } + + if (state & META_VIEWPORT) { + if (save->ViewportX != ctx->Viewport.X || + save->ViewportY != ctx->Viewport.Y || + save->ViewportW != ctx->Viewport.Width || + save->ViewportH != ctx->Viewport.Height) { + _mesa_set_viewport(ctx, save->ViewportX, save->ViewportY, + save->ViewportW, save->ViewportH); + } + _mesa_DepthRange(save->DepthNear, save->DepthFar); + } + + /* misc */ + if (save->Lighting) { + _mesa_set_enable(ctx, GL_LIGHTING, GL_TRUE); + } +} + + +/** + * Convert Z from a normalized value in the range [0, 1] to an object-space + * Z coordinate in [-1, +1] so that drawing at the new Z position with the + * default/identity ortho projection results in the original Z value. + * Used by the meta-Clear, Draw/CopyPixels and Bitmap functions where the Z + * value comes from the clear value or raster position. + */ +static INLINE GLfloat +invert_z(GLfloat normZ) +{ + GLfloat objZ = 1.0 - 2.0 * normZ; + return objZ; +} + + +/** + * One-time init for a temp_texture object. + * Choose tex target, compute max tex size, etc. + */ +static void +init_temp_texture(struct gl_context *ctx, struct temp_texture *tex) +{ + /* prefer texture rectangle */ + if (ctx->Extensions.NV_texture_rectangle) { + tex->Target = GL_TEXTURE_RECTANGLE; + tex->MaxSize = ctx->Const.MaxTextureRectSize; + tex->NPOT = GL_TRUE; + } + else { + /* use 2D texture, NPOT if possible */ + tex->Target = GL_TEXTURE_2D; + tex->MaxSize = 1 << (ctx->Const.MaxTextureLevels - 1); + tex->NPOT = ctx->Extensions.ARB_texture_non_power_of_two; + } + tex->MinSize = 16; /* 16 x 16 at least */ + assert(tex->MaxSize > 0); + + _mesa_GenTextures(1, &tex->TexObj); +} + + +/** + * Return pointer to temp_texture info for non-bitmap ops. + * This does some one-time init if needed. + */ +static struct temp_texture * +get_temp_texture(struct gl_context *ctx) +{ + struct temp_texture *tex = &ctx->Meta->TempTex; + + if (!tex->TexObj) { + init_temp_texture(ctx, tex); + } + + return tex; +} + + +/** + * Return pointer to temp_texture info for _mesa_meta_bitmap(). + * We use a separate texture for bitmaps to reduce texture + * allocation/deallocation. + */ +static struct temp_texture * +get_bitmap_temp_texture(struct gl_context *ctx) +{ + struct temp_texture *tex = &ctx->Meta->Bitmap.Tex; + + if (!tex->TexObj) { + init_temp_texture(ctx, tex); + } + + return tex; +} + + +/** + * Compute the width/height of texture needed to draw an image of the + * given size. Return a flag indicating whether the current texture + * can be re-used (glTexSubImage2D) or if a new texture needs to be + * allocated (glTexImage2D). + * Also, compute s/t texcoords for drawing. + * + * \return GL_TRUE if new texture is needed, GL_FALSE otherwise + */ +static GLboolean +alloc_texture(struct temp_texture *tex, + GLsizei width, GLsizei height, GLenum intFormat) +{ + GLboolean newTex = GL_FALSE; + + ASSERT(width <= tex->MaxSize); + ASSERT(height <= tex->MaxSize); + + if (width > tex->Width || + height > tex->Height || + intFormat != tex->IntFormat) { + /* alloc new texture (larger or different format) */ + + if (tex->NPOT) { + /* use non-power of two size */ + tex->Width = MAX2(tex->MinSize, width); + tex->Height = MAX2(tex->MinSize, height); + } + else { + /* find power of two size */ + GLsizei w, h; + w = h = tex->MinSize; + while (w < width) + w *= 2; + while (h < height) + h *= 2; + tex->Width = w; + tex->Height = h; + } + + tex->IntFormat = intFormat; + + newTex = GL_TRUE; + } + + /* compute texcoords */ + if (tex->Target == GL_TEXTURE_RECTANGLE) { + tex->Sright = (GLfloat) width; + tex->Ttop = (GLfloat) height; + } + else { + tex->Sright = (GLfloat) width / tex->Width; + tex->Ttop = (GLfloat) height / tex->Height; + } + + return newTex; +} + + +/** + * Setup/load texture for glCopyPixels or glBlitFramebuffer. + */ +static void +setup_copypix_texture(struct temp_texture *tex, + GLboolean newTex, + GLint srcX, GLint srcY, + GLsizei width, GLsizei height, GLenum intFormat, + GLenum filter) +{ + _mesa_BindTexture(tex->Target, tex->TexObj); + _mesa_TexParameteri(tex->Target, GL_TEXTURE_MIN_FILTER, filter); + _mesa_TexParameteri(tex->Target, GL_TEXTURE_MAG_FILTER, filter); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + /* copy framebuffer image to texture */ + if (newTex) { + /* create new tex image */ + if (tex->Width == width && tex->Height == height) { + /* create new tex with framebuffer data */ + _mesa_CopyTexImage2D(tex->Target, 0, tex->IntFormat, + srcX, srcY, width, height, 0); + } + else { + /* create empty texture */ + _mesa_TexImage2D(tex->Target, 0, tex->IntFormat, + tex->Width, tex->Height, 0, + intFormat, GL_UNSIGNED_BYTE, NULL); + /* load image */ + _mesa_CopyTexSubImage2D(tex->Target, 0, + 0, 0, srcX, srcY, width, height); + } + } + else { + /* replace existing tex image */ + _mesa_CopyTexSubImage2D(tex->Target, 0, + 0, 0, srcX, srcY, width, height); + } +} + + +/** + * Setup/load texture for glDrawPixels. + */ +static void +setup_drawpix_texture(struct gl_context *ctx, + struct temp_texture *tex, + GLboolean newTex, + GLenum texIntFormat, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const GLvoid *pixels) +{ + _mesa_BindTexture(tex->Target, tex->TexObj); + _mesa_TexParameteri(tex->Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + _mesa_TexParameteri(tex->Target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + /* copy pixel data to texture */ + if (newTex) { + /* create new tex image */ + if (tex->Width == width && tex->Height == height) { + /* create new tex and load image data */ + _mesa_TexImage2D(tex->Target, 0, tex->IntFormat, + tex->Width, tex->Height, 0, format, type, pixels); + } + else { + struct gl_buffer_object *save_unpack_obj = NULL; + + _mesa_reference_buffer_object(ctx, &save_unpack_obj, + ctx->Unpack.BufferObj); + _mesa_BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + /* create empty texture */ + _mesa_TexImage2D(tex->Target, 0, tex->IntFormat, + tex->Width, tex->Height, 0, format, type, NULL); + if (save_unpack_obj != NULL) + _mesa_BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, + save_unpack_obj->Name); + /* load image */ + _mesa_TexSubImage2D(tex->Target, 0, + 0, 0, width, height, format, type, pixels); + } + } + else { + /* replace existing tex image */ + _mesa_TexSubImage2D(tex->Target, 0, + 0, 0, width, height, format, type, pixels); + } +} + + + +/** + * One-time init for drawing depth pixels. + */ +static void +init_blit_depth_pixels(struct gl_context *ctx) +{ + static const char *program = + "!!ARBfp1.0\n" + "TEX result.depth, fragment.texcoord[0], texture[0], %s; \n" + "END \n"; + char program2[200]; + struct blit_state *blit = &ctx->Meta->Blit; + struct temp_texture *tex = get_temp_texture(ctx); + const char *texTarget; + + assert(blit->DepthFP == 0); + + /* replace %s with "RECT" or "2D" */ + assert(strlen(program) + 4 < sizeof(program2)); + if (tex->Target == GL_TEXTURE_RECTANGLE) + texTarget = "RECT"; + else + texTarget = "2D"; + _mesa_snprintf(program2, sizeof(program2), program, texTarget); + + _mesa_GenPrograms(1, &blit->DepthFP); + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, blit->DepthFP); + _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, + strlen(program2), (const GLubyte *) program2); +} + + +/** + * Try to do a glBlitFramebuffer using no-copy texturing. + * We can do this when the src renderbuffer is actually a texture. + * But if the src buffer == dst buffer we cannot do this. + * + * \return new buffer mask indicating the buffers left to blit using the + * normal path. + */ +static GLbitfield +blitframebuffer_texture(struct gl_context *ctx, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + if (mask & GL_COLOR_BUFFER_BIT) { + const struct gl_framebuffer *drawFb = ctx->DrawBuffer; + const struct gl_framebuffer *readFb = ctx->ReadBuffer; + const struct gl_renderbuffer_attachment *drawAtt = + &drawFb->Attachment[drawFb->_ColorDrawBufferIndexes[0]]; + const struct gl_renderbuffer_attachment *readAtt = + &readFb->Attachment[readFb->_ColorReadBufferIndex]; + + if (readAtt && readAtt->Texture) { + const struct gl_texture_object *texObj = readAtt->Texture; + const GLuint srcLevel = readAtt->TextureLevel; + const GLenum minFilterSave = texObj->MinFilter; + const GLenum magFilterSave = texObj->MagFilter; + const GLint baseLevelSave = texObj->BaseLevel; + const GLint maxLevelSave = texObj->MaxLevel; + const GLenum wrapSSave = texObj->WrapS; + const GLenum wrapTSave = texObj->WrapT; + const GLenum target = texObj->Target; + + if (drawAtt->Texture == readAtt->Texture) { + /* Can't use same texture as both the source and dest. We need + * to handle overlapping blits and besides, some hw may not + * support this. + */ + return mask; + } + + if (target != GL_TEXTURE_2D && target != GL_TEXTURE_RECTANGLE_ARB) { + /* Can't handle other texture types at this time */ + return mask; + } + + /* + printf("Blit from texture!\n"); + printf(" srcAtt %p dstAtt %p\n", readAtt, drawAtt); + printf(" srcTex %p dstText %p\n", texObj, drawAtt->Texture); + */ + + /* Prepare src texture state */ + _mesa_BindTexture(target, texObj->Name); + _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter); + _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter); + if (target != GL_TEXTURE_RECTANGLE_ARB) { + _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, srcLevel); + _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel); + } + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + _mesa_set_enable(ctx, target, GL_TRUE); + + /* Prepare vertex data (the VBO was previously created and bound) */ + { + struct vertex { + GLfloat x, y, s, t; + }; + struct vertex verts[4]; + GLfloat s0, t0, s1, t1; + + if (target == GL_TEXTURE_2D) { + const struct gl_texture_image *texImage + = _mesa_select_tex_image(ctx, texObj, target, srcLevel); + s0 = srcX0 / (float) texImage->Width; + s1 = srcX1 / (float) texImage->Width; + t0 = srcY0 / (float) texImage->Height; + t1 = srcY1 / (float) texImage->Height; + } + else { + assert(target == GL_TEXTURE_RECTANGLE_ARB); + s0 = srcX0; + s1 = srcX1; + t0 = srcY0; + t1 = srcY1; + } + + verts[0].x = (GLfloat) dstX0; + verts[0].y = (GLfloat) dstY0; + verts[1].x = (GLfloat) dstX1; + verts[1].y = (GLfloat) dstY0; + verts[2].x = (GLfloat) dstX1; + verts[2].y = (GLfloat) dstY1; + verts[3].x = (GLfloat) dstX0; + verts[3].y = (GLfloat) dstY1; + + verts[0].s = s0; + verts[0].t = t0; + verts[1].s = s1; + verts[1].t = t0; + verts[2].s = s1; + verts[2].t = t1; + verts[3].s = s0; + verts[3].t = t1; + + _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); + } + + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + + /* Restore texture object state, the texture binding will + * be restored by _mesa_meta_end(). + */ + _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilterSave); + _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilterSave); + if (target != GL_TEXTURE_RECTANGLE_ARB) { + _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, baseLevelSave); + _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); + } + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, wrapSSave); + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, wrapTSave); + + /* Done with color buffer */ + mask &= ~GL_COLOR_BUFFER_BIT; + } + } + + return mask; +} + + +/** + * Meta implementation of ctx->Driver.BlitFramebuffer() in terms + * of texture mapping and polygon rendering. + */ +void +_mesa_meta_BlitFramebuffer(struct gl_context *ctx, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + struct blit_state *blit = &ctx->Meta->Blit; + struct temp_texture *tex = get_temp_texture(ctx); + const GLsizei maxTexSize = tex->MaxSize; + const GLint srcX = MIN2(srcX0, srcX1); + const GLint srcY = MIN2(srcY0, srcY1); + const GLint srcW = abs(srcX1 - srcX0); + const GLint srcH = abs(srcY1 - srcY0); + const GLboolean srcFlipX = srcX1 < srcX0; + const GLboolean srcFlipY = srcY1 < srcY0; + struct vertex { + GLfloat x, y, s, t; + }; + struct vertex verts[4]; + GLboolean newTex; + + if (srcW > maxTexSize || srcH > maxTexSize) { + /* XXX avoid this fallback */ + _swrast_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, mask, filter); + return; + } + + if (srcFlipX) { + GLint tmp = dstX0; + dstX0 = dstX1; + dstX1 = tmp; + } + + if (srcFlipY) { + GLint tmp = dstY0; + dstY0 = dstY1; + dstY1 = tmp; + } + + /* only scissor effects blit so save/clear all other relevant state */ + _mesa_meta_begin(ctx, ~META_SCISSOR); + + if (blit->ArrayObj == 0) { + /* one-time setup */ + + /* create vertex array object */ + _mesa_GenVertexArrays(1, &blit->ArrayObj); + _mesa_BindVertexArray(blit->ArrayObj); + + /* create vertex array buffer */ + _mesa_GenBuffersARB(1, &blit->VBO); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, blit->VBO); + _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), + NULL, GL_DYNAMIC_DRAW_ARB); + + /* setup vertex arrays */ + _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); + _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); + _mesa_EnableClientState(GL_VERTEX_ARRAY); + _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); + } + else { + _mesa_BindVertexArray(blit->ArrayObj); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, blit->VBO); + } + + /* Try faster, direct texture approach first */ + mask = blitframebuffer_texture(ctx, srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, mask, filter); + if (mask == 0x0) { + _mesa_meta_end(ctx); + return; + } + + /* Continue with "normal" approach which involves copying the src rect + * into a temporary texture and is "blitted" by drawing a textured quad. + */ + + newTex = alloc_texture(tex, srcW, srcH, GL_RGBA); + + /* vertex positions/texcoords (after texture allocation!) */ + { + verts[0].x = (GLfloat) dstX0; + verts[0].y = (GLfloat) dstY0; + verts[1].x = (GLfloat) dstX1; + verts[1].y = (GLfloat) dstY0; + verts[2].x = (GLfloat) dstX1; + verts[2].y = (GLfloat) dstY1; + verts[3].x = (GLfloat) dstX0; + verts[3].y = (GLfloat) dstY1; + + verts[0].s = 0.0F; + verts[0].t = 0.0F; + verts[1].s = tex->Sright; + verts[1].t = 0.0F; + verts[2].s = tex->Sright; + verts[2].t = tex->Ttop; + verts[3].s = 0.0F; + verts[3].t = tex->Ttop; + + /* upload new vertex data */ + _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); + } + + _mesa_set_enable(ctx, tex->Target, GL_TRUE); + + if (mask & GL_COLOR_BUFFER_BIT) { + setup_copypix_texture(tex, newTex, srcX, srcY, srcW, srcH, + GL_RGBA, filter); + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + mask &= ~GL_COLOR_BUFFER_BIT; + } + + if (mask & GL_DEPTH_BUFFER_BIT) { + GLuint *tmp = (GLuint *) malloc(srcW * srcH * sizeof(GLuint)); + if (tmp) { + if (!blit->DepthFP) + init_blit_depth_pixels(ctx); + + /* maybe change tex format here */ + newTex = alloc_texture(tex, srcW, srcH, GL_DEPTH_COMPONENT); + + _mesa_ReadPixels(srcX, srcY, srcW, srcH, + GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, tmp); + + setup_drawpix_texture(ctx, tex, newTex, GL_DEPTH_COMPONENT, srcW, srcH, + GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, tmp); + + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, blit->DepthFP); + _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); + _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE); + _mesa_DepthFunc(GL_ALWAYS); + _mesa_DepthMask(GL_TRUE); + + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + mask &= ~GL_DEPTH_BUFFER_BIT; + + free(tmp); + } + } + + if (mask & GL_STENCIL_BUFFER_BIT) { + /* XXX can't easily do stencil */ + } + + _mesa_set_enable(ctx, tex->Target, GL_FALSE); + + _mesa_meta_end(ctx); + + if (mask) { + _swrast_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, mask, filter); + } +} + + +/** + * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering. + */ +void +_mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers) +{ + struct clear_state *clear = &ctx->Meta->Clear; + struct vertex { + GLfloat x, y, z, r, g, b, a; + }; + struct vertex verts[4]; + /* save all state but scissor, pixel pack/unpack */ + GLbitfield metaSave = META_ALL - META_SCISSOR - META_PIXEL_STORE; + const GLuint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; + + if (buffers & BUFFER_BITS_COLOR) { + /* if clearing color buffers, don't save/restore colormask */ + metaSave -= META_COLOR_MASK; + } + + _mesa_meta_begin(ctx, metaSave); + + if (clear->ArrayObj == 0) { + /* one-time setup */ + + /* create vertex array object */ + _mesa_GenVertexArrays(1, &clear->ArrayObj); + _mesa_BindVertexArray(clear->ArrayObj); + + /* create vertex array buffer */ + _mesa_GenBuffersARB(1, &clear->VBO); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, clear->VBO); + + /* setup vertex arrays */ + _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); + _mesa_ColorPointer(4, GL_FLOAT, sizeof(struct vertex), OFFSET(r)); + _mesa_EnableClientState(GL_VERTEX_ARRAY); + _mesa_EnableClientState(GL_COLOR_ARRAY); + } + else { + _mesa_BindVertexArray(clear->ArrayObj); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, clear->VBO); + } + + /* GL_COLOR_BUFFER_BIT */ + if (buffers & BUFFER_BITS_COLOR) { + /* leave colormask, glDrawBuffer state as-is */ + } + else { + ASSERT(metaSave & META_COLOR_MASK); + _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + } + + /* GL_DEPTH_BUFFER_BIT */ + if (buffers & BUFFER_BIT_DEPTH) { + _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE); + _mesa_DepthFunc(GL_ALWAYS); + _mesa_DepthMask(GL_TRUE); + } + else { + assert(!ctx->Depth.Test); + } + + /* GL_STENCIL_BUFFER_BIT */ + if (buffers & BUFFER_BIT_STENCIL) { + _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_TRUE); + _mesa_StencilOpSeparate(GL_FRONT_AND_BACK, + GL_REPLACE, GL_REPLACE, GL_REPLACE); + _mesa_StencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS, + ctx->Stencil.Clear & stencilMax, + ctx->Stencil.WriteMask[0]); + } + else { + assert(!ctx->Stencil.Enabled); + } + + /* vertex positions/colors */ + { + const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin; + const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin; + const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax; + const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax; + const GLfloat z = invert_z(ctx->Depth.Clear); + GLuint i; + + verts[0].x = x0; + verts[0].y = y0; + verts[0].z = z; + verts[1].x = x1; + verts[1].y = y0; + verts[1].z = z; + verts[2].x = x1; + verts[2].y = y1; + verts[2].z = z; + verts[3].x = x0; + verts[3].y = y1; + verts[3].z = z; + + /* vertex colors */ + for (i = 0; i < 4; i++) { + verts[i].r = ctx->Color.ClearColor[0]; + verts[i].g = ctx->Color.ClearColor[1]; + verts[i].b = ctx->Color.ClearColor[2]; + verts[i].a = ctx->Color.ClearColor[3]; + } + + /* upload new vertex data */ + _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts, + GL_DYNAMIC_DRAW_ARB); + } + + /* draw quad */ + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + + _mesa_meta_end(ctx); +} + + +/** + * Meta implementation of ctx->Driver.CopyPixels() in terms + * of texture mapping and polygon rendering. + */ +void +_mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY, + GLsizei width, GLsizei height, + GLint dstX, GLint dstY, GLenum type) +{ + struct copypix_state *copypix = &ctx->Meta->CopyPix; + struct temp_texture *tex = get_temp_texture(ctx); + struct vertex { + GLfloat x, y, z, s, t; + }; + struct vertex verts[4]; + GLboolean newTex; + GLenum intFormat = GL_RGBA; + + if (type != GL_COLOR || + ctx->_ImageTransferState || + ctx->Fog.Enabled || + width > tex->MaxSize || + height > tex->MaxSize) { + /* XXX avoid this fallback */ + _swrast_CopyPixels(ctx, srcX, srcY, width, height, dstX, dstY, type); + return; + } + + /* Most GL state applies to glCopyPixels, but a there's a few things + * we need to override: + */ + _mesa_meta_begin(ctx, (META_RASTERIZATION | + META_SHADER | + META_TEXTURE | + META_TRANSFORM | + META_VERTEX | + META_VIEWPORT)); + + if (copypix->ArrayObj == 0) { + /* one-time setup */ + + /* create vertex array object */ + _mesa_GenVertexArrays(1, ©pix->ArrayObj); + _mesa_BindVertexArray(copypix->ArrayObj); + + /* create vertex array buffer */ + _mesa_GenBuffersARB(1, ©pix->VBO); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, copypix->VBO); + _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), + NULL, GL_DYNAMIC_DRAW_ARB); + + /* setup vertex arrays */ + _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); + _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); + _mesa_EnableClientState(GL_VERTEX_ARRAY); + _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); + } + else { + _mesa_BindVertexArray(copypix->ArrayObj); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, copypix->VBO); + } + + newTex = alloc_texture(tex, width, height, intFormat); + + /* vertex positions, texcoords (after texture allocation!) */ + { + const GLfloat dstX0 = (GLfloat) dstX; + const GLfloat dstY0 = (GLfloat) dstY; + const GLfloat dstX1 = dstX + width * ctx->Pixel.ZoomX; + const GLfloat dstY1 = dstY + height * ctx->Pixel.ZoomY; + const GLfloat z = invert_z(ctx->Current.RasterPos[2]); + + verts[0].x = dstX0; + verts[0].y = dstY0; + verts[0].z = z; + verts[0].s = 0.0F; + verts[0].t = 0.0F; + verts[1].x = dstX1; + verts[1].y = dstY0; + verts[1].z = z; + verts[1].s = tex->Sright; + verts[1].t = 0.0F; + verts[2].x = dstX1; + verts[2].y = dstY1; + verts[2].z = z; + verts[2].s = tex->Sright; + verts[2].t = tex->Ttop; + verts[3].x = dstX0; + verts[3].y = dstY1; + verts[3].z = z; + verts[3].s = 0.0F; + verts[3].t = tex->Ttop; + + /* upload new vertex data */ + _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); + } + + /* Alloc/setup texture */ + setup_copypix_texture(tex, newTex, srcX, srcY, width, height, + GL_RGBA, GL_NEAREST); + + _mesa_set_enable(ctx, tex->Target, GL_TRUE); + + /* draw textured quad */ + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + + _mesa_set_enable(ctx, tex->Target, GL_FALSE); + + _mesa_meta_end(ctx); +} + + + +/** + * When the glDrawPixels() image size is greater than the max rectangle + * texture size we use this function to break the glDrawPixels() image + * into tiles which fit into the max texture size. + */ +static void +tiled_draw_pixels(struct gl_context *ctx, + GLint tileSize, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels) +{ + struct gl_pixelstore_attrib tileUnpack = *unpack; + GLint i, j; + + if (tileUnpack.RowLength == 0) + tileUnpack.RowLength = width; + + for (i = 0; i < width; i += tileSize) { + const GLint tileWidth = MIN2(tileSize, width - i); + const GLint tileX = (GLint) (x + i * ctx->Pixel.ZoomX); + + tileUnpack.SkipPixels = unpack->SkipPixels + i; + + for (j = 0; j < height; j += tileSize) { + const GLint tileHeight = MIN2(tileSize, height - j); + const GLint tileY = (GLint) (y + j * ctx->Pixel.ZoomY); + + tileUnpack.SkipRows = unpack->SkipRows + j; + + _mesa_meta_DrawPixels(ctx, tileX, tileY, tileWidth, tileHeight, + format, type, &tileUnpack, pixels); + } + } +} + + +/** + * One-time init for drawing stencil pixels. + */ +static void +init_draw_stencil_pixels(struct gl_context *ctx) +{ + /* This program is run eight times, once for each stencil bit. + * The stencil values to draw are found in an 8-bit alpha texture. + * We read the texture/stencil value and test if bit 'b' is set. + * If the bit is not set, use KIL to kill the fragment. + * Finally, we use the stencil test to update the stencil buffer. + * + * The basic algorithm for checking if a bit is set is: + * if (is_odd(value / (1 << bit))) + * result is one (or non-zero). + * else + * result is zero. + * The program parameter contains three values: + * parm.x = 255 / (1 << bit) + * parm.y = 0.5 + * parm.z = 0.0 + */ + static const char *program = + "!!ARBfp1.0\n" + "PARAM parm = program.local[0]; \n" + "TEMP t; \n" + "TEX t, fragment.texcoord[0], texture[0], %s; \n" /* NOTE %s here! */ + "# t = t * 255 / bit \n" + "MUL t.x, t.a, parm.x; \n" + "# t = (int) t \n" + "FRC t.y, t.x; \n" + "SUB t.x, t.x, t.y; \n" + "# t = t * 0.5 \n" + "MUL t.x, t.x, parm.y; \n" + "# t = fract(t.x) \n" + "FRC t.x, t.x; # if t.x != 0, then the bit is set \n" + "# t.x = (t.x == 0 ? 1 : 0) \n" + "SGE t.x, -t.x, parm.z; \n" + "KIL -t.x; \n" + "# for debug only \n" + "#MOV result.color, t.x; \n" + "END \n"; + char program2[1000]; + struct drawpix_state *drawpix = &ctx->Meta->DrawPix; + struct temp_texture *tex = get_temp_texture(ctx); + const char *texTarget; + + assert(drawpix->StencilFP == 0); + + /* replace %s with "RECT" or "2D" */ + assert(strlen(program) + 4 < sizeof(program2)); + if (tex->Target == GL_TEXTURE_RECTANGLE) + texTarget = "RECT"; + else + texTarget = "2D"; + _mesa_snprintf(program2, sizeof(program2), program, texTarget); + + _mesa_GenPrograms(1, &drawpix->StencilFP); + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, drawpix->StencilFP); + _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, + strlen(program2), (const GLubyte *) program2); +} + + +/** + * One-time init for drawing depth pixels. + */ +static void +init_draw_depth_pixels(struct gl_context *ctx) +{ + static const char *program = + "!!ARBfp1.0\n" + "PARAM color = program.local[0]; \n" + "TEX result.depth, fragment.texcoord[0], texture[0], %s; \n" + "MOV result.color, color; \n" + "END \n"; + char program2[200]; + struct drawpix_state *drawpix = &ctx->Meta->DrawPix; + struct temp_texture *tex = get_temp_texture(ctx); + const char *texTarget; + + assert(drawpix->DepthFP == 0); + + /* replace %s with "RECT" or "2D" */ + assert(strlen(program) + 4 < sizeof(program2)); + if (tex->Target == GL_TEXTURE_RECTANGLE) + texTarget = "RECT"; + else + texTarget = "2D"; + _mesa_snprintf(program2, sizeof(program2), program, texTarget); + + _mesa_GenPrograms(1, &drawpix->DepthFP); + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, drawpix->DepthFP); + _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, + strlen(program2), (const GLubyte *) program2); +} + + +/** + * Meta implementation of ctx->Driver.DrawPixels() in terms + * of texture mapping and polygon rendering. + */ +void +_mesa_meta_DrawPixels(struct gl_context *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels) +{ + struct drawpix_state *drawpix = &ctx->Meta->DrawPix; + struct temp_texture *tex = get_temp_texture(ctx); + const struct gl_pixelstore_attrib unpackSave = ctx->Unpack; + const GLuint origStencilMask = ctx->Stencil.WriteMask[0]; + struct vertex { + GLfloat x, y, z, s, t; + }; + struct vertex verts[4]; + GLenum texIntFormat; + GLboolean fallback, newTex; + GLbitfield metaExtraSave = 0x0; + GLuint vbo; + + /* + * Determine if we can do the glDrawPixels with texture mapping. + */ + fallback = GL_FALSE; + if (ctx->_ImageTransferState || + ctx->Fog.Enabled) { + fallback = GL_TRUE; + } + + if (_mesa_is_color_format(format)) { + /* use more compact format when possible */ + /* XXX disable special case for GL_LUMINANCE for now to work around + * apparent i965 driver bug (see bug #23670). + */ + if (/*format == GL_LUMINANCE ||*/ format == GL_LUMINANCE_ALPHA) + texIntFormat = format; + else + texIntFormat = GL_RGBA; + } + else if (_mesa_is_stencil_format(format)) { + if (ctx->Extensions.ARB_fragment_program && + ctx->Pixel.IndexShift == 0 && + ctx->Pixel.IndexOffset == 0 && + type == GL_UNSIGNED_BYTE) { + /* We'll store stencil as alpha. This only works for GLubyte + * image data because of how incoming values are mapped to alpha + * in [0,1]. + */ + texIntFormat = GL_ALPHA; + metaExtraSave = (META_COLOR_MASK | + META_DEPTH_TEST | + META_SHADER | + META_STENCIL_TEST); + } + else { + fallback = GL_TRUE; + } + } + else if (_mesa_is_depth_format(format)) { + if (ctx->Extensions.ARB_depth_texture && + ctx->Extensions.ARB_fragment_program) { + texIntFormat = GL_DEPTH_COMPONENT; + metaExtraSave = (META_SHADER); + } + else { + fallback = GL_TRUE; + } + } + else { + fallback = GL_TRUE; + } + + if (fallback) { + _swrast_DrawPixels(ctx, x, y, width, height, + format, type, unpack, pixels); + return; + } + + /* + * Check image size against max texture size, draw as tiles if needed. + */ + if (width > tex->MaxSize || height > tex->MaxSize) { + tiled_draw_pixels(ctx, tex->MaxSize, x, y, width, height, + format, type, unpack, pixels); + return; + } + + /* Most GL state applies to glDrawPixels (like blending, stencil, etc), + * but a there's a few things we need to override: + */ + _mesa_meta_begin(ctx, (META_RASTERIZATION | + META_SHADER | + META_TEXTURE | + META_TRANSFORM | + META_VERTEX | + META_VIEWPORT | + metaExtraSave)); + + newTex = alloc_texture(tex, width, height, texIntFormat); + + /* vertex positions, texcoords (after texture allocation!) */ + { + const GLfloat x0 = (GLfloat) x; + const GLfloat y0 = (GLfloat) y; + const GLfloat x1 = x + width * ctx->Pixel.ZoomX; + const GLfloat y1 = y + height * ctx->Pixel.ZoomY; + const GLfloat z = invert_z(ctx->Current.RasterPos[2]); + + verts[0].x = x0; + verts[0].y = y0; + verts[0].z = z; + verts[0].s = 0.0F; + verts[0].t = 0.0F; + verts[1].x = x1; + verts[1].y = y0; + verts[1].z = z; + verts[1].s = tex->Sright; + verts[1].t = 0.0F; + verts[2].x = x1; + verts[2].y = y1; + verts[2].z = z; + verts[2].s = tex->Sright; + verts[2].t = tex->Ttop; + verts[3].x = x0; + verts[3].y = y1; + verts[3].z = z; + verts[3].s = 0.0F; + verts[3].t = tex->Ttop; + } + + if (drawpix->ArrayObj == 0) { + /* one-time setup: create vertex array object */ + _mesa_GenVertexArrays(1, &drawpix->ArrayObj); + } + _mesa_BindVertexArray(drawpix->ArrayObj); + + /* create vertex array buffer */ + _mesa_GenBuffersARB(1, &vbo); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, vbo); + _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), + verts, GL_DYNAMIC_DRAW_ARB); + + /* setup vertex arrays */ + _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); + _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); + _mesa_EnableClientState(GL_VERTEX_ARRAY); + _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); + + /* set given unpack params */ + ctx->Unpack = *unpack; + + _mesa_set_enable(ctx, tex->Target, GL_TRUE); + + if (_mesa_is_stencil_format(format)) { + /* Drawing stencil */ + GLint bit; + + if (!drawpix->StencilFP) + init_draw_stencil_pixels(ctx); + + setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, + GL_ALPHA, type, pixels); + + _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_TRUE); + + /* set all stencil bits to 0 */ + _mesa_StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + _mesa_StencilFunc(GL_ALWAYS, 0, 255); + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + + /* set stencil bits to 1 where needed */ + _mesa_StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, drawpix->StencilFP); + _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); + + for (bit = 0; bit < ctx->DrawBuffer->Visual.stencilBits; bit++) { + const GLuint mask = 1 << bit; + if (mask & origStencilMask) { + _mesa_StencilFunc(GL_ALWAYS, mask, mask); + _mesa_StencilMask(mask); + + _mesa_ProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, + 255.0 / mask, 0.5, 0.0, 0.0); + + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + } + } + else if (_mesa_is_depth_format(format)) { + /* Drawing depth */ + if (!drawpix->DepthFP) + init_draw_depth_pixels(ctx); + + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, drawpix->DepthFP); + _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); + + /* polygon color = current raster color */ + _mesa_ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, + ctx->Current.RasterColor); + + setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, + format, type, pixels); + + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + else { + /* Drawing RGBA */ + setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, + format, type, pixels); + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + + _mesa_set_enable(ctx, tex->Target, GL_FALSE); + + _mesa_DeleteBuffersARB(1, &vbo); + + /* restore unpack params */ + ctx->Unpack = unpackSave; + + _mesa_meta_end(ctx); +} + +static GLboolean +alpha_test_raster_color(struct gl_context *ctx) +{ + GLfloat alpha = ctx->Current.RasterColor[ACOMP]; + GLfloat ref = ctx->Color.AlphaRef; + + switch (ctx->Color.AlphaFunc) { + case GL_NEVER: + return GL_FALSE; + case GL_LESS: + return alpha < ref; + case GL_EQUAL: + return alpha == ref; + case GL_LEQUAL: + return alpha <= ref; + case GL_GREATER: + return alpha > ref; + case GL_NOTEQUAL: + return alpha != ref; + case GL_GEQUAL: + return alpha >= ref; + case GL_ALWAYS: + return GL_TRUE; + default: + assert(0); + return GL_FALSE; + } +} + +/** + * Do glBitmap with a alpha texture quad. Use the alpha test to cull + * the 'off' bits. A bitmap cache as in the gallium/mesa state + * tracker would improve performance a lot. + */ +void +_mesa_meta_Bitmap(struct gl_context *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap1) +{ + struct bitmap_state *bitmap = &ctx->Meta->Bitmap; + struct temp_texture *tex = get_bitmap_temp_texture(ctx); + const GLenum texIntFormat = GL_ALPHA; + const struct gl_pixelstore_attrib unpackSave = *unpack; + GLubyte fg, bg; + struct vertex { + GLfloat x, y, z, s, t, r, g, b, a; + }; + struct vertex verts[4]; + GLboolean newTex; + GLubyte *bitmap8; + + /* + * Check if swrast fallback is needed. + */ + if (ctx->_ImageTransferState || + ctx->FragmentProgram._Enabled || + ctx->Fog.Enabled || + ctx->Texture._EnabledUnits || + width > tex->MaxSize || + height > tex->MaxSize) { + _swrast_Bitmap(ctx, x, y, width, height, unpack, bitmap1); + return; + } + + if (ctx->Color.AlphaEnabled && !alpha_test_raster_color(ctx)) + return; + + /* Most GL state applies to glBitmap (like blending, stencil, etc), + * but a there's a few things we need to override: + */ + _mesa_meta_begin(ctx, (META_ALPHA_TEST | + META_PIXEL_STORE | + META_RASTERIZATION | + META_SHADER | + META_TEXTURE | + META_TRANSFORM | + META_VERTEX | + META_VIEWPORT)); + + if (bitmap->ArrayObj == 0) { + /* one-time setup */ + + /* create vertex array object */ + _mesa_GenVertexArraysAPPLE(1, &bitmap->ArrayObj); + _mesa_BindVertexArrayAPPLE(bitmap->ArrayObj); + + /* create vertex array buffer */ + _mesa_GenBuffersARB(1, &bitmap->VBO); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, bitmap->VBO); + _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), + NULL, GL_DYNAMIC_DRAW_ARB); + + /* setup vertex arrays */ + _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); + _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); + _mesa_ColorPointer(4, GL_FLOAT, sizeof(struct vertex), OFFSET(r)); + _mesa_EnableClientState(GL_VERTEX_ARRAY); + _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); + _mesa_EnableClientState(GL_COLOR_ARRAY); + } + else { + _mesa_BindVertexArray(bitmap->ArrayObj); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, bitmap->VBO); + } + + newTex = alloc_texture(tex, width, height, texIntFormat); + + /* vertex positions, texcoords, colors (after texture allocation!) */ + { + const GLfloat x0 = (GLfloat) x; + const GLfloat y0 = (GLfloat) y; + const GLfloat x1 = (GLfloat) (x + width); + const GLfloat y1 = (GLfloat) (y + height); + const GLfloat z = invert_z(ctx->Current.RasterPos[2]); + GLuint i; + + verts[0].x = x0; + verts[0].y = y0; + verts[0].z = z; + verts[0].s = 0.0F; + verts[0].t = 0.0F; + verts[1].x = x1; + verts[1].y = y0; + verts[1].z = z; + verts[1].s = tex->Sright; + verts[1].t = 0.0F; + verts[2].x = x1; + verts[2].y = y1; + verts[2].z = z; + verts[2].s = tex->Sright; + verts[2].t = tex->Ttop; + verts[3].x = x0; + verts[3].y = y1; + verts[3].z = z; + verts[3].s = 0.0F; + verts[3].t = tex->Ttop; + + for (i = 0; i < 4; i++) { + verts[i].r = ctx->Current.RasterColor[0]; + verts[i].g = ctx->Current.RasterColor[1]; + verts[i].b = ctx->Current.RasterColor[2]; + verts[i].a = ctx->Current.RasterColor[3]; + } + + /* upload new vertex data */ + _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); + } + + /* choose different foreground/background alpha values */ + CLAMPED_FLOAT_TO_UBYTE(fg, ctx->Current.RasterColor[ACOMP]); + bg = (fg > 127 ? 0 : 255); + + bitmap1 = _mesa_map_pbo_source(ctx, &unpackSave, bitmap1); + if (!bitmap1) { + _mesa_meta_end(ctx); + return; + } + + bitmap8 = (GLubyte *) malloc(width * height); + if (bitmap8) { + memset(bitmap8, bg, width * height); + _mesa_expand_bitmap(width, height, &unpackSave, bitmap1, + bitmap8, width, fg); + + _mesa_set_enable(ctx, tex->Target, GL_TRUE); + + _mesa_set_enable(ctx, GL_ALPHA_TEST, GL_TRUE); + _mesa_AlphaFunc(GL_NOTEQUAL, UBYTE_TO_FLOAT(bg)); + + setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, + GL_ALPHA, GL_UNSIGNED_BYTE, bitmap8); + + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + + _mesa_set_enable(ctx, tex->Target, GL_FALSE); + + free(bitmap8); + } + + _mesa_unmap_pbo_source(ctx, &unpackSave); + + _mesa_meta_end(ctx); +} + + +/** + * Check if the call to _mesa_meta_GenerateMipmap() will require a + * software fallback. The fallback path will require that the texture + * images are mapped. + * \return GL_TRUE if a fallback is needed, GL_FALSE otherwise + */ +GLboolean +_mesa_meta_check_generate_mipmap_fallback(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj) +{ + const GLuint fboSave = ctx->DrawBuffer->Name; + struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap; + struct gl_texture_image *baseImage; + GLuint srcLevel; + GLenum status; + + /* check for fallbacks */ + if (!ctx->Extensions.EXT_framebuffer_object || + target == GL_TEXTURE_3D) { + return GL_TRUE; + } + + srcLevel = texObj->BaseLevel; + baseImage = _mesa_select_tex_image(ctx, texObj, target, srcLevel); + if (!baseImage || _mesa_is_format_compressed(baseImage->TexFormat)) { + return GL_TRUE; + } + + /* + * Test that we can actually render in the texture's format. + */ + if (!mipmap->FBO) + _mesa_GenFramebuffersEXT(1, &mipmap->FBO); + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mipmap->FBO); + + if (target == GL_TEXTURE_1D) { + _mesa_FramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + target, texObj->Name, srcLevel); + } +#if 0 + /* other work is needed to enable 3D mipmap generation */ + else if (target == GL_TEXTURE_3D) { + GLint zoffset = 0; + _mesa_FramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + target, texObj->Name, srcLevel, zoffset); + } +#endif + else { + /* 2D / cube */ + _mesa_FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + target, texObj->Name, srcLevel); + } + + status = _mesa_CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboSave); + + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + return GL_TRUE; + } + + return GL_FALSE; +} + + +/** + * Called via ctx->Driver.GenerateMipmap() + * Note: texture borders and 3D texture support not yet complete. + */ +void +_mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj) +{ + struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap; + struct vertex { + GLfloat x, y, s, t, r; + }; + struct vertex verts[4]; + const GLuint baseLevel = texObj->BaseLevel; + const GLuint maxLevel = texObj->MaxLevel; + const GLenum minFilterSave = texObj->MinFilter; + const GLenum magFilterSave = texObj->MagFilter; + const GLint maxLevelSave = texObj->MaxLevel; + const GLboolean genMipmapSave = texObj->GenerateMipmap; + const GLenum wrapSSave = texObj->WrapS; + const GLenum wrapTSave = texObj->WrapT; + const GLenum wrapRSave = texObj->WrapR; + const GLuint fboSave = ctx->DrawBuffer->Name; + const GLuint original_active_unit = ctx->Texture.CurrentUnit; + GLenum faceTarget; + GLuint dstLevel; + GLuint border = 0; + + if (_mesa_meta_check_generate_mipmap_fallback(ctx, target, texObj)) { + _mesa_generate_mipmap(ctx, target, texObj); + return; + } + + if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) { + faceTarget = target; + target = GL_TEXTURE_CUBE_MAP; + } + else { + faceTarget = target; + } + + _mesa_meta_begin(ctx, META_ALL); + + if (original_active_unit != 0) + _mesa_BindTexture(target, texObj->Name); + + if (mipmap->ArrayObj == 0) { + /* one-time setup */ + + /* create vertex array object */ + _mesa_GenVertexArraysAPPLE(1, &mipmap->ArrayObj); + _mesa_BindVertexArrayAPPLE(mipmap->ArrayObj); + + /* create vertex array buffer */ + _mesa_GenBuffersARB(1, &mipmap->VBO); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, mipmap->VBO); + _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), + NULL, GL_DYNAMIC_DRAW_ARB); + + /* setup vertex arrays */ + _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); + _mesa_TexCoordPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); + _mesa_EnableClientState(GL_VERTEX_ARRAY); + _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); + } + else { + _mesa_BindVertexArray(mipmap->ArrayObj); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, mipmap->VBO); + } + + if (!mipmap->FBO) { + _mesa_GenFramebuffersEXT(1, &mipmap->FBO); + } + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mipmap->FBO); + + _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE); + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + _mesa_set_enable(ctx, target, GL_TRUE); + + /* setup texcoords once (XXX what about border?) */ + switch (faceTarget) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + verts[0].s = 0.0F; + verts[0].t = 0.0F; + verts[0].r = 0.0F; + verts[1].s = 1.0F; + verts[1].t = 0.0F; + verts[1].r = 0.0F; + verts[2].s = 1.0F; + verts[2].t = 1.0F; + verts[2].r = 0.0F; + verts[3].s = 0.0F; + verts[3].t = 1.0F; + verts[3].r = 0.0F; + break; + case GL_TEXTURE_3D: + abort(); + break; + default: + /* cube face */ + { + static const GLfloat st[4][2] = { + {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f} + }; + GLuint i; + + /* loop over quad verts */ + for (i = 0; i < 4; i++) { + /* Compute sc = +/-scale and tc = +/-scale. + * Not +/-1 to avoid cube face selection ambiguity near the edges, + * though that can still sometimes happen with this scale factor... + */ + const GLfloat scale = 0.9999f; + const GLfloat sc = (2.0f * st[i][0] - 1.0f) * scale; + const GLfloat tc = (2.0f * st[i][1] - 1.0f) * scale; + + switch (faceTarget) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + verts[i].s = 1.0f; + verts[i].t = -tc; + verts[i].r = -sc; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + verts[i].s = -1.0f; + verts[i].t = -tc; + verts[i].r = sc; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + verts[i].s = sc; + verts[i].t = 1.0f; + verts[i].r = tc; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + verts[i].s = sc; + verts[i].t = -1.0f; + verts[i].r = -tc; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + verts[i].s = sc; + verts[i].t = -tc; + verts[i].r = 1.0f; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + verts[i].s = -sc; + verts[i].t = -tc; + verts[i].r = -1.0f; + break; + default: + assert(0); + } + } + } + } + + _mesa_set_enable(ctx, target, GL_TRUE); + + /* setup vertex positions */ + { + verts[0].x = 0.0F; + verts[0].y = 0.0F; + verts[1].x = 1.0F; + verts[1].y = 0.0F; + verts[2].x = 1.0F; + verts[2].y = 1.0F; + verts[3].x = 0.0F; + verts[3].y = 1.0F; + + /* upload new vertex data */ + _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); + } + + /* setup projection matrix */ + _mesa_MatrixMode(GL_PROJECTION); + _mesa_LoadIdentity(); + _mesa_Ortho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); + + /* texture is already locked, unlock now */ + _mesa_unlock_texture(ctx, texObj); + + for (dstLevel = baseLevel + 1; dstLevel <= maxLevel; dstLevel++) { + const struct gl_texture_image *srcImage; + const GLuint srcLevel = dstLevel - 1; + GLsizei srcWidth, srcHeight, srcDepth; + GLsizei dstWidth, dstHeight, dstDepth; + GLenum status; + + srcImage = _mesa_select_tex_image(ctx, texObj, faceTarget, srcLevel); + assert(srcImage->Border == 0); /* XXX we can fix this */ + + /* src size w/out border */ + srcWidth = srcImage->Width - 2 * border; + srcHeight = srcImage->Height - 2 * border; + srcDepth = srcImage->Depth - 2 * border; + + /* new dst size w/ border */ + dstWidth = MAX2(1, srcWidth / 2) + 2 * border; + dstHeight = MAX2(1, srcHeight / 2) + 2 * border; + dstDepth = MAX2(1, srcDepth / 2) + 2 * border; + + if (dstWidth == srcImage->Width && + dstHeight == srcImage->Height && + dstDepth == srcImage->Depth) { + /* all done */ + break; + } + + /* Set MaxLevel large enough to hold the new level when we allocate it */ + _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, dstLevel); + + /* Create empty dest image */ + if (target == GL_TEXTURE_1D) { + _mesa_TexImage1D(target, dstLevel, srcImage->InternalFormat, + dstWidth, border, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + else if (target == GL_TEXTURE_3D) { + _mesa_TexImage3D(target, dstLevel, srcImage->InternalFormat, + dstWidth, dstHeight, dstDepth, border, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + else { + /* 2D or cube */ + _mesa_TexImage2D(faceTarget, dstLevel, srcImage->InternalFormat, + dstWidth, dstHeight, border, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + if (target == GL_TEXTURE_CUBE_MAP) { + /* If texturing from a cube, we need to make sure all src faces + * have been defined (even if we're not sampling from them.) + * Otherwise the texture object will be 'incomplete' and + * texturing from it will not be allowed. + */ + GLuint face; + for (face = 0; face < 6; face++) { + if (!texObj->Image[face][srcLevel] || + texObj->Image[face][srcLevel]->Width != srcWidth) { + _mesa_TexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, + srcLevel, srcImage->InternalFormat, + srcWidth, srcHeight, border, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + } + } + } + + /* limit minification to src level */ + _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel); + + /* Set to draw into the current dstLevel */ + if (target == GL_TEXTURE_1D) { + _mesa_FramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + target, + texObj->Name, + dstLevel); + } + else if (target == GL_TEXTURE_3D) { + GLint zoffset = 0; /* XXX unfinished */ + _mesa_FramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + target, + texObj->Name, + dstLevel, zoffset); + } + else { + /* 2D / cube */ + _mesa_FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + faceTarget, + texObj->Name, + dstLevel); + } + + _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + + /* sanity check */ + status = _mesa_CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + abort(); + break; + } + + assert(dstWidth == ctx->DrawBuffer->Width); + assert(dstHeight == ctx->DrawBuffer->Height); + + /* setup viewport */ + _mesa_set_viewport(ctx, 0, 0, dstWidth, dstHeight); + + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + + _mesa_lock_texture(ctx, texObj); /* relock */ + + _mesa_meta_end(ctx); + + _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilterSave); + _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilterSave); + _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); + _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave); + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, wrapSSave); + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, wrapTSave); + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_R, wrapRSave); + + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboSave); +} + + +/** + * Determine the GL data type to use for the temporary image read with + * ReadPixels() and passed to Tex[Sub]Image(). + */ +static GLenum +get_temp_image_type(struct gl_context *ctx, GLenum baseFormat) +{ + switch (baseFormat) { + case GL_RGBA: + case GL_RGB: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + if (ctx->DrawBuffer->Visual.redBits <= 8) + return GL_UNSIGNED_BYTE; + else if (ctx->DrawBuffer->Visual.redBits <= 8) + return GL_UNSIGNED_SHORT; + else + return GL_FLOAT; + case GL_DEPTH_COMPONENT: + return GL_UNSIGNED_INT; + case GL_DEPTH_STENCIL: + return GL_UNSIGNED_INT_24_8; + default: + _mesa_problem(ctx, "Unexpected format in get_temp_image_type()"); + return 0; + } +} + + +/** + * Helper for _mesa_meta_CopyTexImage1/2D() functions. + * Have to be careful with locking and meta state for pixel transfer. + */ +static void +copy_tex_image(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, + GLenum internalFormat, GLint x, GLint y, + GLsizei width, GLsizei height, GLint border) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GLenum format, type; + GLint bpp; + void *buf; + + texObj = _mesa_get_current_tex_object(ctx, target); + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + + /* Choose format/type for temporary image buffer */ + format = _mesa_base_tex_format(ctx, internalFormat); + type = get_temp_image_type(ctx, format); + bpp = _mesa_bytes_per_pixel(format, type); + if (bpp <= 0) { + _mesa_problem(ctx, "Bad bpp in meta copy_tex_image()"); + return; + } + + /* + * Alloc image buffer (XXX could use a PBO) + */ + buf = malloc(width * height * bpp); + if (!buf) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims); + return; + } + + _mesa_unlock_texture(ctx, texObj); /* need to unlock first */ + + /* + * Read image from framebuffer (disable pixel transfer ops) + */ + _mesa_meta_begin(ctx, META_PIXEL_STORE | META_PIXEL_TRANSFER); + ctx->Driver.ReadPixels(ctx, x, y, width, height, + format, type, &ctx->Pack, buf); + _mesa_meta_end(ctx); + + if (texImage->Data) { + ctx->Driver.FreeTexImageData(ctx, texImage); + } + + /* The texture's format was already chosen in _mesa_CopyTexImage() */ + ASSERT(texImage->TexFormat != MESA_FORMAT_NONE); + + /* + * Store texture data (with pixel transfer ops) + */ + _mesa_meta_begin(ctx, META_PIXEL_STORE); + + _mesa_update_state(ctx); /* to update pixel transfer state */ + + if (target == GL_TEXTURE_1D) { + ctx->Driver.TexImage1D(ctx, target, level, internalFormat, + width, border, format, type, + buf, &ctx->Unpack, texObj, texImage); + } + else { + ctx->Driver.TexImage2D(ctx, target, level, internalFormat, + width, height, border, format, type, + buf, &ctx->Unpack, texObj, texImage); + } + _mesa_meta_end(ctx); + + _mesa_lock_texture(ctx, texObj); /* re-lock */ + + free(buf); +} + + +void +_mesa_meta_CopyTexImage1D(struct gl_context *ctx, GLenum target, GLint level, + GLenum internalFormat, GLint x, GLint y, + GLsizei width, GLint border) +{ + copy_tex_image(ctx, 1, target, level, internalFormat, x, y, + width, 1, border); +} + + +void +_mesa_meta_CopyTexImage2D(struct gl_context *ctx, GLenum target, GLint level, + GLenum internalFormat, GLint x, GLint y, + GLsizei width, GLsizei height, GLint border) +{ + copy_tex_image(ctx, 2, target, level, internalFormat, x, y, + width, height, border); +} + + + +/** + * Helper for _mesa_meta_CopyTexSubImage1/2/3D() functions. + * Have to be careful with locking and meta state for pixel transfer. + */ +static void +copy_tex_sub_image(struct gl_context *ctx, + GLuint dims, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, + GLsizei width, GLsizei height) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GLenum format, type; + GLint bpp; + void *buf; + + texObj = _mesa_get_current_tex_object(ctx, target); + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + /* Choose format/type for temporary image buffer */ + format = _mesa_get_format_base_format(texImage->TexFormat); + type = get_temp_image_type(ctx, format); + bpp = _mesa_bytes_per_pixel(format, type); + if (bpp <= 0) { + _mesa_problem(ctx, "Bad bpp in meta copy_tex_sub_image()"); + return; + } + + /* + * Alloc image buffer (XXX could use a PBO) + */ + buf = malloc(width * height * bpp); + if (!buf) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage%uD", dims); + return; + } + + _mesa_unlock_texture(ctx, texObj); /* need to unlock first */ + + /* + * Read image from framebuffer (disable pixel transfer ops) + */ + _mesa_meta_begin(ctx, META_PIXEL_STORE | META_PIXEL_TRANSFER); + ctx->Driver.ReadPixels(ctx, x, y, width, height, + format, type, &ctx->Pack, buf); + _mesa_meta_end(ctx); + + _mesa_update_state(ctx); /* to update pixel transfer state */ + + /* + * Store texture data (with pixel transfer ops) + */ + _mesa_meta_begin(ctx, META_PIXEL_STORE); + if (target == GL_TEXTURE_1D) { + ctx->Driver.TexSubImage1D(ctx, target, level, xoffset, + width, format, type, buf, + &ctx->Unpack, texObj, texImage); + } + else if (target == GL_TEXTURE_3D) { + ctx->Driver.TexSubImage3D(ctx, target, level, xoffset, yoffset, zoffset, + width, height, 1, format, type, buf, + &ctx->Unpack, texObj, texImage); + } + else { + ctx->Driver.TexSubImage2D(ctx, target, level, xoffset, yoffset, + width, height, format, type, buf, + &ctx->Unpack, texObj, texImage); + } + _mesa_meta_end(ctx); + + _mesa_lock_texture(ctx, texObj); /* re-lock */ + + free(buf); +} + + +void +_mesa_meta_CopyTexSubImage1D(struct gl_context *ctx, GLenum target, GLint level, + GLint xoffset, + GLint x, GLint y, GLsizei width) +{ + copy_tex_sub_image(ctx, 1, target, level, xoffset, 0, 0, + x, y, width, 1); +} + + +void +_mesa_meta_CopyTexSubImage2D(struct gl_context *ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLint x, GLint y, + GLsizei width, GLsizei height) +{ + copy_tex_sub_image(ctx, 2, target, level, xoffset, yoffset, 0, + x, y, width, height); +} + + +void +_mesa_meta_CopyTexSubImage3D(struct gl_context *ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, + GLsizei width, GLsizei height) +{ + copy_tex_sub_image(ctx, 3, target, level, xoffset, yoffset, zoffset, + x, y, width, height); +} + + +void +_mesa_meta_CopyColorTable(struct gl_context *ctx, + GLenum target, GLenum internalformat, + GLint x, GLint y, GLsizei width) +{ + GLfloat *buf; + + buf = (GLfloat *) malloc(width * 4 * sizeof(GLfloat)); + if (!buf) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyColorTable"); + return; + } + + /* + * Read image from framebuffer (disable pixel transfer ops) + */ + _mesa_meta_begin(ctx, META_PIXEL_STORE | META_PIXEL_TRANSFER); + ctx->Driver.ReadPixels(ctx, x, y, width, 1, + GL_RGBA, GL_FLOAT, &ctx->Pack, buf); + + _mesa_ColorTable(target, internalformat, width, GL_RGBA, GL_FLOAT, buf); + + _mesa_meta_end(ctx); + + free(buf); +} + + +void +_mesa_meta_CopyColorSubTable(struct gl_context *ctx,GLenum target, GLsizei start, + GLint x, GLint y, GLsizei width) +{ + GLfloat *buf; + + buf = (GLfloat *) malloc(width * 4 * sizeof(GLfloat)); + if (!buf) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyColorSubTable"); + return; + } + + /* + * Read image from framebuffer (disable pixel transfer ops) + */ + _mesa_meta_begin(ctx, META_PIXEL_STORE | META_PIXEL_TRANSFER); + ctx->Driver.ReadPixels(ctx, x, y, width, 1, + GL_RGBA, GL_FLOAT, &ctx->Pack, buf); + + _mesa_ColorSubTable(target, start, width, GL_RGBA, GL_FLOAT, buf); + + _mesa_meta_end(ctx); + + free(buf); +} diff --git a/mesalib/src/mesa/main/attrib.c b/mesalib/src/mesa/main/attrib.c index f97ec08e5..ae7f633b8 100644 --- a/mesalib/src/mesa/main/attrib.c +++ b/mesalib/src/mesa/main/attrib.c @@ -1,1566 +1,1555 @@ -/* - * Mesa 3-D graphics library - * Version: 7.6 - * - * 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. - */ - -#include "glheader.h" -#include "imports.h" -#include "accum.h" -#include "arrayobj.h" -#include "attrib.h" -#include "blend.h" -#include "buffers.h" -#include "bufferobj.h" -#include "clear.h" -#include "colormac.h" -#include "context.h" -#include "depth.h" -#include "enable.h" -#include "enums.h" -#include "fog.h" -#include "hint.h" -#include "light.h" -#include "lines.h" -#include "macros.h" -#include "matrix.h" -#include "mfeatures.h" -#include "multisample.h" -#include "points.h" -#include "polygon.h" -#include "scissor.h" -#include "stencil.h" -#include "texenv.h" -#include "texgen.h" -#include "texobj.h" -#include "texparam.h" -#include "texstate.h" -#include "varray.h" -#include "viewport.h" -#include "mtypes.h" -#include "main/dispatch.h" - - -/** - * glEnable()/glDisable() attribute group (GL_ENABLE_BIT). - */ -struct gl_enable_attrib -{ - GLboolean AlphaTest; - GLboolean AutoNormal; - GLboolean Blend; - GLbitfield ClipPlanes; - GLboolean ColorMaterial; - GLboolean CullFace; - GLboolean DepthClamp; - GLboolean DepthTest; - GLboolean Dither; - GLboolean Fog; - GLboolean Light[MAX_LIGHTS]; - GLboolean Lighting; - GLboolean LineSmooth; - GLboolean LineStipple; - GLboolean IndexLogicOp; - GLboolean ColorLogicOp; - - GLboolean Map1Color4; - GLboolean Map1Index; - GLboolean Map1Normal; - GLboolean Map1TextureCoord1; - GLboolean Map1TextureCoord2; - GLboolean Map1TextureCoord3; - GLboolean Map1TextureCoord4; - GLboolean Map1Vertex3; - GLboolean Map1Vertex4; - GLboolean Map1Attrib[16]; /* GL_NV_vertex_program */ - GLboolean Map2Color4; - GLboolean Map2Index; - GLboolean Map2Normal; - GLboolean Map2TextureCoord1; - GLboolean Map2TextureCoord2; - GLboolean Map2TextureCoord3; - GLboolean Map2TextureCoord4; - GLboolean Map2Vertex3; - GLboolean Map2Vertex4; - GLboolean Map2Attrib[16]; /* GL_NV_vertex_program */ - - GLboolean Normalize; - GLboolean PixelTexture; - GLboolean PointSmooth; - GLboolean PolygonOffsetPoint; - GLboolean PolygonOffsetLine; - GLboolean PolygonOffsetFill; - GLboolean PolygonSmooth; - GLboolean PolygonStipple; - GLboolean RescaleNormals; - GLboolean Scissor; - GLboolean Stencil; - GLboolean StencilTwoSide; /* GL_EXT_stencil_two_side */ - GLboolean MultisampleEnabled; /* GL_ARB_multisample */ - GLboolean SampleAlphaToCoverage; /* GL_ARB_multisample */ - GLboolean SampleAlphaToOne; /* GL_ARB_multisample */ - GLboolean SampleCoverage; /* GL_ARB_multisample */ - GLboolean SampleCoverageInvert; /* GL_ARB_multisample */ - GLboolean RasterPositionUnclipped; /* GL_IBM_rasterpos_clip */ - - GLbitfield Texture[MAX_TEXTURE_UNITS]; - GLbitfield TexGen[MAX_TEXTURE_UNITS]; - - /* SGI_texture_color_table */ - GLboolean TextureColorTable[MAX_TEXTURE_UNITS]; - - /* GL_ARB_vertex_program / GL_NV_vertex_program */ - GLboolean VertexProgram; - GLboolean VertexProgramPointSize; - GLboolean VertexProgramTwoSide; - - /* GL_ARB_point_sprite / GL_NV_point_sprite */ - GLboolean PointSprite; - GLboolean FragmentShaderATI; -}; - - -/** - * Node for the attribute stack. - */ -struct gl_attrib_node -{ - GLbitfield kind; - void *data; - struct gl_attrib_node *next; -}; - - - -/** - * Special struct for saving/restoring texture state (GL_TEXTURE_BIT) - */ -struct texture_state -{ - struct gl_texture_attrib Texture; /**< The usual context state */ - - /** to save per texture object state (wrap modes, filters, etc): */ - struct gl_texture_object SavedObj[MAX_TEXTURE_UNITS][NUM_TEXTURE_TARGETS]; - - /** - * To save references to texture objects (so they don't get accidentally - * deleted while saved in the attribute stack). - */ - struct gl_texture_object *SavedTexRef[MAX_TEXTURE_UNITS][NUM_TEXTURE_TARGETS]; -}; - - -#if FEATURE_attrib_stack - - -/** - * Allocate new attribute node of given type/kind. Attach payload data. - * Insert it into the linked list named by 'head'. - */ -static void -save_attrib_data(struct gl_attrib_node **head, - GLbitfield kind, void *payload) -{ - struct gl_attrib_node *n = MALLOC_STRUCT(gl_attrib_node); - if (n) { - n->kind = kind; - n->data = payload; - /* insert at head */ - n->next = *head; - *head = n; - } - else { - /* out of memory! */ - } -} - - -void GLAPIENTRY -_mesa_PushAttrib(GLbitfield mask) -{ - struct gl_attrib_node *head; - - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glPushAttrib %x\n", (int) mask); - - if (ctx->AttribStackDepth >= MAX_ATTRIB_STACK_DEPTH) { - _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushAttrib" ); - return; - } - - /* Build linked list of attribute nodes which save all attribute */ - /* groups specified by the mask. */ - head = NULL; - - if (mask & GL_ACCUM_BUFFER_BIT) { - struct gl_accum_attrib *attr; - attr = MALLOC_STRUCT( gl_accum_attrib ); - memcpy( attr, &ctx->Accum, sizeof(struct gl_accum_attrib) ); - save_attrib_data(&head, GL_ACCUM_BUFFER_BIT, attr); - } - - if (mask & GL_COLOR_BUFFER_BIT) { - GLuint i; - struct gl_colorbuffer_attrib *attr; - attr = MALLOC_STRUCT( gl_colorbuffer_attrib ); - memcpy( attr, &ctx->Color, sizeof(struct gl_colorbuffer_attrib) ); - /* push the Draw FBO's DrawBuffer[] state, not ctx->Color.DrawBuffer[] */ - for (i = 0; i < ctx->Const.MaxDrawBuffers; i ++) - attr->DrawBuffer[i] = ctx->DrawBuffer->ColorDrawBuffer[i]; - save_attrib_data(&head, GL_COLOR_BUFFER_BIT, attr); - } - - if (mask & GL_CURRENT_BIT) { - struct gl_current_attrib *attr; - FLUSH_CURRENT( ctx, 0 ); - attr = MALLOC_STRUCT( gl_current_attrib ); - memcpy( attr, &ctx->Current, sizeof(struct gl_current_attrib) ); - save_attrib_data(&head, GL_CURRENT_BIT, attr); - } - - if (mask & GL_DEPTH_BUFFER_BIT) { - struct gl_depthbuffer_attrib *attr; - attr = MALLOC_STRUCT( gl_depthbuffer_attrib ); - memcpy( attr, &ctx->Depth, sizeof(struct gl_depthbuffer_attrib) ); - save_attrib_data(&head, GL_DEPTH_BUFFER_BIT, attr); - } - - if (mask & GL_ENABLE_BIT) { - struct gl_enable_attrib *attr; - GLuint i; - attr = MALLOC_STRUCT( gl_enable_attrib ); - /* Copy enable flags from all other attributes into the enable struct. */ - attr->AlphaTest = ctx->Color.AlphaEnabled; - attr->AutoNormal = ctx->Eval.AutoNormal; - attr->Blend = ctx->Color.BlendEnabled; - attr->ClipPlanes = ctx->Transform.ClipPlanesEnabled; - attr->ColorMaterial = ctx->Light.ColorMaterialEnabled; - attr->CullFace = ctx->Polygon.CullFlag; - attr->DepthClamp = ctx->Transform.DepthClamp; - attr->DepthTest = ctx->Depth.Test; - attr->Dither = ctx->Color.DitherFlag; - attr->Fog = ctx->Fog.Enabled; - for (i = 0; i < ctx->Const.MaxLights; i++) { - attr->Light[i] = ctx->Light.Light[i].Enabled; - } - attr->Lighting = ctx->Light.Enabled; - attr->LineSmooth = ctx->Line.SmoothFlag; - attr->LineStipple = ctx->Line.StippleFlag; - attr->IndexLogicOp = ctx->Color.IndexLogicOpEnabled; - attr->ColorLogicOp = ctx->Color.ColorLogicOpEnabled; - attr->Map1Color4 = ctx->Eval.Map1Color4; - attr->Map1Index = ctx->Eval.Map1Index; - attr->Map1Normal = ctx->Eval.Map1Normal; - attr->Map1TextureCoord1 = ctx->Eval.Map1TextureCoord1; - attr->Map1TextureCoord2 = ctx->Eval.Map1TextureCoord2; - attr->Map1TextureCoord3 = ctx->Eval.Map1TextureCoord3; - attr->Map1TextureCoord4 = ctx->Eval.Map1TextureCoord4; - attr->Map1Vertex3 = ctx->Eval.Map1Vertex3; - attr->Map1Vertex4 = ctx->Eval.Map1Vertex4; - memcpy(attr->Map1Attrib, ctx->Eval.Map1Attrib, sizeof(ctx->Eval.Map1Attrib)); - attr->Map2Color4 = ctx->Eval.Map2Color4; - attr->Map2Index = ctx->Eval.Map2Index; - attr->Map2Normal = ctx->Eval.Map2Normal; - attr->Map2TextureCoord1 = ctx->Eval.Map2TextureCoord1; - attr->Map2TextureCoord2 = ctx->Eval.Map2TextureCoord2; - attr->Map2TextureCoord3 = ctx->Eval.Map2TextureCoord3; - attr->Map2TextureCoord4 = ctx->Eval.Map2TextureCoord4; - attr->Map2Vertex3 = ctx->Eval.Map2Vertex3; - attr->Map2Vertex4 = ctx->Eval.Map2Vertex4; - memcpy(attr->Map2Attrib, ctx->Eval.Map2Attrib, sizeof(ctx->Eval.Map2Attrib)); - attr->Normalize = ctx->Transform.Normalize; - attr->RasterPositionUnclipped = ctx->Transform.RasterPositionUnclipped; - attr->PointSmooth = ctx->Point.SmoothFlag; - attr->PointSprite = ctx->Point.PointSprite; - attr->PolygonOffsetPoint = ctx->Polygon.OffsetPoint; - attr->PolygonOffsetLine = ctx->Polygon.OffsetLine; - attr->PolygonOffsetFill = ctx->Polygon.OffsetFill; - attr->PolygonSmooth = ctx->Polygon.SmoothFlag; - attr->PolygonStipple = ctx->Polygon.StippleFlag; - attr->RescaleNormals = ctx->Transform.RescaleNormals; - attr->Scissor = ctx->Scissor.Enabled; - attr->Stencil = ctx->Stencil.Enabled; - attr->StencilTwoSide = ctx->Stencil.TestTwoSide; - attr->MultisampleEnabled = ctx->Multisample.Enabled; - attr->SampleAlphaToCoverage = ctx->Multisample.SampleAlphaToCoverage; - attr->SampleAlphaToOne = ctx->Multisample.SampleAlphaToOne; - attr->SampleCoverage = ctx->Multisample.SampleCoverage; - attr->SampleCoverageInvert = ctx->Multisample.SampleCoverageInvert; - for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { - attr->Texture[i] = ctx->Texture.Unit[i].Enabled; - attr->TexGen[i] = ctx->Texture.Unit[i].TexGenEnabled; - attr->TextureColorTable[i] = ctx->Texture.Unit[i].ColorTableEnabled; - } - /* GL_NV_vertex_program */ - attr->VertexProgram = ctx->VertexProgram.Enabled; - attr->VertexProgramPointSize = ctx->VertexProgram.PointSizeEnabled; - attr->VertexProgramTwoSide = ctx->VertexProgram.TwoSideEnabled; - save_attrib_data(&head, GL_ENABLE_BIT, attr); - } - - if (mask & GL_EVAL_BIT) { - struct gl_eval_attrib *attr; - attr = MALLOC_STRUCT( gl_eval_attrib ); - memcpy( attr, &ctx->Eval, sizeof(struct gl_eval_attrib) ); - save_attrib_data(&head, GL_EVAL_BIT, attr); - } - - if (mask & GL_FOG_BIT) { - struct gl_fog_attrib *attr; - attr = MALLOC_STRUCT( gl_fog_attrib ); - memcpy( attr, &ctx->Fog, sizeof(struct gl_fog_attrib) ); - save_attrib_data(&head, GL_FOG_BIT, attr); - } - - if (mask & GL_HINT_BIT) { - struct gl_hint_attrib *attr; - attr = MALLOC_STRUCT( gl_hint_attrib ); - memcpy( attr, &ctx->Hint, sizeof(struct gl_hint_attrib) ); - save_attrib_data(&head, GL_HINT_BIT, attr); - } - - if (mask & GL_LIGHTING_BIT) { - struct gl_light_attrib *attr; - FLUSH_CURRENT(ctx, 0); /* flush material changes */ - attr = MALLOC_STRUCT( gl_light_attrib ); - memcpy( attr, &ctx->Light, sizeof(struct gl_light_attrib) ); - save_attrib_data(&head, GL_LIGHTING_BIT, attr); - } - - if (mask & GL_LINE_BIT) { - struct gl_line_attrib *attr; - attr = MALLOC_STRUCT( gl_line_attrib ); - memcpy( attr, &ctx->Line, sizeof(struct gl_line_attrib) ); - save_attrib_data(&head, GL_LINE_BIT, attr); - } - - if (mask & GL_LIST_BIT) { - struct gl_list_attrib *attr; - attr = MALLOC_STRUCT( gl_list_attrib ); - memcpy( attr, &ctx->List, sizeof(struct gl_list_attrib) ); - save_attrib_data(&head, GL_LIST_BIT, attr); - } - - if (mask & GL_PIXEL_MODE_BIT) { - struct gl_pixel_attrib *attr; - attr = MALLOC_STRUCT( gl_pixel_attrib ); - memcpy( attr, &ctx->Pixel, sizeof(struct gl_pixel_attrib) ); - /* push the Read FBO's ReadBuffer state, not ctx->Pixel.ReadBuffer */ - attr->ReadBuffer = ctx->ReadBuffer->ColorReadBuffer; - save_attrib_data(&head, GL_PIXEL_MODE_BIT, attr); - } - - if (mask & GL_POINT_BIT) { - struct gl_point_attrib *attr; - attr = MALLOC_STRUCT( gl_point_attrib ); - memcpy( attr, &ctx->Point, sizeof(struct gl_point_attrib) ); - save_attrib_data(&head, GL_POINT_BIT, attr); - } - - if (mask & GL_POLYGON_BIT) { - struct gl_polygon_attrib *attr; - attr = MALLOC_STRUCT( gl_polygon_attrib ); - memcpy( attr, &ctx->Polygon, sizeof(struct gl_polygon_attrib) ); - save_attrib_data(&head, GL_POLYGON_BIT, attr); - } - - if (mask & GL_POLYGON_STIPPLE_BIT) { - GLuint *stipple; - stipple = (GLuint *) MALLOC( 32*sizeof(GLuint) ); - memcpy( stipple, ctx->PolygonStipple, 32*sizeof(GLuint) ); - save_attrib_data(&head, GL_POLYGON_STIPPLE_BIT, stipple); - } - - if (mask & GL_SCISSOR_BIT) { - struct gl_scissor_attrib *attr; - attr = MALLOC_STRUCT( gl_scissor_attrib ); - memcpy( attr, &ctx->Scissor, sizeof(struct gl_scissor_attrib) ); - save_attrib_data(&head, GL_SCISSOR_BIT, attr); - } - - if (mask & GL_STENCIL_BUFFER_BIT) { - struct gl_stencil_attrib *attr; - attr = MALLOC_STRUCT( gl_stencil_attrib ); - memcpy( attr, &ctx->Stencil, sizeof(struct gl_stencil_attrib) ); - save_attrib_data(&head, GL_STENCIL_BUFFER_BIT, attr); - } - - if (mask & GL_TEXTURE_BIT) { - struct texture_state *texstate = CALLOC_STRUCT(texture_state); - GLuint u, tex; - - if (!texstate) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glPushAttrib(GL_TEXTURE_BIT)"); - goto end; - } - - _mesa_lock_context_textures(ctx); - - /* copy/save the bulk of texture state here */ - memcpy(&texstate->Texture, &ctx->Texture, sizeof(ctx->Texture)); - - /* Save references to the currently bound texture objects so they don't - * accidentally get deleted while referenced in the attribute stack. - */ - for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { - for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { - _mesa_reference_texobj(&texstate->SavedTexRef[u][tex], - ctx->Texture.Unit[u].CurrentTex[tex]); - } - } - - /* copy state/contents of the currently bound texture objects */ - for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { - for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { - _mesa_copy_texture_object(&texstate->SavedObj[u][tex], - ctx->Texture.Unit[u].CurrentTex[tex]); - } - } - - _mesa_unlock_context_textures(ctx); - - save_attrib_data(&head, GL_TEXTURE_BIT, texstate); - } - - if (mask & GL_TRANSFORM_BIT) { - struct gl_transform_attrib *attr; - attr = MALLOC_STRUCT( gl_transform_attrib ); - memcpy( attr, &ctx->Transform, sizeof(struct gl_transform_attrib) ); - save_attrib_data(&head, GL_TRANSFORM_BIT, attr); - } - - if (mask & GL_VIEWPORT_BIT) { - struct gl_viewport_attrib *attr; - attr = MALLOC_STRUCT( gl_viewport_attrib ); - memcpy( attr, &ctx->Viewport, sizeof(struct gl_viewport_attrib) ); - save_attrib_data(&head, GL_VIEWPORT_BIT, attr); - } - - /* GL_ARB_multisample */ - if (mask & GL_MULTISAMPLE_BIT_ARB) { - struct gl_multisample_attrib *attr; - attr = MALLOC_STRUCT( gl_multisample_attrib ); - memcpy( attr, &ctx->Multisample, sizeof(struct gl_multisample_attrib) ); - save_attrib_data(&head, GL_MULTISAMPLE_BIT_ARB, attr); - } - -end: - ctx->AttribStack[ctx->AttribStackDepth] = head; - ctx->AttribStackDepth++; -} - - - -static void -pop_enable_group(struct gl_context *ctx, const struct gl_enable_attrib *enable) -{ - const GLuint curTexUnitSave = ctx->Texture.CurrentUnit; - GLuint i; - -#define TEST_AND_UPDATE(VALUE, NEWVALUE, ENUM) \ - if ((VALUE) != (NEWVALUE)) { \ - _mesa_set_enable( ctx, ENUM, (NEWVALUE) ); \ - } - - TEST_AND_UPDATE(ctx->Color.AlphaEnabled, enable->AlphaTest, GL_ALPHA_TEST); - if (ctx->Color.BlendEnabled != enable->Blend) { - if (ctx->Extensions.EXT_draw_buffers2) { - GLuint i; - for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { - _mesa_set_enablei(ctx, GL_BLEND, i, (enable->Blend >> i) & 1); - } - } - else { - _mesa_set_enable(ctx, GL_BLEND, (enable->Blend & 1)); - } - } - - for (i=0;iTransform.ClipPlanesEnabled & mask) != (enable->ClipPlanes & mask)) - _mesa_set_enable(ctx, (GLenum) (GL_CLIP_PLANE0 + i), - (GLboolean) ((enable->ClipPlanes & mask) ? GL_TRUE : GL_FALSE)); - } - - TEST_AND_UPDATE(ctx->Light.ColorMaterialEnabled, enable->ColorMaterial, - GL_COLOR_MATERIAL); - TEST_AND_UPDATE(ctx->Polygon.CullFlag, enable->CullFace, GL_CULL_FACE); - TEST_AND_UPDATE(ctx->Transform.DepthClamp, enable->DepthClamp, - GL_DEPTH_CLAMP); - TEST_AND_UPDATE(ctx->Depth.Test, enable->DepthTest, GL_DEPTH_TEST); - TEST_AND_UPDATE(ctx->Color.DitherFlag, enable->Dither, GL_DITHER); - TEST_AND_UPDATE(ctx->Fog.Enabled, enable->Fog, GL_FOG); - TEST_AND_UPDATE(ctx->Light.Enabled, enable->Lighting, GL_LIGHTING); - TEST_AND_UPDATE(ctx->Line.SmoothFlag, enable->LineSmooth, GL_LINE_SMOOTH); - TEST_AND_UPDATE(ctx->Line.StippleFlag, enable->LineStipple, - GL_LINE_STIPPLE); - TEST_AND_UPDATE(ctx->Color.IndexLogicOpEnabled, enable->IndexLogicOp, - GL_INDEX_LOGIC_OP); - TEST_AND_UPDATE(ctx->Color.ColorLogicOpEnabled, enable->ColorLogicOp, - GL_COLOR_LOGIC_OP); - - TEST_AND_UPDATE(ctx->Eval.Map1Color4, enable->Map1Color4, GL_MAP1_COLOR_4); - TEST_AND_UPDATE(ctx->Eval.Map1Index, enable->Map1Index, GL_MAP1_INDEX); - TEST_AND_UPDATE(ctx->Eval.Map1Normal, enable->Map1Normal, GL_MAP1_NORMAL); - TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord1, enable->Map1TextureCoord1, - GL_MAP1_TEXTURE_COORD_1); - TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord2, enable->Map1TextureCoord2, - GL_MAP1_TEXTURE_COORD_2); - TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord3, enable->Map1TextureCoord3, - GL_MAP1_TEXTURE_COORD_3); - TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord4, enable->Map1TextureCoord4, - GL_MAP1_TEXTURE_COORD_4); - TEST_AND_UPDATE(ctx->Eval.Map1Vertex3, enable->Map1Vertex3, - GL_MAP1_VERTEX_3); - TEST_AND_UPDATE(ctx->Eval.Map1Vertex4, enable->Map1Vertex4, - GL_MAP1_VERTEX_4); - for (i = 0; i < 16; i++) { - TEST_AND_UPDATE(ctx->Eval.Map1Attrib[i], enable->Map1Attrib[i], - GL_MAP1_VERTEX_ATTRIB0_4_NV + i); - } - - TEST_AND_UPDATE(ctx->Eval.Map2Color4, enable->Map2Color4, GL_MAP2_COLOR_4); - TEST_AND_UPDATE(ctx->Eval.Map2Index, enable->Map2Index, GL_MAP2_INDEX); - TEST_AND_UPDATE(ctx->Eval.Map2Normal, enable->Map2Normal, GL_MAP2_NORMAL); - TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord1, enable->Map2TextureCoord1, - GL_MAP2_TEXTURE_COORD_1); - TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord2, enable->Map2TextureCoord2, - GL_MAP2_TEXTURE_COORD_2); - TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord3, enable->Map2TextureCoord3, - GL_MAP2_TEXTURE_COORD_3); - TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord4, enable->Map2TextureCoord4, - GL_MAP2_TEXTURE_COORD_4); - TEST_AND_UPDATE(ctx->Eval.Map2Vertex3, enable->Map2Vertex3, - GL_MAP2_VERTEX_3); - TEST_AND_UPDATE(ctx->Eval.Map2Vertex4, enable->Map2Vertex4, - GL_MAP2_VERTEX_4); - for (i = 0; i < 16; i++) { - TEST_AND_UPDATE(ctx->Eval.Map2Attrib[i], enable->Map2Attrib[i], - GL_MAP2_VERTEX_ATTRIB0_4_NV + i); - } - - TEST_AND_UPDATE(ctx->Eval.AutoNormal, enable->AutoNormal, GL_AUTO_NORMAL); - TEST_AND_UPDATE(ctx->Transform.Normalize, enable->Normalize, GL_NORMALIZE); - TEST_AND_UPDATE(ctx->Transform.RescaleNormals, enable->RescaleNormals, - GL_RESCALE_NORMAL_EXT); - TEST_AND_UPDATE(ctx->Transform.RasterPositionUnclipped, - enable->RasterPositionUnclipped, - GL_RASTER_POSITION_UNCLIPPED_IBM); - TEST_AND_UPDATE(ctx->Point.SmoothFlag, enable->PointSmooth, - GL_POINT_SMOOTH); - if (ctx->Extensions.NV_point_sprite || ctx->Extensions.ARB_point_sprite) { - TEST_AND_UPDATE(ctx->Point.PointSprite, enable->PointSprite, - GL_POINT_SPRITE_NV); - } - TEST_AND_UPDATE(ctx->Polygon.OffsetPoint, enable->PolygonOffsetPoint, - GL_POLYGON_OFFSET_POINT); - TEST_AND_UPDATE(ctx->Polygon.OffsetLine, enable->PolygonOffsetLine, - GL_POLYGON_OFFSET_LINE); - TEST_AND_UPDATE(ctx->Polygon.OffsetFill, enable->PolygonOffsetFill, - GL_POLYGON_OFFSET_FILL); - TEST_AND_UPDATE(ctx->Polygon.SmoothFlag, enable->PolygonSmooth, - GL_POLYGON_SMOOTH); - TEST_AND_UPDATE(ctx->Polygon.StippleFlag, enable->PolygonStipple, - GL_POLYGON_STIPPLE); - TEST_AND_UPDATE(ctx->Scissor.Enabled, enable->Scissor, GL_SCISSOR_TEST); - TEST_AND_UPDATE(ctx->Stencil.Enabled, enable->Stencil, GL_STENCIL_TEST); - if (ctx->Extensions.EXT_stencil_two_side) { - TEST_AND_UPDATE(ctx->Stencil.TestTwoSide, enable->StencilTwoSide, GL_STENCIL_TEST_TWO_SIDE_EXT); - } - TEST_AND_UPDATE(ctx->Multisample.Enabled, enable->MultisampleEnabled, - GL_MULTISAMPLE_ARB); - TEST_AND_UPDATE(ctx->Multisample.SampleAlphaToCoverage, - enable->SampleAlphaToCoverage, - GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); - TEST_AND_UPDATE(ctx->Multisample.SampleAlphaToOne, - enable->SampleAlphaToOne, - GL_SAMPLE_ALPHA_TO_ONE_ARB); - TEST_AND_UPDATE(ctx->Multisample.SampleCoverage, - enable->SampleCoverage, - GL_SAMPLE_COVERAGE_ARB); - TEST_AND_UPDATE(ctx->Multisample.SampleCoverageInvert, - enable->SampleCoverageInvert, - GL_SAMPLE_COVERAGE_INVERT_ARB); - /* GL_ARB_vertex_program, GL_NV_vertex_program */ - TEST_AND_UPDATE(ctx->VertexProgram.Enabled, - enable->VertexProgram, - GL_VERTEX_PROGRAM_ARB); - TEST_AND_UPDATE(ctx->VertexProgram.PointSizeEnabled, - enable->VertexProgramPointSize, - GL_VERTEX_PROGRAM_POINT_SIZE_ARB); - TEST_AND_UPDATE(ctx->VertexProgram.TwoSideEnabled, - enable->VertexProgramTwoSide, - GL_VERTEX_PROGRAM_TWO_SIDE_ARB); - -#undef TEST_AND_UPDATE - - /* texture unit enables */ - for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { - const GLbitfield enabled = enable->Texture[i]; - const GLbitfield genEnabled = enable->TexGen[i]; - - if (ctx->Texture.Unit[i].Enabled != enabled) { - _mesa_ActiveTextureARB(GL_TEXTURE0 + i); - - _mesa_set_enable(ctx, GL_TEXTURE_1D, - (enabled & TEXTURE_1D_BIT) ? GL_TRUE : GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_2D, - (enabled & TEXTURE_2D_BIT) ? GL_TRUE : GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_3D, - (enabled & TEXTURE_3D_BIT) ? GL_TRUE : GL_FALSE); - if (ctx->Extensions.NV_texture_rectangle) { - _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE_ARB, - (enabled & TEXTURE_RECT_BIT) ? GL_TRUE : GL_FALSE); - } - if (ctx->Extensions.ARB_texture_cube_map) { - _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, - (enabled & TEXTURE_CUBE_BIT) ? GL_TRUE : GL_FALSE); - } - if (ctx->Extensions.MESA_texture_array) { - _mesa_set_enable(ctx, GL_TEXTURE_1D_ARRAY_EXT, - (enabled & TEXTURE_1D_ARRAY_BIT) ? GL_TRUE : GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_2D_ARRAY_EXT, - (enabled & TEXTURE_2D_ARRAY_BIT) ? GL_TRUE : GL_FALSE); - } - } - - if (ctx->Texture.Unit[i].TexGenEnabled != genEnabled) { - _mesa_ActiveTextureARB(GL_TEXTURE0 + i); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, - (genEnabled & S_BIT) ? GL_TRUE : GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, - (genEnabled & T_BIT) ? GL_TRUE : GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, - (genEnabled & R_BIT) ? GL_TRUE : GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, - (genEnabled & Q_BIT) ? GL_TRUE : GL_FALSE); - } - - /* GL_SGI_texture_color_table */ - ctx->Texture.Unit[i].ColorTableEnabled = enable->TextureColorTable[i]; - } - - _mesa_ActiveTextureARB(GL_TEXTURE0 + curTexUnitSave); -} - - -/** - * Pop/restore texture attribute/group state. - */ -static void -pop_texture_group(struct gl_context *ctx, struct texture_state *texstate) -{ - GLuint u; - - _mesa_lock_context_textures(ctx); - - for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { - const struct gl_texture_unit *unit = &texstate->Texture.Unit[u]; - GLuint tgt; - - _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + u); - _mesa_set_enable(ctx, GL_TEXTURE_1D, - (unit->Enabled & TEXTURE_1D_BIT) ? GL_TRUE : GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_2D, - (unit->Enabled & TEXTURE_2D_BIT) ? GL_TRUE : GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_3D, - (unit->Enabled & TEXTURE_3D_BIT) ? GL_TRUE : GL_FALSE); - if (ctx->Extensions.ARB_texture_cube_map) { - _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP_ARB, - (unit->Enabled & TEXTURE_CUBE_BIT) ? GL_TRUE : GL_FALSE); - } - if (ctx->Extensions.NV_texture_rectangle) { - _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE_NV, - (unit->Enabled & TEXTURE_RECT_BIT) ? GL_TRUE : GL_FALSE); - } - if (ctx->Extensions.MESA_texture_array) { - _mesa_set_enable(ctx, GL_TEXTURE_1D_ARRAY_EXT, - (unit->Enabled & TEXTURE_1D_ARRAY_BIT) ? GL_TRUE : GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_2D_ARRAY_EXT, - (unit->Enabled & TEXTURE_2D_ARRAY_BIT) ? GL_TRUE : GL_FALSE); - } - - if (ctx->Extensions.SGI_texture_color_table) { - _mesa_set_enable(ctx, GL_TEXTURE_COLOR_TABLE_SGI, - unit->ColorTableEnabled); - } - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->EnvMode); - _mesa_TexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, unit->EnvColor); - _mesa_TexGeni(GL_S, GL_TEXTURE_GEN_MODE, unit->GenS.Mode); - _mesa_TexGeni(GL_T, GL_TEXTURE_GEN_MODE, unit->GenT.Mode); - _mesa_TexGeni(GL_R, GL_TEXTURE_GEN_MODE, unit->GenR.Mode); - _mesa_TexGeni(GL_Q, GL_TEXTURE_GEN_MODE, unit->GenQ.Mode); - _mesa_TexGenfv(GL_S, GL_OBJECT_PLANE, unit->GenS.ObjectPlane); - _mesa_TexGenfv(GL_T, GL_OBJECT_PLANE, unit->GenT.ObjectPlane); - _mesa_TexGenfv(GL_R, GL_OBJECT_PLANE, unit->GenR.ObjectPlane); - _mesa_TexGenfv(GL_Q, GL_OBJECT_PLANE, unit->GenQ.ObjectPlane); - /* Eye plane done differently to avoid re-transformation */ - { - struct gl_texture_unit *destUnit = &ctx->Texture.Unit[u]; - COPY_4FV(destUnit->GenS.EyePlane, unit->GenS.EyePlane); - COPY_4FV(destUnit->GenT.EyePlane, unit->GenT.EyePlane); - COPY_4FV(destUnit->GenR.EyePlane, unit->GenR.EyePlane); - COPY_4FV(destUnit->GenQ.EyePlane, unit->GenQ.EyePlane); - if (ctx->Driver.TexGen) { - ctx->Driver.TexGen(ctx, GL_S, GL_EYE_PLANE, unit->GenS.EyePlane); - ctx->Driver.TexGen(ctx, GL_T, GL_EYE_PLANE, unit->GenT.EyePlane); - ctx->Driver.TexGen(ctx, GL_R, GL_EYE_PLANE, unit->GenR.EyePlane); - ctx->Driver.TexGen(ctx, GL_Q, GL_EYE_PLANE, unit->GenQ.EyePlane); - } - } - _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, - ((unit->TexGenEnabled & S_BIT) ? GL_TRUE : GL_FALSE)); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, - ((unit->TexGenEnabled & T_BIT) ? GL_TRUE : GL_FALSE)); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, - ((unit->TexGenEnabled & R_BIT) ? GL_TRUE : GL_FALSE)); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, - ((unit->TexGenEnabled & Q_BIT) ? GL_TRUE : GL_FALSE)); - if (ctx->Extensions.EXT_texture_lod_bias) { - _mesa_TexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, - GL_TEXTURE_LOD_BIAS_EXT, unit->LodBias); - } - if (ctx->Extensions.EXT_texture_env_combine || - ctx->Extensions.ARB_texture_env_combine) { - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, - unit->Combine.ModeRGB); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, - unit->Combine.ModeA); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, - unit->Combine.SourceRGB[0]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, - unit->Combine.SourceRGB[1]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, - unit->Combine.SourceRGB[2]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, - unit->Combine.SourceA[0]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, - unit->Combine.SourceA[1]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, - unit->Combine.SourceA[2]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, - unit->Combine.OperandRGB[0]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, - unit->Combine.OperandRGB[1]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, - unit->Combine.OperandRGB[2]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, - unit->Combine.OperandA[0]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, - unit->Combine.OperandA[1]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, - unit->Combine.OperandA[2]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, - 1 << unit->Combine.ScaleShiftRGB); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, - 1 << unit->Combine.ScaleShiftA); - } - - /* Restore texture object state for each target */ - for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { - const struct gl_texture_object *obj = NULL; - GLenum target; - - obj = &texstate->SavedObj[u][tgt]; - - /* don't restore state for unsupported targets to prevent - * raising GL errors. - */ - if (obj->Target == GL_TEXTURE_CUBE_MAP_ARB && - !ctx->Extensions.ARB_texture_cube_map) { - continue; - } - else if (obj->Target == GL_TEXTURE_RECTANGLE_NV && - !ctx->Extensions.NV_texture_rectangle) { - continue; - } - else if ((obj->Target == GL_TEXTURE_1D_ARRAY_EXT || - obj->Target == GL_TEXTURE_2D_ARRAY_EXT) && - !ctx->Extensions.MESA_texture_array) { - continue; - } - - target = obj->Target; - - _mesa_BindTexture(target, obj->Name); - - _mesa_TexParameterfv(target, GL_TEXTURE_BORDER_COLOR, obj->BorderColor.f); - _mesa_TexParameterf(target, GL_TEXTURE_PRIORITY, obj->Priority); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, obj->WrapS); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, obj->WrapT); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_R, obj->WrapR); - _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, obj->MinFilter); - _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, obj->MagFilter); - _mesa_TexParameterf(target, GL_TEXTURE_MIN_LOD, obj->MinLod); - _mesa_TexParameterf(target, GL_TEXTURE_MAX_LOD, obj->MaxLod); - _mesa_TexParameterf(target, GL_TEXTURE_LOD_BIAS, obj->LodBias); - _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, obj->BaseLevel); - if (target != GL_TEXTURE_RECTANGLE_ARB) - _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, obj->MaxLevel); - if (ctx->Extensions.EXT_texture_filter_anisotropic) { - _mesa_TexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, - obj->MaxAnisotropy); - } - if (ctx->Extensions.ARB_shadow_ambient) { - _mesa_TexParameterf(target, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, - obj->CompareFailValue); - } - } - - /* remove saved references to the texture objects */ - for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { - _mesa_reference_texobj(&texstate->SavedTexRef[u][tgt], NULL); - } - } - - _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + texstate->Texture.CurrentUnit); - - _mesa_unlock_context_textures(ctx); -} - - -/* - * This function is kind of long just because we have to call a lot - * of device driver functions to update device driver state. - * - * XXX As it is now, most of the pop-code calls immediate-mode Mesa functions - * in order to restore GL state. This isn't terribly efficient but it - * ensures that dirty flags and any derived state gets updated correctly. - * We could at least check if the value to restore equals the current value - * and then skip the Mesa call. - */ -void GLAPIENTRY -_mesa_PopAttrib(void) -{ - struct gl_attrib_node *attr, *next; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (ctx->AttribStackDepth == 0) { - _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopAttrib" ); - return; - } - - ctx->AttribStackDepth--; - attr = ctx->AttribStack[ctx->AttribStackDepth]; - - while (attr) { - - if (MESA_VERBOSE & VERBOSE_API) { - _mesa_debug(ctx, "glPopAttrib %s\n", - _mesa_lookup_enum_by_nr(attr->kind)); - } - - switch (attr->kind) { - case GL_ACCUM_BUFFER_BIT: - { - const struct gl_accum_attrib *accum; - accum = (const struct gl_accum_attrib *) attr->data; - _mesa_ClearAccum(accum->ClearColor[0], - accum->ClearColor[1], - accum->ClearColor[2], - accum->ClearColor[3]); - } - break; - case GL_COLOR_BUFFER_BIT: - { - const struct gl_colorbuffer_attrib *color; - - color = (const struct gl_colorbuffer_attrib *) attr->data; - _mesa_ClearIndex((GLfloat) color->ClearIndex); - _mesa_ClearColor(color->ClearColor[0], - color->ClearColor[1], - color->ClearColor[2], - color->ClearColor[3]); - _mesa_IndexMask(color->IndexMask); - if (!ctx->Extensions.EXT_draw_buffers2) { - _mesa_ColorMask((GLboolean) (color->ColorMask[0][0] != 0), - (GLboolean) (color->ColorMask[0][1] != 0), - (GLboolean) (color->ColorMask[0][2] != 0), - (GLboolean) (color->ColorMask[0][3] != 0)); - } - else { - GLuint i; - for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { - _mesa_ColorMaskIndexed(i, - (GLboolean) (color->ColorMask[i][0] != 0), - (GLboolean) (color->ColorMask[i][1] != 0), - (GLboolean) (color->ColorMask[i][2] != 0), - (GLboolean) (color->ColorMask[i][3] != 0)); - } - } - { - /* Need to determine if more than one color output is - * specified. If so, call glDrawBuffersARB, else call - * glDrawBuffer(). This is a subtle, but essential point - * since GL_FRONT (for example) is illegal for the former - * function, but legal for the later. - */ - GLboolean multipleBuffers = GL_FALSE; - GLuint i; - - for (i = 1; i < ctx->Const.MaxDrawBuffers; i++) { - if (color->DrawBuffer[i] != GL_NONE) { - multipleBuffers = GL_TRUE; - break; - } - } - /* Call the API_level functions, not _mesa_drawbuffers() - * since we need to do error checking on the pop'd - * GL_DRAW_BUFFER. - * Ex: if GL_FRONT were pushed, but we're popping with a - * user FBO bound, GL_FRONT will be illegal and we'll need - * to record that error. Per OpenGL ARB decision. - */ - if (multipleBuffers) - _mesa_DrawBuffersARB(ctx->Const.MaxDrawBuffers, - color->DrawBuffer); - else - _mesa_DrawBuffer(color->DrawBuffer[0]); - } - _mesa_set_enable(ctx, GL_ALPHA_TEST, color->AlphaEnabled); - _mesa_AlphaFunc(color->AlphaFunc, color->AlphaRef); - if (ctx->Color.BlendEnabled != color->BlendEnabled) { - if (ctx->Extensions.EXT_draw_buffers2) { - GLuint i; - for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { - _mesa_set_enablei(ctx, GL_BLEND, i, - (color->BlendEnabled >> i) & 1); - } - } - else { - _mesa_set_enable(ctx, GL_BLEND, (color->BlendEnabled & 1)); - } - } - if (ctx->Color._BlendFuncPerBuffer || - ctx->Color._BlendEquationPerBuffer) { - /* set blend per buffer */ - GLuint buf; - for (buf = 0; buf < ctx->Const.MaxDrawBuffers; buf++) { - _mesa_BlendFuncSeparatei(buf, color->Blend[buf].SrcRGB, - color->Blend[buf].DstRGB, - color->Blend[buf].SrcA, - color->Blend[buf].DstA); - _mesa_BlendEquationSeparatei(buf, - color->Blend[buf].EquationRGB, - color->Blend[buf].EquationA); - } - } - else { - /* set same blend modes for all buffers */ - _mesa_BlendFuncSeparateEXT(color->Blend[0].SrcRGB, - color->Blend[0].DstRGB, - color->Blend[0].SrcA, - color->Blend[0].DstA); - /* This special case is because glBlendEquationSeparateEXT - * cannot take GL_LOGIC_OP as a parameter. - */ - if (color->Blend[0].EquationRGB == - color->Blend[0].EquationA) { - _mesa_BlendEquation(color->Blend[0].EquationRGB); - } - else { - _mesa_BlendEquationSeparateEXT( - color->Blend[0].EquationRGB, - color->Blend[0].EquationA); - } - } - _mesa_BlendColor(color->BlendColor[0], - color->BlendColor[1], - color->BlendColor[2], - color->BlendColor[3]); - _mesa_LogicOp(color->LogicOp); - _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, - color->ColorLogicOpEnabled); - _mesa_set_enable(ctx, GL_INDEX_LOGIC_OP, - color->IndexLogicOpEnabled); - _mesa_set_enable(ctx, GL_DITHER, color->DitherFlag); - } - break; - case GL_CURRENT_BIT: - FLUSH_CURRENT( ctx, 0 ); - memcpy( &ctx->Current, attr->data, - sizeof(struct gl_current_attrib) ); - break; - case GL_DEPTH_BUFFER_BIT: - { - const struct gl_depthbuffer_attrib *depth; - depth = (const struct gl_depthbuffer_attrib *) attr->data; - _mesa_DepthFunc(depth->Func); - _mesa_ClearDepth(depth->Clear); - _mesa_set_enable(ctx, GL_DEPTH_TEST, depth->Test); - _mesa_DepthMask(depth->Mask); - } - break; - case GL_ENABLE_BIT: - { - const struct gl_enable_attrib *enable; - enable = (const struct gl_enable_attrib *) attr->data; - pop_enable_group(ctx, enable); - ctx->NewState |= _NEW_ALL; - } - break; - case GL_EVAL_BIT: - memcpy( &ctx->Eval, attr->data, sizeof(struct gl_eval_attrib) ); - ctx->NewState |= _NEW_EVAL; - break; - case GL_FOG_BIT: - { - const struct gl_fog_attrib *fog; - fog = (const struct gl_fog_attrib *) attr->data; - _mesa_set_enable(ctx, GL_FOG, fog->Enabled); - _mesa_Fogfv(GL_FOG_COLOR, fog->Color); - _mesa_Fogf(GL_FOG_DENSITY, fog->Density); - _mesa_Fogf(GL_FOG_START, fog->Start); - _mesa_Fogf(GL_FOG_END, fog->End); - _mesa_Fogf(GL_FOG_INDEX, fog->Index); - _mesa_Fogi(GL_FOG_MODE, fog->Mode); - } - break; - case GL_HINT_BIT: - { - const struct gl_hint_attrib *hint; - hint = (const struct gl_hint_attrib *) attr->data; - _mesa_Hint(GL_PERSPECTIVE_CORRECTION_HINT, - hint->PerspectiveCorrection ); - _mesa_Hint(GL_POINT_SMOOTH_HINT, hint->PointSmooth); - _mesa_Hint(GL_LINE_SMOOTH_HINT, hint->LineSmooth); - _mesa_Hint(GL_POLYGON_SMOOTH_HINT, hint->PolygonSmooth); - _mesa_Hint(GL_FOG_HINT, hint->Fog); - _mesa_Hint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, - hint->ClipVolumeClipping); - _mesa_Hint(GL_TEXTURE_COMPRESSION_HINT_ARB, - hint->TextureCompression); - } - break; - case GL_LIGHTING_BIT: - { - GLuint i; - const struct gl_light_attrib *light; - light = (const struct gl_light_attrib *) attr->data; - /* lighting enable */ - _mesa_set_enable(ctx, GL_LIGHTING, light->Enabled); - /* per-light state */ - if (_math_matrix_is_dirty(ctx->ModelviewMatrixStack.Top)) - _math_matrix_analyse( ctx->ModelviewMatrixStack.Top ); - - for (i = 0; i < ctx->Const.MaxLights; i++) { - const struct gl_light *l = &light->Light[i]; - _mesa_set_enable(ctx, GL_LIGHT0 + i, l->Enabled); - _mesa_light(ctx, i, GL_AMBIENT, l->Ambient); - _mesa_light(ctx, i, GL_DIFFUSE, l->Diffuse); - _mesa_light(ctx, i, GL_SPECULAR, l->Specular ); - _mesa_light(ctx, i, GL_POSITION, l->EyePosition); - _mesa_light(ctx, i, GL_SPOT_DIRECTION, l->SpotDirection); - { - GLfloat p[4] = { 0 }; - p[0] = l->SpotExponent; - _mesa_light(ctx, i, GL_SPOT_EXPONENT, p); - } - { - GLfloat p[4] = { 0 }; - p[0] = l->SpotCutoff; - _mesa_light(ctx, i, GL_SPOT_CUTOFF, p); - } - { - GLfloat p[4] = { 0 }; - p[0] = l->ConstantAttenuation; - _mesa_light(ctx, i, GL_CONSTANT_ATTENUATION, p); - } - { - GLfloat p[4] = { 0 }; - p[0] = l->LinearAttenuation; - _mesa_light(ctx, i, GL_LINEAR_ATTENUATION, p); - } - { - GLfloat p[4] = { 0 }; - p[0] = l->QuadraticAttenuation; - _mesa_light(ctx, i, GL_QUADRATIC_ATTENUATION, p); - } - } - /* light model */ - _mesa_LightModelfv(GL_LIGHT_MODEL_AMBIENT, - light->Model.Ambient); - _mesa_LightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, - (GLfloat) light->Model.LocalViewer); - _mesa_LightModelf(GL_LIGHT_MODEL_TWO_SIDE, - (GLfloat) light->Model.TwoSide); - _mesa_LightModelf(GL_LIGHT_MODEL_COLOR_CONTROL, - (GLfloat) light->Model.ColorControl); - /* shade model */ - _mesa_ShadeModel(light->ShadeModel); - /* color material */ - _mesa_ColorMaterial(light->ColorMaterialFace, - light->ColorMaterialMode); - _mesa_set_enable(ctx, GL_COLOR_MATERIAL, - light->ColorMaterialEnabled); - /* materials */ - memcpy(&ctx->Light.Material, &light->Material, - sizeof(struct gl_material)); - } - break; - case GL_LINE_BIT: - { - const struct gl_line_attrib *line; - line = (const struct gl_line_attrib *) attr->data; - _mesa_set_enable(ctx, GL_LINE_SMOOTH, line->SmoothFlag); - _mesa_set_enable(ctx, GL_LINE_STIPPLE, line->StippleFlag); - _mesa_LineStipple(line->StippleFactor, line->StipplePattern); - _mesa_LineWidth(line->Width); - } - break; - case GL_LIST_BIT: - memcpy( &ctx->List, attr->data, sizeof(struct gl_list_attrib) ); - break; - case GL_PIXEL_MODE_BIT: - memcpy( &ctx->Pixel, attr->data, sizeof(struct gl_pixel_attrib) ); - /* XXX what other pixel state needs to be set by function calls? */ - _mesa_ReadBuffer(ctx->Pixel.ReadBuffer); - ctx->NewState |= _NEW_PIXEL; - break; - case GL_POINT_BIT: - { - const struct gl_point_attrib *point; - point = (const struct gl_point_attrib *) attr->data; - _mesa_PointSize(point->Size); - _mesa_set_enable(ctx, GL_POINT_SMOOTH, point->SmoothFlag); - if (ctx->Extensions.EXT_point_parameters) { - _mesa_PointParameterfv(GL_DISTANCE_ATTENUATION_EXT, - point->Params); - _mesa_PointParameterf(GL_POINT_SIZE_MIN_EXT, - point->MinSize); - _mesa_PointParameterf(GL_POINT_SIZE_MAX_EXT, - point->MaxSize); - _mesa_PointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_EXT, - point->Threshold); - } - if (ctx->Extensions.NV_point_sprite - || ctx->Extensions.ARB_point_sprite) { - GLuint u; - for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { - _mesa_TexEnvi(GL_POINT_SPRITE_NV, GL_COORD_REPLACE_NV, - (GLint) point->CoordReplace[u]); - } - _mesa_set_enable(ctx, GL_POINT_SPRITE_NV,point->PointSprite); - if (ctx->Extensions.NV_point_sprite) - _mesa_PointParameteri(GL_POINT_SPRITE_R_MODE_NV, - ctx->Point.SpriteRMode); - _mesa_PointParameterf(GL_POINT_SPRITE_COORD_ORIGIN, - (GLfloat)ctx->Point.SpriteOrigin); - } - } - break; - case GL_POLYGON_BIT: - { - const struct gl_polygon_attrib *polygon; - polygon = (const struct gl_polygon_attrib *) attr->data; - _mesa_CullFace(polygon->CullFaceMode); - _mesa_FrontFace(polygon->FrontFace); - _mesa_PolygonMode(GL_FRONT, polygon->FrontMode); - _mesa_PolygonMode(GL_BACK, polygon->BackMode); - _mesa_PolygonOffset(polygon->OffsetFactor, - polygon->OffsetUnits); - _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, polygon->SmoothFlag); - _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, polygon->StippleFlag); - _mesa_set_enable(ctx, GL_CULL_FACE, polygon->CullFlag); - _mesa_set_enable(ctx, GL_POLYGON_OFFSET_POINT, - polygon->OffsetPoint); - _mesa_set_enable(ctx, GL_POLYGON_OFFSET_LINE, - polygon->OffsetLine); - _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, - polygon->OffsetFill); - } - break; - case GL_POLYGON_STIPPLE_BIT: - memcpy( ctx->PolygonStipple, attr->data, 32*sizeof(GLuint) ); - ctx->NewState |= _NEW_POLYGONSTIPPLE; - if (ctx->Driver.PolygonStipple) - ctx->Driver.PolygonStipple( ctx, (const GLubyte *) attr->data ); - break; - case GL_SCISSOR_BIT: - { - const struct gl_scissor_attrib *scissor; - scissor = (const struct gl_scissor_attrib *) attr->data; - _mesa_Scissor(scissor->X, scissor->Y, - scissor->Width, scissor->Height); - _mesa_set_enable(ctx, GL_SCISSOR_TEST, scissor->Enabled); - } - break; - case GL_STENCIL_BUFFER_BIT: - { - const struct gl_stencil_attrib *stencil; - stencil = (const struct gl_stencil_attrib *) attr->data; - _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled); - _mesa_ClearStencil(stencil->Clear); - if (ctx->Extensions.EXT_stencil_two_side) { - _mesa_set_enable(ctx, GL_STENCIL_TEST_TWO_SIDE_EXT, - stencil->TestTwoSide); - _mesa_ActiveStencilFaceEXT(stencil->ActiveFace - ? GL_BACK : GL_FRONT); - } - /* front state */ - _mesa_StencilFuncSeparate(GL_FRONT, - stencil->Function[0], - stencil->Ref[0], - stencil->ValueMask[0]); - _mesa_StencilMaskSeparate(GL_FRONT, stencil->WriteMask[0]); - _mesa_StencilOpSeparate(GL_FRONT, stencil->FailFunc[0], - stencil->ZFailFunc[0], - stencil->ZPassFunc[0]); - /* back state */ - _mesa_StencilFuncSeparate(GL_BACK, - stencil->Function[1], - stencil->Ref[1], - stencil->ValueMask[1]); - _mesa_StencilMaskSeparate(GL_BACK, stencil->WriteMask[1]); - _mesa_StencilOpSeparate(GL_BACK, stencil->FailFunc[1], - stencil->ZFailFunc[1], - stencil->ZPassFunc[1]); - } - break; - case GL_TRANSFORM_BIT: - { - GLuint i; - const struct gl_transform_attrib *xform; - xform = (const struct gl_transform_attrib *) attr->data; - _mesa_MatrixMode(xform->MatrixMode); - if (_math_matrix_is_dirty(ctx->ProjectionMatrixStack.Top)) - _math_matrix_analyse( ctx->ProjectionMatrixStack.Top ); - - /* restore clip planes */ - for (i = 0; i < MAX_CLIP_PLANES; i++) { - const GLuint mask = 1 << i; - const GLfloat *eyePlane = xform->EyeUserPlane[i]; - COPY_4V(ctx->Transform.EyeUserPlane[i], eyePlane); - if (xform->ClipPlanesEnabled & mask) { - _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_TRUE); - } - else { - _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_FALSE); - } - if (ctx->Driver.ClipPlane) - ctx->Driver.ClipPlane( ctx, GL_CLIP_PLANE0 + i, eyePlane ); - } - - /* normalize/rescale */ - if (xform->Normalize != ctx->Transform.Normalize) - _mesa_set_enable(ctx, GL_NORMALIZE,ctx->Transform.Normalize); - if (xform->RescaleNormals != ctx->Transform.RescaleNormals) - _mesa_set_enable(ctx, GL_RESCALE_NORMAL_EXT, - ctx->Transform.RescaleNormals); - if (xform->DepthClamp != ctx->Transform.DepthClamp) - _mesa_set_enable(ctx, GL_DEPTH_CLAMP, - ctx->Transform.DepthClamp); - } - break; - case GL_TEXTURE_BIT: - /* Take care of texture object reference counters */ - { - struct texture_state *texstate - = (struct texture_state *) attr->data; - pop_texture_group(ctx, texstate); - ctx->NewState |= _NEW_TEXTURE; - } - break; - case GL_VIEWPORT_BIT: - { - const struct gl_viewport_attrib *vp; - vp = (const struct gl_viewport_attrib *) attr->data; - _mesa_Viewport(vp->X, vp->Y, vp->Width, vp->Height); - _mesa_DepthRange(vp->Near, vp->Far); - } - break; - case GL_MULTISAMPLE_BIT_ARB: - { - const struct gl_multisample_attrib *ms; - ms = (const struct gl_multisample_attrib *) attr->data; - _mesa_SampleCoverageARB(ms->SampleCoverageValue, - ms->SampleCoverageInvert); - } - break; - - default: - _mesa_problem( ctx, "Bad attrib flag in PopAttrib"); - break; - } - - next = attr->next; - FREE( attr->data ); - FREE( attr ); - attr = next; - } -} - - -/** - * Helper for incrementing/decrementing vertex buffer object reference - * counts when pushing/popping the GL_CLIENT_VERTEX_ARRAY_BIT attribute group. - */ -static void -adjust_buffer_object_ref_counts(struct gl_array_object *arrayObj, GLint step) -{ - GLuint i; - - arrayObj->Vertex.BufferObj->RefCount += step; - arrayObj->Weight.BufferObj->RefCount += step; - arrayObj->Normal.BufferObj->RefCount += step; - arrayObj->Color.BufferObj->RefCount += step; - arrayObj->SecondaryColor.BufferObj->RefCount += step; - arrayObj->FogCoord.BufferObj->RefCount += step; - arrayObj->Index.BufferObj->RefCount += step; - arrayObj->EdgeFlag.BufferObj->RefCount += step; - for (i = 0; i < Elements(arrayObj->TexCoord); i++) - arrayObj->TexCoord[i].BufferObj->RefCount += step; - for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) - arrayObj->VertexAttrib[i].BufferObj->RefCount += step; -} - - -/** - * Copy gl_pixelstore_attrib from src to dst, updating buffer - * object refcounts. - */ -static void -copy_pixelstore(struct gl_context *ctx, - struct gl_pixelstore_attrib *dst, - const struct gl_pixelstore_attrib *src) -{ - dst->Alignment = src->Alignment; - dst->RowLength = src->RowLength; - dst->SkipPixels = src->SkipPixels; - dst->SkipRows = src->SkipRows; - dst->ImageHeight = src->ImageHeight; - dst->SkipImages = src->SkipImages; - dst->SwapBytes = src->SwapBytes; - dst->LsbFirst = src->LsbFirst; - dst->ClientStorage = src->ClientStorage; - dst->Invert = src->Invert; - _mesa_reference_buffer_object(ctx, &dst->BufferObj, src->BufferObj); -} - - -#define GL_CLIENT_PACK_BIT (1<<20) -#define GL_CLIENT_UNPACK_BIT (1<<21) - - -void GLAPIENTRY -_mesa_PushClientAttrib(GLbitfield mask) -{ - struct gl_attrib_node *head; - - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (ctx->ClientAttribStackDepth >= MAX_CLIENT_ATTRIB_STACK_DEPTH) { - _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushClientAttrib" ); - return; - } - - /* Build linked list of attribute nodes which save all attribute - * groups specified by the mask. - */ - head = NULL; - - if (mask & GL_CLIENT_PIXEL_STORE_BIT) { - struct gl_pixelstore_attrib *attr; - /* packing attribs */ - attr = CALLOC_STRUCT( gl_pixelstore_attrib ); - copy_pixelstore(ctx, attr, &ctx->Pack); - save_attrib_data(&head, GL_CLIENT_PACK_BIT, attr); - /* unpacking attribs */ - attr = CALLOC_STRUCT( gl_pixelstore_attrib ); - copy_pixelstore(ctx, attr, &ctx->Unpack); - save_attrib_data(&head, GL_CLIENT_UNPACK_BIT, attr); - } - - if (mask & GL_CLIENT_VERTEX_ARRAY_BIT) { - struct gl_array_attrib *attr; - struct gl_array_object *obj; - - attr = MALLOC_STRUCT( gl_array_attrib ); - obj = MALLOC_STRUCT( gl_array_object ); - -#if FEATURE_ARB_vertex_buffer_object - /* increment ref counts since we're copying pointers to these objects */ - ctx->Array.ArrayBufferObj->RefCount++; - ctx->Array.ElementArrayBufferObj->RefCount++; -#endif - - memcpy( attr, &ctx->Array, sizeof(struct gl_array_attrib) ); - memcpy( obj, ctx->Array.ArrayObj, sizeof(struct gl_array_object) ); - - attr->ArrayObj = obj; - - save_attrib_data(&head, GL_CLIENT_VERTEX_ARRAY_BIT, attr); - - /* bump reference counts on buffer objects */ - adjust_buffer_object_ref_counts(ctx->Array.ArrayObj, 1); - } - - ctx->ClientAttribStack[ctx->ClientAttribStackDepth] = head; - ctx->ClientAttribStackDepth++; -} - - - - -void GLAPIENTRY -_mesa_PopClientAttrib(void) -{ - struct gl_attrib_node *node, *next; - - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (ctx->ClientAttribStackDepth == 0) { - _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopClientAttrib" ); - return; - } - - ctx->ClientAttribStackDepth--; - node = ctx->ClientAttribStack[ctx->ClientAttribStackDepth]; - - while (node) { - switch (node->kind) { - case GL_CLIENT_PACK_BIT: - { - struct gl_pixelstore_attrib *store = - (struct gl_pixelstore_attrib *) node->data; - copy_pixelstore(ctx, &ctx->Pack, store); - _mesa_reference_buffer_object(ctx, &store->BufferObj, NULL); - } - ctx->NewState |= _NEW_PACKUNPACK; - break; - case GL_CLIENT_UNPACK_BIT: - { - struct gl_pixelstore_attrib *store = - (struct gl_pixelstore_attrib *) node->data; - copy_pixelstore(ctx, &ctx->Unpack, store); - _mesa_reference_buffer_object(ctx, &store->BufferObj, NULL); - } - ctx->NewState |= _NEW_PACKUNPACK; - break; - case GL_CLIENT_VERTEX_ARRAY_BIT: { - struct gl_array_attrib * data = - (struct gl_array_attrib *) node->data; - - adjust_buffer_object_ref_counts(ctx->Array.ArrayObj, -1); - - ctx->Array.ActiveTexture = data->ActiveTexture; - if (data->LockCount != 0) - _mesa_LockArraysEXT(data->LockFirst, data->LockCount); - else if (ctx->Array.LockCount) - _mesa_UnlockArraysEXT(); - - _mesa_BindVertexArrayAPPLE( data->ArrayObj->Name ); - -#if FEATURE_ARB_vertex_buffer_object - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, - data->ArrayBufferObj->Name); - _mesa_BindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, - data->ElementArrayBufferObj->Name); -#endif - - memcpy( ctx->Array.ArrayObj, data->ArrayObj, - sizeof( struct gl_array_object ) ); - - FREE( data->ArrayObj ); - - /* FIXME: Should some bits in ctx->Array->NewState also be set - * FIXME: here? It seems like it should be set to inclusive-or - * FIXME: of the old ArrayObj->_Enabled and the new _Enabled. - */ - - ctx->NewState |= _NEW_ARRAY; - break; - } - default: - _mesa_problem( ctx, "Bad attrib flag in PopClientAttrib"); - break; - } - - next = node->next; - FREE( node->data ); - FREE( node ); - node = next; - } -} - - -void -_mesa_init_attrib_dispatch(struct _glapi_table *disp) -{ - SET_PopAttrib(disp, _mesa_PopAttrib); - SET_PushAttrib(disp, _mesa_PushAttrib); - SET_PopClientAttrib(disp, _mesa_PopClientAttrib); - SET_PushClientAttrib(disp, _mesa_PushClientAttrib); -} - - -#endif /* FEATURE_attrib_stack */ - - -/** - * Free any attribute state data that might be attached to the context. - */ -void -_mesa_free_attrib_data(struct gl_context *ctx) -{ - while (ctx->AttribStackDepth > 0) { - struct gl_attrib_node *attr, *next; - - ctx->AttribStackDepth--; - attr = ctx->AttribStack[ctx->AttribStackDepth]; - - while (attr) { - if (attr->kind == GL_TEXTURE_BIT) { - struct texture_state *texstate = (struct texture_state*)attr->data; - GLuint u, tgt; - /* clear references to the saved texture objects */ - for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { - for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { - _mesa_reference_texobj(&texstate->SavedTexRef[u][tgt], NULL); - } - } - } - else { - /* any other chunks of state that requires special handling? */ - } - - next = attr->next; - free(attr->data); - free(attr); - attr = next; - } - } -} - - -void _mesa_init_attrib( struct gl_context *ctx ) -{ - /* Renderer and client attribute stacks */ - ctx->AttribStackDepth = 0; - ctx->ClientAttribStackDepth = 0; -} +/* + * Mesa 3-D graphics library + * Version: 7.6 + * + * 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. + */ + +#include "glheader.h" +#include "imports.h" +#include "accum.h" +#include "arrayobj.h" +#include "attrib.h" +#include "blend.h" +#include "buffers.h" +#include "bufferobj.h" +#include "clear.h" +#include "colormac.h" +#include "context.h" +#include "depth.h" +#include "enable.h" +#include "enums.h" +#include "fog.h" +#include "hint.h" +#include "light.h" +#include "lines.h" +#include "macros.h" +#include "matrix.h" +#include "mfeatures.h" +#include "multisample.h" +#include "points.h" +#include "polygon.h" +#include "scissor.h" +#include "stencil.h" +#include "texenv.h" +#include "texgen.h" +#include "texobj.h" +#include "texparam.h" +#include "texstate.h" +#include "varray.h" +#include "viewport.h" +#include "mtypes.h" +#include "main/dispatch.h" + + +/** + * glEnable()/glDisable() attribute group (GL_ENABLE_BIT). + */ +struct gl_enable_attrib +{ + GLboolean AlphaTest; + GLboolean AutoNormal; + GLboolean Blend; + GLbitfield ClipPlanes; + GLboolean ColorMaterial; + GLboolean CullFace; + GLboolean DepthClamp; + GLboolean DepthTest; + GLboolean Dither; + GLboolean Fog; + GLboolean Light[MAX_LIGHTS]; + GLboolean Lighting; + GLboolean LineSmooth; + GLboolean LineStipple; + GLboolean IndexLogicOp; + GLboolean ColorLogicOp; + + GLboolean Map1Color4; + GLboolean Map1Index; + GLboolean Map1Normal; + GLboolean Map1TextureCoord1; + GLboolean Map1TextureCoord2; + GLboolean Map1TextureCoord3; + GLboolean Map1TextureCoord4; + GLboolean Map1Vertex3; + GLboolean Map1Vertex4; + GLboolean Map1Attrib[16]; /* GL_NV_vertex_program */ + GLboolean Map2Color4; + GLboolean Map2Index; + GLboolean Map2Normal; + GLboolean Map2TextureCoord1; + GLboolean Map2TextureCoord2; + GLboolean Map2TextureCoord3; + GLboolean Map2TextureCoord4; + GLboolean Map2Vertex3; + GLboolean Map2Vertex4; + GLboolean Map2Attrib[16]; /* GL_NV_vertex_program */ + + GLboolean Normalize; + GLboolean PixelTexture; + GLboolean PointSmooth; + GLboolean PolygonOffsetPoint; + GLboolean PolygonOffsetLine; + GLboolean PolygonOffsetFill; + GLboolean PolygonSmooth; + GLboolean PolygonStipple; + GLboolean RescaleNormals; + GLboolean Scissor; + GLboolean Stencil; + GLboolean StencilTwoSide; /* GL_EXT_stencil_two_side */ + GLboolean MultisampleEnabled; /* GL_ARB_multisample */ + GLboolean SampleAlphaToCoverage; /* GL_ARB_multisample */ + GLboolean SampleAlphaToOne; /* GL_ARB_multisample */ + GLboolean SampleCoverage; /* GL_ARB_multisample */ + GLboolean SampleCoverageInvert; /* GL_ARB_multisample */ + GLboolean RasterPositionUnclipped; /* GL_IBM_rasterpos_clip */ + + GLbitfield Texture[MAX_TEXTURE_UNITS]; + GLbitfield TexGen[MAX_TEXTURE_UNITS]; + + /* GL_ARB_vertex_program / GL_NV_vertex_program */ + GLboolean VertexProgram; + GLboolean VertexProgramPointSize; + GLboolean VertexProgramTwoSide; + + /* GL_ARB_point_sprite / GL_NV_point_sprite */ + GLboolean PointSprite; + GLboolean FragmentShaderATI; +}; + + +/** + * Node for the attribute stack. + */ +struct gl_attrib_node +{ + GLbitfield kind; + void *data; + struct gl_attrib_node *next; +}; + + + +/** + * Special struct for saving/restoring texture state (GL_TEXTURE_BIT) + */ +struct texture_state +{ + struct gl_texture_attrib Texture; /**< The usual context state */ + + /** to save per texture object state (wrap modes, filters, etc): */ + struct gl_texture_object SavedObj[MAX_TEXTURE_UNITS][NUM_TEXTURE_TARGETS]; + + /** + * To save references to texture objects (so they don't get accidentally + * deleted while saved in the attribute stack). + */ + struct gl_texture_object *SavedTexRef[MAX_TEXTURE_UNITS][NUM_TEXTURE_TARGETS]; +}; + + +#if FEATURE_attrib_stack + + +/** + * Allocate new attribute node of given type/kind. Attach payload data. + * Insert it into the linked list named by 'head'. + */ +static void +save_attrib_data(struct gl_attrib_node **head, + GLbitfield kind, void *payload) +{ + struct gl_attrib_node *n = MALLOC_STRUCT(gl_attrib_node); + if (n) { + n->kind = kind; + n->data = payload; + /* insert at head */ + n->next = *head; + *head = n; + } + else { + /* out of memory! */ + } +} + + +void GLAPIENTRY +_mesa_PushAttrib(GLbitfield mask) +{ + struct gl_attrib_node *head; + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glPushAttrib %x\n", (int) mask); + + if (ctx->AttribStackDepth >= MAX_ATTRIB_STACK_DEPTH) { + _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushAttrib" ); + return; + } + + /* Build linked list of attribute nodes which save all attribute */ + /* groups specified by the mask. */ + head = NULL; + + if (mask & GL_ACCUM_BUFFER_BIT) { + struct gl_accum_attrib *attr; + attr = MALLOC_STRUCT( gl_accum_attrib ); + memcpy( attr, &ctx->Accum, sizeof(struct gl_accum_attrib) ); + save_attrib_data(&head, GL_ACCUM_BUFFER_BIT, attr); + } + + if (mask & GL_COLOR_BUFFER_BIT) { + GLuint i; + struct gl_colorbuffer_attrib *attr; + attr = MALLOC_STRUCT( gl_colorbuffer_attrib ); + memcpy( attr, &ctx->Color, sizeof(struct gl_colorbuffer_attrib) ); + /* push the Draw FBO's DrawBuffer[] state, not ctx->Color.DrawBuffer[] */ + for (i = 0; i < ctx->Const.MaxDrawBuffers; i ++) + attr->DrawBuffer[i] = ctx->DrawBuffer->ColorDrawBuffer[i]; + save_attrib_data(&head, GL_COLOR_BUFFER_BIT, attr); + } + + if (mask & GL_CURRENT_BIT) { + struct gl_current_attrib *attr; + FLUSH_CURRENT( ctx, 0 ); + attr = MALLOC_STRUCT( gl_current_attrib ); + memcpy( attr, &ctx->Current, sizeof(struct gl_current_attrib) ); + save_attrib_data(&head, GL_CURRENT_BIT, attr); + } + + if (mask & GL_DEPTH_BUFFER_BIT) { + struct gl_depthbuffer_attrib *attr; + attr = MALLOC_STRUCT( gl_depthbuffer_attrib ); + memcpy( attr, &ctx->Depth, sizeof(struct gl_depthbuffer_attrib) ); + save_attrib_data(&head, GL_DEPTH_BUFFER_BIT, attr); + } + + if (mask & GL_ENABLE_BIT) { + struct gl_enable_attrib *attr; + GLuint i; + attr = MALLOC_STRUCT( gl_enable_attrib ); + /* Copy enable flags from all other attributes into the enable struct. */ + attr->AlphaTest = ctx->Color.AlphaEnabled; + attr->AutoNormal = ctx->Eval.AutoNormal; + attr->Blend = ctx->Color.BlendEnabled; + attr->ClipPlanes = ctx->Transform.ClipPlanesEnabled; + attr->ColorMaterial = ctx->Light.ColorMaterialEnabled; + attr->CullFace = ctx->Polygon.CullFlag; + attr->DepthClamp = ctx->Transform.DepthClamp; + attr->DepthTest = ctx->Depth.Test; + attr->Dither = ctx->Color.DitherFlag; + attr->Fog = ctx->Fog.Enabled; + for (i = 0; i < ctx->Const.MaxLights; i++) { + attr->Light[i] = ctx->Light.Light[i].Enabled; + } + attr->Lighting = ctx->Light.Enabled; + attr->LineSmooth = ctx->Line.SmoothFlag; + attr->LineStipple = ctx->Line.StippleFlag; + attr->IndexLogicOp = ctx->Color.IndexLogicOpEnabled; + attr->ColorLogicOp = ctx->Color.ColorLogicOpEnabled; + attr->Map1Color4 = ctx->Eval.Map1Color4; + attr->Map1Index = ctx->Eval.Map1Index; + attr->Map1Normal = ctx->Eval.Map1Normal; + attr->Map1TextureCoord1 = ctx->Eval.Map1TextureCoord1; + attr->Map1TextureCoord2 = ctx->Eval.Map1TextureCoord2; + attr->Map1TextureCoord3 = ctx->Eval.Map1TextureCoord3; + attr->Map1TextureCoord4 = ctx->Eval.Map1TextureCoord4; + attr->Map1Vertex3 = ctx->Eval.Map1Vertex3; + attr->Map1Vertex4 = ctx->Eval.Map1Vertex4; + memcpy(attr->Map1Attrib, ctx->Eval.Map1Attrib, sizeof(ctx->Eval.Map1Attrib)); + attr->Map2Color4 = ctx->Eval.Map2Color4; + attr->Map2Index = ctx->Eval.Map2Index; + attr->Map2Normal = ctx->Eval.Map2Normal; + attr->Map2TextureCoord1 = ctx->Eval.Map2TextureCoord1; + attr->Map2TextureCoord2 = ctx->Eval.Map2TextureCoord2; + attr->Map2TextureCoord3 = ctx->Eval.Map2TextureCoord3; + attr->Map2TextureCoord4 = ctx->Eval.Map2TextureCoord4; + attr->Map2Vertex3 = ctx->Eval.Map2Vertex3; + attr->Map2Vertex4 = ctx->Eval.Map2Vertex4; + memcpy(attr->Map2Attrib, ctx->Eval.Map2Attrib, sizeof(ctx->Eval.Map2Attrib)); + attr->Normalize = ctx->Transform.Normalize; + attr->RasterPositionUnclipped = ctx->Transform.RasterPositionUnclipped; + attr->PointSmooth = ctx->Point.SmoothFlag; + attr->PointSprite = ctx->Point.PointSprite; + attr->PolygonOffsetPoint = ctx->Polygon.OffsetPoint; + attr->PolygonOffsetLine = ctx->Polygon.OffsetLine; + attr->PolygonOffsetFill = ctx->Polygon.OffsetFill; + attr->PolygonSmooth = ctx->Polygon.SmoothFlag; + attr->PolygonStipple = ctx->Polygon.StippleFlag; + attr->RescaleNormals = ctx->Transform.RescaleNormals; + attr->Scissor = ctx->Scissor.Enabled; + attr->Stencil = ctx->Stencil.Enabled; + attr->StencilTwoSide = ctx->Stencil.TestTwoSide; + attr->MultisampleEnabled = ctx->Multisample.Enabled; + attr->SampleAlphaToCoverage = ctx->Multisample.SampleAlphaToCoverage; + attr->SampleAlphaToOne = ctx->Multisample.SampleAlphaToOne; + attr->SampleCoverage = ctx->Multisample.SampleCoverage; + attr->SampleCoverageInvert = ctx->Multisample.SampleCoverageInvert; + for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { + attr->Texture[i] = ctx->Texture.Unit[i].Enabled; + attr->TexGen[i] = ctx->Texture.Unit[i].TexGenEnabled; + } + /* GL_NV_vertex_program */ + attr->VertexProgram = ctx->VertexProgram.Enabled; + attr->VertexProgramPointSize = ctx->VertexProgram.PointSizeEnabled; + attr->VertexProgramTwoSide = ctx->VertexProgram.TwoSideEnabled; + save_attrib_data(&head, GL_ENABLE_BIT, attr); + } + + if (mask & GL_EVAL_BIT) { + struct gl_eval_attrib *attr; + attr = MALLOC_STRUCT( gl_eval_attrib ); + memcpy( attr, &ctx->Eval, sizeof(struct gl_eval_attrib) ); + save_attrib_data(&head, GL_EVAL_BIT, attr); + } + + if (mask & GL_FOG_BIT) { + struct gl_fog_attrib *attr; + attr = MALLOC_STRUCT( gl_fog_attrib ); + memcpy( attr, &ctx->Fog, sizeof(struct gl_fog_attrib) ); + save_attrib_data(&head, GL_FOG_BIT, attr); + } + + if (mask & GL_HINT_BIT) { + struct gl_hint_attrib *attr; + attr = MALLOC_STRUCT( gl_hint_attrib ); + memcpy( attr, &ctx->Hint, sizeof(struct gl_hint_attrib) ); + save_attrib_data(&head, GL_HINT_BIT, attr); + } + + if (mask & GL_LIGHTING_BIT) { + struct gl_light_attrib *attr; + FLUSH_CURRENT(ctx, 0); /* flush material changes */ + attr = MALLOC_STRUCT( gl_light_attrib ); + memcpy( attr, &ctx->Light, sizeof(struct gl_light_attrib) ); + save_attrib_data(&head, GL_LIGHTING_BIT, attr); + } + + if (mask & GL_LINE_BIT) { + struct gl_line_attrib *attr; + attr = MALLOC_STRUCT( gl_line_attrib ); + memcpy( attr, &ctx->Line, sizeof(struct gl_line_attrib) ); + save_attrib_data(&head, GL_LINE_BIT, attr); + } + + if (mask & GL_LIST_BIT) { + struct gl_list_attrib *attr; + attr = MALLOC_STRUCT( gl_list_attrib ); + memcpy( attr, &ctx->List, sizeof(struct gl_list_attrib) ); + save_attrib_data(&head, GL_LIST_BIT, attr); + } + + if (mask & GL_PIXEL_MODE_BIT) { + struct gl_pixel_attrib *attr; + attr = MALLOC_STRUCT( gl_pixel_attrib ); + memcpy( attr, &ctx->Pixel, sizeof(struct gl_pixel_attrib) ); + /* push the Read FBO's ReadBuffer state, not ctx->Pixel.ReadBuffer */ + attr->ReadBuffer = ctx->ReadBuffer->ColorReadBuffer; + save_attrib_data(&head, GL_PIXEL_MODE_BIT, attr); + } + + if (mask & GL_POINT_BIT) { + struct gl_point_attrib *attr; + attr = MALLOC_STRUCT( gl_point_attrib ); + memcpy( attr, &ctx->Point, sizeof(struct gl_point_attrib) ); + save_attrib_data(&head, GL_POINT_BIT, attr); + } + + if (mask & GL_POLYGON_BIT) { + struct gl_polygon_attrib *attr; + attr = MALLOC_STRUCT( gl_polygon_attrib ); + memcpy( attr, &ctx->Polygon, sizeof(struct gl_polygon_attrib) ); + save_attrib_data(&head, GL_POLYGON_BIT, attr); + } + + if (mask & GL_POLYGON_STIPPLE_BIT) { + GLuint *stipple; + stipple = (GLuint *) MALLOC( 32*sizeof(GLuint) ); + memcpy( stipple, ctx->PolygonStipple, 32*sizeof(GLuint) ); + save_attrib_data(&head, GL_POLYGON_STIPPLE_BIT, stipple); + } + + if (mask & GL_SCISSOR_BIT) { + struct gl_scissor_attrib *attr; + attr = MALLOC_STRUCT( gl_scissor_attrib ); + memcpy( attr, &ctx->Scissor, sizeof(struct gl_scissor_attrib) ); + save_attrib_data(&head, GL_SCISSOR_BIT, attr); + } + + if (mask & GL_STENCIL_BUFFER_BIT) { + struct gl_stencil_attrib *attr; + attr = MALLOC_STRUCT( gl_stencil_attrib ); + memcpy( attr, &ctx->Stencil, sizeof(struct gl_stencil_attrib) ); + save_attrib_data(&head, GL_STENCIL_BUFFER_BIT, attr); + } + + if (mask & GL_TEXTURE_BIT) { + struct texture_state *texstate = CALLOC_STRUCT(texture_state); + GLuint u, tex; + + if (!texstate) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glPushAttrib(GL_TEXTURE_BIT)"); + goto end; + } + + _mesa_lock_context_textures(ctx); + + /* copy/save the bulk of texture state here */ + memcpy(&texstate->Texture, &ctx->Texture, sizeof(ctx->Texture)); + + /* Save references to the currently bound texture objects so they don't + * accidentally get deleted while referenced in the attribute stack. + */ + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { + _mesa_reference_texobj(&texstate->SavedTexRef[u][tex], + ctx->Texture.Unit[u].CurrentTex[tex]); + } + } + + /* copy state/contents of the currently bound texture objects */ + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { + _mesa_copy_texture_object(&texstate->SavedObj[u][tex], + ctx->Texture.Unit[u].CurrentTex[tex]); + } + } + + _mesa_unlock_context_textures(ctx); + + save_attrib_data(&head, GL_TEXTURE_BIT, texstate); + } + + if (mask & GL_TRANSFORM_BIT) { + struct gl_transform_attrib *attr; + attr = MALLOC_STRUCT( gl_transform_attrib ); + memcpy( attr, &ctx->Transform, sizeof(struct gl_transform_attrib) ); + save_attrib_data(&head, GL_TRANSFORM_BIT, attr); + } + + if (mask & GL_VIEWPORT_BIT) { + struct gl_viewport_attrib *attr; + attr = MALLOC_STRUCT( gl_viewport_attrib ); + memcpy( attr, &ctx->Viewport, sizeof(struct gl_viewport_attrib) ); + save_attrib_data(&head, GL_VIEWPORT_BIT, attr); + } + + /* GL_ARB_multisample */ + if (mask & GL_MULTISAMPLE_BIT_ARB) { + struct gl_multisample_attrib *attr; + attr = MALLOC_STRUCT( gl_multisample_attrib ); + memcpy( attr, &ctx->Multisample, sizeof(struct gl_multisample_attrib) ); + save_attrib_data(&head, GL_MULTISAMPLE_BIT_ARB, attr); + } + +end: + ctx->AttribStack[ctx->AttribStackDepth] = head; + ctx->AttribStackDepth++; +} + + + +static void +pop_enable_group(struct gl_context *ctx, const struct gl_enable_attrib *enable) +{ + const GLuint curTexUnitSave = ctx->Texture.CurrentUnit; + GLuint i; + +#define TEST_AND_UPDATE(VALUE, NEWVALUE, ENUM) \ + if ((VALUE) != (NEWVALUE)) { \ + _mesa_set_enable( ctx, ENUM, (NEWVALUE) ); \ + } + + TEST_AND_UPDATE(ctx->Color.AlphaEnabled, enable->AlphaTest, GL_ALPHA_TEST); + if (ctx->Color.BlendEnabled != enable->Blend) { + if (ctx->Extensions.EXT_draw_buffers2) { + GLuint i; + for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { + _mesa_set_enablei(ctx, GL_BLEND, i, (enable->Blend >> i) & 1); + } + } + else { + _mesa_set_enable(ctx, GL_BLEND, (enable->Blend & 1)); + } + } + + for (i=0;iTransform.ClipPlanesEnabled & mask) != (enable->ClipPlanes & mask)) + _mesa_set_enable(ctx, (GLenum) (GL_CLIP_PLANE0 + i), + (GLboolean) ((enable->ClipPlanes & mask) ? GL_TRUE : GL_FALSE)); + } + + TEST_AND_UPDATE(ctx->Light.ColorMaterialEnabled, enable->ColorMaterial, + GL_COLOR_MATERIAL); + TEST_AND_UPDATE(ctx->Polygon.CullFlag, enable->CullFace, GL_CULL_FACE); + TEST_AND_UPDATE(ctx->Transform.DepthClamp, enable->DepthClamp, + GL_DEPTH_CLAMP); + TEST_AND_UPDATE(ctx->Depth.Test, enable->DepthTest, GL_DEPTH_TEST); + TEST_AND_UPDATE(ctx->Color.DitherFlag, enable->Dither, GL_DITHER); + TEST_AND_UPDATE(ctx->Fog.Enabled, enable->Fog, GL_FOG); + TEST_AND_UPDATE(ctx->Light.Enabled, enable->Lighting, GL_LIGHTING); + TEST_AND_UPDATE(ctx->Line.SmoothFlag, enable->LineSmooth, GL_LINE_SMOOTH); + TEST_AND_UPDATE(ctx->Line.StippleFlag, enable->LineStipple, + GL_LINE_STIPPLE); + TEST_AND_UPDATE(ctx->Color.IndexLogicOpEnabled, enable->IndexLogicOp, + GL_INDEX_LOGIC_OP); + TEST_AND_UPDATE(ctx->Color.ColorLogicOpEnabled, enable->ColorLogicOp, + GL_COLOR_LOGIC_OP); + + TEST_AND_UPDATE(ctx->Eval.Map1Color4, enable->Map1Color4, GL_MAP1_COLOR_4); + TEST_AND_UPDATE(ctx->Eval.Map1Index, enable->Map1Index, GL_MAP1_INDEX); + TEST_AND_UPDATE(ctx->Eval.Map1Normal, enable->Map1Normal, GL_MAP1_NORMAL); + TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord1, enable->Map1TextureCoord1, + GL_MAP1_TEXTURE_COORD_1); + TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord2, enable->Map1TextureCoord2, + GL_MAP1_TEXTURE_COORD_2); + TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord3, enable->Map1TextureCoord3, + GL_MAP1_TEXTURE_COORD_3); + TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord4, enable->Map1TextureCoord4, + GL_MAP1_TEXTURE_COORD_4); + TEST_AND_UPDATE(ctx->Eval.Map1Vertex3, enable->Map1Vertex3, + GL_MAP1_VERTEX_3); + TEST_AND_UPDATE(ctx->Eval.Map1Vertex4, enable->Map1Vertex4, + GL_MAP1_VERTEX_4); + for (i = 0; i < 16; i++) { + TEST_AND_UPDATE(ctx->Eval.Map1Attrib[i], enable->Map1Attrib[i], + GL_MAP1_VERTEX_ATTRIB0_4_NV + i); + } + + TEST_AND_UPDATE(ctx->Eval.Map2Color4, enable->Map2Color4, GL_MAP2_COLOR_4); + TEST_AND_UPDATE(ctx->Eval.Map2Index, enable->Map2Index, GL_MAP2_INDEX); + TEST_AND_UPDATE(ctx->Eval.Map2Normal, enable->Map2Normal, GL_MAP2_NORMAL); + TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord1, enable->Map2TextureCoord1, + GL_MAP2_TEXTURE_COORD_1); + TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord2, enable->Map2TextureCoord2, + GL_MAP2_TEXTURE_COORD_2); + TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord3, enable->Map2TextureCoord3, + GL_MAP2_TEXTURE_COORD_3); + TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord4, enable->Map2TextureCoord4, + GL_MAP2_TEXTURE_COORD_4); + TEST_AND_UPDATE(ctx->Eval.Map2Vertex3, enable->Map2Vertex3, + GL_MAP2_VERTEX_3); + TEST_AND_UPDATE(ctx->Eval.Map2Vertex4, enable->Map2Vertex4, + GL_MAP2_VERTEX_4); + for (i = 0; i < 16; i++) { + TEST_AND_UPDATE(ctx->Eval.Map2Attrib[i], enable->Map2Attrib[i], + GL_MAP2_VERTEX_ATTRIB0_4_NV + i); + } + + TEST_AND_UPDATE(ctx->Eval.AutoNormal, enable->AutoNormal, GL_AUTO_NORMAL); + TEST_AND_UPDATE(ctx->Transform.Normalize, enable->Normalize, GL_NORMALIZE); + TEST_AND_UPDATE(ctx->Transform.RescaleNormals, enable->RescaleNormals, + GL_RESCALE_NORMAL_EXT); + TEST_AND_UPDATE(ctx->Transform.RasterPositionUnclipped, + enable->RasterPositionUnclipped, + GL_RASTER_POSITION_UNCLIPPED_IBM); + TEST_AND_UPDATE(ctx->Point.SmoothFlag, enable->PointSmooth, + GL_POINT_SMOOTH); + if (ctx->Extensions.NV_point_sprite || ctx->Extensions.ARB_point_sprite) { + TEST_AND_UPDATE(ctx->Point.PointSprite, enable->PointSprite, + GL_POINT_SPRITE_NV); + } + TEST_AND_UPDATE(ctx->Polygon.OffsetPoint, enable->PolygonOffsetPoint, + GL_POLYGON_OFFSET_POINT); + TEST_AND_UPDATE(ctx->Polygon.OffsetLine, enable->PolygonOffsetLine, + GL_POLYGON_OFFSET_LINE); + TEST_AND_UPDATE(ctx->Polygon.OffsetFill, enable->PolygonOffsetFill, + GL_POLYGON_OFFSET_FILL); + TEST_AND_UPDATE(ctx->Polygon.SmoothFlag, enable->PolygonSmooth, + GL_POLYGON_SMOOTH); + TEST_AND_UPDATE(ctx->Polygon.StippleFlag, enable->PolygonStipple, + GL_POLYGON_STIPPLE); + TEST_AND_UPDATE(ctx->Scissor.Enabled, enable->Scissor, GL_SCISSOR_TEST); + TEST_AND_UPDATE(ctx->Stencil.Enabled, enable->Stencil, GL_STENCIL_TEST); + if (ctx->Extensions.EXT_stencil_two_side) { + TEST_AND_UPDATE(ctx->Stencil.TestTwoSide, enable->StencilTwoSide, GL_STENCIL_TEST_TWO_SIDE_EXT); + } + TEST_AND_UPDATE(ctx->Multisample.Enabled, enable->MultisampleEnabled, + GL_MULTISAMPLE_ARB); + TEST_AND_UPDATE(ctx->Multisample.SampleAlphaToCoverage, + enable->SampleAlphaToCoverage, + GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); + TEST_AND_UPDATE(ctx->Multisample.SampleAlphaToOne, + enable->SampleAlphaToOne, + GL_SAMPLE_ALPHA_TO_ONE_ARB); + TEST_AND_UPDATE(ctx->Multisample.SampleCoverage, + enable->SampleCoverage, + GL_SAMPLE_COVERAGE_ARB); + TEST_AND_UPDATE(ctx->Multisample.SampleCoverageInvert, + enable->SampleCoverageInvert, + GL_SAMPLE_COVERAGE_INVERT_ARB); + /* GL_ARB_vertex_program, GL_NV_vertex_program */ + TEST_AND_UPDATE(ctx->VertexProgram.Enabled, + enable->VertexProgram, + GL_VERTEX_PROGRAM_ARB); + TEST_AND_UPDATE(ctx->VertexProgram.PointSizeEnabled, + enable->VertexProgramPointSize, + GL_VERTEX_PROGRAM_POINT_SIZE_ARB); + TEST_AND_UPDATE(ctx->VertexProgram.TwoSideEnabled, + enable->VertexProgramTwoSide, + GL_VERTEX_PROGRAM_TWO_SIDE_ARB); + +#undef TEST_AND_UPDATE + + /* texture unit enables */ + for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { + const GLbitfield enabled = enable->Texture[i]; + const GLbitfield genEnabled = enable->TexGen[i]; + + if (ctx->Texture.Unit[i].Enabled != enabled) { + _mesa_ActiveTextureARB(GL_TEXTURE0 + i); + + _mesa_set_enable(ctx, GL_TEXTURE_1D, + (enabled & TEXTURE_1D_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_2D, + (enabled & TEXTURE_2D_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_3D, + (enabled & TEXTURE_3D_BIT) ? GL_TRUE : GL_FALSE); + if (ctx->Extensions.NV_texture_rectangle) { + _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE_ARB, + (enabled & TEXTURE_RECT_BIT) ? GL_TRUE : GL_FALSE); + } + if (ctx->Extensions.ARB_texture_cube_map) { + _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, + (enabled & TEXTURE_CUBE_BIT) ? GL_TRUE : GL_FALSE); + } + if (ctx->Extensions.MESA_texture_array) { + _mesa_set_enable(ctx, GL_TEXTURE_1D_ARRAY_EXT, + (enabled & TEXTURE_1D_ARRAY_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_2D_ARRAY_EXT, + (enabled & TEXTURE_2D_ARRAY_BIT) ? GL_TRUE : GL_FALSE); + } + } + + if (ctx->Texture.Unit[i].TexGenEnabled != genEnabled) { + _mesa_ActiveTextureARB(GL_TEXTURE0 + i); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, + (genEnabled & S_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, + (genEnabled & T_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, + (genEnabled & R_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, + (genEnabled & Q_BIT) ? GL_TRUE : GL_FALSE); + } + } + + _mesa_ActiveTextureARB(GL_TEXTURE0 + curTexUnitSave); +} + + +/** + * Pop/restore texture attribute/group state. + */ +static void +pop_texture_group(struct gl_context *ctx, struct texture_state *texstate) +{ + GLuint u; + + _mesa_lock_context_textures(ctx); + + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + const struct gl_texture_unit *unit = &texstate->Texture.Unit[u]; + GLuint tgt; + + _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + u); + _mesa_set_enable(ctx, GL_TEXTURE_1D, + (unit->Enabled & TEXTURE_1D_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_2D, + (unit->Enabled & TEXTURE_2D_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_3D, + (unit->Enabled & TEXTURE_3D_BIT) ? GL_TRUE : GL_FALSE); + if (ctx->Extensions.ARB_texture_cube_map) { + _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP_ARB, + (unit->Enabled & TEXTURE_CUBE_BIT) ? GL_TRUE : GL_FALSE); + } + if (ctx->Extensions.NV_texture_rectangle) { + _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE_NV, + (unit->Enabled & TEXTURE_RECT_BIT) ? GL_TRUE : GL_FALSE); + } + if (ctx->Extensions.MESA_texture_array) { + _mesa_set_enable(ctx, GL_TEXTURE_1D_ARRAY_EXT, + (unit->Enabled & TEXTURE_1D_ARRAY_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_2D_ARRAY_EXT, + (unit->Enabled & TEXTURE_2D_ARRAY_BIT) ? GL_TRUE : GL_FALSE); + } + + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->EnvMode); + _mesa_TexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, unit->EnvColor); + _mesa_TexGeni(GL_S, GL_TEXTURE_GEN_MODE, unit->GenS.Mode); + _mesa_TexGeni(GL_T, GL_TEXTURE_GEN_MODE, unit->GenT.Mode); + _mesa_TexGeni(GL_R, GL_TEXTURE_GEN_MODE, unit->GenR.Mode); + _mesa_TexGeni(GL_Q, GL_TEXTURE_GEN_MODE, unit->GenQ.Mode); + _mesa_TexGenfv(GL_S, GL_OBJECT_PLANE, unit->GenS.ObjectPlane); + _mesa_TexGenfv(GL_T, GL_OBJECT_PLANE, unit->GenT.ObjectPlane); + _mesa_TexGenfv(GL_R, GL_OBJECT_PLANE, unit->GenR.ObjectPlane); + _mesa_TexGenfv(GL_Q, GL_OBJECT_PLANE, unit->GenQ.ObjectPlane); + /* Eye plane done differently to avoid re-transformation */ + { + struct gl_texture_unit *destUnit = &ctx->Texture.Unit[u]; + COPY_4FV(destUnit->GenS.EyePlane, unit->GenS.EyePlane); + COPY_4FV(destUnit->GenT.EyePlane, unit->GenT.EyePlane); + COPY_4FV(destUnit->GenR.EyePlane, unit->GenR.EyePlane); + COPY_4FV(destUnit->GenQ.EyePlane, unit->GenQ.EyePlane); + if (ctx->Driver.TexGen) { + ctx->Driver.TexGen(ctx, GL_S, GL_EYE_PLANE, unit->GenS.EyePlane); + ctx->Driver.TexGen(ctx, GL_T, GL_EYE_PLANE, unit->GenT.EyePlane); + ctx->Driver.TexGen(ctx, GL_R, GL_EYE_PLANE, unit->GenR.EyePlane); + ctx->Driver.TexGen(ctx, GL_Q, GL_EYE_PLANE, unit->GenQ.EyePlane); + } + } + _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, + ((unit->TexGenEnabled & S_BIT) ? GL_TRUE : GL_FALSE)); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, + ((unit->TexGenEnabled & T_BIT) ? GL_TRUE : GL_FALSE)); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, + ((unit->TexGenEnabled & R_BIT) ? GL_TRUE : GL_FALSE)); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, + ((unit->TexGenEnabled & Q_BIT) ? GL_TRUE : GL_FALSE)); + if (ctx->Extensions.EXT_texture_lod_bias) { + _mesa_TexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, + GL_TEXTURE_LOD_BIAS_EXT, unit->LodBias); + } + if (ctx->Extensions.EXT_texture_env_combine || + ctx->Extensions.ARB_texture_env_combine) { + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, + unit->Combine.ModeRGB); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, + unit->Combine.ModeA); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, + unit->Combine.SourceRGB[0]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, + unit->Combine.SourceRGB[1]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, + unit->Combine.SourceRGB[2]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, + unit->Combine.SourceA[0]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, + unit->Combine.SourceA[1]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, + unit->Combine.SourceA[2]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, + unit->Combine.OperandRGB[0]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, + unit->Combine.OperandRGB[1]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, + unit->Combine.OperandRGB[2]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, + unit->Combine.OperandA[0]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, + unit->Combine.OperandA[1]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, + unit->Combine.OperandA[2]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, + 1 << unit->Combine.ScaleShiftRGB); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, + 1 << unit->Combine.ScaleShiftA); + } + + /* Restore texture object state for each target */ + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + const struct gl_texture_object *obj = NULL; + GLenum target; + + obj = &texstate->SavedObj[u][tgt]; + + /* don't restore state for unsupported targets to prevent + * raising GL errors. + */ + if (obj->Target == GL_TEXTURE_CUBE_MAP_ARB && + !ctx->Extensions.ARB_texture_cube_map) { + continue; + } + else if (obj->Target == GL_TEXTURE_RECTANGLE_NV && + !ctx->Extensions.NV_texture_rectangle) { + continue; + } + else if ((obj->Target == GL_TEXTURE_1D_ARRAY_EXT || + obj->Target == GL_TEXTURE_2D_ARRAY_EXT) && + !ctx->Extensions.MESA_texture_array) { + continue; + } + + target = obj->Target; + + _mesa_BindTexture(target, obj->Name); + + _mesa_TexParameterfv(target, GL_TEXTURE_BORDER_COLOR, obj->BorderColor.f); + _mesa_TexParameterf(target, GL_TEXTURE_PRIORITY, obj->Priority); + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, obj->WrapS); + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, obj->WrapT); + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_R, obj->WrapR); + _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, obj->MinFilter); + _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, obj->MagFilter); + _mesa_TexParameterf(target, GL_TEXTURE_MIN_LOD, obj->MinLod); + _mesa_TexParameterf(target, GL_TEXTURE_MAX_LOD, obj->MaxLod); + _mesa_TexParameterf(target, GL_TEXTURE_LOD_BIAS, obj->LodBias); + _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, obj->BaseLevel); + if (target != GL_TEXTURE_RECTANGLE_ARB) + _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, obj->MaxLevel); + if (ctx->Extensions.EXT_texture_filter_anisotropic) { + _mesa_TexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, + obj->MaxAnisotropy); + } + if (ctx->Extensions.ARB_shadow_ambient) { + _mesa_TexParameterf(target, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, + obj->CompareFailValue); + } + } + + /* remove saved references to the texture objects */ + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + _mesa_reference_texobj(&texstate->SavedTexRef[u][tgt], NULL); + } + } + + _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + texstate->Texture.CurrentUnit); + + _mesa_unlock_context_textures(ctx); +} + + +/* + * This function is kind of long just because we have to call a lot + * of device driver functions to update device driver state. + * + * XXX As it is now, most of the pop-code calls immediate-mode Mesa functions + * in order to restore GL state. This isn't terribly efficient but it + * ensures that dirty flags and any derived state gets updated correctly. + * We could at least check if the value to restore equals the current value + * and then skip the Mesa call. + */ +void GLAPIENTRY +_mesa_PopAttrib(void) +{ + struct gl_attrib_node *attr, *next; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (ctx->AttribStackDepth == 0) { + _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopAttrib" ); + return; + } + + ctx->AttribStackDepth--; + attr = ctx->AttribStack[ctx->AttribStackDepth]; + + while (attr) { + + if (MESA_VERBOSE & VERBOSE_API) { + _mesa_debug(ctx, "glPopAttrib %s\n", + _mesa_lookup_enum_by_nr(attr->kind)); + } + + switch (attr->kind) { + case GL_ACCUM_BUFFER_BIT: + { + const struct gl_accum_attrib *accum; + accum = (const struct gl_accum_attrib *) attr->data; + _mesa_ClearAccum(accum->ClearColor[0], + accum->ClearColor[1], + accum->ClearColor[2], + accum->ClearColor[3]); + } + break; + case GL_COLOR_BUFFER_BIT: + { + const struct gl_colorbuffer_attrib *color; + + color = (const struct gl_colorbuffer_attrib *) attr->data; + _mesa_ClearIndex((GLfloat) color->ClearIndex); + _mesa_ClearColor(color->ClearColor[0], + color->ClearColor[1], + color->ClearColor[2], + color->ClearColor[3]); + _mesa_IndexMask(color->IndexMask); + if (!ctx->Extensions.EXT_draw_buffers2) { + _mesa_ColorMask((GLboolean) (color->ColorMask[0][0] != 0), + (GLboolean) (color->ColorMask[0][1] != 0), + (GLboolean) (color->ColorMask[0][2] != 0), + (GLboolean) (color->ColorMask[0][3] != 0)); + } + else { + GLuint i; + for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { + _mesa_ColorMaskIndexed(i, + (GLboolean) (color->ColorMask[i][0] != 0), + (GLboolean) (color->ColorMask[i][1] != 0), + (GLboolean) (color->ColorMask[i][2] != 0), + (GLboolean) (color->ColorMask[i][3] != 0)); + } + } + { + /* Need to determine if more than one color output is + * specified. If so, call glDrawBuffersARB, else call + * glDrawBuffer(). This is a subtle, but essential point + * since GL_FRONT (for example) is illegal for the former + * function, but legal for the later. + */ + GLboolean multipleBuffers = GL_FALSE; + GLuint i; + + for (i = 1; i < ctx->Const.MaxDrawBuffers; i++) { + if (color->DrawBuffer[i] != GL_NONE) { + multipleBuffers = GL_TRUE; + break; + } + } + /* Call the API_level functions, not _mesa_drawbuffers() + * since we need to do error checking on the pop'd + * GL_DRAW_BUFFER. + * Ex: if GL_FRONT were pushed, but we're popping with a + * user FBO bound, GL_FRONT will be illegal and we'll need + * to record that error. Per OpenGL ARB decision. + */ + if (multipleBuffers) + _mesa_DrawBuffersARB(ctx->Const.MaxDrawBuffers, + color->DrawBuffer); + else + _mesa_DrawBuffer(color->DrawBuffer[0]); + } + _mesa_set_enable(ctx, GL_ALPHA_TEST, color->AlphaEnabled); + _mesa_AlphaFunc(color->AlphaFunc, color->AlphaRef); + if (ctx->Color.BlendEnabled != color->BlendEnabled) { + if (ctx->Extensions.EXT_draw_buffers2) { + GLuint i; + for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { + _mesa_set_enablei(ctx, GL_BLEND, i, + (color->BlendEnabled >> i) & 1); + } + } + else { + _mesa_set_enable(ctx, GL_BLEND, (color->BlendEnabled & 1)); + } + } + if (ctx->Color._BlendFuncPerBuffer || + ctx->Color._BlendEquationPerBuffer) { + /* set blend per buffer */ + GLuint buf; + for (buf = 0; buf < ctx->Const.MaxDrawBuffers; buf++) { + _mesa_BlendFuncSeparatei(buf, color->Blend[buf].SrcRGB, + color->Blend[buf].DstRGB, + color->Blend[buf].SrcA, + color->Blend[buf].DstA); + _mesa_BlendEquationSeparatei(buf, + color->Blend[buf].EquationRGB, + color->Blend[buf].EquationA); + } + } + else { + /* set same blend modes for all buffers */ + _mesa_BlendFuncSeparateEXT(color->Blend[0].SrcRGB, + color->Blend[0].DstRGB, + color->Blend[0].SrcA, + color->Blend[0].DstA); + /* This special case is because glBlendEquationSeparateEXT + * cannot take GL_LOGIC_OP as a parameter. + */ + if (color->Blend[0].EquationRGB == + color->Blend[0].EquationA) { + _mesa_BlendEquation(color->Blend[0].EquationRGB); + } + else { + _mesa_BlendEquationSeparateEXT( + color->Blend[0].EquationRGB, + color->Blend[0].EquationA); + } + } + _mesa_BlendColor(color->BlendColor[0], + color->BlendColor[1], + color->BlendColor[2], + color->BlendColor[3]); + _mesa_LogicOp(color->LogicOp); + _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, + color->ColorLogicOpEnabled); + _mesa_set_enable(ctx, GL_INDEX_LOGIC_OP, + color->IndexLogicOpEnabled); + _mesa_set_enable(ctx, GL_DITHER, color->DitherFlag); + } + break; + case GL_CURRENT_BIT: + FLUSH_CURRENT( ctx, 0 ); + memcpy( &ctx->Current, attr->data, + sizeof(struct gl_current_attrib) ); + break; + case GL_DEPTH_BUFFER_BIT: + { + const struct gl_depthbuffer_attrib *depth; + depth = (const struct gl_depthbuffer_attrib *) attr->data; + _mesa_DepthFunc(depth->Func); + _mesa_ClearDepth(depth->Clear); + _mesa_set_enable(ctx, GL_DEPTH_TEST, depth->Test); + _mesa_DepthMask(depth->Mask); + } + break; + case GL_ENABLE_BIT: + { + const struct gl_enable_attrib *enable; + enable = (const struct gl_enable_attrib *) attr->data; + pop_enable_group(ctx, enable); + ctx->NewState |= _NEW_ALL; + } + break; + case GL_EVAL_BIT: + memcpy( &ctx->Eval, attr->data, sizeof(struct gl_eval_attrib) ); + ctx->NewState |= _NEW_EVAL; + break; + case GL_FOG_BIT: + { + const struct gl_fog_attrib *fog; + fog = (const struct gl_fog_attrib *) attr->data; + _mesa_set_enable(ctx, GL_FOG, fog->Enabled); + _mesa_Fogfv(GL_FOG_COLOR, fog->Color); + _mesa_Fogf(GL_FOG_DENSITY, fog->Density); + _mesa_Fogf(GL_FOG_START, fog->Start); + _mesa_Fogf(GL_FOG_END, fog->End); + _mesa_Fogf(GL_FOG_INDEX, fog->Index); + _mesa_Fogi(GL_FOG_MODE, fog->Mode); + } + break; + case GL_HINT_BIT: + { + const struct gl_hint_attrib *hint; + hint = (const struct gl_hint_attrib *) attr->data; + _mesa_Hint(GL_PERSPECTIVE_CORRECTION_HINT, + hint->PerspectiveCorrection ); + _mesa_Hint(GL_POINT_SMOOTH_HINT, hint->PointSmooth); + _mesa_Hint(GL_LINE_SMOOTH_HINT, hint->LineSmooth); + _mesa_Hint(GL_POLYGON_SMOOTH_HINT, hint->PolygonSmooth); + _mesa_Hint(GL_FOG_HINT, hint->Fog); + _mesa_Hint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, + hint->ClipVolumeClipping); + _mesa_Hint(GL_TEXTURE_COMPRESSION_HINT_ARB, + hint->TextureCompression); + } + break; + case GL_LIGHTING_BIT: + { + GLuint i; + const struct gl_light_attrib *light; + light = (const struct gl_light_attrib *) attr->data; + /* lighting enable */ + _mesa_set_enable(ctx, GL_LIGHTING, light->Enabled); + /* per-light state */ + if (_math_matrix_is_dirty(ctx->ModelviewMatrixStack.Top)) + _math_matrix_analyse( ctx->ModelviewMatrixStack.Top ); + + for (i = 0; i < ctx->Const.MaxLights; i++) { + const struct gl_light *l = &light->Light[i]; + _mesa_set_enable(ctx, GL_LIGHT0 + i, l->Enabled); + _mesa_light(ctx, i, GL_AMBIENT, l->Ambient); + _mesa_light(ctx, i, GL_DIFFUSE, l->Diffuse); + _mesa_light(ctx, i, GL_SPECULAR, l->Specular ); + _mesa_light(ctx, i, GL_POSITION, l->EyePosition); + _mesa_light(ctx, i, GL_SPOT_DIRECTION, l->SpotDirection); + { + GLfloat p[4] = { 0 }; + p[0] = l->SpotExponent; + _mesa_light(ctx, i, GL_SPOT_EXPONENT, p); + } + { + GLfloat p[4] = { 0 }; + p[0] = l->SpotCutoff; + _mesa_light(ctx, i, GL_SPOT_CUTOFF, p); + } + { + GLfloat p[4] = { 0 }; + p[0] = l->ConstantAttenuation; + _mesa_light(ctx, i, GL_CONSTANT_ATTENUATION, p); + } + { + GLfloat p[4] = { 0 }; + p[0] = l->LinearAttenuation; + _mesa_light(ctx, i, GL_LINEAR_ATTENUATION, p); + } + { + GLfloat p[4] = { 0 }; + p[0] = l->QuadraticAttenuation; + _mesa_light(ctx, i, GL_QUADRATIC_ATTENUATION, p); + } + } + /* light model */ + _mesa_LightModelfv(GL_LIGHT_MODEL_AMBIENT, + light->Model.Ambient); + _mesa_LightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, + (GLfloat) light->Model.LocalViewer); + _mesa_LightModelf(GL_LIGHT_MODEL_TWO_SIDE, + (GLfloat) light->Model.TwoSide); + _mesa_LightModelf(GL_LIGHT_MODEL_COLOR_CONTROL, + (GLfloat) light->Model.ColorControl); + /* shade model */ + _mesa_ShadeModel(light->ShadeModel); + /* color material */ + _mesa_ColorMaterial(light->ColorMaterialFace, + light->ColorMaterialMode); + _mesa_set_enable(ctx, GL_COLOR_MATERIAL, + light->ColorMaterialEnabled); + /* materials */ + memcpy(&ctx->Light.Material, &light->Material, + sizeof(struct gl_material)); + } + break; + case GL_LINE_BIT: + { + const struct gl_line_attrib *line; + line = (const struct gl_line_attrib *) attr->data; + _mesa_set_enable(ctx, GL_LINE_SMOOTH, line->SmoothFlag); + _mesa_set_enable(ctx, GL_LINE_STIPPLE, line->StippleFlag); + _mesa_LineStipple(line->StippleFactor, line->StipplePattern); + _mesa_LineWidth(line->Width); + } + break; + case GL_LIST_BIT: + memcpy( &ctx->List, attr->data, sizeof(struct gl_list_attrib) ); + break; + case GL_PIXEL_MODE_BIT: + memcpy( &ctx->Pixel, attr->data, sizeof(struct gl_pixel_attrib) ); + /* XXX what other pixel state needs to be set by function calls? */ + _mesa_ReadBuffer(ctx->Pixel.ReadBuffer); + ctx->NewState |= _NEW_PIXEL; + break; + case GL_POINT_BIT: + { + const struct gl_point_attrib *point; + point = (const struct gl_point_attrib *) attr->data; + _mesa_PointSize(point->Size); + _mesa_set_enable(ctx, GL_POINT_SMOOTH, point->SmoothFlag); + if (ctx->Extensions.EXT_point_parameters) { + _mesa_PointParameterfv(GL_DISTANCE_ATTENUATION_EXT, + point->Params); + _mesa_PointParameterf(GL_POINT_SIZE_MIN_EXT, + point->MinSize); + _mesa_PointParameterf(GL_POINT_SIZE_MAX_EXT, + point->MaxSize); + _mesa_PointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_EXT, + point->Threshold); + } + if (ctx->Extensions.NV_point_sprite + || ctx->Extensions.ARB_point_sprite) { + GLuint u; + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + _mesa_TexEnvi(GL_POINT_SPRITE_NV, GL_COORD_REPLACE_NV, + (GLint) point->CoordReplace[u]); + } + _mesa_set_enable(ctx, GL_POINT_SPRITE_NV,point->PointSprite); + if (ctx->Extensions.NV_point_sprite) + _mesa_PointParameteri(GL_POINT_SPRITE_R_MODE_NV, + ctx->Point.SpriteRMode); + _mesa_PointParameterf(GL_POINT_SPRITE_COORD_ORIGIN, + (GLfloat)ctx->Point.SpriteOrigin); + } + } + break; + case GL_POLYGON_BIT: + { + const struct gl_polygon_attrib *polygon; + polygon = (const struct gl_polygon_attrib *) attr->data; + _mesa_CullFace(polygon->CullFaceMode); + _mesa_FrontFace(polygon->FrontFace); + _mesa_PolygonMode(GL_FRONT, polygon->FrontMode); + _mesa_PolygonMode(GL_BACK, polygon->BackMode); + _mesa_PolygonOffset(polygon->OffsetFactor, + polygon->OffsetUnits); + _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, polygon->SmoothFlag); + _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, polygon->StippleFlag); + _mesa_set_enable(ctx, GL_CULL_FACE, polygon->CullFlag); + _mesa_set_enable(ctx, GL_POLYGON_OFFSET_POINT, + polygon->OffsetPoint); + _mesa_set_enable(ctx, GL_POLYGON_OFFSET_LINE, + polygon->OffsetLine); + _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, + polygon->OffsetFill); + } + break; + case GL_POLYGON_STIPPLE_BIT: + memcpy( ctx->PolygonStipple, attr->data, 32*sizeof(GLuint) ); + ctx->NewState |= _NEW_POLYGONSTIPPLE; + if (ctx->Driver.PolygonStipple) + ctx->Driver.PolygonStipple( ctx, (const GLubyte *) attr->data ); + break; + case GL_SCISSOR_BIT: + { + const struct gl_scissor_attrib *scissor; + scissor = (const struct gl_scissor_attrib *) attr->data; + _mesa_Scissor(scissor->X, scissor->Y, + scissor->Width, scissor->Height); + _mesa_set_enable(ctx, GL_SCISSOR_TEST, scissor->Enabled); + } + break; + case GL_STENCIL_BUFFER_BIT: + { + const struct gl_stencil_attrib *stencil; + stencil = (const struct gl_stencil_attrib *) attr->data; + _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled); + _mesa_ClearStencil(stencil->Clear); + if (ctx->Extensions.EXT_stencil_two_side) { + _mesa_set_enable(ctx, GL_STENCIL_TEST_TWO_SIDE_EXT, + stencil->TestTwoSide); + _mesa_ActiveStencilFaceEXT(stencil->ActiveFace + ? GL_BACK : GL_FRONT); + } + /* front state */ + _mesa_StencilFuncSeparate(GL_FRONT, + stencil->Function[0], + stencil->Ref[0], + stencil->ValueMask[0]); + _mesa_StencilMaskSeparate(GL_FRONT, stencil->WriteMask[0]); + _mesa_StencilOpSeparate(GL_FRONT, stencil->FailFunc[0], + stencil->ZFailFunc[0], + stencil->ZPassFunc[0]); + /* back state */ + _mesa_StencilFuncSeparate(GL_BACK, + stencil->Function[1], + stencil->Ref[1], + stencil->ValueMask[1]); + _mesa_StencilMaskSeparate(GL_BACK, stencil->WriteMask[1]); + _mesa_StencilOpSeparate(GL_BACK, stencil->FailFunc[1], + stencil->ZFailFunc[1], + stencil->ZPassFunc[1]); + } + break; + case GL_TRANSFORM_BIT: + { + GLuint i; + const struct gl_transform_attrib *xform; + xform = (const struct gl_transform_attrib *) attr->data; + _mesa_MatrixMode(xform->MatrixMode); + if (_math_matrix_is_dirty(ctx->ProjectionMatrixStack.Top)) + _math_matrix_analyse( ctx->ProjectionMatrixStack.Top ); + + /* restore clip planes */ + for (i = 0; i < MAX_CLIP_PLANES; i++) { + const GLuint mask = 1 << i; + const GLfloat *eyePlane = xform->EyeUserPlane[i]; + COPY_4V(ctx->Transform.EyeUserPlane[i], eyePlane); + if (xform->ClipPlanesEnabled & mask) { + _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_TRUE); + } + else { + _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_FALSE); + } + if (ctx->Driver.ClipPlane) + ctx->Driver.ClipPlane( ctx, GL_CLIP_PLANE0 + i, eyePlane ); + } + + /* normalize/rescale */ + if (xform->Normalize != ctx->Transform.Normalize) + _mesa_set_enable(ctx, GL_NORMALIZE,ctx->Transform.Normalize); + if (xform->RescaleNormals != ctx->Transform.RescaleNormals) + _mesa_set_enable(ctx, GL_RESCALE_NORMAL_EXT, + ctx->Transform.RescaleNormals); + if (xform->DepthClamp != ctx->Transform.DepthClamp) + _mesa_set_enable(ctx, GL_DEPTH_CLAMP, + ctx->Transform.DepthClamp); + } + break; + case GL_TEXTURE_BIT: + /* Take care of texture object reference counters */ + { + struct texture_state *texstate + = (struct texture_state *) attr->data; + pop_texture_group(ctx, texstate); + ctx->NewState |= _NEW_TEXTURE; + } + break; + case GL_VIEWPORT_BIT: + { + const struct gl_viewport_attrib *vp; + vp = (const struct gl_viewport_attrib *) attr->data; + _mesa_Viewport(vp->X, vp->Y, vp->Width, vp->Height); + _mesa_DepthRange(vp->Near, vp->Far); + } + break; + case GL_MULTISAMPLE_BIT_ARB: + { + const struct gl_multisample_attrib *ms; + ms = (const struct gl_multisample_attrib *) attr->data; + _mesa_SampleCoverageARB(ms->SampleCoverageValue, + ms->SampleCoverageInvert); + } + break; + + default: + _mesa_problem( ctx, "Bad attrib flag in PopAttrib"); + break; + } + + next = attr->next; + FREE( attr->data ); + FREE( attr ); + attr = next; + } +} + + +/** + * Helper for incrementing/decrementing vertex buffer object reference + * counts when pushing/popping the GL_CLIENT_VERTEX_ARRAY_BIT attribute group. + */ +static void +adjust_buffer_object_ref_counts(struct gl_array_object *arrayObj, GLint step) +{ + GLuint i; + + arrayObj->Vertex.BufferObj->RefCount += step; + arrayObj->Weight.BufferObj->RefCount += step; + arrayObj->Normal.BufferObj->RefCount += step; + arrayObj->Color.BufferObj->RefCount += step; + arrayObj->SecondaryColor.BufferObj->RefCount += step; + arrayObj->FogCoord.BufferObj->RefCount += step; + arrayObj->Index.BufferObj->RefCount += step; + arrayObj->EdgeFlag.BufferObj->RefCount += step; + for (i = 0; i < Elements(arrayObj->TexCoord); i++) + arrayObj->TexCoord[i].BufferObj->RefCount += step; + for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) + arrayObj->VertexAttrib[i].BufferObj->RefCount += step; +} + + +/** + * Copy gl_pixelstore_attrib from src to dst, updating buffer + * object refcounts. + */ +static void +copy_pixelstore(struct gl_context *ctx, + struct gl_pixelstore_attrib *dst, + const struct gl_pixelstore_attrib *src) +{ + dst->Alignment = src->Alignment; + dst->RowLength = src->RowLength; + dst->SkipPixels = src->SkipPixels; + dst->SkipRows = src->SkipRows; + dst->ImageHeight = src->ImageHeight; + dst->SkipImages = src->SkipImages; + dst->SwapBytes = src->SwapBytes; + dst->LsbFirst = src->LsbFirst; + dst->ClientStorage = src->ClientStorage; + dst->Invert = src->Invert; + _mesa_reference_buffer_object(ctx, &dst->BufferObj, src->BufferObj); +} + + +#define GL_CLIENT_PACK_BIT (1<<20) +#define GL_CLIENT_UNPACK_BIT (1<<21) + + +void GLAPIENTRY +_mesa_PushClientAttrib(GLbitfield mask) +{ + struct gl_attrib_node *head; + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (ctx->ClientAttribStackDepth >= MAX_CLIENT_ATTRIB_STACK_DEPTH) { + _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushClientAttrib" ); + return; + } + + /* Build linked list of attribute nodes which save all attribute + * groups specified by the mask. + */ + head = NULL; + + if (mask & GL_CLIENT_PIXEL_STORE_BIT) { + struct gl_pixelstore_attrib *attr; + /* packing attribs */ + attr = CALLOC_STRUCT( gl_pixelstore_attrib ); + copy_pixelstore(ctx, attr, &ctx->Pack); + save_attrib_data(&head, GL_CLIENT_PACK_BIT, attr); + /* unpacking attribs */ + attr = CALLOC_STRUCT( gl_pixelstore_attrib ); + copy_pixelstore(ctx, attr, &ctx->Unpack); + save_attrib_data(&head, GL_CLIENT_UNPACK_BIT, attr); + } + + if (mask & GL_CLIENT_VERTEX_ARRAY_BIT) { + struct gl_array_attrib *attr; + struct gl_array_object *obj; + + attr = MALLOC_STRUCT( gl_array_attrib ); + obj = MALLOC_STRUCT( gl_array_object ); + +#if FEATURE_ARB_vertex_buffer_object + /* increment ref counts since we're copying pointers to these objects */ + ctx->Array.ArrayBufferObj->RefCount++; + ctx->Array.ElementArrayBufferObj->RefCount++; +#endif + + memcpy( attr, &ctx->Array, sizeof(struct gl_array_attrib) ); + memcpy( obj, ctx->Array.ArrayObj, sizeof(struct gl_array_object) ); + + attr->ArrayObj = obj; + + save_attrib_data(&head, GL_CLIENT_VERTEX_ARRAY_BIT, attr); + + /* bump reference counts on buffer objects */ + adjust_buffer_object_ref_counts(ctx->Array.ArrayObj, 1); + } + + ctx->ClientAttribStack[ctx->ClientAttribStackDepth] = head; + ctx->ClientAttribStackDepth++; +} + + + + +void GLAPIENTRY +_mesa_PopClientAttrib(void) +{ + struct gl_attrib_node *node, *next; + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (ctx->ClientAttribStackDepth == 0) { + _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopClientAttrib" ); + return; + } + + ctx->ClientAttribStackDepth--; + node = ctx->ClientAttribStack[ctx->ClientAttribStackDepth]; + + while (node) { + switch (node->kind) { + case GL_CLIENT_PACK_BIT: + { + struct gl_pixelstore_attrib *store = + (struct gl_pixelstore_attrib *) node->data; + copy_pixelstore(ctx, &ctx->Pack, store); + _mesa_reference_buffer_object(ctx, &store->BufferObj, NULL); + } + ctx->NewState |= _NEW_PACKUNPACK; + break; + case GL_CLIENT_UNPACK_BIT: + { + struct gl_pixelstore_attrib *store = + (struct gl_pixelstore_attrib *) node->data; + copy_pixelstore(ctx, &ctx->Unpack, store); + _mesa_reference_buffer_object(ctx, &store->BufferObj, NULL); + } + ctx->NewState |= _NEW_PACKUNPACK; + break; + case GL_CLIENT_VERTEX_ARRAY_BIT: { + struct gl_array_attrib * data = + (struct gl_array_attrib *) node->data; + + adjust_buffer_object_ref_counts(ctx->Array.ArrayObj, -1); + + ctx->Array.ActiveTexture = data->ActiveTexture; + if (data->LockCount != 0) + _mesa_LockArraysEXT(data->LockFirst, data->LockCount); + else if (ctx->Array.LockCount) + _mesa_UnlockArraysEXT(); + + _mesa_BindVertexArrayAPPLE( data->ArrayObj->Name ); + +#if FEATURE_ARB_vertex_buffer_object + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, + data->ArrayBufferObj->Name); + _mesa_BindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, + data->ElementArrayBufferObj->Name); +#endif + + memcpy( ctx->Array.ArrayObj, data->ArrayObj, + sizeof( struct gl_array_object ) ); + + FREE( data->ArrayObj ); + + /* FIXME: Should some bits in ctx->Array->NewState also be set + * FIXME: here? It seems like it should be set to inclusive-or + * FIXME: of the old ArrayObj->_Enabled and the new _Enabled. + */ + + ctx->NewState |= _NEW_ARRAY; + break; + } + default: + _mesa_problem( ctx, "Bad attrib flag in PopClientAttrib"); + break; + } + + next = node->next; + FREE( node->data ); + FREE( node ); + node = next; + } +} + + +void +_mesa_init_attrib_dispatch(struct _glapi_table *disp) +{ + SET_PopAttrib(disp, _mesa_PopAttrib); + SET_PushAttrib(disp, _mesa_PushAttrib); + SET_PopClientAttrib(disp, _mesa_PopClientAttrib); + SET_PushClientAttrib(disp, _mesa_PushClientAttrib); +} + + +#endif /* FEATURE_attrib_stack */ + + +/** + * Free any attribute state data that might be attached to the context. + */ +void +_mesa_free_attrib_data(struct gl_context *ctx) +{ + while (ctx->AttribStackDepth > 0) { + struct gl_attrib_node *attr, *next; + + ctx->AttribStackDepth--; + attr = ctx->AttribStack[ctx->AttribStackDepth]; + + while (attr) { + if (attr->kind == GL_TEXTURE_BIT) { + struct texture_state *texstate = (struct texture_state*)attr->data; + GLuint u, tgt; + /* clear references to the saved texture objects */ + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + _mesa_reference_texobj(&texstate->SavedTexRef[u][tgt], NULL); + } + } + } + else { + /* any other chunks of state that requires special handling? */ + } + + next = attr->next; + free(attr->data); + free(attr); + attr = next; + } + } +} + + +void _mesa_init_attrib( struct gl_context *ctx ) +{ + /* Renderer and client attribute stacks */ + ctx->AttribStackDepth = 0; + ctx->ClientAttribStackDepth = 0; +} diff --git a/mesalib/src/mesa/main/bufferobj.c b/mesalib/src/mesa/main/bufferobj.c index 75afae0ad..35d92616f 100644 --- a/mesalib/src/mesa/main/bufferobj.c +++ b/mesalib/src/mesa/main/bufferobj.c @@ -658,248 +658,6 @@ _mesa_update_default_objects_buffer_objects(struct gl_context *ctx) } -/** - * When we're about to read pixel data out of a PBO (via glDrawPixels, - * glTexImage, etc) or write data into a PBO (via glReadPixels, - * glGetTexImage, etc) we call this function to check that we're not - * going to read out of bounds. - * - * XXX This would also be a convenient time to check that the PBO isn't - * currently mapped. Whoever calls this function should check for that. - * Remember, we can't use a PBO when it's mapped! - * - * If we're not using a PBO, this is a no-op. - * - * \param width width of image to read/write - * \param height height of image to read/write - * \param depth depth of image to read/write - * \param format format of image to read/write - * \param type datatype of image to read/write - * \param ptr the user-provided pointer/offset - * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would - * go out of bounds. - */ -GLboolean -_mesa_validate_pbo_access(GLuint dimensions, - const struct gl_pixelstore_attrib *pack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *ptr) -{ - GLvoid *start, *end; - const GLubyte *sizeAddr; /* buffer size, cast to a pointer */ - - if (!_mesa_is_bufferobj(pack->BufferObj)) - return GL_TRUE; /* no PBO, OK */ - - if (pack->BufferObj->Size == 0) - /* no buffer! */ - return GL_FALSE; - - /* get address of first pixel we'll read */ - start = _mesa_image_address(dimensions, pack, ptr, width, height, - format, type, 0, 0, 0); - - /* get address just past the last pixel we'll read */ - end = _mesa_image_address(dimensions, pack, ptr, width, height, - format, type, depth-1, height-1, width); - - - sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size; - - if ((const GLubyte *) start > sizeAddr) { - /* This will catch negative values / wrap-around */ - return GL_FALSE; - } - if ((const GLubyte *) end > sizeAddr) { - /* Image read goes beyond end of buffer */ - return GL_FALSE; - } - - /* OK! */ - return GL_TRUE; -} - - -/** - * For commands that read from a PBO (glDrawPixels, glTexImage, - * glPolygonStipple, etc), if we're reading from a PBO, map it read-only - * and return the pointer into the PBO. If we're not reading from a - * PBO, return \p src as-is. - * If non-null return, must call _mesa_unmap_pbo_source() when done. - * - * \return NULL if error, else pointer to start of data - */ -const GLvoid * -_mesa_map_pbo_source(struct gl_context *ctx, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *src) -{ - const GLubyte *buf; - - if (_mesa_is_bufferobj(unpack->BufferObj)) { - /* unpack from PBO */ - buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, - GL_READ_ONLY_ARB, - unpack->BufferObj); - if (!buf) - return NULL; - - buf = ADD_POINTERS(buf, src); - } - else { - /* unpack from normal memory */ - buf = src; - } - - return buf; -} - - -/** - * Combine PBO-read validation and mapping. - * If any GL errors are detected, they'll be recorded and NULL returned. - * \sa _mesa_validate_pbo_access - * \sa _mesa_map_pbo_source - * A call to this function should have a matching call to - * _mesa_unmap_pbo_source(). - */ -const GLvoid * -_mesa_map_validate_pbo_source(struct gl_context *ctx, - GLuint dimensions, - const struct gl_pixelstore_attrib *unpack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *ptr, - const char *where) -{ - ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); - - if (!_mesa_is_bufferobj(unpack->BufferObj)) { - /* non-PBO access: no validation to be done */ - return ptr; - } - - if (!_mesa_validate_pbo_access(dimensions, unpack, - width, height, depth, format, type, ptr)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(out of bounds PBO access)", where); - return NULL; - } - - if (_mesa_bufferobj_mapped(unpack->BufferObj)) { - /* buffer is already mapped - that's an error */ - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); - return NULL; - } - - ptr = _mesa_map_pbo_source(ctx, unpack, ptr); - return ptr; -} - - -/** - * Counterpart to _mesa_map_pbo_source() - */ -void -_mesa_unmap_pbo_source(struct gl_context *ctx, - const struct gl_pixelstore_attrib *unpack) -{ - ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */ - if (_mesa_is_bufferobj(unpack->BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, - unpack->BufferObj); - } -} - - -/** - * For commands that write to a PBO (glReadPixels, glGetColorTable, etc), - * if we're writing to a PBO, map it write-only and return the pointer - * into the PBO. If we're not writing to a PBO, return \p dst as-is. - * If non-null return, must call _mesa_unmap_pbo_dest() when done. - * - * \return NULL if error, else pointer to start of data - */ -void * -_mesa_map_pbo_dest(struct gl_context *ctx, - const struct gl_pixelstore_attrib *pack, - GLvoid *dest) -{ - void *buf; - - if (_mesa_is_bufferobj(pack->BufferObj)) { - /* pack into PBO */ - buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, - GL_WRITE_ONLY_ARB, - pack->BufferObj); - if (!buf) - return NULL; - - buf = ADD_POINTERS(buf, dest); - } - else { - /* pack to normal memory */ - buf = dest; - } - - return buf; -} - - -/** - * Combine PBO-write validation and mapping. - * If any GL errors are detected, they'll be recorded and NULL returned. - * \sa _mesa_validate_pbo_access - * \sa _mesa_map_pbo_dest - * A call to this function should have a matching call to - * _mesa_unmap_pbo_dest(). - */ -GLvoid * -_mesa_map_validate_pbo_dest(struct gl_context *ctx, - GLuint dimensions, - const struct gl_pixelstore_attrib *unpack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, GLvoid *ptr, - const char *where) -{ - ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); - - if (!_mesa_is_bufferobj(unpack->BufferObj)) { - /* non-PBO access: no validation to be done */ - return ptr; - } - - if (!_mesa_validate_pbo_access(dimensions, unpack, - width, height, depth, format, type, ptr)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(out of bounds PBO access)", where); - return NULL; - } - - if (_mesa_bufferobj_mapped(unpack->BufferObj)) { - /* buffer is already mapped - that's an error */ - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); - return NULL; - } - - ptr = _mesa_map_pbo_dest(ctx, unpack, ptr); - return ptr; -} - - -/** - * Counterpart to _mesa_map_pbo_dest() - */ -void -_mesa_unmap_pbo_dest(struct gl_context *ctx, - const struct gl_pixelstore_attrib *pack) -{ - ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */ - if (_mesa_is_bufferobj(pack->BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj); - } -} - - /** * Return the gl_buffer_object for the given ID. diff --git a/mesalib/src/mesa/main/bufferobj.h b/mesalib/src/mesa/main/bufferobj.h index cf43ad9a2..91fa073b6 100644 --- a/mesalib/src/mesa/main/bufferobj.h +++ b/mesalib/src/mesa/main/bufferobj.h @@ -1,190 +1,149 @@ -/* - * Mesa 3-D graphics library - * Version: 7.6 - * - * 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. - */ - - - -#ifndef BUFFEROBJ_H -#define BUFFEROBJ_H - - -#include "mfeatures.h" -#include "mtypes.h" - - -/* - * Internal functions - */ - - -/** Is the given buffer object currently mapped? */ -static INLINE GLboolean -_mesa_bufferobj_mapped(const struct gl_buffer_object *obj) -{ - return obj->Pointer != NULL; -} - -/** - * Is the given buffer object a user-created buffer object? - * Mesa uses default buffer objects in several places. Default buffers - * always have Name==0. User created buffers have Name!=0. - */ -static INLINE GLboolean -_mesa_is_bufferobj(const struct gl_buffer_object *obj) -{ - return obj->Name != 0; -} - - -extern void -_mesa_init_buffer_objects( struct gl_context *ctx ); - -extern void -_mesa_free_buffer_objects( struct gl_context *ctx ); - -extern void -_mesa_update_default_objects_buffer_objects(struct gl_context *ctx); - - -extern struct gl_buffer_object * -_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer); - -extern void -_mesa_initialize_buffer_object( struct gl_buffer_object *obj, - GLuint name, GLenum target ); - -extern void -_mesa_reference_buffer_object(struct gl_context *ctx, - struct gl_buffer_object **ptr, - struct gl_buffer_object *bufObj); - -extern GLboolean -_mesa_validate_pbo_access(GLuint dimensions, - const struct gl_pixelstore_attrib *pack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *ptr); - -extern const GLvoid * -_mesa_map_pbo_source(struct gl_context *ctx, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *src); - -extern const GLvoid * -_mesa_map_validate_pbo_source(struct gl_context *ctx, - GLuint dimensions, - const struct gl_pixelstore_attrib *unpack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *ptr, - const char *where); - -extern void -_mesa_unmap_pbo_source(struct gl_context *ctx, - const struct gl_pixelstore_attrib *unpack); - -extern void * -_mesa_map_pbo_dest(struct gl_context *ctx, - const struct gl_pixelstore_attrib *pack, - GLvoid *dest); - -extern GLvoid * -_mesa_map_validate_pbo_dest(struct gl_context *ctx, - GLuint dimensions, - const struct gl_pixelstore_attrib *unpack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, GLvoid *ptr, - const char *where); - -extern void -_mesa_unmap_pbo_dest(struct gl_context *ctx, - const struct gl_pixelstore_attrib *pack); - - -extern void -_mesa_init_buffer_object_functions(struct dd_function_table *driver); - - -/* - * API functions - */ - -extern void GLAPIENTRY -_mesa_BindBufferARB(GLenum target, GLuint buffer); - -extern void GLAPIENTRY -_mesa_DeleteBuffersARB(GLsizei n, const GLuint * buffer); - -extern void GLAPIENTRY -_mesa_GenBuffersARB(GLsizei n, GLuint * buffer); - -extern GLboolean GLAPIENTRY -_mesa_IsBufferARB(GLuint buffer); - -extern void GLAPIENTRY -_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage); - -extern void GLAPIENTRY -_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data); - -extern void GLAPIENTRY -_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, void * data); - -extern void * GLAPIENTRY -_mesa_MapBufferARB(GLenum target, GLenum access); - -extern GLboolean GLAPIENTRY -_mesa_UnmapBufferARB(GLenum target); - -extern void GLAPIENTRY -_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params); - -extern void GLAPIENTRY -_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params); - -extern void GLAPIENTRY -_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params); - -extern void GLAPIENTRY -_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, - GLintptr readOffset, GLintptr writeOffset, - GLsizeiptr size); - -extern void * GLAPIENTRY -_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, - GLbitfield access); - -extern void GLAPIENTRY -_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length); - -#if FEATURE_APPLE_object_purgeable -extern GLenum GLAPIENTRY -_mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option); - -extern GLenum GLAPIENTRY -_mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option); - -extern void GLAPIENTRY -_mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname, GLint* params); -#endif - -#endif +/* + * Mesa 3-D graphics library + * Version: 7.6 + * + * 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. + */ + + + +#ifndef BUFFEROBJ_H +#define BUFFEROBJ_H + + +#include "mfeatures.h" +#include "mtypes.h" + + +/* + * Internal functions + */ + + +/** Is the given buffer object currently mapped? */ +static INLINE GLboolean +_mesa_bufferobj_mapped(const struct gl_buffer_object *obj) +{ + return obj->Pointer != NULL; +} + +/** + * Is the given buffer object a user-created buffer object? + * Mesa uses default buffer objects in several places. Default buffers + * always have Name==0. User created buffers have Name!=0. + */ +static INLINE GLboolean +_mesa_is_bufferobj(const struct gl_buffer_object *obj) +{ + return obj->Name != 0; +} + + +extern void +_mesa_init_buffer_objects( struct gl_context *ctx ); + +extern void +_mesa_free_buffer_objects( struct gl_context *ctx ); + +extern void +_mesa_update_default_objects_buffer_objects(struct gl_context *ctx); + + +extern struct gl_buffer_object * +_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer); + +extern void +_mesa_initialize_buffer_object( struct gl_buffer_object *obj, + GLuint name, GLenum target ); + +extern void +_mesa_reference_buffer_object(struct gl_context *ctx, + struct gl_buffer_object **ptr, + struct gl_buffer_object *bufObj); + +extern void +_mesa_init_buffer_object_functions(struct dd_function_table *driver); + + +/* + * API functions + */ + +extern void GLAPIENTRY +_mesa_BindBufferARB(GLenum target, GLuint buffer); + +extern void GLAPIENTRY +_mesa_DeleteBuffersARB(GLsizei n, const GLuint * buffer); + +extern void GLAPIENTRY +_mesa_GenBuffersARB(GLsizei n, GLuint * buffer); + +extern GLboolean GLAPIENTRY +_mesa_IsBufferARB(GLuint buffer); + +extern void GLAPIENTRY +_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage); + +extern void GLAPIENTRY +_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data); + +extern void GLAPIENTRY +_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, void * data); + +extern void * GLAPIENTRY +_mesa_MapBufferARB(GLenum target, GLenum access); + +extern GLboolean GLAPIENTRY +_mesa_UnmapBufferARB(GLenum target); + +extern void GLAPIENTRY +_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params); + +extern void GLAPIENTRY +_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params); + +extern void GLAPIENTRY +_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params); + +extern void GLAPIENTRY +_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, + GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size); + +extern void * GLAPIENTRY +_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, + GLbitfield access); + +extern void GLAPIENTRY +_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length); + +#if FEATURE_APPLE_object_purgeable +extern GLenum GLAPIENTRY +_mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option); + +extern GLenum GLAPIENTRY +_mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option); + +extern void GLAPIENTRY +_mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname, GLint* params); +#endif + +#endif diff --git a/mesalib/src/mesa/main/colortab.c b/mesalib/src/mesa/main/colortab.c index 9c23e253b..d0c865735 100644 --- a/mesalib/src/mesa/main/colortab.c +++ b/mesalib/src/mesa/main/colortab.c @@ -1,934 +1,821 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#include "glheader.h" -#include "bufferobj.h" -#include "colortab.h" -#include "context.h" -#include "image.h" -#include "macros.h" -#include "mfeatures.h" -#include "mtypes.h" -#include "pack.h" -#include "state.h" -#include "teximage.h" -#include "texstate.h" -#include "main/dispatch.h" - - -#if FEATURE_colortable - - -/** - * Given an internalFormat token passed to glColorTable, - * return the corresponding base format. - * Return -1 if invalid token. - */ -static GLint -base_colortab_format( GLenum format ) -{ - switch (format) { - case GL_ALPHA: - case GL_ALPHA4: - case GL_ALPHA8: - case GL_ALPHA12: - case GL_ALPHA16: - return GL_ALPHA; - case GL_LUMINANCE: - case GL_LUMINANCE4: - case GL_LUMINANCE8: - case GL_LUMINANCE12: - case GL_LUMINANCE16: - return GL_LUMINANCE; - case GL_LUMINANCE_ALPHA: - case GL_LUMINANCE4_ALPHA4: - case GL_LUMINANCE6_ALPHA2: - case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE12_ALPHA4: - case GL_LUMINANCE12_ALPHA12: - case GL_LUMINANCE16_ALPHA16: - return GL_LUMINANCE_ALPHA; - case GL_INTENSITY: - case GL_INTENSITY4: - case GL_INTENSITY8: - case GL_INTENSITY12: - case GL_INTENSITY16: - return GL_INTENSITY; - case GL_RGB: - case GL_R3_G3_B2: - case GL_RGB4: - case GL_RGB5: - case GL_RGB8: - case GL_RGB10: - case GL_RGB12: - case GL_RGB16: - return GL_RGB; - case GL_RGBA: - case GL_RGBA2: - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGBA8: - case GL_RGB10_A2: - case GL_RGBA12: - case GL_RGBA16: - return GL_RGBA; - default: - return -1; /* error */ - } -} - - - -/** - * Examine table's format and set the component sizes accordingly. - */ -static void -set_component_sizes( struct gl_color_table *table ) -{ - /* assuming the ubyte table */ - const GLubyte sz = 8; - - switch (table->_BaseFormat) { - case GL_ALPHA: - table->RedSize = 0; - table->GreenSize = 0; - table->BlueSize = 0; - table->AlphaSize = sz; - table->IntensitySize = 0; - table->LuminanceSize = 0; - break; - case GL_LUMINANCE: - table->RedSize = 0; - table->GreenSize = 0; - table->BlueSize = 0; - table->AlphaSize = 0; - table->IntensitySize = 0; - table->LuminanceSize = sz; - break; - case GL_LUMINANCE_ALPHA: - table->RedSize = 0; - table->GreenSize = 0; - table->BlueSize = 0; - table->AlphaSize = sz; - table->IntensitySize = 0; - table->LuminanceSize = sz; - break; - case GL_INTENSITY: - table->RedSize = 0; - table->GreenSize = 0; - table->BlueSize = 0; - table->AlphaSize = 0; - table->IntensitySize = sz; - table->LuminanceSize = 0; - break; - case GL_RGB: - table->RedSize = sz; - table->GreenSize = sz; - table->BlueSize = sz; - table->AlphaSize = 0; - table->IntensitySize = 0; - table->LuminanceSize = 0; - break; - case GL_RGBA: - table->RedSize = sz; - table->GreenSize = sz; - table->BlueSize = sz; - table->AlphaSize = sz; - table->IntensitySize = 0; - table->LuminanceSize = 0; - break; - default: - _mesa_problem(NULL, "unexpected format in set_component_sizes"); - } -} - - - -/** - * Update/replace all or part of a color table. Helper function - * used by _mesa_ColorTable() and _mesa_ColorSubTable(). - * The table->Table buffer should already be allocated. - * \param start first entry to update - * \param count number of entries to update - * \param format format of user-provided table data - * \param type datatype of user-provided table data - * \param data user-provided table data - * \param [rgba]Scale - RGBA scale factors - * \param [rgba]Bias - RGBA bias factors - */ -static void -store_colortable_entries(struct gl_context *ctx, struct gl_color_table *table, - GLsizei start, GLsizei count, - GLenum format, GLenum type, const GLvoid *data, - GLfloat rScale, GLfloat rBias, - GLfloat gScale, GLfloat gBias, - GLfloat bScale, GLfloat bBias, - GLfloat aScale, GLfloat aBias) -{ - data = _mesa_map_validate_pbo_source(ctx, - 1, &ctx->Unpack, count, 1, 1, - format, type, data, - "glColor[Sub]Table"); - if (!data) - return; - - { - /* convert user-provided data to GLfloat values */ - GLfloat tempTab[MAX_COLOR_TABLE_SIZE * 4]; - GLfloat *tableF; - GLint i; - - _mesa_unpack_color_span_float(ctx, - count, /* number of pixels */ - table->_BaseFormat, /* dest format */ - tempTab, /* dest address */ - format, type, /* src format/type */ - data, /* src data */ - &ctx->Unpack, - IMAGE_CLAMP_BIT); /* transfer ops */ - - /* the destination */ - tableF = table->TableF; - - /* Apply scale & bias & clamp now */ - switch (table->_BaseFormat) { - case GL_INTENSITY: - for (i = 0; i < count; i++) { - GLuint j = start + i; - tableF[j] = CLAMP(tempTab[i] * rScale + rBias, 0.0F, 1.0F); - } - break; - case GL_LUMINANCE: - for (i = 0; i < count; i++) { - GLuint j = start + i; - tableF[j] = CLAMP(tempTab[i] * rScale + rBias, 0.0F, 1.0F); - } - break; - case GL_ALPHA: - for (i = 0; i < count; i++) { - GLuint j = start + i; - tableF[j] = CLAMP(tempTab[i] * aScale + aBias, 0.0F, 1.0F); - } - break; - case GL_LUMINANCE_ALPHA: - for (i = 0; i < count; i++) { - GLuint j = start + i; - tableF[j*2+0] = CLAMP(tempTab[i*2+0] * rScale + rBias, 0.0F, 1.0F); - tableF[j*2+1] = CLAMP(tempTab[i*2+1] * aScale + aBias, 0.0F, 1.0F); - } - break; - case GL_RGB: - for (i = 0; i < count; i++) { - GLuint j = start + i; - tableF[j*3+0] = CLAMP(tempTab[i*3+0] * rScale + rBias, 0.0F, 1.0F); - tableF[j*3+1] = CLAMP(tempTab[i*3+1] * gScale + gBias, 0.0F, 1.0F); - tableF[j*3+2] = CLAMP(tempTab[i*3+2] * bScale + bBias, 0.0F, 1.0F); - } - break; - case GL_RGBA: - for (i = 0; i < count; i++) { - GLuint j = start + i; - tableF[j*4+0] = CLAMP(tempTab[i*4+0] * rScale + rBias, 0.0F, 1.0F); - tableF[j*4+1] = CLAMP(tempTab[i*4+1] * gScale + gBias, 0.0F, 1.0F); - tableF[j*4+2] = CLAMP(tempTab[i*4+2] * bScale + bBias, 0.0F, 1.0F); - tableF[j*4+3] = CLAMP(tempTab[i*4+3] * aScale + aBias, 0.0F, 1.0F); - } - break; - default: - _mesa_problem(ctx, "Bad format in store_colortable_entries"); - return; - } - } - - /* update the ubyte table */ - { - const GLint comps = _mesa_components_in_format(table->_BaseFormat); - const GLfloat *tableF = table->TableF + start * comps; - GLubyte *tableUB = table->TableUB + start * comps; - GLint i; - for (i = 0; i < count * comps; i++) { - CLAMPED_FLOAT_TO_UBYTE(tableUB[i], tableF[i]); - } - } - - _mesa_unmap_pbo_source(ctx, &ctx->Unpack); -} - - - -void GLAPIENTRY -_mesa_ColorTable( GLenum target, GLenum internalFormat, - GLsizei width, GLenum format, GLenum type, - const GLvoid *data ) -{ - static const GLfloat one[4] = { 1.0, 1.0, 1.0, 1.0 }; - static const GLfloat zero[4] = { 0.0, 0.0, 0.0, 0.0 }; - GET_CURRENT_CONTEXT(ctx); - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - struct gl_texture_object *texObj = NULL; - struct gl_color_table *table = NULL; - GLboolean proxy = GL_FALSE; - GLint baseFormat; - const GLfloat *scale = one, *bias = zero; - GLint comps; - - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */ - - switch (target) { - case GL_SHARED_TEXTURE_PALETTE_EXT: - table = &ctx->Texture.Palette; - break; - case GL_TEXTURE_COLOR_TABLE_SGI: - if (!ctx->Extensions.SGI_texture_color_table) { - _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(target)"); - return; - } - table = &(texUnit->ColorTable); - scale = ctx->Pixel.TextureColorTableScale; - bias = ctx->Pixel.TextureColorTableBias; - break; - case GL_PROXY_TEXTURE_COLOR_TABLE_SGI: - if (!ctx->Extensions.SGI_texture_color_table) { - _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(target)"); - return; - } - table = &(texUnit->ProxyColorTable); - proxy = GL_TRUE; - break; - default: - /* try texture targets */ - { - struct gl_texture_object *texobj - = _mesa_select_tex_object(ctx, texUnit, target); - if (texobj) { - table = &texobj->Palette; - proxy = _mesa_is_proxy_texture(target); - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(target)"); - return; - } - } - } - - assert(table); - - if (!_mesa_is_legal_format_and_type(ctx, format, type) || - format == GL_INTENSITY) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glColorTable(format or type)"); - return; - } - - baseFormat = base_colortab_format(internalFormat); - if (baseFormat < 0) { - _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(internalFormat)"); - return; - } - - if (width < 0 || (width != 0 && !_mesa_is_pow_two(width))) { - /* error */ - if (proxy) { - table->Size = 0; - table->InternalFormat = (GLenum) 0; - table->_BaseFormat = (GLenum) 0; - } - else { - _mesa_error(ctx, GL_INVALID_VALUE, "glColorTable(width=%d)", width); - } - return; - } - - if (width > (GLsizei) ctx->Const.MaxColorTableSize) { - if (proxy) { - table->Size = 0; - table->InternalFormat = (GLenum) 0; - table->_BaseFormat = (GLenum) 0; - } - else { - _mesa_error(ctx, GL_TABLE_TOO_LARGE, "glColorTable(width)"); - } - return; - } - - table->Size = width; - table->InternalFormat = internalFormat; - table->_BaseFormat = (GLenum) baseFormat; - - comps = _mesa_components_in_format(table->_BaseFormat); - assert(comps > 0); /* error should have been caught sooner */ - - if (!proxy) { - _mesa_free_colortable_data(table); - - if (width > 0) { - table->TableF = (GLfloat *) malloc(comps * width * sizeof(GLfloat)); - table->TableUB = (GLubyte *) malloc(comps * width * sizeof(GLubyte)); - - if (!table->TableF || !table->TableUB) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glColorTable"); - return; - } - - store_colortable_entries(ctx, table, - 0, width, /* start, count */ - format, type, data, - scale[0], bias[0], - scale[1], bias[1], - scale[2], bias[2], - scale[3], bias[3]); - } - } /* proxy */ - - /* do this after the table's Type and Format are set */ - set_component_sizes(table); - - if (texObj || target == GL_SHARED_TEXTURE_PALETTE_EXT) { - /* texture object palette, texObj==NULL means the shared palette */ - if (ctx->Driver.UpdateTexturePalette) { - (*ctx->Driver.UpdateTexturePalette)( ctx, texObj ); - } - } - - ctx->NewState |= _NEW_PIXEL; -} - - - -void GLAPIENTRY -_mesa_ColorSubTable( GLenum target, GLsizei start, - GLsizei count, GLenum format, GLenum type, - const GLvoid *data ) -{ - static const GLfloat one[4] = { 1.0, 1.0, 1.0, 1.0 }; - static const GLfloat zero[4] = { 0.0, 0.0, 0.0, 0.0 }; - GET_CURRENT_CONTEXT(ctx); - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - struct gl_texture_object *texObj = NULL; - struct gl_color_table *table = NULL; - const GLfloat *scale = one, *bias = zero; - - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - switch (target) { - case GL_SHARED_TEXTURE_PALETTE_EXT: - table = &ctx->Texture.Palette; - break; - case GL_TEXTURE_COLOR_TABLE_SGI: - if (!ctx->Extensions.SGI_texture_color_table) { - _mesa_error(ctx, GL_INVALID_ENUM, "glColorSubTable(target)"); - return; - } - table = &(texUnit->ColorTable); - scale = ctx->Pixel.TextureColorTableScale; - bias = ctx->Pixel.TextureColorTableBias; - break; - default: - /* try texture targets */ - texObj = _mesa_select_tex_object(ctx, texUnit, target); - if (texObj && !_mesa_is_proxy_texture(target)) { - table = &texObj->Palette; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glColorSubTable(target)"); - return; - } - } - - assert(table); - - if (!_mesa_is_legal_format_and_type(ctx, format, type) || - format == GL_INTENSITY) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glColorSubTable(format or type)"); - return; - } - - if (count < 1) { - _mesa_error(ctx, GL_INVALID_VALUE, "glColorSubTable(count)"); - return; - } - - /* error should have been caught sooner */ - assert(_mesa_components_in_format(table->_BaseFormat) > 0); - - if (start + count > (GLint) table->Size) { - _mesa_error(ctx, GL_INVALID_VALUE, "glColorSubTable(count)"); - return; - } - - if (!table->TableF || !table->TableUB) { - /* a GL_OUT_OF_MEMORY error would have been recorded previously */ - return; - } - - store_colortable_entries(ctx, table, start, count, - format, type, data, - scale[0], bias[0], - scale[1], bias[1], - scale[2], bias[2], - scale[3], bias[3]); - - if (texObj || target == GL_SHARED_TEXTURE_PALETTE_EXT) { - /* per-texture object palette */ - if (ctx->Driver.UpdateTexturePalette) { - (*ctx->Driver.UpdateTexturePalette)( ctx, texObj ); - } - } - - ctx->NewState |= _NEW_PIXEL; -} - - - -static void GLAPIENTRY -_mesa_CopyColorTable(GLenum target, GLenum internalformat, - GLint x, GLint y, GLsizei width) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (!ctx->ReadBuffer->_ColorReadBuffer) { - return; /* no readbuffer - OK */ - } - - ctx->Driver.CopyColorTable( ctx, target, internalformat, x, y, width ); -} - - - -static void GLAPIENTRY -_mesa_CopyColorSubTable(GLenum target, GLsizei start, - GLint x, GLint y, GLsizei width) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (!ctx->ReadBuffer->_ColorReadBuffer) { - return; /* no readbuffer - OK */ - } - - ctx->Driver.CopyColorSubTable( ctx, target, start, x, y, width ); -} - - - -static void GLAPIENTRY -_mesa_GetColorTable( GLenum target, GLenum format, - GLenum type, GLvoid *data ) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - struct gl_color_table *table = NULL; - GLfloat rgba[MAX_COLOR_TABLE_SIZE][4]; - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (ctx->NewState) { - _mesa_update_state(ctx); - } - - switch (target) { - case GL_SHARED_TEXTURE_PALETTE_EXT: - table = &ctx->Texture.Palette; - break; - case GL_TEXTURE_COLOR_TABLE_SGI: - if (!ctx->Extensions.SGI_texture_color_table) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTable(target)"); - return; - } - table = &(texUnit->ColorTable); - break; - default: - /* try texture targets */ - { - struct gl_texture_object *texobj - = _mesa_select_tex_object(ctx, texUnit, target); - if (texobj && !_mesa_is_proxy_texture(target)) { - table = &texobj->Palette; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTable(target)"); - return; - } - } - } - - ASSERT(table); - - if (table->Size <= 0) { - return; - } - - switch (table->_BaseFormat) { - case GL_ALPHA: - { - GLuint i; - for (i = 0; i < table->Size; i++) { - rgba[i][RCOMP] = 0; - rgba[i][GCOMP] = 0; - rgba[i][BCOMP] = 0; - rgba[i][ACOMP] = table->TableF[i]; - } - } - break; - case GL_LUMINANCE: - { - GLuint i; - for (i = 0; i < table->Size; i++) { - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = table->TableF[i]; - rgba[i][ACOMP] = 1.0F; - } - } - break; - case GL_LUMINANCE_ALPHA: - { - GLuint i; - for (i = 0; i < table->Size; i++) { - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = table->TableF[i*2+0]; - rgba[i][ACOMP] = table->TableF[i*2+1]; - } - } - break; - case GL_INTENSITY: - { - GLuint i; - for (i = 0; i < table->Size; i++) { - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = - rgba[i][ACOMP] = table->TableF[i]; - } - } - break; - case GL_RGB: - { - GLuint i; - for (i = 0; i < table->Size; i++) { - rgba[i][RCOMP] = table->TableF[i*3+0]; - rgba[i][GCOMP] = table->TableF[i*3+1]; - rgba[i][BCOMP] = table->TableF[i*3+2]; - rgba[i][ACOMP] = 1.0F; - } - } - break; - case GL_RGBA: - memcpy(rgba, table->TableF, 4 * table->Size * sizeof(GLfloat)); - break; - default: - _mesa_problem(ctx, "bad table format in glGetColorTable"); - return; - } - - data = _mesa_map_validate_pbo_dest(ctx, - 1, &ctx->Pack, table->Size, 1, 1, - format, type, data, - "glGetColorTable"); - if (!data) - return; - - _mesa_pack_rgba_span_float(ctx, table->Size, rgba, - format, type, data, &ctx->Pack, 0x0); - - _mesa_unmap_pbo_dest(ctx, &ctx->Pack); -} - - - -static void GLAPIENTRY -_mesa_ColorTableParameterfv(GLenum target, GLenum pname, const GLfloat *params) -{ - GLfloat *scale, *bias; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - switch (target) { - case GL_TEXTURE_COLOR_TABLE_SGI: - scale = ctx->Pixel.TextureColorTableScale; - bias = ctx->Pixel.TextureColorTableBias; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glColorTableParameter(target)"); - return; - } - - if (pname == GL_COLOR_TABLE_SCALE_SGI) { - COPY_4V(scale, params); - } - else if (pname == GL_COLOR_TABLE_BIAS_SGI) { - COPY_4V(bias, params); - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glColorTableParameterfv(pname)"); - return; - } - - ctx->NewState |= _NEW_PIXEL; -} - - - -static void GLAPIENTRY -_mesa_ColorTableParameteriv(GLenum target, GLenum pname, const GLint *params) -{ - GLfloat fparams[4]; - if (pname == GL_TEXTURE_COLOR_TABLE_SGI) { - /* four values */ - fparams[0] = (GLfloat) params[0]; - fparams[1] = (GLfloat) params[1]; - fparams[2] = (GLfloat) params[2]; - fparams[3] = (GLfloat) params[3]; - } - else { - /* one values */ - fparams[0] = (GLfloat) params[0]; - } - _mesa_ColorTableParameterfv(target, pname, fparams); -} - - - -static void GLAPIENTRY -_mesa_GetColorTableParameterfv( GLenum target, GLenum pname, GLfloat *params ) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - struct gl_color_table *table = NULL; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - switch (target) { - case GL_SHARED_TEXTURE_PALETTE_EXT: - table = &ctx->Texture.Palette; - break; - case GL_TEXTURE_COLOR_TABLE_SGI: - if (!ctx->Extensions.SGI_texture_color_table) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameter(target)"); - return; - } - table = &(texUnit->ColorTable); - if (pname == GL_COLOR_TABLE_SCALE_SGI) { - COPY_4V(params, ctx->Pixel.TextureColorTableScale); - return; - } - else if (pname == GL_COLOR_TABLE_BIAS_SGI) { - COPY_4V(params, ctx->Pixel.TextureColorTableBias); - return; - } - break; - case GL_PROXY_TEXTURE_COLOR_TABLE_SGI: - if (!ctx->Extensions.SGI_texture_color_table) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameter(target)"); - return; - } - table = &(texUnit->ProxyColorTable); - break; - default: - /* try texture targets */ - { - struct gl_texture_object *texobj - = _mesa_select_tex_object(ctx, texUnit, target); - if (texobj) { - table = &texobj->Palette; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetColorTableParameterfv(target)"); - return; - } - } - } - - assert(table); - - switch (pname) { - case GL_COLOR_TABLE_FORMAT: - *params = (GLfloat) table->InternalFormat; - break; - case GL_COLOR_TABLE_WIDTH: - *params = (GLfloat) table->Size; - break; - case GL_COLOR_TABLE_RED_SIZE: - *params = (GLfloat) table->RedSize; - break; - case GL_COLOR_TABLE_GREEN_SIZE: - *params = (GLfloat) table->GreenSize; - break; - case GL_COLOR_TABLE_BLUE_SIZE: - *params = (GLfloat) table->BlueSize; - break; - case GL_COLOR_TABLE_ALPHA_SIZE: - *params = (GLfloat) table->AlphaSize; - break; - case GL_COLOR_TABLE_LUMINANCE_SIZE: - *params = (GLfloat) table->LuminanceSize; - break; - case GL_COLOR_TABLE_INTENSITY_SIZE: - *params = (GLfloat) table->IntensitySize; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameterfv(pname)" ); - return; - } -} - - - -static void GLAPIENTRY -_mesa_GetColorTableParameteriv( GLenum target, GLenum pname, GLint *params ) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - struct gl_color_table *table = NULL; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - switch (target) { - case GL_SHARED_TEXTURE_PALETTE_EXT: - table = &ctx->Texture.Palette; - break; - case GL_TEXTURE_COLOR_TABLE_SGI: - if (!ctx->Extensions.SGI_texture_color_table) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameter(target)"); - return; - } - table = &(texUnit->ColorTable); - if (pname == GL_COLOR_TABLE_SCALE_SGI) { - params[0] = (GLint) ctx->Pixel.TextureColorTableScale[0]; - params[1] = (GLint) ctx->Pixel.TextureColorTableScale[1]; - params[2] = (GLint) ctx->Pixel.TextureColorTableScale[2]; - params[3] = (GLint) ctx->Pixel.TextureColorTableScale[3]; - return; - } - else if (pname == GL_COLOR_TABLE_BIAS_SGI) { - params[0] = (GLint) ctx->Pixel.TextureColorTableBias[0]; - params[1] = (GLint) ctx->Pixel.TextureColorTableBias[1]; - params[2] = (GLint) ctx->Pixel.TextureColorTableBias[2]; - params[3] = (GLint) ctx->Pixel.TextureColorTableBias[3]; - return; - } - break; - case GL_PROXY_TEXTURE_COLOR_TABLE_SGI: - if (!ctx->Extensions.SGI_texture_color_table) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameter(target)"); - return; - } - table = &(texUnit->ProxyColorTable); - break; - default: - /* Try texture targets */ - { - struct gl_texture_object *texobj - = _mesa_select_tex_object(ctx, texUnit, target); - if (texobj) { - table = &texobj->Palette; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetColorTableParameteriv(target)"); - return; - } - } - } - - assert(table); - - switch (pname) { - case GL_COLOR_TABLE_FORMAT: - *params = table->InternalFormat; - break; - case GL_COLOR_TABLE_WIDTH: - *params = table->Size; - break; - case GL_COLOR_TABLE_RED_SIZE: - *params = table->RedSize; - break; - case GL_COLOR_TABLE_GREEN_SIZE: - *params = table->GreenSize; - break; - case GL_COLOR_TABLE_BLUE_SIZE: - *params = table->BlueSize; - break; - case GL_COLOR_TABLE_ALPHA_SIZE: - *params = table->AlphaSize; - break; - case GL_COLOR_TABLE_LUMINANCE_SIZE: - *params = table->LuminanceSize; - break; - case GL_COLOR_TABLE_INTENSITY_SIZE: - *params = table->IntensitySize; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameteriv(pname)" ); - return; - } -} - - -void -_mesa_init_colortable_dispatch(struct _glapi_table *disp) -{ - SET_ColorSubTable(disp, _mesa_ColorSubTable); - SET_ColorTable(disp, _mesa_ColorTable); - SET_ColorTableParameterfv(disp, _mesa_ColorTableParameterfv); - SET_ColorTableParameteriv(disp, _mesa_ColorTableParameteriv); - SET_CopyColorSubTable(disp, _mesa_CopyColorSubTable); - SET_CopyColorTable(disp, _mesa_CopyColorTable); - SET_GetColorTable(disp, _mesa_GetColorTable); - SET_GetColorTableParameterfv(disp, _mesa_GetColorTableParameterfv); - SET_GetColorTableParameteriv(disp, _mesa_GetColorTableParameteriv); -} - - -#endif /* FEATURE_colortable */ - - -/**********************************************************************/ -/***** Initialization *****/ -/**********************************************************************/ - - -void -_mesa_init_colortable( struct gl_color_table *p ) -{ - p->TableF = NULL; - p->TableUB = NULL; - p->Size = 0; - p->InternalFormat = GL_RGBA; -} - - - -void -_mesa_free_colortable_data( struct gl_color_table *p ) -{ - if (p->TableF) { - free(p->TableF); - p->TableF = NULL; - } - if (p->TableUB) { - free(p->TableUB); - p->TableUB = NULL; - } -} +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include "glheader.h" +#include "bufferobj.h" +#include "colortab.h" +#include "context.h" +#include "image.h" +#include "macros.h" +#include "mfeatures.h" +#include "mtypes.h" +#include "pack.h" +#include "pbo.h" +#include "state.h" +#include "teximage.h" +#include "texstate.h" +#include "main/dispatch.h" + + +#if FEATURE_colortable + + +/** + * Given an internalFormat token passed to glColorTable, + * return the corresponding base format. + * Return -1 if invalid token. + */ +static GLint +base_colortab_format( GLenum format ) +{ + switch (format) { + case GL_ALPHA: + case GL_ALPHA4: + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16: + return GL_ALPHA; + case GL_LUMINANCE: + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE4_ALPHA4: + case GL_LUMINANCE6_ALPHA2: + case GL_LUMINANCE8_ALPHA8: + case GL_LUMINANCE12_ALPHA4: + case GL_LUMINANCE12_ALPHA12: + case GL_LUMINANCE16_ALPHA16: + return GL_LUMINANCE_ALPHA; + case GL_INTENSITY: + case GL_INTENSITY4: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + return GL_INTENSITY; + case GL_RGB: + case GL_R3_G3_B2: + case GL_RGB4: + case GL_RGB5: + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + return GL_RGB; + case GL_RGBA: + case GL_RGBA2: + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGBA8: + case GL_RGB10_A2: + case GL_RGBA12: + case GL_RGBA16: + return GL_RGBA; + default: + return -1; /* error */ + } +} + + + +/** + * Examine table's format and set the component sizes accordingly. + */ +static void +set_component_sizes( struct gl_color_table *table ) +{ + /* assuming the ubyte table */ + const GLubyte sz = 8; + + switch (table->_BaseFormat) { + case GL_ALPHA: + table->RedSize = 0; + table->GreenSize = 0; + table->BlueSize = 0; + table->AlphaSize = sz; + table->IntensitySize = 0; + table->LuminanceSize = 0; + break; + case GL_LUMINANCE: + table->RedSize = 0; + table->GreenSize = 0; + table->BlueSize = 0; + table->AlphaSize = 0; + table->IntensitySize = 0; + table->LuminanceSize = sz; + break; + case GL_LUMINANCE_ALPHA: + table->RedSize = 0; + table->GreenSize = 0; + table->BlueSize = 0; + table->AlphaSize = sz; + table->IntensitySize = 0; + table->LuminanceSize = sz; + break; + case GL_INTENSITY: + table->RedSize = 0; + table->GreenSize = 0; + table->BlueSize = 0; + table->AlphaSize = 0; + table->IntensitySize = sz; + table->LuminanceSize = 0; + break; + case GL_RGB: + table->RedSize = sz; + table->GreenSize = sz; + table->BlueSize = sz; + table->AlphaSize = 0; + table->IntensitySize = 0; + table->LuminanceSize = 0; + break; + case GL_RGBA: + table->RedSize = sz; + table->GreenSize = sz; + table->BlueSize = sz; + table->AlphaSize = sz; + table->IntensitySize = 0; + table->LuminanceSize = 0; + break; + default: + _mesa_problem(NULL, "unexpected format in set_component_sizes"); + } +} + + + +/** + * Update/replace all or part of a color table. Helper function + * used by _mesa_ColorTable() and _mesa_ColorSubTable(). + * The table->Table buffer should already be allocated. + * \param start first entry to update + * \param count number of entries to update + * \param format format of user-provided table data + * \param type datatype of user-provided table data + * \param data user-provided table data + * \param [rgba]Scale - RGBA scale factors + * \param [rgba]Bias - RGBA bias factors + */ +static void +store_colortable_entries(struct gl_context *ctx, struct gl_color_table *table, + GLsizei start, GLsizei count, + GLenum format, GLenum type, const GLvoid *data, + GLfloat rScale, GLfloat rBias, + GLfloat gScale, GLfloat gBias, + GLfloat bScale, GLfloat bBias, + GLfloat aScale, GLfloat aBias) +{ + data = _mesa_map_validate_pbo_source(ctx, + 1, &ctx->Unpack, count, 1, 1, + format, type, data, + "glColor[Sub]Table"); + if (!data) + return; + + { + /* convert user-provided data to GLfloat values */ + GLfloat tempTab[MAX_COLOR_TABLE_SIZE * 4]; + GLfloat *tableF; + GLint i; + + _mesa_unpack_color_span_float(ctx, + count, /* number of pixels */ + table->_BaseFormat, /* dest format */ + tempTab, /* dest address */ + format, type, /* src format/type */ + data, /* src data */ + &ctx->Unpack, + IMAGE_CLAMP_BIT); /* transfer ops */ + + /* the destination */ + tableF = table->TableF; + + /* Apply scale & bias & clamp now */ + switch (table->_BaseFormat) { + case GL_INTENSITY: + for (i = 0; i < count; i++) { + GLuint j = start + i; + tableF[j] = CLAMP(tempTab[i] * rScale + rBias, 0.0F, 1.0F); + } + break; + case GL_LUMINANCE: + for (i = 0; i < count; i++) { + GLuint j = start + i; + tableF[j] = CLAMP(tempTab[i] * rScale + rBias, 0.0F, 1.0F); + } + break; + case GL_ALPHA: + for (i = 0; i < count; i++) { + GLuint j = start + i; + tableF[j] = CLAMP(tempTab[i] * aScale + aBias, 0.0F, 1.0F); + } + break; + case GL_LUMINANCE_ALPHA: + for (i = 0; i < count; i++) { + GLuint j = start + i; + tableF[j*2+0] = CLAMP(tempTab[i*2+0] * rScale + rBias, 0.0F, 1.0F); + tableF[j*2+1] = CLAMP(tempTab[i*2+1] * aScale + aBias, 0.0F, 1.0F); + } + break; + case GL_RGB: + for (i = 0; i < count; i++) { + GLuint j = start + i; + tableF[j*3+0] = CLAMP(tempTab[i*3+0] * rScale + rBias, 0.0F, 1.0F); + tableF[j*3+1] = CLAMP(tempTab[i*3+1] * gScale + gBias, 0.0F, 1.0F); + tableF[j*3+2] = CLAMP(tempTab[i*3+2] * bScale + bBias, 0.0F, 1.0F); + } + break; + case GL_RGBA: + for (i = 0; i < count; i++) { + GLuint j = start + i; + tableF[j*4+0] = CLAMP(tempTab[i*4+0] * rScale + rBias, 0.0F, 1.0F); + tableF[j*4+1] = CLAMP(tempTab[i*4+1] * gScale + gBias, 0.0F, 1.0F); + tableF[j*4+2] = CLAMP(tempTab[i*4+2] * bScale + bBias, 0.0F, 1.0F); + tableF[j*4+3] = CLAMP(tempTab[i*4+3] * aScale + aBias, 0.0F, 1.0F); + } + break; + default: + _mesa_problem(ctx, "Bad format in store_colortable_entries"); + return; + } + } + + /* update the ubyte table */ + { + const GLint comps = _mesa_components_in_format(table->_BaseFormat); + const GLfloat *tableF = table->TableF + start * comps; + GLubyte *tableUB = table->TableUB + start * comps; + GLint i; + for (i = 0; i < count * comps; i++) { + CLAMPED_FLOAT_TO_UBYTE(tableUB[i], tableF[i]); + } + } + + _mesa_unmap_pbo_source(ctx, &ctx->Unpack); +} + + + +void GLAPIENTRY +_mesa_ColorTable( GLenum target, GLenum internalFormat, + GLsizei width, GLenum format, GLenum type, + const GLvoid *data ) +{ + static const GLfloat one[4] = { 1.0, 1.0, 1.0, 1.0 }; + static const GLfloat zero[4] = { 0.0, 0.0, 0.0, 0.0 }; + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + struct gl_texture_object *texObj = NULL; + struct gl_color_table *table = NULL; + GLboolean proxy = GL_FALSE; + GLint baseFormat; + const GLfloat *scale = one, *bias = zero; + GLint comps; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */ + + switch (target) { + case GL_SHARED_TEXTURE_PALETTE_EXT: + table = &ctx->Texture.Palette; + break; + default: + /* try texture targets */ + { + struct gl_texture_object *texobj + = _mesa_select_tex_object(ctx, texUnit, target); + if (texobj) { + table = &texobj->Palette; + proxy = _mesa_is_proxy_texture(target); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(target)"); + return; + } + } + } + + assert(table); + + if (!_mesa_is_legal_format_and_type(ctx, format, type) || + format == GL_INTENSITY) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glColorTable(format or type)"); + return; + } + + baseFormat = base_colortab_format(internalFormat); + if (baseFormat < 0) { + _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(internalFormat)"); + return; + } + + if (width < 0 || (width != 0 && !_mesa_is_pow_two(width))) { + /* error */ + if (proxy) { + table->Size = 0; + table->InternalFormat = (GLenum) 0; + table->_BaseFormat = (GLenum) 0; + } + else { + _mesa_error(ctx, GL_INVALID_VALUE, "glColorTable(width=%d)", width); + } + return; + } + + if (width > (GLsizei) ctx->Const.MaxColorTableSize) { + if (proxy) { + table->Size = 0; + table->InternalFormat = (GLenum) 0; + table->_BaseFormat = (GLenum) 0; + } + else { + _mesa_error(ctx, GL_TABLE_TOO_LARGE, "glColorTable(width)"); + } + return; + } + + table->Size = width; + table->InternalFormat = internalFormat; + table->_BaseFormat = (GLenum) baseFormat; + + comps = _mesa_components_in_format(table->_BaseFormat); + assert(comps > 0); /* error should have been caught sooner */ + + if (!proxy) { + _mesa_free_colortable_data(table); + + if (width > 0) { + table->TableF = (GLfloat *) malloc(comps * width * sizeof(GLfloat)); + table->TableUB = (GLubyte *) malloc(comps * width * sizeof(GLubyte)); + + if (!table->TableF || !table->TableUB) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glColorTable"); + return; + } + + store_colortable_entries(ctx, table, + 0, width, /* start, count */ + format, type, data, + scale[0], bias[0], + scale[1], bias[1], + scale[2], bias[2], + scale[3], bias[3]); + } + } /* proxy */ + + /* do this after the table's Type and Format are set */ + set_component_sizes(table); + + if (texObj || target == GL_SHARED_TEXTURE_PALETTE_EXT) { + /* texture object palette, texObj==NULL means the shared palette */ + if (ctx->Driver.UpdateTexturePalette) { + (*ctx->Driver.UpdateTexturePalette)( ctx, texObj ); + } + } + + ctx->NewState |= _NEW_PIXEL; +} + + + +void GLAPIENTRY +_mesa_ColorSubTable( GLenum target, GLsizei start, + GLsizei count, GLenum format, GLenum type, + const GLvoid *data ) +{ + static const GLfloat one[4] = { 1.0, 1.0, 1.0, 1.0 }; + static const GLfloat zero[4] = { 0.0, 0.0, 0.0, 0.0 }; + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + struct gl_texture_object *texObj = NULL; + struct gl_color_table *table = NULL; + const GLfloat *scale = one, *bias = zero; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + switch (target) { + case GL_SHARED_TEXTURE_PALETTE_EXT: + table = &ctx->Texture.Palette; + break; + default: + /* try texture targets */ + texObj = _mesa_select_tex_object(ctx, texUnit, target); + if (texObj && !_mesa_is_proxy_texture(target)) { + table = &texObj->Palette; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glColorSubTable(target)"); + return; + } + } + + assert(table); + + if (!_mesa_is_legal_format_and_type(ctx, format, type) || + format == GL_INTENSITY) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glColorSubTable(format or type)"); + return; + } + + if (count < 1) { + _mesa_error(ctx, GL_INVALID_VALUE, "glColorSubTable(count)"); + return; + } + + /* error should have been caught sooner */ + assert(_mesa_components_in_format(table->_BaseFormat) > 0); + + if (start + count > (GLint) table->Size) { + _mesa_error(ctx, GL_INVALID_VALUE, "glColorSubTable(count)"); + return; + } + + if (!table->TableF || !table->TableUB) { + /* a GL_OUT_OF_MEMORY error would have been recorded previously */ + return; + } + + store_colortable_entries(ctx, table, start, count, + format, type, data, + scale[0], bias[0], + scale[1], bias[1], + scale[2], bias[2], + scale[3], bias[3]); + + if (texObj || target == GL_SHARED_TEXTURE_PALETTE_EXT) { + /* per-texture object palette */ + if (ctx->Driver.UpdateTexturePalette) { + (*ctx->Driver.UpdateTexturePalette)( ctx, texObj ); + } + } + + ctx->NewState |= _NEW_PIXEL; +} + + + +static void GLAPIENTRY +_mesa_CopyColorTable(GLenum target, GLenum internalformat, + GLint x, GLint y, GLsizei width) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (!ctx->ReadBuffer->_ColorReadBuffer) { + return; /* no readbuffer - OK */ + } + + ctx->Driver.CopyColorTable( ctx, target, internalformat, x, y, width ); +} + + + +static void GLAPIENTRY +_mesa_CopyColorSubTable(GLenum target, GLsizei start, + GLint x, GLint y, GLsizei width) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (!ctx->ReadBuffer->_ColorReadBuffer) { + return; /* no readbuffer - OK */ + } + + ctx->Driver.CopyColorSubTable( ctx, target, start, x, y, width ); +} + + + +static void GLAPIENTRY +_mesa_GetColorTable( GLenum target, GLenum format, + GLenum type, GLvoid *data ) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + struct gl_color_table *table = NULL; + GLfloat rgba[MAX_COLOR_TABLE_SIZE][4]; + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (ctx->NewState) { + _mesa_update_state(ctx); + } + + switch (target) { + case GL_SHARED_TEXTURE_PALETTE_EXT: + table = &ctx->Texture.Palette; + break; + default: + /* try texture targets */ + { + struct gl_texture_object *texobj + = _mesa_select_tex_object(ctx, texUnit, target); + if (texobj && !_mesa_is_proxy_texture(target)) { + table = &texobj->Palette; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTable(target)"); + return; + } + } + } + + ASSERT(table); + + if (table->Size <= 0) { + return; + } + + switch (table->_BaseFormat) { + case GL_ALPHA: + { + GLuint i; + for (i = 0; i < table->Size; i++) { + rgba[i][RCOMP] = 0; + rgba[i][GCOMP] = 0; + rgba[i][BCOMP] = 0; + rgba[i][ACOMP] = table->TableF[i]; + } + } + break; + case GL_LUMINANCE: + { + GLuint i; + for (i = 0; i < table->Size; i++) { + rgba[i][RCOMP] = + rgba[i][GCOMP] = + rgba[i][BCOMP] = table->TableF[i]; + rgba[i][ACOMP] = 1.0F; + } + } + break; + case GL_LUMINANCE_ALPHA: + { + GLuint i; + for (i = 0; i < table->Size; i++) { + rgba[i][RCOMP] = + rgba[i][GCOMP] = + rgba[i][BCOMP] = table->TableF[i*2+0]; + rgba[i][ACOMP] = table->TableF[i*2+1]; + } + } + break; + case GL_INTENSITY: + { + GLuint i; + for (i = 0; i < table->Size; i++) { + rgba[i][RCOMP] = + rgba[i][GCOMP] = + rgba[i][BCOMP] = + rgba[i][ACOMP] = table->TableF[i]; + } + } + break; + case GL_RGB: + { + GLuint i; + for (i = 0; i < table->Size; i++) { + rgba[i][RCOMP] = table->TableF[i*3+0]; + rgba[i][GCOMP] = table->TableF[i*3+1]; + rgba[i][BCOMP] = table->TableF[i*3+2]; + rgba[i][ACOMP] = 1.0F; + } + } + break; + case GL_RGBA: + memcpy(rgba, table->TableF, 4 * table->Size * sizeof(GLfloat)); + break; + default: + _mesa_problem(ctx, "bad table format in glGetColorTable"); + return; + } + + data = _mesa_map_validate_pbo_dest(ctx, + 1, &ctx->Pack, table->Size, 1, 1, + format, type, data, + "glGetColorTable"); + if (!data) + return; + + _mesa_pack_rgba_span_float(ctx, table->Size, rgba, + format, type, data, &ctx->Pack, 0x0); + + _mesa_unmap_pbo_dest(ctx, &ctx->Pack); +} + + + +static void GLAPIENTRY +_mesa_ColorTableParameterfv(GLenum target, GLenum pname, const GLfloat *params) +{ + /* no extensions use this function */ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + _mesa_error(ctx, GL_INVALID_ENUM, "glColorTableParameterfv(target)"); +} + + + +static void GLAPIENTRY +_mesa_ColorTableParameteriv(GLenum target, GLenum pname, const GLint *params) +{ + /* no extensions use this function */ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + _mesa_error(ctx, GL_INVALID_ENUM, "glColorTableParameteriv(target)"); +} + + + +static void GLAPIENTRY +_mesa_GetColorTableParameterfv( GLenum target, GLenum pname, GLfloat *params ) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + struct gl_color_table *table = NULL; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + switch (target) { + case GL_SHARED_TEXTURE_PALETTE_EXT: + table = &ctx->Texture.Palette; + break; + default: + /* try texture targets */ + { + struct gl_texture_object *texobj + = _mesa_select_tex_object(ctx, texUnit, target); + if (texobj) { + table = &texobj->Palette; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetColorTableParameterfv(target)"); + return; + } + } + } + + assert(table); + + switch (pname) { + case GL_COLOR_TABLE_FORMAT: + *params = (GLfloat) table->InternalFormat; + break; + case GL_COLOR_TABLE_WIDTH: + *params = (GLfloat) table->Size; + break; + case GL_COLOR_TABLE_RED_SIZE: + *params = (GLfloat) table->RedSize; + break; + case GL_COLOR_TABLE_GREEN_SIZE: + *params = (GLfloat) table->GreenSize; + break; + case GL_COLOR_TABLE_BLUE_SIZE: + *params = (GLfloat) table->BlueSize; + break; + case GL_COLOR_TABLE_ALPHA_SIZE: + *params = (GLfloat) table->AlphaSize; + break; + case GL_COLOR_TABLE_LUMINANCE_SIZE: + *params = (GLfloat) table->LuminanceSize; + break; + case GL_COLOR_TABLE_INTENSITY_SIZE: + *params = (GLfloat) table->IntensitySize; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameterfv(pname)" ); + return; + } +} + + + +static void GLAPIENTRY +_mesa_GetColorTableParameteriv( GLenum target, GLenum pname, GLint *params ) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + struct gl_color_table *table = NULL; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + switch (target) { + case GL_SHARED_TEXTURE_PALETTE_EXT: + table = &ctx->Texture.Palette; + break; + default: + /* Try texture targets */ + { + struct gl_texture_object *texobj + = _mesa_select_tex_object(ctx, texUnit, target); + if (texobj) { + table = &texobj->Palette; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetColorTableParameteriv(target)"); + return; + } + } + } + + assert(table); + + switch (pname) { + case GL_COLOR_TABLE_FORMAT: + *params = table->InternalFormat; + break; + case GL_COLOR_TABLE_WIDTH: + *params = table->Size; + break; + case GL_COLOR_TABLE_RED_SIZE: + *params = table->RedSize; + break; + case GL_COLOR_TABLE_GREEN_SIZE: + *params = table->GreenSize; + break; + case GL_COLOR_TABLE_BLUE_SIZE: + *params = table->BlueSize; + break; + case GL_COLOR_TABLE_ALPHA_SIZE: + *params = table->AlphaSize; + break; + case GL_COLOR_TABLE_LUMINANCE_SIZE: + *params = table->LuminanceSize; + break; + case GL_COLOR_TABLE_INTENSITY_SIZE: + *params = table->IntensitySize; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameteriv(pname)" ); + return; + } +} + + +void +_mesa_init_colortable_dispatch(struct _glapi_table *disp) +{ + SET_ColorSubTable(disp, _mesa_ColorSubTable); + SET_ColorTable(disp, _mesa_ColorTable); + SET_ColorTableParameterfv(disp, _mesa_ColorTableParameterfv); + SET_ColorTableParameteriv(disp, _mesa_ColorTableParameteriv); + SET_CopyColorSubTable(disp, _mesa_CopyColorSubTable); + SET_CopyColorTable(disp, _mesa_CopyColorTable); + SET_GetColorTable(disp, _mesa_GetColorTable); + SET_GetColorTableParameterfv(disp, _mesa_GetColorTableParameterfv); + SET_GetColorTableParameteriv(disp, _mesa_GetColorTableParameteriv); +} + + +#endif /* FEATURE_colortable */ + + +/**********************************************************************/ +/***** Initialization *****/ +/**********************************************************************/ + + +void +_mesa_init_colortable( struct gl_color_table *p ) +{ + p->TableF = NULL; + p->TableUB = NULL; + p->Size = 0; + p->InternalFormat = GL_RGBA; +} + + + +void +_mesa_free_colortable_data( struct gl_color_table *p ) +{ + if (p->TableF) { + free(p->TableF); + p->TableF = NULL; + } + if (p->TableUB) { + free(p->TableUB); + p->TableUB = NULL; + } +} diff --git a/mesalib/src/mesa/main/dlist.c b/mesalib/src/mesa/main/dlist.c index 8e904c778..4e463dd06 100644 --- a/mesalib/src/mesa/main/dlist.c +++ b/mesalib/src/mesa/main/dlist.c @@ -54,6 +54,7 @@ #include "light.h" #include "macros.h" #include "pack.h" +#include "pbo.h" #include "queryobj.h" #include "teximage.h" #include "mtypes.h" diff --git a/mesalib/src/mesa/main/drawpix.c b/mesalib/src/mesa/main/drawpix.c index 554d7a84a..98e82ef85 100644 --- a/mesalib/src/mesa/main/drawpix.c +++ b/mesalib/src/mesa/main/drawpix.c @@ -1,303 +1,304 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * 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 "glheader.h" -#include "imports.h" -#include "bufferobj.h" -#include "context.h" -#include "drawpix.h" -#include "enums.h" -#include "feedback.h" -#include "framebuffer.h" -#include "mfeatures.h" -#include "readpix.h" -#include "state.h" -#include "dispatch.h" - - -#if FEATURE_drawpix - - -/* - * Execute glDrawPixels - */ -static void GLAPIENTRY -_mesa_DrawPixels( GLsizei width, GLsizei height, - GLenum format, GLenum type, const GLvoid *pixels ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glDrawPixels(%d, %d, %s, %s, %p) // to %s at %d, %d\n", - width, height, - _mesa_lookup_enum_by_nr(format), - _mesa_lookup_enum_by_nr(type), - pixels, - _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]), - IROUND(ctx->Current.RasterPos[0]), - IROUND(ctx->Current.RasterPos[1])); - - - if (width < 0 || height < 0) { - _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0" ); - return; - } - - /* We're not using the current vertex program, and the driver may install - * its own. Note: this may dirty some state. - */ - _mesa_set_vp_override(ctx, GL_TRUE); - - /* Note: this call does state validation */ - if (!_mesa_valid_to_render(ctx, "glDrawPixels")) { - goto end; /* the error code was recorded */ - } - - if (_mesa_error_check_format_type(ctx, format, type, GL_TRUE)) { - goto end; /* the error code was recorded */ - } - - if (!ctx->Current.RasterPosValid) { - goto end; /* no-op, not an error */ - } - - if (ctx->RenderMode == GL_RENDER) { - if (width > 0 && height > 0) { - /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ - GLint x = IROUND(ctx->Current.RasterPos[0]); - GLint y = IROUND(ctx->Current.RasterPos[1]); - - if (ctx->Unpack.BufferObj->Name) { - /* unpack from PBO */ - if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1, - format, type, pixels)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glDrawPixels(invalid PBO access)"); - goto end; - } - if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) { - /* buffer is mapped - that's an error */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "glDrawPixels(PBO is mapped)"); - goto end; - } - } - - ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, - &ctx->Unpack, pixels); - } - } - else if (ctx->RenderMode == GL_FEEDBACK) { - /* Feedback the current raster pos info */ - FLUSH_CURRENT( ctx, 0 ); - _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); - _mesa_feedback_vertex( ctx, - ctx->Current.RasterPos, - ctx->Current.RasterColor, - ctx->Current.RasterTexCoords[0] ); - } - else { - ASSERT(ctx->RenderMode == GL_SELECT); - /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ - } - -end: - _mesa_set_vp_override(ctx, GL_FALSE); -} - - -static void GLAPIENTRY -_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, - GLenum type ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - _mesa_finish(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, - "glCopyPixels(%d, %d, %d, %d, %s) // from %s to %s at %d, %d\n", - srcx, srcy, width, height, - _mesa_lookup_enum_by_nr(type), - _mesa_lookup_enum_by_nr(ctx->ReadBuffer->ColorReadBuffer), - _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]), - IROUND(ctx->Current.RasterPos[0]), - IROUND(ctx->Current.RasterPos[1])); - - if (width < 0 || height < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)"); - return; - } - - /* Note: more detailed 'type' checking is done by the - * _mesa_source/dest_buffer_exists() calls below. That's where we - * check if the stencil buffer exists, etc. - */ - if (type != GL_COLOR && - type != GL_DEPTH && - type != GL_STENCIL && - type != GL_DEPTH_STENCIL) { - _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)", - _mesa_lookup_enum_by_nr(type)); - return; - } - - /* We're not using the current vertex program, and the driver may install - * it's own. Note: this may dirty some state. - */ - _mesa_set_vp_override(ctx, GL_TRUE); - - /* Note: this call does state validation */ - if (!_mesa_valid_to_render(ctx, "glCopyPixels")) { - goto end; /* the error code was recorded */ - } - - /* Check read buffer's status (draw buffer was already checked) */ - if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { - _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, - "glCopyPixels(incomplete framebuffer)" ); - goto end; - } - - if (!_mesa_source_buffer_exists(ctx, type) || - !_mesa_dest_buffer_exists(ctx, type)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyPixels(missing source or dest buffer)"); - goto end; - } - - if (!ctx->Current.RasterPosValid || width ==0 || height == 0) { - goto end; /* no-op, not an error */ - } - - if (ctx->RenderMode == GL_RENDER) { - /* Round to satisfy conformance tests (matches SGI's OpenGL) */ - if (width > 0 && height > 0) { - GLint destx = IROUND(ctx->Current.RasterPos[0]); - GLint desty = IROUND(ctx->Current.RasterPos[1]); - ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty, - type ); - } - } - else if (ctx->RenderMode == GL_FEEDBACK) { - FLUSH_CURRENT( ctx, 0 ); - _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); - _mesa_feedback_vertex( ctx, - ctx->Current.RasterPos, - ctx->Current.RasterColor, - ctx->Current.RasterTexCoords[0] ); - } - else { - ASSERT(ctx->RenderMode == GL_SELECT); - /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ - } - -end: - _mesa_set_vp_override(ctx, GL_FALSE); -} - - -static void GLAPIENTRY -_mesa_Bitmap( GLsizei width, GLsizei height, - GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, - const GLubyte *bitmap ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (width < 0 || height < 0) { - _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); - return; - } - - if (!ctx->Current.RasterPosValid) { - return; /* do nothing */ - } - - /* Note: this call does state validation */ - if (!_mesa_valid_to_render(ctx, "glBitmap")) { - /* the error code was recorded */ - return; - } - - if (ctx->RenderMode == GL_RENDER) { - /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ - if (width > 0 && height > 0) { - const GLfloat epsilon = 0.0001F; - GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig); - GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig); - - if (ctx->Unpack.BufferObj->Name) { - /* unpack from PBO */ - if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1, - GL_COLOR_INDEX, GL_BITMAP, - (GLvoid *) bitmap)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBitmap(invalid PBO access)"); - return; - } - if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) { - /* buffer is mapped - that's an error */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBitmap(PBO is mapped)"); - return; - } - } - - ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); - } - } -#if _HAVE_FULL_GL - else if (ctx->RenderMode == GL_FEEDBACK) { - FLUSH_CURRENT(ctx, 0); - _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); - _mesa_feedback_vertex( ctx, - ctx->Current.RasterPos, - ctx->Current.RasterColor, - ctx->Current.RasterTexCoords[0] ); - } - else { - ASSERT(ctx->RenderMode == GL_SELECT); - /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ - } -#endif - - /* update raster position */ - ctx->Current.RasterPos[0] += xmove; - ctx->Current.RasterPos[1] += ymove; -} - - -void -_mesa_init_drawpix_dispatch(struct _glapi_table *disp) -{ - SET_Bitmap(disp, _mesa_Bitmap); - SET_CopyPixels(disp, _mesa_CopyPixels); - SET_DrawPixels(disp, _mesa_DrawPixels); -} - - -#endif /* FEATURE_drawpix */ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * 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 "glheader.h" +#include "imports.h" +#include "bufferobj.h" +#include "context.h" +#include "drawpix.h" +#include "enums.h" +#include "feedback.h" +#include "framebuffer.h" +#include "mfeatures.h" +#include "pbo.h" +#include "readpix.h" +#include "state.h" +#include "dispatch.h" + + +#if FEATURE_drawpix + + +/* + * Execute glDrawPixels + */ +static void GLAPIENTRY +_mesa_DrawPixels( GLsizei width, GLsizei height, + GLenum format, GLenum type, const GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glDrawPixels(%d, %d, %s, %s, %p) // to %s at %d, %d\n", + width, height, + _mesa_lookup_enum_by_nr(format), + _mesa_lookup_enum_by_nr(type), + pixels, + _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]), + IROUND(ctx->Current.RasterPos[0]), + IROUND(ctx->Current.RasterPos[1])); + + + if (width < 0 || height < 0) { + _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0" ); + return; + } + + /* We're not using the current vertex program, and the driver may install + * its own. Note: this may dirty some state. + */ + _mesa_set_vp_override(ctx, GL_TRUE); + + /* Note: this call does state validation */ + if (!_mesa_valid_to_render(ctx, "glDrawPixels")) { + goto end; /* the error code was recorded */ + } + + if (_mesa_error_check_format_type(ctx, format, type, GL_TRUE)) { + goto end; /* the error code was recorded */ + } + + if (!ctx->Current.RasterPosValid) { + goto end; /* no-op, not an error */ + } + + if (ctx->RenderMode == GL_RENDER) { + if (width > 0 && height > 0) { + /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ + GLint x = IROUND(ctx->Current.RasterPos[0]); + GLint y = IROUND(ctx->Current.RasterPos[1]); + + if (ctx->Unpack.BufferObj->Name) { + /* unpack from PBO */ + if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1, + format, type, pixels)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDrawPixels(invalid PBO access)"); + goto end; + } + if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) { + /* buffer is mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDrawPixels(PBO is mapped)"); + goto end; + } + } + + ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, + &ctx->Unpack, pixels); + } + } + else if (ctx->RenderMode == GL_FEEDBACK) { + /* Feedback the current raster pos info */ + FLUSH_CURRENT( ctx, 0 ); + _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); + _mesa_feedback_vertex( ctx, + ctx->Current.RasterPos, + ctx->Current.RasterColor, + ctx->Current.RasterTexCoords[0] ); + } + else { + ASSERT(ctx->RenderMode == GL_SELECT); + /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ + } + +end: + _mesa_set_vp_override(ctx, GL_FALSE); +} + + +static void GLAPIENTRY +_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, + GLenum type ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + _mesa_finish(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, + "glCopyPixels(%d, %d, %d, %d, %s) // from %s to %s at %d, %d\n", + srcx, srcy, width, height, + _mesa_lookup_enum_by_nr(type), + _mesa_lookup_enum_by_nr(ctx->ReadBuffer->ColorReadBuffer), + _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]), + IROUND(ctx->Current.RasterPos[0]), + IROUND(ctx->Current.RasterPos[1])); + + if (width < 0 || height < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)"); + return; + } + + /* Note: more detailed 'type' checking is done by the + * _mesa_source/dest_buffer_exists() calls below. That's where we + * check if the stencil buffer exists, etc. + */ + if (type != GL_COLOR && + type != GL_DEPTH && + type != GL_STENCIL && + type != GL_DEPTH_STENCIL) { + _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)", + _mesa_lookup_enum_by_nr(type)); + return; + } + + /* We're not using the current vertex program, and the driver may install + * it's own. Note: this may dirty some state. + */ + _mesa_set_vp_override(ctx, GL_TRUE); + + /* Note: this call does state validation */ + if (!_mesa_valid_to_render(ctx, "glCopyPixels")) { + goto end; /* the error code was recorded */ + } + + /* Check read buffer's status (draw buffer was already checked) */ + if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "glCopyPixels(incomplete framebuffer)" ); + goto end; + } + + if (!_mesa_source_buffer_exists(ctx, type) || + !_mesa_dest_buffer_exists(ctx, type)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyPixels(missing source or dest buffer)"); + goto end; + } + + if (!ctx->Current.RasterPosValid || width ==0 || height == 0) { + goto end; /* no-op, not an error */ + } + + if (ctx->RenderMode == GL_RENDER) { + /* Round to satisfy conformance tests (matches SGI's OpenGL) */ + if (width > 0 && height > 0) { + GLint destx = IROUND(ctx->Current.RasterPos[0]); + GLint desty = IROUND(ctx->Current.RasterPos[1]); + ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty, + type ); + } + } + else if (ctx->RenderMode == GL_FEEDBACK) { + FLUSH_CURRENT( ctx, 0 ); + _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); + _mesa_feedback_vertex( ctx, + ctx->Current.RasterPos, + ctx->Current.RasterColor, + ctx->Current.RasterTexCoords[0] ); + } + else { + ASSERT(ctx->RenderMode == GL_SELECT); + /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ + } + +end: + _mesa_set_vp_override(ctx, GL_FALSE); +} + + +static void GLAPIENTRY +_mesa_Bitmap( GLsizei width, GLsizei height, + GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, + const GLubyte *bitmap ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (width < 0 || height < 0) { + _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); + return; + } + + if (!ctx->Current.RasterPosValid) { + return; /* do nothing */ + } + + /* Note: this call does state validation */ + if (!_mesa_valid_to_render(ctx, "glBitmap")) { + /* the error code was recorded */ + return; + } + + if (ctx->RenderMode == GL_RENDER) { + /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ + if (width > 0 && height > 0) { + const GLfloat epsilon = 0.0001F; + GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig); + GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig); + + if (ctx->Unpack.BufferObj->Name) { + /* unpack from PBO */ + if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1, + GL_COLOR_INDEX, GL_BITMAP, + (GLvoid *) bitmap)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBitmap(invalid PBO access)"); + return; + } + if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) { + /* buffer is mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBitmap(PBO is mapped)"); + return; + } + } + + ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); + } + } +#if _HAVE_FULL_GL + else if (ctx->RenderMode == GL_FEEDBACK) { + FLUSH_CURRENT(ctx, 0); + _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); + _mesa_feedback_vertex( ctx, + ctx->Current.RasterPos, + ctx->Current.RasterColor, + ctx->Current.RasterTexCoords[0] ); + } + else { + ASSERT(ctx->RenderMode == GL_SELECT); + /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ + } +#endif + + /* update raster position */ + ctx->Current.RasterPos[0] += xmove; + ctx->Current.RasterPos[1] += ymove; +} + + +void +_mesa_init_drawpix_dispatch(struct _glapi_table *disp) +{ + SET_Bitmap(disp, _mesa_Bitmap); + SET_CopyPixels(disp, _mesa_CopyPixels); + SET_DrawPixels(disp, _mesa_DrawPixels); +} + + +#endif /* FEATURE_drawpix */ diff --git a/mesalib/src/mesa/main/enable.c b/mesalib/src/mesa/main/enable.c index 231278bee..f24709241 100644 --- a/mesalib/src/mesa/main/enable.c +++ b/mesalib/src/mesa/main/enable.c @@ -1,1501 +1,1487 @@ -/** - * \file enable.c - * Enable/disable/query GL capabilities. - */ - -/* - * Mesa 3-D graphics library - * Version: 7.0.3 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#include "glheader.h" -#include "context.h" -#include "enable.h" -#include "light.h" -#include "simple_list.h" -#include "mfeatures.h" -#include "mtypes.h" -#include "enums.h" -#include "api_arrayelt.h" -#include "texstate.h" - - - -#define CHECK_EXTENSION(EXTNAME, CAP) \ - if (!ctx->Extensions.EXTNAME) { \ - goto invalid_enum_error; \ - } - - -/** - * Helper to enable/disable client-side state. - */ -static void -client_state(struct gl_context *ctx, GLenum cap, GLboolean state) -{ - struct gl_array_object *arrayObj = ctx->Array.ArrayObj; - GLuint flag; - GLboolean *var; - - switch (cap) { - case GL_VERTEX_ARRAY: - var = &arrayObj->Vertex.Enabled; - flag = _NEW_ARRAY_VERTEX; - break; - case GL_NORMAL_ARRAY: - var = &arrayObj->Normal.Enabled; - flag = _NEW_ARRAY_NORMAL; - break; - case GL_COLOR_ARRAY: - var = &arrayObj->Color.Enabled; - flag = _NEW_ARRAY_COLOR0; - break; - case GL_INDEX_ARRAY: - var = &arrayObj->Index.Enabled; - flag = _NEW_ARRAY_INDEX; - break; - case GL_TEXTURE_COORD_ARRAY: - var = &arrayObj->TexCoord[ctx->Array.ActiveTexture].Enabled; - flag = _NEW_ARRAY_TEXCOORD(ctx->Array.ActiveTexture); - break; - case GL_EDGE_FLAG_ARRAY: - var = &arrayObj->EdgeFlag.Enabled; - flag = _NEW_ARRAY_EDGEFLAG; - break; - case GL_FOG_COORDINATE_ARRAY_EXT: - var = &arrayObj->FogCoord.Enabled; - flag = _NEW_ARRAY_FOGCOORD; - break; - case GL_SECONDARY_COLOR_ARRAY_EXT: - var = &arrayObj->SecondaryColor.Enabled; - flag = _NEW_ARRAY_COLOR1; - break; - -#if FEATURE_point_size_array - case GL_POINT_SIZE_ARRAY_OES: - var = &arrayObj->PointSize.Enabled; - flag = _NEW_ARRAY_POINT_SIZE; - break; -#endif - -#if FEATURE_NV_vertex_program - case GL_VERTEX_ATTRIB_ARRAY0_NV: - case GL_VERTEX_ATTRIB_ARRAY1_NV: - case GL_VERTEX_ATTRIB_ARRAY2_NV: - case GL_VERTEX_ATTRIB_ARRAY3_NV: - case GL_VERTEX_ATTRIB_ARRAY4_NV: - case GL_VERTEX_ATTRIB_ARRAY5_NV: - case GL_VERTEX_ATTRIB_ARRAY6_NV: - case GL_VERTEX_ATTRIB_ARRAY7_NV: - case GL_VERTEX_ATTRIB_ARRAY8_NV: - case GL_VERTEX_ATTRIB_ARRAY9_NV: - case GL_VERTEX_ATTRIB_ARRAY10_NV: - case GL_VERTEX_ATTRIB_ARRAY11_NV: - case GL_VERTEX_ATTRIB_ARRAY12_NV: - case GL_VERTEX_ATTRIB_ARRAY13_NV: - case GL_VERTEX_ATTRIB_ARRAY14_NV: - case GL_VERTEX_ATTRIB_ARRAY15_NV: - CHECK_EXTENSION(NV_vertex_program, cap); - { - GLint n = (GLint) cap - GL_VERTEX_ATTRIB_ARRAY0_NV; - ASSERT(n < Elements(ctx->Array.ArrayObj->VertexAttrib)); - var = &arrayObj->VertexAttrib[n].Enabled; - flag = _NEW_ARRAY_ATTRIB(n); - } - break; -#endif /* FEATURE_NV_vertex_program */ - - /* GL_NV_primitive_restart */ - case GL_PRIMITIVE_RESTART_NV: - if (!ctx->Extensions.NV_primitive_restart) { - goto invalid_enum_error; - } - var = &ctx->Array.PrimitiveRestart; - flag = 0; - break; - - default: - goto invalid_enum_error; - } - - if (*var == state) - return; - - FLUSH_VERTICES(ctx, _NEW_ARRAY); - ctx->Array.NewState |= flag; - - _ae_invalidate_state(ctx, _NEW_ARRAY); - - *var = state; - - if (state) - ctx->Array.ArrayObj->_Enabled |= flag; - else - ctx->Array.ArrayObj->_Enabled &= ~flag; - - if (ctx->Driver.Enable) { - ctx->Driver.Enable( ctx, cap, state ); - } - - return; - -invalid_enum_error: - _mesa_error(ctx, GL_INVALID_ENUM, "gl%sClientState(0x%x)", - state ? "Enable" : "Disable", cap); -} - - -/** - * Enable GL capability. - * \param cap state to enable/disable. - * - * Get's the current context, assures that we're outside glBegin()/glEnd() and - * calls client_state(). - */ -void GLAPIENTRY -_mesa_EnableClientState( GLenum cap ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - client_state( ctx, cap, GL_TRUE ); -} - - -/** - * Disable GL capability. - * \param cap state to enable/disable. - * - * Get's the current context, assures that we're outside glBegin()/glEnd() and - * calls client_state(). - */ -void GLAPIENTRY -_mesa_DisableClientState( GLenum cap ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - client_state( ctx, cap, GL_FALSE ); -} - - -#undef CHECK_EXTENSION -#define CHECK_EXTENSION(EXTNAME, CAP) \ - if (!ctx->Extensions.EXTNAME) { \ - goto invalid_enum_error; \ - } - -#define CHECK_EXTENSION2(EXT1, EXT2, CAP) \ - if (!ctx->Extensions.EXT1 && !ctx->Extensions.EXT2) { \ - goto invalid_enum_error; \ - } - - - -/** - * Return pointer to current texture unit for setting/getting coordinate - * state. - * Note that we'll set GL_INVALID_OPERATION if the active texture unit is - * higher than the number of supported coordinate units. And we'll return NULL. - */ -static struct gl_texture_unit * -get_texcoord_unit(struct gl_context *ctx) -{ - if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glEnable/Disable(texcoord unit)"); - return NULL; - } - else { - return &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - } -} - - -/** - * Helper function to enable or disable a texture target. - * \param bit one of the TEXTURE_x_BIT values - * \return GL_TRUE if state is changing or GL_FALSE if no change - */ -static GLboolean -enable_texture(struct gl_context *ctx, GLboolean state, GLbitfield texBit) -{ - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - const GLbitfield newenabled = state - ? (texUnit->Enabled | texBit) : (texUnit->Enabled & ~texBit); - - if (texUnit->Enabled == newenabled) - return GL_FALSE; - - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - texUnit->Enabled = newenabled; - return GL_TRUE; -} - - -/** - * Helper function to enable or disable state. - * - * \param ctx GL context. - * \param cap the state to enable/disable - * \param state whether to enable or disable the specified capability. - * - * Updates the current context and flushes the vertices as needed. For - * capabilities associated with extensions it verifies that those extensions - * are effectivly present before updating. Notifies the driver via - * dd_function_table::Enable. - */ -void -_mesa_set_enable(struct gl_context *ctx, GLenum cap, GLboolean state) -{ - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "%s %s (newstate is %x)\n", - state ? "glEnable" : "glDisable", - _mesa_lookup_enum_by_nr(cap), - ctx->NewState); - - switch (cap) { - case GL_ALPHA_TEST: - if (ctx->Color.AlphaEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.AlphaEnabled = state; - break; - case GL_AUTO_NORMAL: - if (ctx->Eval.AutoNormal == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.AutoNormal = state; - break; - case GL_BLEND: - { - GLbitfield newEnabled = state * ((1 << ctx->Const.MaxDrawBuffers) - 1); - if (newEnabled != ctx->Color.BlendEnabled) { - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.BlendEnabled = newEnabled; - } - } - break; -#if FEATURE_userclip - case GL_CLIP_PLANE0: - case GL_CLIP_PLANE1: - case GL_CLIP_PLANE2: - case GL_CLIP_PLANE3: - case GL_CLIP_PLANE4: - case GL_CLIP_PLANE5: - { - const GLuint p = cap - GL_CLIP_PLANE0; - - if ((ctx->Transform.ClipPlanesEnabled & (1 << p)) == ((GLuint) state << p)) - return; - - FLUSH_VERTICES(ctx, _NEW_TRANSFORM); - - if (state) { - ctx->Transform.ClipPlanesEnabled |= (1 << p); - - if (_math_matrix_is_dirty(ctx->ProjectionMatrixStack.Top)) - _math_matrix_analyse( ctx->ProjectionMatrixStack.Top ); - - /* This derived state also calculated in clip.c and - * from _mesa_update_state() on changes to EyeUserPlane - * and ctx->ProjectionMatrix respectively. - */ - _mesa_transform_vector( ctx->Transform._ClipUserPlane[p], - ctx->Transform.EyeUserPlane[p], - ctx->ProjectionMatrixStack.Top->inv ); - } - else { - ctx->Transform.ClipPlanesEnabled &= ~(1 << p); - } - } - break; -#endif - case GL_COLOR_MATERIAL: - if (ctx->Light.ColorMaterialEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_LIGHT); - FLUSH_CURRENT(ctx, 0); - ctx->Light.ColorMaterialEnabled = state; - if (state) { - _mesa_update_color_material( ctx, - ctx->Current.Attrib[VERT_ATTRIB_COLOR0] ); - } - break; - case GL_CULL_FACE: - if (ctx->Polygon.CullFlag == state) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.CullFlag = state; - break; - case GL_DEPTH_TEST: - if (ctx->Depth.Test == state) - return; - FLUSH_VERTICES(ctx, _NEW_DEPTH); - ctx->Depth.Test = state; - break; - case GL_DITHER: - if (ctx->Color.DitherFlag == state) - return; - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.DitherFlag = state; - break; - case GL_FOG: - if (ctx->Fog.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_FOG); - ctx->Fog.Enabled = state; - break; - case GL_LIGHT0: - case GL_LIGHT1: - case GL_LIGHT2: - case GL_LIGHT3: - case GL_LIGHT4: - case GL_LIGHT5: - case GL_LIGHT6: - case GL_LIGHT7: - if (ctx->Light.Light[cap-GL_LIGHT0].Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_LIGHT); - ctx->Light.Light[cap-GL_LIGHT0].Enabled = state; - if (state) { - insert_at_tail(&ctx->Light.EnabledList, - &ctx->Light.Light[cap-GL_LIGHT0]); - } - else { - remove_from_list(&ctx->Light.Light[cap-GL_LIGHT0]); - } - break; - case GL_LIGHTING: - if (ctx->Light.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_LIGHT); - ctx->Light.Enabled = state; - if (ctx->Light.Enabled && ctx->Light.Model.TwoSide) - ctx->_TriangleCaps |= DD_TRI_LIGHT_TWOSIDE; - else - ctx->_TriangleCaps &= ~DD_TRI_LIGHT_TWOSIDE; - break; - case GL_LINE_SMOOTH: - if (ctx->Line.SmoothFlag == state) - return; - FLUSH_VERTICES(ctx, _NEW_LINE); - ctx->Line.SmoothFlag = state; - ctx->_TriangleCaps ^= DD_LINE_SMOOTH; - break; - case GL_LINE_STIPPLE: - if (ctx->Line.StippleFlag == state) - return; - FLUSH_VERTICES(ctx, _NEW_LINE); - ctx->Line.StippleFlag = state; - ctx->_TriangleCaps ^= DD_LINE_STIPPLE; - break; - case GL_INDEX_LOGIC_OP: - if (ctx->Color.IndexLogicOpEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.IndexLogicOpEnabled = state; - break; - case GL_COLOR_LOGIC_OP: - if (ctx->Color.ColorLogicOpEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.ColorLogicOpEnabled = state; - break; - case GL_MAP1_COLOR_4: - if (ctx->Eval.Map1Color4 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1Color4 = state; - break; - case GL_MAP1_INDEX: - if (ctx->Eval.Map1Index == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1Index = state; - break; - case GL_MAP1_NORMAL: - if (ctx->Eval.Map1Normal == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1Normal = state; - break; - case GL_MAP1_TEXTURE_COORD_1: - if (ctx->Eval.Map1TextureCoord1 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1TextureCoord1 = state; - break; - case GL_MAP1_TEXTURE_COORD_2: - if (ctx->Eval.Map1TextureCoord2 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1TextureCoord2 = state; - break; - case GL_MAP1_TEXTURE_COORD_3: - if (ctx->Eval.Map1TextureCoord3 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1TextureCoord3 = state; - break; - case GL_MAP1_TEXTURE_COORD_4: - if (ctx->Eval.Map1TextureCoord4 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1TextureCoord4 = state; - break; - case GL_MAP1_VERTEX_3: - if (ctx->Eval.Map1Vertex3 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1Vertex3 = state; - break; - case GL_MAP1_VERTEX_4: - if (ctx->Eval.Map1Vertex4 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1Vertex4 = state; - break; - case GL_MAP2_COLOR_4: - if (ctx->Eval.Map2Color4 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2Color4 = state; - break; - case GL_MAP2_INDEX: - if (ctx->Eval.Map2Index == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2Index = state; - break; - case GL_MAP2_NORMAL: - if (ctx->Eval.Map2Normal == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2Normal = state; - break; - case GL_MAP2_TEXTURE_COORD_1: - if (ctx->Eval.Map2TextureCoord1 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2TextureCoord1 = state; - break; - case GL_MAP2_TEXTURE_COORD_2: - if (ctx->Eval.Map2TextureCoord2 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2TextureCoord2 = state; - break; - case GL_MAP2_TEXTURE_COORD_3: - if (ctx->Eval.Map2TextureCoord3 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2TextureCoord3 = state; - break; - case GL_MAP2_TEXTURE_COORD_4: - if (ctx->Eval.Map2TextureCoord4 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2TextureCoord4 = state; - break; - case GL_MAP2_VERTEX_3: - if (ctx->Eval.Map2Vertex3 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2Vertex3 = state; - break; - case GL_MAP2_VERTEX_4: - if (ctx->Eval.Map2Vertex4 == state) - return; - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2Vertex4 = state; - break; - case GL_NORMALIZE: - if (ctx->Transform.Normalize == state) - return; - FLUSH_VERTICES(ctx, _NEW_TRANSFORM); - ctx->Transform.Normalize = state; - break; - case GL_POINT_SMOOTH: - if (ctx->Point.SmoothFlag == state) - return; - FLUSH_VERTICES(ctx, _NEW_POINT); - ctx->Point.SmoothFlag = state; - ctx->_TriangleCaps ^= DD_POINT_SMOOTH; - break; - case GL_POLYGON_SMOOTH: - if (ctx->Polygon.SmoothFlag == state) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.SmoothFlag = state; - ctx->_TriangleCaps ^= DD_TRI_SMOOTH; - break; - case GL_POLYGON_STIPPLE: - if (ctx->Polygon.StippleFlag == state) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.StippleFlag = state; - ctx->_TriangleCaps ^= DD_TRI_STIPPLE; - break; - case GL_POLYGON_OFFSET_POINT: - if (ctx->Polygon.OffsetPoint == state) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.OffsetPoint = state; - break; - case GL_POLYGON_OFFSET_LINE: - if (ctx->Polygon.OffsetLine == state) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.OffsetLine = state; - break; - case GL_POLYGON_OFFSET_FILL: - /*case GL_POLYGON_OFFSET_EXT:*/ - if (ctx->Polygon.OffsetFill == state) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.OffsetFill = state; - break; - case GL_RESCALE_NORMAL_EXT: - if (ctx->Transform.RescaleNormals == state) - return; - FLUSH_VERTICES(ctx, _NEW_TRANSFORM); - ctx->Transform.RescaleNormals = state; - break; - case GL_SCISSOR_TEST: - if (ctx->Scissor.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_SCISSOR); - ctx->Scissor.Enabled = state; - break; - case GL_SHARED_TEXTURE_PALETTE_EXT: - if (ctx->Texture.SharedPalette == state) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - ctx->Texture.SharedPalette = state; - break; - case GL_STENCIL_TEST: - if (ctx->Stencil.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.Enabled = state; - break; - case GL_TEXTURE_1D: - if (!enable_texture(ctx, state, TEXTURE_1D_BIT)) { - return; - } - break; - case GL_TEXTURE_2D: - if (!enable_texture(ctx, state, TEXTURE_2D_BIT)) { - return; - } - break; - case GL_TEXTURE_3D: - if (!enable_texture(ctx, state, TEXTURE_3D_BIT)) { - return; - } - break; - case GL_TEXTURE_GEN_Q: - { - struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - GLuint newenabled = texUnit->TexGenEnabled & ~Q_BIT; - if (state) - newenabled |= Q_BIT; - if (texUnit->TexGenEnabled == newenabled) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - texUnit->TexGenEnabled = newenabled; - } - } - break; - case GL_TEXTURE_GEN_R: - { - struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - GLuint newenabled = texUnit->TexGenEnabled & ~R_BIT; - if (state) - newenabled |= R_BIT; - if (texUnit->TexGenEnabled == newenabled) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - texUnit->TexGenEnabled = newenabled; - } - } - break; - case GL_TEXTURE_GEN_S: - { - struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - GLuint newenabled = texUnit->TexGenEnabled & ~S_BIT; - if (state) - newenabled |= S_BIT; - if (texUnit->TexGenEnabled == newenabled) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - texUnit->TexGenEnabled = newenabled; - } - } - break; - case GL_TEXTURE_GEN_T: - { - struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - GLuint newenabled = texUnit->TexGenEnabled & ~T_BIT; - if (state) - newenabled |= T_BIT; - if (texUnit->TexGenEnabled == newenabled) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - texUnit->TexGenEnabled = newenabled; - } - } - break; - -#if FEATURE_ES1 - case GL_TEXTURE_GEN_STR_OES: - /* disable S, T, and R at the same time */ - { - struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - GLuint newenabled = - texUnit->TexGenEnabled & ~STR_BITS; - if (state) - newenabled |= STR_BITS; - if (texUnit->TexGenEnabled == newenabled) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - texUnit->TexGenEnabled = newenabled; - } - } - break; -#endif - - /* - * CLIENT STATE!!! - */ - case GL_VERTEX_ARRAY: - case GL_NORMAL_ARRAY: - case GL_COLOR_ARRAY: - case GL_INDEX_ARRAY: - case GL_TEXTURE_COORD_ARRAY: - case GL_EDGE_FLAG_ARRAY: - case GL_FOG_COORDINATE_ARRAY_EXT: - case GL_SECONDARY_COLOR_ARRAY_EXT: - case GL_POINT_SIZE_ARRAY_OES: - client_state( ctx, cap, state ); - return; - - /* GL_SGI_texture_color_table */ - case GL_TEXTURE_COLOR_TABLE_SGI: - CHECK_EXTENSION(SGI_texture_color_table, cap); - if (ctx->Texture.Unit[ctx->Texture.CurrentUnit].ColorTableEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - ctx->Texture.Unit[ctx->Texture.CurrentUnit].ColorTableEnabled = state; - break; - - /* GL_ARB_texture_cube_map */ - case GL_TEXTURE_CUBE_MAP_ARB: - CHECK_EXTENSION(ARB_texture_cube_map, cap); - if (!enable_texture(ctx, state, TEXTURE_CUBE_BIT)) { - return; - } - break; - - /* GL_EXT_secondary_color */ - case GL_COLOR_SUM_EXT: - CHECK_EXTENSION2(EXT_secondary_color, ARB_vertex_program, cap); - if (ctx->Fog.ColorSumEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_FOG); - ctx->Fog.ColorSumEnabled = state; - break; - - /* GL_ARB_multisample */ - case GL_MULTISAMPLE_ARB: - if (ctx->Multisample.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); - ctx->Multisample.Enabled = state; - break; - case GL_SAMPLE_ALPHA_TO_COVERAGE_ARB: - if (ctx->Multisample.SampleAlphaToCoverage == state) - return; - FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); - ctx->Multisample.SampleAlphaToCoverage = state; - break; - case GL_SAMPLE_ALPHA_TO_ONE_ARB: - if (ctx->Multisample.SampleAlphaToOne == state) - return; - FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); - ctx->Multisample.SampleAlphaToOne = state; - break; - case GL_SAMPLE_COVERAGE_ARB: - if (ctx->Multisample.SampleCoverage == state) - return; - FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); - ctx->Multisample.SampleCoverage = state; - break; - case GL_SAMPLE_COVERAGE_INVERT_ARB: - if (ctx->Multisample.SampleCoverageInvert == state) - return; - FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); - ctx->Multisample.SampleCoverageInvert = state; - break; - - /* GL_IBM_rasterpos_clip */ - case GL_RASTER_POSITION_UNCLIPPED_IBM: - CHECK_EXTENSION(IBM_rasterpos_clip, cap); - if (ctx->Transform.RasterPositionUnclipped == state) - return; - FLUSH_VERTICES(ctx, _NEW_TRANSFORM); - ctx->Transform.RasterPositionUnclipped = state; - break; - - /* GL_NV_point_sprite */ - case GL_POINT_SPRITE_NV: - CHECK_EXTENSION2(NV_point_sprite, ARB_point_sprite, cap); - if (ctx->Point.PointSprite == state) - return; - FLUSH_VERTICES(ctx, _NEW_POINT); - ctx->Point.PointSprite = state; - break; - -#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program - case GL_VERTEX_PROGRAM_ARB: - CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap); - if (ctx->VertexProgram.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - ctx->VertexProgram.Enabled = state; - break; - case GL_VERTEX_PROGRAM_POINT_SIZE_ARB: - CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap); - if (ctx->VertexProgram.PointSizeEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - ctx->VertexProgram.PointSizeEnabled = state; - break; - case GL_VERTEX_PROGRAM_TWO_SIDE_ARB: - CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap); - if (ctx->VertexProgram.TwoSideEnabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - ctx->VertexProgram.TwoSideEnabled = state; - break; -#endif -#if FEATURE_NV_vertex_program - case GL_MAP1_VERTEX_ATTRIB0_4_NV: - case GL_MAP1_VERTEX_ATTRIB1_4_NV: - case GL_MAP1_VERTEX_ATTRIB2_4_NV: - case GL_MAP1_VERTEX_ATTRIB3_4_NV: - case GL_MAP1_VERTEX_ATTRIB4_4_NV: - case GL_MAP1_VERTEX_ATTRIB5_4_NV: - case GL_MAP1_VERTEX_ATTRIB6_4_NV: - case GL_MAP1_VERTEX_ATTRIB7_4_NV: - case GL_MAP1_VERTEX_ATTRIB8_4_NV: - case GL_MAP1_VERTEX_ATTRIB9_4_NV: - case GL_MAP1_VERTEX_ATTRIB10_4_NV: - case GL_MAP1_VERTEX_ATTRIB11_4_NV: - case GL_MAP1_VERTEX_ATTRIB12_4_NV: - case GL_MAP1_VERTEX_ATTRIB13_4_NV: - case GL_MAP1_VERTEX_ATTRIB14_4_NV: - case GL_MAP1_VERTEX_ATTRIB15_4_NV: - CHECK_EXTENSION(NV_vertex_program, cap); - { - const GLuint map = (GLuint) (cap - GL_MAP1_VERTEX_ATTRIB0_4_NV); - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map1Attrib[map] = state; - } - break; - case GL_MAP2_VERTEX_ATTRIB0_4_NV: - case GL_MAP2_VERTEX_ATTRIB1_4_NV: - case GL_MAP2_VERTEX_ATTRIB2_4_NV: - case GL_MAP2_VERTEX_ATTRIB3_4_NV: - case GL_MAP2_VERTEX_ATTRIB4_4_NV: - case GL_MAP2_VERTEX_ATTRIB5_4_NV: - case GL_MAP2_VERTEX_ATTRIB6_4_NV: - case GL_MAP2_VERTEX_ATTRIB7_4_NV: - case GL_MAP2_VERTEX_ATTRIB8_4_NV: - case GL_MAP2_VERTEX_ATTRIB9_4_NV: - case GL_MAP2_VERTEX_ATTRIB10_4_NV: - case GL_MAP2_VERTEX_ATTRIB11_4_NV: - case GL_MAP2_VERTEX_ATTRIB12_4_NV: - case GL_MAP2_VERTEX_ATTRIB13_4_NV: - case GL_MAP2_VERTEX_ATTRIB14_4_NV: - case GL_MAP2_VERTEX_ATTRIB15_4_NV: - CHECK_EXTENSION(NV_vertex_program, cap); - { - const GLuint map = (GLuint) (cap - GL_MAP2_VERTEX_ATTRIB0_4_NV); - FLUSH_VERTICES(ctx, _NEW_EVAL); - ctx->Eval.Map2Attrib[map] = state; - } - break; -#endif /* FEATURE_NV_vertex_program */ - -#if FEATURE_NV_fragment_program - case GL_FRAGMENT_PROGRAM_NV: - CHECK_EXTENSION(NV_fragment_program, cap); - if (ctx->FragmentProgram.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - ctx->FragmentProgram.Enabled = state; - break; -#endif /* FEATURE_NV_fragment_program */ - - /* GL_NV_texture_rectangle */ - case GL_TEXTURE_RECTANGLE_NV: - CHECK_EXTENSION(NV_texture_rectangle, cap); - if (!enable_texture(ctx, state, TEXTURE_RECT_BIT)) { - return; - } - break; - - /* GL_EXT_stencil_two_side */ - case GL_STENCIL_TEST_TWO_SIDE_EXT: - CHECK_EXTENSION(EXT_stencil_two_side, cap); - if (ctx->Stencil.TestTwoSide == state) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.TestTwoSide = state; - if (state) { - ctx->Stencil._BackFace = 2; - ctx->_TriangleCaps |= DD_TRI_TWOSTENCIL; - } else { - ctx->Stencil._BackFace = 1; - ctx->_TriangleCaps &= ~DD_TRI_TWOSTENCIL; - } - break; - -#if FEATURE_ARB_fragment_program - case GL_FRAGMENT_PROGRAM_ARB: - CHECK_EXTENSION(ARB_fragment_program, cap); - if (ctx->FragmentProgram.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - ctx->FragmentProgram.Enabled = state; - break; -#endif /* FEATURE_ARB_fragment_program */ - - /* GL_EXT_depth_bounds_test */ - case GL_DEPTH_BOUNDS_TEST_EXT: - CHECK_EXTENSION(EXT_depth_bounds_test, cap); - if (ctx->Depth.BoundsTest == state) - return; - FLUSH_VERTICES(ctx, _NEW_DEPTH); - ctx->Depth.BoundsTest = state; - break; - - case GL_DEPTH_CLAMP: - if (ctx->Transform.DepthClamp == state) - return; - CHECK_EXTENSION(ARB_depth_clamp, cap); - FLUSH_VERTICES(ctx, _NEW_TRANSFORM); - ctx->Transform.DepthClamp = state; - break; - -#if FEATURE_ATI_fragment_shader - case GL_FRAGMENT_SHADER_ATI: - CHECK_EXTENSION(ATI_fragment_shader, cap); - if (ctx->ATIFragmentShader.Enabled == state) - return; - FLUSH_VERTICES(ctx, _NEW_PROGRAM); - ctx->ATIFragmentShader.Enabled = state; - break; -#endif - - /* GL_MESA_texture_array */ - case GL_TEXTURE_1D_ARRAY_EXT: - CHECK_EXTENSION(MESA_texture_array, cap); - if (!enable_texture(ctx, state, TEXTURE_1D_ARRAY_BIT)) { - return; - } - break; - - case GL_TEXTURE_2D_ARRAY_EXT: - CHECK_EXTENSION(MESA_texture_array, cap); - if (!enable_texture(ctx, state, TEXTURE_2D_ARRAY_BIT)) { - return; - } - break; - - case GL_TEXTURE_CUBE_MAP_SEAMLESS: - CHECK_EXTENSION(ARB_seamless_cube_map, cap); - ctx->Texture.CubeMapSeamless = state; - break; - -#if FEATURE_EXT_transform_feedback - case GL_RASTERIZER_DISCARD: - CHECK_EXTENSION(EXT_transform_feedback, cap); - if (ctx->TransformFeedback.RasterDiscard != state) { - ctx->TransformFeedback.RasterDiscard = state; - FLUSH_VERTICES(ctx, _NEW_TRANSFORM); - } - break; -#endif - - /* GL 3.1 primitive restart. Note: this enum is different from - * GL_PRIMITIVE_RESTART_NV (which is client state). - */ - case GL_PRIMITIVE_RESTART: - if (ctx->VersionMajor * 10 + ctx->VersionMinor < 31) { - goto invalid_enum_error; - } - if (ctx->Array.PrimitiveRestart != state) { - FLUSH_VERTICES(ctx, _NEW_TRANSFORM); - ctx->Array.PrimitiveRestart = state; - } - break; - - /* GL3.0 - GL_framebuffer_sRGB */ - case GL_FRAMEBUFFER_SRGB_EXT: - CHECK_EXTENSION(EXT_framebuffer_sRGB, cap); - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - ctx->Color.sRGBEnabled = state; - break; - - default: - goto invalid_enum_error; - } - - if (ctx->Driver.Enable) { - ctx->Driver.Enable( ctx, cap, state ); - } - - return; - -invalid_enum_error: - _mesa_error(ctx, GL_INVALID_ENUM, "gl%s(0x%x)", - state ? "Enable" : "Disable", cap); -} - - -/** - * Enable GL capability. Called by glEnable() - * \param cap state to enable. - */ -void GLAPIENTRY -_mesa_Enable( GLenum cap ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - _mesa_set_enable( ctx, cap, GL_TRUE ); -} - - -/** - * Disable GL capability. Called by glDisable() - * \param cap state to disable. - */ -void GLAPIENTRY -_mesa_Disable( GLenum cap ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - _mesa_set_enable( ctx, cap, GL_FALSE ); -} - - - -/** - * Enable/disable an indexed state var. - */ -void -_mesa_set_enablei(struct gl_context *ctx, GLenum cap, GLuint index, GLboolean state) -{ - ASSERT(state == 0 || state == 1); - switch (cap) { - case GL_BLEND: - if (!ctx->Extensions.EXT_draw_buffers2) { - goto invalid_enum_error; - } - if (index >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%u)", - state ? "glEnableIndexed" : "glDisableIndexed", index); - return; - } - if (((ctx->Color.BlendEnabled >> index) & 1) != state) { - FLUSH_VERTICES(ctx, _NEW_COLOR); - if (state) - ctx->Color.BlendEnabled |= (1 << index); - else - ctx->Color.BlendEnabled &= ~(1 << index); - } - break; - default: - goto invalid_enum_error; - } - return; - -invalid_enum_error: - _mesa_error(ctx, GL_INVALID_ENUM, "%s(cap=%s)", - state ? "glEnablei" : "glDisablei", - _mesa_lookup_enum_by_nr(cap)); -} - - -void GLAPIENTRY -_mesa_DisableIndexed( GLenum cap, GLuint index ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - _mesa_set_enablei(ctx, cap, index, GL_FALSE); -} - - -void GLAPIENTRY -_mesa_EnableIndexed( GLenum cap, GLuint index ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - _mesa_set_enablei(ctx, cap, index, GL_TRUE); -} - - -GLboolean GLAPIENTRY -_mesa_IsEnabledIndexed( GLenum cap, GLuint index ) -{ - GET_CURRENT_CONTEXT(ctx); - switch (cap) { - case GL_BLEND: - if (index >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glIsEnabledIndexed(index=%u)", - index); - return GL_FALSE; - } - return (ctx->Color.BlendEnabled >> index) & 1; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glIsEnabledIndexed(cap=%s)", - _mesa_lookup_enum_by_nr(cap)); - return GL_FALSE; - } -} - - - - -#undef CHECK_EXTENSION -#define CHECK_EXTENSION(EXTNAME) \ - if (!ctx->Extensions.EXTNAME) { \ - goto invalid_enum_error; \ - } - -#undef CHECK_EXTENSION2 -#define CHECK_EXTENSION2(EXT1, EXT2) \ - if (!ctx->Extensions.EXT1 && !ctx->Extensions.EXT2) { \ - goto invalid_enum_error; \ - } - - -/** - * Helper function to determine whether a texture target is enabled. - */ -static GLboolean -is_texture_enabled(struct gl_context *ctx, GLbitfield bit) -{ - const struct gl_texture_unit *const texUnit = - &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - return (texUnit->Enabled & bit) ? GL_TRUE : GL_FALSE; -} - - -/** - * Return simple enable/disable state. - * - * \param cap state variable to query. - * - * Returns the state of the specified capability from the current GL context. - * For the capabilities associated with extensions verifies that those - * extensions are effectively present before reporting. - */ -GLboolean GLAPIENTRY -_mesa_IsEnabled( GLenum cap ) -{ - GET_CURRENT_CONTEXT(ctx); - switch (cap) { - case GL_ALPHA_TEST: - return ctx->Color.AlphaEnabled; - case GL_AUTO_NORMAL: - return ctx->Eval.AutoNormal; - case GL_BLEND: - return ctx->Color.BlendEnabled & 1; /* return state for buffer[0] */ - case GL_CLIP_PLANE0: - case GL_CLIP_PLANE1: - case GL_CLIP_PLANE2: - case GL_CLIP_PLANE3: - case GL_CLIP_PLANE4: - case GL_CLIP_PLANE5: - return (ctx->Transform.ClipPlanesEnabled >> (cap - GL_CLIP_PLANE0)) & 1; - case GL_COLOR_MATERIAL: - return ctx->Light.ColorMaterialEnabled; - case GL_CULL_FACE: - return ctx->Polygon.CullFlag; - case GL_DEPTH_TEST: - return ctx->Depth.Test; - case GL_DITHER: - return ctx->Color.DitherFlag; - case GL_FOG: - return ctx->Fog.Enabled; - case GL_LIGHTING: - return ctx->Light.Enabled; - case GL_LIGHT0: - case GL_LIGHT1: - case GL_LIGHT2: - case GL_LIGHT3: - case GL_LIGHT4: - case GL_LIGHT5: - case GL_LIGHT6: - case GL_LIGHT7: - return ctx->Light.Light[cap-GL_LIGHT0].Enabled; - case GL_LINE_SMOOTH: - return ctx->Line.SmoothFlag; - case GL_LINE_STIPPLE: - return ctx->Line.StippleFlag; - case GL_INDEX_LOGIC_OP: - return ctx->Color.IndexLogicOpEnabled; - case GL_COLOR_LOGIC_OP: - return ctx->Color.ColorLogicOpEnabled; - case GL_MAP1_COLOR_4: - return ctx->Eval.Map1Color4; - case GL_MAP1_INDEX: - return ctx->Eval.Map1Index; - case GL_MAP1_NORMAL: - return ctx->Eval.Map1Normal; - case GL_MAP1_TEXTURE_COORD_1: - return ctx->Eval.Map1TextureCoord1; - case GL_MAP1_TEXTURE_COORD_2: - return ctx->Eval.Map1TextureCoord2; - case GL_MAP1_TEXTURE_COORD_3: - return ctx->Eval.Map1TextureCoord3; - case GL_MAP1_TEXTURE_COORD_4: - return ctx->Eval.Map1TextureCoord4; - case GL_MAP1_VERTEX_3: - return ctx->Eval.Map1Vertex3; - case GL_MAP1_VERTEX_4: - return ctx->Eval.Map1Vertex4; - case GL_MAP2_COLOR_4: - return ctx->Eval.Map2Color4; - case GL_MAP2_INDEX: - return ctx->Eval.Map2Index; - case GL_MAP2_NORMAL: - return ctx->Eval.Map2Normal; - case GL_MAP2_TEXTURE_COORD_1: - return ctx->Eval.Map2TextureCoord1; - case GL_MAP2_TEXTURE_COORD_2: - return ctx->Eval.Map2TextureCoord2; - case GL_MAP2_TEXTURE_COORD_3: - return ctx->Eval.Map2TextureCoord3; - case GL_MAP2_TEXTURE_COORD_4: - return ctx->Eval.Map2TextureCoord4; - case GL_MAP2_VERTEX_3: - return ctx->Eval.Map2Vertex3; - case GL_MAP2_VERTEX_4: - return ctx->Eval.Map2Vertex4; - case GL_NORMALIZE: - return ctx->Transform.Normalize; - case GL_POINT_SMOOTH: - return ctx->Point.SmoothFlag; - case GL_POLYGON_SMOOTH: - return ctx->Polygon.SmoothFlag; - case GL_POLYGON_STIPPLE: - return ctx->Polygon.StippleFlag; - case GL_POLYGON_OFFSET_POINT: - return ctx->Polygon.OffsetPoint; - case GL_POLYGON_OFFSET_LINE: - return ctx->Polygon.OffsetLine; - case GL_POLYGON_OFFSET_FILL: - /*case GL_POLYGON_OFFSET_EXT:*/ - return ctx->Polygon.OffsetFill; - case GL_RESCALE_NORMAL_EXT: - return ctx->Transform.RescaleNormals; - case GL_SCISSOR_TEST: - return ctx->Scissor.Enabled; - case GL_SHARED_TEXTURE_PALETTE_EXT: - return ctx->Texture.SharedPalette; - case GL_STENCIL_TEST: - return ctx->Stencil.Enabled; - case GL_TEXTURE_1D: - return is_texture_enabled(ctx, TEXTURE_1D_BIT); - case GL_TEXTURE_2D: - return is_texture_enabled(ctx, TEXTURE_2D_BIT); - case GL_TEXTURE_3D: - return is_texture_enabled(ctx, TEXTURE_3D_BIT); - case GL_TEXTURE_GEN_Q: - { - const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - return (texUnit->TexGenEnabled & Q_BIT) ? GL_TRUE : GL_FALSE; - } - } - return GL_FALSE; - case GL_TEXTURE_GEN_R: - { - const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - return (texUnit->TexGenEnabled & R_BIT) ? GL_TRUE : GL_FALSE; - } - } - return GL_FALSE; - case GL_TEXTURE_GEN_S: - { - const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - return (texUnit->TexGenEnabled & S_BIT) ? GL_TRUE : GL_FALSE; - } - } - return GL_FALSE; - case GL_TEXTURE_GEN_T: - { - const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - return (texUnit->TexGenEnabled & T_BIT) ? GL_TRUE : GL_FALSE; - } - } - return GL_FALSE; -#if FEATURE_ES1 - case GL_TEXTURE_GEN_STR_OES: - { - const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); - if (texUnit) { - return (texUnit->TexGenEnabled & STR_BITS) == STR_BITS ? GL_TRUE : GL_FALSE; - } - } -#endif - - /* - * CLIENT STATE!!! - */ - case GL_VERTEX_ARRAY: - return (ctx->Array.ArrayObj->Vertex.Enabled != 0); - case GL_NORMAL_ARRAY: - return (ctx->Array.ArrayObj->Normal.Enabled != 0); - case GL_COLOR_ARRAY: - return (ctx->Array.ArrayObj->Color.Enabled != 0); - case GL_INDEX_ARRAY: - return (ctx->Array.ArrayObj->Index.Enabled != 0); - case GL_TEXTURE_COORD_ARRAY: - return (ctx->Array.ArrayObj->TexCoord[ctx->Array.ActiveTexture].Enabled != 0); - case GL_EDGE_FLAG_ARRAY: - return (ctx->Array.ArrayObj->EdgeFlag.Enabled != 0); - case GL_FOG_COORDINATE_ARRAY_EXT: - CHECK_EXTENSION(EXT_fog_coord); - return (ctx->Array.ArrayObj->FogCoord.Enabled != 0); - case GL_SECONDARY_COLOR_ARRAY_EXT: - CHECK_EXTENSION(EXT_secondary_color); - return (ctx->Array.ArrayObj->SecondaryColor.Enabled != 0); -#if FEATURE_point_size_array - case GL_POINT_SIZE_ARRAY_OES: - return (ctx->Array.ArrayObj->PointSize.Enabled != 0); -#endif - - /* GL_SGI_texture_color_table */ - case GL_TEXTURE_COLOR_TABLE_SGI: - CHECK_EXTENSION(SGI_texture_color_table); - return ctx->Texture.Unit[ctx->Texture.CurrentUnit].ColorTableEnabled; - - /* GL_ARB_texture_cube_map */ - case GL_TEXTURE_CUBE_MAP_ARB: - CHECK_EXTENSION(ARB_texture_cube_map); - return is_texture_enabled(ctx, TEXTURE_CUBE_BIT); - - /* GL_EXT_secondary_color */ - case GL_COLOR_SUM_EXT: - CHECK_EXTENSION2(EXT_secondary_color, ARB_vertex_program); - return ctx->Fog.ColorSumEnabled; - - /* GL_ARB_multisample */ - case GL_MULTISAMPLE_ARB: - return ctx->Multisample.Enabled; - case GL_SAMPLE_ALPHA_TO_COVERAGE_ARB: - return ctx->Multisample.SampleAlphaToCoverage; - case GL_SAMPLE_ALPHA_TO_ONE_ARB: - return ctx->Multisample.SampleAlphaToOne; - case GL_SAMPLE_COVERAGE_ARB: - return ctx->Multisample.SampleCoverage; - case GL_SAMPLE_COVERAGE_INVERT_ARB: - return ctx->Multisample.SampleCoverageInvert; - - /* GL_IBM_rasterpos_clip */ - case GL_RASTER_POSITION_UNCLIPPED_IBM: - CHECK_EXTENSION(IBM_rasterpos_clip); - return ctx->Transform.RasterPositionUnclipped; - - /* GL_NV_point_sprite */ - case GL_POINT_SPRITE_NV: - CHECK_EXTENSION2(NV_point_sprite, ARB_point_sprite) - return ctx->Point.PointSprite; - -#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program - case GL_VERTEX_PROGRAM_ARB: - CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program); - return ctx->VertexProgram.Enabled; - case GL_VERTEX_PROGRAM_POINT_SIZE_ARB: - CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program); - return ctx->VertexProgram.PointSizeEnabled; - case GL_VERTEX_PROGRAM_TWO_SIDE_ARB: - CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program); - return ctx->VertexProgram.TwoSideEnabled; -#endif -#if FEATURE_NV_vertex_program - case GL_VERTEX_ATTRIB_ARRAY0_NV: - case GL_VERTEX_ATTRIB_ARRAY1_NV: - case GL_VERTEX_ATTRIB_ARRAY2_NV: - case GL_VERTEX_ATTRIB_ARRAY3_NV: - case GL_VERTEX_ATTRIB_ARRAY4_NV: - case GL_VERTEX_ATTRIB_ARRAY5_NV: - case GL_VERTEX_ATTRIB_ARRAY6_NV: - case GL_VERTEX_ATTRIB_ARRAY7_NV: - case GL_VERTEX_ATTRIB_ARRAY8_NV: - case GL_VERTEX_ATTRIB_ARRAY9_NV: - case GL_VERTEX_ATTRIB_ARRAY10_NV: - case GL_VERTEX_ATTRIB_ARRAY11_NV: - case GL_VERTEX_ATTRIB_ARRAY12_NV: - case GL_VERTEX_ATTRIB_ARRAY13_NV: - case GL_VERTEX_ATTRIB_ARRAY14_NV: - case GL_VERTEX_ATTRIB_ARRAY15_NV: - CHECK_EXTENSION(NV_vertex_program); - { - GLint n = (GLint) cap - GL_VERTEX_ATTRIB_ARRAY0_NV; - ASSERT(n < Elements(ctx->Array.ArrayObj->VertexAttrib)); - return (ctx->Array.ArrayObj->VertexAttrib[n].Enabled != 0); - } - case GL_MAP1_VERTEX_ATTRIB0_4_NV: - case GL_MAP1_VERTEX_ATTRIB1_4_NV: - case GL_MAP1_VERTEX_ATTRIB2_4_NV: - case GL_MAP1_VERTEX_ATTRIB3_4_NV: - case GL_MAP1_VERTEX_ATTRIB4_4_NV: - case GL_MAP1_VERTEX_ATTRIB5_4_NV: - case GL_MAP1_VERTEX_ATTRIB6_4_NV: - case GL_MAP1_VERTEX_ATTRIB7_4_NV: - case GL_MAP1_VERTEX_ATTRIB8_4_NV: - case GL_MAP1_VERTEX_ATTRIB9_4_NV: - case GL_MAP1_VERTEX_ATTRIB10_4_NV: - case GL_MAP1_VERTEX_ATTRIB11_4_NV: - case GL_MAP1_VERTEX_ATTRIB12_4_NV: - case GL_MAP1_VERTEX_ATTRIB13_4_NV: - case GL_MAP1_VERTEX_ATTRIB14_4_NV: - case GL_MAP1_VERTEX_ATTRIB15_4_NV: - CHECK_EXTENSION(NV_vertex_program); - { - const GLuint map = (GLuint) (cap - GL_MAP1_VERTEX_ATTRIB0_4_NV); - return ctx->Eval.Map1Attrib[map]; - } - case GL_MAP2_VERTEX_ATTRIB0_4_NV: - case GL_MAP2_VERTEX_ATTRIB1_4_NV: - case GL_MAP2_VERTEX_ATTRIB2_4_NV: - case GL_MAP2_VERTEX_ATTRIB3_4_NV: - case GL_MAP2_VERTEX_ATTRIB4_4_NV: - case GL_MAP2_VERTEX_ATTRIB5_4_NV: - case GL_MAP2_VERTEX_ATTRIB6_4_NV: - case GL_MAP2_VERTEX_ATTRIB7_4_NV: - case GL_MAP2_VERTEX_ATTRIB8_4_NV: - case GL_MAP2_VERTEX_ATTRIB9_4_NV: - case GL_MAP2_VERTEX_ATTRIB10_4_NV: - case GL_MAP2_VERTEX_ATTRIB11_4_NV: - case GL_MAP2_VERTEX_ATTRIB12_4_NV: - case GL_MAP2_VERTEX_ATTRIB13_4_NV: - case GL_MAP2_VERTEX_ATTRIB14_4_NV: - case GL_MAP2_VERTEX_ATTRIB15_4_NV: - CHECK_EXTENSION(NV_vertex_program); - { - const GLuint map = (GLuint) (cap - GL_MAP2_VERTEX_ATTRIB0_4_NV); - return ctx->Eval.Map2Attrib[map]; - } -#endif /* FEATURE_NV_vertex_program */ - -#if FEATURE_NV_fragment_program - case GL_FRAGMENT_PROGRAM_NV: - CHECK_EXTENSION(NV_fragment_program); - return ctx->FragmentProgram.Enabled; -#endif /* FEATURE_NV_fragment_program */ - - /* GL_NV_texture_rectangle */ - case GL_TEXTURE_RECTANGLE_NV: - CHECK_EXTENSION(NV_texture_rectangle); - return is_texture_enabled(ctx, TEXTURE_RECT_BIT); - - /* GL_EXT_stencil_two_side */ - case GL_STENCIL_TEST_TWO_SIDE_EXT: - CHECK_EXTENSION(EXT_stencil_two_side); - return ctx->Stencil.TestTwoSide; - -#if FEATURE_ARB_fragment_program - case GL_FRAGMENT_PROGRAM_ARB: - return ctx->FragmentProgram.Enabled; -#endif /* FEATURE_ARB_fragment_program */ - - /* GL_EXT_depth_bounds_test */ - case GL_DEPTH_BOUNDS_TEST_EXT: - CHECK_EXTENSION(EXT_depth_bounds_test); - return ctx->Depth.BoundsTest; - - /* GL_ARB_depth_clamp */ - case GL_DEPTH_CLAMP: - CHECK_EXTENSION(ARB_depth_clamp); - return ctx->Transform.DepthClamp; - -#if FEATURE_ATI_fragment_shader - case GL_FRAGMENT_SHADER_ATI: - CHECK_EXTENSION(ATI_fragment_shader); - return ctx->ATIFragmentShader.Enabled; -#endif /* FEATURE_ATI_fragment_shader */ - - case GL_TEXTURE_CUBE_MAP_SEAMLESS: - CHECK_EXTENSION(ARB_seamless_cube_map); - return ctx->Texture.CubeMapSeamless; - -#if FEATURE_EXT_transform_feedback - case GL_RASTERIZER_DISCARD: - CHECK_EXTENSION(EXT_transform_feedback); - return ctx->TransformFeedback.RasterDiscard; -#endif - - /* GL_NV_primitive_restart */ - case GL_PRIMITIVE_RESTART_NV: - if (!ctx->Extensions.NV_primitive_restart) { - goto invalid_enum_error; - } - return ctx->Array.PrimitiveRestart; - - /* GL 3.1 primitive restart */ - case GL_PRIMITIVE_RESTART: - if (ctx->VersionMajor * 10 + ctx->VersionMinor < 31) { - goto invalid_enum_error; - } - return ctx->Array.PrimitiveRestart; - - /* GL3.0 - GL_framebuffer_sRGB */ - case GL_FRAMEBUFFER_SRGB_EXT: - CHECK_EXTENSION(EXT_framebuffer_sRGB); - return ctx->Color.sRGBEnabled; - - default: - goto invalid_enum_error; - } - - return GL_FALSE; - -invalid_enum_error: - _mesa_error(ctx, GL_INVALID_ENUM, "glIsEnabled(0x%x)", (int) cap); - return GL_FALSE; -} +/** + * \file enable.c + * Enable/disable/query GL capabilities. + */ + +/* + * Mesa 3-D graphics library + * Version: 7.0.3 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include "glheader.h" +#include "context.h" +#include "enable.h" +#include "light.h" +#include "simple_list.h" +#include "mfeatures.h" +#include "mtypes.h" +#include "enums.h" +#include "api_arrayelt.h" +#include "texstate.h" + + + +#define CHECK_EXTENSION(EXTNAME, CAP) \ + if (!ctx->Extensions.EXTNAME) { \ + goto invalid_enum_error; \ + } + + +/** + * Helper to enable/disable client-side state. + */ +static void +client_state(struct gl_context *ctx, GLenum cap, GLboolean state) +{ + struct gl_array_object *arrayObj = ctx->Array.ArrayObj; + GLuint flag; + GLboolean *var; + + switch (cap) { + case GL_VERTEX_ARRAY: + var = &arrayObj->Vertex.Enabled; + flag = _NEW_ARRAY_VERTEX; + break; + case GL_NORMAL_ARRAY: + var = &arrayObj->Normal.Enabled; + flag = _NEW_ARRAY_NORMAL; + break; + case GL_COLOR_ARRAY: + var = &arrayObj->Color.Enabled; + flag = _NEW_ARRAY_COLOR0; + break; + case GL_INDEX_ARRAY: + var = &arrayObj->Index.Enabled; + flag = _NEW_ARRAY_INDEX; + break; + case GL_TEXTURE_COORD_ARRAY: + var = &arrayObj->TexCoord[ctx->Array.ActiveTexture].Enabled; + flag = _NEW_ARRAY_TEXCOORD(ctx->Array.ActiveTexture); + break; + case GL_EDGE_FLAG_ARRAY: + var = &arrayObj->EdgeFlag.Enabled; + flag = _NEW_ARRAY_EDGEFLAG; + break; + case GL_FOG_COORDINATE_ARRAY_EXT: + var = &arrayObj->FogCoord.Enabled; + flag = _NEW_ARRAY_FOGCOORD; + break; + case GL_SECONDARY_COLOR_ARRAY_EXT: + var = &arrayObj->SecondaryColor.Enabled; + flag = _NEW_ARRAY_COLOR1; + break; + +#if FEATURE_point_size_array + case GL_POINT_SIZE_ARRAY_OES: + var = &arrayObj->PointSize.Enabled; + flag = _NEW_ARRAY_POINT_SIZE; + break; +#endif + +#if FEATURE_NV_vertex_program + case GL_VERTEX_ATTRIB_ARRAY0_NV: + case GL_VERTEX_ATTRIB_ARRAY1_NV: + case GL_VERTEX_ATTRIB_ARRAY2_NV: + case GL_VERTEX_ATTRIB_ARRAY3_NV: + case GL_VERTEX_ATTRIB_ARRAY4_NV: + case GL_VERTEX_ATTRIB_ARRAY5_NV: + case GL_VERTEX_ATTRIB_ARRAY6_NV: + case GL_VERTEX_ATTRIB_ARRAY7_NV: + case GL_VERTEX_ATTRIB_ARRAY8_NV: + case GL_VERTEX_ATTRIB_ARRAY9_NV: + case GL_VERTEX_ATTRIB_ARRAY10_NV: + case GL_VERTEX_ATTRIB_ARRAY11_NV: + case GL_VERTEX_ATTRIB_ARRAY12_NV: + case GL_VERTEX_ATTRIB_ARRAY13_NV: + case GL_VERTEX_ATTRIB_ARRAY14_NV: + case GL_VERTEX_ATTRIB_ARRAY15_NV: + CHECK_EXTENSION(NV_vertex_program, cap); + { + GLint n = (GLint) cap - GL_VERTEX_ATTRIB_ARRAY0_NV; + ASSERT(n < Elements(ctx->Array.ArrayObj->VertexAttrib)); + var = &arrayObj->VertexAttrib[n].Enabled; + flag = _NEW_ARRAY_ATTRIB(n); + } + break; +#endif /* FEATURE_NV_vertex_program */ + + /* GL_NV_primitive_restart */ + case GL_PRIMITIVE_RESTART_NV: + if (!ctx->Extensions.NV_primitive_restart) { + goto invalid_enum_error; + } + var = &ctx->Array.PrimitiveRestart; + flag = 0; + break; + + default: + goto invalid_enum_error; + } + + if (*var == state) + return; + + FLUSH_VERTICES(ctx, _NEW_ARRAY); + ctx->Array.NewState |= flag; + + _ae_invalidate_state(ctx, _NEW_ARRAY); + + *var = state; + + if (state) + ctx->Array.ArrayObj->_Enabled |= flag; + else + ctx->Array.ArrayObj->_Enabled &= ~flag; + + if (ctx->Driver.Enable) { + ctx->Driver.Enable( ctx, cap, state ); + } + + return; + +invalid_enum_error: + _mesa_error(ctx, GL_INVALID_ENUM, "gl%sClientState(0x%x)", + state ? "Enable" : "Disable", cap); +} + + +/** + * Enable GL capability. + * \param cap state to enable/disable. + * + * Get's the current context, assures that we're outside glBegin()/glEnd() and + * calls client_state(). + */ +void GLAPIENTRY +_mesa_EnableClientState( GLenum cap ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + client_state( ctx, cap, GL_TRUE ); +} + + +/** + * Disable GL capability. + * \param cap state to enable/disable. + * + * Get's the current context, assures that we're outside glBegin()/glEnd() and + * calls client_state(). + */ +void GLAPIENTRY +_mesa_DisableClientState( GLenum cap ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + client_state( ctx, cap, GL_FALSE ); +} + + +#undef CHECK_EXTENSION +#define CHECK_EXTENSION(EXTNAME, CAP) \ + if (!ctx->Extensions.EXTNAME) { \ + goto invalid_enum_error; \ + } + +#define CHECK_EXTENSION2(EXT1, EXT2, CAP) \ + if (!ctx->Extensions.EXT1 && !ctx->Extensions.EXT2) { \ + goto invalid_enum_error; \ + } + + + +/** + * Return pointer to current texture unit for setting/getting coordinate + * state. + * Note that we'll set GL_INVALID_OPERATION if the active texture unit is + * higher than the number of supported coordinate units. And we'll return NULL. + */ +static struct gl_texture_unit * +get_texcoord_unit(struct gl_context *ctx) +{ + if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glEnable/Disable(texcoord unit)"); + return NULL; + } + else { + return &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + } +} + + +/** + * Helper function to enable or disable a texture target. + * \param bit one of the TEXTURE_x_BIT values + * \return GL_TRUE if state is changing or GL_FALSE if no change + */ +static GLboolean +enable_texture(struct gl_context *ctx, GLboolean state, GLbitfield texBit) +{ + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + const GLbitfield newenabled = state + ? (texUnit->Enabled | texBit) : (texUnit->Enabled & ~texBit); + + if (texUnit->Enabled == newenabled) + return GL_FALSE; + + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + texUnit->Enabled = newenabled; + return GL_TRUE; +} + + +/** + * Helper function to enable or disable state. + * + * \param ctx GL context. + * \param cap the state to enable/disable + * \param state whether to enable or disable the specified capability. + * + * Updates the current context and flushes the vertices as needed. For + * capabilities associated with extensions it verifies that those extensions + * are effectivly present before updating. Notifies the driver via + * dd_function_table::Enable. + */ +void +_mesa_set_enable(struct gl_context *ctx, GLenum cap, GLboolean state) +{ + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "%s %s (newstate is %x)\n", + state ? "glEnable" : "glDisable", + _mesa_lookup_enum_by_nr(cap), + ctx->NewState); + + switch (cap) { + case GL_ALPHA_TEST: + if (ctx->Color.AlphaEnabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.AlphaEnabled = state; + break; + case GL_AUTO_NORMAL: + if (ctx->Eval.AutoNormal == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.AutoNormal = state; + break; + case GL_BLEND: + { + GLbitfield newEnabled = state * ((1 << ctx->Const.MaxDrawBuffers) - 1); + if (newEnabled != ctx->Color.BlendEnabled) { + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.BlendEnabled = newEnabled; + } + } + break; +#if FEATURE_userclip + case GL_CLIP_PLANE0: + case GL_CLIP_PLANE1: + case GL_CLIP_PLANE2: + case GL_CLIP_PLANE3: + case GL_CLIP_PLANE4: + case GL_CLIP_PLANE5: + { + const GLuint p = cap - GL_CLIP_PLANE0; + + if ((ctx->Transform.ClipPlanesEnabled & (1 << p)) == ((GLuint) state << p)) + return; + + FLUSH_VERTICES(ctx, _NEW_TRANSFORM); + + if (state) { + ctx->Transform.ClipPlanesEnabled |= (1 << p); + + if (_math_matrix_is_dirty(ctx->ProjectionMatrixStack.Top)) + _math_matrix_analyse( ctx->ProjectionMatrixStack.Top ); + + /* This derived state also calculated in clip.c and + * from _mesa_update_state() on changes to EyeUserPlane + * and ctx->ProjectionMatrix respectively. + */ + _mesa_transform_vector( ctx->Transform._ClipUserPlane[p], + ctx->Transform.EyeUserPlane[p], + ctx->ProjectionMatrixStack.Top->inv ); + } + else { + ctx->Transform.ClipPlanesEnabled &= ~(1 << p); + } + } + break; +#endif + case GL_COLOR_MATERIAL: + if (ctx->Light.ColorMaterialEnabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_LIGHT); + FLUSH_CURRENT(ctx, 0); + ctx->Light.ColorMaterialEnabled = state; + if (state) { + _mesa_update_color_material( ctx, + ctx->Current.Attrib[VERT_ATTRIB_COLOR0] ); + } + break; + case GL_CULL_FACE: + if (ctx->Polygon.CullFlag == state) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.CullFlag = state; + break; + case GL_DEPTH_TEST: + if (ctx->Depth.Test == state) + return; + FLUSH_VERTICES(ctx, _NEW_DEPTH); + ctx->Depth.Test = state; + break; + case GL_DITHER: + if (ctx->Color.DitherFlag == state) + return; + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.DitherFlag = state; + break; + case GL_FOG: + if (ctx->Fog.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_FOG); + ctx->Fog.Enabled = state; + break; + case GL_LIGHT0: + case GL_LIGHT1: + case GL_LIGHT2: + case GL_LIGHT3: + case GL_LIGHT4: + case GL_LIGHT5: + case GL_LIGHT6: + case GL_LIGHT7: + if (ctx->Light.Light[cap-GL_LIGHT0].Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_LIGHT); + ctx->Light.Light[cap-GL_LIGHT0].Enabled = state; + if (state) { + insert_at_tail(&ctx->Light.EnabledList, + &ctx->Light.Light[cap-GL_LIGHT0]); + } + else { + remove_from_list(&ctx->Light.Light[cap-GL_LIGHT0]); + } + break; + case GL_LIGHTING: + if (ctx->Light.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_LIGHT); + ctx->Light.Enabled = state; + if (ctx->Light.Enabled && ctx->Light.Model.TwoSide) + ctx->_TriangleCaps |= DD_TRI_LIGHT_TWOSIDE; + else + ctx->_TriangleCaps &= ~DD_TRI_LIGHT_TWOSIDE; + break; + case GL_LINE_SMOOTH: + if (ctx->Line.SmoothFlag == state) + return; + FLUSH_VERTICES(ctx, _NEW_LINE); + ctx->Line.SmoothFlag = state; + ctx->_TriangleCaps ^= DD_LINE_SMOOTH; + break; + case GL_LINE_STIPPLE: + if (ctx->Line.StippleFlag == state) + return; + FLUSH_VERTICES(ctx, _NEW_LINE); + ctx->Line.StippleFlag = state; + ctx->_TriangleCaps ^= DD_LINE_STIPPLE; + break; + case GL_INDEX_LOGIC_OP: + if (ctx->Color.IndexLogicOpEnabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.IndexLogicOpEnabled = state; + break; + case GL_COLOR_LOGIC_OP: + if (ctx->Color.ColorLogicOpEnabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.ColorLogicOpEnabled = state; + break; + case GL_MAP1_COLOR_4: + if (ctx->Eval.Map1Color4 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1Color4 = state; + break; + case GL_MAP1_INDEX: + if (ctx->Eval.Map1Index == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1Index = state; + break; + case GL_MAP1_NORMAL: + if (ctx->Eval.Map1Normal == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1Normal = state; + break; + case GL_MAP1_TEXTURE_COORD_1: + if (ctx->Eval.Map1TextureCoord1 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1TextureCoord1 = state; + break; + case GL_MAP1_TEXTURE_COORD_2: + if (ctx->Eval.Map1TextureCoord2 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1TextureCoord2 = state; + break; + case GL_MAP1_TEXTURE_COORD_3: + if (ctx->Eval.Map1TextureCoord3 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1TextureCoord3 = state; + break; + case GL_MAP1_TEXTURE_COORD_4: + if (ctx->Eval.Map1TextureCoord4 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1TextureCoord4 = state; + break; + case GL_MAP1_VERTEX_3: + if (ctx->Eval.Map1Vertex3 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1Vertex3 = state; + break; + case GL_MAP1_VERTEX_4: + if (ctx->Eval.Map1Vertex4 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1Vertex4 = state; + break; + case GL_MAP2_COLOR_4: + if (ctx->Eval.Map2Color4 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2Color4 = state; + break; + case GL_MAP2_INDEX: + if (ctx->Eval.Map2Index == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2Index = state; + break; + case GL_MAP2_NORMAL: + if (ctx->Eval.Map2Normal == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2Normal = state; + break; + case GL_MAP2_TEXTURE_COORD_1: + if (ctx->Eval.Map2TextureCoord1 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2TextureCoord1 = state; + break; + case GL_MAP2_TEXTURE_COORD_2: + if (ctx->Eval.Map2TextureCoord2 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2TextureCoord2 = state; + break; + case GL_MAP2_TEXTURE_COORD_3: + if (ctx->Eval.Map2TextureCoord3 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2TextureCoord3 = state; + break; + case GL_MAP2_TEXTURE_COORD_4: + if (ctx->Eval.Map2TextureCoord4 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2TextureCoord4 = state; + break; + case GL_MAP2_VERTEX_3: + if (ctx->Eval.Map2Vertex3 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2Vertex3 = state; + break; + case GL_MAP2_VERTEX_4: + if (ctx->Eval.Map2Vertex4 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2Vertex4 = state; + break; + case GL_NORMALIZE: + if (ctx->Transform.Normalize == state) + return; + FLUSH_VERTICES(ctx, _NEW_TRANSFORM); + ctx->Transform.Normalize = state; + break; + case GL_POINT_SMOOTH: + if (ctx->Point.SmoothFlag == state) + return; + FLUSH_VERTICES(ctx, _NEW_POINT); + ctx->Point.SmoothFlag = state; + ctx->_TriangleCaps ^= DD_POINT_SMOOTH; + break; + case GL_POLYGON_SMOOTH: + if (ctx->Polygon.SmoothFlag == state) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.SmoothFlag = state; + ctx->_TriangleCaps ^= DD_TRI_SMOOTH; + break; + case GL_POLYGON_STIPPLE: + if (ctx->Polygon.StippleFlag == state) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.StippleFlag = state; + ctx->_TriangleCaps ^= DD_TRI_STIPPLE; + break; + case GL_POLYGON_OFFSET_POINT: + if (ctx->Polygon.OffsetPoint == state) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.OffsetPoint = state; + break; + case GL_POLYGON_OFFSET_LINE: + if (ctx->Polygon.OffsetLine == state) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.OffsetLine = state; + break; + case GL_POLYGON_OFFSET_FILL: + /*case GL_POLYGON_OFFSET_EXT:*/ + if (ctx->Polygon.OffsetFill == state) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.OffsetFill = state; + break; + case GL_RESCALE_NORMAL_EXT: + if (ctx->Transform.RescaleNormals == state) + return; + FLUSH_VERTICES(ctx, _NEW_TRANSFORM); + ctx->Transform.RescaleNormals = state; + break; + case GL_SCISSOR_TEST: + if (ctx->Scissor.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_SCISSOR); + ctx->Scissor.Enabled = state; + break; + case GL_SHARED_TEXTURE_PALETTE_EXT: + if (ctx->Texture.SharedPalette == state) + return; + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + ctx->Texture.SharedPalette = state; + break; + case GL_STENCIL_TEST: + if (ctx->Stencil.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.Enabled = state; + break; + case GL_TEXTURE_1D: + if (!enable_texture(ctx, state, TEXTURE_1D_BIT)) { + return; + } + break; + case GL_TEXTURE_2D: + if (!enable_texture(ctx, state, TEXTURE_2D_BIT)) { + return; + } + break; + case GL_TEXTURE_3D: + if (!enable_texture(ctx, state, TEXTURE_3D_BIT)) { + return; + } + break; + case GL_TEXTURE_GEN_Q: + { + struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + GLuint newenabled = texUnit->TexGenEnabled & ~Q_BIT; + if (state) + newenabled |= Q_BIT; + if (texUnit->TexGenEnabled == newenabled) + return; + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + texUnit->TexGenEnabled = newenabled; + } + } + break; + case GL_TEXTURE_GEN_R: + { + struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + GLuint newenabled = texUnit->TexGenEnabled & ~R_BIT; + if (state) + newenabled |= R_BIT; + if (texUnit->TexGenEnabled == newenabled) + return; + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + texUnit->TexGenEnabled = newenabled; + } + } + break; + case GL_TEXTURE_GEN_S: + { + struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + GLuint newenabled = texUnit->TexGenEnabled & ~S_BIT; + if (state) + newenabled |= S_BIT; + if (texUnit->TexGenEnabled == newenabled) + return; + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + texUnit->TexGenEnabled = newenabled; + } + } + break; + case GL_TEXTURE_GEN_T: + { + struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + GLuint newenabled = texUnit->TexGenEnabled & ~T_BIT; + if (state) + newenabled |= T_BIT; + if (texUnit->TexGenEnabled == newenabled) + return; + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + texUnit->TexGenEnabled = newenabled; + } + } + break; + +#if FEATURE_ES1 + case GL_TEXTURE_GEN_STR_OES: + /* disable S, T, and R at the same time */ + { + struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + GLuint newenabled = + texUnit->TexGenEnabled & ~STR_BITS; + if (state) + newenabled |= STR_BITS; + if (texUnit->TexGenEnabled == newenabled) + return; + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + texUnit->TexGenEnabled = newenabled; + } + } + break; +#endif + + /* + * CLIENT STATE!!! + */ + case GL_VERTEX_ARRAY: + case GL_NORMAL_ARRAY: + case GL_COLOR_ARRAY: + case GL_INDEX_ARRAY: + case GL_TEXTURE_COORD_ARRAY: + case GL_EDGE_FLAG_ARRAY: + case GL_FOG_COORDINATE_ARRAY_EXT: + case GL_SECONDARY_COLOR_ARRAY_EXT: + case GL_POINT_SIZE_ARRAY_OES: + client_state( ctx, cap, state ); + return; + + /* GL_ARB_texture_cube_map */ + case GL_TEXTURE_CUBE_MAP_ARB: + CHECK_EXTENSION(ARB_texture_cube_map, cap); + if (!enable_texture(ctx, state, TEXTURE_CUBE_BIT)) { + return; + } + break; + + /* GL_EXT_secondary_color */ + case GL_COLOR_SUM_EXT: + CHECK_EXTENSION2(EXT_secondary_color, ARB_vertex_program, cap); + if (ctx->Fog.ColorSumEnabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_FOG); + ctx->Fog.ColorSumEnabled = state; + break; + + /* GL_ARB_multisample */ + case GL_MULTISAMPLE_ARB: + if (ctx->Multisample.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); + ctx->Multisample.Enabled = state; + break; + case GL_SAMPLE_ALPHA_TO_COVERAGE_ARB: + if (ctx->Multisample.SampleAlphaToCoverage == state) + return; + FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); + ctx->Multisample.SampleAlphaToCoverage = state; + break; + case GL_SAMPLE_ALPHA_TO_ONE_ARB: + if (ctx->Multisample.SampleAlphaToOne == state) + return; + FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); + ctx->Multisample.SampleAlphaToOne = state; + break; + case GL_SAMPLE_COVERAGE_ARB: + if (ctx->Multisample.SampleCoverage == state) + return; + FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); + ctx->Multisample.SampleCoverage = state; + break; + case GL_SAMPLE_COVERAGE_INVERT_ARB: + if (ctx->Multisample.SampleCoverageInvert == state) + return; + FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); + ctx->Multisample.SampleCoverageInvert = state; + break; + + /* GL_IBM_rasterpos_clip */ + case GL_RASTER_POSITION_UNCLIPPED_IBM: + CHECK_EXTENSION(IBM_rasterpos_clip, cap); + if (ctx->Transform.RasterPositionUnclipped == state) + return; + FLUSH_VERTICES(ctx, _NEW_TRANSFORM); + ctx->Transform.RasterPositionUnclipped = state; + break; + + /* GL_NV_point_sprite */ + case GL_POINT_SPRITE_NV: + CHECK_EXTENSION2(NV_point_sprite, ARB_point_sprite, cap); + if (ctx->Point.PointSprite == state) + return; + FLUSH_VERTICES(ctx, _NEW_POINT); + ctx->Point.PointSprite = state; + break; + +#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program + case GL_VERTEX_PROGRAM_ARB: + CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap); + if (ctx->VertexProgram.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + ctx->VertexProgram.Enabled = state; + break; + case GL_VERTEX_PROGRAM_POINT_SIZE_ARB: + CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap); + if (ctx->VertexProgram.PointSizeEnabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + ctx->VertexProgram.PointSizeEnabled = state; + break; + case GL_VERTEX_PROGRAM_TWO_SIDE_ARB: + CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap); + if (ctx->VertexProgram.TwoSideEnabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + ctx->VertexProgram.TwoSideEnabled = state; + break; +#endif +#if FEATURE_NV_vertex_program + case GL_MAP1_VERTEX_ATTRIB0_4_NV: + case GL_MAP1_VERTEX_ATTRIB1_4_NV: + case GL_MAP1_VERTEX_ATTRIB2_4_NV: + case GL_MAP1_VERTEX_ATTRIB3_4_NV: + case GL_MAP1_VERTEX_ATTRIB4_4_NV: + case GL_MAP1_VERTEX_ATTRIB5_4_NV: + case GL_MAP1_VERTEX_ATTRIB6_4_NV: + case GL_MAP1_VERTEX_ATTRIB7_4_NV: + case GL_MAP1_VERTEX_ATTRIB8_4_NV: + case GL_MAP1_VERTEX_ATTRIB9_4_NV: + case GL_MAP1_VERTEX_ATTRIB10_4_NV: + case GL_MAP1_VERTEX_ATTRIB11_4_NV: + case GL_MAP1_VERTEX_ATTRIB12_4_NV: + case GL_MAP1_VERTEX_ATTRIB13_4_NV: + case GL_MAP1_VERTEX_ATTRIB14_4_NV: + case GL_MAP1_VERTEX_ATTRIB15_4_NV: + CHECK_EXTENSION(NV_vertex_program, cap); + { + const GLuint map = (GLuint) (cap - GL_MAP1_VERTEX_ATTRIB0_4_NV); + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1Attrib[map] = state; + } + break; + case GL_MAP2_VERTEX_ATTRIB0_4_NV: + case GL_MAP2_VERTEX_ATTRIB1_4_NV: + case GL_MAP2_VERTEX_ATTRIB2_4_NV: + case GL_MAP2_VERTEX_ATTRIB3_4_NV: + case GL_MAP2_VERTEX_ATTRIB4_4_NV: + case GL_MAP2_VERTEX_ATTRIB5_4_NV: + case GL_MAP2_VERTEX_ATTRIB6_4_NV: + case GL_MAP2_VERTEX_ATTRIB7_4_NV: + case GL_MAP2_VERTEX_ATTRIB8_4_NV: + case GL_MAP2_VERTEX_ATTRIB9_4_NV: + case GL_MAP2_VERTEX_ATTRIB10_4_NV: + case GL_MAP2_VERTEX_ATTRIB11_4_NV: + case GL_MAP2_VERTEX_ATTRIB12_4_NV: + case GL_MAP2_VERTEX_ATTRIB13_4_NV: + case GL_MAP2_VERTEX_ATTRIB14_4_NV: + case GL_MAP2_VERTEX_ATTRIB15_4_NV: + CHECK_EXTENSION(NV_vertex_program, cap); + { + const GLuint map = (GLuint) (cap - GL_MAP2_VERTEX_ATTRIB0_4_NV); + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2Attrib[map] = state; + } + break; +#endif /* FEATURE_NV_vertex_program */ + +#if FEATURE_NV_fragment_program + case GL_FRAGMENT_PROGRAM_NV: + CHECK_EXTENSION(NV_fragment_program, cap); + if (ctx->FragmentProgram.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + ctx->FragmentProgram.Enabled = state; + break; +#endif /* FEATURE_NV_fragment_program */ + + /* GL_NV_texture_rectangle */ + case GL_TEXTURE_RECTANGLE_NV: + CHECK_EXTENSION(NV_texture_rectangle, cap); + if (!enable_texture(ctx, state, TEXTURE_RECT_BIT)) { + return; + } + break; + + /* GL_EXT_stencil_two_side */ + case GL_STENCIL_TEST_TWO_SIDE_EXT: + CHECK_EXTENSION(EXT_stencil_two_side, cap); + if (ctx->Stencil.TestTwoSide == state) + return; + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.TestTwoSide = state; + if (state) { + ctx->Stencil._BackFace = 2; + ctx->_TriangleCaps |= DD_TRI_TWOSTENCIL; + } else { + ctx->Stencil._BackFace = 1; + ctx->_TriangleCaps &= ~DD_TRI_TWOSTENCIL; + } + break; + +#if FEATURE_ARB_fragment_program + case GL_FRAGMENT_PROGRAM_ARB: + CHECK_EXTENSION(ARB_fragment_program, cap); + if (ctx->FragmentProgram.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + ctx->FragmentProgram.Enabled = state; + break; +#endif /* FEATURE_ARB_fragment_program */ + + /* GL_EXT_depth_bounds_test */ + case GL_DEPTH_BOUNDS_TEST_EXT: + CHECK_EXTENSION(EXT_depth_bounds_test, cap); + if (ctx->Depth.BoundsTest == state) + return; + FLUSH_VERTICES(ctx, _NEW_DEPTH); + ctx->Depth.BoundsTest = state; + break; + + case GL_DEPTH_CLAMP: + if (ctx->Transform.DepthClamp == state) + return; + CHECK_EXTENSION(ARB_depth_clamp, cap); + FLUSH_VERTICES(ctx, _NEW_TRANSFORM); + ctx->Transform.DepthClamp = state; + break; + +#if FEATURE_ATI_fragment_shader + case GL_FRAGMENT_SHADER_ATI: + CHECK_EXTENSION(ATI_fragment_shader, cap); + if (ctx->ATIFragmentShader.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + ctx->ATIFragmentShader.Enabled = state; + break; +#endif + + /* GL_MESA_texture_array */ + case GL_TEXTURE_1D_ARRAY_EXT: + CHECK_EXTENSION(MESA_texture_array, cap); + if (!enable_texture(ctx, state, TEXTURE_1D_ARRAY_BIT)) { + return; + } + break; + + case GL_TEXTURE_2D_ARRAY_EXT: + CHECK_EXTENSION(MESA_texture_array, cap); + if (!enable_texture(ctx, state, TEXTURE_2D_ARRAY_BIT)) { + return; + } + break; + + case GL_TEXTURE_CUBE_MAP_SEAMLESS: + CHECK_EXTENSION(ARB_seamless_cube_map, cap); + ctx->Texture.CubeMapSeamless = state; + break; + +#if FEATURE_EXT_transform_feedback + case GL_RASTERIZER_DISCARD: + CHECK_EXTENSION(EXT_transform_feedback, cap); + if (ctx->TransformFeedback.RasterDiscard != state) { + ctx->TransformFeedback.RasterDiscard = state; + FLUSH_VERTICES(ctx, _NEW_TRANSFORM); + } + break; +#endif + + /* GL 3.1 primitive restart. Note: this enum is different from + * GL_PRIMITIVE_RESTART_NV (which is client state). + */ + case GL_PRIMITIVE_RESTART: + if (ctx->VersionMajor * 10 + ctx->VersionMinor < 31) { + goto invalid_enum_error; + } + if (ctx->Array.PrimitiveRestart != state) { + FLUSH_VERTICES(ctx, _NEW_TRANSFORM); + ctx->Array.PrimitiveRestart = state; + } + break; + + /* GL3.0 - GL_framebuffer_sRGB */ + case GL_FRAMEBUFFER_SRGB_EXT: + CHECK_EXTENSION(EXT_framebuffer_sRGB, cap); + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + ctx->Color.sRGBEnabled = state; + break; + + default: + goto invalid_enum_error; + } + + if (ctx->Driver.Enable) { + ctx->Driver.Enable( ctx, cap, state ); + } + + return; + +invalid_enum_error: + _mesa_error(ctx, GL_INVALID_ENUM, "gl%s(0x%x)", + state ? "Enable" : "Disable", cap); +} + + +/** + * Enable GL capability. Called by glEnable() + * \param cap state to enable. + */ +void GLAPIENTRY +_mesa_Enable( GLenum cap ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + _mesa_set_enable( ctx, cap, GL_TRUE ); +} + + +/** + * Disable GL capability. Called by glDisable() + * \param cap state to disable. + */ +void GLAPIENTRY +_mesa_Disable( GLenum cap ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + _mesa_set_enable( ctx, cap, GL_FALSE ); +} + + + +/** + * Enable/disable an indexed state var. + */ +void +_mesa_set_enablei(struct gl_context *ctx, GLenum cap, GLuint index, GLboolean state) +{ + ASSERT(state == 0 || state == 1); + switch (cap) { + case GL_BLEND: + if (!ctx->Extensions.EXT_draw_buffers2) { + goto invalid_enum_error; + } + if (index >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%u)", + state ? "glEnableIndexed" : "glDisableIndexed", index); + return; + } + if (((ctx->Color.BlendEnabled >> index) & 1) != state) { + FLUSH_VERTICES(ctx, _NEW_COLOR); + if (state) + ctx->Color.BlendEnabled |= (1 << index); + else + ctx->Color.BlendEnabled &= ~(1 << index); + } + break; + default: + goto invalid_enum_error; + } + return; + +invalid_enum_error: + _mesa_error(ctx, GL_INVALID_ENUM, "%s(cap=%s)", + state ? "glEnablei" : "glDisablei", + _mesa_lookup_enum_by_nr(cap)); +} + + +void GLAPIENTRY +_mesa_DisableIndexed( GLenum cap, GLuint index ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + _mesa_set_enablei(ctx, cap, index, GL_FALSE); +} + + +void GLAPIENTRY +_mesa_EnableIndexed( GLenum cap, GLuint index ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + _mesa_set_enablei(ctx, cap, index, GL_TRUE); +} + + +GLboolean GLAPIENTRY +_mesa_IsEnabledIndexed( GLenum cap, GLuint index ) +{ + GET_CURRENT_CONTEXT(ctx); + switch (cap) { + case GL_BLEND: + if (index >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, "glIsEnabledIndexed(index=%u)", + index); + return GL_FALSE; + } + return (ctx->Color.BlendEnabled >> index) & 1; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glIsEnabledIndexed(cap=%s)", + _mesa_lookup_enum_by_nr(cap)); + return GL_FALSE; + } +} + + + + +#undef CHECK_EXTENSION +#define CHECK_EXTENSION(EXTNAME) \ + if (!ctx->Extensions.EXTNAME) { \ + goto invalid_enum_error; \ + } + +#undef CHECK_EXTENSION2 +#define CHECK_EXTENSION2(EXT1, EXT2) \ + if (!ctx->Extensions.EXT1 && !ctx->Extensions.EXT2) { \ + goto invalid_enum_error; \ + } + + +/** + * Helper function to determine whether a texture target is enabled. + */ +static GLboolean +is_texture_enabled(struct gl_context *ctx, GLbitfield bit) +{ + const struct gl_texture_unit *const texUnit = + &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + return (texUnit->Enabled & bit) ? GL_TRUE : GL_FALSE; +} + + +/** + * Return simple enable/disable state. + * + * \param cap state variable to query. + * + * Returns the state of the specified capability from the current GL context. + * For the capabilities associated with extensions verifies that those + * extensions are effectively present before reporting. + */ +GLboolean GLAPIENTRY +_mesa_IsEnabled( GLenum cap ) +{ + GET_CURRENT_CONTEXT(ctx); + switch (cap) { + case GL_ALPHA_TEST: + return ctx->Color.AlphaEnabled; + case GL_AUTO_NORMAL: + return ctx->Eval.AutoNormal; + case GL_BLEND: + return ctx->Color.BlendEnabled & 1; /* return state for buffer[0] */ + case GL_CLIP_PLANE0: + case GL_CLIP_PLANE1: + case GL_CLIP_PLANE2: + case GL_CLIP_PLANE3: + case GL_CLIP_PLANE4: + case GL_CLIP_PLANE5: + return (ctx->Transform.ClipPlanesEnabled >> (cap - GL_CLIP_PLANE0)) & 1; + case GL_COLOR_MATERIAL: + return ctx->Light.ColorMaterialEnabled; + case GL_CULL_FACE: + return ctx->Polygon.CullFlag; + case GL_DEPTH_TEST: + return ctx->Depth.Test; + case GL_DITHER: + return ctx->Color.DitherFlag; + case GL_FOG: + return ctx->Fog.Enabled; + case GL_LIGHTING: + return ctx->Light.Enabled; + case GL_LIGHT0: + case GL_LIGHT1: + case GL_LIGHT2: + case GL_LIGHT3: + case GL_LIGHT4: + case GL_LIGHT5: + case GL_LIGHT6: + case GL_LIGHT7: + return ctx->Light.Light[cap-GL_LIGHT0].Enabled; + case GL_LINE_SMOOTH: + return ctx->Line.SmoothFlag; + case GL_LINE_STIPPLE: + return ctx->Line.StippleFlag; + case GL_INDEX_LOGIC_OP: + return ctx->Color.IndexLogicOpEnabled; + case GL_COLOR_LOGIC_OP: + return ctx->Color.ColorLogicOpEnabled; + case GL_MAP1_COLOR_4: + return ctx->Eval.Map1Color4; + case GL_MAP1_INDEX: + return ctx->Eval.Map1Index; + case GL_MAP1_NORMAL: + return ctx->Eval.Map1Normal; + case GL_MAP1_TEXTURE_COORD_1: + return ctx->Eval.Map1TextureCoord1; + case GL_MAP1_TEXTURE_COORD_2: + return ctx->Eval.Map1TextureCoord2; + case GL_MAP1_TEXTURE_COORD_3: + return ctx->Eval.Map1TextureCoord3; + case GL_MAP1_TEXTURE_COORD_4: + return ctx->Eval.Map1TextureCoord4; + case GL_MAP1_VERTEX_3: + return ctx->Eval.Map1Vertex3; + case GL_MAP1_VERTEX_4: + return ctx->Eval.Map1Vertex4; + case GL_MAP2_COLOR_4: + return ctx->Eval.Map2Color4; + case GL_MAP2_INDEX: + return ctx->Eval.Map2Index; + case GL_MAP2_NORMAL: + return ctx->Eval.Map2Normal; + case GL_MAP2_TEXTURE_COORD_1: + return ctx->Eval.Map2TextureCoord1; + case GL_MAP2_TEXTURE_COORD_2: + return ctx->Eval.Map2TextureCoord2; + case GL_MAP2_TEXTURE_COORD_3: + return ctx->Eval.Map2TextureCoord3; + case GL_MAP2_TEXTURE_COORD_4: + return ctx->Eval.Map2TextureCoord4; + case GL_MAP2_VERTEX_3: + return ctx->Eval.Map2Vertex3; + case GL_MAP2_VERTEX_4: + return ctx->Eval.Map2Vertex4; + case GL_NORMALIZE: + return ctx->Transform.Normalize; + case GL_POINT_SMOOTH: + return ctx->Point.SmoothFlag; + case GL_POLYGON_SMOOTH: + return ctx->Polygon.SmoothFlag; + case GL_POLYGON_STIPPLE: + return ctx->Polygon.StippleFlag; + case GL_POLYGON_OFFSET_POINT: + return ctx->Polygon.OffsetPoint; + case GL_POLYGON_OFFSET_LINE: + return ctx->Polygon.OffsetLine; + case GL_POLYGON_OFFSET_FILL: + /*case GL_POLYGON_OFFSET_EXT:*/ + return ctx->Polygon.OffsetFill; + case GL_RESCALE_NORMAL_EXT: + return ctx->Transform.RescaleNormals; + case GL_SCISSOR_TEST: + return ctx->Scissor.Enabled; + case GL_SHARED_TEXTURE_PALETTE_EXT: + return ctx->Texture.SharedPalette; + case GL_STENCIL_TEST: + return ctx->Stencil.Enabled; + case GL_TEXTURE_1D: + return is_texture_enabled(ctx, TEXTURE_1D_BIT); + case GL_TEXTURE_2D: + return is_texture_enabled(ctx, TEXTURE_2D_BIT); + case GL_TEXTURE_3D: + return is_texture_enabled(ctx, TEXTURE_3D_BIT); + case GL_TEXTURE_GEN_Q: + { + const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + return (texUnit->TexGenEnabled & Q_BIT) ? GL_TRUE : GL_FALSE; + } + } + return GL_FALSE; + case GL_TEXTURE_GEN_R: + { + const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + return (texUnit->TexGenEnabled & R_BIT) ? GL_TRUE : GL_FALSE; + } + } + return GL_FALSE; + case GL_TEXTURE_GEN_S: + { + const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + return (texUnit->TexGenEnabled & S_BIT) ? GL_TRUE : GL_FALSE; + } + } + return GL_FALSE; + case GL_TEXTURE_GEN_T: + { + const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + return (texUnit->TexGenEnabled & T_BIT) ? GL_TRUE : GL_FALSE; + } + } + return GL_FALSE; +#if FEATURE_ES1 + case GL_TEXTURE_GEN_STR_OES: + { + const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + return (texUnit->TexGenEnabled & STR_BITS) == STR_BITS ? GL_TRUE : GL_FALSE; + } + } +#endif + + /* + * CLIENT STATE!!! + */ + case GL_VERTEX_ARRAY: + return (ctx->Array.ArrayObj->Vertex.Enabled != 0); + case GL_NORMAL_ARRAY: + return (ctx->Array.ArrayObj->Normal.Enabled != 0); + case GL_COLOR_ARRAY: + return (ctx->Array.ArrayObj->Color.Enabled != 0); + case GL_INDEX_ARRAY: + return (ctx->Array.ArrayObj->Index.Enabled != 0); + case GL_TEXTURE_COORD_ARRAY: + return (ctx->Array.ArrayObj->TexCoord[ctx->Array.ActiveTexture].Enabled != 0); + case GL_EDGE_FLAG_ARRAY: + return (ctx->Array.ArrayObj->EdgeFlag.Enabled != 0); + case GL_FOG_COORDINATE_ARRAY_EXT: + CHECK_EXTENSION(EXT_fog_coord); + return (ctx->Array.ArrayObj->FogCoord.Enabled != 0); + case GL_SECONDARY_COLOR_ARRAY_EXT: + CHECK_EXTENSION(EXT_secondary_color); + return (ctx->Array.ArrayObj->SecondaryColor.Enabled != 0); +#if FEATURE_point_size_array + case GL_POINT_SIZE_ARRAY_OES: + return (ctx->Array.ArrayObj->PointSize.Enabled != 0); +#endif + + /* GL_ARB_texture_cube_map */ + case GL_TEXTURE_CUBE_MAP_ARB: + CHECK_EXTENSION(ARB_texture_cube_map); + return is_texture_enabled(ctx, TEXTURE_CUBE_BIT); + + /* GL_EXT_secondary_color */ + case GL_COLOR_SUM_EXT: + CHECK_EXTENSION2(EXT_secondary_color, ARB_vertex_program); + return ctx->Fog.ColorSumEnabled; + + /* GL_ARB_multisample */ + case GL_MULTISAMPLE_ARB: + return ctx->Multisample.Enabled; + case GL_SAMPLE_ALPHA_TO_COVERAGE_ARB: + return ctx->Multisample.SampleAlphaToCoverage; + case GL_SAMPLE_ALPHA_TO_ONE_ARB: + return ctx->Multisample.SampleAlphaToOne; + case GL_SAMPLE_COVERAGE_ARB: + return ctx->Multisample.SampleCoverage; + case GL_SAMPLE_COVERAGE_INVERT_ARB: + return ctx->Multisample.SampleCoverageInvert; + + /* GL_IBM_rasterpos_clip */ + case GL_RASTER_POSITION_UNCLIPPED_IBM: + CHECK_EXTENSION(IBM_rasterpos_clip); + return ctx->Transform.RasterPositionUnclipped; + + /* GL_NV_point_sprite */ + case GL_POINT_SPRITE_NV: + CHECK_EXTENSION2(NV_point_sprite, ARB_point_sprite) + return ctx->Point.PointSprite; + +#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program + case GL_VERTEX_PROGRAM_ARB: + CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program); + return ctx->VertexProgram.Enabled; + case GL_VERTEX_PROGRAM_POINT_SIZE_ARB: + CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program); + return ctx->VertexProgram.PointSizeEnabled; + case GL_VERTEX_PROGRAM_TWO_SIDE_ARB: + CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program); + return ctx->VertexProgram.TwoSideEnabled; +#endif +#if FEATURE_NV_vertex_program + case GL_VERTEX_ATTRIB_ARRAY0_NV: + case GL_VERTEX_ATTRIB_ARRAY1_NV: + case GL_VERTEX_ATTRIB_ARRAY2_NV: + case GL_VERTEX_ATTRIB_ARRAY3_NV: + case GL_VERTEX_ATTRIB_ARRAY4_NV: + case GL_VERTEX_ATTRIB_ARRAY5_NV: + case GL_VERTEX_ATTRIB_ARRAY6_NV: + case GL_VERTEX_ATTRIB_ARRAY7_NV: + case GL_VERTEX_ATTRIB_ARRAY8_NV: + case GL_VERTEX_ATTRIB_ARRAY9_NV: + case GL_VERTEX_ATTRIB_ARRAY10_NV: + case GL_VERTEX_ATTRIB_ARRAY11_NV: + case GL_VERTEX_ATTRIB_ARRAY12_NV: + case GL_VERTEX_ATTRIB_ARRAY13_NV: + case GL_VERTEX_ATTRIB_ARRAY14_NV: + case GL_VERTEX_ATTRIB_ARRAY15_NV: + CHECK_EXTENSION(NV_vertex_program); + { + GLint n = (GLint) cap - GL_VERTEX_ATTRIB_ARRAY0_NV; + ASSERT(n < Elements(ctx->Array.ArrayObj->VertexAttrib)); + return (ctx->Array.ArrayObj->VertexAttrib[n].Enabled != 0); + } + case GL_MAP1_VERTEX_ATTRIB0_4_NV: + case GL_MAP1_VERTEX_ATTRIB1_4_NV: + case GL_MAP1_VERTEX_ATTRIB2_4_NV: + case GL_MAP1_VERTEX_ATTRIB3_4_NV: + case GL_MAP1_VERTEX_ATTRIB4_4_NV: + case GL_MAP1_VERTEX_ATTRIB5_4_NV: + case GL_MAP1_VERTEX_ATTRIB6_4_NV: + case GL_MAP1_VERTEX_ATTRIB7_4_NV: + case GL_MAP1_VERTEX_ATTRIB8_4_NV: + case GL_MAP1_VERTEX_ATTRIB9_4_NV: + case GL_MAP1_VERTEX_ATTRIB10_4_NV: + case GL_MAP1_VERTEX_ATTRIB11_4_NV: + case GL_MAP1_VERTEX_ATTRIB12_4_NV: + case GL_MAP1_VERTEX_ATTRIB13_4_NV: + case GL_MAP1_VERTEX_ATTRIB14_4_NV: + case GL_MAP1_VERTEX_ATTRIB15_4_NV: + CHECK_EXTENSION(NV_vertex_program); + { + const GLuint map = (GLuint) (cap - GL_MAP1_VERTEX_ATTRIB0_4_NV); + return ctx->Eval.Map1Attrib[map]; + } + case GL_MAP2_VERTEX_ATTRIB0_4_NV: + case GL_MAP2_VERTEX_ATTRIB1_4_NV: + case GL_MAP2_VERTEX_ATTRIB2_4_NV: + case GL_MAP2_VERTEX_ATTRIB3_4_NV: + case GL_MAP2_VERTEX_ATTRIB4_4_NV: + case GL_MAP2_VERTEX_ATTRIB5_4_NV: + case GL_MAP2_VERTEX_ATTRIB6_4_NV: + case GL_MAP2_VERTEX_ATTRIB7_4_NV: + case GL_MAP2_VERTEX_ATTRIB8_4_NV: + case GL_MAP2_VERTEX_ATTRIB9_4_NV: + case GL_MAP2_VERTEX_ATTRIB10_4_NV: + case GL_MAP2_VERTEX_ATTRIB11_4_NV: + case GL_MAP2_VERTEX_ATTRIB12_4_NV: + case GL_MAP2_VERTEX_ATTRIB13_4_NV: + case GL_MAP2_VERTEX_ATTRIB14_4_NV: + case GL_MAP2_VERTEX_ATTRIB15_4_NV: + CHECK_EXTENSION(NV_vertex_program); + { + const GLuint map = (GLuint) (cap - GL_MAP2_VERTEX_ATTRIB0_4_NV); + return ctx->Eval.Map2Attrib[map]; + } +#endif /* FEATURE_NV_vertex_program */ + +#if FEATURE_NV_fragment_program + case GL_FRAGMENT_PROGRAM_NV: + CHECK_EXTENSION(NV_fragment_program); + return ctx->FragmentProgram.Enabled; +#endif /* FEATURE_NV_fragment_program */ + + /* GL_NV_texture_rectangle */ + case GL_TEXTURE_RECTANGLE_NV: + CHECK_EXTENSION(NV_texture_rectangle); + return is_texture_enabled(ctx, TEXTURE_RECT_BIT); + + /* GL_EXT_stencil_two_side */ + case GL_STENCIL_TEST_TWO_SIDE_EXT: + CHECK_EXTENSION(EXT_stencil_two_side); + return ctx->Stencil.TestTwoSide; + +#if FEATURE_ARB_fragment_program + case GL_FRAGMENT_PROGRAM_ARB: + return ctx->FragmentProgram.Enabled; +#endif /* FEATURE_ARB_fragment_program */ + + /* GL_EXT_depth_bounds_test */ + case GL_DEPTH_BOUNDS_TEST_EXT: + CHECK_EXTENSION(EXT_depth_bounds_test); + return ctx->Depth.BoundsTest; + + /* GL_ARB_depth_clamp */ + case GL_DEPTH_CLAMP: + CHECK_EXTENSION(ARB_depth_clamp); + return ctx->Transform.DepthClamp; + +#if FEATURE_ATI_fragment_shader + case GL_FRAGMENT_SHADER_ATI: + CHECK_EXTENSION(ATI_fragment_shader); + return ctx->ATIFragmentShader.Enabled; +#endif /* FEATURE_ATI_fragment_shader */ + + case GL_TEXTURE_CUBE_MAP_SEAMLESS: + CHECK_EXTENSION(ARB_seamless_cube_map); + return ctx->Texture.CubeMapSeamless; + +#if FEATURE_EXT_transform_feedback + case GL_RASTERIZER_DISCARD: + CHECK_EXTENSION(EXT_transform_feedback); + return ctx->TransformFeedback.RasterDiscard; +#endif + + /* GL_NV_primitive_restart */ + case GL_PRIMITIVE_RESTART_NV: + if (!ctx->Extensions.NV_primitive_restart) { + goto invalid_enum_error; + } + return ctx->Array.PrimitiveRestart; + + /* GL 3.1 primitive restart */ + case GL_PRIMITIVE_RESTART: + if (ctx->VersionMajor * 10 + ctx->VersionMinor < 31) { + goto invalid_enum_error; + } + return ctx->Array.PrimitiveRestart; + + /* GL3.0 - GL_framebuffer_sRGB */ + case GL_FRAMEBUFFER_SRGB_EXT: + CHECK_EXTENSION(EXT_framebuffer_sRGB); + return ctx->Color.sRGBEnabled; + + default: + goto invalid_enum_error; + } + + return GL_FALSE; + +invalid_enum_error: + _mesa_error(ctx, GL_INVALID_ENUM, "glIsEnabled(0x%x)", (int) cap); + return GL_FALSE; +} diff --git a/mesalib/src/mesa/main/extensions.c b/mesalib/src/mesa/main/extensions.c index 310740b0d..3840cdc5d 100644 --- a/mesalib/src/mesa/main/extensions.c +++ b/mesalib/src/mesa/main/extensions.c @@ -241,8 +241,7 @@ static const struct extension extension_table[] = { { "GL_OES_stencil4", o(dummy_false), DISABLE }, { "GL_OES_stencil8", o(EXT_framebuffer_object), ES1 | ES2 }, { "GL_OES_stencil_wrap", o(EXT_stencil_wrap), ES1 }, - /* GL_OES_texture_3D is disabled due to missing GLSL support. */ - { "GL_OES_texture_3D", o(EXT_texture3D), DISABLE }, + { "GL_OES_texture_3D", o(EXT_texture3D), ES2 }, { "GL_OES_texture_cube_map", o(ARB_texture_cube_map), ES1 }, { "GL_OES_texture_env_crossbar", o(ARB_texture_env_crossbar), ES1 }, { "GL_OES_texture_mirrored_repeat", o(ARB_texture_mirrored_repeat), ES1 }, @@ -291,7 +290,6 @@ static const struct extension extension_table[] = { { "GL_SGIS_texture_border_clamp", o(ARB_texture_border_clamp), GL }, { "GL_SGIS_texture_edge_clamp", o(SGIS_texture_edge_clamp), GL }, { "GL_SGIS_texture_lod", o(SGIS_texture_lod), GL }, - { "GL_SGI_texture_color_table", o(SGI_texture_color_table), GL }, { "GL_SUN_multi_draw_arrays", o(EXT_multi_draw_arrays), GL }, { 0, 0, 0 }, @@ -521,7 +519,6 @@ _mesa_enable_sw_extensions(struct gl_context *ctx) #if FEATURE_NV_fragment_program && FEATURE_ARB_fragment_program ctx->Extensions.NV_fragment_program_option = GL_TRUE; #endif - ctx->Extensions.SGI_texture_color_table = GL_TRUE; /*ctx->Extensions.SGIS_generate_mipmap = GL_TRUE;*/ ctx->Extensions.SGIS_texture_edge_clamp = GL_TRUE; #if FEATURE_ARB_vertex_program || FEATURE_ARB_fragment_program diff --git a/mesalib/src/mesa/main/fbobject.c b/mesalib/src/mesa/main/fbobject.c index b2ff4dc29..c242e568d 100644 --- a/mesalib/src/mesa/main/fbobject.c +++ b/mesalib/src/mesa/main/fbobject.c @@ -1,2494 +1,2438 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -/* - * GL_EXT/ARB_framebuffer_object extensions - * - * Authors: - * Brian Paul - */ - - -#include "buffers.h" -#include "context.h" -#include "enums.h" -#include "fbobject.h" -#include "formats.h" -#include "framebuffer.h" -#include "hash.h" -#include "macros.h" -#include "mfeatures.h" -#include "mtypes.h" -#include "renderbuffer.h" -#include "state.h" -#include "teximage.h" -#include "texobj.h" - - -/** Set this to 1 to help debug FBO incompleteness problems */ -#define DEBUG_FBO 0 - -/** Set this to 1 to debug/log glBlitFramebuffer() calls */ -#define DEBUG_BLIT 0 - - -/** - * Notes: - * - * None of the GL_EXT_framebuffer_object functions are compiled into - * display lists. - */ - - - -/* - * When glGenRender/FramebuffersEXT() is called we insert pointers to - * these placeholder objects into the hash table. - * Later, when the object ID is first bound, we replace the placeholder - * with the real frame/renderbuffer. - */ -static struct gl_framebuffer DummyFramebuffer; -static struct gl_renderbuffer DummyRenderbuffer; - -/* We bind this framebuffer when applications pass a NULL - * drawable/surface in make current. */ -static struct gl_framebuffer IncompleteFramebuffer; - - -#define IS_CUBE_FACE(TARGET) \ - ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \ - (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) - - -static void -delete_dummy_renderbuffer(struct gl_renderbuffer *rb) -{ - /* no op */ -} - -static void -delete_dummy_framebuffer(struct gl_framebuffer *fb) -{ - /* no op */ -} - - -void -_mesa_init_fbobjects(struct gl_context *ctx) -{ - _glthread_INIT_MUTEX(DummyFramebuffer.Mutex); - _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex); - _glthread_INIT_MUTEX(IncompleteFramebuffer.Mutex); - DummyFramebuffer.Delete = delete_dummy_framebuffer; - DummyRenderbuffer.Delete = delete_dummy_renderbuffer; - IncompleteFramebuffer.Delete = delete_dummy_framebuffer; -} - -struct gl_framebuffer * -_mesa_get_incomplete_framebuffer(void) -{ - return &IncompleteFramebuffer; -} - -/** - * Helper routine for getting a gl_renderbuffer. - */ -struct gl_renderbuffer * -_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id) -{ - struct gl_renderbuffer *rb; - - if (id == 0) - return NULL; - - rb = (struct gl_renderbuffer *) - _mesa_HashLookup(ctx->Shared->RenderBuffers, id); - return rb; -} - - -/** - * Helper routine for getting a gl_framebuffer. - */ -struct gl_framebuffer * -_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id) -{ - struct gl_framebuffer *fb; - - if (id == 0) - return NULL; - - fb = (struct gl_framebuffer *) - _mesa_HashLookup(ctx->Shared->FrameBuffers, id); - return fb; -} - - -/** - * Mark the given framebuffer as invalid. This will force the - * test for framebuffer completeness to be done before the framebuffer - * is used. - */ -static void -invalidate_framebuffer(struct gl_framebuffer *fb) -{ - fb->_Status = 0; /* "indeterminate" */ -} - - -/** - * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding - * gl_renderbuffer_attachment object. - * This function is only used for user-created FB objects, not the - * default / window-system FB object. - * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to - * the depth buffer attachment point. - */ -struct gl_renderbuffer_attachment * -_mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, - GLenum attachment) -{ - GLuint i; - - assert(fb->Name > 0); - - switch (attachment) { - case GL_COLOR_ATTACHMENT0_EXT: - case GL_COLOR_ATTACHMENT1_EXT: - case GL_COLOR_ATTACHMENT2_EXT: - case GL_COLOR_ATTACHMENT3_EXT: - case GL_COLOR_ATTACHMENT4_EXT: - case GL_COLOR_ATTACHMENT5_EXT: - case GL_COLOR_ATTACHMENT6_EXT: - case GL_COLOR_ATTACHMENT7_EXT: - case GL_COLOR_ATTACHMENT8_EXT: - case GL_COLOR_ATTACHMENT9_EXT: - case GL_COLOR_ATTACHMENT10_EXT: - case GL_COLOR_ATTACHMENT11_EXT: - case GL_COLOR_ATTACHMENT12_EXT: - case GL_COLOR_ATTACHMENT13_EXT: - case GL_COLOR_ATTACHMENT14_EXT: - case GL_COLOR_ATTACHMENT15_EXT: - i = attachment - GL_COLOR_ATTACHMENT0_EXT; - if (i >= ctx->Const.MaxColorAttachments) { - return NULL; - } - return &fb->Attachment[BUFFER_COLOR0 + i]; - case GL_DEPTH_STENCIL_ATTACHMENT: - /* fall-through */ - case GL_DEPTH_BUFFER: - /* fall-through / new in GL 3.0 */ - case GL_DEPTH_ATTACHMENT_EXT: - return &fb->Attachment[BUFFER_DEPTH]; - case GL_STENCIL_BUFFER: - /* fall-through / new in GL 3.0 */ - case GL_STENCIL_ATTACHMENT_EXT: - return &fb->Attachment[BUFFER_STENCIL]; - default: - return NULL; - } -} - - -/** - * As above, but only used for getting attachments of the default / - * window-system framebuffer (not user-created framebuffer objects). - */ -static struct gl_renderbuffer_attachment * -_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, - GLenum attachment) -{ - assert(fb->Name == 0); - - switch (attachment) { - case GL_FRONT_LEFT: - return &fb->Attachment[BUFFER_FRONT_LEFT]; - case GL_FRONT_RIGHT: - return &fb->Attachment[BUFFER_FRONT_RIGHT]; - case GL_BACK_LEFT: - return &fb->Attachment[BUFFER_BACK_LEFT]; - case GL_BACK_RIGHT: - return &fb->Attachment[BUFFER_BACK_RIGHT]; - case GL_AUX0: - if (fb->Visual.numAuxBuffers == 1) { - return &fb->Attachment[BUFFER_AUX0]; - } - return NULL; - case GL_DEPTH_BUFFER: - /* fall-through / new in GL 3.0 */ - case GL_DEPTH_ATTACHMENT_EXT: - return &fb->Attachment[BUFFER_DEPTH]; - case GL_STENCIL_BUFFER: - /* fall-through / new in GL 3.0 */ - case GL_STENCIL_ATTACHMENT_EXT: - return &fb->Attachment[BUFFER_STENCIL]; - default: - return NULL; - } -} - - - -/** - * Remove any texture or renderbuffer attached to the given attachment - * point. Update reference counts, etc. - */ -void -_mesa_remove_attachment(struct gl_context *ctx, - struct gl_renderbuffer_attachment *att) -{ - if (att->Type == GL_TEXTURE) { - ASSERT(att->Texture); - if (ctx->Driver.FinishRenderTexture) { - /* tell driver that we're done rendering to this texture. */ - ctx->Driver.FinishRenderTexture(ctx, att); - } - _mesa_reference_texobj(&att->Texture, NULL); /* unbind */ - ASSERT(!att->Texture); - } - if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) { - ASSERT(!att->Texture); - _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */ - ASSERT(!att->Renderbuffer); - } - att->Type = GL_NONE; - att->Complete = GL_TRUE; -} - - -/** - * Bind a texture object to an attachment point. - * The previous binding, if any, will be removed first. - */ -void -_mesa_set_texture_attachment(struct gl_context *ctx, - struct gl_framebuffer *fb, - struct gl_renderbuffer_attachment *att, - struct gl_texture_object *texObj, - GLenum texTarget, GLuint level, GLuint zoffset) -{ - if (att->Texture == texObj) { - /* re-attaching same texture */ - ASSERT(att->Type == GL_TEXTURE); - if (ctx->Driver.FinishRenderTexture) - ctx->Driver.FinishRenderTexture(ctx, att); - } - else { - /* new attachment */ - if (ctx->Driver.FinishRenderTexture && att->Texture) - ctx->Driver.FinishRenderTexture(ctx, att); - _mesa_remove_attachment(ctx, att); - att->Type = GL_TEXTURE; - assert(!att->Texture); - _mesa_reference_texobj(&att->Texture, texObj); - } - - /* always update these fields */ - att->TextureLevel = level; - att->CubeMapFace = _mesa_tex_target_to_face(texTarget); - att->Zoffset = zoffset; - att->Complete = GL_FALSE; - - if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { - ctx->Driver.RenderTexture(ctx, fb, att); - } - - invalidate_framebuffer(fb); -} - - -/** - * Bind a renderbuffer to an attachment point. - * The previous binding, if any, will be removed first. - */ -void -_mesa_set_renderbuffer_attachment(struct gl_context *ctx, - struct gl_renderbuffer_attachment *att, - struct gl_renderbuffer *rb) -{ - /* XXX check if re-doing same attachment, exit early */ - _mesa_remove_attachment(ctx, att); - att->Type = GL_RENDERBUFFER_EXT; - att->Texture = NULL; /* just to be safe */ - att->Complete = GL_FALSE; - _mesa_reference_renderbuffer(&att->Renderbuffer, rb); -} - - -/** - * Fallback for ctx->Driver.FramebufferRenderbuffer() - * Attach a renderbuffer object to a framebuffer object. - */ -void -_mesa_framebuffer_renderbuffer(struct gl_context *ctx, - struct gl_framebuffer *fb, - GLenum attachment, struct gl_renderbuffer *rb) -{ - struct gl_renderbuffer_attachment *att; - - _glthread_LOCK_MUTEX(fb->Mutex); - - att = _mesa_get_attachment(ctx, fb, attachment); - ASSERT(att); - if (rb) { - _mesa_set_renderbuffer_attachment(ctx, att, rb); - if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { - /* do stencil attachment here (depth already done above) */ - att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT); - assert(att); - _mesa_set_renderbuffer_attachment(ctx, att, rb); - } - } - else { - _mesa_remove_attachment(ctx, att); - } - - invalidate_framebuffer(fb); - - _glthread_UNLOCK_MUTEX(fb->Mutex); -} - - -/** - * Fallback for ctx->Driver.ValidateFramebuffer() - * Check if the renderbuffer's formats are supported by the software - * renderer. - * Drivers should probably override this. - */ -void -_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) -{ - gl_buffer_index buf; - for (buf = 0; buf < BUFFER_COUNT; buf++) { - const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer; - if (rb) { - switch (rb->_BaseFormat) { - case GL_ALPHA: - case GL_LUMINANCE_ALPHA: - case GL_LUMINANCE: - case GL_INTENSITY: - case GL_RED: - case GL_RG: - fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; - return; - default: - /* render buffer format is supported by software rendering */ - ; - } - } - } -} - - -/** - * For debug only. - */ -static void -att_incomplete(const char *msg) -{ -#if DEBUG_FBO - _mesa_debug(NULL, "attachment incomplete: %s\n", msg); -#else - (void) msg; -#endif -} - - -/** - * For debug only. - */ -static void -fbo_incomplete(const char *msg, int index) -{ -#if DEBUG_FBO - _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); -#else - (void) msg; - (void) index; -#endif -} - - -/** - * Is the given base format a legal format for a color renderbuffer? - */ -GLboolean -_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat) -{ - switch (baseFormat) { - case GL_RGB: - case GL_RGBA: - return GL_TRUE; - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - case GL_INTENSITY: - case GL_ALPHA: - return ctx->Extensions.ARB_framebuffer_object; - case GL_RED: - case GL_RG: - return ctx->Extensions.ARB_texture_rg; - default: - return GL_FALSE; - } -} - - -/** - * Is the given base format a legal format for a depth/stencil renderbuffer? - */ -static GLboolean -is_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat) -{ - switch (baseFormat) { - case GL_DEPTH_COMPONENT: - case GL_DEPTH_STENCIL_EXT: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Test if an attachment point is complete and update its Complete field. - * \param format if GL_COLOR, this is a color attachment point, - * if GL_DEPTH, this is a depth component attachment point, - * if GL_STENCIL, this is a stencil component attachment point. - */ -static void -test_attachment_completeness(const struct gl_context *ctx, GLenum format, - struct gl_renderbuffer_attachment *att) -{ - assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL); - - /* assume complete */ - att->Complete = GL_TRUE; - - /* Look for reasons why the attachment might be incomplete */ - if (att->Type == GL_TEXTURE) { - const struct gl_texture_object *texObj = att->Texture; - struct gl_texture_image *texImage; - GLenum baseFormat; - - if (!texObj) { - att_incomplete("no texobj"); - att->Complete = GL_FALSE; - return; - } - - texImage = texObj->Image[att->CubeMapFace][att->TextureLevel]; - if (!texImage) { - att_incomplete("no teximage"); - att->Complete = GL_FALSE; - return; - } - if (texImage->Width < 1 || texImage->Height < 1) { - att_incomplete("teximage width/height=0"); - printf("texobj = %u\n", texObj->Name); - printf("level = %d\n", att->TextureLevel); - att->Complete = GL_FALSE; - return; - } - if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) { - att_incomplete("bad z offset"); - att->Complete = GL_FALSE; - return; - } - - baseFormat = _mesa_get_format_base_format(texImage->TexFormat); - - if (format == GL_COLOR) { - if (!_mesa_is_legal_color_format(ctx, baseFormat)) { - att_incomplete("bad format"); - att->Complete = GL_FALSE; - return; - } - if (_mesa_is_format_compressed(texImage->TexFormat)) { - att_incomplete("compressed internalformat"); - att->Complete = GL_FALSE; - return; - } - } - else if (format == GL_DEPTH) { - if (baseFormat == GL_DEPTH_COMPONENT) { - /* OK */ - } - else if (ctx->Extensions.EXT_packed_depth_stencil && - ctx->Extensions.ARB_depth_texture && - baseFormat == GL_DEPTH_STENCIL_EXT) { - /* OK */ - } - else { - att->Complete = GL_FALSE; - att_incomplete("bad depth format"); - return; - } - } - else { - ASSERT(format == GL_STENCIL); - if (ctx->Extensions.EXT_packed_depth_stencil && - ctx->Extensions.ARB_depth_texture && - baseFormat == GL_DEPTH_STENCIL_EXT) { - /* OK */ - } - else { - /* no such thing as stencil-only textures */ - att_incomplete("illegal stencil texture"); - att->Complete = GL_FALSE; - return; - } - } - } - else if (att->Type == GL_RENDERBUFFER_EXT) { - const GLenum baseFormat = - _mesa_get_format_base_format(att->Renderbuffer->Format); - - ASSERT(att->Renderbuffer); - if (!att->Renderbuffer->InternalFormat || - att->Renderbuffer->Width < 1 || - att->Renderbuffer->Height < 1) { - att_incomplete("0x0 renderbuffer"); - att->Complete = GL_FALSE; - return; - } - if (format == GL_COLOR) { - if (!_mesa_is_legal_color_format(ctx, baseFormat)) { - att_incomplete("bad renderbuffer color format"); - att->Complete = GL_FALSE; - return; - } - } - else if (format == GL_DEPTH) { - if (baseFormat == GL_DEPTH_COMPONENT) { - /* OK */ - } - else if (ctx->Extensions.EXT_packed_depth_stencil && - baseFormat == GL_DEPTH_STENCIL_EXT) { - /* OK */ - } - else { - att_incomplete("bad renderbuffer depth format"); - att->Complete = GL_FALSE; - return; - } - } - else { - assert(format == GL_STENCIL); - if (baseFormat == GL_STENCIL_INDEX) { - /* OK */ - } - else if (ctx->Extensions.EXT_packed_depth_stencil && - baseFormat == GL_DEPTH_STENCIL_EXT) { - /* OK */ - } - else { - att->Complete = GL_FALSE; - att_incomplete("bad renderbuffer stencil format"); - return; - } - } - } - else { - ASSERT(att->Type == GL_NONE); - /* complete */ - return; - } -} - - -/** - * Test if the given framebuffer object is complete and update its - * Status field with the results. - * Calls the ctx->Driver.ValidateFramebuffer() function to allow the - * driver to make hardware-specific validation/completeness checks. - * Also update the framebuffer's Width and Height fields if the - * framebuffer is complete. - */ -void -_mesa_test_framebuffer_completeness(struct gl_context *ctx, - struct gl_framebuffer *fb) -{ - GLuint numImages; - GLenum intFormat = GL_NONE; /* color buffers' internal format */ - GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0; - GLint numSamples = -1; - GLint i; - GLuint j; - - assert(fb->Name != 0); - - numImages = 0; - fb->Width = 0; - fb->Height = 0; - - /* Start at -2 to more easily loop over all attachment points. - * -2: depth buffer - * -1: stencil buffer - * >=0: color buffer - */ - for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { - struct gl_renderbuffer_attachment *att; - GLenum f; - gl_format mesaFormat; - - /* - * XXX for ARB_fbo, only check color buffers that are named by - * GL_READ_BUFFER and GL_DRAW_BUFFERi. - */ - - /* check for attachment completeness - */ - if (i == -2) { - att = &fb->Attachment[BUFFER_DEPTH]; - test_attachment_completeness(ctx, GL_DEPTH, att); - if (!att->Complete) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; - fbo_incomplete("depth attachment incomplete", -1); - return; - } - } - else if (i == -1) { - att = &fb->Attachment[BUFFER_STENCIL]; - test_attachment_completeness(ctx, GL_STENCIL, att); - if (!att->Complete) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; - fbo_incomplete("stencil attachment incomplete", -1); - return; - } - } - else { - att = &fb->Attachment[BUFFER_COLOR0 + i]; - test_attachment_completeness(ctx, GL_COLOR, att); - if (!att->Complete) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; - fbo_incomplete("color attachment incomplete", i); - return; - } - } - - /* get width, height, format of the renderbuffer/texture - */ - if (att->Type == GL_TEXTURE) { - const struct gl_texture_image *texImg - = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; - minWidth = MIN2(minWidth, texImg->Width); - maxWidth = MAX2(maxWidth, texImg->Width); - minHeight = MIN2(minHeight, texImg->Height); - maxHeight = MAX2(maxHeight, texImg->Height); - f = texImg->_BaseFormat; - mesaFormat = texImg->TexFormat; - numImages++; - if (!_mesa_is_legal_color_format(ctx, f) && - !is_legal_depth_format(ctx, f)) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; - fbo_incomplete("texture attachment incomplete", -1); - return; - } - } - else if (att->Type == GL_RENDERBUFFER_EXT) { - minWidth = MIN2(minWidth, att->Renderbuffer->Width); - maxWidth = MAX2(minWidth, att->Renderbuffer->Width); - minHeight = MIN2(minHeight, att->Renderbuffer->Height); - maxHeight = MAX2(minHeight, att->Renderbuffer->Height); - f = att->Renderbuffer->InternalFormat; - mesaFormat = att->Renderbuffer->Format; - numImages++; - } - else { - assert(att->Type == GL_NONE); - continue; - } - - if (numSamples < 0) { - /* first buffer */ - numSamples = att->Renderbuffer->NumSamples; - } - - /* check if integer color */ - fb->_IntegerColor = _mesa_is_format_integer_color(mesaFormat); - - /* Error-check width, height, format, samples - */ - if (numImages == 1) { - /* save format, num samples */ - if (i >= 0) { - intFormat = f; - } - } - else { - if (!ctx->Extensions.ARB_framebuffer_object) { - /* check that width, height, format are same */ - if (minWidth != maxWidth || minHeight != maxHeight) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; - fbo_incomplete("width or height mismatch", -1); - return; - } - /* check that all color buffer have same format */ - if (intFormat != GL_NONE && f != intFormat) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; - fbo_incomplete("format mismatch", -1); - return; - } - } - if (att->Renderbuffer && - att->Renderbuffer->NumSamples != numSamples) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; - fbo_incomplete("inconsistant number of samples", i); - return; - } - - } - } - -#if FEATURE_GL - if (ctx->API == API_OPENGL) { - /* Check that all DrawBuffers are present */ - for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { - if (fb->ColorDrawBuffer[j] != GL_NONE) { - const struct gl_renderbuffer_attachment *att - = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]); - assert(att); - if (att->Type == GL_NONE) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; - fbo_incomplete("missing drawbuffer", j); - return; - } - } - } - - /* Check that the ReadBuffer is present */ - if (fb->ColorReadBuffer != GL_NONE) { - const struct gl_renderbuffer_attachment *att - = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer); - assert(att); - if (att->Type == GL_NONE) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; - fbo_incomplete("missing readbuffer", -1); - return; - } - } - } -#else - (void) j; -#endif - - if (numImages == 0) { - fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; - fbo_incomplete("no attachments", -1); - return; - } - - /* Provisionally set status = COMPLETE ... */ - fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; - - /* ... but the driver may say the FB is incomplete. - * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED - * if anything. - */ - if (ctx->Driver.ValidateFramebuffer) { - ctx->Driver.ValidateFramebuffer(ctx, fb); - if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { - fbo_incomplete("driver marked FBO as incomplete", -1); - } - } - - if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) { - /* - * Note that if ARB_framebuffer_object is supported and the attached - * renderbuffers/textures are different sizes, the framebuffer - * width/height will be set to the smallest width/height. - */ - fb->Width = minWidth; - fb->Height = minHeight; - - /* finally, update the visual info for the framebuffer */ - _mesa_update_framebuffer_visual(ctx, fb); - } -} - - -GLboolean GLAPIENTRY -_mesa_IsRenderbufferEXT(GLuint renderbuffer) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - if (renderbuffer) { - struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); - if (rb != NULL && rb != &DummyRenderbuffer) - return GL_TRUE; - } - return GL_FALSE; -} - - -void GLAPIENTRY -_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) -{ - struct gl_renderbuffer *newRb; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (target != GL_RENDERBUFFER_EXT) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)"); - return; - } - - /* No need to flush here since the render buffer binding has no - * effect on rendering state. - */ - - if (renderbuffer) { - newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer); - if (newRb == &DummyRenderbuffer) { - /* ID was reserved, but no real renderbuffer object made yet */ - newRb = NULL; - } - else if (!newRb && ctx->Extensions.ARB_framebuffer_object) { - /* All RB IDs must be Gen'd */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)"); - return; - } - - if (!newRb) { - /* create new renderbuffer object */ - newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); - if (!newRb) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); - return; - } - ASSERT(newRb->AllocStorage); - _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); - newRb->RefCount = 1; /* referenced by hash table */ - } - } - else { - newRb = NULL; - } - - ASSERT(newRb != &DummyRenderbuffer); - - _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); -} - - -/** - * If the given renderbuffer is anywhere attached to the framebuffer, detach - * the renderbuffer. - * This is used when a renderbuffer object is deleted. - * The spec calls for unbinding. - */ -static void -detach_renderbuffer(struct gl_context *ctx, - struct gl_framebuffer *fb, - struct gl_renderbuffer *rb) -{ - GLuint i; - for (i = 0; i < BUFFER_COUNT; i++) { - if (fb->Attachment[i].Renderbuffer == rb) { - _mesa_remove_attachment(ctx, &fb->Attachment[i]); - } - } - invalidate_framebuffer(fb); -} - - -void GLAPIENTRY -_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) -{ - GLint i; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - for (i = 0; i < n; i++) { - if (renderbuffers[i] > 0) { - struct gl_renderbuffer *rb; - rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]); - if (rb) { - /* check if deleting currently bound renderbuffer object */ - if (rb == ctx->CurrentRenderbuffer) { - /* bind default */ - ASSERT(rb->RefCount >= 2); - _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); - } - - if (ctx->DrawBuffer->Name) { - detach_renderbuffer(ctx, ctx->DrawBuffer, rb); - } - if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) { - detach_renderbuffer(ctx, ctx->ReadBuffer, rb); - } - - /* Remove from hash table immediately, to free the ID. - * But the object will not be freed until it's no longer - * referenced anywhere else. - */ - _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); - - if (rb != &DummyRenderbuffer) { - /* no longer referenced by hash table */ - _mesa_reference_renderbuffer(&rb, NULL); - } - } - } - } -} - - -void GLAPIENTRY -_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) -{ - GET_CURRENT_CONTEXT(ctx); - GLuint first; - GLint i; - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)"); - return; - } - - if (!renderbuffers) - return; - - first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); - - for (i = 0; i < n; i++) { - GLuint name = first + i; - renderbuffers[i] = name; - /* insert dummy placeholder into hash table */ - _glthread_LOCK_MUTEX(ctx->Shared->Mutex); - _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer); - _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); - } -} - - -/** - * Given an internal format token for a render buffer, return the - * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, - * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE, - * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc). - * - * This is similar to _mesa_base_tex_format() but the set of valid - * internal formats is different. - * - * Note that even if a format is determined to be legal here, validation - * of the FBO may fail if the format is not supported by the driver/GPU. - * - * \param internalFormat as passed to glRenderbufferStorage() - * \return the base internal format, or 0 if internalFormat is illegal - */ -GLenum -_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) -{ - /* - * Notes: some formats such as alpha, luminance, etc. were added - * with GL_ARB_framebuffer_object. - */ - switch (internalFormat) { - case GL_ALPHA: - case GL_ALPHA4: - case GL_ALPHA8: - case GL_ALPHA12: - case GL_ALPHA16: - return ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; - case GL_LUMINANCE: - case GL_LUMINANCE4: - case GL_LUMINANCE8: - case GL_LUMINANCE12: - case GL_LUMINANCE16: - return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; - case GL_LUMINANCE_ALPHA: - case GL_LUMINANCE4_ALPHA4: - case GL_LUMINANCE6_ALPHA2: - case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE12_ALPHA4: - case GL_LUMINANCE12_ALPHA12: - case GL_LUMINANCE16_ALPHA16: - return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; - case GL_INTENSITY: - case GL_INTENSITY4: - case GL_INTENSITY8: - case GL_INTENSITY12: - case GL_INTENSITY16: - return ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; - case GL_RGB: - case GL_R3_G3_B2: - case GL_RGB4: - case GL_RGB5: - case GL_RGB8: - case GL_RGB10: - case GL_RGB12: - case GL_RGB16: - case GL_SRGB8_EXT: - return GL_RGB; - case GL_RGBA: - case GL_RGBA2: - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGBA8: - case GL_RGB10_A2: - case GL_RGBA12: - case GL_RGBA16: - case GL_RGBA16_SNORM: - case GL_SRGB8_ALPHA8_EXT: - return GL_RGBA; - case GL_STENCIL_INDEX: - case GL_STENCIL_INDEX1_EXT: - case GL_STENCIL_INDEX4_EXT: - case GL_STENCIL_INDEX8_EXT: - case GL_STENCIL_INDEX16_EXT: - return GL_STENCIL_INDEX; - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT24: - case GL_DEPTH_COMPONENT32: - return GL_DEPTH_COMPONENT; - case GL_DEPTH_STENCIL_EXT: - case GL_DEPTH24_STENCIL8_EXT: - if (ctx->Extensions.EXT_packed_depth_stencil) - return GL_DEPTH_STENCIL_EXT; - else - return 0; - case GL_RED: - case GL_R8: - case GL_R16: - return ctx->Extensions.ARB_texture_rg ? GL_RED : 0; - case GL_RG: - case GL_RG8: - case GL_RG16: - return ctx->Extensions.ARB_texture_rg ? GL_RG : 0; - /* XXX add floating point and integer formats eventually */ - default: - return 0; - } -} - - -/** sentinal value, see below */ -#define NO_SAMPLES 1000 - - -/** - * Helper function used by _mesa_RenderbufferStorageEXT() and - * _mesa_RenderbufferStorageMultisample(). - * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT(). - */ -static void -renderbuffer_storage(GLenum target, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei samples) -{ - const char *func = samples == NO_SAMPLES ? - "glRenderbufferStorage" : "RenderbufferStorageMultisample"; - struct gl_renderbuffer *rb; - GLenum baseFormat; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (target != GL_RENDERBUFFER_EXT) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); - return; - } - - baseFormat = _mesa_base_fbo_format(ctx, internalFormat); - if (baseFormat == 0) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func); - return; - } - - if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func); - return; - } - - if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func); - return; - } - - if (samples == NO_SAMPLES) { - /* NumSamples == 0 indicates non-multisampling */ - samples = 0; - } - else if (samples > (GLsizei) ctx->Const.MaxSamples) { - /* note: driver may choose to use more samples than what's requested */ - _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func); - return; - } - - rb = ctx->CurrentRenderbuffer; - if (!rb) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); - return; - } - - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - if (rb->InternalFormat == internalFormat && - rb->Width == (GLuint) width && - rb->Height == (GLuint) height) { - /* no change in allocation needed */ - return; - } - - /* These MUST get set by the AllocStorage func */ - rb->Format = MESA_FORMAT_NONE; - rb->NumSamples = samples; - - /* Now allocate the storage */ - ASSERT(rb->AllocStorage); - if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { - /* No error - check/set fields now */ - assert(rb->Format != MESA_FORMAT_NONE); - assert(rb->Width == (GLuint) width); - assert(rb->Height == (GLuint) height); - rb->InternalFormat = internalFormat; - rb->_BaseFormat = baseFormat; - assert(rb->_BaseFormat != 0); - } - else { - /* Probably ran out of memory - clear the fields */ - rb->Width = 0; - rb->Height = 0; - rb->Format = MESA_FORMAT_NONE; - rb->InternalFormat = GL_NONE; - rb->_BaseFormat = GL_NONE; - rb->NumSamples = 0; - } - - /* - test_framebuffer_completeness(ctx, fb); - */ - /* XXX if this renderbuffer is attached anywhere, invalidate attachment - * points??? - */ -} - - -#if FEATURE_OES_EGL_image -void GLAPIENTRY -_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) -{ - struct gl_renderbuffer *rb; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!ctx->Extensions.OES_EGL_image) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glEGLImageTargetRenderbufferStorageOES(unsupported)"); - return; - } - - if (target != GL_RENDERBUFFER) { - _mesa_error(ctx, GL_INVALID_ENUM, - "EGLImageTargetRenderbufferStorageOES"); - return; - } - - rb = ctx->CurrentRenderbuffer; - if (!rb) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "EGLImageTargetRenderbufferStorageOES"); - return; - } - - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image); -} -#endif - - -/** - * Helper function for _mesa_GetRenderbufferParameterivEXT() and - * _mesa_GetFramebufferAttachmentParameterivEXT() - * We have to be careful to respect the base format. For example, if a - * renderbuffer/texture was created with internalFormat=GL_RGB but the - * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE - * we need to return zero. - */ -static GLint -get_component_bits(GLenum pname, GLenum baseFormat, gl_format format) -{ - switch (pname) { - case GL_RENDERBUFFER_RED_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: - if (baseFormat == GL_RGB || baseFormat == GL_RGBA || - baseFormat == GL_RG || baseFormat == GL_RED) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_GREEN_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: - if (baseFormat == GL_RGB || baseFormat == GL_RGBA || baseFormat == GL_RG) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_BLUE_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: - if (baseFormat == GL_RGB || baseFormat == GL_RGBA) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_ALPHA_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: - if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA || - baseFormat == GL_LUMINANCE_ALPHA) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_DEPTH_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: - if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL) - return _mesa_get_format_bits(format, pname); - else - return 0; - case GL_RENDERBUFFER_STENCIL_SIZE_EXT: - case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: - if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL) - return _mesa_get_format_bits(format, pname); - else - return 0; - default: - return 0; - } -} - - - -void GLAPIENTRY -_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, - GLsizei width, GLsizei height) -{ - /* GL_ARB_fbo says calling this function is equivalent to calling - * glRenderbufferStorageMultisample() with samples=0. We pass in - * a token value here just for error reporting purposes. - */ - renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES); -} - - -void GLAPIENTRY -_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples, - GLenum internalFormat, - GLsizei width, GLsizei height) -{ - renderbuffer_storage(target, internalFormat, width, height, samples); -} - - -/** - * OpenGL ES version of glRenderBufferStorage. - */ -void GLAPIENTRY -_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, - GLsizei width, GLsizei height) -{ - switch (internalFormat) { - case GL_RGB565: - /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */ - /* choose a closest format */ - internalFormat = GL_RGB5; - break; - default: - break; - } - - renderbuffer_storage(target, internalFormat, width, height, 0); -} - - -void GLAPIENTRY -_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) -{ - struct gl_renderbuffer *rb; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (target != GL_RENDERBUFFER_EXT) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetRenderbufferParameterivEXT(target)"); - return; - } - - rb = ctx->CurrentRenderbuffer; - if (!rb) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetRenderbufferParameterivEXT"); - return; - } - - /* No need to flush here since we're just quering state which is - * not effected by rendering. - */ - - switch (pname) { - case GL_RENDERBUFFER_WIDTH_EXT: - *params = rb->Width; - return; - case GL_RENDERBUFFER_HEIGHT_EXT: - *params = rb->Height; - return; - case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: - *params = rb->InternalFormat; - return; - case GL_RENDERBUFFER_RED_SIZE_EXT: - case GL_RENDERBUFFER_GREEN_SIZE_EXT: - case GL_RENDERBUFFER_BLUE_SIZE_EXT: - case GL_RENDERBUFFER_ALPHA_SIZE_EXT: - case GL_RENDERBUFFER_DEPTH_SIZE_EXT: - case GL_RENDERBUFFER_STENCIL_SIZE_EXT: - *params = get_component_bits(pname, rb->_BaseFormat, rb->Format); - break; - case GL_RENDERBUFFER_SAMPLES: - if (ctx->Extensions.ARB_framebuffer_object) { - *params = rb->NumSamples; - break; - } - /* fallthrough */ - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetRenderbufferParameterivEXT(target)"); - return; - } -} - - -GLboolean GLAPIENTRY -_mesa_IsFramebufferEXT(GLuint framebuffer) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - if (framebuffer) { - struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer); - if (rb != NULL && rb != &DummyFramebuffer) - return GL_TRUE; - } - return GL_FALSE; -} - - -/** - * Check if any of the attachments of the given framebuffer are textures - * (render to texture). Call ctx->Driver.RenderTexture() for such - * attachments. - */ -static void -check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) -{ - GLuint i; - ASSERT(ctx->Driver.RenderTexture); - - if (fb->Name == 0) - return; /* can't render to texture with winsys framebuffers */ - - for (i = 0; i < BUFFER_COUNT; i++) { - struct gl_renderbuffer_attachment *att = fb->Attachment + i; - struct gl_texture_object *texObj = att->Texture; - if (texObj - && texObj->Image[att->CubeMapFace][att->TextureLevel]) { - ctx->Driver.RenderTexture(ctx, fb, att); - } - } -} - - -/** - * Examine all the framebuffer's attachments to see if any are textures. - * If so, call ctx->Driver.FinishRenderTexture() for each texture to - * notify the device driver that the texture image may have changed. - */ -static void -check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) -{ - if (fb->Name == 0) - return; /* can't render to texture with winsys framebuffers */ - - if (ctx->Driver.FinishRenderTexture) { - GLuint i; - for (i = 0; i < BUFFER_COUNT; i++) { - struct gl_renderbuffer_attachment *att = fb->Attachment + i; - if (att->Texture && att->Renderbuffer) { - ctx->Driver.FinishRenderTexture(ctx, att); - } - } - } -} - - -void GLAPIENTRY -_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) -{ - struct gl_framebuffer *newDrawFb, *newReadFb; - struct gl_framebuffer *oldDrawFb, *oldReadFb; - GLboolean bindReadBuf, bindDrawBuf; - GET_CURRENT_CONTEXT(ctx); - -#ifdef DEBUG - if (ctx->Extensions.ARB_framebuffer_object) { - ASSERT(ctx->Extensions.EXT_framebuffer_object); - ASSERT(ctx->Extensions.EXT_framebuffer_blit); - } -#endif - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!ctx->Extensions.EXT_framebuffer_object) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBindFramebufferEXT(unsupported)"); - return; - } - - switch (target) { -#if FEATURE_EXT_framebuffer_blit - case GL_DRAW_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); - return; - } - bindDrawBuf = GL_TRUE; - bindReadBuf = GL_FALSE; - break; - case GL_READ_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); - return; - } - bindDrawBuf = GL_FALSE; - bindReadBuf = GL_TRUE; - break; -#endif - case GL_FRAMEBUFFER_EXT: - bindDrawBuf = GL_TRUE; - bindReadBuf = GL_TRUE; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); - return; - } - - if (framebuffer) { - /* Binding a user-created framebuffer object */ - newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer); - if (newDrawFb == &DummyFramebuffer) { - /* ID was reserved, but no real framebuffer object made yet */ - newDrawFb = NULL; - } - else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) { - /* All FBO IDs must be Gen'd */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)"); - return; - } - - if (!newDrawFb) { - /* create new framebuffer object */ - newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); - if (!newDrawFb) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); - return; - } - _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb); - } - newReadFb = newDrawFb; - } - else { - /* Binding the window system framebuffer (which was originally set - * with MakeCurrent). - */ - newDrawFb = ctx->WinSysDrawBuffer; - newReadFb = ctx->WinSysReadBuffer; - } - - ASSERT(newDrawFb); - ASSERT(newDrawFb != &DummyFramebuffer); - - /* save pointers to current/old framebuffers */ - oldDrawFb = ctx->DrawBuffer; - oldReadFb = ctx->ReadBuffer; - - /* check if really changing bindings */ - if (oldDrawFb == newDrawFb) - bindDrawBuf = GL_FALSE; - if (oldReadFb == newReadFb) - bindReadBuf = GL_FALSE; - - /* - * OK, now bind the new Draw/Read framebuffers, if they're changing. - * - * We also check if we're beginning and/or ending render-to-texture. - * When a framebuffer with texture attachments is unbound, call - * ctx->Driver.FinishRenderTexture(). - * When a framebuffer with texture attachments is bound, call - * ctx->Driver.RenderTexture(). - * - * Note that if the ReadBuffer has texture attachments we don't consider - * that a render-to-texture case. - */ - if (bindReadBuf) { - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - /* check if old readbuffer was render-to-texture */ - check_end_texture_render(ctx, oldReadFb); - - _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb); - } - - if (bindDrawBuf) { - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - /* check if old read/draw buffers were render-to-texture */ - if (!bindReadBuf) - check_end_texture_render(ctx, oldReadFb); - - if (oldDrawFb != oldReadFb) - check_end_texture_render(ctx, oldDrawFb); - - /* check if newly bound framebuffer has any texture attachments */ - check_begin_texture_render(ctx, newDrawFb); - - _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb); - } - - if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) { - ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb); - } -} - - -void GLAPIENTRY -_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) -{ - GLint i; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - for (i = 0; i < n; i++) { - if (framebuffers[i] > 0) { - struct gl_framebuffer *fb; - fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]); - if (fb) { - ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); - - /* check if deleting currently bound framebuffer object */ - if (ctx->Extensions.EXT_framebuffer_blit) { - /* separate draw/read binding points */ - if (fb == ctx->DrawBuffer) { - /* bind default */ - ASSERT(fb->RefCount >= 2); - _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); - } - if (fb == ctx->ReadBuffer) { - /* bind default */ - ASSERT(fb->RefCount >= 2); - _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); - } - } - else { - /* only one binding point for read/draw buffers */ - if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) { - /* bind default */ - ASSERT(fb->RefCount >= 2); - _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - } - } - - /* remove from hash table immediately, to free the ID */ - _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); - - if (fb != &DummyFramebuffer) { - /* But the object will not be freed until it's no longer - * bound in any context. - */ - _mesa_reference_framebuffer(&fb, NULL); - } - } - } - } -} - - -void GLAPIENTRY -_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers) -{ - GET_CURRENT_CONTEXT(ctx); - GLuint first; - GLint i; - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); - return; - } - - if (!framebuffers) - return; - - first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); - - for (i = 0; i < n; i++) { - GLuint name = first + i; - framebuffers[i] = name; - /* insert dummy placeholder into hash table */ - _glthread_LOCK_MUTEX(ctx->Shared->Mutex); - _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); - _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); - } -} - - - -GLenum GLAPIENTRY -_mesa_CheckFramebufferStatusEXT(GLenum target) -{ - struct gl_framebuffer *buffer; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); - - switch (target) { -#if FEATURE_EXT_framebuffer_blit - case GL_DRAW_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); - return 0; - } - buffer = ctx->DrawBuffer; - break; - case GL_READ_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); - return 0; - } - buffer = ctx->ReadBuffer; - break; -#endif - case GL_FRAMEBUFFER_EXT: - buffer = ctx->DrawBuffer; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); - return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */ - } - - if (buffer->Name == 0) { - /* The window system / default framebuffer is always complete */ - return GL_FRAMEBUFFER_COMPLETE_EXT; - } - - /* No need to flush here */ - - if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) { - _mesa_test_framebuffer_completeness(ctx, buffer); - } - - return buffer->_Status; -} - - - -/** - * Common code called by glFramebufferTexture1D/2D/3DEXT(). - */ -static void -framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, - GLenum attachment, GLenum textarget, GLuint texture, - GLint level, GLint zoffset) -{ - struct gl_renderbuffer_attachment *att; - struct gl_texture_object *texObj = NULL; - struct gl_framebuffer *fb; - GLboolean error = GL_FALSE; - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - switch (target) { - case GL_READ_FRAMEBUFFER_EXT: - error = !ctx->Extensions.EXT_framebuffer_blit; - fb = ctx->ReadBuffer; - break; - case GL_DRAW_FRAMEBUFFER_EXT: - error = !ctx->Extensions.EXT_framebuffer_blit; - /* fall-through */ - case GL_FRAMEBUFFER_EXT: - fb = ctx->DrawBuffer; - break; - default: - error = GL_TRUE; - } - - if (error) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture%sEXT(target=0x%x)", caller, target); - return; - } - - ASSERT(fb); - - /* check framebuffer binding */ - if (fb->Name == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture%sEXT", caller); - return; - } - - - /* The textarget, level, and zoffset parameters are only validated if - * texture is non-zero. - */ - if (texture) { - GLboolean err = GL_TRUE; - - texObj = _mesa_lookup_texture(ctx, texture); - if (texObj != NULL) { - if (textarget == 0) { - /* XXX what's the purpose of this? */ - err = (texObj->Target != GL_TEXTURE_3D) && - (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && - (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT); - } - else { - err = (texObj->Target == GL_TEXTURE_CUBE_MAP) - ? !IS_CUBE_FACE(textarget) - : (texObj->Target != textarget); - } - } - else { - /* can't render to a non-existant texture */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture%sEXT(non existant texture)", - caller); - return; - } - - if (err) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture%sEXT(texture target mismatch)", - caller); - return; - } - - if (texObj->Target == GL_TEXTURE_3D) { - const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); - if (zoffset < 0 || zoffset >= maxSize) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture%sEXT(zoffset)", caller); - return; - } - } - else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || - (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) { - if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture%sEXT(layer)", caller); - return; - } - } - - if ((level < 0) || - (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture%sEXT(level)", caller); - return; - } - } - - att = _mesa_get_attachment(ctx, fb, attachment); - if (att == NULL) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture%sEXT(attachment)", caller); - return; - } - - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - _glthread_LOCK_MUTEX(fb->Mutex); - if (texObj) { - _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, - level, zoffset); - /* Set the render-to-texture flag. We'll check this flag in - * glTexImage() and friends to determine if we need to revalidate - * any FBOs that might be rendering into this texture. - * This flag never gets cleared since it's non-trivial to determine - * when all FBOs might be done rendering to this texture. That's OK - * though since it's uncommon to render to a texture then repeatedly - * call glTexImage() to change images in the texture. - */ - texObj->_RenderToTexture = GL_TRUE; - } - else { - _mesa_remove_attachment(ctx, att); - } - - invalidate_framebuffer(fb); - - _glthread_UNLOCK_MUTEX(fb->Mutex); -} - - - -void GLAPIENTRY -_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, GLint level) -{ - GET_CURRENT_CONTEXT(ctx); - - if ((texture != 0) && (textarget != GL_TEXTURE_1D)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture1DEXT(textarget)"); - return; - } - - framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, - level, 0); -} - - -void GLAPIENTRY -_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, GLint level) -{ - GET_CURRENT_CONTEXT(ctx); - - if ((texture != 0) && - (textarget != GL_TEXTURE_2D) && - (textarget != GL_TEXTURE_RECTANGLE_ARB) && - (!IS_CUBE_FACE(textarget))) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture2DEXT(textarget=0x%x)", textarget); - return; - } - - framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, - level, 0); -} - - -void GLAPIENTRY -_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, - GLint level, GLint zoffset) -{ - GET_CURRENT_CONTEXT(ctx); - - if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture3DEXT(textarget)"); - return; - } - - framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, - level, zoffset); -} - - -void GLAPIENTRY -_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment, - GLuint texture, GLint level, GLint layer) -{ - GET_CURRENT_CONTEXT(ctx); - - framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, - level, layer); -} - - -void GLAPIENTRY -_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, - GLenum renderbufferTarget, - GLuint renderbuffer) -{ - struct gl_renderbuffer_attachment *att; - struct gl_framebuffer *fb; - struct gl_renderbuffer *rb; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - switch (target) { -#if FEATURE_EXT_framebuffer_blit - case GL_DRAW_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbufferEXT(target)"); - return; - } - fb = ctx->DrawBuffer; - break; - case GL_READ_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbufferEXT(target)"); - return; - } - fb = ctx->ReadBuffer; - break; -#endif - case GL_FRAMEBUFFER_EXT: - fb = ctx->DrawBuffer; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbufferEXT(target)"); - return; - } - - if (renderbufferTarget != GL_RENDERBUFFER_EXT) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbufferEXT(renderbufferTarget)"); - return; - } - - if (fb->Name == 0) { - /* Can't attach new renderbuffers to a window system framebuffer */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); - return; - } - - att = _mesa_get_attachment(ctx, fb, attachment); - if (att == NULL) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbufferEXT(invalid attachment %s)", - _mesa_lookup_enum_by_nr(attachment)); - return; - } - - if (renderbuffer) { - rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); - if (!rb) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferRenderbufferEXT(non-existant" - " renderbuffer %u)", renderbuffer); - return; - } - else if (rb == &DummyRenderbuffer) { - /* This is what NVIDIA does */ - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferRenderbufferEXT(renderbuffer %u)", - renderbuffer); - return; - } - } - else { - /* remove renderbuffer attachment */ - rb = NULL; - } - - if (attachment == GL_DEPTH_STENCIL_ATTACHMENT && - rb && rb->Format != MESA_FORMAT_NONE) { - /* make sure the renderbuffer is a depth/stencil format */ - const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); - if (baseFormat != GL_DEPTH_STENCIL) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferRenderbufferEXT(renderbuffer" - " is not DEPTH_STENCIL format)"); - return; - } - } - - - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - assert(ctx->Driver.FramebufferRenderbuffer); - ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); - - /* Some subsequent GL commands may depend on the framebuffer's visual - * after the binding is updated. Update visual info now. - */ - _mesa_update_framebuffer_visual(ctx, fb); -} - - -void GLAPIENTRY -_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, - GLenum pname, GLint *params) -{ - const struct gl_renderbuffer_attachment *att; - struct gl_framebuffer *buffer; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - switch (target) { -#if FEATURE_EXT_framebuffer_blit - case GL_DRAW_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(target)"); - return; - } - buffer = ctx->DrawBuffer; - break; - case GL_READ_FRAMEBUFFER_EXT: - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(target)"); - return; - } - buffer = ctx->ReadBuffer; - break; -#endif - case GL_FRAMEBUFFER_EXT: - buffer = ctx->DrawBuffer; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(target)"); - return; - } - - if (buffer->Name == 0) { - /* the default / window-system FBO */ - att = _mesa_get_fb0_attachment(ctx, buffer, attachment); - } - else { - /* user-created framebuffer FBO */ - att = _mesa_get_attachment(ctx, buffer, attachment); - } - - if (att == NULL) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(attachment)"); - return; - } - - if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { - /* the depth and stencil attachments must point to the same buffer */ - const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt; - depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT); - stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT); - if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL" - " attachments differ)"); - return; - } - } - - /* No need to flush here */ - - switch (pname) { - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: - *params = buffer->Name == 0 ? GL_FRAMEBUFFER_DEFAULT : att->Type; - return; - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: - if (att->Type == GL_RENDERBUFFER_EXT) { - *params = att->Renderbuffer->Name; - } - else if (att->Type == GL_TEXTURE) { - *params = att->Texture->Name; - } - else { - assert(att->Type == GL_NONE); - *params = 0; - } - return; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: - if (att->Type == GL_TEXTURE) { - *params = att->TextureLevel; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - } - return; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: - if (att->Type == GL_TEXTURE) { - if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) { - *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; - } - else { - *params = 0; - } - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - } - return; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: - if (att->Type == GL_TEXTURE) { - if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) { - *params = att->Zoffset; - } - else { - *params = 0; - } - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - } - return; - case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: - if (!ctx->Extensions.ARB_framebuffer_object) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - } - else { - if (ctx->Extensions.EXT_framebuffer_sRGB && ctx->Const.sRGBCapable) { - *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format); - } - else { - /* According to ARB_framebuffer_sRGB, we should return LINEAR - * if the sRGB conversion is unsupported. */ - *params = GL_LINEAR; - } - } - return; - case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: - if (!ctx->Extensions.ARB_framebuffer_object) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - return; - } - else { - gl_format format = att->Renderbuffer->Format; - if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) { - /* special cases */ - *params = GL_INDEX; - } - else { - *params = _mesa_get_format_datatype(format); - } - } - return; - case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: - if (!ctx->Extensions.ARB_framebuffer_object) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - } - else if (att->Texture) { - const struct gl_texture_image *texImage = - _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target, - att->TextureLevel); - if (texImage) { - *params = get_component_bits(pname, texImage->_BaseFormat, - texImage->TexFormat); - } - else { - *params = 0; - } - } - else if (att->Renderbuffer) { - *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat, - att->Renderbuffer->Format); - } - else { - *params = 0; - } - return; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameterivEXT(pname)"); - return; - } -} - - -void GLAPIENTRY -_mesa_GenerateMipmapEXT(GLenum target) -{ - struct gl_texture_object *texObj; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - switch (target) { - case GL_TEXTURE_1D: - case GL_TEXTURE_2D: - case GL_TEXTURE_3D: - case GL_TEXTURE_CUBE_MAP: - /* OK, legal value */ - break; - default: - /* XXX need to implement GL_TEXTURE_1D_ARRAY and GL_TEXTURE_2D_ARRAY */ - _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)"); - return; - } - - texObj = _mesa_get_current_tex_object(ctx, target); - - if (texObj->BaseLevel >= texObj->MaxLevel) { - /* nothing to do */ - return; - } - - if (texObj->Target == GL_TEXTURE_CUBE_MAP && - !_mesa_cube_complete(texObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGenerateMipmap(incomplete cube map)"); - return; - } - - _mesa_lock_texture(ctx, texObj); - if (target == GL_TEXTURE_CUBE_MAP) { - GLuint face; - for (face = 0; face < 6; face++) - ctx->Driver.GenerateMipmap(ctx, - GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face, - texObj); - } - else { - ctx->Driver.GenerateMipmap(ctx, target, texObj); - } - _mesa_unlock_texture(ctx, texObj); -} - - -#if FEATURE_EXT_framebuffer_blit - -static const struct gl_renderbuffer_attachment * -find_attachment(const struct gl_framebuffer *fb, - const struct gl_renderbuffer *rb) -{ - GLuint i; - for (i = 0; i < Elements(fb->Attachment); i++) { - if (fb->Attachment[i].Renderbuffer == rb) - return &fb->Attachment[i]; - } - return NULL; -} - - - -/** - * Blit rectangular region, optionally from one framebuffer to another. - * - * Note, if the src buffer is multisampled and the dest is not, this is - * when the samples must be resolved to a single color. - */ -void GLAPIENTRY -_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter) -{ - const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT | - GL_DEPTH_BUFFER_BIT | - GL_STENCIL_BUFFER_BIT); - const struct gl_framebuffer *readFb, *drawFb; - const struct gl_renderbuffer *colorReadRb, *colorDrawRb; - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - FLUSH_VERTICES(ctx, _NEW_BUFFERS); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, - "glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)\n", - srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, - mask, _mesa_lookup_enum_by_nr(filter)); - - if (ctx->NewState) { - _mesa_update_state(ctx); - } - - readFb = ctx->ReadBuffer; - drawFb = ctx->DrawBuffer; - - if (!readFb || !drawFb) { - /* This will normally never happen but someday we may want to - * support MakeCurrent() with no drawables. - */ - return; - } - - /* check for complete framebuffers */ - if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || - readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { - _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, - "glBlitFramebufferEXT(incomplete draw/read buffers)"); - return; - } - - if (filter != GL_NEAREST && filter != GL_LINEAR) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)"); - return; - } - - if (mask & ~legalMaskBits) { - _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)"); - return; - } - - /* depth/stencil must be blitted with nearest filtering */ - if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) - && filter != GL_NEAREST) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter"); - return; - } - - /* get color read/draw renderbuffers */ - if (mask & GL_COLOR_BUFFER_BIT) { - colorReadRb = readFb->_ColorReadBuffer; - colorDrawRb = drawFb->_ColorDrawBuffers[0]; - } - else { - colorReadRb = colorDrawRb = NULL; - } - - if (mask & GL_STENCIL_BUFFER_BIT) { - struct gl_renderbuffer *readRb = readFb->_StencilBuffer; - struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer; - if (!readRb || - !drawRb || - _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) != - _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(stencil buffer size mismatch"); - return; - } - } - - if (mask & GL_DEPTH_BUFFER_BIT) { - struct gl_renderbuffer *readRb = readFb->_DepthBuffer; - struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer; - if (!readRb || - !drawRb || - _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) != - _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(depth buffer size mismatch"); - return; - } - } - - if (readFb->Visual.samples > 0 && - drawFb->Visual.samples > 0 && - readFb->Visual.samples != drawFb->Visual.samples) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(mismatched samples"); - return; - } - - /* extra checks for multisample copies... */ - if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) { - /* src and dest region sizes must be the same */ - if (srcX1 - srcX0 != dstX1 - dstX0 || - srcY1 - srcY0 != dstY1 - dstY0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(bad src/dst multisample region sizes"); - return; - } - - /* color formats must match */ - if (colorReadRb && - colorDrawRb && - colorReadRb->Format != colorDrawRb->Format) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(bad src/dst multisample pixel formats"); - return; - } - } - - if (!ctx->Extensions.EXT_framebuffer_blit) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT"); - return; - } - - /* Debug code */ - if (DEBUG_BLIT) { - printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d," - " 0x%x, 0x%x)\n", - srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, - mask, filter); - if (colorReadRb) { - const struct gl_renderbuffer_attachment *att; - - att = find_attachment(readFb, colorReadRb); - printf(" Src FBO %u RB %u (%dx%d) ", - readFb->Name, colorReadRb->Name, - colorReadRb->Width, colorReadRb->Height); - if (att && att->Texture) { - printf("Tex %u tgt 0x%x level %u face %u", - att->Texture->Name, - att->Texture->Target, - att->TextureLevel, - att->CubeMapFace); - } - printf("\n"); - - att = find_attachment(drawFb, colorDrawRb); - printf(" Dst FBO %u RB %u (%dx%d) ", - drawFb->Name, colorDrawRb->Name, - colorDrawRb->Width, colorDrawRb->Height); - if (att && att->Texture) { - printf("Tex %u tgt 0x%x level %u face %u", - att->Texture->Name, - att->Texture->Target, - att->TextureLevel, - att->CubeMapFace); - } - printf("\n"); - } - } - - ASSERT(ctx->Driver.BlitFramebuffer); - ctx->Driver.BlitFramebuffer(ctx, - srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, - mask, filter); -} -#endif /* FEATURE_EXT_framebuffer_blit */ - -#if FEATURE_ARB_geometry_shader4 -void GLAPIENTRY -_mesa_FramebufferTextureARB(GLenum target, GLenum attachment, - GLuint texture, GLint level) -{ - GET_CURRENT_CONTEXT(ctx); - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTextureARB " - "not implemented!"); -} - -void GLAPIENTRY -_mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment, - GLuint texture, GLint level, GLenum face) -{ - GET_CURRENT_CONTEXT(ctx); - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTextureFaceARB " - "not implemented!"); -} -#endif /* FEATURE_ARB_geometry_shader4 */ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/* + * GL_EXT/ARB_framebuffer_object extensions + * + * Authors: + * Brian Paul + */ + + +#include "buffers.h" +#include "context.h" +#include "enums.h" +#include "fbobject.h" +#include "formats.h" +#include "framebuffer.h" +#include "hash.h" +#include "macros.h" +#include "mfeatures.h" +#include "mtypes.h" +#include "renderbuffer.h" +#include "state.h" +#include "teximage.h" +#include "texobj.h" + + +/** Set this to 1 to help debug FBO incompleteness problems */ +#define DEBUG_FBO 0 + +/** Set this to 1 to debug/log glBlitFramebuffer() calls */ +#define DEBUG_BLIT 0 + + +/** + * Notes: + * + * None of the GL_EXT_framebuffer_object functions are compiled into + * display lists. + */ + + + +/* + * When glGenRender/FramebuffersEXT() is called we insert pointers to + * these placeholder objects into the hash table. + * Later, when the object ID is first bound, we replace the placeholder + * with the real frame/renderbuffer. + */ +static struct gl_framebuffer DummyFramebuffer; +static struct gl_renderbuffer DummyRenderbuffer; + +/* We bind this framebuffer when applications pass a NULL + * drawable/surface in make current. */ +static struct gl_framebuffer IncompleteFramebuffer; + + +#define IS_CUBE_FACE(TARGET) \ + ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \ + (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) + + +static void +delete_dummy_renderbuffer(struct gl_renderbuffer *rb) +{ + /* no op */ +} + +static void +delete_dummy_framebuffer(struct gl_framebuffer *fb) +{ + /* no op */ +} + + +void +_mesa_init_fbobjects(struct gl_context *ctx) +{ + _glthread_INIT_MUTEX(DummyFramebuffer.Mutex); + _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex); + _glthread_INIT_MUTEX(IncompleteFramebuffer.Mutex); + DummyFramebuffer.Delete = delete_dummy_framebuffer; + DummyRenderbuffer.Delete = delete_dummy_renderbuffer; + IncompleteFramebuffer.Delete = delete_dummy_framebuffer; +} + +struct gl_framebuffer * +_mesa_get_incomplete_framebuffer(void) +{ + return &IncompleteFramebuffer; +} + +/** + * Helper routine for getting a gl_renderbuffer. + */ +struct gl_renderbuffer * +_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id) +{ + struct gl_renderbuffer *rb; + + if (id == 0) + return NULL; + + rb = (struct gl_renderbuffer *) + _mesa_HashLookup(ctx->Shared->RenderBuffers, id); + return rb; +} + + +/** + * Helper routine for getting a gl_framebuffer. + */ +struct gl_framebuffer * +_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id) +{ + struct gl_framebuffer *fb; + + if (id == 0) + return NULL; + + fb = (struct gl_framebuffer *) + _mesa_HashLookup(ctx->Shared->FrameBuffers, id); + return fb; +} + + +/** + * Mark the given framebuffer as invalid. This will force the + * test for framebuffer completeness to be done before the framebuffer + * is used. + */ +static void +invalidate_framebuffer(struct gl_framebuffer *fb) +{ + fb->_Status = 0; /* "indeterminate" */ +} + + +/** + * Return the gl_framebuffer object which corresponds to the given + * framebuffer target, such as GL_DRAW_FRAMEBUFFER. + * Check support for GL_EXT_framebuffer_blit to determine if certain + * targets are legal. + * \return gl_framebuffer pointer or NULL if target is illegal + */ +static struct gl_framebuffer * +get_framebuffer_target(struct gl_context *ctx, GLenum target) +{ + switch (target) { + case GL_DRAW_FRAMEBUFFER: + return ctx->Extensions.EXT_framebuffer_blit ? ctx->DrawBuffer : NULL; + case GL_READ_FRAMEBUFFER: + return ctx->Extensions.EXT_framebuffer_blit ? ctx->ReadBuffer : NULL; + case GL_FRAMEBUFFER_EXT: + return ctx->DrawBuffer; + default: + return NULL; + } +} + + +/** + * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding + * gl_renderbuffer_attachment object. + * This function is only used for user-created FB objects, not the + * default / window-system FB object. + * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to + * the depth buffer attachment point. + */ +struct gl_renderbuffer_attachment * +_mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum attachment) +{ + GLuint i; + + assert(fb->Name > 0); + + switch (attachment) { + case GL_COLOR_ATTACHMENT0_EXT: + case GL_COLOR_ATTACHMENT1_EXT: + case GL_COLOR_ATTACHMENT2_EXT: + case GL_COLOR_ATTACHMENT3_EXT: + case GL_COLOR_ATTACHMENT4_EXT: + case GL_COLOR_ATTACHMENT5_EXT: + case GL_COLOR_ATTACHMENT6_EXT: + case GL_COLOR_ATTACHMENT7_EXT: + case GL_COLOR_ATTACHMENT8_EXT: + case GL_COLOR_ATTACHMENT9_EXT: + case GL_COLOR_ATTACHMENT10_EXT: + case GL_COLOR_ATTACHMENT11_EXT: + case GL_COLOR_ATTACHMENT12_EXT: + case GL_COLOR_ATTACHMENT13_EXT: + case GL_COLOR_ATTACHMENT14_EXT: + case GL_COLOR_ATTACHMENT15_EXT: + i = attachment - GL_COLOR_ATTACHMENT0_EXT; + if (i >= ctx->Const.MaxColorAttachments) { + return NULL; + } + return &fb->Attachment[BUFFER_COLOR0 + i]; + case GL_DEPTH_STENCIL_ATTACHMENT: + /* fall-through */ + case GL_DEPTH_BUFFER: + /* fall-through / new in GL 3.0 */ + case GL_DEPTH_ATTACHMENT_EXT: + return &fb->Attachment[BUFFER_DEPTH]; + case GL_STENCIL_BUFFER: + /* fall-through / new in GL 3.0 */ + case GL_STENCIL_ATTACHMENT_EXT: + return &fb->Attachment[BUFFER_STENCIL]; + default: + return NULL; + } +} + + +/** + * As above, but only used for getting attachments of the default / + * window-system framebuffer (not user-created framebuffer objects). + */ +static struct gl_renderbuffer_attachment * +_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum attachment) +{ + assert(fb->Name == 0); + + switch (attachment) { + case GL_FRONT_LEFT: + return &fb->Attachment[BUFFER_FRONT_LEFT]; + case GL_FRONT_RIGHT: + return &fb->Attachment[BUFFER_FRONT_RIGHT]; + case GL_BACK_LEFT: + return &fb->Attachment[BUFFER_BACK_LEFT]; + case GL_BACK_RIGHT: + return &fb->Attachment[BUFFER_BACK_RIGHT]; + case GL_AUX0: + if (fb->Visual.numAuxBuffers == 1) { + return &fb->Attachment[BUFFER_AUX0]; + } + return NULL; + case GL_DEPTH_BUFFER: + /* fall-through / new in GL 3.0 */ + case GL_DEPTH_ATTACHMENT_EXT: + return &fb->Attachment[BUFFER_DEPTH]; + case GL_STENCIL_BUFFER: + /* fall-through / new in GL 3.0 */ + case GL_STENCIL_ATTACHMENT_EXT: + return &fb->Attachment[BUFFER_STENCIL]; + default: + return NULL; + } +} + + + +/** + * Remove any texture or renderbuffer attached to the given attachment + * point. Update reference counts, etc. + */ +void +_mesa_remove_attachment(struct gl_context *ctx, + struct gl_renderbuffer_attachment *att) +{ + if (att->Type == GL_TEXTURE) { + ASSERT(att->Texture); + if (ctx->Driver.FinishRenderTexture) { + /* tell driver that we're done rendering to this texture. */ + ctx->Driver.FinishRenderTexture(ctx, att); + } + _mesa_reference_texobj(&att->Texture, NULL); /* unbind */ + ASSERT(!att->Texture); + } + if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) { + ASSERT(!att->Texture); + _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */ + ASSERT(!att->Renderbuffer); + } + att->Type = GL_NONE; + att->Complete = GL_TRUE; +} + + +/** + * Bind a texture object to an attachment point. + * The previous binding, if any, will be removed first. + */ +void +_mesa_set_texture_attachment(struct gl_context *ctx, + struct gl_framebuffer *fb, + struct gl_renderbuffer_attachment *att, + struct gl_texture_object *texObj, + GLenum texTarget, GLuint level, GLuint zoffset) +{ + if (att->Texture == texObj) { + /* re-attaching same texture */ + ASSERT(att->Type == GL_TEXTURE); + if (ctx->Driver.FinishRenderTexture) + ctx->Driver.FinishRenderTexture(ctx, att); + } + else { + /* new attachment */ + if (ctx->Driver.FinishRenderTexture && att->Texture) + ctx->Driver.FinishRenderTexture(ctx, att); + _mesa_remove_attachment(ctx, att); + att->Type = GL_TEXTURE; + assert(!att->Texture); + _mesa_reference_texobj(&att->Texture, texObj); + } + + /* always update these fields */ + att->TextureLevel = level; + att->CubeMapFace = _mesa_tex_target_to_face(texTarget); + att->Zoffset = zoffset; + att->Complete = GL_FALSE; + + if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { + ctx->Driver.RenderTexture(ctx, fb, att); + } + + invalidate_framebuffer(fb); +} + + +/** + * Bind a renderbuffer to an attachment point. + * The previous binding, if any, will be removed first. + */ +void +_mesa_set_renderbuffer_attachment(struct gl_context *ctx, + struct gl_renderbuffer_attachment *att, + struct gl_renderbuffer *rb) +{ + /* XXX check if re-doing same attachment, exit early */ + _mesa_remove_attachment(ctx, att); + att->Type = GL_RENDERBUFFER_EXT; + att->Texture = NULL; /* just to be safe */ + att->Complete = GL_FALSE; + _mesa_reference_renderbuffer(&att->Renderbuffer, rb); +} + + +/** + * Fallback for ctx->Driver.FramebufferRenderbuffer() + * Attach a renderbuffer object to a framebuffer object. + */ +void +_mesa_framebuffer_renderbuffer(struct gl_context *ctx, + struct gl_framebuffer *fb, + GLenum attachment, struct gl_renderbuffer *rb) +{ + struct gl_renderbuffer_attachment *att; + + _glthread_LOCK_MUTEX(fb->Mutex); + + att = _mesa_get_attachment(ctx, fb, attachment); + ASSERT(att); + if (rb) { + _mesa_set_renderbuffer_attachment(ctx, att, rb); + if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { + /* do stencil attachment here (depth already done above) */ + att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT); + assert(att); + _mesa_set_renderbuffer_attachment(ctx, att, rb); + } + } + else { + _mesa_remove_attachment(ctx, att); + } + + invalidate_framebuffer(fb); + + _glthread_UNLOCK_MUTEX(fb->Mutex); +} + + +/** + * Fallback for ctx->Driver.ValidateFramebuffer() + * Check if the renderbuffer's formats are supported by the software + * renderer. + * Drivers should probably override this. + */ +void +_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) +{ + gl_buffer_index buf; + for (buf = 0; buf < BUFFER_COUNT; buf++) { + const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer; + if (rb) { + switch (rb->_BaseFormat) { + case GL_ALPHA: + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE: + case GL_INTENSITY: + case GL_RED: + case GL_RG: + fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; + return; + default: + /* render buffer format is supported by software rendering */ + ; + } + } + } +} + + +/** + * For debug only. + */ +static void +att_incomplete(const char *msg) +{ +#if DEBUG_FBO + _mesa_debug(NULL, "attachment incomplete: %s\n", msg); +#else + (void) msg; +#endif +} + + +/** + * For debug only. + */ +static void +fbo_incomplete(const char *msg, int index) +{ +#if DEBUG_FBO + _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); +#else + (void) msg; + (void) index; +#endif +} + + +/** + * Is the given base format a legal format for a color renderbuffer? + */ +GLboolean +_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat) +{ + switch (baseFormat) { + case GL_RGB: + case GL_RGBA: + return GL_TRUE; + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + case GL_ALPHA: + return ctx->Extensions.ARB_framebuffer_object; + case GL_RED: + case GL_RG: + return ctx->Extensions.ARB_texture_rg; + default: + return GL_FALSE; + } +} + + +/** + * Is the given base format a legal format for a depth/stencil renderbuffer? + */ +static GLboolean +is_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat) +{ + switch (baseFormat) { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_EXT: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Test if an attachment point is complete and update its Complete field. + * \param format if GL_COLOR, this is a color attachment point, + * if GL_DEPTH, this is a depth component attachment point, + * if GL_STENCIL, this is a stencil component attachment point. + */ +static void +test_attachment_completeness(const struct gl_context *ctx, GLenum format, + struct gl_renderbuffer_attachment *att) +{ + assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL); + + /* assume complete */ + att->Complete = GL_TRUE; + + /* Look for reasons why the attachment might be incomplete */ + if (att->Type == GL_TEXTURE) { + const struct gl_texture_object *texObj = att->Texture; + struct gl_texture_image *texImage; + GLenum baseFormat; + + if (!texObj) { + att_incomplete("no texobj"); + att->Complete = GL_FALSE; + return; + } + + texImage = texObj->Image[att->CubeMapFace][att->TextureLevel]; + if (!texImage) { + att_incomplete("no teximage"); + att->Complete = GL_FALSE; + return; + } + if (texImage->Width < 1 || texImage->Height < 1) { + att_incomplete("teximage width/height=0"); + printf("texobj = %u\n", texObj->Name); + printf("level = %d\n", att->TextureLevel); + att->Complete = GL_FALSE; + return; + } + if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) { + att_incomplete("bad z offset"); + att->Complete = GL_FALSE; + return; + } + + baseFormat = _mesa_get_format_base_format(texImage->TexFormat); + + if (format == GL_COLOR) { + if (!_mesa_is_legal_color_format(ctx, baseFormat)) { + att_incomplete("bad format"); + att->Complete = GL_FALSE; + return; + } + if (_mesa_is_format_compressed(texImage->TexFormat)) { + att_incomplete("compressed internalformat"); + att->Complete = GL_FALSE; + return; + } + } + else if (format == GL_DEPTH) { + if (baseFormat == GL_DEPTH_COMPONENT) { + /* OK */ + } + else if (ctx->Extensions.EXT_packed_depth_stencil && + ctx->Extensions.ARB_depth_texture && + baseFormat == GL_DEPTH_STENCIL_EXT) { + /* OK */ + } + else { + att->Complete = GL_FALSE; + att_incomplete("bad depth format"); + return; + } + } + else { + ASSERT(format == GL_STENCIL); + if (ctx->Extensions.EXT_packed_depth_stencil && + ctx->Extensions.ARB_depth_texture && + baseFormat == GL_DEPTH_STENCIL_EXT) { + /* OK */ + } + else { + /* no such thing as stencil-only textures */ + att_incomplete("illegal stencil texture"); + att->Complete = GL_FALSE; + return; + } + } + } + else if (att->Type == GL_RENDERBUFFER_EXT) { + const GLenum baseFormat = + _mesa_get_format_base_format(att->Renderbuffer->Format); + + ASSERT(att->Renderbuffer); + if (!att->Renderbuffer->InternalFormat || + att->Renderbuffer->Width < 1 || + att->Renderbuffer->Height < 1) { + att_incomplete("0x0 renderbuffer"); + att->Complete = GL_FALSE; + return; + } + if (format == GL_COLOR) { + if (!_mesa_is_legal_color_format(ctx, baseFormat)) { + att_incomplete("bad renderbuffer color format"); + att->Complete = GL_FALSE; + return; + } + } + else if (format == GL_DEPTH) { + if (baseFormat == GL_DEPTH_COMPONENT) { + /* OK */ + } + else if (ctx->Extensions.EXT_packed_depth_stencil && + baseFormat == GL_DEPTH_STENCIL_EXT) { + /* OK */ + } + else { + att_incomplete("bad renderbuffer depth format"); + att->Complete = GL_FALSE; + return; + } + } + else { + assert(format == GL_STENCIL); + if (baseFormat == GL_STENCIL_INDEX) { + /* OK */ + } + else if (ctx->Extensions.EXT_packed_depth_stencil && + baseFormat == GL_DEPTH_STENCIL_EXT) { + /* OK */ + } + else { + att->Complete = GL_FALSE; + att_incomplete("bad renderbuffer stencil format"); + return; + } + } + } + else { + ASSERT(att->Type == GL_NONE); + /* complete */ + return; + } +} + + +/** + * Test if the given framebuffer object is complete and update its + * Status field with the results. + * Calls the ctx->Driver.ValidateFramebuffer() function to allow the + * driver to make hardware-specific validation/completeness checks. + * Also update the framebuffer's Width and Height fields if the + * framebuffer is complete. + */ +void +_mesa_test_framebuffer_completeness(struct gl_context *ctx, + struct gl_framebuffer *fb) +{ + GLuint numImages; + GLenum intFormat = GL_NONE; /* color buffers' internal format */ + GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0; + GLint numSamples = -1; + GLint i; + GLuint j; + + assert(fb->Name != 0); + + numImages = 0; + fb->Width = 0; + fb->Height = 0; + + /* Start at -2 to more easily loop over all attachment points. + * -2: depth buffer + * -1: stencil buffer + * >=0: color buffer + */ + for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { + struct gl_renderbuffer_attachment *att; + GLenum f; + gl_format attFormat; + + /* + * XXX for ARB_fbo, only check color buffers that are named by + * GL_READ_BUFFER and GL_DRAW_BUFFERi. + */ + + /* check for attachment completeness + */ + if (i == -2) { + att = &fb->Attachment[BUFFER_DEPTH]; + test_attachment_completeness(ctx, GL_DEPTH, att); + if (!att->Complete) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; + fbo_incomplete("depth attachment incomplete", -1); + return; + } + } + else if (i == -1) { + att = &fb->Attachment[BUFFER_STENCIL]; + test_attachment_completeness(ctx, GL_STENCIL, att); + if (!att->Complete) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; + fbo_incomplete("stencil attachment incomplete", -1); + return; + } + } + else { + att = &fb->Attachment[BUFFER_COLOR0 + i]; + test_attachment_completeness(ctx, GL_COLOR, att); + if (!att->Complete) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; + fbo_incomplete("color attachment incomplete", i); + return; + } + } + + /* get width, height, format of the renderbuffer/texture + */ + if (att->Type == GL_TEXTURE) { + const struct gl_texture_image *texImg + = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; + minWidth = MIN2(minWidth, texImg->Width); + maxWidth = MAX2(maxWidth, texImg->Width); + minHeight = MIN2(minHeight, texImg->Height); + maxHeight = MAX2(maxHeight, texImg->Height); + f = texImg->_BaseFormat; + attFormat = texImg->TexFormat; + numImages++; + if (!_mesa_is_legal_color_format(ctx, f) && + !is_legal_depth_format(ctx, f)) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; + fbo_incomplete("texture attachment incomplete", -1); + return; + } + } + else if (att->Type == GL_RENDERBUFFER_EXT) { + minWidth = MIN2(minWidth, att->Renderbuffer->Width); + maxWidth = MAX2(minWidth, att->Renderbuffer->Width); + minHeight = MIN2(minHeight, att->Renderbuffer->Height); + maxHeight = MAX2(minHeight, att->Renderbuffer->Height); + f = att->Renderbuffer->InternalFormat; + attFormat = att->Renderbuffer->Format; + numImages++; + } + else { + assert(att->Type == GL_NONE); + continue; + } + + if (numSamples < 0) { + /* first buffer */ + numSamples = att->Renderbuffer->NumSamples; + } + + /* check if integer color */ + fb->_IntegerColor = _mesa_is_format_integer_color(attFormat); + + /* Error-check width, height, format, samples + */ + if (numImages == 1) { + /* save format, num samples */ + if (i >= 0) { + intFormat = f; + } + } + else { + if (!ctx->Extensions.ARB_framebuffer_object) { + /* check that width, height, format are same */ + if (minWidth != maxWidth || minHeight != maxHeight) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; + fbo_incomplete("width or height mismatch", -1); + return; + } + /* check that all color buffer have same format */ + if (intFormat != GL_NONE && f != intFormat) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; + fbo_incomplete("format mismatch", -1); + return; + } + } + if (att->Renderbuffer && + att->Renderbuffer->NumSamples != numSamples) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + fbo_incomplete("inconsistant number of samples", i); + return; + } + + } + } + +#if FEATURE_GL + if (ctx->API == API_OPENGL) { + /* Check that all DrawBuffers are present */ + for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { + if (fb->ColorDrawBuffer[j] != GL_NONE) { + const struct gl_renderbuffer_attachment *att + = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]); + assert(att); + if (att->Type == GL_NONE) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; + fbo_incomplete("missing drawbuffer", j); + return; + } + } + } + + /* Check that the ReadBuffer is present */ + if (fb->ColorReadBuffer != GL_NONE) { + const struct gl_renderbuffer_attachment *att + = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer); + assert(att); + if (att->Type == GL_NONE) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; + fbo_incomplete("missing readbuffer", -1); + return; + } + } + } +#else + (void) j; +#endif + + if (numImages == 0) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; + fbo_incomplete("no attachments", -1); + return; + } + + /* Provisionally set status = COMPLETE ... */ + fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; + + /* ... but the driver may say the FB is incomplete. + * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED + * if anything. + */ + if (ctx->Driver.ValidateFramebuffer) { + ctx->Driver.ValidateFramebuffer(ctx, fb); + if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + fbo_incomplete("driver marked FBO as incomplete", -1); + } + } + + if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) { + /* + * Note that if ARB_framebuffer_object is supported and the attached + * renderbuffers/textures are different sizes, the framebuffer + * width/height will be set to the smallest width/height. + */ + fb->Width = minWidth; + fb->Height = minHeight; + + /* finally, update the visual info for the framebuffer */ + _mesa_update_framebuffer_visual(ctx, fb); + } +} + + +GLboolean GLAPIENTRY +_mesa_IsRenderbufferEXT(GLuint renderbuffer) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + if (renderbuffer) { + struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); + if (rb != NULL && rb != &DummyRenderbuffer) + return GL_TRUE; + } + return GL_FALSE; +} + + +void GLAPIENTRY +_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) +{ + struct gl_renderbuffer *newRb; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target != GL_RENDERBUFFER_EXT) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)"); + return; + } + + /* No need to flush here since the render buffer binding has no + * effect on rendering state. + */ + + if (renderbuffer) { + newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer); + if (newRb == &DummyRenderbuffer) { + /* ID was reserved, but no real renderbuffer object made yet */ + newRb = NULL; + } + else if (!newRb && ctx->Extensions.ARB_framebuffer_object) { + /* All RB IDs must be Gen'd */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)"); + return; + } + + if (!newRb) { + /* create new renderbuffer object */ + newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); + if (!newRb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); + return; + } + ASSERT(newRb->AllocStorage); + _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); + newRb->RefCount = 1; /* referenced by hash table */ + } + } + else { + newRb = NULL; + } + + ASSERT(newRb != &DummyRenderbuffer); + + _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); +} + + +/** + * If the given renderbuffer is anywhere attached to the framebuffer, detach + * the renderbuffer. + * This is used when a renderbuffer object is deleted. + * The spec calls for unbinding. + */ +static void +detach_renderbuffer(struct gl_context *ctx, + struct gl_framebuffer *fb, + struct gl_renderbuffer *rb) +{ + GLuint i; + for (i = 0; i < BUFFER_COUNT; i++) { + if (fb->Attachment[i].Renderbuffer == rb) { + _mesa_remove_attachment(ctx, &fb->Attachment[i]); + } + } + invalidate_framebuffer(fb); +} + + +void GLAPIENTRY +_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) +{ + GLint i; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + for (i = 0; i < n; i++) { + if (renderbuffers[i] > 0) { + struct gl_renderbuffer *rb; + rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]); + if (rb) { + /* check if deleting currently bound renderbuffer object */ + if (rb == ctx->CurrentRenderbuffer) { + /* bind default */ + ASSERT(rb->RefCount >= 2); + _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + } + + if (ctx->DrawBuffer->Name) { + detach_renderbuffer(ctx, ctx->DrawBuffer, rb); + } + if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) { + detach_renderbuffer(ctx, ctx->ReadBuffer, rb); + } + + /* Remove from hash table immediately, to free the ID. + * But the object will not be freed until it's no longer + * referenced anywhere else. + */ + _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); + + if (rb != &DummyRenderbuffer) { + /* no longer referenced by hash table */ + _mesa_reference_renderbuffer(&rb, NULL); + } + } + } + } +} + + +void GLAPIENTRY +_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint first; + GLint i; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)"); + return; + } + + if (!renderbuffers) + return; + + first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); + + for (i = 0; i < n; i++) { + GLuint name = first + i; + renderbuffers[i] = name; + /* insert dummy placeholder into hash table */ + _glthread_LOCK_MUTEX(ctx->Shared->Mutex); + _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer); + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); + } +} + + +/** + * Given an internal format token for a render buffer, return the + * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, + * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE, + * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc). + * + * This is similar to _mesa_base_tex_format() but the set of valid + * internal formats is different. + * + * Note that even if a format is determined to be legal here, validation + * of the FBO may fail if the format is not supported by the driver/GPU. + * + * \param internalFormat as passed to glRenderbufferStorage() + * \return the base internal format, or 0 if internalFormat is illegal + */ +GLenum +_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) +{ + /* + * Notes: some formats such as alpha, luminance, etc. were added + * with GL_ARB_framebuffer_object. + */ + switch (internalFormat) { + case GL_ALPHA: + case GL_ALPHA4: + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16: + return ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; + case GL_LUMINANCE: + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE4_ALPHA4: + case GL_LUMINANCE6_ALPHA2: + case GL_LUMINANCE8_ALPHA8: + case GL_LUMINANCE12_ALPHA4: + case GL_LUMINANCE12_ALPHA12: + case GL_LUMINANCE16_ALPHA16: + return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; + case GL_INTENSITY: + case GL_INTENSITY4: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + return ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; + case GL_RGB: + case GL_R3_G3_B2: + case GL_RGB4: + case GL_RGB5: + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + case GL_SRGB8_EXT: + return GL_RGB; + case GL_RGBA: + case GL_RGBA2: + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGBA8: + case GL_RGB10_A2: + case GL_RGBA12: + case GL_RGBA16: + case GL_RGBA16_SNORM: + case GL_SRGB8_ALPHA8_EXT: + return GL_RGBA; + case GL_STENCIL_INDEX: + case GL_STENCIL_INDEX1_EXT: + case GL_STENCIL_INDEX4_EXT: + case GL_STENCIL_INDEX8_EXT: + case GL_STENCIL_INDEX16_EXT: + return GL_STENCIL_INDEX; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH_COMPONENT32: + return GL_DEPTH_COMPONENT; + case GL_DEPTH_STENCIL_EXT: + case GL_DEPTH24_STENCIL8_EXT: + if (ctx->Extensions.EXT_packed_depth_stencil) + return GL_DEPTH_STENCIL_EXT; + else + return 0; + case GL_RED: + case GL_R8: + case GL_R16: + return ctx->Extensions.ARB_texture_rg ? GL_RED : 0; + case GL_RG: + case GL_RG8: + case GL_RG16: + return ctx->Extensions.ARB_texture_rg ? GL_RG : 0; + /* XXX add floating point and integer formats eventually */ + default: + return 0; + } +} + + +/** sentinal value, see below */ +#define NO_SAMPLES 1000 + + +/** + * Helper function used by _mesa_RenderbufferStorageEXT() and + * _mesa_RenderbufferStorageMultisample(). + * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT(). + */ +static void +renderbuffer_storage(GLenum target, GLenum internalFormat, + GLsizei width, GLsizei height, GLsizei samples) +{ + const char *func = samples == NO_SAMPLES ? + "glRenderbufferStorage" : "RenderbufferStorageMultisample"; + struct gl_renderbuffer *rb; + GLenum baseFormat; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target != GL_RENDERBUFFER_EXT) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); + return; + } + + baseFormat = _mesa_base_fbo_format(ctx, internalFormat); + if (baseFormat == 0) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func); + return; + } + + if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func); + return; + } + + if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func); + return; + } + + if (samples == NO_SAMPLES) { + /* NumSamples == 0 indicates non-multisampling */ + samples = 0; + } + else if (samples > (GLsizei) ctx->Const.MaxSamples) { + /* note: driver may choose to use more samples than what's requested */ + _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func); + return; + } + + rb = ctx->CurrentRenderbuffer; + if (!rb) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); + return; + } + + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + if (rb->InternalFormat == internalFormat && + rb->Width == (GLuint) width && + rb->Height == (GLuint) height) { + /* no change in allocation needed */ + return; + } + + /* These MUST get set by the AllocStorage func */ + rb->Format = MESA_FORMAT_NONE; + rb->NumSamples = samples; + + /* Now allocate the storage */ + ASSERT(rb->AllocStorage); + if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { + /* No error - check/set fields now */ + assert(rb->Format != MESA_FORMAT_NONE); + assert(rb->Width == (GLuint) width); + assert(rb->Height == (GLuint) height); + rb->InternalFormat = internalFormat; + rb->_BaseFormat = baseFormat; + assert(rb->_BaseFormat != 0); + } + else { + /* Probably ran out of memory - clear the fields */ + rb->Width = 0; + rb->Height = 0; + rb->Format = MESA_FORMAT_NONE; + rb->InternalFormat = GL_NONE; + rb->_BaseFormat = GL_NONE; + rb->NumSamples = 0; + } + + /* + test_framebuffer_completeness(ctx, fb); + */ + /* XXX if this renderbuffer is attached anywhere, invalidate attachment + * points??? + */ +} + + +#if FEATURE_OES_EGL_image +void GLAPIENTRY +_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) +{ + struct gl_renderbuffer *rb; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!ctx->Extensions.OES_EGL_image) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glEGLImageTargetRenderbufferStorageOES(unsupported)"); + return; + } + + if (target != GL_RENDERBUFFER) { + _mesa_error(ctx, GL_INVALID_ENUM, + "EGLImageTargetRenderbufferStorageOES"); + return; + } + + rb = ctx->CurrentRenderbuffer; + if (!rb) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "EGLImageTargetRenderbufferStorageOES"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image); +} +#endif + + +/** + * Helper function for _mesa_GetRenderbufferParameterivEXT() and + * _mesa_GetFramebufferAttachmentParameterivEXT() + * We have to be careful to respect the base format. For example, if a + * renderbuffer/texture was created with internalFormat=GL_RGB but the + * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE + * we need to return zero. + */ +static GLint +get_component_bits(GLenum pname, GLenum baseFormat, gl_format format) +{ + switch (pname) { + case GL_RENDERBUFFER_RED_SIZE_EXT: + case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: + if (baseFormat == GL_RGB || baseFormat == GL_RGBA || + baseFormat == GL_RG || baseFormat == GL_RED) + return _mesa_get_format_bits(format, pname); + else + return 0; + case GL_RENDERBUFFER_GREEN_SIZE_EXT: + case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: + if (baseFormat == GL_RGB || baseFormat == GL_RGBA || baseFormat == GL_RG) + return _mesa_get_format_bits(format, pname); + else + return 0; + case GL_RENDERBUFFER_BLUE_SIZE_EXT: + case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: + if (baseFormat == GL_RGB || baseFormat == GL_RGBA) + return _mesa_get_format_bits(format, pname); + else + return 0; + case GL_RENDERBUFFER_ALPHA_SIZE_EXT: + case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: + if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA || + baseFormat == GL_LUMINANCE_ALPHA) + return _mesa_get_format_bits(format, pname); + else + return 0; + case GL_RENDERBUFFER_DEPTH_SIZE_EXT: + case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: + if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL) + return _mesa_get_format_bits(format, pname); + else + return 0; + case GL_RENDERBUFFER_STENCIL_SIZE_EXT: + case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: + if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL) + return _mesa_get_format_bits(format, pname); + else + return 0; + default: + return 0; + } +} + + + +void GLAPIENTRY +_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, + GLsizei width, GLsizei height) +{ + /* GL_ARB_fbo says calling this function is equivalent to calling + * glRenderbufferStorageMultisample() with samples=0. We pass in + * a token value here just for error reporting purposes. + */ + renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES); +} + + +void GLAPIENTRY +_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples, + GLenum internalFormat, + GLsizei width, GLsizei height) +{ + renderbuffer_storage(target, internalFormat, width, height, samples); +} + + +/** + * OpenGL ES version of glRenderBufferStorage. + */ +void GLAPIENTRY +_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, + GLsizei width, GLsizei height) +{ + switch (internalFormat) { + case GL_RGB565: + /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */ + /* choose a closest format */ + internalFormat = GL_RGB5; + break; + default: + break; + } + + renderbuffer_storage(target, internalFormat, width, height, 0); +} + + +void GLAPIENTRY +_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) +{ + struct gl_renderbuffer *rb; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target != GL_RENDERBUFFER_EXT) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetRenderbufferParameterivEXT(target)"); + return; + } + + rb = ctx->CurrentRenderbuffer; + if (!rb) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetRenderbufferParameterivEXT"); + return; + } + + /* No need to flush here since we're just quering state which is + * not effected by rendering. + */ + + switch (pname) { + case GL_RENDERBUFFER_WIDTH_EXT: + *params = rb->Width; + return; + case GL_RENDERBUFFER_HEIGHT_EXT: + *params = rb->Height; + return; + case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: + *params = rb->InternalFormat; + return; + case GL_RENDERBUFFER_RED_SIZE_EXT: + case GL_RENDERBUFFER_GREEN_SIZE_EXT: + case GL_RENDERBUFFER_BLUE_SIZE_EXT: + case GL_RENDERBUFFER_ALPHA_SIZE_EXT: + case GL_RENDERBUFFER_DEPTH_SIZE_EXT: + case GL_RENDERBUFFER_STENCIL_SIZE_EXT: + *params = get_component_bits(pname, rb->_BaseFormat, rb->Format); + break; + case GL_RENDERBUFFER_SAMPLES: + if (ctx->Extensions.ARB_framebuffer_object) { + *params = rb->NumSamples; + break; + } + /* fallthrough */ + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetRenderbufferParameterivEXT(target)"); + return; + } +} + + +GLboolean GLAPIENTRY +_mesa_IsFramebufferEXT(GLuint framebuffer) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + if (framebuffer) { + struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer); + if (rb != NULL && rb != &DummyFramebuffer) + return GL_TRUE; + } + return GL_FALSE; +} + + +/** + * Check if any of the attachments of the given framebuffer are textures + * (render to texture). Call ctx->Driver.RenderTexture() for such + * attachments. + */ +static void +check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) +{ + GLuint i; + ASSERT(ctx->Driver.RenderTexture); + + if (fb->Name == 0) + return; /* can't render to texture with winsys framebuffers */ + + for (i = 0; i < BUFFER_COUNT; i++) { + struct gl_renderbuffer_attachment *att = fb->Attachment + i; + struct gl_texture_object *texObj = att->Texture; + if (texObj + && texObj->Image[att->CubeMapFace][att->TextureLevel]) { + ctx->Driver.RenderTexture(ctx, fb, att); + } + } +} + + +/** + * Examine all the framebuffer's attachments to see if any are textures. + * If so, call ctx->Driver.FinishRenderTexture() for each texture to + * notify the device driver that the texture image may have changed. + */ +static void +check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) +{ + if (fb->Name == 0) + return; /* can't render to texture with winsys framebuffers */ + + if (ctx->Driver.FinishRenderTexture) { + GLuint i; + for (i = 0; i < BUFFER_COUNT; i++) { + struct gl_renderbuffer_attachment *att = fb->Attachment + i; + if (att->Texture && att->Renderbuffer) { + ctx->Driver.FinishRenderTexture(ctx, att); + } + } + } +} + + +void GLAPIENTRY +_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) +{ + struct gl_framebuffer *newDrawFb, *newReadFb; + struct gl_framebuffer *oldDrawFb, *oldReadFb; + GLboolean bindReadBuf, bindDrawBuf; + GET_CURRENT_CONTEXT(ctx); + +#ifdef DEBUG + if (ctx->Extensions.ARB_framebuffer_object) { + ASSERT(ctx->Extensions.EXT_framebuffer_object); + ASSERT(ctx->Extensions.EXT_framebuffer_blit); + } +#endif + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!ctx->Extensions.EXT_framebuffer_object) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindFramebufferEXT(unsupported)"); + return; + } + + switch (target) { +#if FEATURE_EXT_framebuffer_blit + case GL_DRAW_FRAMEBUFFER_EXT: + if (!ctx->Extensions.EXT_framebuffer_blit) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); + return; + } + bindDrawBuf = GL_TRUE; + bindReadBuf = GL_FALSE; + break; + case GL_READ_FRAMEBUFFER_EXT: + if (!ctx->Extensions.EXT_framebuffer_blit) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); + return; + } + bindDrawBuf = GL_FALSE; + bindReadBuf = GL_TRUE; + break; +#endif + case GL_FRAMEBUFFER_EXT: + bindDrawBuf = GL_TRUE; + bindReadBuf = GL_TRUE; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); + return; + } + + if (framebuffer) { + /* Binding a user-created framebuffer object */ + newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer); + if (newDrawFb == &DummyFramebuffer) { + /* ID was reserved, but no real framebuffer object made yet */ + newDrawFb = NULL; + } + else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) { + /* All FBO IDs must be Gen'd */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)"); + return; + } + + if (!newDrawFb) { + /* create new framebuffer object */ + newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); + if (!newDrawFb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); + return; + } + _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb); + } + newReadFb = newDrawFb; + } + else { + /* Binding the window system framebuffer (which was originally set + * with MakeCurrent). + */ + newDrawFb = ctx->WinSysDrawBuffer; + newReadFb = ctx->WinSysReadBuffer; + } + + ASSERT(newDrawFb); + ASSERT(newDrawFb != &DummyFramebuffer); + + /* save pointers to current/old framebuffers */ + oldDrawFb = ctx->DrawBuffer; + oldReadFb = ctx->ReadBuffer; + + /* check if really changing bindings */ + if (oldDrawFb == newDrawFb) + bindDrawBuf = GL_FALSE; + if (oldReadFb == newReadFb) + bindReadBuf = GL_FALSE; + + /* + * OK, now bind the new Draw/Read framebuffers, if they're changing. + * + * We also check if we're beginning and/or ending render-to-texture. + * When a framebuffer with texture attachments is unbound, call + * ctx->Driver.FinishRenderTexture(). + * When a framebuffer with texture attachments is bound, call + * ctx->Driver.RenderTexture(). + * + * Note that if the ReadBuffer has texture attachments we don't consider + * that a render-to-texture case. + */ + if (bindReadBuf) { + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + /* check if old readbuffer was render-to-texture */ + check_end_texture_render(ctx, oldReadFb); + + _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb); + } + + if (bindDrawBuf) { + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + /* check if old read/draw buffers were render-to-texture */ + if (!bindReadBuf) + check_end_texture_render(ctx, oldReadFb); + + if (oldDrawFb != oldReadFb) + check_end_texture_render(ctx, oldDrawFb); + + /* check if newly bound framebuffer has any texture attachments */ + check_begin_texture_render(ctx, newDrawFb); + + _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb); + } + + if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) { + ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb); + } +} + + +void GLAPIENTRY +_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) +{ + GLint i; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + for (i = 0; i < n; i++) { + if (framebuffers[i] > 0) { + struct gl_framebuffer *fb; + fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]); + if (fb) { + ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); + + /* check if deleting currently bound framebuffer object */ + if (ctx->Extensions.EXT_framebuffer_blit) { + /* separate draw/read binding points */ + if (fb == ctx->DrawBuffer) { + /* bind default */ + ASSERT(fb->RefCount >= 2); + _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); + } + if (fb == ctx->ReadBuffer) { + /* bind default */ + ASSERT(fb->RefCount >= 2); + _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); + } + } + else { + /* only one binding point for read/draw buffers */ + if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) { + /* bind default */ + ASSERT(fb->RefCount >= 2); + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } + } + + /* remove from hash table immediately, to free the ID */ + _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); + + if (fb != &DummyFramebuffer) { + /* But the object will not be freed until it's no longer + * bound in any context. + */ + _mesa_reference_framebuffer(&fb, NULL); + } + } + } + } +} + + +void GLAPIENTRY +_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint first; + GLint i; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); + return; + } + + if (!framebuffers) + return; + + first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); + + for (i = 0; i < n; i++) { + GLuint name = first + i; + framebuffers[i] = name; + /* insert dummy placeholder into hash table */ + _glthread_LOCK_MUTEX(ctx->Shared->Mutex); + _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); + } +} + + + +GLenum GLAPIENTRY +_mesa_CheckFramebufferStatusEXT(GLenum target) +{ + struct gl_framebuffer *buffer; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); + + buffer = get_framebuffer_target(ctx, target); + if (!buffer) { + _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); + return 0; + } + + if (buffer->Name == 0) { + /* The window system / default framebuffer is always complete */ + return GL_FRAMEBUFFER_COMPLETE_EXT; + } + + /* No need to flush here */ + + if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) { + _mesa_test_framebuffer_completeness(ctx, buffer); + } + + return buffer->_Status; +} + + + +/** + * Common code called by glFramebufferTexture1D/2D/3DEXT(). + */ +static void +framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, + GLenum attachment, GLenum textarget, GLuint texture, + GLint level, GLint zoffset) +{ + struct gl_renderbuffer_attachment *att; + struct gl_texture_object *texObj = NULL; + struct gl_framebuffer *fb; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferTexture%sEXT(target=0x%x)", caller, target); + return; + } + + /* check framebuffer binding */ + if (fb->Name == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTexture%sEXT", caller); + return; + } + + + /* The textarget, level, and zoffset parameters are only validated if + * texture is non-zero. + */ + if (texture) { + GLboolean err = GL_TRUE; + + texObj = _mesa_lookup_texture(ctx, texture); + if (texObj != NULL) { + if (textarget == 0) { + /* XXX what's the purpose of this? */ + err = (texObj->Target != GL_TEXTURE_3D) && + (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && + (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT); + } + else { + err = (texObj->Target == GL_TEXTURE_CUBE_MAP) + ? !IS_CUBE_FACE(textarget) + : (texObj->Target != textarget); + } + } + else { + /* can't render to a non-existant texture */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTexture%sEXT(non existant texture)", + caller); + return; + } + + if (err) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTexture%sEXT(texture target mismatch)", + caller); + return; + } + + if (texObj->Target == GL_TEXTURE_3D) { + const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); + if (zoffset < 0 || zoffset >= maxSize) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glFramebufferTexture%sEXT(zoffset)", caller); + return; + } + } + else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || + (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) { + if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glFramebufferTexture%sEXT(layer)", caller); + return; + } + } + + if ((level < 0) || + (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glFramebufferTexture%sEXT(level)", caller); + return; + } + } + + att = _mesa_get_attachment(ctx, fb, attachment); + if (att == NULL) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferTexture%sEXT(attachment)", caller); + return; + } + + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + _glthread_LOCK_MUTEX(fb->Mutex); + if (texObj) { + _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, + level, zoffset); + /* Set the render-to-texture flag. We'll check this flag in + * glTexImage() and friends to determine if we need to revalidate + * any FBOs that might be rendering into this texture. + * This flag never gets cleared since it's non-trivial to determine + * when all FBOs might be done rendering to this texture. That's OK + * though since it's uncommon to render to a texture then repeatedly + * call glTexImage() to change images in the texture. + */ + texObj->_RenderToTexture = GL_TRUE; + } + else { + _mesa_remove_attachment(ctx, att); + } + + invalidate_framebuffer(fb); + + _glthread_UNLOCK_MUTEX(fb->Mutex); +} + + + +void GLAPIENTRY +_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level) +{ + GET_CURRENT_CONTEXT(ctx); + + if ((texture != 0) && (textarget != GL_TEXTURE_1D)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferTexture1DEXT(textarget)"); + return; + } + + framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, + level, 0); +} + + +void GLAPIENTRY +_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level) +{ + GET_CURRENT_CONTEXT(ctx); + + if ((texture != 0) && + (textarget != GL_TEXTURE_2D) && + (textarget != GL_TEXTURE_RECTANGLE_ARB) && + (!IS_CUBE_FACE(textarget))) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTexture2DEXT(textarget=0x%x)", textarget); + return; + } + + framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, + level, 0); +} + + +void GLAPIENTRY +_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level, GLint zoffset) +{ + GET_CURRENT_CONTEXT(ctx); + + if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferTexture3DEXT(textarget)"); + return; + } + + framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, + level, zoffset); +} + + +void GLAPIENTRY +_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer) +{ + GET_CURRENT_CONTEXT(ctx); + + framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, + level, layer); +} + + +void GLAPIENTRY +_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, + GLenum renderbufferTarget, + GLuint renderbuffer) +{ + struct gl_renderbuffer_attachment *att; + struct gl_framebuffer *fb; + struct gl_renderbuffer *rb; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferRenderbufferEXT(target)"); + return; + } + + if (renderbufferTarget != GL_RENDERBUFFER_EXT) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferRenderbufferEXT(renderbufferTarget)"); + return; + } + + if (fb->Name == 0) { + /* Can't attach new renderbuffers to a window system framebuffer */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); + return; + } + + att = _mesa_get_attachment(ctx, fb, attachment); + if (att == NULL) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferRenderbufferEXT(invalid attachment %s)", + _mesa_lookup_enum_by_nr(attachment)); + return; + } + + if (renderbuffer) { + rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); + if (!rb) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferRenderbufferEXT(non-existant" + " renderbuffer %u)", renderbuffer); + return; + } + else if (rb == &DummyRenderbuffer) { + /* This is what NVIDIA does */ + _mesa_error(ctx, GL_INVALID_VALUE, + "glFramebufferRenderbufferEXT(renderbuffer %u)", + renderbuffer); + return; + } + } + else { + /* remove renderbuffer attachment */ + rb = NULL; + } + + if (attachment == GL_DEPTH_STENCIL_ATTACHMENT && + rb && rb->Format != MESA_FORMAT_NONE) { + /* make sure the renderbuffer is a depth/stencil format */ + const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); + if (baseFormat != GL_DEPTH_STENCIL) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferRenderbufferEXT(renderbuffer" + " is not DEPTH_STENCIL format)"); + return; + } + } + + + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + assert(ctx->Driver.FramebufferRenderbuffer); + ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); + + /* Some subsequent GL commands may depend on the framebuffer's visual + * after the binding is updated. Update visual info now. + */ + _mesa_update_framebuffer_visual(ctx, fb); +} + + +void GLAPIENTRY +_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, + GLenum pname, GLint *params) +{ + const struct gl_renderbuffer_attachment *att; + struct gl_framebuffer *buffer; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + buffer = get_framebuffer_target(ctx, target); + if (!buffer) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(target)"); + return; + } + + if (buffer->Name == 0) { + /* the default / window-system FBO */ + att = _mesa_get_fb0_attachment(ctx, buffer, attachment); + } + else { + /* user-created framebuffer FBO */ + att = _mesa_get_attachment(ctx, buffer, attachment); + } + + if (att == NULL) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(attachment)"); + return; + } + + if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { + /* the depth and stencil attachments must point to the same buffer */ + const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt; + depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT); + stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT); + if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL" + " attachments differ)"); + return; + } + } + + /* No need to flush here */ + + switch (pname) { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: + *params = buffer->Name == 0 ? GL_FRAMEBUFFER_DEFAULT : att->Type; + return; + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: + if (att->Type == GL_RENDERBUFFER_EXT) { + *params = att->Renderbuffer->Name; + } + else if (att->Type == GL_TEXTURE) { + *params = att->Texture->Name; + } + else { + assert(att->Type == GL_NONE); + *params = 0; + } + return; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: + if (att->Type == GL_TEXTURE) { + *params = att->TextureLevel; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } + return; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: + if (att->Type == GL_TEXTURE) { + if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) { + *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; + } + else { + *params = 0; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } + return; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: + if (att->Type == GL_TEXTURE) { + if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) { + *params = att->Zoffset; + } + else { + *params = 0; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } + return; + case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: + if (!ctx->Extensions.ARB_framebuffer_object) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } + else { + if (ctx->Extensions.EXT_framebuffer_sRGB && ctx->Const.sRGBCapable) { + *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format); + } + else { + /* According to ARB_framebuffer_sRGB, we should return LINEAR + * if the sRGB conversion is unsupported. */ + *params = GL_LINEAR; + } + } + return; + case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: + if (!ctx->Extensions.ARB_framebuffer_object) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + return; + } + else { + gl_format format = att->Renderbuffer->Format; + if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) { + /* special cases */ + *params = GL_INDEX; + } + else { + *params = _mesa_get_format_datatype(format); + } + } + return; + case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: + if (!ctx->Extensions.ARB_framebuffer_object) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } + else if (att->Texture) { + const struct gl_texture_image *texImage = + _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target, + att->TextureLevel); + if (texImage) { + *params = get_component_bits(pname, texImage->_BaseFormat, + texImage->TexFormat); + } + else { + *params = 0; + } + } + else if (att->Renderbuffer) { + *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat, + att->Renderbuffer->Format); + } + else { + *params = 0; + } + return; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + return; + } +} + + +void GLAPIENTRY +_mesa_GenerateMipmapEXT(GLenum target) +{ + struct gl_texture_object *texObj; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + switch (target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + case GL_TEXTURE_CUBE_MAP: + /* OK, legal value */ + break; + default: + /* XXX need to implement GL_TEXTURE_1D_ARRAY and GL_TEXTURE_2D_ARRAY */ + _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)"); + return; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + + if (texObj->BaseLevel >= texObj->MaxLevel) { + /* nothing to do */ + return; + } + + if (texObj->Target == GL_TEXTURE_CUBE_MAP && + !_mesa_cube_complete(texObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGenerateMipmap(incomplete cube map)"); + return; + } + + _mesa_lock_texture(ctx, texObj); + if (target == GL_TEXTURE_CUBE_MAP) { + GLuint face; + for (face = 0; face < 6; face++) + ctx->Driver.GenerateMipmap(ctx, + GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face, + texObj); + } + else { + ctx->Driver.GenerateMipmap(ctx, target, texObj); + } + _mesa_unlock_texture(ctx, texObj); +} + + +#if FEATURE_EXT_framebuffer_blit + +static const struct gl_renderbuffer_attachment * +find_attachment(const struct gl_framebuffer *fb, + const struct gl_renderbuffer *rb) +{ + GLuint i; + for (i = 0; i < Elements(fb->Attachment); i++) { + if (fb->Attachment[i].Renderbuffer == rb) + return &fb->Attachment[i]; + } + return NULL; +} + + + +/** + * Blit rectangular region, optionally from one framebuffer to another. + * + * Note, if the src buffer is multisampled and the dest is not, this is + * when the samples must be resolved to a single color. + */ +void GLAPIENTRY +_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT | + GL_DEPTH_BUFFER_BIT | + GL_STENCIL_BUFFER_BIT); + const struct gl_framebuffer *readFb, *drawFb; + const struct gl_renderbuffer *colorReadRb, *colorDrawRb; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, + "glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)\n", + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, _mesa_lookup_enum_by_nr(filter)); + + if (ctx->NewState) { + _mesa_update_state(ctx); + } + + readFb = ctx->ReadBuffer; + drawFb = ctx->DrawBuffer; + + if (!readFb || !drawFb) { + /* This will normally never happen but someday we may want to + * support MakeCurrent() with no drawables. + */ + return; + } + + /* check for complete framebuffers */ + if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || + readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "glBlitFramebufferEXT(incomplete draw/read buffers)"); + return; + } + + if (filter != GL_NEAREST && filter != GL_LINEAR) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)"); + return; + } + + if (mask & ~legalMaskBits) { + _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)"); + return; + } + + /* depth/stencil must be blitted with nearest filtering */ + if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) + && filter != GL_NEAREST) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter"); + return; + } + + /* get color read/draw renderbuffers */ + if (mask & GL_COLOR_BUFFER_BIT) { + colorReadRb = readFb->_ColorReadBuffer; + colorDrawRb = drawFb->_ColorDrawBuffers[0]; + } + else { + colorReadRb = colorDrawRb = NULL; + } + + if (mask & GL_STENCIL_BUFFER_BIT) { + struct gl_renderbuffer *readRb = readFb->_StencilBuffer; + struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer; + if (!readRb || + !drawRb || + _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) != + _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(stencil buffer size mismatch"); + return; + } + } + + if (mask & GL_DEPTH_BUFFER_BIT) { + struct gl_renderbuffer *readRb = readFb->_DepthBuffer; + struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer; + if (!readRb || + !drawRb || + _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) != + _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(depth buffer size mismatch"); + return; + } + } + + if (readFb->Visual.samples > 0 && + drawFb->Visual.samples > 0 && + readFb->Visual.samples != drawFb->Visual.samples) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(mismatched samples"); + return; + } + + /* extra checks for multisample copies... */ + if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) { + /* src and dest region sizes must be the same */ + if (srcX1 - srcX0 != dstX1 - dstX0 || + srcY1 - srcY0 != dstY1 - dstY0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(bad src/dst multisample region sizes"); + return; + } + + /* color formats must match */ + if (colorReadRb && + colorDrawRb && + colorReadRb->Format != colorDrawRb->Format) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(bad src/dst multisample pixel formats"); + return; + } + } + + if (!ctx->Extensions.EXT_framebuffer_blit) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT"); + return; + } + + /* Debug code */ + if (DEBUG_BLIT) { + printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d," + " 0x%x, 0x%x)\n", + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, filter); + if (colorReadRb) { + const struct gl_renderbuffer_attachment *att; + + att = find_attachment(readFb, colorReadRb); + printf(" Src FBO %u RB %u (%dx%d) ", + readFb->Name, colorReadRb->Name, + colorReadRb->Width, colorReadRb->Height); + if (att && att->Texture) { + printf("Tex %u tgt 0x%x level %u face %u", + att->Texture->Name, + att->Texture->Target, + att->TextureLevel, + att->CubeMapFace); + } + printf("\n"); + + att = find_attachment(drawFb, colorDrawRb); + printf(" Dst FBO %u RB %u (%dx%d) ", + drawFb->Name, colorDrawRb->Name, + colorDrawRb->Width, colorDrawRb->Height); + if (att && att->Texture) { + printf("Tex %u tgt 0x%x level %u face %u", + att->Texture->Name, + att->Texture->Target, + att->TextureLevel, + att->CubeMapFace); + } + printf("\n"); + } + } + + ASSERT(ctx->Driver.BlitFramebuffer); + ctx->Driver.BlitFramebuffer(ctx, + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, filter); +} +#endif /* FEATURE_EXT_framebuffer_blit */ + +#if FEATURE_ARB_geometry_shader4 +void GLAPIENTRY +_mesa_FramebufferTextureARB(GLenum target, GLenum attachment, + GLuint texture, GLint level) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTextureARB " + "not implemented!"); +} + +void GLAPIENTRY +_mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment, + GLuint texture, GLint level, GLenum face) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTextureFaceARB " + "not implemented!"); +} +#endif /* FEATURE_ARB_geometry_shader4 */ diff --git a/mesalib/src/mesa/main/framebuffer.c b/mesalib/src/mesa/main/framebuffer.c index 948b3b7b5..227b214a5 100644 --- a/mesalib/src/mesa/main/framebuffer.c +++ b/mesalib/src/mesa/main/framebuffer.c @@ -794,15 +794,12 @@ update_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, ctx->Color.DrawBuffer, NULL); } - if (fb->ColorReadBuffer != ctx->Pixel.ReadBuffer) { - - } } else { /* This is a user-created framebuffer. * Completeness only matters for user-created framebuffers. */ - if (fb->_Status != GL_FRAMEBUFFER_COMPLETE) { + if (fb->_Status == 0) { _mesa_test_framebuffer_completeness(ctx, fb); } } diff --git a/mesalib/src/mesa/main/get.c b/mesalib/src/mesa/main/get.c index 3e5ddfcfd..336304c59 100644 --- a/mesalib/src/mesa/main/get.c +++ b/mesalib/src/mesa/main/get.c @@ -1,2533 +1,2527 @@ -/* - * Copyright (C) 2010 Brian Paul All Rights Reserved. - * Copyright (C) 2010 Intel Corporation - * - * 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. - * - * Author: Kristian Høgsberg - */ - -#include "glheader.h" -#include "context.h" -#include "enable.h" -#include "enums.h" -#include "extensions.h" -#include "get.h" -#include "macros.h" -#include "mfeatures.h" -#include "mtypes.h" -#include "state.h" -#include "texcompress.h" -#include "framebuffer.h" - -/* This is a table driven implemetation of the glGet*v() functions. - * The basic idea is that most getters just look up an int somewhere - * in struct gl_context and then convert it to a bool or float according to - * which of glGetIntegerv() glGetBooleanv() etc is being called. - * Instead of generating code to do this, we can just record the enum - * value and the offset into struct gl_context in an array of structs. Then - * in glGet*(), we lookup the struct for the enum in question, and use - * the offset to get the int we need. - * - * Sometimes we need to look up a float, a boolean, a bit in a - * bitfield, a matrix or other types instead, so we need to track the - * type of the value in struct gl_context. And sometimes the value isn't in - * struct gl_context but in the drawbuffer, the array object, current texture - * unit, or maybe it's a computed value. So we need to also track - * where or how to find the value. Finally, we sometimes need to - * check that one of a number of extensions are enabled, the GL - * version or flush or call _mesa_update_state(). This is done by - * attaching optional extra information to the value description - * struct, it's sort of like an array of opcodes that describe extra - * checks or actions. - * - * Putting all this together we end up with struct value_desc below, - * and with a couple of macros to help, the table of struct value_desc - * is about as concise as the specification in the old python script. - */ - -#undef CONST - -#define FLOAT_TO_BOOLEAN(X) ( (X) ? GL_TRUE : GL_FALSE ) -#define FLOAT_TO_FIXED(F) ( ((F) * 65536.0f > INT_MAX) ? INT_MAX : \ - ((F) * 65536.0f < INT_MIN) ? INT_MIN : \ - (GLint) ((F) * 65536.0f) ) - -#define INT_TO_BOOLEAN(I) ( (I) ? GL_TRUE : GL_FALSE ) -#define INT_TO_FIXED(I) ( ((I) > SHRT_MAX) ? INT_MAX : \ - ((I) < SHRT_MIN) ? INT_MIN : \ - (GLint) ((I) * 65536) ) - -#define INT64_TO_BOOLEAN(I) ( (I) ? GL_TRUE : GL_FALSE ) -#define INT64_TO_INT(I) ( (GLint)((I > INT_MAX) ? INT_MAX : ((I < INT_MIN) ? INT_MIN : (I))) ) - -#define BOOLEAN_TO_INT(B) ( (GLint) (B) ) -#define BOOLEAN_TO_INT64(B) ( (GLint64) (B) ) -#define BOOLEAN_TO_FLOAT(B) ( (B) ? 1.0F : 0.0F ) -#define BOOLEAN_TO_FIXED(B) ( (GLint) ((B) ? 1 : 0) << 16 ) - -#define ENUM_TO_INT64(E) ( (GLint64) (E) ) -#define ENUM_TO_FIXED(E) (E) - -enum value_type { - TYPE_INVALID, - TYPE_API_MASK, - TYPE_INT, - TYPE_INT_2, - TYPE_INT_3, - TYPE_INT_4, - TYPE_INT_N, - TYPE_INT64, - TYPE_ENUM, - TYPE_ENUM_2, - TYPE_BOOLEAN, - TYPE_BIT_0, - TYPE_BIT_1, - TYPE_BIT_2, - TYPE_BIT_3, - TYPE_BIT_4, - TYPE_BIT_5, - TYPE_FLOAT, - TYPE_FLOAT_2, - TYPE_FLOAT_3, - TYPE_FLOAT_4, - TYPE_FLOATN, - TYPE_FLOATN_2, - TYPE_FLOATN_3, - TYPE_FLOATN_4, - TYPE_DOUBLEN, - TYPE_MATRIX, - TYPE_MATRIX_T, - TYPE_CONST -}; - -enum value_location { - LOC_BUFFER, - LOC_CONTEXT, - LOC_ARRAY, - LOC_TEXUNIT, - LOC_CUSTOM -}; - -enum value_extra { - EXTRA_END = 0x8000, - EXTRA_VERSION_30, - EXTRA_VERSION_31, - EXTRA_VERSION_32, - EXTRA_VERSION_ES2, - EXTRA_NEW_BUFFERS, - EXTRA_VALID_DRAW_BUFFER, - EXTRA_VALID_TEXTURE_UNIT, - EXTRA_FLUSH_CURRENT, -}; - -#define NO_EXTRA NULL -#define NO_OFFSET 0 - -struct value_desc { - GLenum pname; - GLubyte location; /**< enum value_location */ - GLubyte type; /**< enum value_type */ - int offset; - const int *extra; -}; - -union value { - GLfloat value_float; - GLfloat value_float_4[4]; - GLmatrix *value_matrix; - GLint value_int; - GLint value_int_4[4]; - GLint64 value_int64; - GLenum value_enum; - - /* Sigh, see GL_COMPRESSED_TEXTURE_FORMATS_ARB handling */ - struct { - GLint n, ints[100]; - } value_int_n; - GLboolean value_bool; -}; - -#define BUFFER_FIELD(field, type) \ - LOC_BUFFER, type, offsetof(struct gl_framebuffer, field) -#define CONTEXT_FIELD(field, type) \ - LOC_CONTEXT, type, offsetof(struct gl_context, field) -#define ARRAY_FIELD(field, type) \ - LOC_ARRAY, type, offsetof(struct gl_array_object, field) -#define CONST(value) \ - LOC_CONTEXT, TYPE_CONST, value - -#define BUFFER_INT(field) BUFFER_FIELD(field, TYPE_INT) -#define BUFFER_ENUM(field) BUFFER_FIELD(field, TYPE_ENUM) -#define BUFFER_BOOL(field) BUFFER_FIELD(field, TYPE_BOOLEAN) - -#define CONTEXT_INT(field) CONTEXT_FIELD(field, TYPE_INT) -#define CONTEXT_INT2(field) CONTEXT_FIELD(field, TYPE_INT_2) -#define CONTEXT_INT64(field) CONTEXT_FIELD(field, TYPE_INT64) -#define CONTEXT_ENUM(field) CONTEXT_FIELD(field, TYPE_ENUM) -#define CONTEXT_ENUM2(field) CONTEXT_FIELD(field, TYPE_ENUM_2) -#define CONTEXT_BOOL(field) CONTEXT_FIELD(field, TYPE_BOOLEAN) -#define CONTEXT_BIT0(field) CONTEXT_FIELD(field, TYPE_BIT_0) -#define CONTEXT_BIT1(field) CONTEXT_FIELD(field, TYPE_BIT_1) -#define CONTEXT_BIT2(field) CONTEXT_FIELD(field, TYPE_BIT_2) -#define CONTEXT_BIT3(field) CONTEXT_FIELD(field, TYPE_BIT_3) -#define CONTEXT_BIT4(field) CONTEXT_FIELD(field, TYPE_BIT_4) -#define CONTEXT_BIT5(field) CONTEXT_FIELD(field, TYPE_BIT_5) -#define CONTEXT_FLOAT(field) CONTEXT_FIELD(field, TYPE_FLOAT) -#define CONTEXT_FLOAT2(field) CONTEXT_FIELD(field, TYPE_FLOAT_2) -#define CONTEXT_FLOAT3(field) CONTEXT_FIELD(field, TYPE_FLOAT_3) -#define CONTEXT_FLOAT4(field) CONTEXT_FIELD(field, TYPE_FLOAT_4) -#define CONTEXT_MATRIX(field) CONTEXT_FIELD(field, TYPE_MATRIX) -#define CONTEXT_MATRIX_T(field) CONTEXT_FIELD(field, TYPE_MATRIX_T) - -#define ARRAY_INT(field) ARRAY_FIELD(field, TYPE_INT) -#define ARRAY_ENUM(field) ARRAY_FIELD(field, TYPE_ENUM) -#define ARRAY_BOOL(field) ARRAY_FIELD(field, TYPE_BOOLEAN) - -#define EXT(f) \ - offsetof(struct gl_extensions, f) - -#define EXTRA_EXT(e) \ - static const int extra_##e[] = { \ - EXT(e), EXTRA_END \ - } - -#define EXTRA_EXT2(e1, e2) \ - static const int extra_##e1##_##e2[] = { \ - EXT(e1), EXT(e2), EXTRA_END \ - } - -/* The 'extra' mechanism is a way to specify extra checks (such as - * extensions or specific gl versions) or actions (flush current, new - * buffers) that we need to do before looking up an enum. We need to - * declare them all up front so we can refer to them in the value_desc - * structs below. */ - -static const int extra_new_buffers[] = { - EXTRA_NEW_BUFFERS, - EXTRA_END -}; - -static const int extra_valid_draw_buffer[] = { - EXTRA_VALID_DRAW_BUFFER, - EXTRA_END -}; - -static const int extra_valid_texture_unit[] = { - EXTRA_VALID_TEXTURE_UNIT, - EXTRA_END -}; - -static const int extra_flush_current_valid_texture_unit[] = { - EXTRA_FLUSH_CURRENT, - EXTRA_VALID_TEXTURE_UNIT, - EXTRA_END -}; - -static const int extra_flush_current[] = { - EXTRA_FLUSH_CURRENT, - EXTRA_END -}; - -static const int extra_new_buffers_OES_read_format[] = { - EXTRA_NEW_BUFFERS, - EXT(OES_read_format), - EXTRA_END -}; - -static const int extra_EXT_secondary_color_flush_current[] = { - EXT(EXT_secondary_color), - EXTRA_FLUSH_CURRENT, - EXTRA_END -}; - -static const int extra_EXT_fog_coord_flush_current[] = { - EXT(EXT_fog_coord), - EXTRA_FLUSH_CURRENT, - EXTRA_END -}; - -static const int extra_EXT_texture_integer[] = { - EXT(EXT_texture_integer), - EXTRA_END -}; - -static const int extra_EXT_gpu_shader4[] = { - EXT(EXT_gpu_shader4), - EXTRA_END -}; - - -EXTRA_EXT(ARB_ES2_compatibility); -EXTRA_EXT(ARB_multitexture); -EXTRA_EXT(ARB_texture_cube_map); -EXTRA_EXT(MESA_texture_array); -EXTRA_EXT2(EXT_secondary_color, ARB_vertex_program); -EXTRA_EXT(EXT_secondary_color); -EXTRA_EXT(EXT_fog_coord); -EXTRA_EXT(EXT_texture_lod_bias); -EXTRA_EXT(EXT_texture_filter_anisotropic); -EXTRA_EXT(IBM_rasterpos_clip); -EXTRA_EXT(NV_point_sprite); -EXTRA_EXT(SGIS_generate_mipmap); -EXTRA_EXT(NV_vertex_program); -EXTRA_EXT(NV_fragment_program); -EXTRA_EXT(NV_texture_rectangle); -EXTRA_EXT(EXT_stencil_two_side); -EXTRA_EXT(NV_light_max_exponent); -EXTRA_EXT(SGI_texture_color_table); -EXTRA_EXT(EXT_depth_bounds_test); -EXTRA_EXT(ARB_depth_clamp); -EXTRA_EXT(ATI_fragment_shader); -EXTRA_EXT(EXT_framebuffer_blit); -EXTRA_EXT(ARB_shader_objects); -EXTRA_EXT(EXT_provoking_vertex); -EXTRA_EXT(ARB_fragment_shader); -EXTRA_EXT(ARB_fragment_program); -EXTRA_EXT2(ARB_framebuffer_object, EXT_framebuffer_multisample); -EXTRA_EXT(EXT_framebuffer_object); -EXTRA_EXT(APPLE_vertex_array_object); -EXTRA_EXT(ARB_seamless_cube_map); -EXTRA_EXT(EXT_compiled_vertex_array); -EXTRA_EXT(ARB_sync); -EXTRA_EXT(ARB_vertex_shader); -EXTRA_EXT(EXT_transform_feedback); -EXTRA_EXT(ARB_transform_feedback2); -EXTRA_EXT(EXT_pixel_buffer_object); -EXTRA_EXT(ARB_vertex_program); -EXTRA_EXT2(NV_point_sprite, ARB_point_sprite); -EXTRA_EXT2(ARB_fragment_program, NV_fragment_program); -EXTRA_EXT2(ARB_vertex_program, NV_vertex_program); -EXTRA_EXT2(ARB_vertex_program, ARB_fragment_program); -EXTRA_EXT(ARB_vertex_buffer_object); -EXTRA_EXT(ARB_geometry_shader4); -EXTRA_EXT(ARB_copy_buffer); -EXTRA_EXT(EXT_framebuffer_sRGB); - -static const int -extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program[] = { - EXT(ARB_vertex_program), - EXT(ARB_fragment_program), - EXT(NV_vertex_program), - EXTRA_END -}; - -static const int -extra_NV_vertex_program_ARB_vertex_program_ARB_fragment_program_NV_vertex_program[] = { - EXT(NV_vertex_program), - EXT(ARB_vertex_program), - EXT(ARB_fragment_program), - EXT(NV_vertex_program), - EXTRA_END -}; - -static const int -extra_NV_primitive_restart[] = { - EXT(NV_primitive_restart), - EXTRA_END -}; - -static const int extra_version_30[] = { EXTRA_VERSION_30, EXTRA_END }; -static const int extra_version_31[] = { EXTRA_VERSION_31, EXTRA_END }; -static const int extra_version_32[] = { EXTRA_VERSION_32, EXTRA_END }; - -static const int -extra_ARB_vertex_program_version_es2[] = { - EXT(ARB_vertex_program), - EXTRA_VERSION_ES2, - EXTRA_END -}; - -#define API_OPENGL_BIT (1 << API_OPENGL) -#define API_OPENGLES_BIT (1 << API_OPENGLES) -#define API_OPENGLES2_BIT (1 << API_OPENGLES2) - -/* This is the big table describing all the enums we accept in - * glGet*v(). The table is partitioned into six parts: enums - * understood by all GL APIs (OpenGL, GLES and GLES2), enums shared - * between OpenGL and GLES, enums exclusive to GLES, etc for the - * remaining combinations. When we add the enums to the hash table in - * _mesa_init_get_hash(), we only add the enums for the API we're - * instantiating and the different sections are guarded by #if - * FEATURE_GL etc to make sure we only compile in the enums we may - * need. */ - -static const struct value_desc values[] = { - /* Enums shared between OpenGL, GLES1 and GLES2 */ - { 0, 0, TYPE_API_MASK, - API_OPENGL_BIT | API_OPENGLES_BIT | API_OPENGLES2_BIT, NO_EXTRA}, - { GL_ALPHA_BITS, BUFFER_INT(Visual.alphaBits), extra_new_buffers }, - { GL_BLEND, CONTEXT_BIT0(Color.BlendEnabled), NO_EXTRA }, - { GL_BLEND_SRC, CONTEXT_ENUM(Color.Blend[0].SrcRGB), NO_EXTRA }, - { GL_BLUE_BITS, BUFFER_INT(Visual.blueBits), extra_new_buffers }, - { GL_COLOR_CLEAR_VALUE, CONTEXT_FIELD(Color.ClearColor[0], TYPE_FLOATN_4), NO_EXTRA }, - { GL_COLOR_WRITEMASK, LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA }, - { GL_CULL_FACE, CONTEXT_BOOL(Polygon.CullFlag), NO_EXTRA }, - { GL_CULL_FACE_MODE, CONTEXT_ENUM(Polygon.CullFaceMode), NO_EXTRA }, - { GL_DEPTH_BITS, BUFFER_INT(Visual.depthBits), NO_EXTRA }, - { GL_DEPTH_CLEAR_VALUE, CONTEXT_FIELD(Depth.Clear, TYPE_DOUBLEN), NO_EXTRA }, - { GL_DEPTH_FUNC, CONTEXT_ENUM(Depth.Func), NO_EXTRA }, - { GL_DEPTH_RANGE, CONTEXT_FIELD(Viewport.Near, TYPE_FLOATN_2), NO_EXTRA }, - { GL_DEPTH_TEST, CONTEXT_BOOL(Depth.Test), NO_EXTRA }, - { GL_DEPTH_WRITEMASK, CONTEXT_BOOL(Depth.Mask), NO_EXTRA }, - { GL_DITHER, CONTEXT_BOOL(Color.DitherFlag), NO_EXTRA }, - { GL_FRONT_FACE, CONTEXT_ENUM(Polygon.FrontFace), NO_EXTRA }, - { GL_GREEN_BITS, BUFFER_INT(Visual.greenBits), extra_new_buffers }, - { GL_LINE_WIDTH, CONTEXT_FLOAT(Line.Width), NO_EXTRA }, - { GL_ALIASED_LINE_WIDTH_RANGE, CONTEXT_FLOAT2(Const.MinLineWidth), NO_EXTRA }, - { GL_MAX_ELEMENTS_VERTICES, CONTEXT_INT(Const.MaxArrayLockSize), NO_EXTRA }, - { GL_MAX_ELEMENTS_INDICES, CONTEXT_INT(Const.MaxArrayLockSize), NO_EXTRA }, - { GL_MAX_TEXTURE_SIZE, LOC_CUSTOM, TYPE_INT, - offsetof(struct gl_context, Const.MaxTextureLevels), NO_EXTRA }, - { GL_MAX_VIEWPORT_DIMS, CONTEXT_INT2(Const.MaxViewportWidth), NO_EXTRA }, - { GL_PACK_ALIGNMENT, CONTEXT_INT(Pack.Alignment), NO_EXTRA }, - { GL_ALIASED_POINT_SIZE_RANGE, CONTEXT_FLOAT2(Const.MinPointSize), NO_EXTRA }, - { GL_POLYGON_OFFSET_FACTOR, CONTEXT_FLOAT(Polygon.OffsetFactor ), NO_EXTRA }, - { GL_POLYGON_OFFSET_UNITS, CONTEXT_FLOAT(Polygon.OffsetUnits ), NO_EXTRA }, - { GL_POLYGON_OFFSET_FILL, CONTEXT_BOOL(Polygon.OffsetFill), NO_EXTRA }, - { GL_RED_BITS, BUFFER_INT(Visual.redBits), extra_new_buffers }, - { GL_SCISSOR_BOX, LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA }, - { GL_SCISSOR_TEST, CONTEXT_BOOL(Scissor.Enabled), NO_EXTRA }, - { GL_STENCIL_BITS, BUFFER_INT(Visual.stencilBits), NO_EXTRA }, - { GL_STENCIL_CLEAR_VALUE, CONTEXT_INT(Stencil.Clear), NO_EXTRA }, - { GL_STENCIL_FAIL, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, - { GL_STENCIL_FUNC, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, - { GL_STENCIL_PASS_DEPTH_FAIL, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, - { GL_STENCIL_PASS_DEPTH_PASS, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, - { GL_STENCIL_REF, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA }, - { GL_STENCIL_TEST, CONTEXT_BOOL(Stencil.Enabled), NO_EXTRA }, - { GL_STENCIL_VALUE_MASK, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA }, - { GL_STENCIL_WRITEMASK, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA }, - { GL_SUBPIXEL_BITS, CONTEXT_INT(Const.SubPixelBits), NO_EXTRA }, - { GL_TEXTURE_BINDING_2D, LOC_CUSTOM, TYPE_INT, TEXTURE_2D_INDEX, NO_EXTRA }, - { GL_UNPACK_ALIGNMENT, CONTEXT_INT(Unpack.Alignment), NO_EXTRA }, - { GL_VIEWPORT, LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA }, - - /* GL_ARB_multitexture */ - { GL_ACTIVE_TEXTURE_ARB, - LOC_CUSTOM, TYPE_INT, 0, extra_ARB_multitexture }, - - /* Note that all the OES_* extensions require that the Mesa "struct - * gl_extensions" include a member with the name of the extension. - * That structure does not yet include OES extensions (and we're - * not sure whether it will). If it does, all the OES_* - * extensions below should mark the dependency. */ - - /* GL_ARB_texture_cube_map */ - { GL_TEXTURE_BINDING_CUBE_MAP_ARB, LOC_CUSTOM, TYPE_INT, - TEXTURE_CUBE_INDEX, extra_ARB_texture_cube_map }, - { GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, LOC_CUSTOM, TYPE_INT, - offsetof(struct gl_context, Const.MaxCubeTextureLevels), - extra_ARB_texture_cube_map }, /* XXX: OES_texture_cube_map */ - - /* XXX: OES_blend_subtract */ - { GL_BLEND_SRC_RGB_EXT, CONTEXT_ENUM(Color.Blend[0].SrcRGB), NO_EXTRA }, - { GL_BLEND_DST_RGB_EXT, CONTEXT_ENUM(Color.Blend[0].DstRGB), NO_EXTRA }, - { GL_BLEND_SRC_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].SrcA), NO_EXTRA }, - { GL_BLEND_DST_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].DstA), NO_EXTRA }, - - /* GL_BLEND_EQUATION_RGB, which is what we're really after, is - * defined identically to GL_BLEND_EQUATION. */ - { GL_BLEND_EQUATION, CONTEXT_ENUM(Color.Blend[0].EquationRGB), NO_EXTRA }, - { GL_BLEND_EQUATION_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].EquationA), NO_EXTRA }, - - /* GL_ARB_texture_compression */ - { GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, - { GL_COMPRESSED_TEXTURE_FORMATS_ARB, LOC_CUSTOM, TYPE_INT_N, 0, NO_EXTRA }, - - /* GL_ARB_multisample */ - { GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, - CONTEXT_BOOL(Multisample.SampleAlphaToCoverage), NO_EXTRA }, - { GL_SAMPLE_COVERAGE_ARB, CONTEXT_BOOL(Multisample.SampleCoverage), NO_EXTRA }, - { GL_SAMPLE_COVERAGE_VALUE_ARB, - CONTEXT_FLOAT(Multisample.SampleCoverageValue), NO_EXTRA }, - { GL_SAMPLE_COVERAGE_INVERT_ARB, - CONTEXT_BOOL(Multisample.SampleCoverageInvert), NO_EXTRA }, - { GL_SAMPLE_BUFFERS_ARB, BUFFER_INT(Visual.sampleBuffers), NO_EXTRA }, - { GL_SAMPLES_ARB, BUFFER_INT(Visual.samples), NO_EXTRA }, - - /* GL_SGIS_generate_mipmap */ - { GL_GENERATE_MIPMAP_HINT_SGIS, CONTEXT_ENUM(Hint.GenerateMipmap), - extra_SGIS_generate_mipmap }, - - /* GL_ARB_vertex_buffer_object */ - { GL_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, - - /* GL_ARB_vertex_buffer_object */ - /* GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB - not supported */ - { GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, 0, - extra_ARB_vertex_buffer_object }, - - /* GL_ARB_copy_buffer */ - { GL_COPY_READ_BUFFER, LOC_CUSTOM, TYPE_INT, 0, extra_ARB_copy_buffer }, - { GL_COPY_WRITE_BUFFER, LOC_CUSTOM, TYPE_INT, 0, extra_ARB_copy_buffer }, - - /* GL_OES_read_format */ - { GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, LOC_CUSTOM, TYPE_INT, 0, - extra_new_buffers_OES_read_format }, - { GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, LOC_CUSTOM, TYPE_INT, 0, - extra_new_buffers_OES_read_format }, - - /* GL_EXT_framebuffer_object */ - { GL_FRAMEBUFFER_BINDING_EXT, BUFFER_INT(Name), - extra_EXT_framebuffer_object }, - { GL_RENDERBUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0, - extra_EXT_framebuffer_object }, - { GL_MAX_RENDERBUFFER_SIZE_EXT, CONTEXT_INT(Const.MaxRenderbufferSize), - extra_EXT_framebuffer_object }, - - /* This entry isn't spec'ed for GLES 2, but is needed for Mesa's - * GLSL: */ - { GL_MAX_CLIP_PLANES, CONTEXT_INT(Const.MaxClipPlanes), NO_EXTRA }, - -#if FEATURE_GL || FEATURE_ES1 - /* Enums in OpenGL and GLES1 */ - { 0, 0, TYPE_API_MASK, API_OPENGL_BIT | API_OPENGLES_BIT, NO_EXTRA }, - { GL_LIGHT0, CONTEXT_BOOL(Light.Light[0].Enabled), NO_EXTRA }, - { GL_LIGHT1, CONTEXT_BOOL(Light.Light[1].Enabled), NO_EXTRA }, - { GL_LIGHT2, CONTEXT_BOOL(Light.Light[2].Enabled), NO_EXTRA }, - { GL_LIGHT3, CONTEXT_BOOL(Light.Light[3].Enabled), NO_EXTRA }, - { GL_LIGHT4, CONTEXT_BOOL(Light.Light[4].Enabled), NO_EXTRA }, - { GL_LIGHT5, CONTEXT_BOOL(Light.Light[5].Enabled), NO_EXTRA }, - { GL_LIGHT6, CONTEXT_BOOL(Light.Light[6].Enabled), NO_EXTRA }, - { GL_LIGHT7, CONTEXT_BOOL(Light.Light[7].Enabled), NO_EXTRA }, - { GL_LIGHTING, CONTEXT_BOOL(Light.Enabled), NO_EXTRA }, - { GL_LIGHT_MODEL_AMBIENT, - CONTEXT_FIELD(Light.Model.Ambient[0], TYPE_FLOATN_4), NO_EXTRA }, - { GL_LIGHT_MODEL_TWO_SIDE, CONTEXT_BOOL(Light.Model.TwoSide), NO_EXTRA }, - { GL_ALPHA_TEST, CONTEXT_BOOL(Color.AlphaEnabled), NO_EXTRA }, - { GL_ALPHA_TEST_FUNC, CONTEXT_ENUM(Color.AlphaFunc), NO_EXTRA }, - { GL_ALPHA_TEST_REF, CONTEXT_FIELD(Color.AlphaRef, TYPE_FLOATN), NO_EXTRA }, - { GL_BLEND_DST, CONTEXT_ENUM(Color.Blend[0].DstRGB), NO_EXTRA }, - { GL_CLIP_PLANE0, CONTEXT_BIT0(Transform.ClipPlanesEnabled), NO_EXTRA }, - { GL_CLIP_PLANE1, CONTEXT_BIT1(Transform.ClipPlanesEnabled), NO_EXTRA }, - { GL_CLIP_PLANE2, CONTEXT_BIT2(Transform.ClipPlanesEnabled), NO_EXTRA }, - { GL_CLIP_PLANE3, CONTEXT_BIT3(Transform.ClipPlanesEnabled), NO_EXTRA }, - { GL_CLIP_PLANE4, CONTEXT_BIT4(Transform.ClipPlanesEnabled), NO_EXTRA }, - { GL_CLIP_PLANE5, CONTEXT_BIT5(Transform.ClipPlanesEnabled), NO_EXTRA }, - { GL_COLOR_MATERIAL, CONTEXT_BOOL(Light.ColorMaterialEnabled), NO_EXTRA }, - { GL_CURRENT_COLOR, - CONTEXT_FIELD(Current.Attrib[VERT_ATTRIB_COLOR0][0], TYPE_FLOATN_4), - extra_flush_current }, - { GL_CURRENT_NORMAL, - CONTEXT_FIELD(Current.Attrib[VERT_ATTRIB_NORMAL][0], TYPE_FLOATN_3), - extra_flush_current }, - { GL_CURRENT_TEXTURE_COORDS, LOC_CUSTOM, TYPE_FLOAT_4, 0, - extra_flush_current_valid_texture_unit }, - { GL_DISTANCE_ATTENUATION_EXT, CONTEXT_FLOAT3(Point.Params[0]), NO_EXTRA }, - { GL_FOG, CONTEXT_BOOL(Fog.Enabled), NO_EXTRA }, - { GL_FOG_COLOR, CONTEXT_FIELD(Fog.Color[0], TYPE_FLOATN_4), NO_EXTRA }, - { GL_FOG_DENSITY, CONTEXT_FLOAT(Fog.Density), NO_EXTRA }, - { GL_FOG_END, CONTEXT_FLOAT(Fog.End), NO_EXTRA }, - { GL_FOG_HINT, CONTEXT_ENUM(Hint.Fog), NO_EXTRA }, - { GL_FOG_MODE, CONTEXT_ENUM(Fog.Mode), NO_EXTRA }, - { GL_FOG_START, CONTEXT_FLOAT(Fog.Start), NO_EXTRA }, - { GL_LINE_SMOOTH, CONTEXT_BOOL(Line.SmoothFlag), NO_EXTRA }, - { GL_LINE_SMOOTH_HINT, CONTEXT_ENUM(Hint.LineSmooth), NO_EXTRA }, - { GL_LINE_WIDTH_RANGE, CONTEXT_FLOAT2(Const.MinLineWidthAA), NO_EXTRA }, - { GL_COLOR_LOGIC_OP, CONTEXT_BOOL(Color.ColorLogicOpEnabled), NO_EXTRA }, - { GL_LOGIC_OP_MODE, CONTEXT_ENUM(Color.LogicOp), NO_EXTRA }, - { GL_MATRIX_MODE, CONTEXT_ENUM(Transform.MatrixMode), NO_EXTRA }, - { GL_MAX_MODELVIEW_STACK_DEPTH, CONST(MAX_MODELVIEW_STACK_DEPTH), NO_EXTRA }, - { GL_MAX_PROJECTION_STACK_DEPTH, CONST(MAX_PROJECTION_STACK_DEPTH), NO_EXTRA }, - { GL_MAX_TEXTURE_STACK_DEPTH, CONST(MAX_TEXTURE_STACK_DEPTH), NO_EXTRA }, - { GL_MODELVIEW_MATRIX, CONTEXT_MATRIX(ModelviewMatrixStack.Top), NO_EXTRA }, - { GL_MODELVIEW_STACK_DEPTH, LOC_CUSTOM, TYPE_INT, - offsetof(struct gl_context, ModelviewMatrixStack.Depth), NO_EXTRA }, - { GL_NORMALIZE, CONTEXT_BOOL(Transform.Normalize), NO_EXTRA }, - { GL_PACK_SKIP_IMAGES_EXT, CONTEXT_INT(Pack.SkipImages), NO_EXTRA }, - { GL_PERSPECTIVE_CORRECTION_HINT, CONTEXT_ENUM(Hint.PerspectiveCorrection), NO_EXTRA }, - { GL_POINT_SIZE, CONTEXT_FLOAT(Point.Size), NO_EXTRA }, - { GL_POINT_SIZE_RANGE, CONTEXT_FLOAT2(Const.MinPointSizeAA), NO_EXTRA }, - { GL_POINT_SMOOTH, CONTEXT_BOOL(Point.SmoothFlag), NO_EXTRA }, - { GL_POINT_SMOOTH_HINT, CONTEXT_ENUM(Hint.PointSmooth), NO_EXTRA }, - { GL_POINT_SIZE_MIN_EXT, CONTEXT_FLOAT(Point.MinSize), NO_EXTRA }, - { GL_POINT_SIZE_MAX_EXT, CONTEXT_FLOAT(Point.MaxSize), NO_EXTRA }, - { GL_POINT_FADE_THRESHOLD_SIZE_EXT, CONTEXT_FLOAT(Point.Threshold), NO_EXTRA }, - { GL_PROJECTION_MATRIX, CONTEXT_MATRIX(ProjectionMatrixStack.Top), NO_EXTRA }, - { GL_PROJECTION_STACK_DEPTH, LOC_CUSTOM, TYPE_INT, - offsetof(struct gl_context, ProjectionMatrixStack.Depth), NO_EXTRA }, - { GL_RESCALE_NORMAL, CONTEXT_BOOL(Transform.RescaleNormals), NO_EXTRA }, - { GL_SHADE_MODEL, CONTEXT_ENUM(Light.ShadeModel), NO_EXTRA }, - { GL_TEXTURE_2D, LOC_CUSTOM, TYPE_BOOLEAN, 0, NO_EXTRA }, - { GL_TEXTURE_MATRIX, LOC_CUSTOM, TYPE_MATRIX, 0, extra_valid_texture_unit }, - { GL_TEXTURE_STACK_DEPTH, LOC_CUSTOM, TYPE_INT, 0, - extra_valid_texture_unit }, - - { GL_VERTEX_ARRAY, ARRAY_BOOL(Vertex.Enabled), NO_EXTRA }, - { GL_VERTEX_ARRAY_SIZE, ARRAY_INT(Vertex.Size), NO_EXTRA }, - { GL_VERTEX_ARRAY_TYPE, ARRAY_ENUM(Vertex.Type), NO_EXTRA }, - { GL_VERTEX_ARRAY_STRIDE, ARRAY_INT(Vertex.Stride), NO_EXTRA }, - { GL_NORMAL_ARRAY, ARRAY_ENUM(Normal.Enabled), NO_EXTRA }, - { GL_NORMAL_ARRAY_TYPE, ARRAY_ENUM(Normal.Type), NO_EXTRA }, - { GL_NORMAL_ARRAY_STRIDE, ARRAY_INT(Normal.Stride), NO_EXTRA }, - { GL_COLOR_ARRAY, ARRAY_BOOL(Color.Enabled), NO_EXTRA }, - { GL_COLOR_ARRAY_SIZE, ARRAY_INT(Color.Size), NO_EXTRA }, - { GL_COLOR_ARRAY_TYPE, ARRAY_ENUM(Color.Type), NO_EXTRA }, - { GL_COLOR_ARRAY_STRIDE, ARRAY_INT(Color.Stride), NO_EXTRA }, - { GL_TEXTURE_COORD_ARRAY, - LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Enabled), NO_EXTRA }, - { GL_TEXTURE_COORD_ARRAY_SIZE, - LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Size), NO_EXTRA }, - { GL_TEXTURE_COORD_ARRAY_TYPE, - LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Type), NO_EXTRA }, - { GL_TEXTURE_COORD_ARRAY_STRIDE, - LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Stride), NO_EXTRA }, - - /* GL_ARB_ES2_compatibility */ - { GL_SHADER_COMPILER, CONST(1), extra_ARB_ES2_compatibility }, - { GL_MAX_VARYING_VECTORS, CONTEXT_INT(Const.MaxVarying), - extra_ARB_ES2_compatibility }, - { GL_MAX_VERTEX_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0, - extra_ARB_ES2_compatibility }, - { GL_MAX_FRAGMENT_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0, - extra_ARB_ES2_compatibility }, - - /* GL_ARB_multitexture */ - { GL_MAX_TEXTURE_UNITS_ARB, - CONTEXT_INT(Const.MaxTextureUnits), extra_ARB_multitexture }, - { GL_CLIENT_ACTIVE_TEXTURE_ARB, - LOC_CUSTOM, TYPE_INT, 0, extra_ARB_multitexture }, - - /* GL_ARB_texture_cube_map */ - { GL_TEXTURE_CUBE_MAP_ARB, LOC_CUSTOM, TYPE_BOOLEAN, 0, NO_EXTRA }, - /* S, T, and R are always set at the same time */ - { GL_TEXTURE_GEN_STR_OES, LOC_TEXUNIT, TYPE_BIT_0, - offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, - - /* GL_ARB_multisample */ - { GL_MULTISAMPLE_ARB, CONTEXT_BOOL(Multisample.Enabled), NO_EXTRA }, - { GL_SAMPLE_ALPHA_TO_ONE_ARB, CONTEXT_BOOL(Multisample.SampleAlphaToOne), NO_EXTRA }, - - /* GL_ARB_vertex_buffer_object */ - { GL_VERTEX_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, - offsetof(struct gl_array_object, Vertex.BufferObj), NO_EXTRA }, - { GL_NORMAL_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, - offsetof(struct gl_array_object, Normal.BufferObj), NO_EXTRA }, - { GL_COLOR_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, - offsetof(struct gl_array_object, Color.BufferObj), NO_EXTRA }, - { GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA }, - - /* GL_OES_point_sprite */ - { GL_POINT_SPRITE_NV, - CONTEXT_BOOL(Point.PointSprite), - extra_NV_point_sprite_ARB_point_sprite }, - - /* GL_ARB_fragment_shader */ - { GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, - CONTEXT_INT(Const.FragmentProgram.MaxUniformComponents), - extra_ARB_fragment_shader }, - - /* GL_ARB_vertex_shader */ - { GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, - CONTEXT_INT(Const.VertexProgram.MaxUniformComponents), - extra_ARB_vertex_shader }, - { GL_MAX_VARYING_FLOATS_ARB, LOC_CUSTOM, TYPE_INT, 0, - extra_ARB_vertex_shader }, - - /* GL_EXT_texture_lod_bias */ - { GL_MAX_TEXTURE_LOD_BIAS_EXT, CONTEXT_FLOAT(Const.MaxTextureLodBias), - extra_EXT_texture_lod_bias }, - - /* GL_EXT_texture_filter_anisotropic */ - { GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, - CONTEXT_FLOAT(Const.MaxTextureMaxAnisotropy), - extra_EXT_texture_filter_anisotropic }, -#endif /* FEATURE_GL || FEATURE_ES1 */ - -#if FEATURE_ES1 - { 0, 0, TYPE_API_MASK, API_OPENGLES_BIT }, - /* XXX: OES_matrix_get */ - { GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES }, - { GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES }, - { GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES }, - - /* OES_point_size_array */ - { GL_POINT_SIZE_ARRAY_OES, ARRAY_FIELD(PointSize.Enabled, TYPE_BOOLEAN) }, - { GL_POINT_SIZE_ARRAY_TYPE_OES, ARRAY_FIELD(PointSize.Type, TYPE_ENUM) }, - { GL_POINT_SIZE_ARRAY_STRIDE_OES, ARRAY_FIELD(PointSize.Stride, TYPE_INT) }, - { GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES, LOC_CUSTOM, TYPE_INT, 0 }, -#endif /* FEATURE_ES1 */ - -#if FEATURE_GL || FEATURE_ES2 - { 0, 0, TYPE_API_MASK, API_OPENGL_BIT | API_OPENGLES2_BIT, NO_EXTRA }, - /* This entry isn't spec'ed for GLES 2, but is needed for Mesa's GLSL: */ - { GL_MAX_LIGHTS, CONTEXT_INT(Const.MaxLights), NO_EXTRA }, - { GL_MAX_TEXTURE_COORDS_ARB, /* == GL_MAX_TEXTURE_COORDS_NV */ - CONTEXT_INT(Const.MaxTextureCoordUnits), - extra_ARB_fragment_program_NV_fragment_program }, - - /* GL_ARB_draw_buffers */ - { GL_MAX_DRAW_BUFFERS_ARB, CONTEXT_INT(Const.MaxDrawBuffers), NO_EXTRA }, - - { GL_BLEND_COLOR_EXT, CONTEXT_FIELD(Color.BlendColor[0], TYPE_FLOATN_4), NO_EXTRA }, - /* GL_ARB_fragment_program */ - { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, /* == GL_MAX_TEXTURE_IMAGE_UNITS_NV */ - CONTEXT_INT(Const.MaxTextureImageUnits), - extra_ARB_fragment_program_NV_fragment_program }, - { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, - CONTEXT_INT(Const.MaxVertexTextureImageUnits), extra_ARB_vertex_shader }, - { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, - CONTEXT_INT(Const.MaxCombinedTextureImageUnits), - extra_ARB_vertex_shader }, - - /* GL_ARB_shader_objects - * Actually, this token isn't part of GL_ARB_shader_objects, but is - * close enough for now. */ - { GL_CURRENT_PROGRAM, LOC_CUSTOM, TYPE_INT, 0, extra_ARB_shader_objects }, - - /* OpenGL 2.0 */ - { GL_STENCIL_BACK_FUNC, CONTEXT_ENUM(Stencil.Function[1]), NO_EXTRA }, - { GL_STENCIL_BACK_VALUE_MASK, CONTEXT_INT(Stencil.ValueMask[1]), NO_EXTRA }, - { GL_STENCIL_BACK_WRITEMASK, CONTEXT_INT(Stencil.WriteMask[1]), NO_EXTRA }, - { GL_STENCIL_BACK_REF, CONTEXT_INT(Stencil.Ref[1]), NO_EXTRA }, - { GL_STENCIL_BACK_FAIL, CONTEXT_ENUM(Stencil.FailFunc[1]), NO_EXTRA }, - { GL_STENCIL_BACK_PASS_DEPTH_FAIL, CONTEXT_ENUM(Stencil.ZFailFunc[1]), NO_EXTRA }, - { GL_STENCIL_BACK_PASS_DEPTH_PASS, CONTEXT_ENUM(Stencil.ZPassFunc[1]), NO_EXTRA }, - - { GL_MAX_VERTEX_ATTRIBS_ARB, - CONTEXT_INT(Const.VertexProgram.MaxAttribs), - extra_ARB_vertex_program_version_es2 }, - - /* OES_texture_3D */ - { GL_TEXTURE_BINDING_3D, LOC_CUSTOM, TYPE_INT, TEXTURE_3D_INDEX, NO_EXTRA }, - { GL_MAX_3D_TEXTURE_SIZE, LOC_CUSTOM, TYPE_INT, - offsetof(struct gl_context, Const.Max3DTextureLevels), NO_EXTRA }, - - /* GL_ARB_fragment_program/OES_standard_derivatives */ - { GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB, - CONTEXT_ENUM(Hint.FragmentShaderDerivative), extra_ARB_fragment_shader }, -#endif /* FEATURE_GL || FEATURE_ES2 */ - -#if FEATURE_ES2 - /* Enums unique to OpenGL ES 2.0 */ - { 0, 0, TYPE_API_MASK, API_OPENGLES2_BIT, NO_EXTRA }, - { GL_MAX_FRAGMENT_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, - { GL_MAX_VARYING_VECTORS, CONTEXT_INT(Const.MaxVarying), NO_EXTRA }, - { GL_MAX_VERTEX_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, - { GL_SHADER_COMPILER, CONST(1), NO_EXTRA }, - /* OES_get_program_binary */ - { GL_NUM_SHADER_BINARY_FORMATS, CONST(0), NO_EXTRA }, - { GL_SHADER_BINARY_FORMATS, CONST(0), NO_EXTRA }, -#endif /* FEATURE_ES2 */ - -#if FEATURE_GL - /* Remaining enums are only in OpenGL */ - { 0, 0, TYPE_API_MASK, API_OPENGL_BIT, NO_EXTRA }, - { GL_ACCUM_RED_BITS, BUFFER_INT(Visual.accumRedBits), NO_EXTRA }, - { GL_ACCUM_GREEN_BITS, BUFFER_INT(Visual.accumGreenBits), NO_EXTRA }, - { GL_ACCUM_BLUE_BITS, BUFFER_INT(Visual.accumBlueBits), NO_EXTRA }, - { GL_ACCUM_ALPHA_BITS, BUFFER_INT(Visual.accumAlphaBits), NO_EXTRA }, - { GL_ACCUM_CLEAR_VALUE, CONTEXT_FIELD(Accum.ClearColor[0], TYPE_FLOATN_4), NO_EXTRA }, - { GL_ALPHA_BIAS, CONTEXT_FLOAT(Pixel.AlphaBias), NO_EXTRA }, - { GL_ALPHA_SCALE, CONTEXT_FLOAT(Pixel.AlphaScale), NO_EXTRA }, - { GL_ATTRIB_STACK_DEPTH, CONTEXT_INT(AttribStackDepth), NO_EXTRA }, - { GL_AUTO_NORMAL, CONTEXT_BOOL(Eval.AutoNormal), NO_EXTRA }, - { GL_AUX_BUFFERS, BUFFER_INT(Visual.numAuxBuffers), NO_EXTRA }, - { GL_BLUE_BIAS, CONTEXT_FLOAT(Pixel.BlueBias), NO_EXTRA }, - { GL_BLUE_SCALE, CONTEXT_FLOAT(Pixel.BlueScale), NO_EXTRA }, - { GL_CLIENT_ATTRIB_STACK_DEPTH, CONTEXT_INT(ClientAttribStackDepth), NO_EXTRA }, - { GL_COLOR_MATERIAL_FACE, CONTEXT_ENUM(Light.ColorMaterialFace), NO_EXTRA }, - { GL_COLOR_MATERIAL_PARAMETER, CONTEXT_ENUM(Light.ColorMaterialMode), NO_EXTRA }, - { GL_CURRENT_INDEX, - CONTEXT_FLOAT(Current.Attrib[VERT_ATTRIB_COLOR_INDEX][0]), - extra_flush_current }, - { GL_CURRENT_RASTER_COLOR, - CONTEXT_FIELD(Current.RasterColor[0], TYPE_FLOATN_4), NO_EXTRA }, - { GL_CURRENT_RASTER_DISTANCE, CONTEXT_FLOAT(Current.RasterDistance), NO_EXTRA }, - { GL_CURRENT_RASTER_INDEX, CONST(1), NO_EXTRA }, - { GL_CURRENT_RASTER_POSITION, CONTEXT_FLOAT4(Current.RasterPos[0]), NO_EXTRA }, - { GL_CURRENT_RASTER_SECONDARY_COLOR, - CONTEXT_FIELD(Current.RasterSecondaryColor[0], TYPE_FLOATN_4), NO_EXTRA }, - { GL_CURRENT_RASTER_TEXTURE_COORDS, LOC_CUSTOM, TYPE_FLOAT_4, 0, - extra_valid_texture_unit }, - { GL_CURRENT_RASTER_POSITION_VALID, CONTEXT_BOOL(Current.RasterPosValid), NO_EXTRA }, - { GL_DEPTH_BIAS, CONTEXT_FLOAT(Pixel.DepthBias), NO_EXTRA }, - { GL_DEPTH_SCALE, CONTEXT_FLOAT(Pixel.DepthScale), NO_EXTRA }, - { GL_DOUBLEBUFFER, BUFFER_INT(Visual.doubleBufferMode), NO_EXTRA }, - { GL_DRAW_BUFFER, BUFFER_ENUM(ColorDrawBuffer[0]), NO_EXTRA }, - { GL_EDGE_FLAG, LOC_CUSTOM, TYPE_BOOLEAN, 0, NO_EXTRA }, - { GL_FEEDBACK_BUFFER_SIZE, CONTEXT_INT(Feedback.BufferSize), NO_EXTRA }, - { GL_FEEDBACK_BUFFER_TYPE, CONTEXT_ENUM(Feedback.Type), NO_EXTRA }, - { GL_FOG_INDEX, CONTEXT_FLOAT(Fog.Index), NO_EXTRA }, - { GL_GREEN_BIAS, CONTEXT_FLOAT(Pixel.GreenBias), NO_EXTRA }, - { GL_GREEN_SCALE, CONTEXT_FLOAT(Pixel.GreenScale), NO_EXTRA }, - { GL_INDEX_BITS, BUFFER_INT(Visual.indexBits), extra_new_buffers }, - { GL_INDEX_CLEAR_VALUE, CONTEXT_INT(Color.ClearIndex), NO_EXTRA }, - { GL_INDEX_MODE, CONST(0) , NO_EXTRA}, - { GL_INDEX_OFFSET, CONTEXT_INT(Pixel.IndexOffset), NO_EXTRA }, - { GL_INDEX_SHIFT, CONTEXT_INT(Pixel.IndexShift), NO_EXTRA }, - { GL_INDEX_WRITEMASK, CONTEXT_INT(Color.IndexMask), NO_EXTRA }, - { GL_LIGHT_MODEL_COLOR_CONTROL, CONTEXT_ENUM(Light.Model.ColorControl), NO_EXTRA }, - { GL_LIGHT_MODEL_LOCAL_VIEWER, CONTEXT_BOOL(Light.Model.LocalViewer), NO_EXTRA }, - { GL_LINE_STIPPLE, CONTEXT_BOOL(Line.StippleFlag), NO_EXTRA }, - { GL_LINE_STIPPLE_PATTERN, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, - { GL_LINE_STIPPLE_REPEAT, CONTEXT_INT(Line.StippleFactor), NO_EXTRA }, - { GL_LINE_WIDTH_GRANULARITY, CONTEXT_FLOAT(Const.LineWidthGranularity), NO_EXTRA }, - { GL_LIST_BASE, CONTEXT_INT(List.ListBase), NO_EXTRA }, - { GL_LIST_INDEX, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, - { GL_LIST_MODE, LOC_CUSTOM, TYPE_ENUM, 0, NO_EXTRA }, - { GL_INDEX_LOGIC_OP, CONTEXT_BOOL(Color.IndexLogicOpEnabled), NO_EXTRA }, - { GL_MAP1_COLOR_4, CONTEXT_BOOL(Eval.Map1Color4), NO_EXTRA }, - { GL_MAP1_GRID_DOMAIN, CONTEXT_FLOAT2(Eval.MapGrid1u1), NO_EXTRA }, - { GL_MAP1_GRID_SEGMENTS, CONTEXT_INT(Eval.MapGrid1un), NO_EXTRA }, - { GL_MAP1_INDEX, CONTEXT_BOOL(Eval.Map1Index), NO_EXTRA }, - { GL_MAP1_NORMAL, CONTEXT_BOOL(Eval.Map1Normal), NO_EXTRA }, - { GL_MAP1_TEXTURE_COORD_1, CONTEXT_BOOL(Eval.Map1TextureCoord1), NO_EXTRA }, - { GL_MAP1_TEXTURE_COORD_2, CONTEXT_BOOL(Eval.Map1TextureCoord2), NO_EXTRA }, - { GL_MAP1_TEXTURE_COORD_3, CONTEXT_BOOL(Eval.Map1TextureCoord3), NO_EXTRA }, - { GL_MAP1_TEXTURE_COORD_4, CONTEXT_BOOL(Eval.Map1TextureCoord4), NO_EXTRA }, - { GL_MAP1_VERTEX_3, CONTEXT_BOOL(Eval.Map1Vertex3), NO_EXTRA }, - { GL_MAP1_VERTEX_4, CONTEXT_BOOL(Eval.Map1Vertex4), NO_EXTRA }, - { GL_MAP2_COLOR_4, CONTEXT_BOOL(Eval.Map2Color4), NO_EXTRA }, - { GL_MAP2_GRID_DOMAIN, LOC_CUSTOM, TYPE_FLOAT_4, 0, NO_EXTRA }, - { GL_MAP2_GRID_SEGMENTS, CONTEXT_INT2(Eval.MapGrid2un), NO_EXTRA }, - { GL_MAP2_INDEX, CONTEXT_BOOL(Eval.Map2Index), NO_EXTRA }, - { GL_MAP2_NORMAL, CONTEXT_BOOL(Eval.Map2Normal), NO_EXTRA }, - { GL_MAP2_TEXTURE_COORD_1, CONTEXT_BOOL(Eval.Map2TextureCoord1), NO_EXTRA }, - { GL_MAP2_TEXTURE_COORD_2, CONTEXT_BOOL(Eval.Map2TextureCoord2), NO_EXTRA }, - { GL_MAP2_TEXTURE_COORD_3, CONTEXT_BOOL(Eval.Map2TextureCoord3), NO_EXTRA }, - { GL_MAP2_TEXTURE_COORD_4, CONTEXT_BOOL(Eval.Map2TextureCoord4), NO_EXTRA }, - { GL_MAP2_VERTEX_3, CONTEXT_BOOL(Eval.Map2Vertex3), NO_EXTRA }, - { GL_MAP2_VERTEX_4, CONTEXT_BOOL(Eval.Map2Vertex4), NO_EXTRA }, - { GL_MAP_COLOR, CONTEXT_BOOL(Pixel.MapColorFlag), NO_EXTRA }, - { GL_MAP_STENCIL, CONTEXT_BOOL(Pixel.MapStencilFlag), NO_EXTRA }, - { GL_MAX_ATTRIB_STACK_DEPTH, CONST(MAX_ATTRIB_STACK_DEPTH), NO_EXTRA }, - { GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, CONST(MAX_CLIENT_ATTRIB_STACK_DEPTH), NO_EXTRA }, - - { GL_MAX_EVAL_ORDER, CONST(MAX_EVAL_ORDER), NO_EXTRA }, - { GL_MAX_LIST_NESTING, CONST(MAX_LIST_NESTING), NO_EXTRA }, - { GL_MAX_NAME_STACK_DEPTH, CONST(MAX_NAME_STACK_DEPTH), NO_EXTRA }, - { GL_MAX_PIXEL_MAP_TABLE, CONST(MAX_PIXEL_MAP_TABLE), NO_EXTRA }, - { GL_NAME_STACK_DEPTH, CONTEXT_INT(Select.NameStackDepth), NO_EXTRA }, - { GL_PACK_LSB_FIRST, CONTEXT_BOOL(Pack.LsbFirst), NO_EXTRA }, - { GL_PACK_ROW_LENGTH, CONTEXT_INT(Pack.RowLength), NO_EXTRA }, - { GL_PACK_SKIP_PIXELS, CONTEXT_INT(Pack.SkipPixels), NO_EXTRA }, - { GL_PACK_SKIP_ROWS, CONTEXT_INT(Pack.SkipRows), NO_EXTRA }, - { GL_PACK_SWAP_BYTES, CONTEXT_BOOL(Pack.SwapBytes), NO_EXTRA }, - { GL_PACK_IMAGE_HEIGHT_EXT, CONTEXT_INT(Pack.ImageHeight), NO_EXTRA }, - { GL_PACK_INVERT_MESA, CONTEXT_BOOL(Pack.Invert), NO_EXTRA }, - { GL_PIXEL_MAP_A_TO_A_SIZE, CONTEXT_INT(PixelMaps.AtoA.Size), NO_EXTRA }, - { GL_PIXEL_MAP_B_TO_B_SIZE, CONTEXT_INT(PixelMaps.BtoB.Size), NO_EXTRA }, - { GL_PIXEL_MAP_G_TO_G_SIZE, CONTEXT_INT(PixelMaps.GtoG.Size), NO_EXTRA }, - { GL_PIXEL_MAP_I_TO_A_SIZE, CONTEXT_INT(PixelMaps.ItoA.Size), NO_EXTRA }, - { GL_PIXEL_MAP_I_TO_B_SIZE, CONTEXT_INT(PixelMaps.ItoB.Size), NO_EXTRA }, - { GL_PIXEL_MAP_I_TO_G_SIZE, CONTEXT_INT(PixelMaps.ItoG.Size), NO_EXTRA }, - { GL_PIXEL_MAP_I_TO_I_SIZE, CONTEXT_INT(PixelMaps.ItoI.Size), NO_EXTRA }, - { GL_PIXEL_MAP_I_TO_R_SIZE, CONTEXT_INT(PixelMaps.ItoR.Size), NO_EXTRA }, - { GL_PIXEL_MAP_R_TO_R_SIZE, CONTEXT_INT(PixelMaps.RtoR.Size), NO_EXTRA }, - { GL_PIXEL_MAP_S_TO_S_SIZE, CONTEXT_INT(PixelMaps.StoS.Size), NO_EXTRA }, - { GL_POINT_SIZE_GRANULARITY, CONTEXT_FLOAT(Const.PointSizeGranularity), NO_EXTRA }, - { GL_POLYGON_MODE, CONTEXT_ENUM2(Polygon.FrontMode), NO_EXTRA }, - { GL_POLYGON_OFFSET_BIAS_EXT, CONTEXT_FLOAT(Polygon.OffsetUnits), NO_EXTRA }, - { GL_POLYGON_OFFSET_POINT, CONTEXT_BOOL(Polygon.OffsetPoint), NO_EXTRA }, - { GL_POLYGON_OFFSET_LINE, CONTEXT_BOOL(Polygon.OffsetLine), NO_EXTRA }, - { GL_POLYGON_SMOOTH, CONTEXT_BOOL(Polygon.SmoothFlag), NO_EXTRA }, - { GL_POLYGON_SMOOTH_HINT, CONTEXT_ENUM(Hint.PolygonSmooth), NO_EXTRA }, - { GL_POLYGON_STIPPLE, CONTEXT_BOOL(Polygon.StippleFlag), NO_EXTRA }, - { GL_READ_BUFFER, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, - { GL_RED_BIAS, CONTEXT_FLOAT(Pixel.RedBias), NO_EXTRA }, - { GL_RED_SCALE, CONTEXT_FLOAT(Pixel.RedScale), NO_EXTRA }, - { GL_RENDER_MODE, CONTEXT_ENUM(RenderMode), NO_EXTRA }, - { GL_RGBA_MODE, CONST(1), NO_EXTRA }, - { GL_SELECTION_BUFFER_SIZE, CONTEXT_INT(Select.BufferSize), NO_EXTRA }, - { GL_SHARED_TEXTURE_PALETTE_EXT, CONTEXT_BOOL(Texture.SharedPalette), NO_EXTRA }, - - { GL_STEREO, BUFFER_INT(Visual.stereoMode), NO_EXTRA }, - - { GL_TEXTURE_1D, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA }, - { GL_TEXTURE_3D, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA }, - { GL_TEXTURE_1D_ARRAY_EXT, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA }, - { GL_TEXTURE_2D_ARRAY_EXT, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA }, - - { GL_TEXTURE_BINDING_1D, LOC_CUSTOM, TYPE_INT, TEXTURE_1D_INDEX, NO_EXTRA }, - { GL_TEXTURE_BINDING_1D_ARRAY, LOC_CUSTOM, TYPE_INT, - TEXTURE_1D_ARRAY_INDEX, extra_MESA_texture_array }, - { GL_TEXTURE_BINDING_2D_ARRAY, LOC_CUSTOM, TYPE_INT, - TEXTURE_1D_ARRAY_INDEX, extra_MESA_texture_array }, - { GL_MAX_ARRAY_TEXTURE_LAYERS_EXT, - CONTEXT_INT(Const.MaxArrayTextureLayers), extra_MESA_texture_array }, - - { GL_TEXTURE_GEN_S, LOC_TEXUNIT, TYPE_BIT_0, - offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, - { GL_TEXTURE_GEN_T, LOC_TEXUNIT, TYPE_BIT_1, - offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, - { GL_TEXTURE_GEN_R, LOC_TEXUNIT, TYPE_BIT_2, - offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, - { GL_TEXTURE_GEN_Q, LOC_TEXUNIT, TYPE_BIT_3, - offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, - { GL_UNPACK_LSB_FIRST, CONTEXT_BOOL(Unpack.LsbFirst), NO_EXTRA }, - { GL_UNPACK_ROW_LENGTH, CONTEXT_INT(Unpack.RowLength), NO_EXTRA }, - { GL_UNPACK_SKIP_PIXELS, CONTEXT_INT(Unpack.SkipPixels), NO_EXTRA }, - { GL_UNPACK_SKIP_ROWS, CONTEXT_INT(Unpack.SkipRows), NO_EXTRA }, - { GL_UNPACK_SWAP_BYTES, CONTEXT_BOOL(Unpack.SwapBytes), NO_EXTRA }, - { GL_UNPACK_SKIP_IMAGES_EXT, CONTEXT_INT(Unpack.SkipImages), NO_EXTRA }, - { GL_UNPACK_IMAGE_HEIGHT_EXT, CONTEXT_INT(Unpack.ImageHeight), NO_EXTRA }, - { GL_UNPACK_CLIENT_STORAGE_APPLE, CONTEXT_BOOL(Unpack.ClientStorage), NO_EXTRA }, - { GL_ZOOM_X, CONTEXT_FLOAT(Pixel.ZoomX), NO_EXTRA }, - { GL_ZOOM_Y, CONTEXT_FLOAT(Pixel.ZoomY), NO_EXTRA }, - - /* Vertex arrays */ - { GL_VERTEX_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, - { GL_NORMAL_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, - { GL_COLOR_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, - { GL_INDEX_ARRAY, ARRAY_BOOL(Index.Enabled), NO_EXTRA }, - { GL_INDEX_ARRAY_TYPE, ARRAY_ENUM(Index.Type), NO_EXTRA }, - { GL_INDEX_ARRAY_STRIDE, ARRAY_INT(Index.Stride), NO_EXTRA }, - { GL_INDEX_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, - { GL_TEXTURE_COORD_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, - { GL_EDGE_FLAG_ARRAY, ARRAY_BOOL(EdgeFlag.Enabled), NO_EXTRA }, - { GL_EDGE_FLAG_ARRAY_STRIDE, ARRAY_INT(EdgeFlag.Stride), NO_EXTRA }, - { GL_EDGE_FLAG_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, - - /* GL_ARB_texture_compression */ - { GL_TEXTURE_COMPRESSION_HINT_ARB, CONTEXT_INT(Hint.TextureCompression), NO_EXTRA }, - - /* GL_EXT_compiled_vertex_array */ - { GL_ARRAY_ELEMENT_LOCK_FIRST_EXT, CONTEXT_INT(Array.LockFirst), - extra_EXT_compiled_vertex_array }, - { GL_ARRAY_ELEMENT_LOCK_COUNT_EXT, CONTEXT_INT(Array.LockCount), - extra_EXT_compiled_vertex_array }, - - /* GL_ARB_transpose_matrix */ - { GL_TRANSPOSE_MODELVIEW_MATRIX_ARB, - CONTEXT_MATRIX_T(ModelviewMatrixStack), NO_EXTRA }, - { GL_TRANSPOSE_PROJECTION_MATRIX_ARB, - CONTEXT_MATRIX_T(ProjectionMatrixStack.Top), NO_EXTRA }, - { GL_TRANSPOSE_TEXTURE_MATRIX_ARB, CONTEXT_MATRIX_T(TextureMatrixStack), NO_EXTRA }, - - /* GL_SGI_texture_color_table */ - { GL_TEXTURE_COLOR_TABLE_SGI, LOC_TEXUNIT, TYPE_BOOLEAN, - offsetof(struct gl_texture_unit, ColorTableEnabled), - extra_SGI_texture_color_table }, - - /* GL_EXT_secondary_color */ - { GL_COLOR_SUM_EXT, CONTEXT_BOOL(Fog.ColorSumEnabled), - extra_EXT_secondary_color_ARB_vertex_program }, - { GL_CURRENT_SECONDARY_COLOR_EXT, - CONTEXT_FIELD(Current.Attrib[VERT_ATTRIB_COLOR1][0], TYPE_FLOATN_4), - extra_EXT_secondary_color_flush_current }, - { GL_SECONDARY_COLOR_ARRAY_EXT, ARRAY_BOOL(SecondaryColor.Enabled), - extra_EXT_secondary_color }, - { GL_SECONDARY_COLOR_ARRAY_TYPE_EXT, ARRAY_ENUM(SecondaryColor.Type), - extra_EXT_secondary_color }, - { GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT, ARRAY_INT(SecondaryColor.Stride), - extra_EXT_secondary_color }, - { GL_SECONDARY_COLOR_ARRAY_SIZE_EXT, ARRAY_INT(SecondaryColor.Size), - extra_EXT_secondary_color }, - - /* GL_EXT_fog_coord */ - { GL_CURRENT_FOG_COORDINATE_EXT, - CONTEXT_FLOAT(Current.Attrib[VERT_ATTRIB_FOG][0]), - extra_EXT_fog_coord_flush_current }, - { GL_FOG_COORDINATE_ARRAY_EXT, ARRAY_BOOL(FogCoord.Enabled), - extra_EXT_fog_coord }, - { GL_FOG_COORDINATE_ARRAY_TYPE_EXT, ARRAY_ENUM(FogCoord.Type), - extra_EXT_fog_coord }, - { GL_FOG_COORDINATE_ARRAY_STRIDE_EXT, ARRAY_INT(FogCoord.Stride), - extra_EXT_fog_coord }, - { GL_FOG_COORDINATE_SOURCE_EXT, CONTEXT_ENUM(Fog.FogCoordinateSource), - extra_EXT_fog_coord }, - - /* GL_IBM_rasterpos_clip */ - { GL_RASTER_POSITION_UNCLIPPED_IBM, - CONTEXT_BOOL(Transform.RasterPositionUnclipped), - extra_IBM_rasterpos_clip }, - - /* GL_NV_point_sprite */ - { GL_POINT_SPRITE_R_MODE_NV, - CONTEXT_ENUM(Point.SpriteRMode), extra_NV_point_sprite }, - { GL_POINT_SPRITE_COORD_ORIGIN, CONTEXT_ENUM(Point.SpriteOrigin), - extra_NV_point_sprite_ARB_point_sprite }, - - /* GL_NV_vertex_program */ - { GL_VERTEX_PROGRAM_BINDING_NV, LOC_CUSTOM, TYPE_INT, 0, - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY0_NV, ARRAY_BOOL(VertexAttrib[0].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY1_NV, ARRAY_BOOL(VertexAttrib[1].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY2_NV, ARRAY_BOOL(VertexAttrib[2].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY3_NV, ARRAY_BOOL(VertexAttrib[3].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY4_NV, ARRAY_BOOL(VertexAttrib[4].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY5_NV, ARRAY_BOOL(VertexAttrib[5].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY6_NV, ARRAY_BOOL(VertexAttrib[6].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY7_NV, ARRAY_BOOL(VertexAttrib[7].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY8_NV, ARRAY_BOOL(VertexAttrib[8].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY9_NV, ARRAY_BOOL(VertexAttrib[9].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY10_NV, ARRAY_BOOL(VertexAttrib[10].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY11_NV, ARRAY_BOOL(VertexAttrib[11].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY12_NV, ARRAY_BOOL(VertexAttrib[12].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY13_NV, ARRAY_BOOL(VertexAttrib[13].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY14_NV, ARRAY_BOOL(VertexAttrib[14].Enabled), - extra_NV_vertex_program }, - { GL_VERTEX_ATTRIB_ARRAY15_NV, ARRAY_BOOL(VertexAttrib[15].Enabled), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB0_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[0]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB1_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[1]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB2_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[2]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB3_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[3]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB4_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[4]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB5_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[5]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB6_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[6]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB7_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[7]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB8_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[8]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB9_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[9]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB10_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[10]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB11_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[11]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB12_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[12]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB13_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[13]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB14_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[14]), - extra_NV_vertex_program }, - { GL_MAP1_VERTEX_ATTRIB15_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[15]), - extra_NV_vertex_program }, - - /* GL_NV_fragment_program */ - { GL_FRAGMENT_PROGRAM_NV, CONTEXT_BOOL(FragmentProgram.Enabled), - extra_NV_fragment_program }, - { GL_FRAGMENT_PROGRAM_BINDING_NV, LOC_CUSTOM, TYPE_INT, 0, - extra_NV_fragment_program }, - { GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV, - CONST(MAX_NV_FRAGMENT_PROGRAM_PARAMS), - extra_NV_fragment_program }, - - /* GL_NV_texture_rectangle */ - { GL_TEXTURE_RECTANGLE_NV, - LOC_CUSTOM, TYPE_BOOLEAN, 0, extra_NV_texture_rectangle }, - { GL_TEXTURE_BINDING_RECTANGLE_NV, - LOC_CUSTOM, TYPE_INT, TEXTURE_RECT_INDEX, extra_NV_texture_rectangle }, - { GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, - CONTEXT_INT(Const.MaxTextureRectSize), extra_NV_texture_rectangle }, - - /* GL_EXT_stencil_two_side */ - { GL_STENCIL_TEST_TWO_SIDE_EXT, CONTEXT_BOOL(Stencil.TestTwoSide), - extra_EXT_stencil_two_side }, - { GL_ACTIVE_STENCIL_FACE_EXT, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, - - /* GL_NV_light_max_exponent */ - { GL_MAX_SHININESS_NV, CONTEXT_FLOAT(Const.MaxShininess), - extra_NV_light_max_exponent }, - { GL_MAX_SPOT_EXPONENT_NV, CONTEXT_FLOAT(Const.MaxSpotExponent), - extra_NV_light_max_exponent }, - - /* GL_NV_primitive_restart */ - { GL_PRIMITIVE_RESTART_NV, CONTEXT_BOOL(Array.PrimitiveRestart), - extra_NV_primitive_restart }, - { GL_PRIMITIVE_RESTART_INDEX_NV, CONTEXT_INT(Array.RestartIndex), - extra_NV_primitive_restart }, - - /* GL_ARB_vertex_buffer_object */ - { GL_INDEX_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, - offsetof(struct gl_array_object, Index.BufferObj), NO_EXTRA }, - { GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, - offsetof(struct gl_array_object, EdgeFlag.BufferObj), NO_EXTRA }, - { GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, - offsetof(struct gl_array_object, SecondaryColor.BufferObj), NO_EXTRA }, - { GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, - offsetof(struct gl_array_object, FogCoord.BufferObj), NO_EXTRA }, - - /* GL_EXT_pixel_buffer_object */ - { GL_PIXEL_PACK_BUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0, - extra_EXT_pixel_buffer_object }, - { GL_PIXEL_UNPACK_BUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0, - extra_EXT_pixel_buffer_object }, - - /* GL_ARB_vertex_program */ - { GL_VERTEX_PROGRAM_ARB, /* == GL_VERTEX_PROGRAM_NV */ - CONTEXT_BOOL(VertexProgram.Enabled), - extra_ARB_vertex_program_NV_vertex_program }, - { GL_VERTEX_PROGRAM_POINT_SIZE_ARB, /* == GL_VERTEX_PROGRAM_POINT_SIZE_NV*/ - CONTEXT_BOOL(VertexProgram.PointSizeEnabled), - extra_ARB_vertex_program_NV_vertex_program }, - { GL_VERTEX_PROGRAM_TWO_SIDE_ARB, /* == GL_VERTEX_PROGRAM_TWO_SIDE_NV */ - CONTEXT_BOOL(VertexProgram.TwoSideEnabled), - extra_ARB_vertex_program_NV_vertex_program }, - { GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB, /* == GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV */ - CONTEXT_INT(Const.MaxProgramMatrixStackDepth), - extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, - { GL_MAX_PROGRAM_MATRICES_ARB, /* == GL_MAX_TRACK_MATRICES_NV */ - CONTEXT_INT(Const.MaxProgramMatrices), - extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, - { GL_CURRENT_MATRIX_STACK_DEPTH_ARB, /* == GL_CURRENT_MATRIX_STACK_DEPTH_NV */ - LOC_CUSTOM, TYPE_INT, 0, - extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, - - { GL_CURRENT_MATRIX_ARB, /* == GL_CURRENT_MATRIX_NV */ - LOC_CUSTOM, TYPE_MATRIX, 0, - extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, - { GL_TRANSPOSE_CURRENT_MATRIX_ARB, /* == GL_CURRENT_MATRIX_NV */ - LOC_CUSTOM, TYPE_MATRIX, 0, - extra_ARB_vertex_program_ARB_fragment_program }, - - { GL_PROGRAM_ERROR_POSITION_ARB, /* == GL_PROGRAM_ERROR_POSITION_NV */ - CONTEXT_INT(Program.ErrorPos), - extra_NV_vertex_program_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, - - /* GL_ARB_fragment_program */ - { GL_FRAGMENT_PROGRAM_ARB, CONTEXT_BOOL(FragmentProgram.Enabled), - extra_ARB_fragment_program }, - - /* GL_EXT_depth_bounds_test */ - { GL_DEPTH_BOUNDS_TEST_EXT, CONTEXT_BOOL(Depth.BoundsTest), - extra_EXT_depth_bounds_test }, - { GL_DEPTH_BOUNDS_EXT, CONTEXT_FLOAT2(Depth.BoundsMin), - extra_EXT_depth_bounds_test }, - - /* GL_ARB_depth_clamp*/ - { GL_DEPTH_CLAMP, CONTEXT_BOOL(Transform.DepthClamp), - extra_ARB_depth_clamp }, - - /* GL_ARB_draw_buffers */ - { GL_DRAW_BUFFER0_ARB, BUFFER_ENUM(ColorDrawBuffer[0]), NO_EXTRA }, - { GL_DRAW_BUFFER1_ARB, BUFFER_ENUM(ColorDrawBuffer[1]), - extra_valid_draw_buffer }, - { GL_DRAW_BUFFER2_ARB, BUFFER_ENUM(ColorDrawBuffer[2]), - extra_valid_draw_buffer }, - { GL_DRAW_BUFFER3_ARB, BUFFER_ENUM(ColorDrawBuffer[3]), - extra_valid_draw_buffer }, - { GL_DRAW_BUFFER4_ARB, BUFFER_ENUM(ColorDrawBuffer[4]), - extra_valid_draw_buffer }, - { GL_DRAW_BUFFER5_ARB, BUFFER_ENUM(ColorDrawBuffer[5]), - extra_valid_draw_buffer }, - { GL_DRAW_BUFFER6_ARB, BUFFER_ENUM(ColorDrawBuffer[6]), - extra_valid_draw_buffer }, - { GL_DRAW_BUFFER7_ARB, BUFFER_ENUM(ColorDrawBuffer[7]), - extra_valid_draw_buffer }, - - /* GL_ATI_fragment_shader */ - { GL_NUM_FRAGMENT_REGISTERS_ATI, CONST(6), extra_ATI_fragment_shader }, - { GL_NUM_FRAGMENT_CONSTANTS_ATI, CONST(8), extra_ATI_fragment_shader }, - { GL_NUM_PASSES_ATI, CONST(2), extra_ATI_fragment_shader }, - { GL_NUM_INSTRUCTIONS_PER_PASS_ATI, CONST(8), extra_ATI_fragment_shader }, - { GL_NUM_INSTRUCTIONS_TOTAL_ATI, CONST(16), extra_ATI_fragment_shader }, - { GL_COLOR_ALPHA_PAIRING_ATI, CONST(GL_TRUE), extra_ATI_fragment_shader }, - { GL_NUM_LOOPBACK_COMPONENTS_ATI, CONST(3), extra_ATI_fragment_shader }, - { GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI, - CONST(3), extra_ATI_fragment_shader }, - - /* GL_EXT_framebuffer_object */ - { GL_MAX_COLOR_ATTACHMENTS_EXT, CONTEXT_INT(Const.MaxColorAttachments), - extra_EXT_framebuffer_object }, - - /* GL_EXT_framebuffer_blit - * NOTE: GL_DRAW_FRAMEBUFFER_BINDING_EXT == GL_FRAMEBUFFER_BINDING_EXT */ - { GL_READ_FRAMEBUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0, - extra_EXT_framebuffer_blit }, - - /* GL_EXT_provoking_vertex */ - { GL_PROVOKING_VERTEX_EXT, - CONTEXT_BOOL(Light.ProvokingVertex), extra_EXT_provoking_vertex }, - { GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT, - CONTEXT_BOOL(Const.QuadsFollowProvokingVertexConvention), - extra_EXT_provoking_vertex }, - - /* GL_ARB_framebuffer_object */ - { GL_MAX_SAMPLES, CONTEXT_INT(Const.MaxSamples), - extra_ARB_framebuffer_object_EXT_framebuffer_multisample }, - - /* GL_APPLE_vertex_array_object */ - { GL_VERTEX_ARRAY_BINDING_APPLE, ARRAY_INT(Name), - extra_APPLE_vertex_array_object }, - - /* GL_ARB_seamless_cube_map */ - { GL_TEXTURE_CUBE_MAP_SEAMLESS, - CONTEXT_BOOL(Texture.CubeMapSeamless), extra_ARB_seamless_cube_map }, - - /* GL_ARB_sync */ - { GL_MAX_SERVER_WAIT_TIMEOUT, - CONTEXT_INT64(Const.MaxServerWaitTimeout), extra_ARB_sync }, - - /* GL_EXT_texture_integer */ - { GL_RGBA_INTEGER_MODE_EXT, BUFFER_BOOL(_IntegerColor), - extra_EXT_texture_integer }, - - /* GL_EXT_transform_feedback */ - { GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, LOC_CUSTOM, TYPE_INT, 0, - extra_EXT_transform_feedback }, - { GL_RASTERIZER_DISCARD, CONTEXT_BOOL(TransformFeedback.RasterDiscard), - extra_EXT_transform_feedback }, - { GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, - CONTEXT_INT(Const.MaxTransformFeedbackInterleavedComponents), - extra_EXT_transform_feedback }, - { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, - CONTEXT_INT(Const.MaxTransformFeedbackSeparateAttribs), - extra_EXT_transform_feedback }, - { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, - CONTEXT_INT(Const.MaxTransformFeedbackSeparateComponents), - extra_EXT_transform_feedback }, - - /* GL_ARB_transform_feedback2 */ - { GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED, LOC_CUSTOM, TYPE_BOOLEAN, 0, - extra_ARB_transform_feedback2 }, - { GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE, LOC_CUSTOM, TYPE_BOOLEAN, 0, - extra_ARB_transform_feedback2 }, - { GL_TRANSFORM_FEEDBACK_BINDING, LOC_CUSTOM, TYPE_INT, 0, - extra_ARB_transform_feedback2 }, - - /* GL_ARB_geometry_shader4 */ - { GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB, - CONTEXT_INT(Const.GeometryProgram.MaxGeometryTextureImageUnits), - extra_ARB_geometry_shader4 }, - { GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB, - CONTEXT_INT(Const.GeometryProgram.MaxGeometryOutputVertices), - extra_ARB_geometry_shader4 }, - { GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB, - CONTEXT_INT(Const.GeometryProgram.MaxGeometryTotalOutputComponents), - extra_ARB_geometry_shader4 }, - { GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB, - CONTEXT_INT(Const.GeometryProgram.MaxGeometryUniformComponents), - extra_ARB_geometry_shader4 }, - { GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB, - CONTEXT_INT(Const.GeometryProgram.MaxGeometryVaryingComponents), - extra_ARB_geometry_shader4 }, - { GL_MAX_VERTEX_VARYING_COMPONENTS_ARB, - CONTEXT_INT(Const.GeometryProgram.MaxVertexVaryingComponents), - extra_ARB_geometry_shader4 }, - - /* GL_EXT_gpu_shader4 / GL 3.0 */ - { GL_MIN_PROGRAM_TEXEL_OFFSET, - CONTEXT_INT(Const.MinProgramTexelOffset), - extra_EXT_gpu_shader4 }, - { GL_MAX_PROGRAM_TEXEL_OFFSET, - CONTEXT_INT(Const.MaxProgramTexelOffset), - extra_EXT_gpu_shader4 }, - - /* GL 3.0 */ - { GL_NUM_EXTENSIONS, LOC_CUSTOM, TYPE_INT, 0, extra_version_30 }, - { GL_MAJOR_VERSION, CONTEXT_INT(VersionMajor), extra_version_30 }, - { GL_MINOR_VERSION, CONTEXT_INT(VersionMinor), extra_version_30 }, - { GL_CONTEXT_FLAGS, CONTEXT_INT(Const.ContextFlags), extra_version_30 }, - - /* GL3.0 / GL_EXT_framebuffer_sRGB */ - { GL_FRAMEBUFFER_SRGB_EXT, CONTEXT_BOOL(Color.sRGBEnabled), extra_EXT_framebuffer_sRGB }, - { GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, BUFFER_INT(Visual.sRGBCapable), extra_EXT_framebuffer_sRGB }, - - /* GL 3.1 */ - /* NOTE: different enum values for GL_PRIMITIVE_RESTART_NV - * vs. GL_PRIMITIVE_RESTART! - */ - { GL_PRIMITIVE_RESTART, CONTEXT_BOOL(Array.PrimitiveRestart), - extra_version_31 }, - { GL_PRIMITIVE_RESTART_INDEX, CONTEXT_INT(Array.RestartIndex), - extra_version_31 }, - - - /* GL 3.2 */ - { GL_CONTEXT_PROFILE_MASK, CONTEXT_INT(Const.ProfileMask), - extra_version_32 }, -#endif /* FEATURE_GL */ -}; - -/* All we need now is a way to look up the value struct from the enum. - * The code generated by gcc for the old generated big switch - * statement is a big, balanced, open coded if/else tree, essentially - * an unrolled binary search. It would be natural to sort the new - * enum table and use bsearch(), but we will use a read-only hash - * table instead. bsearch() has a nice guaranteed worst case - * performance, but we're also guaranteed to hit that worst case - * (log2(n) iterations) for about half the enums. Instead, using an - * open addressing hash table, we can find the enum on the first try - * for 80% of the enums, 1 collision for 10% and never more than 5 - * collisions for any enum (typical numbers). And the code is very - * simple, even though it feels a little magic. */ - -static unsigned short table[1024]; -static const int prime_factor = 89, prime_step = 281; - -#ifdef GET_DEBUG -static void -print_table_stats(void) -{ - int i, j, collisions[11], count, hash, mask; - const struct value_desc *d; - - count = 0; - mask = Elements(table) - 1; - memset(collisions, 0, sizeof collisions); - - for (i = 0; i < Elements(table); i++) { - if (!table[i]) - continue; - count++; - d = &values[table[i]]; - hash = (d->pname * prime_factor); - j = 0; - while (1) { - if (values[table[hash & mask]].pname == d->pname) - break; - hash += prime_step; - j++; - } - - if (j < 10) - collisions[j]++; - else - collisions[10]++; - } - - printf("number of enums: %d (total %d)\n", count, Elements(values)); - for (i = 0; i < Elements(collisions) - 1; i++) - if (collisions[i] > 0) - printf(" %d enums with %d %scollisions\n", - collisions[i], i, i == 10 ? "or more " : ""); -} -#endif - -/** - * Initialize the enum hash for a given API - * - * This is called from one_time_init() to insert the enum values that - * are valid for the API in question into the enum hash table. - * - * \param the current context, for determining the API in question - */ -void _mesa_init_get_hash(struct gl_context *ctx) -{ - int i, hash, index, mask; - int api_mask = 0, api_bit; - - mask = Elements(table) - 1; - api_bit = 1 << ctx->API; - - for (i = 0; i < Elements(values); i++) { - if (values[i].type == TYPE_API_MASK) { - api_mask = values[i].offset; - continue; - } - if (!(api_mask & api_bit)) - continue; - - hash = (values[i].pname * prime_factor) & mask; - while (1) { - index = hash & mask; - if (!table[index]) { - table[index] = i; - break; - } - hash += prime_step; - } - } - -#ifdef GET_DEBUG - print_table_stats(); -#endif -} - -/** - * Handle irregular enums - * - * Some values don't conform to the "well-known type at context - * pointer + offset" pattern, so we have this function to catch all - * the corner cases. Typically, it's a computed value or a one-off - * pointer to a custom struct or something. - * - * In this case we can't return a pointer to the value, so we'll have - * to use the temporary variable 'v' declared back in the calling - * glGet*v() function to store the result. - * - * \param ctx the current context - * \param d the struct value_desc that describes the enum - * \param v pointer to the tmp declared in the calling glGet*v() function - */ -static void -find_custom_value(struct gl_context *ctx, const struct value_desc *d, union value *v) -{ - struct gl_buffer_object *buffer_obj; - struct gl_client_array *array; - GLuint unit, *p; - - switch (d->pname) { - case GL_TEXTURE_1D: - case GL_TEXTURE_2D: - case GL_TEXTURE_3D: - case GL_TEXTURE_1D_ARRAY_EXT: - case GL_TEXTURE_2D_ARRAY_EXT: - case GL_TEXTURE_CUBE_MAP_ARB: - case GL_TEXTURE_RECTANGLE_NV: - v->value_bool = _mesa_IsEnabled(d->pname); - break; - - case GL_LINE_STIPPLE_PATTERN: - /* This is the only GLushort, special case it here by promoting - * to an int rather than introducing a new type. */ - v->value_int = ctx->Line.StipplePattern; - break; - - case GL_CURRENT_RASTER_TEXTURE_COORDS: - unit = ctx->Texture.CurrentUnit; - v->value_float_4[0] = ctx->Current.RasterTexCoords[unit][0]; - v->value_float_4[1] = ctx->Current.RasterTexCoords[unit][1]; - v->value_float_4[2] = ctx->Current.RasterTexCoords[unit][2]; - v->value_float_4[3] = ctx->Current.RasterTexCoords[unit][3]; - break; - - case GL_CURRENT_TEXTURE_COORDS: - unit = ctx->Texture.CurrentUnit; - v->value_float_4[0] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][0]; - v->value_float_4[1] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][1]; - v->value_float_4[2] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][2]; - v->value_float_4[3] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][3]; - break; - - case GL_COLOR_WRITEMASK: - v->value_int_4[0] = ctx->Color.ColorMask[0][RCOMP] ? 1 : 0; - v->value_int_4[1] = ctx->Color.ColorMask[0][GCOMP] ? 1 : 0; - v->value_int_4[2] = ctx->Color.ColorMask[0][BCOMP] ? 1 : 0; - v->value_int_4[3] = ctx->Color.ColorMask[0][ACOMP] ? 1 : 0; - break; - - case GL_EDGE_FLAG: - v->value_bool = ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG][0] == 1.0; - break; - - case GL_READ_BUFFER: - v->value_enum = ctx->ReadBuffer->ColorReadBuffer; - break; - - case GL_MAP2_GRID_DOMAIN: - v->value_float_4[0] = ctx->Eval.MapGrid2u1; - v->value_float_4[1] = ctx->Eval.MapGrid2u2; - v->value_float_4[2] = ctx->Eval.MapGrid2v1; - v->value_float_4[3] = ctx->Eval.MapGrid2v2; - break; - - case GL_TEXTURE_STACK_DEPTH: - unit = ctx->Texture.CurrentUnit; - v->value_int = ctx->TextureMatrixStack[unit].Depth + 1; - break; - case GL_TEXTURE_MATRIX: - unit = ctx->Texture.CurrentUnit; - v->value_matrix = ctx->TextureMatrixStack[unit].Top; - break; - - case GL_TEXTURE_COORD_ARRAY: - case GL_TEXTURE_COORD_ARRAY_SIZE: - case GL_TEXTURE_COORD_ARRAY_TYPE: - case GL_TEXTURE_COORD_ARRAY_STRIDE: - array = &ctx->Array.ArrayObj->TexCoord[ctx->Array.ActiveTexture]; - v->value_int = *(GLuint *) ((char *) array + d->offset); - break; - - case GL_ACTIVE_TEXTURE_ARB: - v->value_int = GL_TEXTURE0_ARB + ctx->Texture.CurrentUnit; - break; - case GL_CLIENT_ACTIVE_TEXTURE_ARB: - v->value_int = GL_TEXTURE0_ARB + ctx->Array.ActiveTexture; - break; - - case GL_MODELVIEW_STACK_DEPTH: - case GL_PROJECTION_STACK_DEPTH: - v->value_int = *(GLint *) ((char *) ctx + d->offset) + 1; - break; - - case GL_MAX_TEXTURE_SIZE: - case GL_MAX_3D_TEXTURE_SIZE: - case GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB: - p = (GLuint *) ((char *) ctx + d->offset); - v->value_int = 1 << (*p - 1); - break; - - case GL_SCISSOR_BOX: - v->value_int_4[0] = ctx->Scissor.X; - v->value_int_4[1] = ctx->Scissor.Y; - v->value_int_4[2] = ctx->Scissor.Width; - v->value_int_4[3] = ctx->Scissor.Height; - break; - - case GL_LIST_INDEX: - v->value_int = - ctx->ListState.CurrentList ? ctx->ListState.CurrentList->Name : 0; - break; - case GL_LIST_MODE: - if (!ctx->CompileFlag) - v->value_enum = 0; - else if (ctx->ExecuteFlag) - v->value_enum = GL_COMPILE_AND_EXECUTE; - else - v->value_enum = GL_COMPILE; - break; - - case GL_VIEWPORT: - v->value_int_4[0] = ctx->Viewport.X; - v->value_int_4[1] = ctx->Viewport.Y; - v->value_int_4[2] = ctx->Viewport.Width; - v->value_int_4[3] = ctx->Viewport.Height; - break; - - case GL_ACTIVE_STENCIL_FACE_EXT: - v->value_enum = ctx->Stencil.ActiveFace ? GL_BACK : GL_FRONT; - break; - - case GL_STENCIL_FAIL: - v->value_enum = ctx->Stencil.FailFunc[ctx->Stencil.ActiveFace]; - break; - case GL_STENCIL_FUNC: - v->value_enum = ctx->Stencil.Function[ctx->Stencil.ActiveFace]; - break; - case GL_STENCIL_PASS_DEPTH_FAIL: - v->value_enum = ctx->Stencil.ZFailFunc[ctx->Stencil.ActiveFace]; - break; - case GL_STENCIL_PASS_DEPTH_PASS: - v->value_enum = ctx->Stencil.ZPassFunc[ctx->Stencil.ActiveFace]; - break; - case GL_STENCIL_REF: - v->value_int = ctx->Stencil.Ref[ctx->Stencil.ActiveFace]; - break; - case GL_STENCIL_VALUE_MASK: - v->value_int = ctx->Stencil.ValueMask[ctx->Stencil.ActiveFace]; - break; - case GL_STENCIL_WRITEMASK: - v->value_int = ctx->Stencil.WriteMask[ctx->Stencil.ActiveFace]; - break; - - case GL_NUM_EXTENSIONS: - v->value_int = _mesa_get_extension_count(ctx); - break; - - case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES: - v->value_int = _mesa_get_color_read_type(ctx); - break; - case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES: - v->value_int = _mesa_get_color_read_format(ctx); - break; - - case GL_CURRENT_MATRIX_STACK_DEPTH_ARB: - v->value_int = ctx->CurrentStack->Depth + 1; - break; - case GL_CURRENT_MATRIX_ARB: - case GL_TRANSPOSE_CURRENT_MATRIX_ARB: - v->value_matrix = ctx->CurrentStack->Top; - break; - - case GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB: - v->value_int = _mesa_get_compressed_formats(ctx, NULL, GL_FALSE); - break; - case GL_COMPRESSED_TEXTURE_FORMATS_ARB: - v->value_int_n.n = - _mesa_get_compressed_formats(ctx, v->value_int_n.ints, GL_FALSE); - ASSERT(v->value_int_n.n <= 100); - break; - - case GL_MAX_VARYING_FLOATS_ARB: - v->value_int = ctx->Const.MaxVarying * 4; - break; - - /* Various object names */ - - case GL_TEXTURE_BINDING_1D: - case GL_TEXTURE_BINDING_2D: - case GL_TEXTURE_BINDING_3D: - case GL_TEXTURE_BINDING_1D_ARRAY_EXT: - case GL_TEXTURE_BINDING_2D_ARRAY_EXT: - case GL_TEXTURE_BINDING_CUBE_MAP_ARB: - case GL_TEXTURE_BINDING_RECTANGLE_NV: - unit = ctx->Texture.CurrentUnit; - v->value_int = - ctx->Texture.Unit[unit].CurrentTex[d->offset]->Name; - break; - - /* GL_ARB_vertex_buffer_object */ - case GL_VERTEX_ARRAY_BUFFER_BINDING_ARB: - case GL_NORMAL_ARRAY_BUFFER_BINDING_ARB: - case GL_COLOR_ARRAY_BUFFER_BINDING_ARB: - case GL_INDEX_ARRAY_BUFFER_BINDING_ARB: - case GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB: - case GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB: - case GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB: - buffer_obj = (struct gl_buffer_object *) - ((char *) ctx->Array.ArrayObj + d->offset); - v->value_int = buffer_obj->Name; - break; - case GL_ARRAY_BUFFER_BINDING_ARB: - v->value_int = ctx->Array.ArrayBufferObj->Name; - break; - case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB: - v->value_int = - ctx->Array.ArrayObj->TexCoord[ctx->Array.ActiveTexture].BufferObj->Name; - break; - case GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB: - v->value_int = ctx->Array.ElementArrayBufferObj->Name; - break; - - /* ARB_copy_buffer */ - case GL_COPY_READ_BUFFER: - v->value_int = ctx->CopyReadBuffer->Name; - break; - case GL_COPY_WRITE_BUFFER: - v->value_int = ctx->CopyWriteBuffer->Name; - break; - - case GL_FRAGMENT_PROGRAM_BINDING_NV: - v->value_int = - ctx->FragmentProgram.Current ? ctx->FragmentProgram.Current->Base.Id : 0; - break; - case GL_VERTEX_PROGRAM_BINDING_NV: - v->value_int = - ctx->VertexProgram.Current ? ctx->VertexProgram.Current->Base.Id : 0; - break; - case GL_PIXEL_PACK_BUFFER_BINDING_EXT: - v->value_int = ctx->Pack.BufferObj->Name; - break; - case GL_PIXEL_UNPACK_BUFFER_BINDING_EXT: - v->value_int = ctx->Unpack.BufferObj->Name; - break; - case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - v->value_int = ctx->TransformFeedback.CurrentBuffer->Name; - break; - case GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED: - v->value_int = ctx->TransformFeedback.CurrentObject->Paused; - break; - case GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE: - v->value_int = ctx->TransformFeedback.CurrentObject->Active; - break; - case GL_TRANSFORM_FEEDBACK_BINDING: - v->value_int = ctx->TransformFeedback.CurrentObject->Name; - break; - case GL_CURRENT_PROGRAM: - v->value_int = - ctx->Shader.ActiveProgram ? ctx->Shader.ActiveProgram->Name : 0; - break; - case GL_READ_FRAMEBUFFER_BINDING_EXT: - v->value_int = ctx->ReadBuffer->Name; - break; - case GL_RENDERBUFFER_BINDING_EXT: - v->value_int = - ctx->CurrentRenderbuffer ? ctx->CurrentRenderbuffer->Name : 0; - break; - case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES: - v->value_int = ctx->Array.ArrayObj->PointSize.BufferObj->Name; - break; - - case GL_MAX_VERTEX_UNIFORM_VECTORS: - v->value_int = ctx->Const.VertexProgram.MaxUniformComponents / 4; - break; - - case GL_MAX_FRAGMENT_UNIFORM_VECTORS: - v->value_int = ctx->Const.FragmentProgram.MaxUniformComponents / 4; - break; - } -} - -/** - * Check extra constraints on a struct value_desc descriptor - * - * If a struct value_desc has a non-NULL extra pointer, it means that - * there are a number of extra constraints to check or actions to - * perform. The extras is just an integer array where each integer - * encode different constraints or actions. - * - * \param ctx current context - * \param func name of calling glGet*v() function for error reporting - * \param d the struct value_desc that has the extra constraints - * - * \return GL_FALSE if one of the constraints was not satisfied, - * otherwise GL_TRUE. - */ -static GLboolean -check_extra(struct gl_context *ctx, const char *func, const struct value_desc *d) -{ - const GLuint version = ctx->VersionMajor * 10 + ctx->VersionMinor; - int total, enabled; - const int *e; - - total = 0; - enabled = 0; - for (e = d->extra; *e != EXTRA_END; e++) - switch (*e) { - case EXTRA_VERSION_30: - if (version >= 30) { - total++; - enabled++; - } - break; - case EXTRA_VERSION_31: - if (version >= 31) { - total++; - enabled++; - } - break; - case EXTRA_VERSION_32: - if (version >= 32) { - total++; - enabled++; - } - break; - case EXTRA_VERSION_ES2: - if (ctx->API == API_OPENGLES2) { - total++; - enabled++; - } - break; - case EXTRA_NEW_BUFFERS: - if (ctx->NewState & _NEW_BUFFERS) - _mesa_update_state(ctx); - break; - case EXTRA_FLUSH_CURRENT: - FLUSH_CURRENT(ctx, 0); - break; - case EXTRA_VALID_DRAW_BUFFER: - if (d->pname - GL_DRAW_BUFFER0_ARB >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(draw buffer %u)", - func, d->pname - GL_DRAW_BUFFER0_ARB); - return GL_FALSE; - } - break; - case EXTRA_VALID_TEXTURE_UNIT: - if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(texture %u)", - func, ctx->Texture.CurrentUnit); - return GL_FALSE; - } - break; - case EXTRA_END: - break; - default: /* *e is a offset into the extension struct */ - total++; - if (*(GLboolean *) ((char *) &ctx->Extensions + *e)) - enabled++; - break; - } - - if (total > 0 && enabled == 0) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", func, - _mesa_lookup_enum_by_nr(d->pname)); - return GL_FALSE; - } - - return GL_TRUE; -} - -static const struct value_desc error_value = - { 0, 0, TYPE_INVALID, NO_OFFSET, NO_EXTRA }; - -/** - * Find the struct value_desc corresponding to the enum 'pname'. - * - * We hash the enum value to get an index into the 'table' array, - * which holds the index in the 'values' array of struct value_desc. - * Once we've found the entry, we do the extra checks, if any, then - * look up the value and return a pointer to it. - * - * If the value has to be computed (for example, it's the result of a - * function call or we need to add 1 to it), we use the tmp 'v' to - * store the result. - * - * \param func name of glGet*v() func for error reporting - * \param pname the enum value we're looking up - * \param p is were we return the pointer to the value - * \param v a tmp union value variable in the calling glGet*v() function - * - * \return the struct value_desc corresponding to the enum or a struct - * value_desc of TYPE_INVALID if not found. This lets the calling - * glGet*v() function jump right into a switch statement and - * handle errors there instead of having to check for NULL. - */ -static const struct value_desc * -find_value(const char *func, GLenum pname, void **p, union value *v) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_texture_unit *unit; - int mask, hash; - const struct value_desc *d; - - mask = Elements(table) - 1; - hash = (pname * prime_factor); - while (1) { - d = &values[table[hash & mask]]; - - /* If the enum isn't valid, the hash walk ends with index 0, - * which is the API mask entry at the beginning of values[]. */ - if (unlikely(d->type == TYPE_API_MASK)) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", func, - _mesa_lookup_enum_by_nr(pname)); - return &error_value; - } - - if (likely(d->pname == pname)) - break; - - hash += prime_step; - } - - if (unlikely(d->extra && !check_extra(ctx, func, d))) - return &error_value; - - switch (d->location) { - case LOC_BUFFER: - *p = ((char *) ctx->DrawBuffer + d->offset); - return d; - case LOC_CONTEXT: - *p = ((char *) ctx + d->offset); - return d; - case LOC_ARRAY: - *p = ((char *) ctx->Array.ArrayObj + d->offset); - return d; - case LOC_TEXUNIT: - unit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - *p = ((char *) unit + d->offset); - return d; - case LOC_CUSTOM: - find_custom_value(ctx, d, v); - *p = v; - return d; - default: - assert(0); - break; - } - - /* silence warning */ - return &error_value; -} - -static const int transpose[] = { - 0, 4, 8, 12, - 1, 5, 9, 13, - 2, 6, 10, 14, - 3, 7, 11, 15 -}; - -void GLAPIENTRY -_mesa_GetBooleanv(GLenum pname, GLboolean *params) -{ - const struct value_desc *d; - union value v; - GLmatrix *m; - int shift, i; - void *p; - - d = find_value("glGetBooleanv", pname, &p, &v); - switch (d->type) { - case TYPE_INVALID: - break; - case TYPE_CONST: - params[0] = INT_TO_BOOLEAN(d->offset); - break; - - case TYPE_FLOAT_4: - case TYPE_FLOATN_4: - params[3] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[3]); - case TYPE_FLOAT_3: - case TYPE_FLOATN_3: - params[2] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[2]); - case TYPE_FLOAT_2: - case TYPE_FLOATN_2: - params[1] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[1]); - case TYPE_FLOAT: - case TYPE_FLOATN: - params[0] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[0]); - break; - - case TYPE_DOUBLEN: - params[0] = FLOAT_TO_BOOLEAN(((GLdouble *) p)[0]); - break; - - case TYPE_INT_4: - params[3] = INT_TO_BOOLEAN(((GLint *) p)[3]); - case TYPE_INT_3: - params[2] = INT_TO_BOOLEAN(((GLint *) p)[2]); - case TYPE_INT_2: - case TYPE_ENUM_2: - params[1] = INT_TO_BOOLEAN(((GLint *) p)[1]); - case TYPE_INT: - case TYPE_ENUM: - params[0] = INT_TO_BOOLEAN(((GLint *) p)[0]); - break; - - case TYPE_INT_N: - for (i = 0; i < v.value_int_n.n; i++) - params[i] = INT_TO_BOOLEAN(v.value_int_n.ints[i]); - break; - - case TYPE_INT64: - params[0] = INT64_TO_BOOLEAN(((GLint64 *) p)[0]); - break; - - case TYPE_BOOLEAN: - params[0] = ((GLboolean*) p)[0]; - break; - - case TYPE_MATRIX: - m = *(GLmatrix **) p; - for (i = 0; i < 16; i++) - params[i] = FLOAT_TO_BOOLEAN(m->m[i]); - break; - - case TYPE_MATRIX_T: - m = *(GLmatrix **) p; - for (i = 0; i < 16; i++) - params[i] = FLOAT_TO_BOOLEAN(m->m[transpose[i]]); - break; - - case TYPE_BIT_0: - case TYPE_BIT_1: - case TYPE_BIT_2: - case TYPE_BIT_3: - case TYPE_BIT_4: - case TYPE_BIT_5: - shift = d->type - TYPE_BIT_0; - params[0] = (*(GLbitfield *) p >> shift) & 1; - break; - } -} - -void GLAPIENTRY -_mesa_GetFloatv(GLenum pname, GLfloat *params) -{ - const struct value_desc *d; - union value v; - GLmatrix *m; - int shift, i; - void *p; - - d = find_value("glGetFloatv", pname, &p, &v); - switch (d->type) { - case TYPE_INVALID: - break; - case TYPE_CONST: - params[0] = (GLfloat) d->offset; - break; - - case TYPE_FLOAT_4: - case TYPE_FLOATN_4: - params[3] = ((GLfloat *) p)[3]; - case TYPE_FLOAT_3: - case TYPE_FLOATN_3: - params[2] = ((GLfloat *) p)[2]; - case TYPE_FLOAT_2: - case TYPE_FLOATN_2: - params[1] = ((GLfloat *) p)[1]; - case TYPE_FLOAT: - case TYPE_FLOATN: - params[0] = ((GLfloat *) p)[0]; - break; - - case TYPE_DOUBLEN: - params[0] = ((GLdouble *) p)[0]; - break; - - case TYPE_INT_4: - params[3] = (GLfloat) (((GLint *) p)[3]); - case TYPE_INT_3: - params[2] = (GLfloat) (((GLint *) p)[2]); - case TYPE_INT_2: - case TYPE_ENUM_2: - params[1] = (GLfloat) (((GLint *) p)[1]); - case TYPE_INT: - case TYPE_ENUM: - params[0] = (GLfloat) (((GLint *) p)[0]); - break; - - case TYPE_INT_N: - for (i = 0; i < v.value_int_n.n; i++) - params[i] = INT_TO_FLOAT(v.value_int_n.ints[i]); - break; - - case TYPE_INT64: - params[0] = ((GLint64 *) p)[0]; - break; - - case TYPE_BOOLEAN: - params[0] = BOOLEAN_TO_FLOAT(*(GLboolean*) p); - break; - - case TYPE_MATRIX: - m = *(GLmatrix **) p; - for (i = 0; i < 16; i++) - params[i] = m->m[i]; - break; - - case TYPE_MATRIX_T: - m = *(GLmatrix **) p; - for (i = 0; i < 16; i++) - params[i] = m->m[transpose[i]]; - break; - - case TYPE_BIT_0: - case TYPE_BIT_1: - case TYPE_BIT_2: - case TYPE_BIT_3: - case TYPE_BIT_4: - case TYPE_BIT_5: - shift = d->type - TYPE_BIT_0; - params[0] = BOOLEAN_TO_FLOAT((*(GLbitfield *) p >> shift) & 1); - break; - } -} - -void GLAPIENTRY -_mesa_GetIntegerv(GLenum pname, GLint *params) -{ - const struct value_desc *d; - union value v; - GLmatrix *m; - int shift, i; - void *p; - - d = find_value("glGetIntegerv", pname, &p, &v); - switch (d->type) { - case TYPE_INVALID: - break; - case TYPE_CONST: - params[0] = d->offset; - break; - - case TYPE_FLOAT_4: - params[3] = IROUND(((GLfloat *) p)[3]); - case TYPE_FLOAT_3: - params[2] = IROUND(((GLfloat *) p)[2]); - case TYPE_FLOAT_2: - params[1] = IROUND(((GLfloat *) p)[1]); - case TYPE_FLOAT: - params[0] = IROUND(((GLfloat *) p)[0]); - break; - - case TYPE_FLOATN_4: - params[3] = FLOAT_TO_INT(((GLfloat *) p)[3]); - case TYPE_FLOATN_3: - params[2] = FLOAT_TO_INT(((GLfloat *) p)[2]); - case TYPE_FLOATN_2: - params[1] = FLOAT_TO_INT(((GLfloat *) p)[1]); - case TYPE_FLOATN: - params[0] = FLOAT_TO_INT(((GLfloat *) p)[0]); - break; - - case TYPE_DOUBLEN: - params[0] = FLOAT_TO_INT(((GLdouble *) p)[0]); - break; - - case TYPE_INT_4: - params[3] = ((GLint *) p)[3]; - case TYPE_INT_3: - params[2] = ((GLint *) p)[2]; - case TYPE_INT_2: - case TYPE_ENUM_2: - params[1] = ((GLint *) p)[1]; - case TYPE_INT: - case TYPE_ENUM: - params[0] = ((GLint *) p)[0]; - break; - - case TYPE_INT_N: - for (i = 0; i < v.value_int_n.n; i++) - params[i] = v.value_int_n.ints[i]; - break; - - case TYPE_INT64: - params[0] = INT64_TO_INT(((GLint64 *) p)[0]); - break; - - case TYPE_BOOLEAN: - params[0] = BOOLEAN_TO_INT(*(GLboolean*) p); - break; - - case TYPE_MATRIX: - m = *(GLmatrix **) p; - for (i = 0; i < 16; i++) - params[i] = FLOAT_TO_INT(m->m[i]); - break; - - case TYPE_MATRIX_T: - m = *(GLmatrix **) p; - for (i = 0; i < 16; i++) - params[i] = FLOAT_TO_INT(m->m[transpose[i]]); - break; - - case TYPE_BIT_0: - case TYPE_BIT_1: - case TYPE_BIT_2: - case TYPE_BIT_3: - case TYPE_BIT_4: - case TYPE_BIT_5: - shift = d->type - TYPE_BIT_0; - params[0] = (*(GLbitfield *) p >> shift) & 1; - break; - } -} - -#if FEATURE_ARB_sync -void GLAPIENTRY -_mesa_GetInteger64v(GLenum pname, GLint64 *params) -{ - const struct value_desc *d; - union value v; - GLmatrix *m; - int shift, i; - void *p; - - d = find_value("glGetInteger64v", pname, &p, &v); - switch (d->type) { - case TYPE_INVALID: - break; - case TYPE_CONST: - params[0] = d->offset; - break; - - case TYPE_FLOAT_4: - params[3] = IROUND64(((GLfloat *) p)[3]); - case TYPE_FLOAT_3: - params[2] = IROUND64(((GLfloat *) p)[2]); - case TYPE_FLOAT_2: - params[1] = IROUND64(((GLfloat *) p)[1]); - case TYPE_FLOAT: - params[0] = IROUND64(((GLfloat *) p)[0]); - break; - - case TYPE_FLOATN_4: - params[3] = FLOAT_TO_INT64(((GLfloat *) p)[3]); - case TYPE_FLOATN_3: - params[2] = FLOAT_TO_INT64(((GLfloat *) p)[2]); - case TYPE_FLOATN_2: - params[1] = FLOAT_TO_INT64(((GLfloat *) p)[1]); - case TYPE_FLOATN: - params[0] = FLOAT_TO_INT64(((GLfloat *) p)[0]); - break; - - case TYPE_DOUBLEN: - params[0] = FLOAT_TO_INT64(((GLdouble *) p)[0]); - break; - - case TYPE_INT_4: - params[3] = ((GLint *) p)[3]; - case TYPE_INT_3: - params[2] = ((GLint *) p)[2]; - case TYPE_INT_2: - case TYPE_ENUM_2: - params[1] = ((GLint *) p)[1]; - case TYPE_INT: - case TYPE_ENUM: - params[0] = ((GLint *) p)[0]; - break; - - case TYPE_INT_N: - for (i = 0; i < v.value_int_n.n; i++) - params[i] = INT_TO_BOOLEAN(v.value_int_n.ints[i]); - break; - - case TYPE_INT64: - params[0] = ((GLint64 *) p)[0]; - break; - - case TYPE_BOOLEAN: - params[0] = ((GLboolean*) p)[0]; - break; - - case TYPE_MATRIX: - m = *(GLmatrix **) p; - for (i = 0; i < 16; i++) - params[i] = FLOAT_TO_INT64(m->m[i]); - break; - - case TYPE_MATRIX_T: - m = *(GLmatrix **) p; - for (i = 0; i < 16; i++) - params[i] = FLOAT_TO_INT64(m->m[transpose[i]]); - break; - - case TYPE_BIT_0: - case TYPE_BIT_1: - case TYPE_BIT_2: - case TYPE_BIT_3: - case TYPE_BIT_4: - case TYPE_BIT_5: - shift = d->type - TYPE_BIT_0; - params[0] = (*(GLbitfield *) p >> shift) & 1; - break; - } -} -#endif /* FEATURE_ARB_sync */ - -void GLAPIENTRY -_mesa_GetDoublev(GLenum pname, GLdouble *params) -{ - const struct value_desc *d; - union value v; - GLmatrix *m; - int shift, i; - void *p; - - d = find_value("glGetDoublev", pname, &p, &v); - switch (d->type) { - case TYPE_INVALID: - break; - case TYPE_CONST: - params[0] = d->offset; - break; - - case TYPE_FLOAT_4: - case TYPE_FLOATN_4: - params[3] = ((GLfloat *) p)[3]; - case TYPE_FLOAT_3: - case TYPE_FLOATN_3: - params[2] = ((GLfloat *) p)[2]; - case TYPE_FLOAT_2: - case TYPE_FLOATN_2: - params[1] = ((GLfloat *) p)[1]; - case TYPE_FLOAT: - case TYPE_FLOATN: - params[0] = ((GLfloat *) p)[0]; - break; - - case TYPE_DOUBLEN: - params[0] = ((GLdouble *) p)[0]; - break; - - case TYPE_INT_4: - params[3] = ((GLint *) p)[3]; - case TYPE_INT_3: - params[2] = ((GLint *) p)[2]; - case TYPE_INT_2: - case TYPE_ENUM_2: - params[1] = ((GLint *) p)[1]; - case TYPE_INT: - case TYPE_ENUM: - params[0] = ((GLint *) p)[0]; - break; - - case TYPE_INT_N: - for (i = 0; i < v.value_int_n.n; i++) - params[i] = v.value_int_n.ints[i]; - break; - - case TYPE_INT64: - params[0] = ((GLint64 *) p)[0]; - break; - - case TYPE_BOOLEAN: - params[0] = *(GLboolean*) p; - break; - - case TYPE_MATRIX: - m = *(GLmatrix **) p; - for (i = 0; i < 16; i++) - params[i] = m->m[i]; - break; - - case TYPE_MATRIX_T: - m = *(GLmatrix **) p; - for (i = 0; i < 16; i++) - params[i] = m->m[transpose[i]]; - break; - - case TYPE_BIT_0: - case TYPE_BIT_1: - case TYPE_BIT_2: - case TYPE_BIT_3: - case TYPE_BIT_4: - case TYPE_BIT_5: - shift = d->type - TYPE_BIT_0; - params[0] = (*(GLbitfield *) p >> shift) & 1; - break; - } -} - -static enum value_type -find_value_indexed(const char *func, GLenum pname, int index, union value *v) -{ - GET_CURRENT_CONTEXT(ctx); - - switch (pname) { - - case GL_BLEND: - if (index >= ctx->Const.MaxDrawBuffers) - goto invalid_value; - if (!ctx->Extensions.EXT_draw_buffers2) - goto invalid_enum; - v->value_int = (ctx->Color.BlendEnabled >> index) & 1; - return TYPE_INT; - - case GL_BLEND_SRC: - /* fall-through */ - case GL_BLEND_SRC_RGB: - if (index >= ctx->Const.MaxDrawBuffers) - goto invalid_value; - if (!ctx->Extensions.ARB_draw_buffers_blend) - goto invalid_enum; - v->value_int = ctx->Color.Blend[index].SrcRGB; - return TYPE_INT; - case GL_BLEND_SRC_ALPHA: - if (index >= ctx->Const.MaxDrawBuffers) - goto invalid_value; - if (!ctx->Extensions.ARB_draw_buffers_blend) - goto invalid_enum; - v->value_int = ctx->Color.Blend[index].SrcA; - return TYPE_INT; - case GL_BLEND_DST: - /* fall-through */ - case GL_BLEND_DST_RGB: - if (index >= ctx->Const.MaxDrawBuffers) - goto invalid_value; - if (!ctx->Extensions.ARB_draw_buffers_blend) - goto invalid_enum; - v->value_int = ctx->Color.Blend[index].DstRGB; - return TYPE_INT; - case GL_BLEND_DST_ALPHA: - if (index >= ctx->Const.MaxDrawBuffers) - goto invalid_value; - if (!ctx->Extensions.ARB_draw_buffers_blend) - goto invalid_enum; - v->value_int = ctx->Color.Blend[index].DstA; - return TYPE_INT; - case GL_BLEND_EQUATION_RGB: - if (index >= ctx->Const.MaxDrawBuffers) - goto invalid_value; - if (!ctx->Extensions.ARB_draw_buffers_blend) - goto invalid_enum; - v->value_int = ctx->Color.Blend[index].EquationRGB; - return TYPE_INT; - case GL_BLEND_EQUATION_ALPHA: - if (index >= ctx->Const.MaxDrawBuffers) - goto invalid_value; - if (!ctx->Extensions.ARB_draw_buffers_blend) - goto invalid_enum; - v->value_int = ctx->Color.Blend[index].EquationA; - return TYPE_INT; - - case GL_COLOR_WRITEMASK: - if (index >= ctx->Const.MaxDrawBuffers) - goto invalid_value; - if (!ctx->Extensions.EXT_draw_buffers2) - goto invalid_enum; - v->value_int_4[0] = ctx->Color.ColorMask[index][RCOMP] ? 1 : 0; - v->value_int_4[1] = ctx->Color.ColorMask[index][GCOMP] ? 1 : 0; - v->value_int_4[2] = ctx->Color.ColorMask[index][BCOMP] ? 1 : 0; - v->value_int_4[3] = ctx->Color.ColorMask[index][ACOMP] ? 1 : 0; - return TYPE_INT_4; - - case GL_TRANSFORM_FEEDBACK_BUFFER_START: - if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) - goto invalid_value; - if (!ctx->Extensions.EXT_transform_feedback) - goto invalid_enum; - v->value_int64 = ctx->TransformFeedback.CurrentObject->Offset[index]; - return TYPE_INT64; - - case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: - if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) - goto invalid_value; - if (!ctx->Extensions.EXT_transform_feedback) - goto invalid_enum; - v->value_int64 = ctx->TransformFeedback.CurrentObject->Size[index]; - return TYPE_INT64; - - case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) - goto invalid_value; - if (!ctx->Extensions.EXT_transform_feedback) - goto invalid_enum; - v->value_int = ctx->TransformFeedback.CurrentObject->Buffers[index]->Name; - return TYPE_INT; - } - - invalid_enum: - _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", func, - _mesa_lookup_enum_by_nr(pname)); - return TYPE_INVALID; - invalid_value: - _mesa_error(ctx, GL_INVALID_VALUE, "%s(pname=%s)", func, - _mesa_lookup_enum_by_nr(pname)); - return TYPE_INVALID; -} - -void GLAPIENTRY -_mesa_GetBooleanIndexedv( GLenum pname, GLuint index, GLboolean *params ) -{ - union value v; - enum value_type type = - find_value_indexed("glGetBooleanIndexedv", pname, index, &v); - - switch (type) { - case TYPE_INT: - params[0] = INT_TO_BOOLEAN(v.value_int); - break; - case TYPE_INT_4: - params[0] = INT_TO_BOOLEAN(v.value_int_4[0]); - params[1] = INT_TO_BOOLEAN(v.value_int_4[1]); - params[2] = INT_TO_BOOLEAN(v.value_int_4[2]); - params[3] = INT_TO_BOOLEAN(v.value_int_4[3]); - break; - case TYPE_INT64: - params[0] = INT64_TO_BOOLEAN(v.value_int); - break; - default: - ; /* nothing - GL error was recorded */ - } -} - -void GLAPIENTRY -_mesa_GetIntegerIndexedv( GLenum pname, GLuint index, GLint *params ) -{ - union value v; - enum value_type type = - find_value_indexed("glGetIntegerIndexedv", pname, index, &v); - - switch (type) { - case TYPE_INT: - params[0] = v.value_int; - break; - case TYPE_INT_4: - params[0] = v.value_int_4[0]; - params[1] = v.value_int_4[1]; - params[2] = v.value_int_4[2]; - params[3] = v.value_int_4[3]; - break; - case TYPE_INT64: - params[0] = INT64_TO_INT(v.value_int); - break; - default: - ; /* nothing - GL error was recorded */ - } -} - -#if FEATURE_ARB_sync -void GLAPIENTRY -_mesa_GetInteger64Indexedv( GLenum pname, GLuint index, GLint64 *params ) -{ - union value v; - enum value_type type = - find_value_indexed("glGetIntegerIndexedv", pname, index, &v); - - switch (type) { - case TYPE_INT: - params[0] = v.value_int; - break; - case TYPE_INT_4: - params[0] = v.value_int_4[0]; - params[1] = v.value_int_4[1]; - params[2] = v.value_int_4[2]; - params[3] = v.value_int_4[3]; - break; - case TYPE_INT64: - params[0] = v.value_int; - break; - default: - ; /* nothing - GL error was recorded */ - } -} -#endif /* FEATURE_ARB_sync */ - -#if FEATURE_ES1 -void GLAPIENTRY -_mesa_GetFixedv(GLenum pname, GLfixed *params) -{ - const struct value_desc *d; - union value v; - GLmatrix *m; - int shift, i; - void *p; - - d = find_value("glGetDoublev", pname, &p, &v); - switch (d->type) { - case TYPE_INVALID: - break; - case TYPE_CONST: - params[0] = INT_TO_FIXED(d->offset); - break; - - case TYPE_FLOAT_4: - case TYPE_FLOATN_4: - params[3] = FLOAT_TO_FIXED(((GLfloat *) p)[3]); - case TYPE_FLOAT_3: - case TYPE_FLOATN_3: - params[2] = FLOAT_TO_FIXED(((GLfloat *) p)[2]); - case TYPE_FLOAT_2: - case TYPE_FLOATN_2: - params[1] = FLOAT_TO_FIXED(((GLfloat *) p)[1]); - case TYPE_FLOAT: - case TYPE_FLOATN: - params[0] = FLOAT_TO_FIXED(((GLfloat *) p)[0]); - break; - - case TYPE_DOUBLEN: - params[0] = FLOAT_TO_FIXED(((GLdouble *) p)[0]); - break; - - case TYPE_INT_4: - params[3] = INT_TO_FIXED(((GLint *) p)[3]); - case TYPE_INT_3: - params[2] = INT_TO_FIXED(((GLint *) p)[2]); - case TYPE_INT_2: - case TYPE_ENUM_2: - params[1] = INT_TO_FIXED(((GLint *) p)[1]); - case TYPE_INT: - case TYPE_ENUM: - params[0] = INT_TO_FIXED(((GLint *) p)[0]); - break; - - case TYPE_INT_N: - for (i = 0; i < v.value_int_n.n; i++) - params[i] = INT_TO_FIXED(v.value_int_n.ints[i]); - break; - - case TYPE_INT64: - params[0] = ((GLint64 *) p)[0]; - break; - - case TYPE_BOOLEAN: - params[0] = BOOLEAN_TO_FIXED(((GLboolean*) p)[0]); - break; - - case TYPE_MATRIX: - m = *(GLmatrix **) p; - for (i = 0; i < 16; i++) - params[i] = FLOAT_TO_FIXED(m->m[i]); - break; - - case TYPE_MATRIX_T: - m = *(GLmatrix **) p; - for (i = 0; i < 16; i++) - params[i] = FLOAT_TO_FIXED(m->m[transpose[i]]); - break; - - case TYPE_BIT_0: - case TYPE_BIT_1: - case TYPE_BIT_2: - case TYPE_BIT_3: - case TYPE_BIT_4: - case TYPE_BIT_5: - shift = d->type - TYPE_BIT_0; - params[0] = BOOLEAN_TO_FIXED((*(GLbitfield *) p >> shift) & 1); - break; - } -} -#endif +/* + * Copyright (C) 2010 Brian Paul All Rights Reserved. + * Copyright (C) 2010 Intel Corporation + * + * 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. + * + * Author: Kristian Høgsberg + */ + +#include "glheader.h" +#include "context.h" +#include "enable.h" +#include "enums.h" +#include "extensions.h" +#include "get.h" +#include "macros.h" +#include "mfeatures.h" +#include "mtypes.h" +#include "state.h" +#include "texcompress.h" +#include "framebuffer.h" + +/* This is a table driven implemetation of the glGet*v() functions. + * The basic idea is that most getters just look up an int somewhere + * in struct gl_context and then convert it to a bool or float according to + * which of glGetIntegerv() glGetBooleanv() etc is being called. + * Instead of generating code to do this, we can just record the enum + * value and the offset into struct gl_context in an array of structs. Then + * in glGet*(), we lookup the struct for the enum in question, and use + * the offset to get the int we need. + * + * Sometimes we need to look up a float, a boolean, a bit in a + * bitfield, a matrix or other types instead, so we need to track the + * type of the value in struct gl_context. And sometimes the value isn't in + * struct gl_context but in the drawbuffer, the array object, current texture + * unit, or maybe it's a computed value. So we need to also track + * where or how to find the value. Finally, we sometimes need to + * check that one of a number of extensions are enabled, the GL + * version or flush or call _mesa_update_state(). This is done by + * attaching optional extra information to the value description + * struct, it's sort of like an array of opcodes that describe extra + * checks or actions. + * + * Putting all this together we end up with struct value_desc below, + * and with a couple of macros to help, the table of struct value_desc + * is about as concise as the specification in the old python script. + */ + +#undef CONST + +#define FLOAT_TO_BOOLEAN(X) ( (X) ? GL_TRUE : GL_FALSE ) +#define FLOAT_TO_FIXED(F) ( ((F) * 65536.0f > INT_MAX) ? INT_MAX : \ + ((F) * 65536.0f < INT_MIN) ? INT_MIN : \ + (GLint) ((F) * 65536.0f) ) + +#define INT_TO_BOOLEAN(I) ( (I) ? GL_TRUE : GL_FALSE ) +#define INT_TO_FIXED(I) ( ((I) > SHRT_MAX) ? INT_MAX : \ + ((I) < SHRT_MIN) ? INT_MIN : \ + (GLint) ((I) * 65536) ) + +#define INT64_TO_BOOLEAN(I) ( (I) ? GL_TRUE : GL_FALSE ) +#define INT64_TO_INT(I) ( (GLint)((I > INT_MAX) ? INT_MAX : ((I < INT_MIN) ? INT_MIN : (I))) ) + +#define BOOLEAN_TO_INT(B) ( (GLint) (B) ) +#define BOOLEAN_TO_INT64(B) ( (GLint64) (B) ) +#define BOOLEAN_TO_FLOAT(B) ( (B) ? 1.0F : 0.0F ) +#define BOOLEAN_TO_FIXED(B) ( (GLint) ((B) ? 1 : 0) << 16 ) + +#define ENUM_TO_INT64(E) ( (GLint64) (E) ) +#define ENUM_TO_FIXED(E) (E) + +enum value_type { + TYPE_INVALID, + TYPE_API_MASK, + TYPE_INT, + TYPE_INT_2, + TYPE_INT_3, + TYPE_INT_4, + TYPE_INT_N, + TYPE_INT64, + TYPE_ENUM, + TYPE_ENUM_2, + TYPE_BOOLEAN, + TYPE_BIT_0, + TYPE_BIT_1, + TYPE_BIT_2, + TYPE_BIT_3, + TYPE_BIT_4, + TYPE_BIT_5, + TYPE_FLOAT, + TYPE_FLOAT_2, + TYPE_FLOAT_3, + TYPE_FLOAT_4, + TYPE_FLOATN, + TYPE_FLOATN_2, + TYPE_FLOATN_3, + TYPE_FLOATN_4, + TYPE_DOUBLEN, + TYPE_MATRIX, + TYPE_MATRIX_T, + TYPE_CONST +}; + +enum value_location { + LOC_BUFFER, + LOC_CONTEXT, + LOC_ARRAY, + LOC_TEXUNIT, + LOC_CUSTOM +}; + +enum value_extra { + EXTRA_END = 0x8000, + EXTRA_VERSION_30, + EXTRA_VERSION_31, + EXTRA_VERSION_32, + EXTRA_VERSION_ES2, + EXTRA_NEW_BUFFERS, + EXTRA_VALID_DRAW_BUFFER, + EXTRA_VALID_TEXTURE_UNIT, + EXTRA_FLUSH_CURRENT, +}; + +#define NO_EXTRA NULL +#define NO_OFFSET 0 + +struct value_desc { + GLenum pname; + GLubyte location; /**< enum value_location */ + GLubyte type; /**< enum value_type */ + int offset; + const int *extra; +}; + +union value { + GLfloat value_float; + GLfloat value_float_4[4]; + GLmatrix *value_matrix; + GLint value_int; + GLint value_int_4[4]; + GLint64 value_int64; + GLenum value_enum; + + /* Sigh, see GL_COMPRESSED_TEXTURE_FORMATS_ARB handling */ + struct { + GLint n, ints[100]; + } value_int_n; + GLboolean value_bool; +}; + +#define BUFFER_FIELD(field, type) \ + LOC_BUFFER, type, offsetof(struct gl_framebuffer, field) +#define CONTEXT_FIELD(field, type) \ + LOC_CONTEXT, type, offsetof(struct gl_context, field) +#define ARRAY_FIELD(field, type) \ + LOC_ARRAY, type, offsetof(struct gl_array_object, field) +#define CONST(value) \ + LOC_CONTEXT, TYPE_CONST, value + +#define BUFFER_INT(field) BUFFER_FIELD(field, TYPE_INT) +#define BUFFER_ENUM(field) BUFFER_FIELD(field, TYPE_ENUM) +#define BUFFER_BOOL(field) BUFFER_FIELD(field, TYPE_BOOLEAN) + +#define CONTEXT_INT(field) CONTEXT_FIELD(field, TYPE_INT) +#define CONTEXT_INT2(field) CONTEXT_FIELD(field, TYPE_INT_2) +#define CONTEXT_INT64(field) CONTEXT_FIELD(field, TYPE_INT64) +#define CONTEXT_ENUM(field) CONTEXT_FIELD(field, TYPE_ENUM) +#define CONTEXT_ENUM2(field) CONTEXT_FIELD(field, TYPE_ENUM_2) +#define CONTEXT_BOOL(field) CONTEXT_FIELD(field, TYPE_BOOLEAN) +#define CONTEXT_BIT0(field) CONTEXT_FIELD(field, TYPE_BIT_0) +#define CONTEXT_BIT1(field) CONTEXT_FIELD(field, TYPE_BIT_1) +#define CONTEXT_BIT2(field) CONTEXT_FIELD(field, TYPE_BIT_2) +#define CONTEXT_BIT3(field) CONTEXT_FIELD(field, TYPE_BIT_3) +#define CONTEXT_BIT4(field) CONTEXT_FIELD(field, TYPE_BIT_4) +#define CONTEXT_BIT5(field) CONTEXT_FIELD(field, TYPE_BIT_5) +#define CONTEXT_FLOAT(field) CONTEXT_FIELD(field, TYPE_FLOAT) +#define CONTEXT_FLOAT2(field) CONTEXT_FIELD(field, TYPE_FLOAT_2) +#define CONTEXT_FLOAT3(field) CONTEXT_FIELD(field, TYPE_FLOAT_3) +#define CONTEXT_FLOAT4(field) CONTEXT_FIELD(field, TYPE_FLOAT_4) +#define CONTEXT_MATRIX(field) CONTEXT_FIELD(field, TYPE_MATRIX) +#define CONTEXT_MATRIX_T(field) CONTEXT_FIELD(field, TYPE_MATRIX_T) + +#define ARRAY_INT(field) ARRAY_FIELD(field, TYPE_INT) +#define ARRAY_ENUM(field) ARRAY_FIELD(field, TYPE_ENUM) +#define ARRAY_BOOL(field) ARRAY_FIELD(field, TYPE_BOOLEAN) + +#define EXT(f) \ + offsetof(struct gl_extensions, f) + +#define EXTRA_EXT(e) \ + static const int extra_##e[] = { \ + EXT(e), EXTRA_END \ + } + +#define EXTRA_EXT2(e1, e2) \ + static const int extra_##e1##_##e2[] = { \ + EXT(e1), EXT(e2), EXTRA_END \ + } + +/* The 'extra' mechanism is a way to specify extra checks (such as + * extensions or specific gl versions) or actions (flush current, new + * buffers) that we need to do before looking up an enum. We need to + * declare them all up front so we can refer to them in the value_desc + * structs below. */ + +static const int extra_new_buffers[] = { + EXTRA_NEW_BUFFERS, + EXTRA_END +}; + +static const int extra_valid_draw_buffer[] = { + EXTRA_VALID_DRAW_BUFFER, + EXTRA_END +}; + +static const int extra_valid_texture_unit[] = { + EXTRA_VALID_TEXTURE_UNIT, + EXTRA_END +}; + +static const int extra_flush_current_valid_texture_unit[] = { + EXTRA_FLUSH_CURRENT, + EXTRA_VALID_TEXTURE_UNIT, + EXTRA_END +}; + +static const int extra_flush_current[] = { + EXTRA_FLUSH_CURRENT, + EXTRA_END +}; + +static const int extra_new_buffers_OES_read_format[] = { + EXTRA_NEW_BUFFERS, + EXT(OES_read_format), + EXTRA_END +}; + +static const int extra_EXT_secondary_color_flush_current[] = { + EXT(EXT_secondary_color), + EXTRA_FLUSH_CURRENT, + EXTRA_END +}; + +static const int extra_EXT_fog_coord_flush_current[] = { + EXT(EXT_fog_coord), + EXTRA_FLUSH_CURRENT, + EXTRA_END +}; + +static const int extra_EXT_texture_integer[] = { + EXT(EXT_texture_integer), + EXTRA_END +}; + +static const int extra_EXT_gpu_shader4[] = { + EXT(EXT_gpu_shader4), + EXTRA_END +}; + + +EXTRA_EXT(ARB_ES2_compatibility); +EXTRA_EXT(ARB_multitexture); +EXTRA_EXT(ARB_texture_cube_map); +EXTRA_EXT(MESA_texture_array); +EXTRA_EXT2(EXT_secondary_color, ARB_vertex_program); +EXTRA_EXT(EXT_secondary_color); +EXTRA_EXT(EXT_fog_coord); +EXTRA_EXT(EXT_texture_lod_bias); +EXTRA_EXT(EXT_texture_filter_anisotropic); +EXTRA_EXT(IBM_rasterpos_clip); +EXTRA_EXT(NV_point_sprite); +EXTRA_EXT(SGIS_generate_mipmap); +EXTRA_EXT(NV_vertex_program); +EXTRA_EXT(NV_fragment_program); +EXTRA_EXT(NV_texture_rectangle); +EXTRA_EXT(EXT_stencil_two_side); +EXTRA_EXT(NV_light_max_exponent); +EXTRA_EXT(EXT_depth_bounds_test); +EXTRA_EXT(ARB_depth_clamp); +EXTRA_EXT(ATI_fragment_shader); +EXTRA_EXT(EXT_framebuffer_blit); +EXTRA_EXT(ARB_shader_objects); +EXTRA_EXT(EXT_provoking_vertex); +EXTRA_EXT(ARB_fragment_shader); +EXTRA_EXT(ARB_fragment_program); +EXTRA_EXT2(ARB_framebuffer_object, EXT_framebuffer_multisample); +EXTRA_EXT(EXT_framebuffer_object); +EXTRA_EXT(APPLE_vertex_array_object); +EXTRA_EXT(ARB_seamless_cube_map); +EXTRA_EXT(EXT_compiled_vertex_array); +EXTRA_EXT(ARB_sync); +EXTRA_EXT(ARB_vertex_shader); +EXTRA_EXT(EXT_transform_feedback); +EXTRA_EXT(ARB_transform_feedback2); +EXTRA_EXT(EXT_pixel_buffer_object); +EXTRA_EXT(ARB_vertex_program); +EXTRA_EXT2(NV_point_sprite, ARB_point_sprite); +EXTRA_EXT2(ARB_fragment_program, NV_fragment_program); +EXTRA_EXT2(ARB_vertex_program, NV_vertex_program); +EXTRA_EXT2(ARB_vertex_program, ARB_fragment_program); +EXTRA_EXT(ARB_vertex_buffer_object); +EXTRA_EXT(ARB_geometry_shader4); +EXTRA_EXT(ARB_copy_buffer); +EXTRA_EXT(EXT_framebuffer_sRGB); + +static const int +extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program[] = { + EXT(ARB_vertex_program), + EXT(ARB_fragment_program), + EXT(NV_vertex_program), + EXTRA_END +}; + +static const int +extra_NV_vertex_program_ARB_vertex_program_ARB_fragment_program_NV_vertex_program[] = { + EXT(NV_vertex_program), + EXT(ARB_vertex_program), + EXT(ARB_fragment_program), + EXT(NV_vertex_program), + EXTRA_END +}; + +static const int +extra_NV_primitive_restart[] = { + EXT(NV_primitive_restart), + EXTRA_END +}; + +static const int extra_version_30[] = { EXTRA_VERSION_30, EXTRA_END }; +static const int extra_version_31[] = { EXTRA_VERSION_31, EXTRA_END }; +static const int extra_version_32[] = { EXTRA_VERSION_32, EXTRA_END }; + +static const int +extra_ARB_vertex_program_version_es2[] = { + EXT(ARB_vertex_program), + EXTRA_VERSION_ES2, + EXTRA_END +}; + +#define API_OPENGL_BIT (1 << API_OPENGL) +#define API_OPENGLES_BIT (1 << API_OPENGLES) +#define API_OPENGLES2_BIT (1 << API_OPENGLES2) + +/* This is the big table describing all the enums we accept in + * glGet*v(). The table is partitioned into six parts: enums + * understood by all GL APIs (OpenGL, GLES and GLES2), enums shared + * between OpenGL and GLES, enums exclusive to GLES, etc for the + * remaining combinations. When we add the enums to the hash table in + * _mesa_init_get_hash(), we only add the enums for the API we're + * instantiating and the different sections are guarded by #if + * FEATURE_GL etc to make sure we only compile in the enums we may + * need. */ + +static const struct value_desc values[] = { + /* Enums shared between OpenGL, GLES1 and GLES2 */ + { 0, 0, TYPE_API_MASK, + API_OPENGL_BIT | API_OPENGLES_BIT | API_OPENGLES2_BIT, NO_EXTRA}, + { GL_ALPHA_BITS, BUFFER_INT(Visual.alphaBits), extra_new_buffers }, + { GL_BLEND, CONTEXT_BIT0(Color.BlendEnabled), NO_EXTRA }, + { GL_BLEND_SRC, CONTEXT_ENUM(Color.Blend[0].SrcRGB), NO_EXTRA }, + { GL_BLUE_BITS, BUFFER_INT(Visual.blueBits), extra_new_buffers }, + { GL_COLOR_CLEAR_VALUE, CONTEXT_FIELD(Color.ClearColor[0], TYPE_FLOATN_4), NO_EXTRA }, + { GL_COLOR_WRITEMASK, LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA }, + { GL_CULL_FACE, CONTEXT_BOOL(Polygon.CullFlag), NO_EXTRA }, + { GL_CULL_FACE_MODE, CONTEXT_ENUM(Polygon.CullFaceMode), NO_EXTRA }, + { GL_DEPTH_BITS, BUFFER_INT(Visual.depthBits), NO_EXTRA }, + { GL_DEPTH_CLEAR_VALUE, CONTEXT_FIELD(Depth.Clear, TYPE_DOUBLEN), NO_EXTRA }, + { GL_DEPTH_FUNC, CONTEXT_ENUM(Depth.Func), NO_EXTRA }, + { GL_DEPTH_RANGE, CONTEXT_FIELD(Viewport.Near, TYPE_FLOATN_2), NO_EXTRA }, + { GL_DEPTH_TEST, CONTEXT_BOOL(Depth.Test), NO_EXTRA }, + { GL_DEPTH_WRITEMASK, CONTEXT_BOOL(Depth.Mask), NO_EXTRA }, + { GL_DITHER, CONTEXT_BOOL(Color.DitherFlag), NO_EXTRA }, + { GL_FRONT_FACE, CONTEXT_ENUM(Polygon.FrontFace), NO_EXTRA }, + { GL_GREEN_BITS, BUFFER_INT(Visual.greenBits), extra_new_buffers }, + { GL_LINE_WIDTH, CONTEXT_FLOAT(Line.Width), NO_EXTRA }, + { GL_ALIASED_LINE_WIDTH_RANGE, CONTEXT_FLOAT2(Const.MinLineWidth), NO_EXTRA }, + { GL_MAX_ELEMENTS_VERTICES, CONTEXT_INT(Const.MaxArrayLockSize), NO_EXTRA }, + { GL_MAX_ELEMENTS_INDICES, CONTEXT_INT(Const.MaxArrayLockSize), NO_EXTRA }, + { GL_MAX_TEXTURE_SIZE, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_context, Const.MaxTextureLevels), NO_EXTRA }, + { GL_MAX_VIEWPORT_DIMS, CONTEXT_INT2(Const.MaxViewportWidth), NO_EXTRA }, + { GL_PACK_ALIGNMENT, CONTEXT_INT(Pack.Alignment), NO_EXTRA }, + { GL_ALIASED_POINT_SIZE_RANGE, CONTEXT_FLOAT2(Const.MinPointSize), NO_EXTRA }, + { GL_POLYGON_OFFSET_FACTOR, CONTEXT_FLOAT(Polygon.OffsetFactor ), NO_EXTRA }, + { GL_POLYGON_OFFSET_UNITS, CONTEXT_FLOAT(Polygon.OffsetUnits ), NO_EXTRA }, + { GL_POLYGON_OFFSET_FILL, CONTEXT_BOOL(Polygon.OffsetFill), NO_EXTRA }, + { GL_RED_BITS, BUFFER_INT(Visual.redBits), extra_new_buffers }, + { GL_SCISSOR_BOX, LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA }, + { GL_SCISSOR_TEST, CONTEXT_BOOL(Scissor.Enabled), NO_EXTRA }, + { GL_STENCIL_BITS, BUFFER_INT(Visual.stencilBits), NO_EXTRA }, + { GL_STENCIL_CLEAR_VALUE, CONTEXT_INT(Stencil.Clear), NO_EXTRA }, + { GL_STENCIL_FAIL, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, + { GL_STENCIL_FUNC, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, + { GL_STENCIL_PASS_DEPTH_FAIL, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, + { GL_STENCIL_PASS_DEPTH_PASS, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, + { GL_STENCIL_REF, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA }, + { GL_STENCIL_TEST, CONTEXT_BOOL(Stencil.Enabled), NO_EXTRA }, + { GL_STENCIL_VALUE_MASK, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA }, + { GL_STENCIL_WRITEMASK, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA }, + { GL_SUBPIXEL_BITS, CONTEXT_INT(Const.SubPixelBits), NO_EXTRA }, + { GL_TEXTURE_BINDING_2D, LOC_CUSTOM, TYPE_INT, TEXTURE_2D_INDEX, NO_EXTRA }, + { GL_UNPACK_ALIGNMENT, CONTEXT_INT(Unpack.Alignment), NO_EXTRA }, + { GL_VIEWPORT, LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA }, + + /* GL_ARB_multitexture */ + { GL_ACTIVE_TEXTURE_ARB, + LOC_CUSTOM, TYPE_INT, 0, extra_ARB_multitexture }, + + /* Note that all the OES_* extensions require that the Mesa "struct + * gl_extensions" include a member with the name of the extension. + * That structure does not yet include OES extensions (and we're + * not sure whether it will). If it does, all the OES_* + * extensions below should mark the dependency. */ + + /* GL_ARB_texture_cube_map */ + { GL_TEXTURE_BINDING_CUBE_MAP_ARB, LOC_CUSTOM, TYPE_INT, + TEXTURE_CUBE_INDEX, extra_ARB_texture_cube_map }, + { GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_context, Const.MaxCubeTextureLevels), + extra_ARB_texture_cube_map }, /* XXX: OES_texture_cube_map */ + + /* XXX: OES_blend_subtract */ + { GL_BLEND_SRC_RGB_EXT, CONTEXT_ENUM(Color.Blend[0].SrcRGB), NO_EXTRA }, + { GL_BLEND_DST_RGB_EXT, CONTEXT_ENUM(Color.Blend[0].DstRGB), NO_EXTRA }, + { GL_BLEND_SRC_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].SrcA), NO_EXTRA }, + { GL_BLEND_DST_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].DstA), NO_EXTRA }, + + /* GL_BLEND_EQUATION_RGB, which is what we're really after, is + * defined identically to GL_BLEND_EQUATION. */ + { GL_BLEND_EQUATION, CONTEXT_ENUM(Color.Blend[0].EquationRGB), NO_EXTRA }, + { GL_BLEND_EQUATION_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].EquationA), NO_EXTRA }, + + /* GL_ARB_texture_compression */ + { GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, + { GL_COMPRESSED_TEXTURE_FORMATS_ARB, LOC_CUSTOM, TYPE_INT_N, 0, NO_EXTRA }, + + /* GL_ARB_multisample */ + { GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, + CONTEXT_BOOL(Multisample.SampleAlphaToCoverage), NO_EXTRA }, + { GL_SAMPLE_COVERAGE_ARB, CONTEXT_BOOL(Multisample.SampleCoverage), NO_EXTRA }, + { GL_SAMPLE_COVERAGE_VALUE_ARB, + CONTEXT_FLOAT(Multisample.SampleCoverageValue), NO_EXTRA }, + { GL_SAMPLE_COVERAGE_INVERT_ARB, + CONTEXT_BOOL(Multisample.SampleCoverageInvert), NO_EXTRA }, + { GL_SAMPLE_BUFFERS_ARB, BUFFER_INT(Visual.sampleBuffers), NO_EXTRA }, + { GL_SAMPLES_ARB, BUFFER_INT(Visual.samples), NO_EXTRA }, + + /* GL_SGIS_generate_mipmap */ + { GL_GENERATE_MIPMAP_HINT_SGIS, CONTEXT_ENUM(Hint.GenerateMipmap), + extra_SGIS_generate_mipmap }, + + /* GL_ARB_vertex_buffer_object */ + { GL_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, + + /* GL_ARB_vertex_buffer_object */ + /* GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB - not supported */ + { GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, 0, + extra_ARB_vertex_buffer_object }, + + /* GL_ARB_copy_buffer */ + { GL_COPY_READ_BUFFER, LOC_CUSTOM, TYPE_INT, 0, extra_ARB_copy_buffer }, + { GL_COPY_WRITE_BUFFER, LOC_CUSTOM, TYPE_INT, 0, extra_ARB_copy_buffer }, + + /* GL_OES_read_format */ + { GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, LOC_CUSTOM, TYPE_INT, 0, + extra_new_buffers_OES_read_format }, + { GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, LOC_CUSTOM, TYPE_INT, 0, + extra_new_buffers_OES_read_format }, + + /* GL_EXT_framebuffer_object */ + { GL_FRAMEBUFFER_BINDING_EXT, BUFFER_INT(Name), + extra_EXT_framebuffer_object }, + { GL_RENDERBUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0, + extra_EXT_framebuffer_object }, + { GL_MAX_RENDERBUFFER_SIZE_EXT, CONTEXT_INT(Const.MaxRenderbufferSize), + extra_EXT_framebuffer_object }, + + /* This entry isn't spec'ed for GLES 2, but is needed for Mesa's + * GLSL: */ + { GL_MAX_CLIP_PLANES, CONTEXT_INT(Const.MaxClipPlanes), NO_EXTRA }, + +#if FEATURE_GL || FEATURE_ES1 + /* Enums in OpenGL and GLES1 */ + { 0, 0, TYPE_API_MASK, API_OPENGL_BIT | API_OPENGLES_BIT, NO_EXTRA }, + { GL_LIGHT0, CONTEXT_BOOL(Light.Light[0].Enabled), NO_EXTRA }, + { GL_LIGHT1, CONTEXT_BOOL(Light.Light[1].Enabled), NO_EXTRA }, + { GL_LIGHT2, CONTEXT_BOOL(Light.Light[2].Enabled), NO_EXTRA }, + { GL_LIGHT3, CONTEXT_BOOL(Light.Light[3].Enabled), NO_EXTRA }, + { GL_LIGHT4, CONTEXT_BOOL(Light.Light[4].Enabled), NO_EXTRA }, + { GL_LIGHT5, CONTEXT_BOOL(Light.Light[5].Enabled), NO_EXTRA }, + { GL_LIGHT6, CONTEXT_BOOL(Light.Light[6].Enabled), NO_EXTRA }, + { GL_LIGHT7, CONTEXT_BOOL(Light.Light[7].Enabled), NO_EXTRA }, + { GL_LIGHTING, CONTEXT_BOOL(Light.Enabled), NO_EXTRA }, + { GL_LIGHT_MODEL_AMBIENT, + CONTEXT_FIELD(Light.Model.Ambient[0], TYPE_FLOATN_4), NO_EXTRA }, + { GL_LIGHT_MODEL_TWO_SIDE, CONTEXT_BOOL(Light.Model.TwoSide), NO_EXTRA }, + { GL_ALPHA_TEST, CONTEXT_BOOL(Color.AlphaEnabled), NO_EXTRA }, + { GL_ALPHA_TEST_FUNC, CONTEXT_ENUM(Color.AlphaFunc), NO_EXTRA }, + { GL_ALPHA_TEST_REF, CONTEXT_FIELD(Color.AlphaRef, TYPE_FLOATN), NO_EXTRA }, + { GL_BLEND_DST, CONTEXT_ENUM(Color.Blend[0].DstRGB), NO_EXTRA }, + { GL_CLIP_PLANE0, CONTEXT_BIT0(Transform.ClipPlanesEnabled), NO_EXTRA }, + { GL_CLIP_PLANE1, CONTEXT_BIT1(Transform.ClipPlanesEnabled), NO_EXTRA }, + { GL_CLIP_PLANE2, CONTEXT_BIT2(Transform.ClipPlanesEnabled), NO_EXTRA }, + { GL_CLIP_PLANE3, CONTEXT_BIT3(Transform.ClipPlanesEnabled), NO_EXTRA }, + { GL_CLIP_PLANE4, CONTEXT_BIT4(Transform.ClipPlanesEnabled), NO_EXTRA }, + { GL_CLIP_PLANE5, CONTEXT_BIT5(Transform.ClipPlanesEnabled), NO_EXTRA }, + { GL_COLOR_MATERIAL, CONTEXT_BOOL(Light.ColorMaterialEnabled), NO_EXTRA }, + { GL_CURRENT_COLOR, + CONTEXT_FIELD(Current.Attrib[VERT_ATTRIB_COLOR0][0], TYPE_FLOATN_4), + extra_flush_current }, + { GL_CURRENT_NORMAL, + CONTEXT_FIELD(Current.Attrib[VERT_ATTRIB_NORMAL][0], TYPE_FLOATN_3), + extra_flush_current }, + { GL_CURRENT_TEXTURE_COORDS, LOC_CUSTOM, TYPE_FLOAT_4, 0, + extra_flush_current_valid_texture_unit }, + { GL_DISTANCE_ATTENUATION_EXT, CONTEXT_FLOAT3(Point.Params[0]), NO_EXTRA }, + { GL_FOG, CONTEXT_BOOL(Fog.Enabled), NO_EXTRA }, + { GL_FOG_COLOR, CONTEXT_FIELD(Fog.Color[0], TYPE_FLOATN_4), NO_EXTRA }, + { GL_FOG_DENSITY, CONTEXT_FLOAT(Fog.Density), NO_EXTRA }, + { GL_FOG_END, CONTEXT_FLOAT(Fog.End), NO_EXTRA }, + { GL_FOG_HINT, CONTEXT_ENUM(Hint.Fog), NO_EXTRA }, + { GL_FOG_MODE, CONTEXT_ENUM(Fog.Mode), NO_EXTRA }, + { GL_FOG_START, CONTEXT_FLOAT(Fog.Start), NO_EXTRA }, + { GL_LINE_SMOOTH, CONTEXT_BOOL(Line.SmoothFlag), NO_EXTRA }, + { GL_LINE_SMOOTH_HINT, CONTEXT_ENUM(Hint.LineSmooth), NO_EXTRA }, + { GL_LINE_WIDTH_RANGE, CONTEXT_FLOAT2(Const.MinLineWidthAA), NO_EXTRA }, + { GL_COLOR_LOGIC_OP, CONTEXT_BOOL(Color.ColorLogicOpEnabled), NO_EXTRA }, + { GL_LOGIC_OP_MODE, CONTEXT_ENUM(Color.LogicOp), NO_EXTRA }, + { GL_MATRIX_MODE, CONTEXT_ENUM(Transform.MatrixMode), NO_EXTRA }, + { GL_MAX_MODELVIEW_STACK_DEPTH, CONST(MAX_MODELVIEW_STACK_DEPTH), NO_EXTRA }, + { GL_MAX_PROJECTION_STACK_DEPTH, CONST(MAX_PROJECTION_STACK_DEPTH), NO_EXTRA }, + { GL_MAX_TEXTURE_STACK_DEPTH, CONST(MAX_TEXTURE_STACK_DEPTH), NO_EXTRA }, + { GL_MODELVIEW_MATRIX, CONTEXT_MATRIX(ModelviewMatrixStack.Top), NO_EXTRA }, + { GL_MODELVIEW_STACK_DEPTH, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_context, ModelviewMatrixStack.Depth), NO_EXTRA }, + { GL_NORMALIZE, CONTEXT_BOOL(Transform.Normalize), NO_EXTRA }, + { GL_PACK_SKIP_IMAGES_EXT, CONTEXT_INT(Pack.SkipImages), NO_EXTRA }, + { GL_PERSPECTIVE_CORRECTION_HINT, CONTEXT_ENUM(Hint.PerspectiveCorrection), NO_EXTRA }, + { GL_POINT_SIZE, CONTEXT_FLOAT(Point.Size), NO_EXTRA }, + { GL_POINT_SIZE_RANGE, CONTEXT_FLOAT2(Const.MinPointSizeAA), NO_EXTRA }, + { GL_POINT_SMOOTH, CONTEXT_BOOL(Point.SmoothFlag), NO_EXTRA }, + { GL_POINT_SMOOTH_HINT, CONTEXT_ENUM(Hint.PointSmooth), NO_EXTRA }, + { GL_POINT_SIZE_MIN_EXT, CONTEXT_FLOAT(Point.MinSize), NO_EXTRA }, + { GL_POINT_SIZE_MAX_EXT, CONTEXT_FLOAT(Point.MaxSize), NO_EXTRA }, + { GL_POINT_FADE_THRESHOLD_SIZE_EXT, CONTEXT_FLOAT(Point.Threshold), NO_EXTRA }, + { GL_PROJECTION_MATRIX, CONTEXT_MATRIX(ProjectionMatrixStack.Top), NO_EXTRA }, + { GL_PROJECTION_STACK_DEPTH, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_context, ProjectionMatrixStack.Depth), NO_EXTRA }, + { GL_RESCALE_NORMAL, CONTEXT_BOOL(Transform.RescaleNormals), NO_EXTRA }, + { GL_SHADE_MODEL, CONTEXT_ENUM(Light.ShadeModel), NO_EXTRA }, + { GL_TEXTURE_2D, LOC_CUSTOM, TYPE_BOOLEAN, 0, NO_EXTRA }, + { GL_TEXTURE_MATRIX, LOC_CUSTOM, TYPE_MATRIX, 0, extra_valid_texture_unit }, + { GL_TEXTURE_STACK_DEPTH, LOC_CUSTOM, TYPE_INT, 0, + extra_valid_texture_unit }, + + { GL_VERTEX_ARRAY, ARRAY_BOOL(Vertex.Enabled), NO_EXTRA }, + { GL_VERTEX_ARRAY_SIZE, ARRAY_INT(Vertex.Size), NO_EXTRA }, + { GL_VERTEX_ARRAY_TYPE, ARRAY_ENUM(Vertex.Type), NO_EXTRA }, + { GL_VERTEX_ARRAY_STRIDE, ARRAY_INT(Vertex.Stride), NO_EXTRA }, + { GL_NORMAL_ARRAY, ARRAY_ENUM(Normal.Enabled), NO_EXTRA }, + { GL_NORMAL_ARRAY_TYPE, ARRAY_ENUM(Normal.Type), NO_EXTRA }, + { GL_NORMAL_ARRAY_STRIDE, ARRAY_INT(Normal.Stride), NO_EXTRA }, + { GL_COLOR_ARRAY, ARRAY_BOOL(Color.Enabled), NO_EXTRA }, + { GL_COLOR_ARRAY_SIZE, ARRAY_INT(Color.Size), NO_EXTRA }, + { GL_COLOR_ARRAY_TYPE, ARRAY_ENUM(Color.Type), NO_EXTRA }, + { GL_COLOR_ARRAY_STRIDE, ARRAY_INT(Color.Stride), NO_EXTRA }, + { GL_TEXTURE_COORD_ARRAY, + LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Enabled), NO_EXTRA }, + { GL_TEXTURE_COORD_ARRAY_SIZE, + LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Size), NO_EXTRA }, + { GL_TEXTURE_COORD_ARRAY_TYPE, + LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Type), NO_EXTRA }, + { GL_TEXTURE_COORD_ARRAY_STRIDE, + LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Stride), NO_EXTRA }, + + /* GL_ARB_ES2_compatibility */ + { GL_SHADER_COMPILER, CONST(1), extra_ARB_ES2_compatibility }, + { GL_MAX_VARYING_VECTORS, CONTEXT_INT(Const.MaxVarying), + extra_ARB_ES2_compatibility }, + { GL_MAX_VERTEX_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0, + extra_ARB_ES2_compatibility }, + { GL_MAX_FRAGMENT_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0, + extra_ARB_ES2_compatibility }, + + /* GL_ARB_multitexture */ + { GL_MAX_TEXTURE_UNITS_ARB, + CONTEXT_INT(Const.MaxTextureUnits), extra_ARB_multitexture }, + { GL_CLIENT_ACTIVE_TEXTURE_ARB, + LOC_CUSTOM, TYPE_INT, 0, extra_ARB_multitexture }, + + /* GL_ARB_texture_cube_map */ + { GL_TEXTURE_CUBE_MAP_ARB, LOC_CUSTOM, TYPE_BOOLEAN, 0, NO_EXTRA }, + /* S, T, and R are always set at the same time */ + { GL_TEXTURE_GEN_STR_OES, LOC_TEXUNIT, TYPE_BIT_0, + offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, + + /* GL_ARB_multisample */ + { GL_MULTISAMPLE_ARB, CONTEXT_BOOL(Multisample.Enabled), NO_EXTRA }, + { GL_SAMPLE_ALPHA_TO_ONE_ARB, CONTEXT_BOOL(Multisample.SampleAlphaToOne), NO_EXTRA }, + + /* GL_ARB_vertex_buffer_object */ + { GL_VERTEX_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_array_object, Vertex.BufferObj), NO_EXTRA }, + { GL_NORMAL_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_array_object, Normal.BufferObj), NO_EXTRA }, + { GL_COLOR_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_array_object, Color.BufferObj), NO_EXTRA }, + { GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA }, + + /* GL_OES_point_sprite */ + { GL_POINT_SPRITE_NV, + CONTEXT_BOOL(Point.PointSprite), + extra_NV_point_sprite_ARB_point_sprite }, + + /* GL_ARB_fragment_shader */ + { GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, + CONTEXT_INT(Const.FragmentProgram.MaxUniformComponents), + extra_ARB_fragment_shader }, + + /* GL_ARB_vertex_shader */ + { GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, + CONTEXT_INT(Const.VertexProgram.MaxUniformComponents), + extra_ARB_vertex_shader }, + { GL_MAX_VARYING_FLOATS_ARB, LOC_CUSTOM, TYPE_INT, 0, + extra_ARB_vertex_shader }, + + /* GL_EXT_texture_lod_bias */ + { GL_MAX_TEXTURE_LOD_BIAS_EXT, CONTEXT_FLOAT(Const.MaxTextureLodBias), + extra_EXT_texture_lod_bias }, + + /* GL_EXT_texture_filter_anisotropic */ + { GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, + CONTEXT_FLOAT(Const.MaxTextureMaxAnisotropy), + extra_EXT_texture_filter_anisotropic }, +#endif /* FEATURE_GL || FEATURE_ES1 */ + +#if FEATURE_ES1 + { 0, 0, TYPE_API_MASK, API_OPENGLES_BIT }, + /* XXX: OES_matrix_get */ + { GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES }, + { GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES }, + { GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES }, + + /* OES_point_size_array */ + { GL_POINT_SIZE_ARRAY_OES, ARRAY_FIELD(PointSize.Enabled, TYPE_BOOLEAN) }, + { GL_POINT_SIZE_ARRAY_TYPE_OES, ARRAY_FIELD(PointSize.Type, TYPE_ENUM) }, + { GL_POINT_SIZE_ARRAY_STRIDE_OES, ARRAY_FIELD(PointSize.Stride, TYPE_INT) }, + { GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES, LOC_CUSTOM, TYPE_INT, 0 }, +#endif /* FEATURE_ES1 */ + +#if FEATURE_GL || FEATURE_ES2 + { 0, 0, TYPE_API_MASK, API_OPENGL_BIT | API_OPENGLES2_BIT, NO_EXTRA }, + /* This entry isn't spec'ed for GLES 2, but is needed for Mesa's GLSL: */ + { GL_MAX_LIGHTS, CONTEXT_INT(Const.MaxLights), NO_EXTRA }, + { GL_MAX_TEXTURE_COORDS_ARB, /* == GL_MAX_TEXTURE_COORDS_NV */ + CONTEXT_INT(Const.MaxTextureCoordUnits), + extra_ARB_fragment_program_NV_fragment_program }, + + /* GL_ARB_draw_buffers */ + { GL_MAX_DRAW_BUFFERS_ARB, CONTEXT_INT(Const.MaxDrawBuffers), NO_EXTRA }, + + { GL_BLEND_COLOR_EXT, CONTEXT_FIELD(Color.BlendColor[0], TYPE_FLOATN_4), NO_EXTRA }, + /* GL_ARB_fragment_program */ + { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, /* == GL_MAX_TEXTURE_IMAGE_UNITS_NV */ + CONTEXT_INT(Const.MaxTextureImageUnits), + extra_ARB_fragment_program_NV_fragment_program }, + { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, + CONTEXT_INT(Const.MaxVertexTextureImageUnits), extra_ARB_vertex_shader }, + { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, + CONTEXT_INT(Const.MaxCombinedTextureImageUnits), + extra_ARB_vertex_shader }, + + /* GL_ARB_shader_objects + * Actually, this token isn't part of GL_ARB_shader_objects, but is + * close enough for now. */ + { GL_CURRENT_PROGRAM, LOC_CUSTOM, TYPE_INT, 0, extra_ARB_shader_objects }, + + /* OpenGL 2.0 */ + { GL_STENCIL_BACK_FUNC, CONTEXT_ENUM(Stencil.Function[1]), NO_EXTRA }, + { GL_STENCIL_BACK_VALUE_MASK, CONTEXT_INT(Stencil.ValueMask[1]), NO_EXTRA }, + { GL_STENCIL_BACK_WRITEMASK, CONTEXT_INT(Stencil.WriteMask[1]), NO_EXTRA }, + { GL_STENCIL_BACK_REF, CONTEXT_INT(Stencil.Ref[1]), NO_EXTRA }, + { GL_STENCIL_BACK_FAIL, CONTEXT_ENUM(Stencil.FailFunc[1]), NO_EXTRA }, + { GL_STENCIL_BACK_PASS_DEPTH_FAIL, CONTEXT_ENUM(Stencil.ZFailFunc[1]), NO_EXTRA }, + { GL_STENCIL_BACK_PASS_DEPTH_PASS, CONTEXT_ENUM(Stencil.ZPassFunc[1]), NO_EXTRA }, + + { GL_MAX_VERTEX_ATTRIBS_ARB, + CONTEXT_INT(Const.VertexProgram.MaxAttribs), + extra_ARB_vertex_program_version_es2 }, + + /* OES_texture_3D */ + { GL_TEXTURE_BINDING_3D, LOC_CUSTOM, TYPE_INT, TEXTURE_3D_INDEX, NO_EXTRA }, + { GL_MAX_3D_TEXTURE_SIZE, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_context, Const.Max3DTextureLevels), NO_EXTRA }, + + /* GL_ARB_fragment_program/OES_standard_derivatives */ + { GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB, + CONTEXT_ENUM(Hint.FragmentShaderDerivative), extra_ARB_fragment_shader }, +#endif /* FEATURE_GL || FEATURE_ES2 */ + +#if FEATURE_ES2 + /* Enums unique to OpenGL ES 2.0 */ + { 0, 0, TYPE_API_MASK, API_OPENGLES2_BIT, NO_EXTRA }, + { GL_MAX_FRAGMENT_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, + { GL_MAX_VARYING_VECTORS, CONTEXT_INT(Const.MaxVarying), NO_EXTRA }, + { GL_MAX_VERTEX_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, + { GL_SHADER_COMPILER, CONST(1), NO_EXTRA }, + /* OES_get_program_binary */ + { GL_NUM_SHADER_BINARY_FORMATS, CONST(0), NO_EXTRA }, + { GL_SHADER_BINARY_FORMATS, CONST(0), NO_EXTRA }, +#endif /* FEATURE_ES2 */ + +#if FEATURE_GL + /* Remaining enums are only in OpenGL */ + { 0, 0, TYPE_API_MASK, API_OPENGL_BIT, NO_EXTRA }, + { GL_ACCUM_RED_BITS, BUFFER_INT(Visual.accumRedBits), NO_EXTRA }, + { GL_ACCUM_GREEN_BITS, BUFFER_INT(Visual.accumGreenBits), NO_EXTRA }, + { GL_ACCUM_BLUE_BITS, BUFFER_INT(Visual.accumBlueBits), NO_EXTRA }, + { GL_ACCUM_ALPHA_BITS, BUFFER_INT(Visual.accumAlphaBits), NO_EXTRA }, + { GL_ACCUM_CLEAR_VALUE, CONTEXT_FIELD(Accum.ClearColor[0], TYPE_FLOATN_4), NO_EXTRA }, + { GL_ALPHA_BIAS, CONTEXT_FLOAT(Pixel.AlphaBias), NO_EXTRA }, + { GL_ALPHA_SCALE, CONTEXT_FLOAT(Pixel.AlphaScale), NO_EXTRA }, + { GL_ATTRIB_STACK_DEPTH, CONTEXT_INT(AttribStackDepth), NO_EXTRA }, + { GL_AUTO_NORMAL, CONTEXT_BOOL(Eval.AutoNormal), NO_EXTRA }, + { GL_AUX_BUFFERS, BUFFER_INT(Visual.numAuxBuffers), NO_EXTRA }, + { GL_BLUE_BIAS, CONTEXT_FLOAT(Pixel.BlueBias), NO_EXTRA }, + { GL_BLUE_SCALE, CONTEXT_FLOAT(Pixel.BlueScale), NO_EXTRA }, + { GL_CLIENT_ATTRIB_STACK_DEPTH, CONTEXT_INT(ClientAttribStackDepth), NO_EXTRA }, + { GL_COLOR_MATERIAL_FACE, CONTEXT_ENUM(Light.ColorMaterialFace), NO_EXTRA }, + { GL_COLOR_MATERIAL_PARAMETER, CONTEXT_ENUM(Light.ColorMaterialMode), NO_EXTRA }, + { GL_CURRENT_INDEX, + CONTEXT_FLOAT(Current.Attrib[VERT_ATTRIB_COLOR_INDEX][0]), + extra_flush_current }, + { GL_CURRENT_RASTER_COLOR, + CONTEXT_FIELD(Current.RasterColor[0], TYPE_FLOATN_4), NO_EXTRA }, + { GL_CURRENT_RASTER_DISTANCE, CONTEXT_FLOAT(Current.RasterDistance), NO_EXTRA }, + { GL_CURRENT_RASTER_INDEX, CONST(1), NO_EXTRA }, + { GL_CURRENT_RASTER_POSITION, CONTEXT_FLOAT4(Current.RasterPos[0]), NO_EXTRA }, + { GL_CURRENT_RASTER_SECONDARY_COLOR, + CONTEXT_FIELD(Current.RasterSecondaryColor[0], TYPE_FLOATN_4), NO_EXTRA }, + { GL_CURRENT_RASTER_TEXTURE_COORDS, LOC_CUSTOM, TYPE_FLOAT_4, 0, + extra_valid_texture_unit }, + { GL_CURRENT_RASTER_POSITION_VALID, CONTEXT_BOOL(Current.RasterPosValid), NO_EXTRA }, + { GL_DEPTH_BIAS, CONTEXT_FLOAT(Pixel.DepthBias), NO_EXTRA }, + { GL_DEPTH_SCALE, CONTEXT_FLOAT(Pixel.DepthScale), NO_EXTRA }, + { GL_DOUBLEBUFFER, BUFFER_INT(Visual.doubleBufferMode), NO_EXTRA }, + { GL_DRAW_BUFFER, BUFFER_ENUM(ColorDrawBuffer[0]), NO_EXTRA }, + { GL_EDGE_FLAG, LOC_CUSTOM, TYPE_BOOLEAN, 0, NO_EXTRA }, + { GL_FEEDBACK_BUFFER_SIZE, CONTEXT_INT(Feedback.BufferSize), NO_EXTRA }, + { GL_FEEDBACK_BUFFER_TYPE, CONTEXT_ENUM(Feedback.Type), NO_EXTRA }, + { GL_FOG_INDEX, CONTEXT_FLOAT(Fog.Index), NO_EXTRA }, + { GL_GREEN_BIAS, CONTEXT_FLOAT(Pixel.GreenBias), NO_EXTRA }, + { GL_GREEN_SCALE, CONTEXT_FLOAT(Pixel.GreenScale), NO_EXTRA }, + { GL_INDEX_BITS, BUFFER_INT(Visual.indexBits), extra_new_buffers }, + { GL_INDEX_CLEAR_VALUE, CONTEXT_INT(Color.ClearIndex), NO_EXTRA }, + { GL_INDEX_MODE, CONST(0) , NO_EXTRA}, + { GL_INDEX_OFFSET, CONTEXT_INT(Pixel.IndexOffset), NO_EXTRA }, + { GL_INDEX_SHIFT, CONTEXT_INT(Pixel.IndexShift), NO_EXTRA }, + { GL_INDEX_WRITEMASK, CONTEXT_INT(Color.IndexMask), NO_EXTRA }, + { GL_LIGHT_MODEL_COLOR_CONTROL, CONTEXT_ENUM(Light.Model.ColorControl), NO_EXTRA }, + { GL_LIGHT_MODEL_LOCAL_VIEWER, CONTEXT_BOOL(Light.Model.LocalViewer), NO_EXTRA }, + { GL_LINE_STIPPLE, CONTEXT_BOOL(Line.StippleFlag), NO_EXTRA }, + { GL_LINE_STIPPLE_PATTERN, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, + { GL_LINE_STIPPLE_REPEAT, CONTEXT_INT(Line.StippleFactor), NO_EXTRA }, + { GL_LINE_WIDTH_GRANULARITY, CONTEXT_FLOAT(Const.LineWidthGranularity), NO_EXTRA }, + { GL_LIST_BASE, CONTEXT_INT(List.ListBase), NO_EXTRA }, + { GL_LIST_INDEX, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, + { GL_LIST_MODE, LOC_CUSTOM, TYPE_ENUM, 0, NO_EXTRA }, + { GL_INDEX_LOGIC_OP, CONTEXT_BOOL(Color.IndexLogicOpEnabled), NO_EXTRA }, + { GL_MAP1_COLOR_4, CONTEXT_BOOL(Eval.Map1Color4), NO_EXTRA }, + { GL_MAP1_GRID_DOMAIN, CONTEXT_FLOAT2(Eval.MapGrid1u1), NO_EXTRA }, + { GL_MAP1_GRID_SEGMENTS, CONTEXT_INT(Eval.MapGrid1un), NO_EXTRA }, + { GL_MAP1_INDEX, CONTEXT_BOOL(Eval.Map1Index), NO_EXTRA }, + { GL_MAP1_NORMAL, CONTEXT_BOOL(Eval.Map1Normal), NO_EXTRA }, + { GL_MAP1_TEXTURE_COORD_1, CONTEXT_BOOL(Eval.Map1TextureCoord1), NO_EXTRA }, + { GL_MAP1_TEXTURE_COORD_2, CONTEXT_BOOL(Eval.Map1TextureCoord2), NO_EXTRA }, + { GL_MAP1_TEXTURE_COORD_3, CONTEXT_BOOL(Eval.Map1TextureCoord3), NO_EXTRA }, + { GL_MAP1_TEXTURE_COORD_4, CONTEXT_BOOL(Eval.Map1TextureCoord4), NO_EXTRA }, + { GL_MAP1_VERTEX_3, CONTEXT_BOOL(Eval.Map1Vertex3), NO_EXTRA }, + { GL_MAP1_VERTEX_4, CONTEXT_BOOL(Eval.Map1Vertex4), NO_EXTRA }, + { GL_MAP2_COLOR_4, CONTEXT_BOOL(Eval.Map2Color4), NO_EXTRA }, + { GL_MAP2_GRID_DOMAIN, LOC_CUSTOM, TYPE_FLOAT_4, 0, NO_EXTRA }, + { GL_MAP2_GRID_SEGMENTS, CONTEXT_INT2(Eval.MapGrid2un), NO_EXTRA }, + { GL_MAP2_INDEX, CONTEXT_BOOL(Eval.Map2Index), NO_EXTRA }, + { GL_MAP2_NORMAL, CONTEXT_BOOL(Eval.Map2Normal), NO_EXTRA }, + { GL_MAP2_TEXTURE_COORD_1, CONTEXT_BOOL(Eval.Map2TextureCoord1), NO_EXTRA }, + { GL_MAP2_TEXTURE_COORD_2, CONTEXT_BOOL(Eval.Map2TextureCoord2), NO_EXTRA }, + { GL_MAP2_TEXTURE_COORD_3, CONTEXT_BOOL(Eval.Map2TextureCoord3), NO_EXTRA }, + { GL_MAP2_TEXTURE_COORD_4, CONTEXT_BOOL(Eval.Map2TextureCoord4), NO_EXTRA }, + { GL_MAP2_VERTEX_3, CONTEXT_BOOL(Eval.Map2Vertex3), NO_EXTRA }, + { GL_MAP2_VERTEX_4, CONTEXT_BOOL(Eval.Map2Vertex4), NO_EXTRA }, + { GL_MAP_COLOR, CONTEXT_BOOL(Pixel.MapColorFlag), NO_EXTRA }, + { GL_MAP_STENCIL, CONTEXT_BOOL(Pixel.MapStencilFlag), NO_EXTRA }, + { GL_MAX_ATTRIB_STACK_DEPTH, CONST(MAX_ATTRIB_STACK_DEPTH), NO_EXTRA }, + { GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, CONST(MAX_CLIENT_ATTRIB_STACK_DEPTH), NO_EXTRA }, + + { GL_MAX_EVAL_ORDER, CONST(MAX_EVAL_ORDER), NO_EXTRA }, + { GL_MAX_LIST_NESTING, CONST(MAX_LIST_NESTING), NO_EXTRA }, + { GL_MAX_NAME_STACK_DEPTH, CONST(MAX_NAME_STACK_DEPTH), NO_EXTRA }, + { GL_MAX_PIXEL_MAP_TABLE, CONST(MAX_PIXEL_MAP_TABLE), NO_EXTRA }, + { GL_NAME_STACK_DEPTH, CONTEXT_INT(Select.NameStackDepth), NO_EXTRA }, + { GL_PACK_LSB_FIRST, CONTEXT_BOOL(Pack.LsbFirst), NO_EXTRA }, + { GL_PACK_ROW_LENGTH, CONTEXT_INT(Pack.RowLength), NO_EXTRA }, + { GL_PACK_SKIP_PIXELS, CONTEXT_INT(Pack.SkipPixels), NO_EXTRA }, + { GL_PACK_SKIP_ROWS, CONTEXT_INT(Pack.SkipRows), NO_EXTRA }, + { GL_PACK_SWAP_BYTES, CONTEXT_BOOL(Pack.SwapBytes), NO_EXTRA }, + { GL_PACK_IMAGE_HEIGHT_EXT, CONTEXT_INT(Pack.ImageHeight), NO_EXTRA }, + { GL_PACK_INVERT_MESA, CONTEXT_BOOL(Pack.Invert), NO_EXTRA }, + { GL_PIXEL_MAP_A_TO_A_SIZE, CONTEXT_INT(PixelMaps.AtoA.Size), NO_EXTRA }, + { GL_PIXEL_MAP_B_TO_B_SIZE, CONTEXT_INT(PixelMaps.BtoB.Size), NO_EXTRA }, + { GL_PIXEL_MAP_G_TO_G_SIZE, CONTEXT_INT(PixelMaps.GtoG.Size), NO_EXTRA }, + { GL_PIXEL_MAP_I_TO_A_SIZE, CONTEXT_INT(PixelMaps.ItoA.Size), NO_EXTRA }, + { GL_PIXEL_MAP_I_TO_B_SIZE, CONTEXT_INT(PixelMaps.ItoB.Size), NO_EXTRA }, + { GL_PIXEL_MAP_I_TO_G_SIZE, CONTEXT_INT(PixelMaps.ItoG.Size), NO_EXTRA }, + { GL_PIXEL_MAP_I_TO_I_SIZE, CONTEXT_INT(PixelMaps.ItoI.Size), NO_EXTRA }, + { GL_PIXEL_MAP_I_TO_R_SIZE, CONTEXT_INT(PixelMaps.ItoR.Size), NO_EXTRA }, + { GL_PIXEL_MAP_R_TO_R_SIZE, CONTEXT_INT(PixelMaps.RtoR.Size), NO_EXTRA }, + { GL_PIXEL_MAP_S_TO_S_SIZE, CONTEXT_INT(PixelMaps.StoS.Size), NO_EXTRA }, + { GL_POINT_SIZE_GRANULARITY, CONTEXT_FLOAT(Const.PointSizeGranularity), NO_EXTRA }, + { GL_POLYGON_MODE, CONTEXT_ENUM2(Polygon.FrontMode), NO_EXTRA }, + { GL_POLYGON_OFFSET_BIAS_EXT, CONTEXT_FLOAT(Polygon.OffsetUnits), NO_EXTRA }, + { GL_POLYGON_OFFSET_POINT, CONTEXT_BOOL(Polygon.OffsetPoint), NO_EXTRA }, + { GL_POLYGON_OFFSET_LINE, CONTEXT_BOOL(Polygon.OffsetLine), NO_EXTRA }, + { GL_POLYGON_SMOOTH, CONTEXT_BOOL(Polygon.SmoothFlag), NO_EXTRA }, + { GL_POLYGON_SMOOTH_HINT, CONTEXT_ENUM(Hint.PolygonSmooth), NO_EXTRA }, + { GL_POLYGON_STIPPLE, CONTEXT_BOOL(Polygon.StippleFlag), NO_EXTRA }, + { GL_READ_BUFFER, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, + { GL_RED_BIAS, CONTEXT_FLOAT(Pixel.RedBias), NO_EXTRA }, + { GL_RED_SCALE, CONTEXT_FLOAT(Pixel.RedScale), NO_EXTRA }, + { GL_RENDER_MODE, CONTEXT_ENUM(RenderMode), NO_EXTRA }, + { GL_RGBA_MODE, CONST(1), NO_EXTRA }, + { GL_SELECTION_BUFFER_SIZE, CONTEXT_INT(Select.BufferSize), NO_EXTRA }, + { GL_SHARED_TEXTURE_PALETTE_EXT, CONTEXT_BOOL(Texture.SharedPalette), NO_EXTRA }, + + { GL_STEREO, BUFFER_INT(Visual.stereoMode), NO_EXTRA }, + + { GL_TEXTURE_1D, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA }, + { GL_TEXTURE_3D, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA }, + { GL_TEXTURE_1D_ARRAY_EXT, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA }, + { GL_TEXTURE_2D_ARRAY_EXT, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA }, + + { GL_TEXTURE_BINDING_1D, LOC_CUSTOM, TYPE_INT, TEXTURE_1D_INDEX, NO_EXTRA }, + { GL_TEXTURE_BINDING_1D_ARRAY, LOC_CUSTOM, TYPE_INT, + TEXTURE_1D_ARRAY_INDEX, extra_MESA_texture_array }, + { GL_TEXTURE_BINDING_2D_ARRAY, LOC_CUSTOM, TYPE_INT, + TEXTURE_1D_ARRAY_INDEX, extra_MESA_texture_array }, + { GL_MAX_ARRAY_TEXTURE_LAYERS_EXT, + CONTEXT_INT(Const.MaxArrayTextureLayers), extra_MESA_texture_array }, + + { GL_TEXTURE_GEN_S, LOC_TEXUNIT, TYPE_BIT_0, + offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, + { GL_TEXTURE_GEN_T, LOC_TEXUNIT, TYPE_BIT_1, + offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, + { GL_TEXTURE_GEN_R, LOC_TEXUNIT, TYPE_BIT_2, + offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, + { GL_TEXTURE_GEN_Q, LOC_TEXUNIT, TYPE_BIT_3, + offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, + { GL_UNPACK_LSB_FIRST, CONTEXT_BOOL(Unpack.LsbFirst), NO_EXTRA }, + { GL_UNPACK_ROW_LENGTH, CONTEXT_INT(Unpack.RowLength), NO_EXTRA }, + { GL_UNPACK_SKIP_PIXELS, CONTEXT_INT(Unpack.SkipPixels), NO_EXTRA }, + { GL_UNPACK_SKIP_ROWS, CONTEXT_INT(Unpack.SkipRows), NO_EXTRA }, + { GL_UNPACK_SWAP_BYTES, CONTEXT_BOOL(Unpack.SwapBytes), NO_EXTRA }, + { GL_UNPACK_SKIP_IMAGES_EXT, CONTEXT_INT(Unpack.SkipImages), NO_EXTRA }, + { GL_UNPACK_IMAGE_HEIGHT_EXT, CONTEXT_INT(Unpack.ImageHeight), NO_EXTRA }, + { GL_UNPACK_CLIENT_STORAGE_APPLE, CONTEXT_BOOL(Unpack.ClientStorage), NO_EXTRA }, + { GL_ZOOM_X, CONTEXT_FLOAT(Pixel.ZoomX), NO_EXTRA }, + { GL_ZOOM_Y, CONTEXT_FLOAT(Pixel.ZoomY), NO_EXTRA }, + + /* Vertex arrays */ + { GL_VERTEX_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, + { GL_NORMAL_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, + { GL_COLOR_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, + { GL_INDEX_ARRAY, ARRAY_BOOL(Index.Enabled), NO_EXTRA }, + { GL_INDEX_ARRAY_TYPE, ARRAY_ENUM(Index.Type), NO_EXTRA }, + { GL_INDEX_ARRAY_STRIDE, ARRAY_INT(Index.Stride), NO_EXTRA }, + { GL_INDEX_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, + { GL_TEXTURE_COORD_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, + { GL_EDGE_FLAG_ARRAY, ARRAY_BOOL(EdgeFlag.Enabled), NO_EXTRA }, + { GL_EDGE_FLAG_ARRAY_STRIDE, ARRAY_INT(EdgeFlag.Stride), NO_EXTRA }, + { GL_EDGE_FLAG_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, + + /* GL_ARB_texture_compression */ + { GL_TEXTURE_COMPRESSION_HINT_ARB, CONTEXT_INT(Hint.TextureCompression), NO_EXTRA }, + + /* GL_EXT_compiled_vertex_array */ + { GL_ARRAY_ELEMENT_LOCK_FIRST_EXT, CONTEXT_INT(Array.LockFirst), + extra_EXT_compiled_vertex_array }, + { GL_ARRAY_ELEMENT_LOCK_COUNT_EXT, CONTEXT_INT(Array.LockCount), + extra_EXT_compiled_vertex_array }, + + /* GL_ARB_transpose_matrix */ + { GL_TRANSPOSE_MODELVIEW_MATRIX_ARB, + CONTEXT_MATRIX_T(ModelviewMatrixStack), NO_EXTRA }, + { GL_TRANSPOSE_PROJECTION_MATRIX_ARB, + CONTEXT_MATRIX_T(ProjectionMatrixStack.Top), NO_EXTRA }, + { GL_TRANSPOSE_TEXTURE_MATRIX_ARB, CONTEXT_MATRIX_T(TextureMatrixStack), NO_EXTRA }, + + /* GL_EXT_secondary_color */ + { GL_COLOR_SUM_EXT, CONTEXT_BOOL(Fog.ColorSumEnabled), + extra_EXT_secondary_color_ARB_vertex_program }, + { GL_CURRENT_SECONDARY_COLOR_EXT, + CONTEXT_FIELD(Current.Attrib[VERT_ATTRIB_COLOR1][0], TYPE_FLOATN_4), + extra_EXT_secondary_color_flush_current }, + { GL_SECONDARY_COLOR_ARRAY_EXT, ARRAY_BOOL(SecondaryColor.Enabled), + extra_EXT_secondary_color }, + { GL_SECONDARY_COLOR_ARRAY_TYPE_EXT, ARRAY_ENUM(SecondaryColor.Type), + extra_EXT_secondary_color }, + { GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT, ARRAY_INT(SecondaryColor.Stride), + extra_EXT_secondary_color }, + { GL_SECONDARY_COLOR_ARRAY_SIZE_EXT, ARRAY_INT(SecondaryColor.Size), + extra_EXT_secondary_color }, + + /* GL_EXT_fog_coord */ + { GL_CURRENT_FOG_COORDINATE_EXT, + CONTEXT_FLOAT(Current.Attrib[VERT_ATTRIB_FOG][0]), + extra_EXT_fog_coord_flush_current }, + { GL_FOG_COORDINATE_ARRAY_EXT, ARRAY_BOOL(FogCoord.Enabled), + extra_EXT_fog_coord }, + { GL_FOG_COORDINATE_ARRAY_TYPE_EXT, ARRAY_ENUM(FogCoord.Type), + extra_EXT_fog_coord }, + { GL_FOG_COORDINATE_ARRAY_STRIDE_EXT, ARRAY_INT(FogCoord.Stride), + extra_EXT_fog_coord }, + { GL_FOG_COORDINATE_SOURCE_EXT, CONTEXT_ENUM(Fog.FogCoordinateSource), + extra_EXT_fog_coord }, + + /* GL_IBM_rasterpos_clip */ + { GL_RASTER_POSITION_UNCLIPPED_IBM, + CONTEXT_BOOL(Transform.RasterPositionUnclipped), + extra_IBM_rasterpos_clip }, + + /* GL_NV_point_sprite */ + { GL_POINT_SPRITE_R_MODE_NV, + CONTEXT_ENUM(Point.SpriteRMode), extra_NV_point_sprite }, + { GL_POINT_SPRITE_COORD_ORIGIN, CONTEXT_ENUM(Point.SpriteOrigin), + extra_NV_point_sprite_ARB_point_sprite }, + + /* GL_NV_vertex_program */ + { GL_VERTEX_PROGRAM_BINDING_NV, LOC_CUSTOM, TYPE_INT, 0, + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY0_NV, ARRAY_BOOL(VertexAttrib[0].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY1_NV, ARRAY_BOOL(VertexAttrib[1].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY2_NV, ARRAY_BOOL(VertexAttrib[2].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY3_NV, ARRAY_BOOL(VertexAttrib[3].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY4_NV, ARRAY_BOOL(VertexAttrib[4].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY5_NV, ARRAY_BOOL(VertexAttrib[5].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY6_NV, ARRAY_BOOL(VertexAttrib[6].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY7_NV, ARRAY_BOOL(VertexAttrib[7].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY8_NV, ARRAY_BOOL(VertexAttrib[8].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY9_NV, ARRAY_BOOL(VertexAttrib[9].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY10_NV, ARRAY_BOOL(VertexAttrib[10].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY11_NV, ARRAY_BOOL(VertexAttrib[11].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY12_NV, ARRAY_BOOL(VertexAttrib[12].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY13_NV, ARRAY_BOOL(VertexAttrib[13].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY14_NV, ARRAY_BOOL(VertexAttrib[14].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY15_NV, ARRAY_BOOL(VertexAttrib[15].Enabled), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB0_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[0]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB1_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[1]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB2_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[2]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB3_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[3]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB4_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[4]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB5_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[5]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB6_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[6]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB7_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[7]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB8_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[8]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB9_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[9]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB10_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[10]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB11_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[11]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB12_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[12]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB13_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[13]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB14_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[14]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB15_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[15]), + extra_NV_vertex_program }, + + /* GL_NV_fragment_program */ + { GL_FRAGMENT_PROGRAM_NV, CONTEXT_BOOL(FragmentProgram.Enabled), + extra_NV_fragment_program }, + { GL_FRAGMENT_PROGRAM_BINDING_NV, LOC_CUSTOM, TYPE_INT, 0, + extra_NV_fragment_program }, + { GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV, + CONST(MAX_NV_FRAGMENT_PROGRAM_PARAMS), + extra_NV_fragment_program }, + + /* GL_NV_texture_rectangle */ + { GL_TEXTURE_RECTANGLE_NV, + LOC_CUSTOM, TYPE_BOOLEAN, 0, extra_NV_texture_rectangle }, + { GL_TEXTURE_BINDING_RECTANGLE_NV, + LOC_CUSTOM, TYPE_INT, TEXTURE_RECT_INDEX, extra_NV_texture_rectangle }, + { GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, + CONTEXT_INT(Const.MaxTextureRectSize), extra_NV_texture_rectangle }, + + /* GL_EXT_stencil_two_side */ + { GL_STENCIL_TEST_TWO_SIDE_EXT, CONTEXT_BOOL(Stencil.TestTwoSide), + extra_EXT_stencil_two_side }, + { GL_ACTIVE_STENCIL_FACE_EXT, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, + + /* GL_NV_light_max_exponent */ + { GL_MAX_SHININESS_NV, CONTEXT_FLOAT(Const.MaxShininess), + extra_NV_light_max_exponent }, + { GL_MAX_SPOT_EXPONENT_NV, CONTEXT_FLOAT(Const.MaxSpotExponent), + extra_NV_light_max_exponent }, + + /* GL_NV_primitive_restart */ + { GL_PRIMITIVE_RESTART_NV, CONTEXT_BOOL(Array.PrimitiveRestart), + extra_NV_primitive_restart }, + { GL_PRIMITIVE_RESTART_INDEX_NV, CONTEXT_INT(Array.RestartIndex), + extra_NV_primitive_restart }, + + /* GL_ARB_vertex_buffer_object */ + { GL_INDEX_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_array_object, Index.BufferObj), NO_EXTRA }, + { GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_array_object, EdgeFlag.BufferObj), NO_EXTRA }, + { GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_array_object, SecondaryColor.BufferObj), NO_EXTRA }, + { GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_array_object, FogCoord.BufferObj), NO_EXTRA }, + + /* GL_EXT_pixel_buffer_object */ + { GL_PIXEL_PACK_BUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0, + extra_EXT_pixel_buffer_object }, + { GL_PIXEL_UNPACK_BUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0, + extra_EXT_pixel_buffer_object }, + + /* GL_ARB_vertex_program */ + { GL_VERTEX_PROGRAM_ARB, /* == GL_VERTEX_PROGRAM_NV */ + CONTEXT_BOOL(VertexProgram.Enabled), + extra_ARB_vertex_program_NV_vertex_program }, + { GL_VERTEX_PROGRAM_POINT_SIZE_ARB, /* == GL_VERTEX_PROGRAM_POINT_SIZE_NV*/ + CONTEXT_BOOL(VertexProgram.PointSizeEnabled), + extra_ARB_vertex_program_NV_vertex_program }, + { GL_VERTEX_PROGRAM_TWO_SIDE_ARB, /* == GL_VERTEX_PROGRAM_TWO_SIDE_NV */ + CONTEXT_BOOL(VertexProgram.TwoSideEnabled), + extra_ARB_vertex_program_NV_vertex_program }, + { GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB, /* == GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV */ + CONTEXT_INT(Const.MaxProgramMatrixStackDepth), + extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, + { GL_MAX_PROGRAM_MATRICES_ARB, /* == GL_MAX_TRACK_MATRICES_NV */ + CONTEXT_INT(Const.MaxProgramMatrices), + extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, + { GL_CURRENT_MATRIX_STACK_DEPTH_ARB, /* == GL_CURRENT_MATRIX_STACK_DEPTH_NV */ + LOC_CUSTOM, TYPE_INT, 0, + extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, + + { GL_CURRENT_MATRIX_ARB, /* == GL_CURRENT_MATRIX_NV */ + LOC_CUSTOM, TYPE_MATRIX, 0, + extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, + { GL_TRANSPOSE_CURRENT_MATRIX_ARB, /* == GL_CURRENT_MATRIX_NV */ + LOC_CUSTOM, TYPE_MATRIX, 0, + extra_ARB_vertex_program_ARB_fragment_program }, + + { GL_PROGRAM_ERROR_POSITION_ARB, /* == GL_PROGRAM_ERROR_POSITION_NV */ + CONTEXT_INT(Program.ErrorPos), + extra_NV_vertex_program_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, + + /* GL_ARB_fragment_program */ + { GL_FRAGMENT_PROGRAM_ARB, CONTEXT_BOOL(FragmentProgram.Enabled), + extra_ARB_fragment_program }, + + /* GL_EXT_depth_bounds_test */ + { GL_DEPTH_BOUNDS_TEST_EXT, CONTEXT_BOOL(Depth.BoundsTest), + extra_EXT_depth_bounds_test }, + { GL_DEPTH_BOUNDS_EXT, CONTEXT_FLOAT2(Depth.BoundsMin), + extra_EXT_depth_bounds_test }, + + /* GL_ARB_depth_clamp*/ + { GL_DEPTH_CLAMP, CONTEXT_BOOL(Transform.DepthClamp), + extra_ARB_depth_clamp }, + + /* GL_ARB_draw_buffers */ + { GL_DRAW_BUFFER0_ARB, BUFFER_ENUM(ColorDrawBuffer[0]), NO_EXTRA }, + { GL_DRAW_BUFFER1_ARB, BUFFER_ENUM(ColorDrawBuffer[1]), + extra_valid_draw_buffer }, + { GL_DRAW_BUFFER2_ARB, BUFFER_ENUM(ColorDrawBuffer[2]), + extra_valid_draw_buffer }, + { GL_DRAW_BUFFER3_ARB, BUFFER_ENUM(ColorDrawBuffer[3]), + extra_valid_draw_buffer }, + { GL_DRAW_BUFFER4_ARB, BUFFER_ENUM(ColorDrawBuffer[4]), + extra_valid_draw_buffer }, + { GL_DRAW_BUFFER5_ARB, BUFFER_ENUM(ColorDrawBuffer[5]), + extra_valid_draw_buffer }, + { GL_DRAW_BUFFER6_ARB, BUFFER_ENUM(ColorDrawBuffer[6]), + extra_valid_draw_buffer }, + { GL_DRAW_BUFFER7_ARB, BUFFER_ENUM(ColorDrawBuffer[7]), + extra_valid_draw_buffer }, + + /* GL_ATI_fragment_shader */ + { GL_NUM_FRAGMENT_REGISTERS_ATI, CONST(6), extra_ATI_fragment_shader }, + { GL_NUM_FRAGMENT_CONSTANTS_ATI, CONST(8), extra_ATI_fragment_shader }, + { GL_NUM_PASSES_ATI, CONST(2), extra_ATI_fragment_shader }, + { GL_NUM_INSTRUCTIONS_PER_PASS_ATI, CONST(8), extra_ATI_fragment_shader }, + { GL_NUM_INSTRUCTIONS_TOTAL_ATI, CONST(16), extra_ATI_fragment_shader }, + { GL_COLOR_ALPHA_PAIRING_ATI, CONST(GL_TRUE), extra_ATI_fragment_shader }, + { GL_NUM_LOOPBACK_COMPONENTS_ATI, CONST(3), extra_ATI_fragment_shader }, + { GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI, + CONST(3), extra_ATI_fragment_shader }, + + /* GL_EXT_framebuffer_object */ + { GL_MAX_COLOR_ATTACHMENTS_EXT, CONTEXT_INT(Const.MaxColorAttachments), + extra_EXT_framebuffer_object }, + + /* GL_EXT_framebuffer_blit + * NOTE: GL_DRAW_FRAMEBUFFER_BINDING_EXT == GL_FRAMEBUFFER_BINDING_EXT */ + { GL_READ_FRAMEBUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0, + extra_EXT_framebuffer_blit }, + + /* GL_EXT_provoking_vertex */ + { GL_PROVOKING_VERTEX_EXT, + CONTEXT_BOOL(Light.ProvokingVertex), extra_EXT_provoking_vertex }, + { GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT, + CONTEXT_BOOL(Const.QuadsFollowProvokingVertexConvention), + extra_EXT_provoking_vertex }, + + /* GL_ARB_framebuffer_object */ + { GL_MAX_SAMPLES, CONTEXT_INT(Const.MaxSamples), + extra_ARB_framebuffer_object_EXT_framebuffer_multisample }, + + /* GL_APPLE_vertex_array_object */ + { GL_VERTEX_ARRAY_BINDING_APPLE, ARRAY_INT(Name), + extra_APPLE_vertex_array_object }, + + /* GL_ARB_seamless_cube_map */ + { GL_TEXTURE_CUBE_MAP_SEAMLESS, + CONTEXT_BOOL(Texture.CubeMapSeamless), extra_ARB_seamless_cube_map }, + + /* GL_ARB_sync */ + { GL_MAX_SERVER_WAIT_TIMEOUT, + CONTEXT_INT64(Const.MaxServerWaitTimeout), extra_ARB_sync }, + + /* GL_EXT_texture_integer */ + { GL_RGBA_INTEGER_MODE_EXT, BUFFER_BOOL(_IntegerColor), + extra_EXT_texture_integer }, + + /* GL_EXT_transform_feedback */ + { GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, LOC_CUSTOM, TYPE_INT, 0, + extra_EXT_transform_feedback }, + { GL_RASTERIZER_DISCARD, CONTEXT_BOOL(TransformFeedback.RasterDiscard), + extra_EXT_transform_feedback }, + { GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, + CONTEXT_INT(Const.MaxTransformFeedbackInterleavedComponents), + extra_EXT_transform_feedback }, + { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, + CONTEXT_INT(Const.MaxTransformFeedbackSeparateAttribs), + extra_EXT_transform_feedback }, + { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, + CONTEXT_INT(Const.MaxTransformFeedbackSeparateComponents), + extra_EXT_transform_feedback }, + + /* GL_ARB_transform_feedback2 */ + { GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED, LOC_CUSTOM, TYPE_BOOLEAN, 0, + extra_ARB_transform_feedback2 }, + { GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE, LOC_CUSTOM, TYPE_BOOLEAN, 0, + extra_ARB_transform_feedback2 }, + { GL_TRANSFORM_FEEDBACK_BINDING, LOC_CUSTOM, TYPE_INT, 0, + extra_ARB_transform_feedback2 }, + + /* GL_ARB_geometry_shader4 */ + { GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB, + CONTEXT_INT(Const.GeometryProgram.MaxGeometryTextureImageUnits), + extra_ARB_geometry_shader4 }, + { GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB, + CONTEXT_INT(Const.GeometryProgram.MaxGeometryOutputVertices), + extra_ARB_geometry_shader4 }, + { GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB, + CONTEXT_INT(Const.GeometryProgram.MaxGeometryTotalOutputComponents), + extra_ARB_geometry_shader4 }, + { GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB, + CONTEXT_INT(Const.GeometryProgram.MaxGeometryUniformComponents), + extra_ARB_geometry_shader4 }, + { GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB, + CONTEXT_INT(Const.GeometryProgram.MaxGeometryVaryingComponents), + extra_ARB_geometry_shader4 }, + { GL_MAX_VERTEX_VARYING_COMPONENTS_ARB, + CONTEXT_INT(Const.GeometryProgram.MaxVertexVaryingComponents), + extra_ARB_geometry_shader4 }, + + /* GL_EXT_gpu_shader4 / GL 3.0 */ + { GL_MIN_PROGRAM_TEXEL_OFFSET, + CONTEXT_INT(Const.MinProgramTexelOffset), + extra_EXT_gpu_shader4 }, + { GL_MAX_PROGRAM_TEXEL_OFFSET, + CONTEXT_INT(Const.MaxProgramTexelOffset), + extra_EXT_gpu_shader4 }, + + /* GL 3.0 */ + { GL_NUM_EXTENSIONS, LOC_CUSTOM, TYPE_INT, 0, extra_version_30 }, + { GL_MAJOR_VERSION, CONTEXT_INT(VersionMajor), extra_version_30 }, + { GL_MINOR_VERSION, CONTEXT_INT(VersionMinor), extra_version_30 }, + { GL_CONTEXT_FLAGS, CONTEXT_INT(Const.ContextFlags), extra_version_30 }, + + /* GL3.0 / GL_EXT_framebuffer_sRGB */ + { GL_FRAMEBUFFER_SRGB_EXT, CONTEXT_BOOL(Color.sRGBEnabled), extra_EXT_framebuffer_sRGB }, + { GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, BUFFER_INT(Visual.sRGBCapable), extra_EXT_framebuffer_sRGB }, + + /* GL 3.1 */ + /* NOTE: different enum values for GL_PRIMITIVE_RESTART_NV + * vs. GL_PRIMITIVE_RESTART! + */ + { GL_PRIMITIVE_RESTART, CONTEXT_BOOL(Array.PrimitiveRestart), + extra_version_31 }, + { GL_PRIMITIVE_RESTART_INDEX, CONTEXT_INT(Array.RestartIndex), + extra_version_31 }, + + + /* GL 3.2 */ + { GL_CONTEXT_PROFILE_MASK, CONTEXT_INT(Const.ProfileMask), + extra_version_32 }, +#endif /* FEATURE_GL */ +}; + +/* All we need now is a way to look up the value struct from the enum. + * The code generated by gcc for the old generated big switch + * statement is a big, balanced, open coded if/else tree, essentially + * an unrolled binary search. It would be natural to sort the new + * enum table and use bsearch(), but we will use a read-only hash + * table instead. bsearch() has a nice guaranteed worst case + * performance, but we're also guaranteed to hit that worst case + * (log2(n) iterations) for about half the enums. Instead, using an + * open addressing hash table, we can find the enum on the first try + * for 80% of the enums, 1 collision for 10% and never more than 5 + * collisions for any enum (typical numbers). And the code is very + * simple, even though it feels a little magic. */ + +static unsigned short table[1024]; +static const int prime_factor = 89, prime_step = 281; + +#ifdef GET_DEBUG +static void +print_table_stats(void) +{ + int i, j, collisions[11], count, hash, mask; + const struct value_desc *d; + + count = 0; + mask = Elements(table) - 1; + memset(collisions, 0, sizeof collisions); + + for (i = 0; i < Elements(table); i++) { + if (!table[i]) + continue; + count++; + d = &values[table[i]]; + hash = (d->pname * prime_factor); + j = 0; + while (1) { + if (values[table[hash & mask]].pname == d->pname) + break; + hash += prime_step; + j++; + } + + if (j < 10) + collisions[j]++; + else + collisions[10]++; + } + + printf("number of enums: %d (total %d)\n", count, Elements(values)); + for (i = 0; i < Elements(collisions) - 1; i++) + if (collisions[i] > 0) + printf(" %d enums with %d %scollisions\n", + collisions[i], i, i == 10 ? "or more " : ""); +} +#endif + +/** + * Initialize the enum hash for a given API + * + * This is called from one_time_init() to insert the enum values that + * are valid for the API in question into the enum hash table. + * + * \param the current context, for determining the API in question + */ +void _mesa_init_get_hash(struct gl_context *ctx) +{ + int i, hash, index, mask; + int api_mask = 0, api_bit; + + mask = Elements(table) - 1; + api_bit = 1 << ctx->API; + + for (i = 0; i < Elements(values); i++) { + if (values[i].type == TYPE_API_MASK) { + api_mask = values[i].offset; + continue; + } + if (!(api_mask & api_bit)) + continue; + + hash = (values[i].pname * prime_factor) & mask; + while (1) { + index = hash & mask; + if (!table[index]) { + table[index] = i; + break; + } + hash += prime_step; + } + } + +#ifdef GET_DEBUG + print_table_stats(); +#endif +} + +/** + * Handle irregular enums + * + * Some values don't conform to the "well-known type at context + * pointer + offset" pattern, so we have this function to catch all + * the corner cases. Typically, it's a computed value or a one-off + * pointer to a custom struct or something. + * + * In this case we can't return a pointer to the value, so we'll have + * to use the temporary variable 'v' declared back in the calling + * glGet*v() function to store the result. + * + * \param ctx the current context + * \param d the struct value_desc that describes the enum + * \param v pointer to the tmp declared in the calling glGet*v() function + */ +static void +find_custom_value(struct gl_context *ctx, const struct value_desc *d, union value *v) +{ + struct gl_buffer_object *buffer_obj; + struct gl_client_array *array; + GLuint unit, *p; + + switch (d->pname) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + case GL_TEXTURE_1D_ARRAY_EXT: + case GL_TEXTURE_2D_ARRAY_EXT: + case GL_TEXTURE_CUBE_MAP_ARB: + case GL_TEXTURE_RECTANGLE_NV: + v->value_bool = _mesa_IsEnabled(d->pname); + break; + + case GL_LINE_STIPPLE_PATTERN: + /* This is the only GLushort, special case it here by promoting + * to an int rather than introducing a new type. */ + v->value_int = ctx->Line.StipplePattern; + break; + + case GL_CURRENT_RASTER_TEXTURE_COORDS: + unit = ctx->Texture.CurrentUnit; + v->value_float_4[0] = ctx->Current.RasterTexCoords[unit][0]; + v->value_float_4[1] = ctx->Current.RasterTexCoords[unit][1]; + v->value_float_4[2] = ctx->Current.RasterTexCoords[unit][2]; + v->value_float_4[3] = ctx->Current.RasterTexCoords[unit][3]; + break; + + case GL_CURRENT_TEXTURE_COORDS: + unit = ctx->Texture.CurrentUnit; + v->value_float_4[0] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][0]; + v->value_float_4[1] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][1]; + v->value_float_4[2] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][2]; + v->value_float_4[3] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][3]; + break; + + case GL_COLOR_WRITEMASK: + v->value_int_4[0] = ctx->Color.ColorMask[0][RCOMP] ? 1 : 0; + v->value_int_4[1] = ctx->Color.ColorMask[0][GCOMP] ? 1 : 0; + v->value_int_4[2] = ctx->Color.ColorMask[0][BCOMP] ? 1 : 0; + v->value_int_4[3] = ctx->Color.ColorMask[0][ACOMP] ? 1 : 0; + break; + + case GL_EDGE_FLAG: + v->value_bool = ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG][0] == 1.0; + break; + + case GL_READ_BUFFER: + v->value_enum = ctx->ReadBuffer->ColorReadBuffer; + break; + + case GL_MAP2_GRID_DOMAIN: + v->value_float_4[0] = ctx->Eval.MapGrid2u1; + v->value_float_4[1] = ctx->Eval.MapGrid2u2; + v->value_float_4[2] = ctx->Eval.MapGrid2v1; + v->value_float_4[3] = ctx->Eval.MapGrid2v2; + break; + + case GL_TEXTURE_STACK_DEPTH: + unit = ctx->Texture.CurrentUnit; + v->value_int = ctx->TextureMatrixStack[unit].Depth + 1; + break; + case GL_TEXTURE_MATRIX: + unit = ctx->Texture.CurrentUnit; + v->value_matrix = ctx->TextureMatrixStack[unit].Top; + break; + + case GL_TEXTURE_COORD_ARRAY: + case GL_TEXTURE_COORD_ARRAY_SIZE: + case GL_TEXTURE_COORD_ARRAY_TYPE: + case GL_TEXTURE_COORD_ARRAY_STRIDE: + array = &ctx->Array.ArrayObj->TexCoord[ctx->Array.ActiveTexture]; + v->value_int = *(GLuint *) ((char *) array + d->offset); + break; + + case GL_ACTIVE_TEXTURE_ARB: + v->value_int = GL_TEXTURE0_ARB + ctx->Texture.CurrentUnit; + break; + case GL_CLIENT_ACTIVE_TEXTURE_ARB: + v->value_int = GL_TEXTURE0_ARB + ctx->Array.ActiveTexture; + break; + + case GL_MODELVIEW_STACK_DEPTH: + case GL_PROJECTION_STACK_DEPTH: + v->value_int = *(GLint *) ((char *) ctx + d->offset) + 1; + break; + + case GL_MAX_TEXTURE_SIZE: + case GL_MAX_3D_TEXTURE_SIZE: + case GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB: + p = (GLuint *) ((char *) ctx + d->offset); + v->value_int = 1 << (*p - 1); + break; + + case GL_SCISSOR_BOX: + v->value_int_4[0] = ctx->Scissor.X; + v->value_int_4[1] = ctx->Scissor.Y; + v->value_int_4[2] = ctx->Scissor.Width; + v->value_int_4[3] = ctx->Scissor.Height; + break; + + case GL_LIST_INDEX: + v->value_int = + ctx->ListState.CurrentList ? ctx->ListState.CurrentList->Name : 0; + break; + case GL_LIST_MODE: + if (!ctx->CompileFlag) + v->value_enum = 0; + else if (ctx->ExecuteFlag) + v->value_enum = GL_COMPILE_AND_EXECUTE; + else + v->value_enum = GL_COMPILE; + break; + + case GL_VIEWPORT: + v->value_int_4[0] = ctx->Viewport.X; + v->value_int_4[1] = ctx->Viewport.Y; + v->value_int_4[2] = ctx->Viewport.Width; + v->value_int_4[3] = ctx->Viewport.Height; + break; + + case GL_ACTIVE_STENCIL_FACE_EXT: + v->value_enum = ctx->Stencil.ActiveFace ? GL_BACK : GL_FRONT; + break; + + case GL_STENCIL_FAIL: + v->value_enum = ctx->Stencil.FailFunc[ctx->Stencil.ActiveFace]; + break; + case GL_STENCIL_FUNC: + v->value_enum = ctx->Stencil.Function[ctx->Stencil.ActiveFace]; + break; + case GL_STENCIL_PASS_DEPTH_FAIL: + v->value_enum = ctx->Stencil.ZFailFunc[ctx->Stencil.ActiveFace]; + break; + case GL_STENCIL_PASS_DEPTH_PASS: + v->value_enum = ctx->Stencil.ZPassFunc[ctx->Stencil.ActiveFace]; + break; + case GL_STENCIL_REF: + v->value_int = ctx->Stencil.Ref[ctx->Stencil.ActiveFace]; + break; + case GL_STENCIL_VALUE_MASK: + v->value_int = ctx->Stencil.ValueMask[ctx->Stencil.ActiveFace]; + break; + case GL_STENCIL_WRITEMASK: + v->value_int = ctx->Stencil.WriteMask[ctx->Stencil.ActiveFace]; + break; + + case GL_NUM_EXTENSIONS: + v->value_int = _mesa_get_extension_count(ctx); + break; + + case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES: + v->value_int = _mesa_get_color_read_type(ctx); + break; + case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES: + v->value_int = _mesa_get_color_read_format(ctx); + break; + + case GL_CURRENT_MATRIX_STACK_DEPTH_ARB: + v->value_int = ctx->CurrentStack->Depth + 1; + break; + case GL_CURRENT_MATRIX_ARB: + case GL_TRANSPOSE_CURRENT_MATRIX_ARB: + v->value_matrix = ctx->CurrentStack->Top; + break; + + case GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB: + v->value_int = _mesa_get_compressed_formats(ctx, NULL, GL_FALSE); + break; + case GL_COMPRESSED_TEXTURE_FORMATS_ARB: + v->value_int_n.n = + _mesa_get_compressed_formats(ctx, v->value_int_n.ints, GL_FALSE); + ASSERT(v->value_int_n.n <= 100); + break; + + case GL_MAX_VARYING_FLOATS_ARB: + v->value_int = ctx->Const.MaxVarying * 4; + break; + + /* Various object names */ + + case GL_TEXTURE_BINDING_1D: + case GL_TEXTURE_BINDING_2D: + case GL_TEXTURE_BINDING_3D: + case GL_TEXTURE_BINDING_1D_ARRAY_EXT: + case GL_TEXTURE_BINDING_2D_ARRAY_EXT: + case GL_TEXTURE_BINDING_CUBE_MAP_ARB: + case GL_TEXTURE_BINDING_RECTANGLE_NV: + unit = ctx->Texture.CurrentUnit; + v->value_int = + ctx->Texture.Unit[unit].CurrentTex[d->offset]->Name; + break; + + /* GL_ARB_vertex_buffer_object */ + case GL_VERTEX_ARRAY_BUFFER_BINDING_ARB: + case GL_NORMAL_ARRAY_BUFFER_BINDING_ARB: + case GL_COLOR_ARRAY_BUFFER_BINDING_ARB: + case GL_INDEX_ARRAY_BUFFER_BINDING_ARB: + case GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB: + case GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB: + case GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB: + buffer_obj = (struct gl_buffer_object *) + ((char *) ctx->Array.ArrayObj + d->offset); + v->value_int = buffer_obj->Name; + break; + case GL_ARRAY_BUFFER_BINDING_ARB: + v->value_int = ctx->Array.ArrayBufferObj->Name; + break; + case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB: + v->value_int = + ctx->Array.ArrayObj->TexCoord[ctx->Array.ActiveTexture].BufferObj->Name; + break; + case GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB: + v->value_int = ctx->Array.ElementArrayBufferObj->Name; + break; + + /* ARB_copy_buffer */ + case GL_COPY_READ_BUFFER: + v->value_int = ctx->CopyReadBuffer->Name; + break; + case GL_COPY_WRITE_BUFFER: + v->value_int = ctx->CopyWriteBuffer->Name; + break; + + case GL_FRAGMENT_PROGRAM_BINDING_NV: + v->value_int = + ctx->FragmentProgram.Current ? ctx->FragmentProgram.Current->Base.Id : 0; + break; + case GL_VERTEX_PROGRAM_BINDING_NV: + v->value_int = + ctx->VertexProgram.Current ? ctx->VertexProgram.Current->Base.Id : 0; + break; + case GL_PIXEL_PACK_BUFFER_BINDING_EXT: + v->value_int = ctx->Pack.BufferObj->Name; + break; + case GL_PIXEL_UNPACK_BUFFER_BINDING_EXT: + v->value_int = ctx->Unpack.BufferObj->Name; + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + v->value_int = ctx->TransformFeedback.CurrentBuffer->Name; + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED: + v->value_int = ctx->TransformFeedback.CurrentObject->Paused; + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE: + v->value_int = ctx->TransformFeedback.CurrentObject->Active; + break; + case GL_TRANSFORM_FEEDBACK_BINDING: + v->value_int = ctx->TransformFeedback.CurrentObject->Name; + break; + case GL_CURRENT_PROGRAM: + v->value_int = + ctx->Shader.ActiveProgram ? ctx->Shader.ActiveProgram->Name : 0; + break; + case GL_READ_FRAMEBUFFER_BINDING_EXT: + v->value_int = ctx->ReadBuffer->Name; + break; + case GL_RENDERBUFFER_BINDING_EXT: + v->value_int = + ctx->CurrentRenderbuffer ? ctx->CurrentRenderbuffer->Name : 0; + break; + case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES: + v->value_int = ctx->Array.ArrayObj->PointSize.BufferObj->Name; + break; + + case GL_MAX_VERTEX_UNIFORM_VECTORS: + v->value_int = ctx->Const.VertexProgram.MaxUniformComponents / 4; + break; + + case GL_MAX_FRAGMENT_UNIFORM_VECTORS: + v->value_int = ctx->Const.FragmentProgram.MaxUniformComponents / 4; + break; + } +} + +/** + * Check extra constraints on a struct value_desc descriptor + * + * If a struct value_desc has a non-NULL extra pointer, it means that + * there are a number of extra constraints to check or actions to + * perform. The extras is just an integer array where each integer + * encode different constraints or actions. + * + * \param ctx current context + * \param func name of calling glGet*v() function for error reporting + * \param d the struct value_desc that has the extra constraints + * + * \return GL_FALSE if one of the constraints was not satisfied, + * otherwise GL_TRUE. + */ +static GLboolean +check_extra(struct gl_context *ctx, const char *func, const struct value_desc *d) +{ + const GLuint version = ctx->VersionMajor * 10 + ctx->VersionMinor; + int total, enabled; + const int *e; + + total = 0; + enabled = 0; + for (e = d->extra; *e != EXTRA_END; e++) + switch (*e) { + case EXTRA_VERSION_30: + if (version >= 30) { + total++; + enabled++; + } + break; + case EXTRA_VERSION_31: + if (version >= 31) { + total++; + enabled++; + } + break; + case EXTRA_VERSION_32: + if (version >= 32) { + total++; + enabled++; + } + break; + case EXTRA_VERSION_ES2: + if (ctx->API == API_OPENGLES2) { + total++; + enabled++; + } + break; + case EXTRA_NEW_BUFFERS: + if (ctx->NewState & _NEW_BUFFERS) + _mesa_update_state(ctx); + break; + case EXTRA_FLUSH_CURRENT: + FLUSH_CURRENT(ctx, 0); + break; + case EXTRA_VALID_DRAW_BUFFER: + if (d->pname - GL_DRAW_BUFFER0_ARB >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(draw buffer %u)", + func, d->pname - GL_DRAW_BUFFER0_ARB); + return GL_FALSE; + } + break; + case EXTRA_VALID_TEXTURE_UNIT: + if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(texture %u)", + func, ctx->Texture.CurrentUnit); + return GL_FALSE; + } + break; + case EXTRA_END: + break; + default: /* *e is a offset into the extension struct */ + total++; + if (*(GLboolean *) ((char *) &ctx->Extensions + *e)) + enabled++; + break; + } + + if (total > 0 && enabled == 0) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", func, + _mesa_lookup_enum_by_nr(d->pname)); + return GL_FALSE; + } + + return GL_TRUE; +} + +static const struct value_desc error_value = + { 0, 0, TYPE_INVALID, NO_OFFSET, NO_EXTRA }; + +/** + * Find the struct value_desc corresponding to the enum 'pname'. + * + * We hash the enum value to get an index into the 'table' array, + * which holds the index in the 'values' array of struct value_desc. + * Once we've found the entry, we do the extra checks, if any, then + * look up the value and return a pointer to it. + * + * If the value has to be computed (for example, it's the result of a + * function call or we need to add 1 to it), we use the tmp 'v' to + * store the result. + * + * \param func name of glGet*v() func for error reporting + * \param pname the enum value we're looking up + * \param p is were we return the pointer to the value + * \param v a tmp union value variable in the calling glGet*v() function + * + * \return the struct value_desc corresponding to the enum or a struct + * value_desc of TYPE_INVALID if not found. This lets the calling + * glGet*v() function jump right into a switch statement and + * handle errors there instead of having to check for NULL. + */ +static const struct value_desc * +find_value(const char *func, GLenum pname, void **p, union value *v) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_unit *unit; + int mask, hash; + const struct value_desc *d; + + mask = Elements(table) - 1; + hash = (pname * prime_factor); + while (1) { + d = &values[table[hash & mask]]; + + /* If the enum isn't valid, the hash walk ends with index 0, + * which is the API mask entry at the beginning of values[]. */ + if (unlikely(d->type == TYPE_API_MASK)) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", func, + _mesa_lookup_enum_by_nr(pname)); + return &error_value; + } + + if (likely(d->pname == pname)) + break; + + hash += prime_step; + } + + if (unlikely(d->extra && !check_extra(ctx, func, d))) + return &error_value; + + switch (d->location) { + case LOC_BUFFER: + *p = ((char *) ctx->DrawBuffer + d->offset); + return d; + case LOC_CONTEXT: + *p = ((char *) ctx + d->offset); + return d; + case LOC_ARRAY: + *p = ((char *) ctx->Array.ArrayObj + d->offset); + return d; + case LOC_TEXUNIT: + unit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + *p = ((char *) unit + d->offset); + return d; + case LOC_CUSTOM: + find_custom_value(ctx, d, v); + *p = v; + return d; + default: + assert(0); + break; + } + + /* silence warning */ + return &error_value; +} + +static const int transpose[] = { + 0, 4, 8, 12, + 1, 5, 9, 13, + 2, 6, 10, 14, + 3, 7, 11, 15 +}; + +void GLAPIENTRY +_mesa_GetBooleanv(GLenum pname, GLboolean *params) +{ + const struct value_desc *d; + union value v; + GLmatrix *m; + int shift, i; + void *p; + + d = find_value("glGetBooleanv", pname, &p, &v); + switch (d->type) { + case TYPE_INVALID: + break; + case TYPE_CONST: + params[0] = INT_TO_BOOLEAN(d->offset); + break; + + case TYPE_FLOAT_4: + case TYPE_FLOATN_4: + params[3] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[3]); + case TYPE_FLOAT_3: + case TYPE_FLOATN_3: + params[2] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[2]); + case TYPE_FLOAT_2: + case TYPE_FLOATN_2: + params[1] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[1]); + case TYPE_FLOAT: + case TYPE_FLOATN: + params[0] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[0]); + break; + + case TYPE_DOUBLEN: + params[0] = FLOAT_TO_BOOLEAN(((GLdouble *) p)[0]); + break; + + case TYPE_INT_4: + params[3] = INT_TO_BOOLEAN(((GLint *) p)[3]); + case TYPE_INT_3: + params[2] = INT_TO_BOOLEAN(((GLint *) p)[2]); + case TYPE_INT_2: + case TYPE_ENUM_2: + params[1] = INT_TO_BOOLEAN(((GLint *) p)[1]); + case TYPE_INT: + case TYPE_ENUM: + params[0] = INT_TO_BOOLEAN(((GLint *) p)[0]); + break; + + case TYPE_INT_N: + for (i = 0; i < v.value_int_n.n; i++) + params[i] = INT_TO_BOOLEAN(v.value_int_n.ints[i]); + break; + + case TYPE_INT64: + params[0] = INT64_TO_BOOLEAN(((GLint64 *) p)[0]); + break; + + case TYPE_BOOLEAN: + params[0] = ((GLboolean*) p)[0]; + break; + + case TYPE_MATRIX: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_BOOLEAN(m->m[i]); + break; + + case TYPE_MATRIX_T: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_BOOLEAN(m->m[transpose[i]]); + break; + + case TYPE_BIT_0: + case TYPE_BIT_1: + case TYPE_BIT_2: + case TYPE_BIT_3: + case TYPE_BIT_4: + case TYPE_BIT_5: + shift = d->type - TYPE_BIT_0; + params[0] = (*(GLbitfield *) p >> shift) & 1; + break; + } +} + +void GLAPIENTRY +_mesa_GetFloatv(GLenum pname, GLfloat *params) +{ + const struct value_desc *d; + union value v; + GLmatrix *m; + int shift, i; + void *p; + + d = find_value("glGetFloatv", pname, &p, &v); + switch (d->type) { + case TYPE_INVALID: + break; + case TYPE_CONST: + params[0] = (GLfloat) d->offset; + break; + + case TYPE_FLOAT_4: + case TYPE_FLOATN_4: + params[3] = ((GLfloat *) p)[3]; + case TYPE_FLOAT_3: + case TYPE_FLOATN_3: + params[2] = ((GLfloat *) p)[2]; + case TYPE_FLOAT_2: + case TYPE_FLOATN_2: + params[1] = ((GLfloat *) p)[1]; + case TYPE_FLOAT: + case TYPE_FLOATN: + params[0] = ((GLfloat *) p)[0]; + break; + + case TYPE_DOUBLEN: + params[0] = ((GLdouble *) p)[0]; + break; + + case TYPE_INT_4: + params[3] = (GLfloat) (((GLint *) p)[3]); + case TYPE_INT_3: + params[2] = (GLfloat) (((GLint *) p)[2]); + case TYPE_INT_2: + case TYPE_ENUM_2: + params[1] = (GLfloat) (((GLint *) p)[1]); + case TYPE_INT: + case TYPE_ENUM: + params[0] = (GLfloat) (((GLint *) p)[0]); + break; + + case TYPE_INT_N: + for (i = 0; i < v.value_int_n.n; i++) + params[i] = INT_TO_FLOAT(v.value_int_n.ints[i]); + break; + + case TYPE_INT64: + params[0] = ((GLint64 *) p)[0]; + break; + + case TYPE_BOOLEAN: + params[0] = BOOLEAN_TO_FLOAT(*(GLboolean*) p); + break; + + case TYPE_MATRIX: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = m->m[i]; + break; + + case TYPE_MATRIX_T: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = m->m[transpose[i]]; + break; + + case TYPE_BIT_0: + case TYPE_BIT_1: + case TYPE_BIT_2: + case TYPE_BIT_3: + case TYPE_BIT_4: + case TYPE_BIT_5: + shift = d->type - TYPE_BIT_0; + params[0] = BOOLEAN_TO_FLOAT((*(GLbitfield *) p >> shift) & 1); + break; + } +} + +void GLAPIENTRY +_mesa_GetIntegerv(GLenum pname, GLint *params) +{ + const struct value_desc *d; + union value v; + GLmatrix *m; + int shift, i; + void *p; + + d = find_value("glGetIntegerv", pname, &p, &v); + switch (d->type) { + case TYPE_INVALID: + break; + case TYPE_CONST: + params[0] = d->offset; + break; + + case TYPE_FLOAT_4: + params[3] = IROUND(((GLfloat *) p)[3]); + case TYPE_FLOAT_3: + params[2] = IROUND(((GLfloat *) p)[2]); + case TYPE_FLOAT_2: + params[1] = IROUND(((GLfloat *) p)[1]); + case TYPE_FLOAT: + params[0] = IROUND(((GLfloat *) p)[0]); + break; + + case TYPE_FLOATN_4: + params[3] = FLOAT_TO_INT(((GLfloat *) p)[3]); + case TYPE_FLOATN_3: + params[2] = FLOAT_TO_INT(((GLfloat *) p)[2]); + case TYPE_FLOATN_2: + params[1] = FLOAT_TO_INT(((GLfloat *) p)[1]); + case TYPE_FLOATN: + params[0] = FLOAT_TO_INT(((GLfloat *) p)[0]); + break; + + case TYPE_DOUBLEN: + params[0] = FLOAT_TO_INT(((GLdouble *) p)[0]); + break; + + case TYPE_INT_4: + params[3] = ((GLint *) p)[3]; + case TYPE_INT_3: + params[2] = ((GLint *) p)[2]; + case TYPE_INT_2: + case TYPE_ENUM_2: + params[1] = ((GLint *) p)[1]; + case TYPE_INT: + case TYPE_ENUM: + params[0] = ((GLint *) p)[0]; + break; + + case TYPE_INT_N: + for (i = 0; i < v.value_int_n.n; i++) + params[i] = v.value_int_n.ints[i]; + break; + + case TYPE_INT64: + params[0] = INT64_TO_INT(((GLint64 *) p)[0]); + break; + + case TYPE_BOOLEAN: + params[0] = BOOLEAN_TO_INT(*(GLboolean*) p); + break; + + case TYPE_MATRIX: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_INT(m->m[i]); + break; + + case TYPE_MATRIX_T: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_INT(m->m[transpose[i]]); + break; + + case TYPE_BIT_0: + case TYPE_BIT_1: + case TYPE_BIT_2: + case TYPE_BIT_3: + case TYPE_BIT_4: + case TYPE_BIT_5: + shift = d->type - TYPE_BIT_0; + params[0] = (*(GLbitfield *) p >> shift) & 1; + break; + } +} + +#if FEATURE_ARB_sync +void GLAPIENTRY +_mesa_GetInteger64v(GLenum pname, GLint64 *params) +{ + const struct value_desc *d; + union value v; + GLmatrix *m; + int shift, i; + void *p; + + d = find_value("glGetInteger64v", pname, &p, &v); + switch (d->type) { + case TYPE_INVALID: + break; + case TYPE_CONST: + params[0] = d->offset; + break; + + case TYPE_FLOAT_4: + params[3] = IROUND64(((GLfloat *) p)[3]); + case TYPE_FLOAT_3: + params[2] = IROUND64(((GLfloat *) p)[2]); + case TYPE_FLOAT_2: + params[1] = IROUND64(((GLfloat *) p)[1]); + case TYPE_FLOAT: + params[0] = IROUND64(((GLfloat *) p)[0]); + break; + + case TYPE_FLOATN_4: + params[3] = FLOAT_TO_INT64(((GLfloat *) p)[3]); + case TYPE_FLOATN_3: + params[2] = FLOAT_TO_INT64(((GLfloat *) p)[2]); + case TYPE_FLOATN_2: + params[1] = FLOAT_TO_INT64(((GLfloat *) p)[1]); + case TYPE_FLOATN: + params[0] = FLOAT_TO_INT64(((GLfloat *) p)[0]); + break; + + case TYPE_DOUBLEN: + params[0] = FLOAT_TO_INT64(((GLdouble *) p)[0]); + break; + + case TYPE_INT_4: + params[3] = ((GLint *) p)[3]; + case TYPE_INT_3: + params[2] = ((GLint *) p)[2]; + case TYPE_INT_2: + case TYPE_ENUM_2: + params[1] = ((GLint *) p)[1]; + case TYPE_INT: + case TYPE_ENUM: + params[0] = ((GLint *) p)[0]; + break; + + case TYPE_INT_N: + for (i = 0; i < v.value_int_n.n; i++) + params[i] = INT_TO_BOOLEAN(v.value_int_n.ints[i]); + break; + + case TYPE_INT64: + params[0] = ((GLint64 *) p)[0]; + break; + + case TYPE_BOOLEAN: + params[0] = ((GLboolean*) p)[0]; + break; + + case TYPE_MATRIX: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_INT64(m->m[i]); + break; + + case TYPE_MATRIX_T: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_INT64(m->m[transpose[i]]); + break; + + case TYPE_BIT_0: + case TYPE_BIT_1: + case TYPE_BIT_2: + case TYPE_BIT_3: + case TYPE_BIT_4: + case TYPE_BIT_5: + shift = d->type - TYPE_BIT_0; + params[0] = (*(GLbitfield *) p >> shift) & 1; + break; + } +} +#endif /* FEATURE_ARB_sync */ + +void GLAPIENTRY +_mesa_GetDoublev(GLenum pname, GLdouble *params) +{ + const struct value_desc *d; + union value v; + GLmatrix *m; + int shift, i; + void *p; + + d = find_value("glGetDoublev", pname, &p, &v); + switch (d->type) { + case TYPE_INVALID: + break; + case TYPE_CONST: + params[0] = d->offset; + break; + + case TYPE_FLOAT_4: + case TYPE_FLOATN_4: + params[3] = ((GLfloat *) p)[3]; + case TYPE_FLOAT_3: + case TYPE_FLOATN_3: + params[2] = ((GLfloat *) p)[2]; + case TYPE_FLOAT_2: + case TYPE_FLOATN_2: + params[1] = ((GLfloat *) p)[1]; + case TYPE_FLOAT: + case TYPE_FLOATN: + params[0] = ((GLfloat *) p)[0]; + break; + + case TYPE_DOUBLEN: + params[0] = ((GLdouble *) p)[0]; + break; + + case TYPE_INT_4: + params[3] = ((GLint *) p)[3]; + case TYPE_INT_3: + params[2] = ((GLint *) p)[2]; + case TYPE_INT_2: + case TYPE_ENUM_2: + params[1] = ((GLint *) p)[1]; + case TYPE_INT: + case TYPE_ENUM: + params[0] = ((GLint *) p)[0]; + break; + + case TYPE_INT_N: + for (i = 0; i < v.value_int_n.n; i++) + params[i] = v.value_int_n.ints[i]; + break; + + case TYPE_INT64: + params[0] = ((GLint64 *) p)[0]; + break; + + case TYPE_BOOLEAN: + params[0] = *(GLboolean*) p; + break; + + case TYPE_MATRIX: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = m->m[i]; + break; + + case TYPE_MATRIX_T: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = m->m[transpose[i]]; + break; + + case TYPE_BIT_0: + case TYPE_BIT_1: + case TYPE_BIT_2: + case TYPE_BIT_3: + case TYPE_BIT_4: + case TYPE_BIT_5: + shift = d->type - TYPE_BIT_0; + params[0] = (*(GLbitfield *) p >> shift) & 1; + break; + } +} + +static enum value_type +find_value_indexed(const char *func, GLenum pname, int index, union value *v) +{ + GET_CURRENT_CONTEXT(ctx); + + switch (pname) { + + case GL_BLEND: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.EXT_draw_buffers2) + goto invalid_enum; + v->value_int = (ctx->Color.BlendEnabled >> index) & 1; + return TYPE_INT; + + case GL_BLEND_SRC: + /* fall-through */ + case GL_BLEND_SRC_RGB: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.ARB_draw_buffers_blend) + goto invalid_enum; + v->value_int = ctx->Color.Blend[index].SrcRGB; + return TYPE_INT; + case GL_BLEND_SRC_ALPHA: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.ARB_draw_buffers_blend) + goto invalid_enum; + v->value_int = ctx->Color.Blend[index].SrcA; + return TYPE_INT; + case GL_BLEND_DST: + /* fall-through */ + case GL_BLEND_DST_RGB: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.ARB_draw_buffers_blend) + goto invalid_enum; + v->value_int = ctx->Color.Blend[index].DstRGB; + return TYPE_INT; + case GL_BLEND_DST_ALPHA: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.ARB_draw_buffers_blend) + goto invalid_enum; + v->value_int = ctx->Color.Blend[index].DstA; + return TYPE_INT; + case GL_BLEND_EQUATION_RGB: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.ARB_draw_buffers_blend) + goto invalid_enum; + v->value_int = ctx->Color.Blend[index].EquationRGB; + return TYPE_INT; + case GL_BLEND_EQUATION_ALPHA: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.ARB_draw_buffers_blend) + goto invalid_enum; + v->value_int = ctx->Color.Blend[index].EquationA; + return TYPE_INT; + + case GL_COLOR_WRITEMASK: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.EXT_draw_buffers2) + goto invalid_enum; + v->value_int_4[0] = ctx->Color.ColorMask[index][RCOMP] ? 1 : 0; + v->value_int_4[1] = ctx->Color.ColorMask[index][GCOMP] ? 1 : 0; + v->value_int_4[2] = ctx->Color.ColorMask[index][BCOMP] ? 1 : 0; + v->value_int_4[3] = ctx->Color.ColorMask[index][ACOMP] ? 1 : 0; + return TYPE_INT_4; + + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) + goto invalid_value; + if (!ctx->Extensions.EXT_transform_feedback) + goto invalid_enum; + v->value_int64 = ctx->TransformFeedback.CurrentObject->Offset[index]; + return TYPE_INT64; + + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) + goto invalid_value; + if (!ctx->Extensions.EXT_transform_feedback) + goto invalid_enum; + v->value_int64 = ctx->TransformFeedback.CurrentObject->Size[index]; + return TYPE_INT64; + + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) + goto invalid_value; + if (!ctx->Extensions.EXT_transform_feedback) + goto invalid_enum; + v->value_int = ctx->TransformFeedback.CurrentObject->Buffers[index]->Name; + return TYPE_INT; + } + + invalid_enum: + _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", func, + _mesa_lookup_enum_by_nr(pname)); + return TYPE_INVALID; + invalid_value: + _mesa_error(ctx, GL_INVALID_VALUE, "%s(pname=%s)", func, + _mesa_lookup_enum_by_nr(pname)); + return TYPE_INVALID; +} + +void GLAPIENTRY +_mesa_GetBooleanIndexedv( GLenum pname, GLuint index, GLboolean *params ) +{ + union value v; + enum value_type type = + find_value_indexed("glGetBooleanIndexedv", pname, index, &v); + + switch (type) { + case TYPE_INT: + params[0] = INT_TO_BOOLEAN(v.value_int); + break; + case TYPE_INT_4: + params[0] = INT_TO_BOOLEAN(v.value_int_4[0]); + params[1] = INT_TO_BOOLEAN(v.value_int_4[1]); + params[2] = INT_TO_BOOLEAN(v.value_int_4[2]); + params[3] = INT_TO_BOOLEAN(v.value_int_4[3]); + break; + case TYPE_INT64: + params[0] = INT64_TO_BOOLEAN(v.value_int); + break; + default: + ; /* nothing - GL error was recorded */ + } +} + +void GLAPIENTRY +_mesa_GetIntegerIndexedv( GLenum pname, GLuint index, GLint *params ) +{ + union value v; + enum value_type type = + find_value_indexed("glGetIntegerIndexedv", pname, index, &v); + + switch (type) { + case TYPE_INT: + params[0] = v.value_int; + break; + case TYPE_INT_4: + params[0] = v.value_int_4[0]; + params[1] = v.value_int_4[1]; + params[2] = v.value_int_4[2]; + params[3] = v.value_int_4[3]; + break; + case TYPE_INT64: + params[0] = INT64_TO_INT(v.value_int); + break; + default: + ; /* nothing - GL error was recorded */ + } +} + +#if FEATURE_ARB_sync +void GLAPIENTRY +_mesa_GetInteger64Indexedv( GLenum pname, GLuint index, GLint64 *params ) +{ + union value v; + enum value_type type = + find_value_indexed("glGetIntegerIndexedv", pname, index, &v); + + switch (type) { + case TYPE_INT: + params[0] = v.value_int; + break; + case TYPE_INT_4: + params[0] = v.value_int_4[0]; + params[1] = v.value_int_4[1]; + params[2] = v.value_int_4[2]; + params[3] = v.value_int_4[3]; + break; + case TYPE_INT64: + params[0] = v.value_int; + break; + default: + ; /* nothing - GL error was recorded */ + } +} +#endif /* FEATURE_ARB_sync */ + +#if FEATURE_ES1 +void GLAPIENTRY +_mesa_GetFixedv(GLenum pname, GLfixed *params) +{ + const struct value_desc *d; + union value v; + GLmatrix *m; + int shift, i; + void *p; + + d = find_value("glGetDoublev", pname, &p, &v); + switch (d->type) { + case TYPE_INVALID: + break; + case TYPE_CONST: + params[0] = INT_TO_FIXED(d->offset); + break; + + case TYPE_FLOAT_4: + case TYPE_FLOATN_4: + params[3] = FLOAT_TO_FIXED(((GLfloat *) p)[3]); + case TYPE_FLOAT_3: + case TYPE_FLOATN_3: + params[2] = FLOAT_TO_FIXED(((GLfloat *) p)[2]); + case TYPE_FLOAT_2: + case TYPE_FLOATN_2: + params[1] = FLOAT_TO_FIXED(((GLfloat *) p)[1]); + case TYPE_FLOAT: + case TYPE_FLOATN: + params[0] = FLOAT_TO_FIXED(((GLfloat *) p)[0]); + break; + + case TYPE_DOUBLEN: + params[0] = FLOAT_TO_FIXED(((GLdouble *) p)[0]); + break; + + case TYPE_INT_4: + params[3] = INT_TO_FIXED(((GLint *) p)[3]); + case TYPE_INT_3: + params[2] = INT_TO_FIXED(((GLint *) p)[2]); + case TYPE_INT_2: + case TYPE_ENUM_2: + params[1] = INT_TO_FIXED(((GLint *) p)[1]); + case TYPE_INT: + case TYPE_ENUM: + params[0] = INT_TO_FIXED(((GLint *) p)[0]); + break; + + case TYPE_INT_N: + for (i = 0; i < v.value_int_n.n; i++) + params[i] = INT_TO_FIXED(v.value_int_n.ints[i]); + break; + + case TYPE_INT64: + params[0] = ((GLint64 *) p)[0]; + break; + + case TYPE_BOOLEAN: + params[0] = BOOLEAN_TO_FIXED(((GLboolean*) p)[0]); + break; + + case TYPE_MATRIX: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_FIXED(m->m[i]); + break; + + case TYPE_MATRIX_T: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_FIXED(m->m[transpose[i]]); + break; + + case TYPE_BIT_0: + case TYPE_BIT_1: + case TYPE_BIT_2: + case TYPE_BIT_3: + case TYPE_BIT_4: + case TYPE_BIT_5: + shift = d->type - TYPE_BIT_0; + params[0] = BOOLEAN_TO_FIXED((*(GLbitfield *) p >> shift) & 1); + break; + } +} +#endif diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h index d2888fa80..fcb06d49e 100644 --- a/mesalib/src/mesa/main/mtypes.h +++ b/mesalib/src/mesa/main/mtypes.h @@ -1,3367 +1,3355 @@ -/* - * Mesa 3-D graphics library - * Version: 7.7 - * - * 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 mtypes.h - * Main Mesa data structures. - * - * Please try to mark derived values with a leading underscore ('_'). - */ - -#ifndef MTYPES_H -#define MTYPES_H - - -#include "main/glheader.h" -#include "main/config.h" -#include "main/mfeatures.h" -#include "glapi/glapi.h" -#include "math/m_matrix.h" /* GLmatrix */ -#include "main/simple_list.h" /* struct simple_node */ -#include "main/formats.h" /* MESA_FORMAT_COUNT */ - - -/** - * Color channel data type. - */ -#if CHAN_BITS == 8 - typedef GLubyte GLchan; -#define CHAN_MAX 255 -#define CHAN_MAXF 255.0F -#define CHAN_TYPE GL_UNSIGNED_BYTE -#elif CHAN_BITS == 16 - typedef GLushort GLchan; -#define CHAN_MAX 65535 -#define CHAN_MAXF 65535.0F -#define CHAN_TYPE GL_UNSIGNED_SHORT -#elif CHAN_BITS == 32 - typedef GLfloat GLchan; -#define CHAN_MAX 1.0 -#define CHAN_MAXF 1.0F -#define CHAN_TYPE GL_FLOAT -#else -#error "illegal number of color channel bits" -#endif - - -/** - * Stencil buffer data type. - */ -#if STENCIL_BITS==8 - typedef GLubyte GLstencil; -#elif STENCIL_BITS==16 - typedef GLushort GLstencil; -#else -# error "illegal number of stencil bits" -#endif - - -/** - * \name 64-bit extension of GLbitfield. - */ -/*@{*/ -typedef GLuint64 GLbitfield64; - -/** Set a single bit */ -#define BITFIELD64_BIT(b) (1ULL << (b)) - - -/** - * \name Some forward type declarations - */ -/*@{*/ -struct _mesa_HashTable; -struct gl_attrib_node; -struct gl_list_extensions; -struct gl_meta_state; -struct gl_pixelstore_attrib; -struct gl_program_cache; -struct gl_texture_format; -struct gl_texture_image; -struct gl_texture_object; -struct gl_context; -struct st_context; -/*@}*/ - - -/** Extra draw modes beyond GL_POINTS, GL_TRIANGLE_FAN, etc */ -#define PRIM_OUTSIDE_BEGIN_END (GL_POLYGON+1) -#define PRIM_INSIDE_UNKNOWN_PRIM (GL_POLYGON+2) -#define PRIM_UNKNOWN (GL_POLYGON+3) - - -/** - * Shader stages. Note that these will become 5 with tessellation. - * These MUST have the same values as gallium's PIPE_SHADER_* - */ -typedef enum -{ - MESA_SHADER_VERTEX = 0, - MESA_SHADER_FRAGMENT = 1, - MESA_SHADER_GEOMETRY = 2, - MESA_SHADER_TYPES = 3 -} gl_shader_type; - - - -/** - * Indexes for vertex program attributes. - * GL_NV_vertex_program aliases generic attributes over the conventional - * attributes. In GL_ARB_vertex_program shader the aliasing is optional. - * In GL_ARB_vertex_shader / OpenGL 2.0 the aliasing is disallowed (the - * generic attributes are distinct/separate). - */ -typedef enum -{ - VERT_ATTRIB_POS = 0, - VERT_ATTRIB_WEIGHT = 1, - VERT_ATTRIB_NORMAL = 2, - VERT_ATTRIB_COLOR0 = 3, - VERT_ATTRIB_COLOR1 = 4, - VERT_ATTRIB_FOG = 5, - VERT_ATTRIB_COLOR_INDEX = 6, - VERT_ATTRIB_POINT_SIZE = 6, /*alias*/ - VERT_ATTRIB_EDGEFLAG = 7, - VERT_ATTRIB_TEX0 = 8, - VERT_ATTRIB_TEX1 = 9, - VERT_ATTRIB_TEX2 = 10, - VERT_ATTRIB_TEX3 = 11, - VERT_ATTRIB_TEX4 = 12, - VERT_ATTRIB_TEX5 = 13, - VERT_ATTRIB_TEX6 = 14, - VERT_ATTRIB_TEX7 = 15, - VERT_ATTRIB_GENERIC0 = 16, - VERT_ATTRIB_GENERIC1 = 17, - VERT_ATTRIB_GENERIC2 = 18, - VERT_ATTRIB_GENERIC3 = 19, - VERT_ATTRIB_GENERIC4 = 20, - VERT_ATTRIB_GENERIC5 = 21, - VERT_ATTRIB_GENERIC6 = 22, - VERT_ATTRIB_GENERIC7 = 23, - VERT_ATTRIB_GENERIC8 = 24, - VERT_ATTRIB_GENERIC9 = 25, - VERT_ATTRIB_GENERIC10 = 26, - VERT_ATTRIB_GENERIC11 = 27, - VERT_ATTRIB_GENERIC12 = 28, - VERT_ATTRIB_GENERIC13 = 29, - VERT_ATTRIB_GENERIC14 = 30, - VERT_ATTRIB_GENERIC15 = 31, - VERT_ATTRIB_MAX = 32 -} gl_vert_attrib; - -/** - * Bitflags for vertex attributes. - * These are used in bitfields in many places. - */ -/*@{*/ -#define VERT_BIT_POS (1 << VERT_ATTRIB_POS) -#define VERT_BIT_WEIGHT (1 << VERT_ATTRIB_WEIGHT) -#define VERT_BIT_NORMAL (1 << VERT_ATTRIB_NORMAL) -#define VERT_BIT_COLOR0 (1 << VERT_ATTRIB_COLOR0) -#define VERT_BIT_COLOR1 (1 << VERT_ATTRIB_COLOR1) -#define VERT_BIT_FOG (1 << VERT_ATTRIB_FOG) -#define VERT_BIT_COLOR_INDEX (1 << VERT_ATTRIB_COLOR_INDEX) -#define VERT_BIT_EDGEFLAG (1 << VERT_ATTRIB_EDGEFLAG) -#define VERT_BIT_TEX0 (1 << VERT_ATTRIB_TEX0) -#define VERT_BIT_TEX1 (1 << VERT_ATTRIB_TEX1) -#define VERT_BIT_TEX2 (1 << VERT_ATTRIB_TEX2) -#define VERT_BIT_TEX3 (1 << VERT_ATTRIB_TEX3) -#define VERT_BIT_TEX4 (1 << VERT_ATTRIB_TEX4) -#define VERT_BIT_TEX5 (1 << VERT_ATTRIB_TEX5) -#define VERT_BIT_TEX6 (1 << VERT_ATTRIB_TEX6) -#define VERT_BIT_TEX7 (1 << VERT_ATTRIB_TEX7) -#define VERT_BIT_GENERIC0 (1 << VERT_ATTRIB_GENERIC0) -#define VERT_BIT_GENERIC1 (1 << VERT_ATTRIB_GENERIC1) -#define VERT_BIT_GENERIC2 (1 << VERT_ATTRIB_GENERIC2) -#define VERT_BIT_GENERIC3 (1 << VERT_ATTRIB_GENERIC3) -#define VERT_BIT_GENERIC4 (1 << VERT_ATTRIB_GENERIC4) -#define VERT_BIT_GENERIC5 (1 << VERT_ATTRIB_GENERIC5) -#define VERT_BIT_GENERIC6 (1 << VERT_ATTRIB_GENERIC6) -#define VERT_BIT_GENERIC7 (1 << VERT_ATTRIB_GENERIC7) -#define VERT_BIT_GENERIC8 (1 << VERT_ATTRIB_GENERIC8) -#define VERT_BIT_GENERIC9 (1 << VERT_ATTRIB_GENERIC9) -#define VERT_BIT_GENERIC10 (1 << VERT_ATTRIB_GENERIC10) -#define VERT_BIT_GENERIC11 (1 << VERT_ATTRIB_GENERIC11) -#define VERT_BIT_GENERIC12 (1 << VERT_ATTRIB_GENERIC12) -#define VERT_BIT_GENERIC13 (1 << VERT_ATTRIB_GENERIC13) -#define VERT_BIT_GENERIC14 (1 << VERT_ATTRIB_GENERIC14) -#define VERT_BIT_GENERIC15 (1 << VERT_ATTRIB_GENERIC15) - -#define VERT_BIT_TEX(u) (1 << (VERT_ATTRIB_TEX0 + (u))) -#define VERT_BIT_GENERIC(g) (1 << (VERT_ATTRIB_GENERIC0 + (g))) -/*@}*/ - - -/** - * Indexes for vertex program result attributes - */ -typedef enum -{ - VERT_RESULT_HPOS = 0, - VERT_RESULT_COL0 = 1, - VERT_RESULT_COL1 = 2, - VERT_RESULT_FOGC = 3, - VERT_RESULT_TEX0 = 4, - VERT_RESULT_TEX1 = 5, - VERT_RESULT_TEX2 = 6, - VERT_RESULT_TEX3 = 7, - VERT_RESULT_TEX4 = 8, - VERT_RESULT_TEX5 = 9, - VERT_RESULT_TEX6 = 10, - VERT_RESULT_TEX7 = 11, - VERT_RESULT_PSIZ = 12, - VERT_RESULT_BFC0 = 13, - VERT_RESULT_BFC1 = 14, - VERT_RESULT_EDGE = 15, - VERT_RESULT_VAR0 = 16, /**< shader varying */ - VERT_RESULT_MAX = (VERT_RESULT_VAR0 + MAX_VARYING) -} gl_vert_result; - - -/*********************************************/ - -/** - * Indexes for geometry program attributes. - */ -typedef enum -{ - GEOM_ATTRIB_POSITION = 0, - GEOM_ATTRIB_COLOR0 = 1, - GEOM_ATTRIB_COLOR1 = 2, - GEOM_ATTRIB_SECONDARY_COLOR0 = 3, - GEOM_ATTRIB_SECONDARY_COLOR1 = 4, - GEOM_ATTRIB_FOG_FRAG_COORD = 5, - GEOM_ATTRIB_POINT_SIZE = 6, - GEOM_ATTRIB_CLIP_VERTEX = 7, - GEOM_ATTRIB_PRIMITIVE_ID = 8, - GEOM_ATTRIB_TEX_COORD = 9, - - GEOM_ATTRIB_VAR0 = 16, - GEOM_ATTRIB_MAX = (GEOM_ATTRIB_VAR0 + MAX_VARYING) -} gl_geom_attrib; - -/** - * Bitflags for geometry attributes. - * These are used in bitfields in many places. - */ -/*@{*/ -#define GEOM_BIT_COLOR0 (1 << GEOM_ATTRIB_COLOR0) -#define GEOM_BIT_COLOR1 (1 << GEOM_ATTRIB_COLOR1) -#define GEOM_BIT_SCOLOR0 (1 << GEOM_ATTRIB_SECONDARY_COLOR0) -#define GEOM_BIT_SCOLOR1 (1 << GEOM_ATTRIB_SECONDARY_COLOR1) -#define GEOM_BIT_TEX_COORD (1 << GEOM_ATTRIB_TEX_COORD) -#define GEOM_BIT_FOG_COORD (1 << GEOM_ATTRIB_FOG_FRAG_COORD) -#define GEOM_BIT_POSITION (1 << GEOM_ATTRIB_POSITION) -#define GEOM_BIT_POINT_SIDE (1 << GEOM_ATTRIB_POINT_SIZE) -#define GEOM_BIT_CLIP_VERTEX (1 << GEOM_ATTRIB_CLIP_VERTEX) -#define GEOM_BIT_PRIM_ID (1 << GEOM_ATTRIB_PRIMITIVE_ID) -#define GEOM_BIT_VAR0 (1 << GEOM_ATTRIB_VAR0) - -#define GEOM_BIT_VAR(g) (1 << (GEOM_BIT_VAR0 + (g))) -/*@}*/ - - -/** - * Indexes for geometry program result attributes - */ -typedef enum -{ - GEOM_RESULT_POS = 0, - GEOM_RESULT_COL0 = 1, - GEOM_RESULT_COL1 = 2, - GEOM_RESULT_SCOL0 = 3, - GEOM_RESULT_SCOL1 = 4, - GEOM_RESULT_FOGC = 5, - GEOM_RESULT_TEX0 = 6, - GEOM_RESULT_TEX1 = 7, - GEOM_RESULT_TEX2 = 8, - GEOM_RESULT_TEX3 = 9, - GEOM_RESULT_TEX4 = 10, - GEOM_RESULT_TEX5 = 11, - GEOM_RESULT_TEX6 = 12, - GEOM_RESULT_TEX7 = 13, - GEOM_RESULT_PSIZ = 14, - GEOM_RESULT_CLPV = 15, - GEOM_RESULT_PRID = 16, - GEOM_RESULT_LAYR = 17, - GEOM_RESULT_VAR0 = 18, /**< shader varying, should really be 16 */ - /* ### we need to -2 because var0 is 18 instead 16 like in the others */ - GEOM_RESULT_MAX = (GEOM_RESULT_VAR0 + MAX_VARYING - 2) -} gl_geom_result; - - -/** - * Indexes for fragment program input attributes. - */ -typedef enum -{ - FRAG_ATTRIB_WPOS = 0, - FRAG_ATTRIB_COL0 = 1, - FRAG_ATTRIB_COL1 = 2, - FRAG_ATTRIB_FOGC = 3, - FRAG_ATTRIB_TEX0 = 4, - FRAG_ATTRIB_TEX1 = 5, - FRAG_ATTRIB_TEX2 = 6, - FRAG_ATTRIB_TEX3 = 7, - FRAG_ATTRIB_TEX4 = 8, - FRAG_ATTRIB_TEX5 = 9, - FRAG_ATTRIB_TEX6 = 10, - FRAG_ATTRIB_TEX7 = 11, - FRAG_ATTRIB_FACE = 12, /**< front/back face */ - FRAG_ATTRIB_PNTC = 13, /**< sprite/point coord */ - FRAG_ATTRIB_VAR0 = 14, /**< shader varying */ - FRAG_ATTRIB_MAX = (FRAG_ATTRIB_VAR0 + MAX_VARYING) -} gl_frag_attrib; - -/** - * Bitflags for fragment program input attributes. - */ -/*@{*/ -#define FRAG_BIT_WPOS (1 << FRAG_ATTRIB_WPOS) -#define FRAG_BIT_COL0 (1 << FRAG_ATTRIB_COL0) -#define FRAG_BIT_COL1 (1 << FRAG_ATTRIB_COL1) -#define FRAG_BIT_FOGC (1 << FRAG_ATTRIB_FOGC) -#define FRAG_BIT_FACE (1 << FRAG_ATTRIB_FACE) -#define FRAG_BIT_PNTC (1 << FRAG_ATTRIB_PNTC) -#define FRAG_BIT_TEX0 (1 << FRAG_ATTRIB_TEX0) -#define FRAG_BIT_TEX1 (1 << FRAG_ATTRIB_TEX1) -#define FRAG_BIT_TEX2 (1 << FRAG_ATTRIB_TEX2) -#define FRAG_BIT_TEX3 (1 << FRAG_ATTRIB_TEX3) -#define FRAG_BIT_TEX4 (1 << FRAG_ATTRIB_TEX4) -#define FRAG_BIT_TEX5 (1 << FRAG_ATTRIB_TEX5) -#define FRAG_BIT_TEX6 (1 << FRAG_ATTRIB_TEX6) -#define FRAG_BIT_TEX7 (1 << FRAG_ATTRIB_TEX7) -#define FRAG_BIT_VAR0 (1 << FRAG_ATTRIB_VAR0) - -#define FRAG_BIT_TEX(U) (FRAG_BIT_TEX0 << (U)) -#define FRAG_BIT_VAR(V) (FRAG_BIT_VAR0 << (V)) - -#define FRAG_BITS_TEX_ANY (FRAG_BIT_TEX0| \ - FRAG_BIT_TEX1| \ - FRAG_BIT_TEX2| \ - FRAG_BIT_TEX3| \ - FRAG_BIT_TEX4| \ - FRAG_BIT_TEX5| \ - FRAG_BIT_TEX6| \ - FRAG_BIT_TEX7) -/*@}*/ - - -/** - * Fragment program results - */ -typedef enum -{ - FRAG_RESULT_DEPTH = 0, - FRAG_RESULT_STENCIL = 1, - FRAG_RESULT_COLOR = 2, - FRAG_RESULT_DATA0 = 3, - FRAG_RESULT_MAX = (FRAG_RESULT_DATA0 + MAX_DRAW_BUFFERS) -} gl_frag_result; - - -/** - * Indexes for all renderbuffers - */ -typedef enum -{ - /* the four standard color buffers */ - BUFFER_FRONT_LEFT, - BUFFER_BACK_LEFT, - BUFFER_FRONT_RIGHT, - BUFFER_BACK_RIGHT, - BUFFER_DEPTH, - BUFFER_STENCIL, - BUFFER_ACCUM, - /* optional aux buffer */ - BUFFER_AUX0, - /* generic renderbuffers */ - BUFFER_COLOR0, - BUFFER_COLOR1, - BUFFER_COLOR2, - BUFFER_COLOR3, - BUFFER_COLOR4, - BUFFER_COLOR5, - BUFFER_COLOR6, - BUFFER_COLOR7, - BUFFER_COUNT -} gl_buffer_index; - -/** - * Bit flags for all renderbuffers - */ -#define BUFFER_BIT_FRONT_LEFT (1 << BUFFER_FRONT_LEFT) -#define BUFFER_BIT_BACK_LEFT (1 << BUFFER_BACK_LEFT) -#define BUFFER_BIT_FRONT_RIGHT (1 << BUFFER_FRONT_RIGHT) -#define BUFFER_BIT_BACK_RIGHT (1 << BUFFER_BACK_RIGHT) -#define BUFFER_BIT_AUX0 (1 << BUFFER_AUX0) -#define BUFFER_BIT_AUX1 (1 << BUFFER_AUX1) -#define BUFFER_BIT_AUX2 (1 << BUFFER_AUX2) -#define BUFFER_BIT_AUX3 (1 << BUFFER_AUX3) -#define BUFFER_BIT_DEPTH (1 << BUFFER_DEPTH) -#define BUFFER_BIT_STENCIL (1 << BUFFER_STENCIL) -#define BUFFER_BIT_ACCUM (1 << BUFFER_ACCUM) -#define BUFFER_BIT_COLOR0 (1 << BUFFER_COLOR0) -#define BUFFER_BIT_COLOR1 (1 << BUFFER_COLOR1) -#define BUFFER_BIT_COLOR2 (1 << BUFFER_COLOR2) -#define BUFFER_BIT_COLOR3 (1 << BUFFER_COLOR3) -#define BUFFER_BIT_COLOR4 (1 << BUFFER_COLOR4) -#define BUFFER_BIT_COLOR5 (1 << BUFFER_COLOR5) -#define BUFFER_BIT_COLOR6 (1 << BUFFER_COLOR6) -#define BUFFER_BIT_COLOR7 (1 << BUFFER_COLOR7) - -/** - * Mask of all the color buffer bits (but not accum). - */ -#define BUFFER_BITS_COLOR (BUFFER_BIT_FRONT_LEFT | \ - BUFFER_BIT_BACK_LEFT | \ - BUFFER_BIT_FRONT_RIGHT | \ - BUFFER_BIT_BACK_RIGHT | \ - BUFFER_BIT_AUX0 | \ - BUFFER_BIT_COLOR0 | \ - BUFFER_BIT_COLOR1 | \ - BUFFER_BIT_COLOR2 | \ - BUFFER_BIT_COLOR3 | \ - BUFFER_BIT_COLOR4 | \ - BUFFER_BIT_COLOR5 | \ - BUFFER_BIT_COLOR6 | \ - BUFFER_BIT_COLOR7) - - -/** - * Framebuffer configuration (aka visual / pixelformat) - * Note: some of these fields should be boolean, but it appears that - * code in drivers/dri/common/util.c requires int-sized fields. - */ -struct gl_config -{ - GLboolean rgbMode; - GLboolean floatMode; - GLboolean colorIndexMode; /* XXX is this used anywhere? */ - GLuint doubleBufferMode; - GLuint stereoMode; - - GLboolean haveAccumBuffer; - GLboolean haveDepthBuffer; - GLboolean haveStencilBuffer; - - GLint redBits, greenBits, blueBits, alphaBits; /* bits per comp */ - GLuint redMask, greenMask, blueMask, alphaMask; - GLint rgbBits; /* total bits for rgb */ - GLint indexBits; /* total bits for colorindex */ - - GLint accumRedBits, accumGreenBits, accumBlueBits, accumAlphaBits; - GLint depthBits; - GLint stencilBits; - - GLint numAuxBuffers; - - GLint level; - - /* EXT_visual_rating / GLX 1.2 */ - GLint visualRating; - - /* EXT_visual_info / GLX 1.2 */ - GLint transparentPixel; - /* colors are floats scaled to ints */ - GLint transparentRed, transparentGreen, transparentBlue, transparentAlpha; - GLint transparentIndex; - - /* ARB_multisample / SGIS_multisample */ - GLint sampleBuffers; - GLint samples; - - /* SGIX_pbuffer / GLX 1.3 */ - GLint maxPbufferWidth; - GLint maxPbufferHeight; - GLint maxPbufferPixels; - GLint optimalPbufferWidth; /* Only for SGIX_pbuffer. */ - GLint optimalPbufferHeight; /* Only for SGIX_pbuffer. */ - - /* OML_swap_method */ - GLint swapMethod; - - /* EXT_texture_from_pixmap */ - GLint bindToTextureRgb; - GLint bindToTextureRgba; - GLint bindToMipmapTexture; - GLint bindToTextureTargets; - GLint yInverted; - - /* EXT_framebuffer_sRGB */ - GLint sRGBCapable; -}; - - -/** - * Data structure for color tables - */ -struct gl_color_table -{ - GLenum InternalFormat; /**< The user-specified format */ - GLenum _BaseFormat; /**< GL_ALPHA, GL_RGBA, GL_RGB, etc */ - GLuint Size; /**< number of entries in table */ - GLfloat *TableF; /**< Color table, floating point values */ - GLubyte *TableUB; /**< Color table, ubyte values */ - GLubyte RedSize; - GLubyte GreenSize; - GLubyte BlueSize; - GLubyte AlphaSize; - GLubyte LuminanceSize; - GLubyte IntensitySize; -}; - - -/** - * \name Bit flags used for updating material values. - */ -/*@{*/ -#define MAT_ATTRIB_FRONT_AMBIENT 0 -#define MAT_ATTRIB_BACK_AMBIENT 1 -#define MAT_ATTRIB_FRONT_DIFFUSE 2 -#define MAT_ATTRIB_BACK_DIFFUSE 3 -#define MAT_ATTRIB_FRONT_SPECULAR 4 -#define MAT_ATTRIB_BACK_SPECULAR 5 -#define MAT_ATTRIB_FRONT_EMISSION 6 -#define MAT_ATTRIB_BACK_EMISSION 7 -#define MAT_ATTRIB_FRONT_SHININESS 8 -#define MAT_ATTRIB_BACK_SHININESS 9 -#define MAT_ATTRIB_FRONT_INDEXES 10 -#define MAT_ATTRIB_BACK_INDEXES 11 -#define MAT_ATTRIB_MAX 12 - -#define MAT_ATTRIB_AMBIENT(f) (MAT_ATTRIB_FRONT_AMBIENT+(f)) -#define MAT_ATTRIB_DIFFUSE(f) (MAT_ATTRIB_FRONT_DIFFUSE+(f)) -#define MAT_ATTRIB_SPECULAR(f) (MAT_ATTRIB_FRONT_SPECULAR+(f)) -#define MAT_ATTRIB_EMISSION(f) (MAT_ATTRIB_FRONT_EMISSION+(f)) -#define MAT_ATTRIB_SHININESS(f)(MAT_ATTRIB_FRONT_SHININESS+(f)) -#define MAT_ATTRIB_INDEXES(f) (MAT_ATTRIB_FRONT_INDEXES+(f)) - -#define MAT_INDEX_AMBIENT 0 -#define MAT_INDEX_DIFFUSE 1 -#define MAT_INDEX_SPECULAR 2 - -#define MAT_BIT_FRONT_AMBIENT (1< ) */ - GLfloat _NormSpotDirection[4]; /**< normalized spotlight direction */ - GLfloat _VP_inf_spot_attenuation; - - GLfloat _SpotExpTable[EXP_TABLE_SIZE][2]; /**< to replace a pow() call */ - GLfloat _MatAmbient[2][3]; /**< material ambient * light ambient */ - GLfloat _MatDiffuse[2][3]; /**< material diffuse * light diffuse */ - GLfloat _MatSpecular[2][3]; /**< material spec * light specular */ - GLfloat _dli; /**< CI diffuse light intensity */ - GLfloat _sli; /**< CI specular light intensity */ - /*@}*/ -}; - - -/** - * Light model state. - */ -struct gl_lightmodel -{ - GLfloat Ambient[4]; /**< ambient color */ - GLboolean LocalViewer; /**< Local (or infinite) view point? */ - GLboolean TwoSide; /**< Two (or one) sided lighting? */ - GLenum ColorControl; /**< either GL_SINGLE_COLOR - * or GL_SEPARATE_SPECULAR_COLOR */ -}; - - -/** - * Material state. - */ -struct gl_material -{ - GLfloat Attrib[MAT_ATTRIB_MAX][4]; -}; - - -/** - * Accumulation buffer attribute group (GL_ACCUM_BUFFER_BIT) - */ -struct gl_accum_attrib -{ - GLfloat ClearColor[4]; /**< Accumulation buffer clear color */ -}; - - -/** - * Color buffer attribute group (GL_COLOR_BUFFER_BIT). - */ -struct gl_colorbuffer_attrib -{ - GLuint ClearIndex; /**< Index to use for glClear */ - GLclampf ClearColor[4]; /**< Color to use for glClear */ - - GLuint IndexMask; /**< Color index write mask */ - GLubyte ColorMask[MAX_DRAW_BUFFERS][4];/**< Each flag is 0xff or 0x0 */ - - GLenum DrawBuffer[MAX_DRAW_BUFFERS]; /**< Which buffer to draw into */ - - /** - * \name alpha testing - */ - /*@{*/ - GLboolean AlphaEnabled; /**< Alpha test enabled flag */ - GLenum AlphaFunc; /**< Alpha test function */ - GLclampf AlphaRef; /**< Alpha reference value */ - /*@}*/ - - /** - * \name Blending - */ - /*@{*/ - GLbitfield BlendEnabled; /**< Per-buffer blend enable flags */ - GLfloat BlendColor[4]; /**< Blending color */ - struct - { - GLenum SrcRGB; /**< RGB blend source term */ - GLenum DstRGB; /**< RGB blend dest term */ - GLenum SrcA; /**< Alpha blend source term */ - GLenum DstA; /**< Alpha blend dest term */ - GLenum EquationRGB; /**< GL_ADD, GL_SUBTRACT, etc. */ - GLenum EquationA; /**< GL_ADD, GL_SUBTRACT, etc. */ - } Blend[MAX_DRAW_BUFFERS]; - /** Are the blend func terms currently different for each buffer/target? */ - GLboolean _BlendFuncPerBuffer; - /** Are the blend equations currently different for each buffer/target? */ - GLboolean _BlendEquationPerBuffer; - /*@}*/ - - /** - * \name Logic op - */ - /*@{*/ - GLenum LogicOp; /**< Logic operator */ - GLboolean IndexLogicOpEnabled; /**< Color index logic op enabled flag */ - GLboolean ColorLogicOpEnabled; /**< RGBA logic op enabled flag */ - GLboolean _LogicOpEnabled; /**< RGBA logic op + EXT_blend_logic_op enabled flag */ - /*@}*/ - - GLboolean DitherFlag; /**< Dither enable flag */ - - GLenum ClampFragmentColor; /**< GL_TRUE, GL_FALSE or GL_FIXED_ONLY_ARB */ - GLenum ClampReadColor; /**< GL_TRUE, GL_FALSE or GL_FIXED_ONLY_ARB */ - - GLboolean sRGBEnabled; /**< Framebuffer sRGB blending/updating requested */ -}; - - -/** - * Current attribute group (GL_CURRENT_BIT). - */ -struct gl_current_attrib -{ - /** - * \name Current vertex attributes. - * \note Values are valid only after FLUSH_VERTICES has been called. - * \note Index and Edgeflag current values are stored as floats in the - * SIX and SEVEN attribute slots. - */ - GLfloat Attrib[VERT_ATTRIB_MAX][4]; /**< Position, color, texcoords, etc */ - - /** - * \name Current raster position attributes (always valid). - * \note This set of attributes is very similar to the SWvertex struct. - */ - /*@{*/ - GLfloat RasterPos[4]; - GLfloat RasterDistance; - GLfloat RasterColor[4]; - GLfloat RasterSecondaryColor[4]; - GLfloat RasterTexCoords[MAX_TEXTURE_COORD_UNITS][4]; - GLboolean RasterPosValid; - /*@}*/ -}; - - -/** - * Depth buffer attribute group (GL_DEPTH_BUFFER_BIT). - */ -struct gl_depthbuffer_attrib -{ - GLenum Func; /**< Function for depth buffer compare */ - GLclampd Clear; /**< Value to clear depth buffer to */ - GLboolean Test; /**< Depth buffering enabled flag */ - GLboolean Mask; /**< Depth buffer writable? */ - GLboolean BoundsTest; /**< GL_EXT_depth_bounds_test */ - GLfloat BoundsMin, BoundsMax;/**< GL_EXT_depth_bounds_test */ -}; - - -/** - * Evaluator attribute group (GL_EVAL_BIT). - */ -struct gl_eval_attrib -{ - /** - * \name Enable bits - */ - /*@{*/ - GLboolean Map1Color4; - GLboolean Map1Index; - GLboolean Map1Normal; - GLboolean Map1TextureCoord1; - GLboolean Map1TextureCoord2; - GLboolean Map1TextureCoord3; - GLboolean Map1TextureCoord4; - GLboolean Map1Vertex3; - GLboolean Map1Vertex4; - GLboolean Map1Attrib[16]; /* GL_NV_vertex_program */ - GLboolean Map2Color4; - GLboolean Map2Index; - GLboolean Map2Normal; - GLboolean Map2TextureCoord1; - GLboolean Map2TextureCoord2; - GLboolean Map2TextureCoord3; - GLboolean Map2TextureCoord4; - GLboolean Map2Vertex3; - GLboolean Map2Vertex4; - GLboolean Map2Attrib[16]; /* GL_NV_vertex_program */ - GLboolean AutoNormal; - /*@}*/ - - /** - * \name Map Grid endpoints and divisions and calculated du values - */ - /*@{*/ - GLint MapGrid1un; - GLfloat MapGrid1u1, MapGrid1u2, MapGrid1du; - GLint MapGrid2un, MapGrid2vn; - GLfloat MapGrid2u1, MapGrid2u2, MapGrid2du; - GLfloat MapGrid2v1, MapGrid2v2, MapGrid2dv; - /*@}*/ -}; - - -/** - * Fog attribute group (GL_FOG_BIT). - */ -struct gl_fog_attrib -{ - GLboolean Enabled; /**< Fog enabled flag */ - GLfloat Color[4]; /**< Fog color */ - GLfloat Density; /**< Density >= 0.0 */ - GLfloat Start; /**< Start distance in eye coords */ - GLfloat End; /**< End distance in eye coords */ - GLfloat Index; /**< Fog index */ - GLenum Mode; /**< Fog mode */ - GLboolean ColorSumEnabled; - GLenum FogCoordinateSource; /**< GL_EXT_fog_coord */ - GLfloat _Scale; /**< (End == Start) ? 1.0 : 1.0 / (End - Start) */ -}; - - -/** - * \brief Layout qualifiers for gl_FragDepth. - * - * Extension AMD_conservative_depth allows gl_FragDepth to be redeclared with - * a layout qualifier. - * - * \see enum ir_depth_layout - */ -enum gl_frag_depth_layout { - FRAG_DEPTH_LAYOUT_NONE, /**< No layout is specified. */ - FRAG_DEPTH_LAYOUT_ANY, - FRAG_DEPTH_LAYOUT_GREATER, - FRAG_DEPTH_LAYOUT_LESS, - FRAG_DEPTH_LAYOUT_UNCHANGED -}; - - -/** - * Hint attribute group (GL_HINT_BIT). - * - * Values are always one of GL_FASTEST, GL_NICEST, or GL_DONT_CARE. - */ -struct gl_hint_attrib -{ - GLenum PerspectiveCorrection; - GLenum PointSmooth; - GLenum LineSmooth; - GLenum PolygonSmooth; - GLenum Fog; - GLenum ClipVolumeClipping; /**< GL_EXT_clip_volume_hint */ - GLenum TextureCompression; /**< GL_ARB_texture_compression */ - GLenum GenerateMipmap; /**< GL_SGIS_generate_mipmap */ - GLenum FragmentShaderDerivative; /**< GL_ARB_fragment_shader */ -}; - -/** - * Light state flags. - */ -/*@{*/ -#define LIGHT_SPOT 0x1 -#define LIGHT_LOCAL_VIEWER 0x2 -#define LIGHT_POSITIONAL 0x4 -#define LIGHT_NEED_VERTICES (LIGHT_POSITIONAL|LIGHT_LOCAL_VIEWER) -/*@}*/ - - -/** - * Lighting attribute group (GL_LIGHT_BIT). - */ -struct gl_light_attrib -{ - struct gl_light Light[MAX_LIGHTS]; /**< Array of light sources */ - struct gl_lightmodel Model; /**< Lighting model */ - - /** - * Must flush FLUSH_VERTICES before referencing: - */ - /*@{*/ - struct gl_material Material; /**< Includes front & back values */ - /*@}*/ - - GLboolean Enabled; /**< Lighting enabled flag */ - GLenum ShadeModel; /**< GL_FLAT or GL_SMOOTH */ - GLenum ProvokingVertex; /**< GL_EXT_provoking_vertex */ - GLenum ColorMaterialFace; /**< GL_FRONT, BACK or FRONT_AND_BACK */ - GLenum ColorMaterialMode; /**< GL_AMBIENT, GL_DIFFUSE, etc */ - GLbitfield ColorMaterialBitmask; /**< bitmask formed from Face and Mode */ - GLboolean ColorMaterialEnabled; - GLenum ClampVertexColor; - - struct gl_light EnabledList; /**< List sentinel */ - - /** - * Derived state for optimizations: - */ - /*@{*/ - GLboolean _NeedEyeCoords; - GLboolean _NeedVertices; /**< Use fast shader? */ - GLbitfield _Flags; /**< LIGHT_* flags, see above */ - GLfloat _BaseColor[2][3]; - /*@}*/ -}; - - -/** - * Line attribute group (GL_LINE_BIT). - */ -struct gl_line_attrib -{ - GLboolean SmoothFlag; /**< GL_LINE_SMOOTH enabled? */ - GLboolean StippleFlag; /**< GL_LINE_STIPPLE enabled? */ - GLushort StipplePattern; /**< Stipple pattern */ - GLint StippleFactor; /**< Stipple repeat factor */ - GLfloat Width; /**< Line width */ -}; - - -/** - * Display list attribute group (GL_LIST_BIT). - */ -struct gl_list_attrib -{ - GLuint ListBase; -}; - - -/** - * Multisample attribute group (GL_MULTISAMPLE_BIT). - */ -struct gl_multisample_attrib -{ - GLboolean Enabled; - GLboolean _Enabled; /**< true if Enabled and multisample buffer */ - GLboolean SampleAlphaToCoverage; - GLboolean SampleAlphaToOne; - GLboolean SampleCoverage; - GLfloat SampleCoverageValue; - GLboolean SampleCoverageInvert; -}; - - -/** - * A pixelmap (see glPixelMap) - */ -struct gl_pixelmap -{ - GLint Size; - GLfloat Map[MAX_PIXEL_MAP_TABLE]; - GLubyte Map8[MAX_PIXEL_MAP_TABLE]; /**< converted to 8-bit color */ -}; - - -/** - * Collection of all pixelmaps - */ -struct gl_pixelmaps -{ - struct gl_pixelmap RtoR; /**< i.e. GL_PIXEL_MAP_R_TO_R */ - struct gl_pixelmap GtoG; - struct gl_pixelmap BtoB; - struct gl_pixelmap AtoA; - struct gl_pixelmap ItoR; - struct gl_pixelmap ItoG; - struct gl_pixelmap ItoB; - struct gl_pixelmap ItoA; - struct gl_pixelmap ItoI; - struct gl_pixelmap StoS; -}; - - -/** - * Pixel attribute group (GL_PIXEL_MODE_BIT). - */ -struct gl_pixel_attrib -{ - GLenum ReadBuffer; /**< source buffer for glRead/CopyPixels() */ - - /*--- Begin Pixel Transfer State ---*/ - /* Fields are in the order in which they're applied... */ - - /** Scale & Bias (index shift, offset) */ - /*@{*/ - GLfloat RedBias, RedScale; - GLfloat GreenBias, GreenScale; - GLfloat BlueBias, BlueScale; - GLfloat AlphaBias, AlphaScale; - GLfloat DepthBias, DepthScale; - GLint IndexShift, IndexOffset; - /*@}*/ - - /* Pixel Maps */ - /* Note: actual pixel maps are not part of this attrib group */ - GLboolean MapColorFlag; - GLboolean MapStencilFlag; - - /*--- End Pixel Transfer State ---*/ - - /** glPixelZoom */ - GLfloat ZoomX, ZoomY; - - /** GL_SGI_texture_color_table */ - GLfloat TextureColorTableScale[4]; /**< RGBA */ - GLfloat TextureColorTableBias[4]; /**< RGBA */ -}; - - -/** - * Point attribute group (GL_POINT_BIT). - */ -struct gl_point_attrib -{ - GLboolean SmoothFlag; /**< True if GL_POINT_SMOOTH is enabled */ - GLfloat Size; /**< User-specified point size */ - GLfloat Params[3]; /**< GL_EXT_point_parameters */ - GLfloat MinSize, MaxSize; /**< GL_EXT_point_parameters */ - GLfloat Threshold; /**< GL_EXT_point_parameters */ - GLboolean _Attenuated; /**< True if Params != [1, 0, 0] */ - GLboolean PointSprite; /**< GL_NV/ARB_point_sprite */ - GLboolean CoordReplace[MAX_TEXTURE_COORD_UNITS]; /**< GL_ARB_point_sprite*/ - GLenum SpriteRMode; /**< GL_NV_point_sprite (only!) */ - GLenum SpriteOrigin; /**< GL_ARB_point_sprite */ -}; - - -/** - * Polygon attribute group (GL_POLYGON_BIT). - */ -struct gl_polygon_attrib -{ - GLenum FrontFace; /**< Either GL_CW or GL_CCW */ - GLenum FrontMode; /**< Either GL_POINT, GL_LINE or GL_FILL */ - GLenum BackMode; /**< Either GL_POINT, GL_LINE or GL_FILL */ - GLboolean _FrontBit; /**< 0=GL_CCW, 1=GL_CW */ - GLboolean CullFlag; /**< Culling on/off flag */ - GLboolean SmoothFlag; /**< True if GL_POLYGON_SMOOTH is enabled */ - GLboolean StippleFlag; /**< True if GL_POLYGON_STIPPLE is enabled */ - GLenum CullFaceMode; /**< Culling mode GL_FRONT or GL_BACK */ - GLfloat OffsetFactor; /**< Polygon offset factor, from user */ - GLfloat OffsetUnits; /**< Polygon offset units, from user */ - GLboolean OffsetPoint; /**< Offset in GL_POINT mode */ - GLboolean OffsetLine; /**< Offset in GL_LINE mode */ - GLboolean OffsetFill; /**< Offset in GL_FILL mode */ -}; - - -/** - * Scissor attributes (GL_SCISSOR_BIT). - */ -struct gl_scissor_attrib -{ - GLboolean Enabled; /**< Scissor test enabled? */ - GLint X, Y; /**< Lower left corner of box */ - GLsizei Width, Height; /**< Size of box */ -}; - - -/** - * Stencil attribute group (GL_STENCIL_BUFFER_BIT). - * - * Three sets of stencil data are tracked so that OpenGL 2.0, - * GL_EXT_stencil_two_side, and GL_ATI_separate_stencil can all be supported - * simultaneously. In each of the stencil state arrays, element 0 corresponds - * to GL_FRONT. Element 1 corresponds to the OpenGL 2.0 / - * GL_ATI_separate_stencil GL_BACK state. Element 2 corresponds to the - * GL_EXT_stencil_two_side GL_BACK state. - * - * The derived value \c _BackFace is either 1 or 2 depending on whether or - * not GL_STENCIL_TEST_TWO_SIDE_EXT is enabled. - * - * The derived value \c _TestTwoSide is set when the front-face and back-face - * stencil state are different. - */ -struct gl_stencil_attrib -{ - GLboolean Enabled; /**< Enabled flag */ - GLboolean TestTwoSide; /**< GL_EXT_stencil_two_side */ - GLubyte ActiveFace; /**< GL_EXT_stencil_two_side (0 or 2) */ - GLboolean _Enabled; /**< Enabled and stencil buffer present */ - GLboolean _TestTwoSide; - GLubyte _BackFace; /**< Current back stencil state (1 or 2) */ - GLenum Function[3]; /**< Stencil function */ - GLenum FailFunc[3]; /**< Fail function */ - GLenum ZPassFunc[3]; /**< Depth buffer pass function */ - GLenum ZFailFunc[3]; /**< Depth buffer fail function */ - GLint Ref[3]; /**< Reference value */ - GLuint ValueMask[3]; /**< Value mask */ - GLuint WriteMask[3]; /**< Write mask */ - GLuint Clear; /**< Clear value */ -}; - - -/** - * An index for each type of texture object. These correspond to the GL - * texture target enums, such as GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP, etc. - * Note: the order is from highest priority to lowest priority. - */ -typedef enum -{ - TEXTURE_2D_ARRAY_INDEX, - TEXTURE_1D_ARRAY_INDEX, - TEXTURE_CUBE_INDEX, - TEXTURE_3D_INDEX, - TEXTURE_RECT_INDEX, - TEXTURE_2D_INDEX, - TEXTURE_1D_INDEX, - NUM_TEXTURE_TARGETS -} gl_texture_index; - - -/** - * Bit flags for each type of texture object - * Used for Texture.Unit[]._ReallyEnabled flags. - */ -/*@{*/ -#define TEXTURE_2D_ARRAY_BIT (1 << TEXTURE_2D_ARRAY_INDEX) -#define TEXTURE_1D_ARRAY_BIT (1 << TEXTURE_1D_ARRAY_INDEX) -#define TEXTURE_CUBE_BIT (1 << TEXTURE_CUBE_INDEX) -#define TEXTURE_3D_BIT (1 << TEXTURE_3D_INDEX) -#define TEXTURE_RECT_BIT (1 << TEXTURE_RECT_INDEX) -#define TEXTURE_2D_BIT (1 << TEXTURE_2D_INDEX) -#define TEXTURE_1D_BIT (1 << TEXTURE_1D_INDEX) -/*@}*/ - - -/** - * TexGenEnabled flags. - */ -/*@{*/ -#define S_BIT 1 -#define T_BIT 2 -#define R_BIT 4 -#define Q_BIT 8 -#define STR_BITS (S_BIT | T_BIT | R_BIT) -/*@}*/ - - -/** - * Bit flag versions of the corresponding GL_ constants. - */ -/*@{*/ -#define TEXGEN_SPHERE_MAP 0x1 -#define TEXGEN_OBJ_LINEAR 0x2 -#define TEXGEN_EYE_LINEAR 0x4 -#define TEXGEN_REFLECTION_MAP_NV 0x8 -#define TEXGEN_NORMAL_MAP_NV 0x10 - -#define TEXGEN_NEED_NORMALS (TEXGEN_SPHERE_MAP | \ - TEXGEN_REFLECTION_MAP_NV | \ - TEXGEN_NORMAL_MAP_NV) -#define TEXGEN_NEED_EYE_COORD (TEXGEN_SPHERE_MAP | \ - TEXGEN_REFLECTION_MAP_NV | \ - TEXGEN_NORMAL_MAP_NV | \ - TEXGEN_EYE_LINEAR) -/*@}*/ - - - -/** Tex-gen enabled for texture unit? */ -#define ENABLE_TEXGEN(unit) (1 << (unit)) - -/** Non-identity texture matrix for texture unit? */ -#define ENABLE_TEXMAT(unit) (1 << (unit)) - - -/** - * Texel fetch function prototype. We use texel fetch functions to - * extract RGBA, color indexes and depth components out of 1D, 2D and 3D - * texture images. These functions help to isolate us from the gritty - * details of all the various texture image encodings. - * - * \param texImage texture image. - * \param col texel column. - * \param row texel row. - * \param img texel image level/layer. - * \param texelOut output texel (up to 4 GLchans) - */ -typedef void (*FetchTexelFuncC)( const struct gl_texture_image *texImage, - GLint col, GLint row, GLint img, - GLchan *texelOut ); - -/** - * As above, but returns floats. - * Used for depth component images and for upcoming signed/float - * texture images. - */ -typedef void (*FetchTexelFuncF)( const struct gl_texture_image *texImage, - GLint col, GLint row, GLint img, - GLfloat *texelOut ); - - -typedef void (*StoreTexelFunc)(struct gl_texture_image *texImage, - GLint col, GLint row, GLint img, - const void *texel); - - -/** - * Texture image state. Describes the dimensions of a texture image, - * the texel format and pointers to Texel Fetch functions. - */ -struct gl_texture_image -{ - GLint InternalFormat; /**< Internal format as given by the user */ - GLenum _BaseFormat; /**< Either GL_RGB, GL_RGBA, GL_ALPHA, - * GL_LUMINANCE, GL_LUMINANCE_ALPHA, - * GL_INTENSITY, GL_COLOR_INDEX, - * GL_DEPTH_COMPONENT or GL_DEPTH_STENCIL_EXT - * only. Used for choosing TexEnv arithmetic. - */ - gl_format TexFormat; /**< The actual texture memory format */ - - GLuint Border; /**< 0 or 1 */ - GLuint Width; /**< = 2^WidthLog2 + 2*Border */ - GLuint Height; /**< = 2^HeightLog2 + 2*Border */ - GLuint Depth; /**< = 2^DepthLog2 + 2*Border */ - GLuint Width2; /**< = Width - 2*Border */ - GLuint Height2; /**< = Height - 2*Border */ - GLuint Depth2; /**< = Depth - 2*Border */ - GLuint WidthLog2; /**< = log2(Width2) */ - GLuint HeightLog2; /**< = log2(Height2) */ - GLuint DepthLog2; /**< = log2(Depth2) */ - GLuint MaxLog2; /**< = MAX(WidthLog2, HeightLog2) */ - GLfloat WidthScale; /**< used for mipmap LOD computation */ - GLfloat HeightScale; /**< used for mipmap LOD computation */ - GLfloat DepthScale; /**< used for mipmap LOD computation */ - GLboolean IsClientData; /**< Data owned by client? */ - GLboolean _IsPowerOfTwo; /**< Are all dimensions powers of two? */ - - struct gl_texture_object *TexObject; /**< Pointer back to parent object */ - - FetchTexelFuncC FetchTexelc; /**< GLchan texel fetch function pointer */ - FetchTexelFuncF FetchTexelf; /**< Float texel fetch function pointer */ - - GLuint RowStride; /**< Padded width in units of texels */ - GLuint *ImageOffsets; /**< if 3D texture: array [Depth] of offsets to - each 2D slice in 'Data', in texels */ - GLvoid *Data; /**< Image data, accessed via FetchTexel() */ - - /** - * \name For device driver: - */ - /*@{*/ - void *DriverData; /**< Arbitrary device driver data */ - /*@}*/ -}; - - -/** - * Indexes for cube map faces. - */ -typedef enum -{ - FACE_POS_X = 0, - FACE_NEG_X = 1, - FACE_POS_Y = 2, - FACE_NEG_Y = 3, - FACE_POS_Z = 4, - FACE_NEG_Z = 5, - MAX_FACES = 6 -} gl_face_index; - - -/** - * Texture object state. Contains the array of mipmap images, border color, - * wrap modes, filter modes, shadow/texcompare state, and the per-texture - * color palette. - */ -struct gl_texture_object -{ - _glthread_Mutex Mutex; /**< for thread safety */ - GLint RefCount; /**< reference count */ - GLuint Name; /**< the user-visible texture object ID */ - GLenum Target; /**< GL_TEXTURE_1D, GL_TEXTURE_2D, etc. */ - GLfloat Priority; /**< in [0,1] */ - union { - GLfloat f[4]; - GLuint ui[4]; - GLint i[4]; - } BorderColor; /**< Interpreted according to texture format */ - GLenum WrapS; /**< S-axis texture image wrap mode */ - GLenum WrapT; /**< T-axis texture image wrap mode */ - GLenum WrapR; /**< R-axis texture image wrap mode */ - GLenum MinFilter; /**< minification filter */ - GLenum MagFilter; /**< magnification filter */ - GLfloat MinLod; /**< min lambda, OpenGL 1.2 */ - GLfloat MaxLod; /**< max lambda, OpenGL 1.2 */ - GLfloat LodBias; /**< OpenGL 1.4 */ - GLint BaseLevel; /**< min mipmap level, OpenGL 1.2 */ - GLint MaxLevel; /**< max mipmap level, OpenGL 1.2 */ - GLfloat MaxAnisotropy; /**< GL_EXT_texture_filter_anisotropic */ - GLenum CompareMode; /**< GL_ARB_shadow */ - GLenum CompareFunc; /**< GL_ARB_shadow */ - GLfloat CompareFailValue; /**< GL_ARB_shadow_ambient */ - GLenum DepthMode; /**< GL_ARB_depth_texture */ - GLint _MaxLevel; /**< actual max mipmap level (q in the spec) */ - GLfloat _MaxLambda; /**< = _MaxLevel - BaseLevel (q - b in spec) */ - GLint CropRect[4]; /**< GL_OES_draw_texture */ - GLenum Swizzle[4]; /**< GL_EXT_texture_swizzle */ - GLuint _Swizzle; /**< same as Swizzle, but SWIZZLE_* format */ - GLboolean GenerateMipmap; /**< GL_SGIS_generate_mipmap */ - GLboolean _Complete; /**< Is texture object complete? */ - GLboolean _RenderToTexture; /**< Any rendering to this texture? */ - GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */ - GLenum sRGBDecode; /**< GL_DECODE_EXT or GL_SKIP_DECODE_EXT */ - - /** Actual texture images, indexed by [cube face] and [mipmap level] */ - struct gl_texture_image *Image[MAX_FACES][MAX_TEXTURE_LEVELS]; - - /** GL_EXT_paletted_texture */ - struct gl_color_table Palette; - - /** - * \name For device driver. - * Note: instead of attaching driver data to this pointer, it's preferable - * to instead use this struct as a base class for your own texture object - * class. Driver->NewTextureObject() can be used to implement the - * allocation. - */ - void *DriverData; /**< Arbitrary device driver data */ -}; - - -/** Up to four combiner sources are possible with GL_NV_texture_env_combine4 */ -#define MAX_COMBINER_TERMS 4 - - -/** - * Texture combine environment state. - */ -struct gl_tex_env_combine_state -{ - GLenum ModeRGB; /**< GL_REPLACE, GL_DECAL, GL_ADD, etc. */ - GLenum ModeA; /**< GL_REPLACE, GL_DECAL, GL_ADD, etc. */ - /** Source terms: GL_PRIMARY_COLOR, GL_TEXTURE, etc */ - GLenum SourceRGB[MAX_COMBINER_TERMS]; - GLenum SourceA[MAX_COMBINER_TERMS]; - /** Source operands: GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, etc */ - GLenum OperandRGB[MAX_COMBINER_TERMS]; - GLenum OperandA[MAX_COMBINER_TERMS]; - GLuint ScaleShiftRGB; /**< 0, 1 or 2 */ - GLuint ScaleShiftA; /**< 0, 1 or 2 */ - GLuint _NumArgsRGB; /**< Number of inputs used for the RGB combiner */ - GLuint _NumArgsA; /**< Number of inputs used for the A combiner */ -}; - - -/** - * Texture coord generation state. - */ -struct gl_texgen -{ - GLenum Mode; /**< GL_EYE_LINEAR, GL_SPHERE_MAP, etc */ - GLbitfield _ModeBit; /**< TEXGEN_x bit corresponding to Mode */ - GLfloat ObjectPlane[4]; - GLfloat EyePlane[4]; -}; - - -/** - * Texture unit state. Contains enable flags, texture environment/function/ - * combiners, texgen state, pointers to current texture objects and - * post-filter color tables. - */ -struct gl_texture_unit -{ - GLbitfield Enabled; /**< bitmask of TEXTURE_*_BIT flags */ - GLbitfield _ReallyEnabled; /**< 0 or exactly one of TEXTURE_*_BIT flags */ - - GLenum EnvMode; /**< GL_MODULATE, GL_DECAL, GL_BLEND, etc. */ - GLfloat EnvColor[4]; - - struct gl_texgen GenS; - struct gl_texgen GenT; - struct gl_texgen GenR; - struct gl_texgen GenQ; - GLbitfield TexGenEnabled; /**< Bitwise-OR of [STRQ]_BIT values */ - GLbitfield _GenFlags; /**< Bitwise-OR of Gen[STRQ]._ModeBit */ - - GLfloat LodBias; /**< for biasing mipmap levels */ - GLenum BumpTarget; - GLfloat RotMatrix[4]; /* 2x2 matrix */ - - /** - * \name GL_EXT_texture_env_combine - */ - struct gl_tex_env_combine_state Combine; - - /** - * Derived state based on \c EnvMode and the \c BaseFormat of the - * currently enabled texture. - */ - struct gl_tex_env_combine_state _EnvMode; - - /** - * Currently enabled combiner state. This will point to either - * \c Combine or \c _EnvMode. - */ - struct gl_tex_env_combine_state *_CurrentCombine; - - /** Current texture object pointers */ - struct gl_texture_object *CurrentTex[NUM_TEXTURE_TARGETS]; - - /** Points to highest priority, complete and enabled texture object */ - struct gl_texture_object *_Current; - - /** GL_SGI_texture_color_table */ - /*@{*/ - struct gl_color_table ColorTable; - struct gl_color_table ProxyColorTable; - GLboolean ColorTableEnabled; - /*@}*/ -}; - - -/** - * Texture attribute group (GL_TEXTURE_BIT). - */ -struct gl_texture_attrib -{ - GLuint CurrentUnit; /**< GL_ACTIVE_TEXTURE */ - struct gl_texture_unit Unit[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; - - struct gl_texture_object *ProxyTex[NUM_TEXTURE_TARGETS]; - - /** GL_ARB_seamless_cubemap */ - GLboolean CubeMapSeamless; - - /** GL_EXT_shared_texture_palette */ - GLboolean SharedPalette; - struct gl_color_table Palette; - - /** Texture units/samplers used by vertex or fragment texturing */ - GLbitfield _EnabledUnits; - - /** Texture coord units/sets used for fragment texturing */ - GLbitfield _EnabledCoordUnits; - - /** Texture coord units that have texgen enabled */ - GLbitfield _TexGenEnabled; - - /** Texture coord units that have non-identity matrices */ - GLbitfield _TexMatEnabled; - - /** Bitwise-OR of all Texture.Unit[i]._GenFlags */ - GLbitfield _GenFlags; -}; - - -/** - * Transformation attribute group (GL_TRANSFORM_BIT). - */ -struct gl_transform_attrib -{ - GLenum MatrixMode; /**< Matrix mode */ - GLfloat EyeUserPlane[MAX_CLIP_PLANES][4]; /**< User clip planes */ - GLfloat _ClipUserPlane[MAX_CLIP_PLANES][4]; /**< derived */ - GLbitfield ClipPlanesEnabled; /**< on/off bitmask */ - GLboolean Normalize; /**< Normalize all normals? */ - GLboolean RescaleNormals; /**< GL_EXT_rescale_normal */ - GLboolean RasterPositionUnclipped; /**< GL_IBM_rasterpos_clip */ - GLboolean DepthClamp; /**< GL_ARB_depth_clamp */ - - GLfloat CullEyePos[4]; - GLfloat CullObjPos[4]; -}; - - -/** - * Viewport attribute group (GL_VIEWPORT_BIT). - */ -struct gl_viewport_attrib -{ - GLint X, Y; /**< position */ - GLsizei Width, Height; /**< size */ - GLfloat Near, Far; /**< Depth buffer range */ - GLmatrix _WindowMap; /**< Mapping transformation as a matrix. */ -}; - - -/** - * GL_ARB_vertex/pixel_buffer_object buffer object - */ -struct gl_buffer_object -{ - _glthread_Mutex Mutex; - GLint RefCount; - GLuint Name; - GLenum Usage; /**< GL_STREAM_DRAW_ARB, GL_STREAM_READ_ARB, etc. */ - GLsizeiptrARB Size; /**< Size of buffer storage in bytes */ - GLubyte *Data; /**< Location of storage either in RAM or VRAM. */ - /** Fields describing a mapped buffer */ - /*@{*/ - GLbitfield AccessFlags; /**< Mask of GL_MAP_x_BIT flags */ - GLvoid *Pointer; /**< User-space address of mapping */ - GLintptr Offset; /**< Mapped offset */ - GLsizeiptr Length; /**< Mapped length */ - /*@}*/ - GLboolean Written; /**< Ever written to? (for debugging) */ - GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */ -}; - - -/** - * Client pixel packing/unpacking attributes - */ -struct gl_pixelstore_attrib -{ - GLint Alignment; - GLint RowLength; - GLint SkipPixels; - GLint SkipRows; - GLint ImageHeight; - GLint SkipImages; - GLboolean SwapBytes; - GLboolean LsbFirst; - GLboolean ClientStorage; /**< GL_APPLE_client_storage */ - GLboolean Invert; /**< GL_MESA_pack_invert */ - struct gl_buffer_object *BufferObj; /**< GL_ARB_pixel_buffer_object */ -}; - - -/** - * Client vertex array attributes - */ -struct gl_client_array -{ - GLint Size; /**< components per element (1,2,3,4) */ - GLenum Type; /**< datatype: GL_FLOAT, GL_INT, etc */ - GLenum Format; /**< default: GL_RGBA, but may be GL_BGRA */ - GLsizei Stride; /**< user-specified stride */ - GLsizei StrideB; /**< actual stride in bytes */ - const GLubyte *Ptr; /**< Points to array data */ - GLboolean Enabled; /**< Enabled flag is a boolean */ - GLboolean Normalized; /**< GL_ARB_vertex_program */ - GLboolean Integer; /**< Integer-valued? */ - GLuint InstanceDivisor; /**< GL_ARB_instanced_arrays */ - GLuint _ElementSize; /**< size of each element in bytes */ - - struct gl_buffer_object *BufferObj;/**< GL_ARB_vertex_buffer_object */ - GLuint _MaxElement; /**< max element index into array buffer + 1 */ -}; - - -/** - * Collection of vertex arrays. Defined by the GL_APPLE_vertex_array_object - * extension, but a nice encapsulation in any case. - */ -struct gl_array_object -{ - /** Name of the array object as received from glGenVertexArrayAPPLE. */ - GLuint Name; - - GLint RefCount; - _glthread_Mutex Mutex; - GLboolean VBOonly; /**< require all arrays to live in VBOs? */ - - /** Conventional vertex arrays */ - /*@{*/ - struct gl_client_array Vertex; - struct gl_client_array Weight; - struct gl_client_array Normal; - struct gl_client_array Color; - struct gl_client_array SecondaryColor; - struct gl_client_array FogCoord; - struct gl_client_array Index; - struct gl_client_array EdgeFlag; - struct gl_client_array TexCoord[MAX_TEXTURE_COORD_UNITS]; - struct gl_client_array PointSize; - /*@}*/ - - /** - * Generic arrays for vertex programs/shaders. - * For NV vertex programs, these attributes alias and take priority - * over the conventional attribs above. For ARB vertex programs and - * GLSL vertex shaders, these attributes are separate. - */ - struct gl_client_array VertexAttrib[MAX_VERTEX_GENERIC_ATTRIBS]; - - /** Mask of _NEW_ARRAY_* values indicating which arrays are enabled */ - GLbitfield _Enabled; - - /** - * Min of all enabled arrays' _MaxElement. When arrays reside inside VBOs - * we can determine the max legal (in bounds) glDrawElements array index. - */ - GLuint _MaxElement; -}; - - -/** - * Vertex array state - */ -struct gl_array_attrib -{ - /** Currently bound array object. See _mesa_BindVertexArrayAPPLE() */ - struct gl_array_object *ArrayObj; - - /** The default vertex array object */ - struct gl_array_object *DefaultArrayObj; - - /** Array objects (GL_ARB/APPLE_vertex_array_object) */ - struct _mesa_HashTable *Objects; - - GLint ActiveTexture; /**< Client Active Texture */ - GLuint LockFirst; /**< GL_EXT_compiled_vertex_array */ - GLuint LockCount; /**< GL_EXT_compiled_vertex_array */ - - /** GL 3.1 (slightly different from GL_NV_primitive_restart) */ - GLboolean PrimitiveRestart; - GLuint RestartIndex; - - GLbitfield NewState; /**< mask of _NEW_ARRAY_* values */ - GLboolean RebindArrays; /**< whether the VBO module should rebind arrays */ - - /* GL_ARB_vertex_buffer_object */ - struct gl_buffer_object *ArrayBufferObj; - struct gl_buffer_object *ElementArrayBufferObj; -}; - - -/** - * Feedback buffer state - */ -struct gl_feedback -{ - GLenum Type; - GLbitfield _Mask; /**< FB_* bits */ - GLfloat *Buffer; - GLuint BufferSize; - GLuint Count; -}; - - -/** - * Selection buffer state - */ -struct gl_selection -{ - GLuint *Buffer; /**< selection buffer */ - GLuint BufferSize; /**< size of the selection buffer */ - GLuint BufferCount; /**< number of values in the selection buffer */ - GLuint Hits; /**< number of records in the selection buffer */ - GLuint NameStackDepth; /**< name stack depth */ - GLuint NameStack[MAX_NAME_STACK_DEPTH]; /**< name stack */ - GLboolean HitFlag; /**< hit flag */ - GLfloat HitMinZ; /**< minimum hit depth */ - GLfloat HitMaxZ; /**< maximum hit depth */ -}; - - -/** - * 1-D Evaluator control points - */ -struct gl_1d_map -{ - GLuint Order; /**< Number of control points */ - GLfloat u1, u2, du; /**< u1, u2, 1.0/(u2-u1) */ - GLfloat *Points; /**< Points to contiguous control points */ -}; - - -/** - * 2-D Evaluator control points - */ -struct gl_2d_map -{ - GLuint Uorder; /**< Number of control points in U dimension */ - GLuint Vorder; /**< Number of control points in V dimension */ - GLfloat u1, u2, du; - GLfloat v1, v2, dv; - GLfloat *Points; /**< Points to contiguous control points */ -}; - - -/** - * All evaluator control point state - */ -struct gl_evaluators -{ - /** - * \name 1-D maps - */ - /*@{*/ - struct gl_1d_map Map1Vertex3; - struct gl_1d_map Map1Vertex4; - struct gl_1d_map Map1Index; - struct gl_1d_map Map1Color4; - struct gl_1d_map Map1Normal; - struct gl_1d_map Map1Texture1; - struct gl_1d_map Map1Texture2; - struct gl_1d_map Map1Texture3; - struct gl_1d_map Map1Texture4; - struct gl_1d_map Map1Attrib[16]; /**< GL_NV_vertex_program */ - /*@}*/ - - /** - * \name 2-D maps - */ - /*@{*/ - struct gl_2d_map Map2Vertex3; - struct gl_2d_map Map2Vertex4; - struct gl_2d_map Map2Index; - struct gl_2d_map Map2Color4; - struct gl_2d_map Map2Normal; - struct gl_2d_map Map2Texture1; - struct gl_2d_map Map2Texture2; - struct gl_2d_map Map2Texture3; - struct gl_2d_map Map2Texture4; - struct gl_2d_map Map2Attrib[16]; /**< GL_NV_vertex_program */ - /*@}*/ -}; - - -/** - * Names of the various vertex/fragment program register files, etc. - * - * NOTE: first four tokens must fit into 2 bits (see t_vb_arbprogram.c) - * All values should fit in a 4-bit field. - * - * NOTE: PROGRAM_ENV_PARAM, PROGRAM_STATE_VAR, PROGRAM_NAMED_PARAM, - * PROGRAM_CONSTANT, and PROGRAM_UNIFORM can all be considered to - * be "uniform" variables since they can only be set outside glBegin/End. - * They're also all stored in the same Parameters array. - */ -typedef enum -{ - PROGRAM_TEMPORARY, /**< machine->Temporary[] */ - PROGRAM_INPUT, /**< machine->Inputs[] */ - PROGRAM_OUTPUT, /**< machine->Outputs[] */ - PROGRAM_VARYING, /**< machine->Inputs[]/Outputs[] */ - PROGRAM_LOCAL_PARAM, /**< gl_program->LocalParams[] */ - PROGRAM_ENV_PARAM, /**< gl_program->Parameters[] */ - PROGRAM_STATE_VAR, /**< gl_program->Parameters[] */ - PROGRAM_NAMED_PARAM, /**< gl_program->Parameters[] */ - PROGRAM_CONSTANT, /**< gl_program->Parameters[] */ - PROGRAM_UNIFORM, /**< gl_program->Parameters[] */ - PROGRAM_WRITE_ONLY, /**< A dummy, write-only register */ - PROGRAM_ADDRESS, /**< machine->AddressReg */ - PROGRAM_SAMPLER, /**< for shader samplers, compile-time only */ - PROGRAM_SYSTEM_VALUE,/**< InstanceId, PrimitiveID, etc. */ - PROGRAM_UNDEFINED, /**< Invalid/TBD value */ - PROGRAM_FILE_MAX -} gl_register_file; - - -/** - * If the register file is PROGRAM_SYSTEM_VALUE, the register index will be - * one of these values. - */ -typedef enum -{ - SYSTEM_VALUE_FRONT_FACE, /**< Fragment shader only (not done yet) */ - SYSTEM_VALUE_INSTANCE_ID, /**< Vertex shader only */ - SYSTEM_VALUE_MAX /**< Number of values */ -} gl_system_value; - - -/** Vertex and fragment instructions */ -struct prog_instruction; -struct gl_program_parameter_list; -struct gl_uniform_list; - - -/** - * Base class for any kind of program object - */ -struct gl_program -{ - GLuint Id; - GLubyte *String; /**< Null-terminated program text */ - GLint RefCount; - GLenum Target; /**< GL_VERTEX/FRAGMENT_PROGRAM_ARB, GL_FRAGMENT_PROGRAM_NV */ - GLenum Format; /**< String encoding format */ - GLboolean Resident; - - struct prog_instruction *Instructions; - - GLbitfield InputsRead; /**< Bitmask of which input regs are read */ - GLbitfield64 OutputsWritten; /**< Bitmask of which output regs are written */ - GLbitfield SystemValuesRead; /**< Bitmask of SYSTEM_VALUE_x inputs used */ - GLbitfield InputFlags[MAX_PROGRAM_INPUTS]; /**< PROG_PARAM_BIT_x flags */ - GLbitfield OutputFlags[MAX_PROGRAM_OUTPUTS]; /**< PROG_PARAM_BIT_x flags */ - GLbitfield TexturesUsed[MAX_TEXTURE_UNITS]; /**< TEXTURE_x_BIT bitmask */ - GLbitfield SamplersUsed; /**< Bitfield of which samplers are used */ - GLbitfield ShadowSamplers; /**< Texture units used for shadow sampling. */ - - - /** Named parameters, constants, etc. from program text */ - struct gl_program_parameter_list *Parameters; - /** Numbered local parameters */ - GLfloat LocalParams[MAX_PROGRAM_LOCAL_PARAMS][4]; - - /** Vertex/fragment shader varying vars */ - struct gl_program_parameter_list *Varying; - /** Vertex program user-defined attributes */ - struct gl_program_parameter_list *Attributes; - - /** Map from sampler unit to texture unit (set by glUniform1i()) */ - GLubyte SamplerUnits[MAX_SAMPLERS]; - /** Which texture target is being sampled (TEXTURE_1D/2D/3D/etc_INDEX) */ - gl_texture_index SamplerTargets[MAX_SAMPLERS]; - - /** Bitmask of which register files are read/written with indirect - * addressing. Mask of (1 << PROGRAM_x) bits. - */ - GLbitfield IndirectRegisterFiles; - - /** Logical counts */ - /*@{*/ - GLuint NumInstructions; - GLuint NumTemporaries; - GLuint NumParameters; - GLuint NumAttributes; - GLuint NumAddressRegs; - GLuint NumAluInstructions; - GLuint NumTexInstructions; - GLuint NumTexIndirections; - /*@}*/ - /** Native, actual h/w counts */ - /*@{*/ - GLuint NumNativeInstructions; - GLuint NumNativeTemporaries; - GLuint NumNativeParameters; - GLuint NumNativeAttributes; - GLuint NumNativeAddressRegs; - GLuint NumNativeAluInstructions; - GLuint NumNativeTexInstructions; - GLuint NumNativeTexIndirections; - /*@}*/ -}; - - -/** Vertex program object */ -struct gl_vertex_program -{ - struct gl_program Base; /**< base class */ - GLboolean IsNVProgram; /**< is this a GL_NV_vertex_program program? */ - GLboolean IsPositionInvariant; -}; - - -/** Geometry program object */ -struct gl_geometry_program -{ - struct gl_program Base; /**< base class */ - - GLint VerticesOut; - GLenum InputType; /**< GL_POINTS, GL_LINES, GL_LINES_ADJACENCY_ARB, - GL_TRIANGLES, or GL_TRIANGLES_ADJACENCY_ARB */ - GLenum OutputType; /**< GL_POINTS, GL_LINE_STRIP or GL_TRIANGLE_STRIP */ -}; - - -/** Fragment program object */ -struct gl_fragment_program -{ - struct gl_program Base; /**< base class */ - GLenum FogOption; - GLboolean UsesKill; /**< shader uses KIL instruction */ - GLboolean OriginUpperLeft; - GLboolean PixelCenterInteger; - enum gl_frag_depth_layout FragDepthLayout; -}; - - -/** - * State common to vertex and fragment programs. - */ -struct gl_program_state -{ - GLint ErrorPos; /* GL_PROGRAM_ERROR_POSITION_ARB/NV */ - const char *ErrorString; /* GL_PROGRAM_ERROR_STRING_ARB/NV */ -}; - - -/** - * Context state for vertex programs. - */ -struct gl_vertex_program_state -{ - GLboolean Enabled; /**< User-set GL_VERTEX_PROGRAM_ARB/NV flag */ - GLboolean _Enabled; /**< Enabled and _valid_ user program? */ - GLboolean PointSizeEnabled; /**< GL_VERTEX_PROGRAM_POINT_SIZE_ARB/NV */ - GLboolean TwoSideEnabled; /**< GL_VERTEX_PROGRAM_TWO_SIDE_ARB/NV */ - struct gl_vertex_program *Current; /**< User-bound vertex program */ - - /** Currently enabled and valid vertex program (including internal - * programs, user-defined vertex programs and GLSL vertex shaders). - * This is the program we must use when rendering. - */ - struct gl_vertex_program *_Current; - - GLfloat Parameters[MAX_PROGRAM_ENV_PARAMS][4]; /**< Env params */ - - /* For GL_NV_vertex_program only: */ - GLenum TrackMatrix[MAX_PROGRAM_ENV_PARAMS / 4]; - GLenum TrackMatrixTransform[MAX_PROGRAM_ENV_PARAMS / 4]; - - /** Should fixed-function T&L be implemented with a vertex prog? */ - GLboolean _MaintainTnlProgram; - - /** Program to emulate fixed-function T&L (see above) */ - struct gl_vertex_program *_TnlProgram; - - /** Cache of fixed-function programs */ - struct gl_program_cache *Cache; - - GLboolean _Overriden; -}; - - -/** - * Context state for geometry programs. - */ -struct gl_geometry_program_state -{ - GLboolean Enabled; /**< GL_ARB_GEOMETRY_SHADER4 */ - GLboolean _Enabled; /**< Enabled and valid program? */ - struct gl_geometry_program *Current; /**< user-bound geometry program */ - - /** Currently enabled and valid program (including internal programs - * and compiled shader programs). - */ - struct gl_geometry_program *_Current; - - GLfloat Parameters[MAX_PROGRAM_ENV_PARAMS][4]; /**< Env params */ - - /** Cache of fixed-function programs */ - struct gl_program_cache *Cache; -}; - -/** - * Context state for fragment programs. - */ -struct gl_fragment_program_state -{ - GLboolean Enabled; /**< User-set fragment program enable flag */ - GLboolean _Enabled; /**< Enabled and _valid_ user program? */ - struct gl_fragment_program *Current; /**< User-bound fragment program */ - - /** Currently enabled and valid fragment program (including internal - * programs, user-defined fragment programs and GLSL fragment shaders). - * This is the program we must use when rendering. - */ - struct gl_fragment_program *_Current; - - GLfloat Parameters[MAX_PROGRAM_ENV_PARAMS][4]; /**< Env params */ - - /** Should fixed-function texturing be implemented with a fragment prog? */ - GLboolean _MaintainTexEnvProgram; - - /** Program to emulate fixed-function texture env/combine (see above) */ - struct gl_fragment_program *_TexEnvProgram; - - /** Cache of fixed-function programs */ - struct gl_program_cache *Cache; -}; - - -/** - * ATI_fragment_shader runtime state - */ -#define ATI_FS_INPUT_PRIMARY 0 -#define ATI_FS_INPUT_SECONDARY 1 - -struct atifs_instruction; -struct atifs_setupinst; - -/** - * ATI fragment shader - */ -struct ati_fragment_shader -{ - GLuint Id; - GLint RefCount; - struct atifs_instruction *Instructions[2]; - struct atifs_setupinst *SetupInst[2]; - GLfloat Constants[8][4]; - GLbitfield LocalConstDef; /**< Indicates which constants have been set */ - GLubyte numArithInstr[2]; - GLubyte regsAssigned[2]; - GLubyte NumPasses; /**< 1 or 2 */ - GLubyte cur_pass; - GLubyte last_optype; - GLboolean interpinp1; - GLboolean isValid; - GLuint swizzlerq; -}; - -/** - * Context state for GL_ATI_fragment_shader - */ -struct gl_ati_fragment_shader_state -{ - GLboolean Enabled; - GLboolean _Enabled; /**< enabled and valid shader? */ - GLboolean Compiling; - GLfloat GlobalConstants[8][4]; - struct ati_fragment_shader *Current; -}; - - -/** - * Occlusion/timer query object. - */ -struct gl_query_object -{ - GLenum Target; /**< The query target, when active */ - GLuint Id; /**< hash table ID/name */ - GLuint64EXT Result; /**< the counter */ - GLboolean Active; /**< inside Begin/EndQuery */ - GLboolean Ready; /**< result is ready? */ -}; - - -/** - * Context state for query objects. - */ -struct gl_query_state -{ - struct _mesa_HashTable *QueryObjects; - struct gl_query_object *CurrentOcclusionObject; /* GL_ARB_occlusion_query */ - struct gl_query_object *CurrentTimerObject; /* GL_EXT_timer_query */ - - /** GL_NV_conditional_render */ - struct gl_query_object *CondRenderQuery; - - /** GL_EXT_transform_feedback */ - struct gl_query_object *PrimitivesGenerated; - struct gl_query_object *PrimitivesWritten; - - /** GL_ARB_timer_query */ - struct gl_query_object *TimeElapsed; - - GLenum CondRenderMode; -}; - - -/** Sync object state */ -struct gl_sync_object { - struct simple_node link; - GLenum Type; /**< GL_SYNC_FENCE */ - GLuint Name; /**< Fence name */ - GLint RefCount; /**< Reference count */ - GLboolean DeletePending; /**< Object was deleted while there were still - * live references (e.g., sync not yet finished) - */ - GLenum SyncCondition; - GLbitfield Flags; /**< Flags passed to glFenceSync */ - GLuint StatusFlag:1; /**< Has the sync object been signaled? */ -}; - - -/** Set by #pragma directives */ -struct gl_sl_pragmas -{ - GLboolean IgnoreOptimize; /**< ignore #pragma optimize(on/off) ? */ - GLboolean IgnoreDebug; /**< ignore #pragma debug(on/off) ? */ - GLboolean Optimize; /**< defaults on */ - GLboolean Debug; /**< defaults off */ -}; - - -/** - * A GLSL vertex or fragment shader object. - */ -struct gl_shader -{ - GLenum Type; /**< GL_FRAGMENT_SHADER || GL_VERTEX_SHADER || GL_GEOMETRY_SHADER_ARB (first field!) */ - GLuint Name; /**< AKA the handle */ - GLint RefCount; /**< Reference count */ - GLboolean DeletePending; - GLboolean CompileStatus; - const GLchar *Source; /**< Source code string */ - GLuint SourceChecksum; /**< for debug/logging purposes */ - struct gl_program *Program; /**< Post-compile assembly code */ - GLchar *InfoLog; - struct gl_sl_pragmas Pragmas; - - unsigned Version; /**< GLSL version used for linking */ - - struct exec_list *ir; - struct glsl_symbol_table *symbols; - - /** Shaders containing built-in functions that are used for linking. */ - struct gl_shader *builtins_to_link[16]; - unsigned num_builtins_to_link; -}; - - -/** - * A GLSL program object. - * Basically a linked collection of vertex and fragment shaders. - */ -struct gl_shader_program -{ - GLenum Type; /**< Always GL_SHADER_PROGRAM (internal token) */ - GLuint Name; /**< aka handle or ID */ - GLint RefCount; /**< Reference count */ - GLboolean DeletePending; - - GLuint NumShaders; /**< number of attached shaders */ - struct gl_shader **Shaders; /**< List of attached the shaders */ - - /** User-defined attribute bindings (glBindAttribLocation) */ - struct gl_program_parameter_list *Attributes; - - /** Transform feedback varyings */ - struct { - GLenum BufferMode; - GLuint NumVarying; - GLchar **VaryingNames; /**< Array [NumVarying] of char * */ - } TransformFeedback; - - /** Geometry shader state - copied into gl_geometry_program at link time */ - struct { - GLint VerticesOut; - GLenum InputType; /**< GL_POINTS, GL_LINES, GL_LINES_ADJACENCY_ARB, - GL_TRIANGLES, or GL_TRIANGLES_ADJACENCY_ARB */ - GLenum OutputType; /**< GL_POINTS, GL_LINE_STRIP or GL_TRIANGLE_STRIP */ - } Geom; - - /* post-link info: */ - struct gl_vertex_program *VertexProgram; /**< Linked vertex program */ - struct gl_fragment_program *FragmentProgram; /**< Linked fragment prog */ - struct gl_geometry_program *GeometryProgram; /**< Linked geometry prog */ - struct gl_uniform_list *Uniforms; - struct gl_program_parameter_list *Varying; - GLboolean LinkStatus; /**< GL_LINK_STATUS */ - GLboolean Validated; - GLboolean _Used; /**< Ever used for drawing? */ - GLchar *InfoLog; - - unsigned Version; /**< GLSL version used for linking */ - - /** - * Per-stage shaders resulting from the first stage of linking. - * - * Set of linked shaders for this program. The array is accessed using the - * \c MESA_SHADER_* defines. Entries for non-existent stages will be - * \c NULL. - */ - struct gl_shader *_LinkedShaders[MESA_SHADER_TYPES]; -}; - - -#define GLSL_DUMP 0x1 /**< Dump shaders to stdout */ -#define GLSL_LOG 0x2 /**< Write shaders to files */ -#define GLSL_OPT 0x4 /**< Force optimizations (override pragmas) */ -#define GLSL_NO_OPT 0x8 /**< Force no optimizations (override pragmas) */ -#define GLSL_UNIFORMS 0x10 /**< Print glUniform calls */ -#define GLSL_NOP_VERT 0x20 /**< Force no-op vertex shaders */ -#define GLSL_NOP_FRAG 0x40 /**< Force no-op fragment shaders */ -#define GLSL_USE_PROG 0x80 /**< Log glUseProgram calls */ - - -/** - * Context state for GLSL vertex/fragment shaders. - */ -struct gl_shader_state -{ - /** - * Programs used for rendering - * - * There is a separate program set for each shader stage. If - * GL_EXT_separate_shader_objects is not supported, each of these must point - * to \c NULL or to the same program. - */ - struct gl_shader_program *CurrentVertexProgram; - struct gl_shader_program *CurrentGeometryProgram; - struct gl_shader_program *CurrentFragmentProgram; - - /** - * Program used by glUniform calls. - * - * Explicitly set by \c glUseProgram and \c glActiveProgramEXT. - */ - struct gl_shader_program *ActiveProgram; - - void *MemPool; - - GLbitfield Flags; /**< Mask of GLSL_x flags */ -}; - -/** - * Compiler options for a single GLSL shaders type - */ -struct gl_shader_compiler_options -{ - /** Driver-selectable options: */ - GLboolean EmitCondCodes; /**< Use condition codes? */ - GLboolean EmitNVTempInitialization; /**< 0-fill NV temp registers */ - /** - * Attempts to flatten all ir_if (OPCODE_IF) for GPUs that can't - * support control flow. - */ - GLboolean EmitNoIfs; - GLboolean EmitNoLoops; - GLboolean EmitNoFunctions; - GLboolean EmitNoCont; /**< Emit CONT opcode? */ - GLboolean EmitNoMainReturn; /**< Emit CONT/RET opcodes? */ - GLboolean EmitNoNoise; /**< Emit NOISE opcodes? */ - GLboolean EmitNoPow; /**< Emit POW opcodes? */ - - /** - * \name Forms of indirect addressing the driver cannot do. - */ - /*@{*/ - GLboolean EmitNoIndirectInput; /**< No indirect addressing of inputs */ - GLboolean EmitNoIndirectOutput; /**< No indirect addressing of outputs */ - GLboolean EmitNoIndirectTemp; /**< No indirect addressing of temps */ - GLboolean EmitNoIndirectUniform; /**< No indirect addressing of constants */ - /*@}*/ - - GLuint MaxUnrollIterations; - - struct gl_sl_pragmas DefaultPragmas; /**< Default #pragma settings */ -}; - -/** - * Transform feedback object state - */ -struct gl_transform_feedback_object -{ - GLuint Name; /**< AKA the object ID */ - GLint RefCount; - GLboolean Active; /**< Is transform feedback enabled? */ - GLboolean Paused; /**< Is transform feedback paused? */ - - /** The feedback buffers */ - GLuint BufferNames[MAX_FEEDBACK_ATTRIBS]; - struct gl_buffer_object *Buffers[MAX_FEEDBACK_ATTRIBS]; - - /** Start of feedback data in dest buffer */ - GLintptr Offset[MAX_FEEDBACK_ATTRIBS]; - /** Max data to put into dest buffer (in bytes) */ - GLsizeiptr Size[MAX_FEEDBACK_ATTRIBS]; -}; - - -/** - * Context state for transform feedback. - */ -struct gl_transform_feedback -{ - GLenum Mode; /**< GL_POINTS, GL_LINES or GL_TRIANGLES */ - - GLboolean RasterDiscard; /**< GL_RASTERIZER_DISCARD */ - - /** The general binding point (GL_TRANSFORM_FEEDBACK_BUFFER) */ - struct gl_buffer_object *CurrentBuffer; - - /** The table of all transform feedback objects */ - struct _mesa_HashTable *Objects; - - /** The current xform-fb object (GL_TRANSFORM_FEEDBACK_BINDING) */ - struct gl_transform_feedback_object *CurrentObject; - - /** The default xform-fb object (Name==0) */ - struct gl_transform_feedback_object *DefaultObject; -}; - - - -/** - * State which can be shared by multiple contexts: - */ -struct gl_shared_state -{ - _glthread_Mutex Mutex; /**< for thread safety */ - GLint RefCount; /**< Reference count */ - struct _mesa_HashTable *DisplayList; /**< Display lists hash table */ - struct _mesa_HashTable *TexObjects; /**< Texture objects hash table */ - - /** Default texture objects (shared by all texture units) */ - struct gl_texture_object *DefaultTex[NUM_TEXTURE_TARGETS]; - - /** Fallback texture used when a bound texture is incomplete */ - struct gl_texture_object *FallbackTex; - - /** - * \name Thread safety and statechange notification for texture - * objects. - * - * \todo Improve the granularity of locking. - */ - /*@{*/ - _glthread_Mutex TexMutex; /**< texobj thread safety */ - GLuint TextureStateStamp; /**< state notification for shared tex */ - /*@}*/ - - /** Default buffer object for vertex arrays that aren't in VBOs */ - struct gl_buffer_object *NullBufferObj; - - /** - * \name Vertex/geometry/fragment programs - */ - /*@{*/ - struct _mesa_HashTable *Programs; /**< All vertex/fragment programs */ - struct gl_vertex_program *DefaultVertexProgram; - struct gl_fragment_program *DefaultFragmentProgram; - struct gl_geometry_program *DefaultGeometryProgram; - /*@}*/ - - /* GL_ATI_fragment_shader */ - struct _mesa_HashTable *ATIShaders; - struct ati_fragment_shader *DefaultFragmentShader; - - struct _mesa_HashTable *BufferObjects; - - /** Table of both gl_shader and gl_shader_program objects */ - struct _mesa_HashTable *ShaderObjects; - - /* GL_EXT_framebuffer_object */ - struct _mesa_HashTable *RenderBuffers; - struct _mesa_HashTable *FrameBuffers; - - /* GL_ARB_sync */ - struct simple_node SyncObjects; - - void *DriverData; /**< Device driver shared state */ -}; - - - - -/** - * A renderbuffer stores colors or depth values or stencil values. - * A framebuffer object will have a collection of these. - * Data are read/written to the buffer with a handful of Get/Put functions. - * - * Instances of this object are allocated with the Driver's NewRenderbuffer - * hook. Drivers will likely wrap this class inside a driver-specific - * class to simulate inheritance. - */ -struct gl_renderbuffer -{ -#define RB_MAGIC 0xaabbccdd - int Magic; /** XXX TEMPORARY DEBUG INFO */ - _glthread_Mutex Mutex; /**< for thread safety */ - GLuint ClassID; /**< Useful for drivers */ - GLuint Name; - GLint RefCount; - GLuint Width, Height; - GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */ - - GLenum InternalFormat; /**< The user-specified format */ - GLenum _BaseFormat; /**< Either GL_RGB, GL_RGBA, GL_DEPTH_COMPONENT or - GL_STENCIL_INDEX. */ - gl_format Format; /**< The actual renderbuffer memory format */ - - GLubyte NumSamples; - - GLenum DataType; /**< Type of values passed to the Get/Put functions */ - GLvoid *Data; /**< This may not be used by some kinds of RBs */ - - /* Used to wrap one renderbuffer around another: */ - struct gl_renderbuffer *Wrapped; - - /* Delete this renderbuffer */ - void (*Delete)(struct gl_renderbuffer *rb); - - /* Allocate new storage for this renderbuffer */ - GLboolean (*AllocStorage)(struct gl_context *ctx, struct gl_renderbuffer *rb, - GLenum internalFormat, - GLuint width, GLuint height); - - /* Lock/Unlock are called before/after calling the Get/Put functions. - * Not sure this is the right place for these yet. - void (*Lock)(struct gl_context *ctx, struct gl_renderbuffer *rb); - void (*Unlock)(struct gl_context *ctx, struct gl_renderbuffer *rb); - */ - - /* Return a pointer to the element/pixel at (x,y). - * Should return NULL if the buffer memory can't be directly addressed. - */ - void *(*GetPointer)(struct gl_context *ctx, struct gl_renderbuffer *rb, - GLint x, GLint y); - - /* Get/Read a row of values. - * The values will be of format _BaseFormat and type DataType. - */ - void (*GetRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, - GLint x, GLint y, void *values); - - /* Get/Read values at arbitrary locations. - * The values will be of format _BaseFormat and type DataType. - */ - void (*GetValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, - const GLint x[], const GLint y[], void *values); - - /* Put/Write a row of values. - * The values will be of format _BaseFormat and type DataType. - */ - void (*PutRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, - GLint x, GLint y, const void *values, const GLubyte *mask); - - /* Put/Write a row of RGB values. This is a special-case routine that's - * only used for RGBA renderbuffers when the source data is GL_RGB. That's - * a common case for glDrawPixels and some triangle routines. - * The values will be of format GL_RGB and type DataType. - */ - void (*PutRowRGB)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, - GLint x, GLint y, const void *values, const GLubyte *mask); - - - /* Put/Write a row of identical values. - * The values will be of format _BaseFormat and type DataType. - */ - void (*PutMonoRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, - GLint x, GLint y, const void *value, const GLubyte *mask); - - /* Put/Write values at arbitrary locations. - * The values will be of format _BaseFormat and type DataType. - */ - void (*PutValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, - const GLint x[], const GLint y[], const void *values, - const GLubyte *mask); - /* Put/Write identical values at arbitrary locations. - * The values will be of format _BaseFormat and type DataType. - */ - void (*PutMonoValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, - GLuint count, const GLint x[], const GLint y[], - const void *value, const GLubyte *mask); -}; - - -/** - * A renderbuffer attachment points to either a texture object (and specifies - * a mipmap level, cube face or 3D texture slice) or points to a renderbuffer. - */ -struct gl_renderbuffer_attachment -{ - GLenum Type; /**< \c GL_NONE or \c GL_TEXTURE or \c GL_RENDERBUFFER_EXT */ - GLboolean Complete; - - /** - * If \c Type is \c GL_RENDERBUFFER_EXT, this stores a pointer to the - * application supplied renderbuffer object. - */ - struct gl_renderbuffer *Renderbuffer; - - /** - * If \c Type is \c GL_TEXTURE, this stores a pointer to the application - * supplied texture object. - */ - struct gl_texture_object *Texture; - GLuint TextureLevel; /**< Attached mipmap level. */ - GLuint CubeMapFace; /**< 0 .. 5, for cube map textures. */ - GLuint Zoffset; /**< Slice for 3D textures, or layer for both 1D - * and 2D array textures */ -}; - - -/** - * A framebuffer is a collection of renderbuffers (color, depth, stencil, etc). - * In C++ terms, think of this as a base class from which device drivers - * will make derived classes. - */ -struct gl_framebuffer -{ - _glthread_Mutex Mutex; /**< for thread safety */ - /** - * If zero, this is a window system framebuffer. If non-zero, this - * is a FBO framebuffer; note that for some devices (i.e. those with - * a natural pixel coordinate system for FBOs that differs from the - * OpenGL/Mesa coordinate system), this means that the viewport, - * polygon face orientation, and polygon stipple will have to be inverted. - */ - GLuint Name; - - GLint RefCount; - GLboolean DeletePending; - - /** - * The framebuffer's visual. Immutable if this is a window system buffer. - * Computed from attachments if user-made FBO. - */ - struct gl_config Visual; - - GLboolean Initialized; - - GLuint Width, Height; /**< size of frame buffer in pixels */ - - /** \name Drawing bounds (Intersection of buffer size and scissor box) */ - /*@{*/ - GLint _Xmin, _Xmax; /**< inclusive */ - GLint _Ymin, _Ymax; /**< exclusive */ - /*@}*/ - - /** \name Derived Z buffer stuff */ - /*@{*/ - GLuint _DepthMax; /**< Max depth buffer value */ - GLfloat _DepthMaxF; /**< Float max depth buffer value */ - GLfloat _MRD; /**< minimum resolvable difference in Z values */ - /*@}*/ - - /** One of the GL_FRAMEBUFFER_(IN)COMPLETE_* tokens */ - GLenum _Status; - - /** Integer color values */ - GLboolean _IntegerColor; - - /** Array of all renderbuffer attachments, indexed by BUFFER_* tokens. */ - struct gl_renderbuffer_attachment Attachment[BUFFER_COUNT]; - - /* In unextended OpenGL these vars are part of the GL_COLOR_BUFFER - * attribute group and GL_PIXEL attribute group, respectively. - */ - GLenum ColorDrawBuffer[MAX_DRAW_BUFFERS]; - GLenum ColorReadBuffer; - - /** Computed from ColorDraw/ReadBuffer above */ - GLuint _NumColorDrawBuffers; - GLint _ColorDrawBufferIndexes[MAX_DRAW_BUFFERS]; /**< BUFFER_x or -1 */ - GLint _ColorReadBufferIndex; /* -1 = None */ - struct gl_renderbuffer *_ColorDrawBuffers[MAX_DRAW_BUFFERS]; - struct gl_renderbuffer *_ColorReadBuffer; - - /** The Actual depth/stencil buffers to use. May be wrappers around the - * depth/stencil buffers attached above. */ - struct gl_renderbuffer *_DepthBuffer; - struct gl_renderbuffer *_StencilBuffer; - - /** Delete this framebuffer */ - void (*Delete)(struct gl_framebuffer *fb); -}; - - -/** - * Precision info for shader datatypes. See glGetShaderPrecisionFormat(). - */ -struct gl_precision -{ - GLushort RangeMin; /**< min value exponent */ - GLushort RangeMax; /**< max value exponent */ - GLushort Precision; /**< number of mantissa bits */ -}; - - -/** - * Limits for vertex and fragment programs/shaders. - */ -struct gl_program_constants -{ - /* logical limits */ - GLuint MaxInstructions; - GLuint MaxAluInstructions; - GLuint MaxTexInstructions; - GLuint MaxTexIndirections; - GLuint MaxAttribs; - GLuint MaxTemps; - GLuint MaxAddressRegs; - GLuint MaxParameters; - GLuint MaxLocalParams; - GLuint MaxEnvParams; - /* native/hardware limits */ - GLuint MaxNativeInstructions; - GLuint MaxNativeAluInstructions; - GLuint MaxNativeTexInstructions; - GLuint MaxNativeTexIndirections; - GLuint MaxNativeAttribs; - GLuint MaxNativeTemps; - GLuint MaxNativeAddressRegs; - GLuint MaxNativeParameters; - /* For shaders */ - GLuint MaxUniformComponents; - /* GL_ARB_geometry_shader4 */ - GLuint MaxGeometryTextureImageUnits; - GLuint MaxGeometryVaryingComponents; - GLuint MaxVertexVaryingComponents; - GLuint MaxGeometryUniformComponents; - GLuint MaxGeometryOutputVertices; - GLuint MaxGeometryTotalOutputComponents; - /* ES 2.0 and GL_ARB_ES2_compatibility */ - struct gl_precision LowFloat, MediumFloat, HighFloat; - struct gl_precision LowInt, MediumInt, HighInt; -}; - - -/** - * Constants which may be overridden by device driver during context creation - * but are never changed after that. - */ -struct gl_constants -{ - GLint MaxTextureMbytes; /**< Max memory per image, in MB */ - GLint MaxTextureLevels; /**< Max mipmap levels. */ - GLint Max3DTextureLevels; /**< Max mipmap levels for 3D textures */ - GLint MaxCubeTextureLevels; /**< Max mipmap levels for cube textures */ - GLint MaxArrayTextureLayers; /**< Max layers in array textures */ - GLint MaxTextureRectSize; /**< Max rectangle texture size, in pixes */ - GLuint MaxTextureCoordUnits; - GLuint MaxTextureImageUnits; - GLuint MaxVertexTextureImageUnits; - GLuint MaxCombinedTextureImageUnits; - GLuint MaxTextureUnits; /**< = MIN(CoordUnits, ImageUnits) */ - GLfloat MaxTextureMaxAnisotropy; /**< GL_EXT_texture_filter_anisotropic */ - GLfloat MaxTextureLodBias; /**< GL_EXT_texture_lod_bias */ - - GLuint MaxArrayLockSize; - - GLint SubPixelBits; - - GLfloat MinPointSize, MaxPointSize; /**< aliased */ - GLfloat MinPointSizeAA, MaxPointSizeAA; /**< antialiased */ - GLfloat PointSizeGranularity; - GLfloat MinLineWidth, MaxLineWidth; /**< aliased */ - GLfloat MinLineWidthAA, MaxLineWidthAA; /**< antialiased */ - GLfloat LineWidthGranularity; - - GLuint MaxColorTableSize; - - GLuint MaxClipPlanes; - GLuint MaxLights; - GLfloat MaxShininess; /**< GL_NV_light_max_exponent */ - GLfloat MaxSpotExponent; /**< GL_NV_light_max_exponent */ - - GLuint MaxViewportWidth, MaxViewportHeight; - - struct gl_program_constants VertexProgram; /**< GL_ARB_vertex_program */ - struct gl_program_constants FragmentProgram; /**< GL_ARB_fragment_program */ - struct gl_program_constants GeometryProgram; /**< GL_ARB_geometry_shader4 */ - GLuint MaxProgramMatrices; - GLuint MaxProgramMatrixStackDepth; - - /** vertex array / buffer object bounds checking */ - GLboolean CheckArrayBounds; - - GLuint MaxDrawBuffers; /**< GL_ARB_draw_buffers */ - - GLuint MaxColorAttachments; /**< GL_EXT_framebuffer_object */ - GLuint MaxRenderbufferSize; /**< GL_EXT_framebuffer_object */ - GLuint MaxSamples; /**< GL_ARB_framebuffer_object */ - - GLuint MaxVarying; /**< Number of float[4] varying parameters */ - - GLuint GLSLVersion; /**< GLSL version supported (ex: 120 = 1.20) */ - - /** Which texture units support GL_ATI_envmap_bumpmap as targets */ - GLbitfield SupportedBumpUnits; - - /** - * Maximum amount of time, measured in nanseconds, that the server can wait. - */ - GLuint64 MaxServerWaitTimeout; - - /** GL_EXT_provoking_vertex */ - GLboolean QuadsFollowProvokingVertexConvention; - - /** OpenGL version 3.0 */ - GLbitfield ContextFlags; /**< Ex: GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT */ - - /** OpenGL version 3.2 */ - GLbitfield ProfileMask; /**< Mask of CONTEXT_x_PROFILE_BIT */ - - /** GL_EXT_transform_feedback */ - GLuint MaxTransformFeedbackSeparateAttribs; - GLuint MaxTransformFeedbackSeparateComponents; - GLuint MaxTransformFeedbackInterleavedComponents; - - /** GL_EXT_gpu_shader4 */ - GLint MinProgramTexelOffset, MaxProgramTexelOffset; - - /* GL_EXT_framebuffer_sRGB */ - GLboolean sRGBCapable; /* can enable sRGB blend/update on FBOs */ -}; - - -/** - * Enable flag for each OpenGL extension. Different device drivers will - * enable different extensions at runtime. - */ -struct gl_extensions -{ - GLboolean dummy; /* don't remove this! */ - GLboolean dummy_true; /* Set true by _mesa_init_extensions(). */ - GLboolean dummy_false; /* Set false by _mesa_init_extensions(). */ - GLboolean ARB_ES2_compatibility; - GLboolean ARB_blend_func_extended; - GLboolean ARB_copy_buffer; - GLboolean ARB_depth_buffer_float; - GLboolean ARB_depth_clamp; - GLboolean ARB_depth_texture; - GLboolean ARB_draw_buffers; - GLboolean ARB_draw_buffers_blend; - GLboolean ARB_draw_elements_base_vertex; - GLboolean ARB_draw_instanced; - GLboolean ARB_fragment_coord_conventions; - GLboolean ARB_fragment_program; - GLboolean ARB_fragment_program_shadow; - GLboolean ARB_fragment_shader; - GLboolean ARB_framebuffer_object; - GLboolean ARB_explicit_attrib_location; - GLboolean ARB_geometry_shader4; - GLboolean ARB_half_float_pixel; - GLboolean ARB_half_float_vertex; - GLboolean ARB_instanced_arrays; - GLboolean ARB_map_buffer_range; - GLboolean ARB_multisample; - GLboolean ARB_multitexture; - GLboolean ARB_occlusion_query; - GLboolean ARB_occlusion_query2; - GLboolean ARB_point_sprite; - GLboolean ARB_sampler_objects; - GLboolean ARB_seamless_cube_map; - GLboolean ARB_shader_objects; - GLboolean ARB_shader_stencil_export; - GLboolean ARB_shading_language_100; - GLboolean ARB_shadow; - GLboolean ARB_shadow_ambient; - GLboolean ARB_sync; - GLboolean ARB_texture_border_clamp; - GLboolean ARB_texture_buffer_object; - GLboolean ARB_texture_compression; - GLboolean ARB_texture_compression_rgtc; - GLboolean ARB_texture_cube_map; - GLboolean ARB_texture_env_combine; - GLboolean ARB_texture_env_crossbar; - GLboolean ARB_texture_env_dot3; - GLboolean ARB_texture_float; - GLboolean ARB_texture_mirrored_repeat; - GLboolean ARB_texture_multisample; - GLboolean ARB_texture_non_power_of_two; - GLboolean ARB_texture_rg; - GLboolean ARB_texture_rgb10_a2ui; - GLboolean ARB_timer_query; - GLboolean ARB_transform_feedback2; - GLboolean ARB_transpose_matrix; - GLboolean ARB_uniform_buffer_object; - GLboolean ARB_vertex_array_object; - GLboolean ARB_vertex_buffer_object; - GLboolean ARB_vertex_program; - GLboolean ARB_vertex_shader; - GLboolean ARB_vertex_type_2_10_10_10_rev; - GLboolean ARB_window_pos; - GLboolean EXT_abgr; - GLboolean EXT_bgra; - GLboolean EXT_blend_color; - GLboolean EXT_blend_equation_separate; - GLboolean EXT_blend_func_separate; - GLboolean EXT_blend_logic_op; - GLboolean EXT_blend_minmax; - GLboolean EXT_blend_subtract; - GLboolean EXT_clip_volume_hint; - GLboolean EXT_compiled_vertex_array; - GLboolean EXT_copy_texture; - GLboolean EXT_depth_bounds_test; - GLboolean EXT_draw_buffers2; - GLboolean EXT_draw_range_elements; - GLboolean EXT_fog_coord; - GLboolean EXT_framebuffer_blit; - GLboolean EXT_framebuffer_multisample; - GLboolean EXT_framebuffer_object; - GLboolean EXT_framebuffer_sRGB; - GLboolean EXT_gpu_program_parameters; - GLboolean EXT_gpu_shader4; - GLboolean EXT_multi_draw_arrays; - GLboolean EXT_paletted_texture; - GLboolean EXT_packed_depth_stencil; - GLboolean EXT_packed_float; - GLboolean EXT_packed_pixels; - GLboolean EXT_pixel_buffer_object; - GLboolean EXT_point_parameters; - GLboolean EXT_polygon_offset; - GLboolean EXT_provoking_vertex; - GLboolean EXT_rescale_normal; - GLboolean EXT_shadow_funcs; - GLboolean EXT_secondary_color; - GLboolean EXT_separate_shader_objects; - GLboolean EXT_separate_specular_color; - GLboolean EXT_shared_texture_palette; - GLboolean EXT_stencil_wrap; - GLboolean EXT_stencil_two_side; - GLboolean EXT_subtexture; - GLboolean EXT_texture; - GLboolean EXT_texture_object; - GLboolean EXT_texture3D; - GLboolean EXT_texture_array; - GLboolean EXT_texture_compression_s3tc; - GLboolean EXT_texture_env_add; - GLboolean EXT_texture_env_combine; - GLboolean EXT_texture_env_dot3; - GLboolean EXT_texture_filter_anisotropic; - GLboolean EXT_texture_integer; - GLboolean EXT_texture_lod_bias; - GLboolean EXT_texture_mirror_clamp; - GLboolean EXT_texture_shared_exponent; - GLboolean EXT_texture_sRGB; - GLboolean EXT_texture_sRGB_decode; - GLboolean EXT_texture_swizzle; - GLboolean EXT_transform_feedback; - GLboolean EXT_timer_query; - GLboolean EXT_vertex_array; - GLboolean EXT_vertex_array_bgra; - GLboolean EXT_vertex_array_set; - GLboolean OES_standard_derivatives; - /* vendor extensions */ - GLboolean AMD_conservative_depth; - GLboolean APPLE_client_storage; - GLboolean APPLE_packed_pixels; - GLboolean APPLE_vertex_array_object; - GLboolean APPLE_object_purgeable; - GLboolean ATI_envmap_bumpmap; - GLboolean ATI_texture_mirror_once; - GLboolean ATI_texture_env_combine3; - GLboolean ATI_fragment_shader; - GLboolean ATI_separate_stencil; - GLboolean IBM_rasterpos_clip; - GLboolean IBM_multimode_draw_arrays; - GLboolean MESA_pack_invert; - GLboolean MESA_resize_buffers; - GLboolean MESA_ycbcr_texture; - GLboolean MESA_texture_array; - GLboolean MESA_texture_signed_rgba; - GLboolean NV_blend_square; - GLboolean NV_conditional_render; - GLboolean NV_fragment_program; - GLboolean NV_fragment_program_option; - GLboolean NV_light_max_exponent; - GLboolean NV_point_sprite; - GLboolean NV_primitive_restart; - GLboolean NV_texgen_reflection; - GLboolean NV_texture_env_combine4; - GLboolean NV_texture_rectangle; - GLboolean NV_vertex_program; - GLboolean NV_vertex_program1_1; - GLboolean OES_read_format; - GLboolean SGI_texture_color_table; - GLboolean SGIS_generate_mipmap; - GLboolean SGIS_texture_edge_clamp; - GLboolean SGIS_texture_lod; - GLboolean TDFX_texture_compression_FXT1; - GLboolean S3_s3tc; - GLboolean OES_EGL_image; - GLboolean OES_draw_texture; - GLboolean EXT_texture_format_BGRA8888; - GLboolean extension_sentinel; - /** The extension string */ - const GLubyte *String; - /** Number of supported extensions */ - GLuint Count; -}; - - -/** - * A stack of matrices (projection, modelview, color, texture, etc). - */ -struct gl_matrix_stack -{ - GLmatrix *Top; /**< points into Stack */ - GLmatrix *Stack; /**< array [MaxDepth] of GLmatrix */ - GLuint Depth; /**< 0 <= Depth < MaxDepth */ - GLuint MaxDepth; /**< size of Stack[] array */ - GLuint DirtyFlag; /**< _NEW_MODELVIEW or _NEW_PROJECTION, for example */ -}; - - -/** - * \name Bits for image transfer operations - * \sa __struct gl_contextRec::ImageTransferState. - */ -/*@{*/ -#define IMAGE_SCALE_BIAS_BIT 0x1 -#define IMAGE_SHIFT_OFFSET_BIT 0x2 -#define IMAGE_MAP_COLOR_BIT 0x4 -#define IMAGE_CLAMP_BIT 0x800 - - -/** Pixel Transfer ops */ -#define IMAGE_BITS (IMAGE_SCALE_BIAS_BIT | \ - IMAGE_SHIFT_OFFSET_BIT | \ - IMAGE_MAP_COLOR_BIT) - -/** - * \name Bits to indicate what state has changed. - */ -/*@{*/ -#define _NEW_MODELVIEW (1 << 0) /**< gl_context::ModelView */ -#define _NEW_PROJECTION (1 << 1) /**< gl_context::Projection */ -#define _NEW_TEXTURE_MATRIX (1 << 2) /**< gl_context::TextureMatrix */ -#define _NEW_COLOR (1 << 3) /**< gl_context::Color */ -#define _NEW_DEPTH (1 << 4) /**< gl_context::Depth */ -#define _NEW_EVAL (1 << 5) /**< gl_context::Eval, EvalMap */ -#define _NEW_FOG (1 << 6) /**< gl_context::Fog */ -#define _NEW_HINT (1 << 7) /**< gl_context::Hint */ -#define _NEW_LIGHT (1 << 8) /**< gl_context::Light */ -#define _NEW_LINE (1 << 9) /**< gl_context::Line */ -#define _NEW_PIXEL (1 << 10) /**< gl_context::Pixel */ -#define _NEW_POINT (1 << 11) /**< gl_context::Point */ -#define _NEW_POLYGON (1 << 12) /**< gl_context::Polygon */ -#define _NEW_POLYGONSTIPPLE (1 << 13) /**< gl_context::PolygonStipple */ -#define _NEW_SCISSOR (1 << 14) /**< gl_context::Scissor */ -#define _NEW_STENCIL (1 << 15) /**< gl_context::Stencil */ -#define _NEW_TEXTURE (1 << 16) /**< gl_context::Texture */ -#define _NEW_TRANSFORM (1 << 17) /**< gl_context::Transform */ -#define _NEW_VIEWPORT (1 << 18) /**< gl_context::Viewport */ -#define _NEW_PACKUNPACK (1 << 19) /**< gl_context::Pack, Unpack */ -#define _NEW_ARRAY (1 << 20) /**< gl_context::Array */ -#define _NEW_RENDERMODE (1 << 21) /**< gl_context::RenderMode, etc */ -#define _NEW_BUFFERS (1 << 22) /**< gl_context::Visual, DrawBuffer, */ -#define _NEW_CURRENT_ATTRIB (1 << 23) /**< gl_context::Current */ -#define _NEW_MULTISAMPLE (1 << 24) /**< gl_context::Multisample */ -#define _NEW_TRACK_MATRIX (1 << 25) /**< gl_context::VertexProgram */ -#define _NEW_PROGRAM (1 << 26) /**< New program/shader state */ -#define _NEW_PROGRAM_CONSTANTS (1 << 27) -#define _NEW_BUFFER_OBJECT (1 << 28) -#define _NEW_ALL ~0 -/*@}*/ - - -/** - * \name Bits to track array state changes - * - * Also used to summarize array enabled. - */ -/*@{*/ -#define _NEW_ARRAY_VERTEX VERT_BIT_POS -#define _NEW_ARRAY_WEIGHT VERT_BIT_WEIGHT -#define _NEW_ARRAY_NORMAL VERT_BIT_NORMAL -#define _NEW_ARRAY_COLOR0 VERT_BIT_COLOR0 -#define _NEW_ARRAY_COLOR1 VERT_BIT_COLOR1 -#define _NEW_ARRAY_FOGCOORD VERT_BIT_FOG -#define _NEW_ARRAY_INDEX VERT_BIT_COLOR_INDEX -#define _NEW_ARRAY_EDGEFLAG VERT_BIT_EDGEFLAG -#define _NEW_ARRAY_POINT_SIZE VERT_BIT_COLOR_INDEX /* aliased */ -#define _NEW_ARRAY_TEXCOORD_0 VERT_BIT_TEX0 -#define _NEW_ARRAY_TEXCOORD_1 VERT_BIT_TEX1 -#define _NEW_ARRAY_TEXCOORD_2 VERT_BIT_TEX2 -#define _NEW_ARRAY_TEXCOORD_3 VERT_BIT_TEX3 -#define _NEW_ARRAY_TEXCOORD_4 VERT_BIT_TEX4 -#define _NEW_ARRAY_TEXCOORD_5 VERT_BIT_TEX5 -#define _NEW_ARRAY_TEXCOORD_6 VERT_BIT_TEX6 -#define _NEW_ARRAY_TEXCOORD_7 VERT_BIT_TEX7 -#define _NEW_ARRAY_ATTRIB_0 VERT_BIT_GENERIC0 /* start at bit 16 */ -#define _NEW_ARRAY_ALL 0xffffffff - - -#define _NEW_ARRAY_TEXCOORD(i) (_NEW_ARRAY_TEXCOORD_0 << (i)) -#define _NEW_ARRAY_ATTRIB(i) (_NEW_ARRAY_ATTRIB_0 << (i)) -/*@}*/ - - - -/** - * \name A bunch of flags that we think might be useful to drivers. - * - * Set in the __struct gl_contextRec::_TriangleCaps bitfield. - */ -/*@{*/ -#define DD_FLATSHADE 0x1 -#define DD_SEPARATE_SPECULAR 0x2 -#define DD_TRI_CULL_FRONT_BACK 0x4 /* special case on some hw */ -#define DD_TRI_LIGHT_TWOSIDE 0x8 -#define DD_TRI_UNFILLED 0x10 -#define DD_TRI_SMOOTH 0x20 -#define DD_TRI_STIPPLE 0x40 -#define DD_TRI_OFFSET 0x80 -#define DD_LINE_SMOOTH 0x100 -#define DD_LINE_STIPPLE 0x200 -#define DD_POINT_SMOOTH 0x400 -#define DD_POINT_ATTEN 0x800 -#define DD_TRI_TWOSTENCIL 0x1000 -/*@}*/ - - -/** - * \name Define the state changes under which each of these bits might change - */ -/*@{*/ -#define _DD_NEW_FLATSHADE _NEW_LIGHT -#define _DD_NEW_SEPARATE_SPECULAR (_NEW_LIGHT | _NEW_FOG | _NEW_PROGRAM) -#define _DD_NEW_TRI_CULL_FRONT_BACK _NEW_POLYGON -#define _DD_NEW_TRI_LIGHT_TWOSIDE _NEW_LIGHT -#define _DD_NEW_TRI_UNFILLED _NEW_POLYGON -#define _DD_NEW_TRI_SMOOTH _NEW_POLYGON -#define _DD_NEW_TRI_STIPPLE _NEW_POLYGON -#define _DD_NEW_TRI_OFFSET _NEW_POLYGON -#define _DD_NEW_LINE_SMOOTH _NEW_LINE -#define _DD_NEW_LINE_STIPPLE _NEW_LINE -#define _DD_NEW_LINE_WIDTH _NEW_LINE -#define _DD_NEW_POINT_SMOOTH _NEW_POINT -#define _DD_NEW_POINT_SIZE _NEW_POINT -#define _DD_NEW_POINT_ATTEN _NEW_POINT -/*@}*/ - - -/** - * Composite state flags - */ -/*@{*/ -#define _MESA_NEW_NEED_EYE_COORDS (_NEW_LIGHT | \ - _NEW_TEXTURE | \ - _NEW_POINT | \ - _NEW_PROGRAM | \ - _NEW_MODELVIEW) - -#define _MESA_NEW_NEED_NORMALS (_NEW_LIGHT | \ - _NEW_TEXTURE) - -#define _MESA_NEW_TRANSFER_STATE (_NEW_PIXEL) -/*@}*/ - - - - -/* This has to be included here. */ -#include "dd.h" - - -/** - * Display list flags. - * Strictly this is a tnl-private concept, but it doesn't seem - * worthwhile adding a tnl private structure just to hold this one bit - * of information: - */ -#define DLIST_DANGLING_REFS 0x1 - - -/** Opaque declaration of display list payload data type */ -union gl_dlist_node; - - -/** - * Provide a location where information about a display list can be - * collected. Could be extended with driverPrivate structures, - * etc. in the future. - */ -struct gl_display_list -{ - GLuint Name; - GLbitfield Flags; /**< DLIST_x flags */ - /** The dlist commands are in a linked list of nodes */ - union gl_dlist_node *Head; -}; - - -/** - * State used during display list compilation and execution. - */ -struct gl_dlist_state -{ - GLuint CallDepth; /**< Current recursion calling depth */ - - struct gl_display_list *CurrentList; /**< List currently being compiled */ - union gl_dlist_node *CurrentBlock; /**< Pointer to current block of nodes */ - GLuint CurrentPos; /**< Index into current block of nodes */ - - GLvertexformat ListVtxfmt; - - GLubyte ActiveAttribSize[VERT_ATTRIB_MAX]; - GLfloat CurrentAttrib[VERT_ATTRIB_MAX][4]; - - GLubyte ActiveMaterialSize[MAT_ATTRIB_MAX]; - GLfloat CurrentMaterial[MAT_ATTRIB_MAX][4]; - - GLubyte ActiveIndex; - GLfloat CurrentIndex; - - GLubyte ActiveEdgeFlag; - GLboolean CurrentEdgeFlag; - - struct { - /* State known to have been set by the currently-compiling display - * list. Used to eliminate some redundant state changes. - */ - GLenum ShadeModel; - } Current; -}; - - -/** - * Enum for the OpenGL APIs we know about and may support. - */ -typedef enum -{ - API_OPENGL, - API_OPENGLES, - API_OPENGLES2 -} gl_api; - - -/** - * Mesa rendering context. - * - * This is the central context data structure for Mesa. Almost all - * OpenGL state is contained in this structure. - * Think of this as a base class from which device drivers will derive - * sub classes. - * - * The struct gl_context typedef names this structure. - */ -struct gl_context -{ - /** State possibly shared with other contexts in the address space */ - struct gl_shared_state *Shared; - - /** \name API function pointer tables */ - /*@{*/ - gl_api API; - struct _glapi_table *Save; /**< Display list save functions */ - struct _glapi_table *Exec; /**< Execute functions */ - struct _glapi_table *CurrentDispatch; /**< == Save or Exec !! */ - /*@}*/ - - struct gl_config Visual; - struct gl_framebuffer *DrawBuffer; /**< buffer for writing */ - struct gl_framebuffer *ReadBuffer; /**< buffer for reading */ - struct gl_framebuffer *WinSysDrawBuffer; /**< set with MakeCurrent */ - struct gl_framebuffer *WinSysReadBuffer; /**< set with MakeCurrent */ - - /** - * Device driver function pointer table - */ - struct dd_function_table Driver; - - void *DriverCtx; /**< Points to device driver context/state */ - - /** Core/Driver constants */ - struct gl_constants Const; - - /** \name The various 4x4 matrix stacks */ - /*@{*/ - struct gl_matrix_stack ModelviewMatrixStack; - struct gl_matrix_stack ProjectionMatrixStack; - struct gl_matrix_stack TextureMatrixStack[MAX_TEXTURE_UNITS]; - struct gl_matrix_stack ProgramMatrixStack[MAX_PROGRAM_MATRICES]; - struct gl_matrix_stack *CurrentStack; /**< Points to one of the above stacks */ - /*@}*/ - - /** Combined modelview and projection matrix */ - GLmatrix _ModelProjectMatrix; - - /** \name Display lists */ - struct gl_dlist_state ListState; - - GLboolean ExecuteFlag; /**< Execute GL commands? */ - GLboolean CompileFlag; /**< Compile GL commands into display list? */ - - /** Extension information */ - struct gl_extensions Extensions; - - /** Version info */ - GLuint VersionMajor, VersionMinor; - char *VersionString; - - /** \name State attribute stack (for glPush/PopAttrib) */ - /*@{*/ - GLuint AttribStackDepth; - struct gl_attrib_node *AttribStack[MAX_ATTRIB_STACK_DEPTH]; - /*@}*/ - - /** \name Renderer attribute groups - * - * We define a struct for each attribute group to make pushing and popping - * attributes easy. Also it's a good organization. - */ - /*@{*/ - struct gl_accum_attrib Accum; /**< Accum buffer attributes */ - struct gl_colorbuffer_attrib Color; /**< Color buffer attributes */ - struct gl_current_attrib Current; /**< Current attributes */ - struct gl_depthbuffer_attrib Depth; /**< Depth buffer attributes */ - struct gl_eval_attrib Eval; /**< Eval attributes */ - struct gl_fog_attrib Fog; /**< Fog attributes */ - struct gl_hint_attrib Hint; /**< Hint attributes */ - struct gl_light_attrib Light; /**< Light attributes */ - struct gl_line_attrib Line; /**< Line attributes */ - struct gl_list_attrib List; /**< List attributes */ - struct gl_multisample_attrib Multisample; - struct gl_pixel_attrib Pixel; /**< Pixel attributes */ - struct gl_point_attrib Point; /**< Point attributes */ - struct gl_polygon_attrib Polygon; /**< Polygon attributes */ - GLuint PolygonStipple[32]; /**< Polygon stipple */ - struct gl_scissor_attrib Scissor; /**< Scissor attributes */ - struct gl_stencil_attrib Stencil; /**< Stencil buffer attributes */ - struct gl_texture_attrib Texture; /**< Texture attributes */ - struct gl_transform_attrib Transform; /**< Transformation attributes */ - struct gl_viewport_attrib Viewport; /**< Viewport attributes */ - /*@}*/ - - /** \name Client attribute stack */ - /*@{*/ - GLuint ClientAttribStackDepth; - struct gl_attrib_node *ClientAttribStack[MAX_CLIENT_ATTRIB_STACK_DEPTH]; - /*@}*/ - - /** \name Client attribute groups */ - /*@{*/ - struct gl_array_attrib Array; /**< Vertex arrays */ - struct gl_pixelstore_attrib Pack; /**< Pixel packing */ - struct gl_pixelstore_attrib Unpack; /**< Pixel unpacking */ - struct gl_pixelstore_attrib DefaultPacking; /**< Default params */ - /*@}*/ - - /** \name Other assorted state (not pushed/popped on attribute stack) */ - /*@{*/ - struct gl_pixelmaps PixelMaps; - - struct gl_evaluators EvalMap; /**< All evaluators */ - struct gl_feedback Feedback; /**< Feedback */ - struct gl_selection Select; /**< Selection */ - - struct gl_program_state Program; /**< general program state */ - struct gl_vertex_program_state VertexProgram; - struct gl_fragment_program_state FragmentProgram; - struct gl_geometry_program_state GeometryProgram; - struct gl_ati_fragment_shader_state ATIFragmentShader; - - struct gl_shader_state Shader; /**< GLSL shader object state */ - struct gl_shader_compiler_options ShaderCompilerOptions[MESA_SHADER_TYPES]; - - struct gl_query_state Query; /**< occlusion, timer queries */ - - struct gl_transform_feedback TransformFeedback; - - struct gl_buffer_object *CopyReadBuffer; /**< GL_ARB_copy_buffer */ - struct gl_buffer_object *CopyWriteBuffer; /**< GL_ARB_copy_buffer */ - /*@}*/ - - struct gl_meta_state *Meta; /**< for "meta" operations */ - - /* GL_EXT_framebuffer_object */ - struct gl_renderbuffer *CurrentRenderbuffer; - - GLenum ErrorValue; /**< Last error code */ - - /** - * Recognize and silence repeated error debug messages in buggy apps. - */ - const char *ErrorDebugFmtString; - GLuint ErrorDebugCount; - - GLenum RenderMode; /**< either GL_RENDER, GL_SELECT, GL_FEEDBACK */ - GLbitfield NewState; /**< bitwise-or of _NEW_* flags */ - - GLboolean ViewportInitialized; /**< has viewport size been initialized? */ - - GLbitfield varying_vp_inputs; /**< mask of VERT_BIT_* flags */ - - /** \name Derived state */ - /*@{*/ - /** Bitwise-or of DD_* flags. Note that this bitfield may be used before - * state validation so they need to always be current. - */ - GLbitfield _TriangleCaps; - GLbitfield _ImageTransferState;/**< bitwise-or of IMAGE_*_BIT flags */ - GLfloat _EyeZDir[3]; - GLfloat _ModelViewInvScale; - GLboolean _NeedEyeCoords; - GLboolean _ForceEyeCoords; - - GLuint TextureStateTimestamp; /**< detect changes to shared state */ - - struct gl_shine_tab *_ShineTable[2]; /**< Active shine tables */ - struct gl_shine_tab *_ShineTabList; /**< MRU list of inactive shine tables */ - /**@}*/ - - struct gl_list_extensions *ListExt; /**< driver dlist extensions */ - - /** \name For debugging/development only */ - /*@{*/ - GLboolean FirstTimeCurrent; - /*@}*/ - - /** software compression/decompression supported or not */ - GLboolean Mesa_DXTn; - - GLboolean TextureFormatSupported[MESA_FORMAT_COUNT]; - - /** - * Use dp4 (rather than mul/mad) instructions for position - * transformation? - */ - GLboolean mvp_with_dp4; - - /** - * \name Hooks for module contexts. - * - * These will eventually live in the driver or elsewhere. - */ - /*@{*/ - void *swrast_context; - void *swsetup_context; - void *swtnl_context; - void *swtnl_im; - struct st_context *st; - void *aelt_context; - /*@}*/ -}; - - -#ifdef DEBUG -extern int MESA_VERBOSE; -extern int MESA_DEBUG_FLAGS; -# define MESA_FUNCTION __FUNCTION__ -#else -# define MESA_VERBOSE 0 -# define MESA_DEBUG_FLAGS 0 -# define MESA_FUNCTION "a function" -# ifndef NDEBUG -# define NDEBUG -# endif -#endif - - -/** The MESA_VERBOSE var is a bitmask of these flags */ -enum _verbose -{ - VERBOSE_VARRAY = 0x0001, - VERBOSE_TEXTURE = 0x0002, - VERBOSE_MATERIAL = 0x0004, - VERBOSE_PIPELINE = 0x0008, - VERBOSE_DRIVER = 0x0010, - VERBOSE_STATE = 0x0020, - VERBOSE_API = 0x0040, - VERBOSE_DISPLAY_LIST = 0x0100, - VERBOSE_LIGHTING = 0x0200, - VERBOSE_PRIMS = 0x0400, - VERBOSE_VERTS = 0x0800, - VERBOSE_DISASSEM = 0x1000, - VERBOSE_DRAW = 0x2000, - VERBOSE_SWAPBUFFERS = 0x4000 -}; - - -/** The MESA_DEBUG_FLAGS var is a bitmask of these flags */ -enum _debug -{ - DEBUG_ALWAYS_FLUSH = 0x1 -}; - - - -#endif /* MTYPES_H */ +/* + * Mesa 3-D graphics library + * Version: 7.7 + * + * 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 mtypes.h + * Main Mesa data structures. + * + * Please try to mark derived values with a leading underscore ('_'). + */ + +#ifndef MTYPES_H +#define MTYPES_H + + +#include "main/glheader.h" +#include "main/config.h" +#include "main/mfeatures.h" +#include "glapi/glapi.h" +#include "math/m_matrix.h" /* GLmatrix */ +#include "main/simple_list.h" /* struct simple_node */ +#include "main/formats.h" /* MESA_FORMAT_COUNT */ + + +/** + * Color channel data type. + */ +#if CHAN_BITS == 8 + typedef GLubyte GLchan; +#define CHAN_MAX 255 +#define CHAN_MAXF 255.0F +#define CHAN_TYPE GL_UNSIGNED_BYTE +#elif CHAN_BITS == 16 + typedef GLushort GLchan; +#define CHAN_MAX 65535 +#define CHAN_MAXF 65535.0F +#define CHAN_TYPE GL_UNSIGNED_SHORT +#elif CHAN_BITS == 32 + typedef GLfloat GLchan; +#define CHAN_MAX 1.0 +#define CHAN_MAXF 1.0F +#define CHAN_TYPE GL_FLOAT +#else +#error "illegal number of color channel bits" +#endif + + +/** + * Stencil buffer data type. + */ +#if STENCIL_BITS==8 + typedef GLubyte GLstencil; +#elif STENCIL_BITS==16 + typedef GLushort GLstencil; +#else +# error "illegal number of stencil bits" +#endif + + +/** + * \name 64-bit extension of GLbitfield. + */ +/*@{*/ +typedef GLuint64 GLbitfield64; + +/** Set a single bit */ +#define BITFIELD64_BIT(b) (1ULL << (b)) + + +/** + * \name Some forward type declarations + */ +/*@{*/ +struct _mesa_HashTable; +struct gl_attrib_node; +struct gl_list_extensions; +struct gl_meta_state; +struct gl_pixelstore_attrib; +struct gl_program_cache; +struct gl_texture_format; +struct gl_texture_image; +struct gl_texture_object; +struct gl_context; +struct st_context; +/*@}*/ + + +/** Extra draw modes beyond GL_POINTS, GL_TRIANGLE_FAN, etc */ +#define PRIM_OUTSIDE_BEGIN_END (GL_POLYGON+1) +#define PRIM_INSIDE_UNKNOWN_PRIM (GL_POLYGON+2) +#define PRIM_UNKNOWN (GL_POLYGON+3) + + +/** + * Shader stages. Note that these will become 5 with tessellation. + * These MUST have the same values as gallium's PIPE_SHADER_* + */ +typedef enum +{ + MESA_SHADER_VERTEX = 0, + MESA_SHADER_FRAGMENT = 1, + MESA_SHADER_GEOMETRY = 2, + MESA_SHADER_TYPES = 3 +} gl_shader_type; + + + +/** + * Indexes for vertex program attributes. + * GL_NV_vertex_program aliases generic attributes over the conventional + * attributes. In GL_ARB_vertex_program shader the aliasing is optional. + * In GL_ARB_vertex_shader / OpenGL 2.0 the aliasing is disallowed (the + * generic attributes are distinct/separate). + */ +typedef enum +{ + VERT_ATTRIB_POS = 0, + VERT_ATTRIB_WEIGHT = 1, + VERT_ATTRIB_NORMAL = 2, + VERT_ATTRIB_COLOR0 = 3, + VERT_ATTRIB_COLOR1 = 4, + VERT_ATTRIB_FOG = 5, + VERT_ATTRIB_COLOR_INDEX = 6, + VERT_ATTRIB_POINT_SIZE = 6, /*alias*/ + VERT_ATTRIB_EDGEFLAG = 7, + VERT_ATTRIB_TEX0 = 8, + VERT_ATTRIB_TEX1 = 9, + VERT_ATTRIB_TEX2 = 10, + VERT_ATTRIB_TEX3 = 11, + VERT_ATTRIB_TEX4 = 12, + VERT_ATTRIB_TEX5 = 13, + VERT_ATTRIB_TEX6 = 14, + VERT_ATTRIB_TEX7 = 15, + VERT_ATTRIB_GENERIC0 = 16, + VERT_ATTRIB_GENERIC1 = 17, + VERT_ATTRIB_GENERIC2 = 18, + VERT_ATTRIB_GENERIC3 = 19, + VERT_ATTRIB_GENERIC4 = 20, + VERT_ATTRIB_GENERIC5 = 21, + VERT_ATTRIB_GENERIC6 = 22, + VERT_ATTRIB_GENERIC7 = 23, + VERT_ATTRIB_GENERIC8 = 24, + VERT_ATTRIB_GENERIC9 = 25, + VERT_ATTRIB_GENERIC10 = 26, + VERT_ATTRIB_GENERIC11 = 27, + VERT_ATTRIB_GENERIC12 = 28, + VERT_ATTRIB_GENERIC13 = 29, + VERT_ATTRIB_GENERIC14 = 30, + VERT_ATTRIB_GENERIC15 = 31, + VERT_ATTRIB_MAX = 32 +} gl_vert_attrib; + +/** + * Bitflags for vertex attributes. + * These are used in bitfields in many places. + */ +/*@{*/ +#define VERT_BIT_POS (1 << VERT_ATTRIB_POS) +#define VERT_BIT_WEIGHT (1 << VERT_ATTRIB_WEIGHT) +#define VERT_BIT_NORMAL (1 << VERT_ATTRIB_NORMAL) +#define VERT_BIT_COLOR0 (1 << VERT_ATTRIB_COLOR0) +#define VERT_BIT_COLOR1 (1 << VERT_ATTRIB_COLOR1) +#define VERT_BIT_FOG (1 << VERT_ATTRIB_FOG) +#define VERT_BIT_COLOR_INDEX (1 << VERT_ATTRIB_COLOR_INDEX) +#define VERT_BIT_EDGEFLAG (1 << VERT_ATTRIB_EDGEFLAG) +#define VERT_BIT_TEX0 (1 << VERT_ATTRIB_TEX0) +#define VERT_BIT_TEX1 (1 << VERT_ATTRIB_TEX1) +#define VERT_BIT_TEX2 (1 << VERT_ATTRIB_TEX2) +#define VERT_BIT_TEX3 (1 << VERT_ATTRIB_TEX3) +#define VERT_BIT_TEX4 (1 << VERT_ATTRIB_TEX4) +#define VERT_BIT_TEX5 (1 << VERT_ATTRIB_TEX5) +#define VERT_BIT_TEX6 (1 << VERT_ATTRIB_TEX6) +#define VERT_BIT_TEX7 (1 << VERT_ATTRIB_TEX7) +#define VERT_BIT_GENERIC0 (1 << VERT_ATTRIB_GENERIC0) +#define VERT_BIT_GENERIC1 (1 << VERT_ATTRIB_GENERIC1) +#define VERT_BIT_GENERIC2 (1 << VERT_ATTRIB_GENERIC2) +#define VERT_BIT_GENERIC3 (1 << VERT_ATTRIB_GENERIC3) +#define VERT_BIT_GENERIC4 (1 << VERT_ATTRIB_GENERIC4) +#define VERT_BIT_GENERIC5 (1 << VERT_ATTRIB_GENERIC5) +#define VERT_BIT_GENERIC6 (1 << VERT_ATTRIB_GENERIC6) +#define VERT_BIT_GENERIC7 (1 << VERT_ATTRIB_GENERIC7) +#define VERT_BIT_GENERIC8 (1 << VERT_ATTRIB_GENERIC8) +#define VERT_BIT_GENERIC9 (1 << VERT_ATTRIB_GENERIC9) +#define VERT_BIT_GENERIC10 (1 << VERT_ATTRIB_GENERIC10) +#define VERT_BIT_GENERIC11 (1 << VERT_ATTRIB_GENERIC11) +#define VERT_BIT_GENERIC12 (1 << VERT_ATTRIB_GENERIC12) +#define VERT_BIT_GENERIC13 (1 << VERT_ATTRIB_GENERIC13) +#define VERT_BIT_GENERIC14 (1 << VERT_ATTRIB_GENERIC14) +#define VERT_BIT_GENERIC15 (1 << VERT_ATTRIB_GENERIC15) + +#define VERT_BIT_TEX(u) (1 << (VERT_ATTRIB_TEX0 + (u))) +#define VERT_BIT_GENERIC(g) (1 << (VERT_ATTRIB_GENERIC0 + (g))) +/*@}*/ + + +/** + * Indexes for vertex program result attributes + */ +typedef enum +{ + VERT_RESULT_HPOS = 0, + VERT_RESULT_COL0 = 1, + VERT_RESULT_COL1 = 2, + VERT_RESULT_FOGC = 3, + VERT_RESULT_TEX0 = 4, + VERT_RESULT_TEX1 = 5, + VERT_RESULT_TEX2 = 6, + VERT_RESULT_TEX3 = 7, + VERT_RESULT_TEX4 = 8, + VERT_RESULT_TEX5 = 9, + VERT_RESULT_TEX6 = 10, + VERT_RESULT_TEX7 = 11, + VERT_RESULT_PSIZ = 12, + VERT_RESULT_BFC0 = 13, + VERT_RESULT_BFC1 = 14, + VERT_RESULT_EDGE = 15, + VERT_RESULT_VAR0 = 16, /**< shader varying */ + VERT_RESULT_MAX = (VERT_RESULT_VAR0 + MAX_VARYING) +} gl_vert_result; + + +/*********************************************/ + +/** + * Indexes for geometry program attributes. + */ +typedef enum +{ + GEOM_ATTRIB_POSITION = 0, + GEOM_ATTRIB_COLOR0 = 1, + GEOM_ATTRIB_COLOR1 = 2, + GEOM_ATTRIB_SECONDARY_COLOR0 = 3, + GEOM_ATTRIB_SECONDARY_COLOR1 = 4, + GEOM_ATTRIB_FOG_FRAG_COORD = 5, + GEOM_ATTRIB_POINT_SIZE = 6, + GEOM_ATTRIB_CLIP_VERTEX = 7, + GEOM_ATTRIB_PRIMITIVE_ID = 8, + GEOM_ATTRIB_TEX_COORD = 9, + + GEOM_ATTRIB_VAR0 = 16, + GEOM_ATTRIB_MAX = (GEOM_ATTRIB_VAR0 + MAX_VARYING) +} gl_geom_attrib; + +/** + * Bitflags for geometry attributes. + * These are used in bitfields in many places. + */ +/*@{*/ +#define GEOM_BIT_COLOR0 (1 << GEOM_ATTRIB_COLOR0) +#define GEOM_BIT_COLOR1 (1 << GEOM_ATTRIB_COLOR1) +#define GEOM_BIT_SCOLOR0 (1 << GEOM_ATTRIB_SECONDARY_COLOR0) +#define GEOM_BIT_SCOLOR1 (1 << GEOM_ATTRIB_SECONDARY_COLOR1) +#define GEOM_BIT_TEX_COORD (1 << GEOM_ATTRIB_TEX_COORD) +#define GEOM_BIT_FOG_COORD (1 << GEOM_ATTRIB_FOG_FRAG_COORD) +#define GEOM_BIT_POSITION (1 << GEOM_ATTRIB_POSITION) +#define GEOM_BIT_POINT_SIDE (1 << GEOM_ATTRIB_POINT_SIZE) +#define GEOM_BIT_CLIP_VERTEX (1 << GEOM_ATTRIB_CLIP_VERTEX) +#define GEOM_BIT_PRIM_ID (1 << GEOM_ATTRIB_PRIMITIVE_ID) +#define GEOM_BIT_VAR0 (1 << GEOM_ATTRIB_VAR0) + +#define GEOM_BIT_VAR(g) (1 << (GEOM_BIT_VAR0 + (g))) +/*@}*/ + + +/** + * Indexes for geometry program result attributes + */ +typedef enum +{ + GEOM_RESULT_POS = 0, + GEOM_RESULT_COL0 = 1, + GEOM_RESULT_COL1 = 2, + GEOM_RESULT_SCOL0 = 3, + GEOM_RESULT_SCOL1 = 4, + GEOM_RESULT_FOGC = 5, + GEOM_RESULT_TEX0 = 6, + GEOM_RESULT_TEX1 = 7, + GEOM_RESULT_TEX2 = 8, + GEOM_RESULT_TEX3 = 9, + GEOM_RESULT_TEX4 = 10, + GEOM_RESULT_TEX5 = 11, + GEOM_RESULT_TEX6 = 12, + GEOM_RESULT_TEX7 = 13, + GEOM_RESULT_PSIZ = 14, + GEOM_RESULT_CLPV = 15, + GEOM_RESULT_PRID = 16, + GEOM_RESULT_LAYR = 17, + GEOM_RESULT_VAR0 = 18, /**< shader varying, should really be 16 */ + /* ### we need to -2 because var0 is 18 instead 16 like in the others */ + GEOM_RESULT_MAX = (GEOM_RESULT_VAR0 + MAX_VARYING - 2) +} gl_geom_result; + + +/** + * Indexes for fragment program input attributes. + */ +typedef enum +{ + FRAG_ATTRIB_WPOS = 0, + FRAG_ATTRIB_COL0 = 1, + FRAG_ATTRIB_COL1 = 2, + FRAG_ATTRIB_FOGC = 3, + FRAG_ATTRIB_TEX0 = 4, + FRAG_ATTRIB_TEX1 = 5, + FRAG_ATTRIB_TEX2 = 6, + FRAG_ATTRIB_TEX3 = 7, + FRAG_ATTRIB_TEX4 = 8, + FRAG_ATTRIB_TEX5 = 9, + FRAG_ATTRIB_TEX6 = 10, + FRAG_ATTRIB_TEX7 = 11, + FRAG_ATTRIB_FACE = 12, /**< front/back face */ + FRAG_ATTRIB_PNTC = 13, /**< sprite/point coord */ + FRAG_ATTRIB_VAR0 = 14, /**< shader varying */ + FRAG_ATTRIB_MAX = (FRAG_ATTRIB_VAR0 + MAX_VARYING) +} gl_frag_attrib; + +/** + * Bitflags for fragment program input attributes. + */ +/*@{*/ +#define FRAG_BIT_WPOS (1 << FRAG_ATTRIB_WPOS) +#define FRAG_BIT_COL0 (1 << FRAG_ATTRIB_COL0) +#define FRAG_BIT_COL1 (1 << FRAG_ATTRIB_COL1) +#define FRAG_BIT_FOGC (1 << FRAG_ATTRIB_FOGC) +#define FRAG_BIT_FACE (1 << FRAG_ATTRIB_FACE) +#define FRAG_BIT_PNTC (1 << FRAG_ATTRIB_PNTC) +#define FRAG_BIT_TEX0 (1 << FRAG_ATTRIB_TEX0) +#define FRAG_BIT_TEX1 (1 << FRAG_ATTRIB_TEX1) +#define FRAG_BIT_TEX2 (1 << FRAG_ATTRIB_TEX2) +#define FRAG_BIT_TEX3 (1 << FRAG_ATTRIB_TEX3) +#define FRAG_BIT_TEX4 (1 << FRAG_ATTRIB_TEX4) +#define FRAG_BIT_TEX5 (1 << FRAG_ATTRIB_TEX5) +#define FRAG_BIT_TEX6 (1 << FRAG_ATTRIB_TEX6) +#define FRAG_BIT_TEX7 (1 << FRAG_ATTRIB_TEX7) +#define FRAG_BIT_VAR0 (1 << FRAG_ATTRIB_VAR0) + +#define FRAG_BIT_TEX(U) (FRAG_BIT_TEX0 << (U)) +#define FRAG_BIT_VAR(V) (FRAG_BIT_VAR0 << (V)) + +#define FRAG_BITS_TEX_ANY (FRAG_BIT_TEX0| \ + FRAG_BIT_TEX1| \ + FRAG_BIT_TEX2| \ + FRAG_BIT_TEX3| \ + FRAG_BIT_TEX4| \ + FRAG_BIT_TEX5| \ + FRAG_BIT_TEX6| \ + FRAG_BIT_TEX7) +/*@}*/ + + +/** + * Fragment program results + */ +typedef enum +{ + FRAG_RESULT_DEPTH = 0, + FRAG_RESULT_STENCIL = 1, + FRAG_RESULT_COLOR = 2, + FRAG_RESULT_DATA0 = 3, + FRAG_RESULT_MAX = (FRAG_RESULT_DATA0 + MAX_DRAW_BUFFERS) +} gl_frag_result; + + +/** + * Indexes for all renderbuffers + */ +typedef enum +{ + /* the four standard color buffers */ + BUFFER_FRONT_LEFT, + BUFFER_BACK_LEFT, + BUFFER_FRONT_RIGHT, + BUFFER_BACK_RIGHT, + BUFFER_DEPTH, + BUFFER_STENCIL, + BUFFER_ACCUM, + /* optional aux buffer */ + BUFFER_AUX0, + /* generic renderbuffers */ + BUFFER_COLOR0, + BUFFER_COLOR1, + BUFFER_COLOR2, + BUFFER_COLOR3, + BUFFER_COLOR4, + BUFFER_COLOR5, + BUFFER_COLOR6, + BUFFER_COLOR7, + BUFFER_COUNT +} gl_buffer_index; + +/** + * Bit flags for all renderbuffers + */ +#define BUFFER_BIT_FRONT_LEFT (1 << BUFFER_FRONT_LEFT) +#define BUFFER_BIT_BACK_LEFT (1 << BUFFER_BACK_LEFT) +#define BUFFER_BIT_FRONT_RIGHT (1 << BUFFER_FRONT_RIGHT) +#define BUFFER_BIT_BACK_RIGHT (1 << BUFFER_BACK_RIGHT) +#define BUFFER_BIT_AUX0 (1 << BUFFER_AUX0) +#define BUFFER_BIT_AUX1 (1 << BUFFER_AUX1) +#define BUFFER_BIT_AUX2 (1 << BUFFER_AUX2) +#define BUFFER_BIT_AUX3 (1 << BUFFER_AUX3) +#define BUFFER_BIT_DEPTH (1 << BUFFER_DEPTH) +#define BUFFER_BIT_STENCIL (1 << BUFFER_STENCIL) +#define BUFFER_BIT_ACCUM (1 << BUFFER_ACCUM) +#define BUFFER_BIT_COLOR0 (1 << BUFFER_COLOR0) +#define BUFFER_BIT_COLOR1 (1 << BUFFER_COLOR1) +#define BUFFER_BIT_COLOR2 (1 << BUFFER_COLOR2) +#define BUFFER_BIT_COLOR3 (1 << BUFFER_COLOR3) +#define BUFFER_BIT_COLOR4 (1 << BUFFER_COLOR4) +#define BUFFER_BIT_COLOR5 (1 << BUFFER_COLOR5) +#define BUFFER_BIT_COLOR6 (1 << BUFFER_COLOR6) +#define BUFFER_BIT_COLOR7 (1 << BUFFER_COLOR7) + +/** + * Mask of all the color buffer bits (but not accum). + */ +#define BUFFER_BITS_COLOR (BUFFER_BIT_FRONT_LEFT | \ + BUFFER_BIT_BACK_LEFT | \ + BUFFER_BIT_FRONT_RIGHT | \ + BUFFER_BIT_BACK_RIGHT | \ + BUFFER_BIT_AUX0 | \ + BUFFER_BIT_COLOR0 | \ + BUFFER_BIT_COLOR1 | \ + BUFFER_BIT_COLOR2 | \ + BUFFER_BIT_COLOR3 | \ + BUFFER_BIT_COLOR4 | \ + BUFFER_BIT_COLOR5 | \ + BUFFER_BIT_COLOR6 | \ + BUFFER_BIT_COLOR7) + + +/** + * Framebuffer configuration (aka visual / pixelformat) + * Note: some of these fields should be boolean, but it appears that + * code in drivers/dri/common/util.c requires int-sized fields. + */ +struct gl_config +{ + GLboolean rgbMode; + GLboolean floatMode; + GLboolean colorIndexMode; /* XXX is this used anywhere? */ + GLuint doubleBufferMode; + GLuint stereoMode; + + GLboolean haveAccumBuffer; + GLboolean haveDepthBuffer; + GLboolean haveStencilBuffer; + + GLint redBits, greenBits, blueBits, alphaBits; /* bits per comp */ + GLuint redMask, greenMask, blueMask, alphaMask; + GLint rgbBits; /* total bits for rgb */ + GLint indexBits; /* total bits for colorindex */ + + GLint accumRedBits, accumGreenBits, accumBlueBits, accumAlphaBits; + GLint depthBits; + GLint stencilBits; + + GLint numAuxBuffers; + + GLint level; + + /* EXT_visual_rating / GLX 1.2 */ + GLint visualRating; + + /* EXT_visual_info / GLX 1.2 */ + GLint transparentPixel; + /* colors are floats scaled to ints */ + GLint transparentRed, transparentGreen, transparentBlue, transparentAlpha; + GLint transparentIndex; + + /* ARB_multisample / SGIS_multisample */ + GLint sampleBuffers; + GLint samples; + + /* SGIX_pbuffer / GLX 1.3 */ + GLint maxPbufferWidth; + GLint maxPbufferHeight; + GLint maxPbufferPixels; + GLint optimalPbufferWidth; /* Only for SGIX_pbuffer. */ + GLint optimalPbufferHeight; /* Only for SGIX_pbuffer. */ + + /* OML_swap_method */ + GLint swapMethod; + + /* EXT_texture_from_pixmap */ + GLint bindToTextureRgb; + GLint bindToTextureRgba; + GLint bindToMipmapTexture; + GLint bindToTextureTargets; + GLint yInverted; + + /* EXT_framebuffer_sRGB */ + GLint sRGBCapable; +}; + + +/** + * Data structure for color tables + */ +struct gl_color_table +{ + GLenum InternalFormat; /**< The user-specified format */ + GLenum _BaseFormat; /**< GL_ALPHA, GL_RGBA, GL_RGB, etc */ + GLuint Size; /**< number of entries in table */ + GLfloat *TableF; /**< Color table, floating point values */ + GLubyte *TableUB; /**< Color table, ubyte values */ + GLubyte RedSize; + GLubyte GreenSize; + GLubyte BlueSize; + GLubyte AlphaSize; + GLubyte LuminanceSize; + GLubyte IntensitySize; +}; + + +/** + * \name Bit flags used for updating material values. + */ +/*@{*/ +#define MAT_ATTRIB_FRONT_AMBIENT 0 +#define MAT_ATTRIB_BACK_AMBIENT 1 +#define MAT_ATTRIB_FRONT_DIFFUSE 2 +#define MAT_ATTRIB_BACK_DIFFUSE 3 +#define MAT_ATTRIB_FRONT_SPECULAR 4 +#define MAT_ATTRIB_BACK_SPECULAR 5 +#define MAT_ATTRIB_FRONT_EMISSION 6 +#define MAT_ATTRIB_BACK_EMISSION 7 +#define MAT_ATTRIB_FRONT_SHININESS 8 +#define MAT_ATTRIB_BACK_SHININESS 9 +#define MAT_ATTRIB_FRONT_INDEXES 10 +#define MAT_ATTRIB_BACK_INDEXES 11 +#define MAT_ATTRIB_MAX 12 + +#define MAT_ATTRIB_AMBIENT(f) (MAT_ATTRIB_FRONT_AMBIENT+(f)) +#define MAT_ATTRIB_DIFFUSE(f) (MAT_ATTRIB_FRONT_DIFFUSE+(f)) +#define MAT_ATTRIB_SPECULAR(f) (MAT_ATTRIB_FRONT_SPECULAR+(f)) +#define MAT_ATTRIB_EMISSION(f) (MAT_ATTRIB_FRONT_EMISSION+(f)) +#define MAT_ATTRIB_SHININESS(f)(MAT_ATTRIB_FRONT_SHININESS+(f)) +#define MAT_ATTRIB_INDEXES(f) (MAT_ATTRIB_FRONT_INDEXES+(f)) + +#define MAT_INDEX_AMBIENT 0 +#define MAT_INDEX_DIFFUSE 1 +#define MAT_INDEX_SPECULAR 2 + +#define MAT_BIT_FRONT_AMBIENT (1< ) */ + GLfloat _NormSpotDirection[4]; /**< normalized spotlight direction */ + GLfloat _VP_inf_spot_attenuation; + + GLfloat _SpotExpTable[EXP_TABLE_SIZE][2]; /**< to replace a pow() call */ + GLfloat _MatAmbient[2][3]; /**< material ambient * light ambient */ + GLfloat _MatDiffuse[2][3]; /**< material diffuse * light diffuse */ + GLfloat _MatSpecular[2][3]; /**< material spec * light specular */ + GLfloat _dli; /**< CI diffuse light intensity */ + GLfloat _sli; /**< CI specular light intensity */ + /*@}*/ +}; + + +/** + * Light model state. + */ +struct gl_lightmodel +{ + GLfloat Ambient[4]; /**< ambient color */ + GLboolean LocalViewer; /**< Local (or infinite) view point? */ + GLboolean TwoSide; /**< Two (or one) sided lighting? */ + GLenum ColorControl; /**< either GL_SINGLE_COLOR + * or GL_SEPARATE_SPECULAR_COLOR */ +}; + + +/** + * Material state. + */ +struct gl_material +{ + GLfloat Attrib[MAT_ATTRIB_MAX][4]; +}; + + +/** + * Accumulation buffer attribute group (GL_ACCUM_BUFFER_BIT) + */ +struct gl_accum_attrib +{ + GLfloat ClearColor[4]; /**< Accumulation buffer clear color */ +}; + + +/** + * Color buffer attribute group (GL_COLOR_BUFFER_BIT). + */ +struct gl_colorbuffer_attrib +{ + GLuint ClearIndex; /**< Index to use for glClear */ + GLclampf ClearColor[4]; /**< Color to use for glClear */ + + GLuint IndexMask; /**< Color index write mask */ + GLubyte ColorMask[MAX_DRAW_BUFFERS][4];/**< Each flag is 0xff or 0x0 */ + + GLenum DrawBuffer[MAX_DRAW_BUFFERS]; /**< Which buffer to draw into */ + + /** + * \name alpha testing + */ + /*@{*/ + GLboolean AlphaEnabled; /**< Alpha test enabled flag */ + GLenum AlphaFunc; /**< Alpha test function */ + GLclampf AlphaRef; /**< Alpha reference value */ + /*@}*/ + + /** + * \name Blending + */ + /*@{*/ + GLbitfield BlendEnabled; /**< Per-buffer blend enable flags */ + GLfloat BlendColor[4]; /**< Blending color */ + struct + { + GLenum SrcRGB; /**< RGB blend source term */ + GLenum DstRGB; /**< RGB blend dest term */ + GLenum SrcA; /**< Alpha blend source term */ + GLenum DstA; /**< Alpha blend dest term */ + GLenum EquationRGB; /**< GL_ADD, GL_SUBTRACT, etc. */ + GLenum EquationA; /**< GL_ADD, GL_SUBTRACT, etc. */ + } Blend[MAX_DRAW_BUFFERS]; + /** Are the blend func terms currently different for each buffer/target? */ + GLboolean _BlendFuncPerBuffer; + /** Are the blend equations currently different for each buffer/target? */ + GLboolean _BlendEquationPerBuffer; + /*@}*/ + + /** + * \name Logic op + */ + /*@{*/ + GLenum LogicOp; /**< Logic operator */ + GLboolean IndexLogicOpEnabled; /**< Color index logic op enabled flag */ + GLboolean ColorLogicOpEnabled; /**< RGBA logic op enabled flag */ + GLboolean _LogicOpEnabled; /**< RGBA logic op + EXT_blend_logic_op enabled flag */ + /*@}*/ + + GLboolean DitherFlag; /**< Dither enable flag */ + + GLenum ClampFragmentColor; /**< GL_TRUE, GL_FALSE or GL_FIXED_ONLY_ARB */ + GLenum ClampReadColor; /**< GL_TRUE, GL_FALSE or GL_FIXED_ONLY_ARB */ + + GLboolean sRGBEnabled; /**< Framebuffer sRGB blending/updating requested */ +}; + + +/** + * Current attribute group (GL_CURRENT_BIT). + */ +struct gl_current_attrib +{ + /** + * \name Current vertex attributes. + * \note Values are valid only after FLUSH_VERTICES has been called. + * \note Index and Edgeflag current values are stored as floats in the + * SIX and SEVEN attribute slots. + */ + GLfloat Attrib[VERT_ATTRIB_MAX][4]; /**< Position, color, texcoords, etc */ + + /** + * \name Current raster position attributes (always valid). + * \note This set of attributes is very similar to the SWvertex struct. + */ + /*@{*/ + GLfloat RasterPos[4]; + GLfloat RasterDistance; + GLfloat RasterColor[4]; + GLfloat RasterSecondaryColor[4]; + GLfloat RasterTexCoords[MAX_TEXTURE_COORD_UNITS][4]; + GLboolean RasterPosValid; + /*@}*/ +}; + + +/** + * Depth buffer attribute group (GL_DEPTH_BUFFER_BIT). + */ +struct gl_depthbuffer_attrib +{ + GLenum Func; /**< Function for depth buffer compare */ + GLclampd Clear; /**< Value to clear depth buffer to */ + GLboolean Test; /**< Depth buffering enabled flag */ + GLboolean Mask; /**< Depth buffer writable? */ + GLboolean BoundsTest; /**< GL_EXT_depth_bounds_test */ + GLfloat BoundsMin, BoundsMax;/**< GL_EXT_depth_bounds_test */ +}; + + +/** + * Evaluator attribute group (GL_EVAL_BIT). + */ +struct gl_eval_attrib +{ + /** + * \name Enable bits + */ + /*@{*/ + GLboolean Map1Color4; + GLboolean Map1Index; + GLboolean Map1Normal; + GLboolean Map1TextureCoord1; + GLboolean Map1TextureCoord2; + GLboolean Map1TextureCoord3; + GLboolean Map1TextureCoord4; + GLboolean Map1Vertex3; + GLboolean Map1Vertex4; + GLboolean Map1Attrib[16]; /* GL_NV_vertex_program */ + GLboolean Map2Color4; + GLboolean Map2Index; + GLboolean Map2Normal; + GLboolean Map2TextureCoord1; + GLboolean Map2TextureCoord2; + GLboolean Map2TextureCoord3; + GLboolean Map2TextureCoord4; + GLboolean Map2Vertex3; + GLboolean Map2Vertex4; + GLboolean Map2Attrib[16]; /* GL_NV_vertex_program */ + GLboolean AutoNormal; + /*@}*/ + + /** + * \name Map Grid endpoints and divisions and calculated du values + */ + /*@{*/ + GLint MapGrid1un; + GLfloat MapGrid1u1, MapGrid1u2, MapGrid1du; + GLint MapGrid2un, MapGrid2vn; + GLfloat MapGrid2u1, MapGrid2u2, MapGrid2du; + GLfloat MapGrid2v1, MapGrid2v2, MapGrid2dv; + /*@}*/ +}; + + +/** + * Fog attribute group (GL_FOG_BIT). + */ +struct gl_fog_attrib +{ + GLboolean Enabled; /**< Fog enabled flag */ + GLfloat Color[4]; /**< Fog color */ + GLfloat Density; /**< Density >= 0.0 */ + GLfloat Start; /**< Start distance in eye coords */ + GLfloat End; /**< End distance in eye coords */ + GLfloat Index; /**< Fog index */ + GLenum Mode; /**< Fog mode */ + GLboolean ColorSumEnabled; + GLenum FogCoordinateSource; /**< GL_EXT_fog_coord */ + GLfloat _Scale; /**< (End == Start) ? 1.0 : 1.0 / (End - Start) */ +}; + + +/** + * \brief Layout qualifiers for gl_FragDepth. + * + * Extension AMD_conservative_depth allows gl_FragDepth to be redeclared with + * a layout qualifier. + * + * \see enum ir_depth_layout + */ +enum gl_frag_depth_layout { + FRAG_DEPTH_LAYOUT_NONE, /**< No layout is specified. */ + FRAG_DEPTH_LAYOUT_ANY, + FRAG_DEPTH_LAYOUT_GREATER, + FRAG_DEPTH_LAYOUT_LESS, + FRAG_DEPTH_LAYOUT_UNCHANGED +}; + + +/** + * Hint attribute group (GL_HINT_BIT). + * + * Values are always one of GL_FASTEST, GL_NICEST, or GL_DONT_CARE. + */ +struct gl_hint_attrib +{ + GLenum PerspectiveCorrection; + GLenum PointSmooth; + GLenum LineSmooth; + GLenum PolygonSmooth; + GLenum Fog; + GLenum ClipVolumeClipping; /**< GL_EXT_clip_volume_hint */ + GLenum TextureCompression; /**< GL_ARB_texture_compression */ + GLenum GenerateMipmap; /**< GL_SGIS_generate_mipmap */ + GLenum FragmentShaderDerivative; /**< GL_ARB_fragment_shader */ +}; + +/** + * Light state flags. + */ +/*@{*/ +#define LIGHT_SPOT 0x1 +#define LIGHT_LOCAL_VIEWER 0x2 +#define LIGHT_POSITIONAL 0x4 +#define LIGHT_NEED_VERTICES (LIGHT_POSITIONAL|LIGHT_LOCAL_VIEWER) +/*@}*/ + + +/** + * Lighting attribute group (GL_LIGHT_BIT). + */ +struct gl_light_attrib +{ + struct gl_light Light[MAX_LIGHTS]; /**< Array of light sources */ + struct gl_lightmodel Model; /**< Lighting model */ + + /** + * Must flush FLUSH_VERTICES before referencing: + */ + /*@{*/ + struct gl_material Material; /**< Includes front & back values */ + /*@}*/ + + GLboolean Enabled; /**< Lighting enabled flag */ + GLenum ShadeModel; /**< GL_FLAT or GL_SMOOTH */ + GLenum ProvokingVertex; /**< GL_EXT_provoking_vertex */ + GLenum ColorMaterialFace; /**< GL_FRONT, BACK or FRONT_AND_BACK */ + GLenum ColorMaterialMode; /**< GL_AMBIENT, GL_DIFFUSE, etc */ + GLbitfield ColorMaterialBitmask; /**< bitmask formed from Face and Mode */ + GLboolean ColorMaterialEnabled; + GLenum ClampVertexColor; + + struct gl_light EnabledList; /**< List sentinel */ + + /** + * Derived state for optimizations: + */ + /*@{*/ + GLboolean _NeedEyeCoords; + GLboolean _NeedVertices; /**< Use fast shader? */ + GLbitfield _Flags; /**< LIGHT_* flags, see above */ + GLfloat _BaseColor[2][3]; + /*@}*/ +}; + + +/** + * Line attribute group (GL_LINE_BIT). + */ +struct gl_line_attrib +{ + GLboolean SmoothFlag; /**< GL_LINE_SMOOTH enabled? */ + GLboolean StippleFlag; /**< GL_LINE_STIPPLE enabled? */ + GLushort StipplePattern; /**< Stipple pattern */ + GLint StippleFactor; /**< Stipple repeat factor */ + GLfloat Width; /**< Line width */ +}; + + +/** + * Display list attribute group (GL_LIST_BIT). + */ +struct gl_list_attrib +{ + GLuint ListBase; +}; + + +/** + * Multisample attribute group (GL_MULTISAMPLE_BIT). + */ +struct gl_multisample_attrib +{ + GLboolean Enabled; + GLboolean _Enabled; /**< true if Enabled and multisample buffer */ + GLboolean SampleAlphaToCoverage; + GLboolean SampleAlphaToOne; + GLboolean SampleCoverage; + GLfloat SampleCoverageValue; + GLboolean SampleCoverageInvert; +}; + + +/** + * A pixelmap (see glPixelMap) + */ +struct gl_pixelmap +{ + GLint Size; + GLfloat Map[MAX_PIXEL_MAP_TABLE]; + GLubyte Map8[MAX_PIXEL_MAP_TABLE]; /**< converted to 8-bit color */ +}; + + +/** + * Collection of all pixelmaps + */ +struct gl_pixelmaps +{ + struct gl_pixelmap RtoR; /**< i.e. GL_PIXEL_MAP_R_TO_R */ + struct gl_pixelmap GtoG; + struct gl_pixelmap BtoB; + struct gl_pixelmap AtoA; + struct gl_pixelmap ItoR; + struct gl_pixelmap ItoG; + struct gl_pixelmap ItoB; + struct gl_pixelmap ItoA; + struct gl_pixelmap ItoI; + struct gl_pixelmap StoS; +}; + + +/** + * Pixel attribute group (GL_PIXEL_MODE_BIT). + */ +struct gl_pixel_attrib +{ + GLenum ReadBuffer; /**< source buffer for glRead/CopyPixels() */ + + /*--- Begin Pixel Transfer State ---*/ + /* Fields are in the order in which they're applied... */ + + /** Scale & Bias (index shift, offset) */ + /*@{*/ + GLfloat RedBias, RedScale; + GLfloat GreenBias, GreenScale; + GLfloat BlueBias, BlueScale; + GLfloat AlphaBias, AlphaScale; + GLfloat DepthBias, DepthScale; + GLint IndexShift, IndexOffset; + /*@}*/ + + /* Pixel Maps */ + /* Note: actual pixel maps are not part of this attrib group */ + GLboolean MapColorFlag; + GLboolean MapStencilFlag; + + /*--- End Pixel Transfer State ---*/ + + /** glPixelZoom */ + GLfloat ZoomX, ZoomY; +}; + + +/** + * Point attribute group (GL_POINT_BIT). + */ +struct gl_point_attrib +{ + GLboolean SmoothFlag; /**< True if GL_POINT_SMOOTH is enabled */ + GLfloat Size; /**< User-specified point size */ + GLfloat Params[3]; /**< GL_EXT_point_parameters */ + GLfloat MinSize, MaxSize; /**< GL_EXT_point_parameters */ + GLfloat Threshold; /**< GL_EXT_point_parameters */ + GLboolean _Attenuated; /**< True if Params != [1, 0, 0] */ + GLboolean PointSprite; /**< GL_NV/ARB_point_sprite */ + GLboolean CoordReplace[MAX_TEXTURE_COORD_UNITS]; /**< GL_ARB_point_sprite*/ + GLenum SpriteRMode; /**< GL_NV_point_sprite (only!) */ + GLenum SpriteOrigin; /**< GL_ARB_point_sprite */ +}; + + +/** + * Polygon attribute group (GL_POLYGON_BIT). + */ +struct gl_polygon_attrib +{ + GLenum FrontFace; /**< Either GL_CW or GL_CCW */ + GLenum FrontMode; /**< Either GL_POINT, GL_LINE or GL_FILL */ + GLenum BackMode; /**< Either GL_POINT, GL_LINE or GL_FILL */ + GLboolean _FrontBit; /**< 0=GL_CCW, 1=GL_CW */ + GLboolean CullFlag; /**< Culling on/off flag */ + GLboolean SmoothFlag; /**< True if GL_POLYGON_SMOOTH is enabled */ + GLboolean StippleFlag; /**< True if GL_POLYGON_STIPPLE is enabled */ + GLenum CullFaceMode; /**< Culling mode GL_FRONT or GL_BACK */ + GLfloat OffsetFactor; /**< Polygon offset factor, from user */ + GLfloat OffsetUnits; /**< Polygon offset units, from user */ + GLboolean OffsetPoint; /**< Offset in GL_POINT mode */ + GLboolean OffsetLine; /**< Offset in GL_LINE mode */ + GLboolean OffsetFill; /**< Offset in GL_FILL mode */ +}; + + +/** + * Scissor attributes (GL_SCISSOR_BIT). + */ +struct gl_scissor_attrib +{ + GLboolean Enabled; /**< Scissor test enabled? */ + GLint X, Y; /**< Lower left corner of box */ + GLsizei Width, Height; /**< Size of box */ +}; + + +/** + * Stencil attribute group (GL_STENCIL_BUFFER_BIT). + * + * Three sets of stencil data are tracked so that OpenGL 2.0, + * GL_EXT_stencil_two_side, and GL_ATI_separate_stencil can all be supported + * simultaneously. In each of the stencil state arrays, element 0 corresponds + * to GL_FRONT. Element 1 corresponds to the OpenGL 2.0 / + * GL_ATI_separate_stencil GL_BACK state. Element 2 corresponds to the + * GL_EXT_stencil_two_side GL_BACK state. + * + * The derived value \c _BackFace is either 1 or 2 depending on whether or + * not GL_STENCIL_TEST_TWO_SIDE_EXT is enabled. + * + * The derived value \c _TestTwoSide is set when the front-face and back-face + * stencil state are different. + */ +struct gl_stencil_attrib +{ + GLboolean Enabled; /**< Enabled flag */ + GLboolean TestTwoSide; /**< GL_EXT_stencil_two_side */ + GLubyte ActiveFace; /**< GL_EXT_stencil_two_side (0 or 2) */ + GLboolean _Enabled; /**< Enabled and stencil buffer present */ + GLboolean _TestTwoSide; + GLubyte _BackFace; /**< Current back stencil state (1 or 2) */ + GLenum Function[3]; /**< Stencil function */ + GLenum FailFunc[3]; /**< Fail function */ + GLenum ZPassFunc[3]; /**< Depth buffer pass function */ + GLenum ZFailFunc[3]; /**< Depth buffer fail function */ + GLint Ref[3]; /**< Reference value */ + GLuint ValueMask[3]; /**< Value mask */ + GLuint WriteMask[3]; /**< Write mask */ + GLuint Clear; /**< Clear value */ +}; + + +/** + * An index for each type of texture object. These correspond to the GL + * texture target enums, such as GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP, etc. + * Note: the order is from highest priority to lowest priority. + */ +typedef enum +{ + TEXTURE_2D_ARRAY_INDEX, + TEXTURE_1D_ARRAY_INDEX, + TEXTURE_CUBE_INDEX, + TEXTURE_3D_INDEX, + TEXTURE_RECT_INDEX, + TEXTURE_2D_INDEX, + TEXTURE_1D_INDEX, + NUM_TEXTURE_TARGETS +} gl_texture_index; + + +/** + * Bit flags for each type of texture object + * Used for Texture.Unit[]._ReallyEnabled flags. + */ +/*@{*/ +#define TEXTURE_2D_ARRAY_BIT (1 << TEXTURE_2D_ARRAY_INDEX) +#define TEXTURE_1D_ARRAY_BIT (1 << TEXTURE_1D_ARRAY_INDEX) +#define TEXTURE_CUBE_BIT (1 << TEXTURE_CUBE_INDEX) +#define TEXTURE_3D_BIT (1 << TEXTURE_3D_INDEX) +#define TEXTURE_RECT_BIT (1 << TEXTURE_RECT_INDEX) +#define TEXTURE_2D_BIT (1 << TEXTURE_2D_INDEX) +#define TEXTURE_1D_BIT (1 << TEXTURE_1D_INDEX) +/*@}*/ + + +/** + * TexGenEnabled flags. + */ +/*@{*/ +#define S_BIT 1 +#define T_BIT 2 +#define R_BIT 4 +#define Q_BIT 8 +#define STR_BITS (S_BIT | T_BIT | R_BIT) +/*@}*/ + + +/** + * Bit flag versions of the corresponding GL_ constants. + */ +/*@{*/ +#define TEXGEN_SPHERE_MAP 0x1 +#define TEXGEN_OBJ_LINEAR 0x2 +#define TEXGEN_EYE_LINEAR 0x4 +#define TEXGEN_REFLECTION_MAP_NV 0x8 +#define TEXGEN_NORMAL_MAP_NV 0x10 + +#define TEXGEN_NEED_NORMALS (TEXGEN_SPHERE_MAP | \ + TEXGEN_REFLECTION_MAP_NV | \ + TEXGEN_NORMAL_MAP_NV) +#define TEXGEN_NEED_EYE_COORD (TEXGEN_SPHERE_MAP | \ + TEXGEN_REFLECTION_MAP_NV | \ + TEXGEN_NORMAL_MAP_NV | \ + TEXGEN_EYE_LINEAR) +/*@}*/ + + + +/** Tex-gen enabled for texture unit? */ +#define ENABLE_TEXGEN(unit) (1 << (unit)) + +/** Non-identity texture matrix for texture unit? */ +#define ENABLE_TEXMAT(unit) (1 << (unit)) + + +/** + * Texel fetch function prototype. We use texel fetch functions to + * extract RGBA, color indexes and depth components out of 1D, 2D and 3D + * texture images. These functions help to isolate us from the gritty + * details of all the various texture image encodings. + * + * \param texImage texture image. + * \param col texel column. + * \param row texel row. + * \param img texel image level/layer. + * \param texelOut output texel (up to 4 GLchans) + */ +typedef void (*FetchTexelFuncC)( const struct gl_texture_image *texImage, + GLint col, GLint row, GLint img, + GLchan *texelOut ); + +/** + * As above, but returns floats. + * Used for depth component images and for upcoming signed/float + * texture images. + */ +typedef void (*FetchTexelFuncF)( const struct gl_texture_image *texImage, + GLint col, GLint row, GLint img, + GLfloat *texelOut ); + + +typedef void (*StoreTexelFunc)(struct gl_texture_image *texImage, + GLint col, GLint row, GLint img, + const void *texel); + + +/** + * Texture image state. Describes the dimensions of a texture image, + * the texel format and pointers to Texel Fetch functions. + */ +struct gl_texture_image +{ + GLint InternalFormat; /**< Internal format as given by the user */ + GLenum _BaseFormat; /**< Either GL_RGB, GL_RGBA, GL_ALPHA, + * GL_LUMINANCE, GL_LUMINANCE_ALPHA, + * GL_INTENSITY, GL_COLOR_INDEX, + * GL_DEPTH_COMPONENT or GL_DEPTH_STENCIL_EXT + * only. Used for choosing TexEnv arithmetic. + */ + gl_format TexFormat; /**< The actual texture memory format */ + + GLuint Border; /**< 0 or 1 */ + GLuint Width; /**< = 2^WidthLog2 + 2*Border */ + GLuint Height; /**< = 2^HeightLog2 + 2*Border */ + GLuint Depth; /**< = 2^DepthLog2 + 2*Border */ + GLuint Width2; /**< = Width - 2*Border */ + GLuint Height2; /**< = Height - 2*Border */ + GLuint Depth2; /**< = Depth - 2*Border */ + GLuint WidthLog2; /**< = log2(Width2) */ + GLuint HeightLog2; /**< = log2(Height2) */ + GLuint DepthLog2; /**< = log2(Depth2) */ + GLuint MaxLog2; /**< = MAX(WidthLog2, HeightLog2) */ + GLfloat WidthScale; /**< used for mipmap LOD computation */ + GLfloat HeightScale; /**< used for mipmap LOD computation */ + GLfloat DepthScale; /**< used for mipmap LOD computation */ + GLboolean IsClientData; /**< Data owned by client? */ + GLboolean _IsPowerOfTwo; /**< Are all dimensions powers of two? */ + + struct gl_texture_object *TexObject; /**< Pointer back to parent object */ + + FetchTexelFuncC FetchTexelc; /**< GLchan texel fetch function pointer */ + FetchTexelFuncF FetchTexelf; /**< Float texel fetch function pointer */ + + GLuint RowStride; /**< Padded width in units of texels */ + GLuint *ImageOffsets; /**< if 3D texture: array [Depth] of offsets to + each 2D slice in 'Data', in texels */ + GLvoid *Data; /**< Image data, accessed via FetchTexel() */ + + /** + * \name For device driver: + */ + /*@{*/ + void *DriverData; /**< Arbitrary device driver data */ + /*@}*/ +}; + + +/** + * Indexes for cube map faces. + */ +typedef enum +{ + FACE_POS_X = 0, + FACE_NEG_X = 1, + FACE_POS_Y = 2, + FACE_NEG_Y = 3, + FACE_POS_Z = 4, + FACE_NEG_Z = 5, + MAX_FACES = 6 +} gl_face_index; + + +/** + * Texture object state. Contains the array of mipmap images, border color, + * wrap modes, filter modes, shadow/texcompare state, and the per-texture + * color palette. + */ +struct gl_texture_object +{ + _glthread_Mutex Mutex; /**< for thread safety */ + GLint RefCount; /**< reference count */ + GLuint Name; /**< the user-visible texture object ID */ + GLenum Target; /**< GL_TEXTURE_1D, GL_TEXTURE_2D, etc. */ + GLfloat Priority; /**< in [0,1] */ + union { + GLfloat f[4]; + GLuint ui[4]; + GLint i[4]; + } BorderColor; /**< Interpreted according to texture format */ + GLenum WrapS; /**< S-axis texture image wrap mode */ + GLenum WrapT; /**< T-axis texture image wrap mode */ + GLenum WrapR; /**< R-axis texture image wrap mode */ + GLenum MinFilter; /**< minification filter */ + GLenum MagFilter; /**< magnification filter */ + GLfloat MinLod; /**< min lambda, OpenGL 1.2 */ + GLfloat MaxLod; /**< max lambda, OpenGL 1.2 */ + GLfloat LodBias; /**< OpenGL 1.4 */ + GLint BaseLevel; /**< min mipmap level, OpenGL 1.2 */ + GLint MaxLevel; /**< max mipmap level, OpenGL 1.2 */ + GLfloat MaxAnisotropy; /**< GL_EXT_texture_filter_anisotropic */ + GLenum CompareMode; /**< GL_ARB_shadow */ + GLenum CompareFunc; /**< GL_ARB_shadow */ + GLfloat CompareFailValue; /**< GL_ARB_shadow_ambient */ + GLenum DepthMode; /**< GL_ARB_depth_texture */ + GLint _MaxLevel; /**< actual max mipmap level (q in the spec) */ + GLfloat _MaxLambda; /**< = _MaxLevel - BaseLevel (q - b in spec) */ + GLint CropRect[4]; /**< GL_OES_draw_texture */ + GLenum Swizzle[4]; /**< GL_EXT_texture_swizzle */ + GLuint _Swizzle; /**< same as Swizzle, but SWIZZLE_* format */ + GLboolean GenerateMipmap; /**< GL_SGIS_generate_mipmap */ + GLboolean _Complete; /**< Is texture object complete? */ + GLboolean _RenderToTexture; /**< Any rendering to this texture? */ + GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */ + GLenum sRGBDecode; /**< GL_DECODE_EXT or GL_SKIP_DECODE_EXT */ + + /** Actual texture images, indexed by [cube face] and [mipmap level] */ + struct gl_texture_image *Image[MAX_FACES][MAX_TEXTURE_LEVELS]; + + /** GL_EXT_paletted_texture */ + struct gl_color_table Palette; + + /** + * \name For device driver. + * Note: instead of attaching driver data to this pointer, it's preferable + * to instead use this struct as a base class for your own texture object + * class. Driver->NewTextureObject() can be used to implement the + * allocation. + */ + void *DriverData; /**< Arbitrary device driver data */ +}; + + +/** Up to four combiner sources are possible with GL_NV_texture_env_combine4 */ +#define MAX_COMBINER_TERMS 4 + + +/** + * Texture combine environment state. + */ +struct gl_tex_env_combine_state +{ + GLenum ModeRGB; /**< GL_REPLACE, GL_DECAL, GL_ADD, etc. */ + GLenum ModeA; /**< GL_REPLACE, GL_DECAL, GL_ADD, etc. */ + /** Source terms: GL_PRIMARY_COLOR, GL_TEXTURE, etc */ + GLenum SourceRGB[MAX_COMBINER_TERMS]; + GLenum SourceA[MAX_COMBINER_TERMS]; + /** Source operands: GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, etc */ + GLenum OperandRGB[MAX_COMBINER_TERMS]; + GLenum OperandA[MAX_COMBINER_TERMS]; + GLuint ScaleShiftRGB; /**< 0, 1 or 2 */ + GLuint ScaleShiftA; /**< 0, 1 or 2 */ + GLuint _NumArgsRGB; /**< Number of inputs used for the RGB combiner */ + GLuint _NumArgsA; /**< Number of inputs used for the A combiner */ +}; + + +/** + * Texture coord generation state. + */ +struct gl_texgen +{ + GLenum Mode; /**< GL_EYE_LINEAR, GL_SPHERE_MAP, etc */ + GLbitfield _ModeBit; /**< TEXGEN_x bit corresponding to Mode */ + GLfloat ObjectPlane[4]; + GLfloat EyePlane[4]; +}; + + +/** + * Texture unit state. Contains enable flags, texture environment/function/ + * combiners, texgen state, pointers to current texture objects and + * post-filter color tables. + */ +struct gl_texture_unit +{ + GLbitfield Enabled; /**< bitmask of TEXTURE_*_BIT flags */ + GLbitfield _ReallyEnabled; /**< 0 or exactly one of TEXTURE_*_BIT flags */ + + GLenum EnvMode; /**< GL_MODULATE, GL_DECAL, GL_BLEND, etc. */ + GLfloat EnvColor[4]; + + struct gl_texgen GenS; + struct gl_texgen GenT; + struct gl_texgen GenR; + struct gl_texgen GenQ; + GLbitfield TexGenEnabled; /**< Bitwise-OR of [STRQ]_BIT values */ + GLbitfield _GenFlags; /**< Bitwise-OR of Gen[STRQ]._ModeBit */ + + GLfloat LodBias; /**< for biasing mipmap levels */ + GLenum BumpTarget; + GLfloat RotMatrix[4]; /* 2x2 matrix */ + + /** + * \name GL_EXT_texture_env_combine + */ + struct gl_tex_env_combine_state Combine; + + /** + * Derived state based on \c EnvMode and the \c BaseFormat of the + * currently enabled texture. + */ + struct gl_tex_env_combine_state _EnvMode; + + /** + * Currently enabled combiner state. This will point to either + * \c Combine or \c _EnvMode. + */ + struct gl_tex_env_combine_state *_CurrentCombine; + + /** Current texture object pointers */ + struct gl_texture_object *CurrentTex[NUM_TEXTURE_TARGETS]; + + /** Points to highest priority, complete and enabled texture object */ + struct gl_texture_object *_Current; +}; + + +/** + * Texture attribute group (GL_TEXTURE_BIT). + */ +struct gl_texture_attrib +{ + GLuint CurrentUnit; /**< GL_ACTIVE_TEXTURE */ + struct gl_texture_unit Unit[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; + + struct gl_texture_object *ProxyTex[NUM_TEXTURE_TARGETS]; + + /** GL_ARB_seamless_cubemap */ + GLboolean CubeMapSeamless; + + /** GL_EXT_shared_texture_palette */ + GLboolean SharedPalette; + struct gl_color_table Palette; + + /** Texture units/samplers used by vertex or fragment texturing */ + GLbitfield _EnabledUnits; + + /** Texture coord units/sets used for fragment texturing */ + GLbitfield _EnabledCoordUnits; + + /** Texture coord units that have texgen enabled */ + GLbitfield _TexGenEnabled; + + /** Texture coord units that have non-identity matrices */ + GLbitfield _TexMatEnabled; + + /** Bitwise-OR of all Texture.Unit[i]._GenFlags */ + GLbitfield _GenFlags; +}; + + +/** + * Transformation attribute group (GL_TRANSFORM_BIT). + */ +struct gl_transform_attrib +{ + GLenum MatrixMode; /**< Matrix mode */ + GLfloat EyeUserPlane[MAX_CLIP_PLANES][4]; /**< User clip planes */ + GLfloat _ClipUserPlane[MAX_CLIP_PLANES][4]; /**< derived */ + GLbitfield ClipPlanesEnabled; /**< on/off bitmask */ + GLboolean Normalize; /**< Normalize all normals? */ + GLboolean RescaleNormals; /**< GL_EXT_rescale_normal */ + GLboolean RasterPositionUnclipped; /**< GL_IBM_rasterpos_clip */ + GLboolean DepthClamp; /**< GL_ARB_depth_clamp */ + + GLfloat CullEyePos[4]; + GLfloat CullObjPos[4]; +}; + + +/** + * Viewport attribute group (GL_VIEWPORT_BIT). + */ +struct gl_viewport_attrib +{ + GLint X, Y; /**< position */ + GLsizei Width, Height; /**< size */ + GLfloat Near, Far; /**< Depth buffer range */ + GLmatrix _WindowMap; /**< Mapping transformation as a matrix. */ +}; + + +/** + * GL_ARB_vertex/pixel_buffer_object buffer object + */ +struct gl_buffer_object +{ + _glthread_Mutex Mutex; + GLint RefCount; + GLuint Name; + GLenum Usage; /**< GL_STREAM_DRAW_ARB, GL_STREAM_READ_ARB, etc. */ + GLsizeiptrARB Size; /**< Size of buffer storage in bytes */ + GLubyte *Data; /**< Location of storage either in RAM or VRAM. */ + /** Fields describing a mapped buffer */ + /*@{*/ + GLbitfield AccessFlags; /**< Mask of GL_MAP_x_BIT flags */ + GLvoid *Pointer; /**< User-space address of mapping */ + GLintptr Offset; /**< Mapped offset */ + GLsizeiptr Length; /**< Mapped length */ + /*@}*/ + GLboolean Written; /**< Ever written to? (for debugging) */ + GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */ +}; + + +/** + * Client pixel packing/unpacking attributes + */ +struct gl_pixelstore_attrib +{ + GLint Alignment; + GLint RowLength; + GLint SkipPixels; + GLint SkipRows; + GLint ImageHeight; + GLint SkipImages; + GLboolean SwapBytes; + GLboolean LsbFirst; + GLboolean ClientStorage; /**< GL_APPLE_client_storage */ + GLboolean Invert; /**< GL_MESA_pack_invert */ + struct gl_buffer_object *BufferObj; /**< GL_ARB_pixel_buffer_object */ +}; + + +/** + * Client vertex array attributes + */ +struct gl_client_array +{ + GLint Size; /**< components per element (1,2,3,4) */ + GLenum Type; /**< datatype: GL_FLOAT, GL_INT, etc */ + GLenum Format; /**< default: GL_RGBA, but may be GL_BGRA */ + GLsizei Stride; /**< user-specified stride */ + GLsizei StrideB; /**< actual stride in bytes */ + const GLubyte *Ptr; /**< Points to array data */ + GLboolean Enabled; /**< Enabled flag is a boolean */ + GLboolean Normalized; /**< GL_ARB_vertex_program */ + GLboolean Integer; /**< Integer-valued? */ + GLuint InstanceDivisor; /**< GL_ARB_instanced_arrays */ + GLuint _ElementSize; /**< size of each element in bytes */ + + struct gl_buffer_object *BufferObj;/**< GL_ARB_vertex_buffer_object */ + GLuint _MaxElement; /**< max element index into array buffer + 1 */ +}; + + +/** + * Collection of vertex arrays. Defined by the GL_APPLE_vertex_array_object + * extension, but a nice encapsulation in any case. + */ +struct gl_array_object +{ + /** Name of the array object as received from glGenVertexArrayAPPLE. */ + GLuint Name; + + GLint RefCount; + _glthread_Mutex Mutex; + GLboolean VBOonly; /**< require all arrays to live in VBOs? */ + + /** Conventional vertex arrays */ + /*@{*/ + struct gl_client_array Vertex; + struct gl_client_array Weight; + struct gl_client_array Normal; + struct gl_client_array Color; + struct gl_client_array SecondaryColor; + struct gl_client_array FogCoord; + struct gl_client_array Index; + struct gl_client_array EdgeFlag; + struct gl_client_array TexCoord[MAX_TEXTURE_COORD_UNITS]; + struct gl_client_array PointSize; + /*@}*/ + + /** + * Generic arrays for vertex programs/shaders. + * For NV vertex programs, these attributes alias and take priority + * over the conventional attribs above. For ARB vertex programs and + * GLSL vertex shaders, these attributes are separate. + */ + struct gl_client_array VertexAttrib[MAX_VERTEX_GENERIC_ATTRIBS]; + + /** Mask of _NEW_ARRAY_* values indicating which arrays are enabled */ + GLbitfield _Enabled; + + /** + * Min of all enabled arrays' _MaxElement. When arrays reside inside VBOs + * we can determine the max legal (in bounds) glDrawElements array index. + */ + GLuint _MaxElement; +}; + + +/** + * Vertex array state + */ +struct gl_array_attrib +{ + /** Currently bound array object. See _mesa_BindVertexArrayAPPLE() */ + struct gl_array_object *ArrayObj; + + /** The default vertex array object */ + struct gl_array_object *DefaultArrayObj; + + /** Array objects (GL_ARB/APPLE_vertex_array_object) */ + struct _mesa_HashTable *Objects; + + GLint ActiveTexture; /**< Client Active Texture */ + GLuint LockFirst; /**< GL_EXT_compiled_vertex_array */ + GLuint LockCount; /**< GL_EXT_compiled_vertex_array */ + + /** GL 3.1 (slightly different from GL_NV_primitive_restart) */ + GLboolean PrimitiveRestart; + GLuint RestartIndex; + + GLbitfield NewState; /**< mask of _NEW_ARRAY_* values */ + GLboolean RebindArrays; /**< whether the VBO module should rebind arrays */ + + /* GL_ARB_vertex_buffer_object */ + struct gl_buffer_object *ArrayBufferObj; + struct gl_buffer_object *ElementArrayBufferObj; +}; + + +/** + * Feedback buffer state + */ +struct gl_feedback +{ + GLenum Type; + GLbitfield _Mask; /**< FB_* bits */ + GLfloat *Buffer; + GLuint BufferSize; + GLuint Count; +}; + + +/** + * Selection buffer state + */ +struct gl_selection +{ + GLuint *Buffer; /**< selection buffer */ + GLuint BufferSize; /**< size of the selection buffer */ + GLuint BufferCount; /**< number of values in the selection buffer */ + GLuint Hits; /**< number of records in the selection buffer */ + GLuint NameStackDepth; /**< name stack depth */ + GLuint NameStack[MAX_NAME_STACK_DEPTH]; /**< name stack */ + GLboolean HitFlag; /**< hit flag */ + GLfloat HitMinZ; /**< minimum hit depth */ + GLfloat HitMaxZ; /**< maximum hit depth */ +}; + + +/** + * 1-D Evaluator control points + */ +struct gl_1d_map +{ + GLuint Order; /**< Number of control points */ + GLfloat u1, u2, du; /**< u1, u2, 1.0/(u2-u1) */ + GLfloat *Points; /**< Points to contiguous control points */ +}; + + +/** + * 2-D Evaluator control points + */ +struct gl_2d_map +{ + GLuint Uorder; /**< Number of control points in U dimension */ + GLuint Vorder; /**< Number of control points in V dimension */ + GLfloat u1, u2, du; + GLfloat v1, v2, dv; + GLfloat *Points; /**< Points to contiguous control points */ +}; + + +/** + * All evaluator control point state + */ +struct gl_evaluators +{ + /** + * \name 1-D maps + */ + /*@{*/ + struct gl_1d_map Map1Vertex3; + struct gl_1d_map Map1Vertex4; + struct gl_1d_map Map1Index; + struct gl_1d_map Map1Color4; + struct gl_1d_map Map1Normal; + struct gl_1d_map Map1Texture1; + struct gl_1d_map Map1Texture2; + struct gl_1d_map Map1Texture3; + struct gl_1d_map Map1Texture4; + struct gl_1d_map Map1Attrib[16]; /**< GL_NV_vertex_program */ + /*@}*/ + + /** + * \name 2-D maps + */ + /*@{*/ + struct gl_2d_map Map2Vertex3; + struct gl_2d_map Map2Vertex4; + struct gl_2d_map Map2Index; + struct gl_2d_map Map2Color4; + struct gl_2d_map Map2Normal; + struct gl_2d_map Map2Texture1; + struct gl_2d_map Map2Texture2; + struct gl_2d_map Map2Texture3; + struct gl_2d_map Map2Texture4; + struct gl_2d_map Map2Attrib[16]; /**< GL_NV_vertex_program */ + /*@}*/ +}; + + +/** + * Names of the various vertex/fragment program register files, etc. + * + * NOTE: first four tokens must fit into 2 bits (see t_vb_arbprogram.c) + * All values should fit in a 4-bit field. + * + * NOTE: PROGRAM_ENV_PARAM, PROGRAM_STATE_VAR, PROGRAM_NAMED_PARAM, + * PROGRAM_CONSTANT, and PROGRAM_UNIFORM can all be considered to + * be "uniform" variables since they can only be set outside glBegin/End. + * They're also all stored in the same Parameters array. + */ +typedef enum +{ + PROGRAM_TEMPORARY, /**< machine->Temporary[] */ + PROGRAM_INPUT, /**< machine->Inputs[] */ + PROGRAM_OUTPUT, /**< machine->Outputs[] */ + PROGRAM_VARYING, /**< machine->Inputs[]/Outputs[] */ + PROGRAM_LOCAL_PARAM, /**< gl_program->LocalParams[] */ + PROGRAM_ENV_PARAM, /**< gl_program->Parameters[] */ + PROGRAM_STATE_VAR, /**< gl_program->Parameters[] */ + PROGRAM_NAMED_PARAM, /**< gl_program->Parameters[] */ + PROGRAM_CONSTANT, /**< gl_program->Parameters[] */ + PROGRAM_UNIFORM, /**< gl_program->Parameters[] */ + PROGRAM_WRITE_ONLY, /**< A dummy, write-only register */ + PROGRAM_ADDRESS, /**< machine->AddressReg */ + PROGRAM_SAMPLER, /**< for shader samplers, compile-time only */ + PROGRAM_SYSTEM_VALUE,/**< InstanceId, PrimitiveID, etc. */ + PROGRAM_UNDEFINED, /**< Invalid/TBD value */ + PROGRAM_FILE_MAX +} gl_register_file; + + +/** + * If the register file is PROGRAM_SYSTEM_VALUE, the register index will be + * one of these values. + */ +typedef enum +{ + SYSTEM_VALUE_FRONT_FACE, /**< Fragment shader only (not done yet) */ + SYSTEM_VALUE_INSTANCE_ID, /**< Vertex shader only */ + SYSTEM_VALUE_MAX /**< Number of values */ +} gl_system_value; + + +/** Vertex and fragment instructions */ +struct prog_instruction; +struct gl_program_parameter_list; +struct gl_uniform_list; + + +/** + * Base class for any kind of program object + */ +struct gl_program +{ + GLuint Id; + GLubyte *String; /**< Null-terminated program text */ + GLint RefCount; + GLenum Target; /**< GL_VERTEX/FRAGMENT_PROGRAM_ARB, GL_FRAGMENT_PROGRAM_NV */ + GLenum Format; /**< String encoding format */ + GLboolean Resident; + + struct prog_instruction *Instructions; + + GLbitfield InputsRead; /**< Bitmask of which input regs are read */ + GLbitfield64 OutputsWritten; /**< Bitmask of which output regs are written */ + GLbitfield SystemValuesRead; /**< Bitmask of SYSTEM_VALUE_x inputs used */ + GLbitfield InputFlags[MAX_PROGRAM_INPUTS]; /**< PROG_PARAM_BIT_x flags */ + GLbitfield OutputFlags[MAX_PROGRAM_OUTPUTS]; /**< PROG_PARAM_BIT_x flags */ + GLbitfield TexturesUsed[MAX_TEXTURE_UNITS]; /**< TEXTURE_x_BIT bitmask */ + GLbitfield SamplersUsed; /**< Bitfield of which samplers are used */ + GLbitfield ShadowSamplers; /**< Texture units used for shadow sampling. */ + + + /** Named parameters, constants, etc. from program text */ + struct gl_program_parameter_list *Parameters; + /** Numbered local parameters */ + GLfloat LocalParams[MAX_PROGRAM_LOCAL_PARAMS][4]; + + /** Vertex/fragment shader varying vars */ + struct gl_program_parameter_list *Varying; + /** Vertex program user-defined attributes */ + struct gl_program_parameter_list *Attributes; + + /** Map from sampler unit to texture unit (set by glUniform1i()) */ + GLubyte SamplerUnits[MAX_SAMPLERS]; + /** Which texture target is being sampled (TEXTURE_1D/2D/3D/etc_INDEX) */ + gl_texture_index SamplerTargets[MAX_SAMPLERS]; + + /** Bitmask of which register files are read/written with indirect + * addressing. Mask of (1 << PROGRAM_x) bits. + */ + GLbitfield IndirectRegisterFiles; + + /** Logical counts */ + /*@{*/ + GLuint NumInstructions; + GLuint NumTemporaries; + GLuint NumParameters; + GLuint NumAttributes; + GLuint NumAddressRegs; + GLuint NumAluInstructions; + GLuint NumTexInstructions; + GLuint NumTexIndirections; + /*@}*/ + /** Native, actual h/w counts */ + /*@{*/ + GLuint NumNativeInstructions; + GLuint NumNativeTemporaries; + GLuint NumNativeParameters; + GLuint NumNativeAttributes; + GLuint NumNativeAddressRegs; + GLuint NumNativeAluInstructions; + GLuint NumNativeTexInstructions; + GLuint NumNativeTexIndirections; + /*@}*/ +}; + + +/** Vertex program object */ +struct gl_vertex_program +{ + struct gl_program Base; /**< base class */ + GLboolean IsNVProgram; /**< is this a GL_NV_vertex_program program? */ + GLboolean IsPositionInvariant; +}; + + +/** Geometry program object */ +struct gl_geometry_program +{ + struct gl_program Base; /**< base class */ + + GLint VerticesOut; + GLenum InputType; /**< GL_POINTS, GL_LINES, GL_LINES_ADJACENCY_ARB, + GL_TRIANGLES, or GL_TRIANGLES_ADJACENCY_ARB */ + GLenum OutputType; /**< GL_POINTS, GL_LINE_STRIP or GL_TRIANGLE_STRIP */ +}; + + +/** Fragment program object */ +struct gl_fragment_program +{ + struct gl_program Base; /**< base class */ + GLenum FogOption; + GLboolean UsesKill; /**< shader uses KIL instruction */ + GLboolean OriginUpperLeft; + GLboolean PixelCenterInteger; + enum gl_frag_depth_layout FragDepthLayout; +}; + + +/** + * State common to vertex and fragment programs. + */ +struct gl_program_state +{ + GLint ErrorPos; /* GL_PROGRAM_ERROR_POSITION_ARB/NV */ + const char *ErrorString; /* GL_PROGRAM_ERROR_STRING_ARB/NV */ +}; + + +/** + * Context state for vertex programs. + */ +struct gl_vertex_program_state +{ + GLboolean Enabled; /**< User-set GL_VERTEX_PROGRAM_ARB/NV flag */ + GLboolean _Enabled; /**< Enabled and _valid_ user program? */ + GLboolean PointSizeEnabled; /**< GL_VERTEX_PROGRAM_POINT_SIZE_ARB/NV */ + GLboolean TwoSideEnabled; /**< GL_VERTEX_PROGRAM_TWO_SIDE_ARB/NV */ + struct gl_vertex_program *Current; /**< User-bound vertex program */ + + /** Currently enabled and valid vertex program (including internal + * programs, user-defined vertex programs and GLSL vertex shaders). + * This is the program we must use when rendering. + */ + struct gl_vertex_program *_Current; + + GLfloat Parameters[MAX_PROGRAM_ENV_PARAMS][4]; /**< Env params */ + + /* For GL_NV_vertex_program only: */ + GLenum TrackMatrix[MAX_PROGRAM_ENV_PARAMS / 4]; + GLenum TrackMatrixTransform[MAX_PROGRAM_ENV_PARAMS / 4]; + + /** Should fixed-function T&L be implemented with a vertex prog? */ + GLboolean _MaintainTnlProgram; + + /** Program to emulate fixed-function T&L (see above) */ + struct gl_vertex_program *_TnlProgram; + + /** Cache of fixed-function programs */ + struct gl_program_cache *Cache; + + GLboolean _Overriden; +}; + + +/** + * Context state for geometry programs. + */ +struct gl_geometry_program_state +{ + GLboolean Enabled; /**< GL_ARB_GEOMETRY_SHADER4 */ + GLboolean _Enabled; /**< Enabled and valid program? */ + struct gl_geometry_program *Current; /**< user-bound geometry program */ + + /** Currently enabled and valid program (including internal programs + * and compiled shader programs). + */ + struct gl_geometry_program *_Current; + + GLfloat Parameters[MAX_PROGRAM_ENV_PARAMS][4]; /**< Env params */ + + /** Cache of fixed-function programs */ + struct gl_program_cache *Cache; +}; + +/** + * Context state for fragment programs. + */ +struct gl_fragment_program_state +{ + GLboolean Enabled; /**< User-set fragment program enable flag */ + GLboolean _Enabled; /**< Enabled and _valid_ user program? */ + struct gl_fragment_program *Current; /**< User-bound fragment program */ + + /** Currently enabled and valid fragment program (including internal + * programs, user-defined fragment programs and GLSL fragment shaders). + * This is the program we must use when rendering. + */ + struct gl_fragment_program *_Current; + + GLfloat Parameters[MAX_PROGRAM_ENV_PARAMS][4]; /**< Env params */ + + /** Should fixed-function texturing be implemented with a fragment prog? */ + GLboolean _MaintainTexEnvProgram; + + /** Program to emulate fixed-function texture env/combine (see above) */ + struct gl_fragment_program *_TexEnvProgram; + + /** Cache of fixed-function programs */ + struct gl_program_cache *Cache; +}; + + +/** + * ATI_fragment_shader runtime state + */ +#define ATI_FS_INPUT_PRIMARY 0 +#define ATI_FS_INPUT_SECONDARY 1 + +struct atifs_instruction; +struct atifs_setupinst; + +/** + * ATI fragment shader + */ +struct ati_fragment_shader +{ + GLuint Id; + GLint RefCount; + struct atifs_instruction *Instructions[2]; + struct atifs_setupinst *SetupInst[2]; + GLfloat Constants[8][4]; + GLbitfield LocalConstDef; /**< Indicates which constants have been set */ + GLubyte numArithInstr[2]; + GLubyte regsAssigned[2]; + GLubyte NumPasses; /**< 1 or 2 */ + GLubyte cur_pass; + GLubyte last_optype; + GLboolean interpinp1; + GLboolean isValid; + GLuint swizzlerq; +}; + +/** + * Context state for GL_ATI_fragment_shader + */ +struct gl_ati_fragment_shader_state +{ + GLboolean Enabled; + GLboolean _Enabled; /**< enabled and valid shader? */ + GLboolean Compiling; + GLfloat GlobalConstants[8][4]; + struct ati_fragment_shader *Current; +}; + + +/** + * Occlusion/timer query object. + */ +struct gl_query_object +{ + GLenum Target; /**< The query target, when active */ + GLuint Id; /**< hash table ID/name */ + GLuint64EXT Result; /**< the counter */ + GLboolean Active; /**< inside Begin/EndQuery */ + GLboolean Ready; /**< result is ready? */ +}; + + +/** + * Context state for query objects. + */ +struct gl_query_state +{ + struct _mesa_HashTable *QueryObjects; + struct gl_query_object *CurrentOcclusionObject; /* GL_ARB_occlusion_query */ + struct gl_query_object *CurrentTimerObject; /* GL_EXT_timer_query */ + + /** GL_NV_conditional_render */ + struct gl_query_object *CondRenderQuery; + + /** GL_EXT_transform_feedback */ + struct gl_query_object *PrimitivesGenerated; + struct gl_query_object *PrimitivesWritten; + + /** GL_ARB_timer_query */ + struct gl_query_object *TimeElapsed; + + GLenum CondRenderMode; +}; + + +/** Sync object state */ +struct gl_sync_object { + struct simple_node link; + GLenum Type; /**< GL_SYNC_FENCE */ + GLuint Name; /**< Fence name */ + GLint RefCount; /**< Reference count */ + GLboolean DeletePending; /**< Object was deleted while there were still + * live references (e.g., sync not yet finished) + */ + GLenum SyncCondition; + GLbitfield Flags; /**< Flags passed to glFenceSync */ + GLuint StatusFlag:1; /**< Has the sync object been signaled? */ +}; + + +/** Set by #pragma directives */ +struct gl_sl_pragmas +{ + GLboolean IgnoreOptimize; /**< ignore #pragma optimize(on/off) ? */ + GLboolean IgnoreDebug; /**< ignore #pragma debug(on/off) ? */ + GLboolean Optimize; /**< defaults on */ + GLboolean Debug; /**< defaults off */ +}; + + +/** + * A GLSL vertex or fragment shader object. + */ +struct gl_shader +{ + GLenum Type; /**< GL_FRAGMENT_SHADER || GL_VERTEX_SHADER || GL_GEOMETRY_SHADER_ARB (first field!) */ + GLuint Name; /**< AKA the handle */ + GLint RefCount; /**< Reference count */ + GLboolean DeletePending; + GLboolean CompileStatus; + const GLchar *Source; /**< Source code string */ + GLuint SourceChecksum; /**< for debug/logging purposes */ + struct gl_program *Program; /**< Post-compile assembly code */ + GLchar *InfoLog; + struct gl_sl_pragmas Pragmas; + + unsigned Version; /**< GLSL version used for linking */ + + struct exec_list *ir; + struct glsl_symbol_table *symbols; + + /** Shaders containing built-in functions that are used for linking. */ + struct gl_shader *builtins_to_link[16]; + unsigned num_builtins_to_link; +}; + + +/** + * A GLSL program object. + * Basically a linked collection of vertex and fragment shaders. + */ +struct gl_shader_program +{ + GLenum Type; /**< Always GL_SHADER_PROGRAM (internal token) */ + GLuint Name; /**< aka handle or ID */ + GLint RefCount; /**< Reference count */ + GLboolean DeletePending; + + GLuint NumShaders; /**< number of attached shaders */ + struct gl_shader **Shaders; /**< List of attached the shaders */ + + /** User-defined attribute bindings (glBindAttribLocation) */ + struct gl_program_parameter_list *Attributes; + + /** Transform feedback varyings */ + struct { + GLenum BufferMode; + GLuint NumVarying; + GLchar **VaryingNames; /**< Array [NumVarying] of char * */ + } TransformFeedback; + + /** Geometry shader state - copied into gl_geometry_program at link time */ + struct { + GLint VerticesOut; + GLenum InputType; /**< GL_POINTS, GL_LINES, GL_LINES_ADJACENCY_ARB, + GL_TRIANGLES, or GL_TRIANGLES_ADJACENCY_ARB */ + GLenum OutputType; /**< GL_POINTS, GL_LINE_STRIP or GL_TRIANGLE_STRIP */ + } Geom; + + /* post-link info: */ + struct gl_vertex_program *VertexProgram; /**< Linked vertex program */ + struct gl_fragment_program *FragmentProgram; /**< Linked fragment prog */ + struct gl_geometry_program *GeometryProgram; /**< Linked geometry prog */ + struct gl_uniform_list *Uniforms; + struct gl_program_parameter_list *Varying; + GLboolean LinkStatus; /**< GL_LINK_STATUS */ + GLboolean Validated; + GLboolean _Used; /**< Ever used for drawing? */ + GLchar *InfoLog; + + unsigned Version; /**< GLSL version used for linking */ + + /** + * Per-stage shaders resulting from the first stage of linking. + * + * Set of linked shaders for this program. The array is accessed using the + * \c MESA_SHADER_* defines. Entries for non-existent stages will be + * \c NULL. + */ + struct gl_shader *_LinkedShaders[MESA_SHADER_TYPES]; +}; + + +#define GLSL_DUMP 0x1 /**< Dump shaders to stdout */ +#define GLSL_LOG 0x2 /**< Write shaders to files */ +#define GLSL_OPT 0x4 /**< Force optimizations (override pragmas) */ +#define GLSL_NO_OPT 0x8 /**< Force no optimizations (override pragmas) */ +#define GLSL_UNIFORMS 0x10 /**< Print glUniform calls */ +#define GLSL_NOP_VERT 0x20 /**< Force no-op vertex shaders */ +#define GLSL_NOP_FRAG 0x40 /**< Force no-op fragment shaders */ +#define GLSL_USE_PROG 0x80 /**< Log glUseProgram calls */ + + +/** + * Context state for GLSL vertex/fragment shaders. + */ +struct gl_shader_state +{ + /** + * Programs used for rendering + * + * There is a separate program set for each shader stage. If + * GL_EXT_separate_shader_objects is not supported, each of these must point + * to \c NULL or to the same program. + */ + struct gl_shader_program *CurrentVertexProgram; + struct gl_shader_program *CurrentGeometryProgram; + struct gl_shader_program *CurrentFragmentProgram; + + /** + * Program used by glUniform calls. + * + * Explicitly set by \c glUseProgram and \c glActiveProgramEXT. + */ + struct gl_shader_program *ActiveProgram; + + void *MemPool; + + GLbitfield Flags; /**< Mask of GLSL_x flags */ +}; + +/** + * Compiler options for a single GLSL shaders type + */ +struct gl_shader_compiler_options +{ + /** Driver-selectable options: */ + GLboolean EmitCondCodes; /**< Use condition codes? */ + GLboolean EmitNVTempInitialization; /**< 0-fill NV temp registers */ + /** + * Attempts to flatten all ir_if (OPCODE_IF) for GPUs that can't + * support control flow. + */ + GLboolean EmitNoIfs; + GLboolean EmitNoLoops; + GLboolean EmitNoFunctions; + GLboolean EmitNoCont; /**< Emit CONT opcode? */ + GLboolean EmitNoMainReturn; /**< Emit CONT/RET opcodes? */ + GLboolean EmitNoNoise; /**< Emit NOISE opcodes? */ + GLboolean EmitNoPow; /**< Emit POW opcodes? */ + + /** + * \name Forms of indirect addressing the driver cannot do. + */ + /*@{*/ + GLboolean EmitNoIndirectInput; /**< No indirect addressing of inputs */ + GLboolean EmitNoIndirectOutput; /**< No indirect addressing of outputs */ + GLboolean EmitNoIndirectTemp; /**< No indirect addressing of temps */ + GLboolean EmitNoIndirectUniform; /**< No indirect addressing of constants */ + /*@}*/ + + GLuint MaxUnrollIterations; + + struct gl_sl_pragmas DefaultPragmas; /**< Default #pragma settings */ +}; + +/** + * Transform feedback object state + */ +struct gl_transform_feedback_object +{ + GLuint Name; /**< AKA the object ID */ + GLint RefCount; + GLboolean Active; /**< Is transform feedback enabled? */ + GLboolean Paused; /**< Is transform feedback paused? */ + + /** The feedback buffers */ + GLuint BufferNames[MAX_FEEDBACK_ATTRIBS]; + struct gl_buffer_object *Buffers[MAX_FEEDBACK_ATTRIBS]; + + /** Start of feedback data in dest buffer */ + GLintptr Offset[MAX_FEEDBACK_ATTRIBS]; + /** Max data to put into dest buffer (in bytes) */ + GLsizeiptr Size[MAX_FEEDBACK_ATTRIBS]; +}; + + +/** + * Context state for transform feedback. + */ +struct gl_transform_feedback +{ + GLenum Mode; /**< GL_POINTS, GL_LINES or GL_TRIANGLES */ + + GLboolean RasterDiscard; /**< GL_RASTERIZER_DISCARD */ + + /** The general binding point (GL_TRANSFORM_FEEDBACK_BUFFER) */ + struct gl_buffer_object *CurrentBuffer; + + /** The table of all transform feedback objects */ + struct _mesa_HashTable *Objects; + + /** The current xform-fb object (GL_TRANSFORM_FEEDBACK_BINDING) */ + struct gl_transform_feedback_object *CurrentObject; + + /** The default xform-fb object (Name==0) */ + struct gl_transform_feedback_object *DefaultObject; +}; + + + +/** + * State which can be shared by multiple contexts: + */ +struct gl_shared_state +{ + _glthread_Mutex Mutex; /**< for thread safety */ + GLint RefCount; /**< Reference count */ + struct _mesa_HashTable *DisplayList; /**< Display lists hash table */ + struct _mesa_HashTable *TexObjects; /**< Texture objects hash table */ + + /** Default texture objects (shared by all texture units) */ + struct gl_texture_object *DefaultTex[NUM_TEXTURE_TARGETS]; + + /** Fallback texture used when a bound texture is incomplete */ + struct gl_texture_object *FallbackTex; + + /** + * \name Thread safety and statechange notification for texture + * objects. + * + * \todo Improve the granularity of locking. + */ + /*@{*/ + _glthread_Mutex TexMutex; /**< texobj thread safety */ + GLuint TextureStateStamp; /**< state notification for shared tex */ + /*@}*/ + + /** Default buffer object for vertex arrays that aren't in VBOs */ + struct gl_buffer_object *NullBufferObj; + + /** + * \name Vertex/geometry/fragment programs + */ + /*@{*/ + struct _mesa_HashTable *Programs; /**< All vertex/fragment programs */ + struct gl_vertex_program *DefaultVertexProgram; + struct gl_fragment_program *DefaultFragmentProgram; + struct gl_geometry_program *DefaultGeometryProgram; + /*@}*/ + + /* GL_ATI_fragment_shader */ + struct _mesa_HashTable *ATIShaders; + struct ati_fragment_shader *DefaultFragmentShader; + + struct _mesa_HashTable *BufferObjects; + + /** Table of both gl_shader and gl_shader_program objects */ + struct _mesa_HashTable *ShaderObjects; + + /* GL_EXT_framebuffer_object */ + struct _mesa_HashTable *RenderBuffers; + struct _mesa_HashTable *FrameBuffers; + + /* GL_ARB_sync */ + struct simple_node SyncObjects; + + void *DriverData; /**< Device driver shared state */ +}; + + + + +/** + * A renderbuffer stores colors or depth values or stencil values. + * A framebuffer object will have a collection of these. + * Data are read/written to the buffer with a handful of Get/Put functions. + * + * Instances of this object are allocated with the Driver's NewRenderbuffer + * hook. Drivers will likely wrap this class inside a driver-specific + * class to simulate inheritance. + */ +struct gl_renderbuffer +{ +#define RB_MAGIC 0xaabbccdd + int Magic; /** XXX TEMPORARY DEBUG INFO */ + _glthread_Mutex Mutex; /**< for thread safety */ + GLuint ClassID; /**< Useful for drivers */ + GLuint Name; + GLint RefCount; + GLuint Width, Height; + GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */ + + GLenum InternalFormat; /**< The user-specified format */ + GLenum _BaseFormat; /**< Either GL_RGB, GL_RGBA, GL_DEPTH_COMPONENT or + GL_STENCIL_INDEX. */ + gl_format Format; /**< The actual renderbuffer memory format */ + + GLubyte NumSamples; + + GLenum DataType; /**< Type of values passed to the Get/Put functions */ + GLvoid *Data; /**< This may not be used by some kinds of RBs */ + + /* Used to wrap one renderbuffer around another: */ + struct gl_renderbuffer *Wrapped; + + /* Delete this renderbuffer */ + void (*Delete)(struct gl_renderbuffer *rb); + + /* Allocate new storage for this renderbuffer */ + GLboolean (*AllocStorage)(struct gl_context *ctx, struct gl_renderbuffer *rb, + GLenum internalFormat, + GLuint width, GLuint height); + + /* Lock/Unlock are called before/after calling the Get/Put functions. + * Not sure this is the right place for these yet. + void (*Lock)(struct gl_context *ctx, struct gl_renderbuffer *rb); + void (*Unlock)(struct gl_context *ctx, struct gl_renderbuffer *rb); + */ + + /* Return a pointer to the element/pixel at (x,y). + * Should return NULL if the buffer memory can't be directly addressed. + */ + void *(*GetPointer)(struct gl_context *ctx, struct gl_renderbuffer *rb, + GLint x, GLint y); + + /* Get/Read a row of values. + * The values will be of format _BaseFormat and type DataType. + */ + void (*GetRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, void *values); + + /* Get/Read values at arbitrary locations. + * The values will be of format _BaseFormat and type DataType. + */ + void (*GetValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], void *values); + + /* Put/Write a row of values. + * The values will be of format _BaseFormat and type DataType. + */ + void (*PutRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask); + + /* Put/Write a row of RGB values. This is a special-case routine that's + * only used for RGBA renderbuffers when the source data is GL_RGB. That's + * a common case for glDrawPixels and some triangle routines. + * The values will be of format GL_RGB and type DataType. + */ + void (*PutRowRGB)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask); + + + /* Put/Write a row of identical values. + * The values will be of format _BaseFormat and type DataType. + */ + void (*PutMonoRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *value, const GLubyte *mask); + + /* Put/Write values at arbitrary locations. + * The values will be of format _BaseFormat and type DataType. + */ + void (*PutValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], const void *values, + const GLubyte *mask); + /* Put/Write identical values at arbitrary locations. + * The values will be of format _BaseFormat and type DataType. + */ + void (*PutMonoValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, + GLuint count, const GLint x[], const GLint y[], + const void *value, const GLubyte *mask); +}; + + +/** + * A renderbuffer attachment points to either a texture object (and specifies + * a mipmap level, cube face or 3D texture slice) or points to a renderbuffer. + */ +struct gl_renderbuffer_attachment +{ + GLenum Type; /**< \c GL_NONE or \c GL_TEXTURE or \c GL_RENDERBUFFER_EXT */ + GLboolean Complete; + + /** + * If \c Type is \c GL_RENDERBUFFER_EXT, this stores a pointer to the + * application supplied renderbuffer object. + */ + struct gl_renderbuffer *Renderbuffer; + + /** + * If \c Type is \c GL_TEXTURE, this stores a pointer to the application + * supplied texture object. + */ + struct gl_texture_object *Texture; + GLuint TextureLevel; /**< Attached mipmap level. */ + GLuint CubeMapFace; /**< 0 .. 5, for cube map textures. */ + GLuint Zoffset; /**< Slice for 3D textures, or layer for both 1D + * and 2D array textures */ +}; + + +/** + * A framebuffer is a collection of renderbuffers (color, depth, stencil, etc). + * In C++ terms, think of this as a base class from which device drivers + * will make derived classes. + */ +struct gl_framebuffer +{ + _glthread_Mutex Mutex; /**< for thread safety */ + /** + * If zero, this is a window system framebuffer. If non-zero, this + * is a FBO framebuffer; note that for some devices (i.e. those with + * a natural pixel coordinate system for FBOs that differs from the + * OpenGL/Mesa coordinate system), this means that the viewport, + * polygon face orientation, and polygon stipple will have to be inverted. + */ + GLuint Name; + + GLint RefCount; + GLboolean DeletePending; + + /** + * The framebuffer's visual. Immutable if this is a window system buffer. + * Computed from attachments if user-made FBO. + */ + struct gl_config Visual; + + GLboolean Initialized; + + GLuint Width, Height; /**< size of frame buffer in pixels */ + + /** \name Drawing bounds (Intersection of buffer size and scissor box) */ + /*@{*/ + GLint _Xmin, _Xmax; /**< inclusive */ + GLint _Ymin, _Ymax; /**< exclusive */ + /*@}*/ + + /** \name Derived Z buffer stuff */ + /*@{*/ + GLuint _DepthMax; /**< Max depth buffer value */ + GLfloat _DepthMaxF; /**< Float max depth buffer value */ + GLfloat _MRD; /**< minimum resolvable difference in Z values */ + /*@}*/ + + /** One of the GL_FRAMEBUFFER_(IN)COMPLETE_* tokens */ + GLenum _Status; + + /** Integer color values */ + GLboolean _IntegerColor; + + /** Array of all renderbuffer attachments, indexed by BUFFER_* tokens. */ + struct gl_renderbuffer_attachment Attachment[BUFFER_COUNT]; + + /* In unextended OpenGL these vars are part of the GL_COLOR_BUFFER + * attribute group and GL_PIXEL attribute group, respectively. + */ + GLenum ColorDrawBuffer[MAX_DRAW_BUFFERS]; + GLenum ColorReadBuffer; + + /** Computed from ColorDraw/ReadBuffer above */ + GLuint _NumColorDrawBuffers; + GLint _ColorDrawBufferIndexes[MAX_DRAW_BUFFERS]; /**< BUFFER_x or -1 */ + GLint _ColorReadBufferIndex; /* -1 = None */ + struct gl_renderbuffer *_ColorDrawBuffers[MAX_DRAW_BUFFERS]; + struct gl_renderbuffer *_ColorReadBuffer; + + /** The Actual depth/stencil buffers to use. May be wrappers around the + * depth/stencil buffers attached above. */ + struct gl_renderbuffer *_DepthBuffer; + struct gl_renderbuffer *_StencilBuffer; + + /** Delete this framebuffer */ + void (*Delete)(struct gl_framebuffer *fb); +}; + + +/** + * Precision info for shader datatypes. See glGetShaderPrecisionFormat(). + */ +struct gl_precision +{ + GLushort RangeMin; /**< min value exponent */ + GLushort RangeMax; /**< max value exponent */ + GLushort Precision; /**< number of mantissa bits */ +}; + + +/** + * Limits for vertex and fragment programs/shaders. + */ +struct gl_program_constants +{ + /* logical limits */ + GLuint MaxInstructions; + GLuint MaxAluInstructions; + GLuint MaxTexInstructions; + GLuint MaxTexIndirections; + GLuint MaxAttribs; + GLuint MaxTemps; + GLuint MaxAddressRegs; + GLuint MaxParameters; + GLuint MaxLocalParams; + GLuint MaxEnvParams; + /* native/hardware limits */ + GLuint MaxNativeInstructions; + GLuint MaxNativeAluInstructions; + GLuint MaxNativeTexInstructions; + GLuint MaxNativeTexIndirections; + GLuint MaxNativeAttribs; + GLuint MaxNativeTemps; + GLuint MaxNativeAddressRegs; + GLuint MaxNativeParameters; + /* For shaders */ + GLuint MaxUniformComponents; + /* GL_ARB_geometry_shader4 */ + GLuint MaxGeometryTextureImageUnits; + GLuint MaxGeometryVaryingComponents; + GLuint MaxVertexVaryingComponents; + GLuint MaxGeometryUniformComponents; + GLuint MaxGeometryOutputVertices; + GLuint MaxGeometryTotalOutputComponents; + /* ES 2.0 and GL_ARB_ES2_compatibility */ + struct gl_precision LowFloat, MediumFloat, HighFloat; + struct gl_precision LowInt, MediumInt, HighInt; +}; + + +/** + * Constants which may be overridden by device driver during context creation + * but are never changed after that. + */ +struct gl_constants +{ + GLint MaxTextureMbytes; /**< Max memory per image, in MB */ + GLint MaxTextureLevels; /**< Max mipmap levels. */ + GLint Max3DTextureLevels; /**< Max mipmap levels for 3D textures */ + GLint MaxCubeTextureLevels; /**< Max mipmap levels for cube textures */ + GLint MaxArrayTextureLayers; /**< Max layers in array textures */ + GLint MaxTextureRectSize; /**< Max rectangle texture size, in pixes */ + GLuint MaxTextureCoordUnits; + GLuint MaxTextureImageUnits; + GLuint MaxVertexTextureImageUnits; + GLuint MaxCombinedTextureImageUnits; + GLuint MaxTextureUnits; /**< = MIN(CoordUnits, ImageUnits) */ + GLfloat MaxTextureMaxAnisotropy; /**< GL_EXT_texture_filter_anisotropic */ + GLfloat MaxTextureLodBias; /**< GL_EXT_texture_lod_bias */ + + GLuint MaxArrayLockSize; + + GLint SubPixelBits; + + GLfloat MinPointSize, MaxPointSize; /**< aliased */ + GLfloat MinPointSizeAA, MaxPointSizeAA; /**< antialiased */ + GLfloat PointSizeGranularity; + GLfloat MinLineWidth, MaxLineWidth; /**< aliased */ + GLfloat MinLineWidthAA, MaxLineWidthAA; /**< antialiased */ + GLfloat LineWidthGranularity; + + GLuint MaxColorTableSize; + + GLuint MaxClipPlanes; + GLuint MaxLights; + GLfloat MaxShininess; /**< GL_NV_light_max_exponent */ + GLfloat MaxSpotExponent; /**< GL_NV_light_max_exponent */ + + GLuint MaxViewportWidth, MaxViewportHeight; + + struct gl_program_constants VertexProgram; /**< GL_ARB_vertex_program */ + struct gl_program_constants FragmentProgram; /**< GL_ARB_fragment_program */ + struct gl_program_constants GeometryProgram; /**< GL_ARB_geometry_shader4 */ + GLuint MaxProgramMatrices; + GLuint MaxProgramMatrixStackDepth; + + /** vertex array / buffer object bounds checking */ + GLboolean CheckArrayBounds; + + GLuint MaxDrawBuffers; /**< GL_ARB_draw_buffers */ + + GLuint MaxColorAttachments; /**< GL_EXT_framebuffer_object */ + GLuint MaxRenderbufferSize; /**< GL_EXT_framebuffer_object */ + GLuint MaxSamples; /**< GL_ARB_framebuffer_object */ + + GLuint MaxVarying; /**< Number of float[4] varying parameters */ + + GLuint GLSLVersion; /**< GLSL version supported (ex: 120 = 1.20) */ + + /** Which texture units support GL_ATI_envmap_bumpmap as targets */ + GLbitfield SupportedBumpUnits; + + /** + * Maximum amount of time, measured in nanseconds, that the server can wait. + */ + GLuint64 MaxServerWaitTimeout; + + /** GL_EXT_provoking_vertex */ + GLboolean QuadsFollowProvokingVertexConvention; + + /** OpenGL version 3.0 */ + GLbitfield ContextFlags; /**< Ex: GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT */ + + /** OpenGL version 3.2 */ + GLbitfield ProfileMask; /**< Mask of CONTEXT_x_PROFILE_BIT */ + + /** GL_EXT_transform_feedback */ + GLuint MaxTransformFeedbackSeparateAttribs; + GLuint MaxTransformFeedbackSeparateComponents; + GLuint MaxTransformFeedbackInterleavedComponents; + + /** GL_EXT_gpu_shader4 */ + GLint MinProgramTexelOffset, MaxProgramTexelOffset; + + /* GL_EXT_framebuffer_sRGB */ + GLboolean sRGBCapable; /* can enable sRGB blend/update on FBOs */ +}; + + +/** + * Enable flag for each OpenGL extension. Different device drivers will + * enable different extensions at runtime. + */ +struct gl_extensions +{ + GLboolean dummy; /* don't remove this! */ + GLboolean dummy_true; /* Set true by _mesa_init_extensions(). */ + GLboolean dummy_false; /* Set false by _mesa_init_extensions(). */ + GLboolean ARB_ES2_compatibility; + GLboolean ARB_blend_func_extended; + GLboolean ARB_copy_buffer; + GLboolean ARB_depth_buffer_float; + GLboolean ARB_depth_clamp; + GLboolean ARB_depth_texture; + GLboolean ARB_draw_buffers; + GLboolean ARB_draw_buffers_blend; + GLboolean ARB_draw_elements_base_vertex; + GLboolean ARB_draw_instanced; + GLboolean ARB_fragment_coord_conventions; + GLboolean ARB_fragment_program; + GLboolean ARB_fragment_program_shadow; + GLboolean ARB_fragment_shader; + GLboolean ARB_framebuffer_object; + GLboolean ARB_explicit_attrib_location; + GLboolean ARB_geometry_shader4; + GLboolean ARB_half_float_pixel; + GLboolean ARB_half_float_vertex; + GLboolean ARB_instanced_arrays; + GLboolean ARB_map_buffer_range; + GLboolean ARB_multisample; + GLboolean ARB_multitexture; + GLboolean ARB_occlusion_query; + GLboolean ARB_occlusion_query2; + GLboolean ARB_point_sprite; + GLboolean ARB_sampler_objects; + GLboolean ARB_seamless_cube_map; + GLboolean ARB_shader_objects; + GLboolean ARB_shader_stencil_export; + GLboolean ARB_shading_language_100; + GLboolean ARB_shadow; + GLboolean ARB_shadow_ambient; + GLboolean ARB_sync; + GLboolean ARB_texture_border_clamp; + GLboolean ARB_texture_buffer_object; + GLboolean ARB_texture_compression; + GLboolean ARB_texture_compression_rgtc; + GLboolean ARB_texture_cube_map; + GLboolean ARB_texture_env_combine; + GLboolean ARB_texture_env_crossbar; + GLboolean ARB_texture_env_dot3; + GLboolean ARB_texture_float; + GLboolean ARB_texture_mirrored_repeat; + GLboolean ARB_texture_multisample; + GLboolean ARB_texture_non_power_of_two; + GLboolean ARB_texture_rg; + GLboolean ARB_texture_rgb10_a2ui; + GLboolean ARB_timer_query; + GLboolean ARB_transform_feedback2; + GLboolean ARB_transpose_matrix; + GLboolean ARB_uniform_buffer_object; + GLboolean ARB_vertex_array_object; + GLboolean ARB_vertex_buffer_object; + GLboolean ARB_vertex_program; + GLboolean ARB_vertex_shader; + GLboolean ARB_vertex_type_2_10_10_10_rev; + GLboolean ARB_window_pos; + GLboolean EXT_abgr; + GLboolean EXT_bgra; + GLboolean EXT_blend_color; + GLboolean EXT_blend_equation_separate; + GLboolean EXT_blend_func_separate; + GLboolean EXT_blend_logic_op; + GLboolean EXT_blend_minmax; + GLboolean EXT_blend_subtract; + GLboolean EXT_clip_volume_hint; + GLboolean EXT_compiled_vertex_array; + GLboolean EXT_copy_texture; + GLboolean EXT_depth_bounds_test; + GLboolean EXT_draw_buffers2; + GLboolean EXT_draw_range_elements; + GLboolean EXT_fog_coord; + GLboolean EXT_framebuffer_blit; + GLboolean EXT_framebuffer_multisample; + GLboolean EXT_framebuffer_object; + GLboolean EXT_framebuffer_sRGB; + GLboolean EXT_gpu_program_parameters; + GLboolean EXT_gpu_shader4; + GLboolean EXT_multi_draw_arrays; + GLboolean EXT_paletted_texture; + GLboolean EXT_packed_depth_stencil; + GLboolean EXT_packed_float; + GLboolean EXT_packed_pixels; + GLboolean EXT_pixel_buffer_object; + GLboolean EXT_point_parameters; + GLboolean EXT_polygon_offset; + GLboolean EXT_provoking_vertex; + GLboolean EXT_rescale_normal; + GLboolean EXT_shadow_funcs; + GLboolean EXT_secondary_color; + GLboolean EXT_separate_shader_objects; + GLboolean EXT_separate_specular_color; + GLboolean EXT_shared_texture_palette; + GLboolean EXT_stencil_wrap; + GLboolean EXT_stencil_two_side; + GLboolean EXT_subtexture; + GLboolean EXT_texture; + GLboolean EXT_texture_object; + GLboolean EXT_texture3D; + GLboolean EXT_texture_array; + GLboolean EXT_texture_compression_s3tc; + GLboolean EXT_texture_env_add; + GLboolean EXT_texture_env_combine; + GLboolean EXT_texture_env_dot3; + GLboolean EXT_texture_filter_anisotropic; + GLboolean EXT_texture_integer; + GLboolean EXT_texture_lod_bias; + GLboolean EXT_texture_mirror_clamp; + GLboolean EXT_texture_shared_exponent; + GLboolean EXT_texture_sRGB; + GLboolean EXT_texture_sRGB_decode; + GLboolean EXT_texture_swizzle; + GLboolean EXT_transform_feedback; + GLboolean EXT_timer_query; + GLboolean EXT_vertex_array; + GLboolean EXT_vertex_array_bgra; + GLboolean EXT_vertex_array_set; + GLboolean OES_standard_derivatives; + /* vendor extensions */ + GLboolean AMD_conservative_depth; + GLboolean APPLE_client_storage; + GLboolean APPLE_packed_pixels; + GLboolean APPLE_vertex_array_object; + GLboolean APPLE_object_purgeable; + GLboolean ATI_envmap_bumpmap; + GLboolean ATI_texture_mirror_once; + GLboolean ATI_texture_env_combine3; + GLboolean ATI_fragment_shader; + GLboolean ATI_separate_stencil; + GLboolean IBM_rasterpos_clip; + GLboolean IBM_multimode_draw_arrays; + GLboolean MESA_pack_invert; + GLboolean MESA_resize_buffers; + GLboolean MESA_ycbcr_texture; + GLboolean MESA_texture_array; + GLboolean MESA_texture_signed_rgba; + GLboolean NV_blend_square; + GLboolean NV_conditional_render; + GLboolean NV_fragment_program; + GLboolean NV_fragment_program_option; + GLboolean NV_light_max_exponent; + GLboolean NV_point_sprite; + GLboolean NV_primitive_restart; + GLboolean NV_texgen_reflection; + GLboolean NV_texture_env_combine4; + GLboolean NV_texture_rectangle; + GLboolean NV_vertex_program; + GLboolean NV_vertex_program1_1; + GLboolean OES_read_format; + GLboolean SGIS_generate_mipmap; + GLboolean SGIS_texture_edge_clamp; + GLboolean SGIS_texture_lod; + GLboolean TDFX_texture_compression_FXT1; + GLboolean S3_s3tc; + GLboolean OES_EGL_image; + GLboolean OES_draw_texture; + GLboolean EXT_texture_format_BGRA8888; + GLboolean extension_sentinel; + /** The extension string */ + const GLubyte *String; + /** Number of supported extensions */ + GLuint Count; +}; + + +/** + * A stack of matrices (projection, modelview, color, texture, etc). + */ +struct gl_matrix_stack +{ + GLmatrix *Top; /**< points into Stack */ + GLmatrix *Stack; /**< array [MaxDepth] of GLmatrix */ + GLuint Depth; /**< 0 <= Depth < MaxDepth */ + GLuint MaxDepth; /**< size of Stack[] array */ + GLuint DirtyFlag; /**< _NEW_MODELVIEW or _NEW_PROJECTION, for example */ +}; + + +/** + * \name Bits for image transfer operations + * \sa __struct gl_contextRec::ImageTransferState. + */ +/*@{*/ +#define IMAGE_SCALE_BIAS_BIT 0x1 +#define IMAGE_SHIFT_OFFSET_BIT 0x2 +#define IMAGE_MAP_COLOR_BIT 0x4 +#define IMAGE_CLAMP_BIT 0x800 + + +/** Pixel Transfer ops */ +#define IMAGE_BITS (IMAGE_SCALE_BIAS_BIT | \ + IMAGE_SHIFT_OFFSET_BIT | \ + IMAGE_MAP_COLOR_BIT) + +/** + * \name Bits to indicate what state has changed. + */ +/*@{*/ +#define _NEW_MODELVIEW (1 << 0) /**< gl_context::ModelView */ +#define _NEW_PROJECTION (1 << 1) /**< gl_context::Projection */ +#define _NEW_TEXTURE_MATRIX (1 << 2) /**< gl_context::TextureMatrix */ +#define _NEW_COLOR (1 << 3) /**< gl_context::Color */ +#define _NEW_DEPTH (1 << 4) /**< gl_context::Depth */ +#define _NEW_EVAL (1 << 5) /**< gl_context::Eval, EvalMap */ +#define _NEW_FOG (1 << 6) /**< gl_context::Fog */ +#define _NEW_HINT (1 << 7) /**< gl_context::Hint */ +#define _NEW_LIGHT (1 << 8) /**< gl_context::Light */ +#define _NEW_LINE (1 << 9) /**< gl_context::Line */ +#define _NEW_PIXEL (1 << 10) /**< gl_context::Pixel */ +#define _NEW_POINT (1 << 11) /**< gl_context::Point */ +#define _NEW_POLYGON (1 << 12) /**< gl_context::Polygon */ +#define _NEW_POLYGONSTIPPLE (1 << 13) /**< gl_context::PolygonStipple */ +#define _NEW_SCISSOR (1 << 14) /**< gl_context::Scissor */ +#define _NEW_STENCIL (1 << 15) /**< gl_context::Stencil */ +#define _NEW_TEXTURE (1 << 16) /**< gl_context::Texture */ +#define _NEW_TRANSFORM (1 << 17) /**< gl_context::Transform */ +#define _NEW_VIEWPORT (1 << 18) /**< gl_context::Viewport */ +#define _NEW_PACKUNPACK (1 << 19) /**< gl_context::Pack, Unpack */ +#define _NEW_ARRAY (1 << 20) /**< gl_context::Array */ +#define _NEW_RENDERMODE (1 << 21) /**< gl_context::RenderMode, etc */ +#define _NEW_BUFFERS (1 << 22) /**< gl_context::Visual, DrawBuffer, */ +#define _NEW_CURRENT_ATTRIB (1 << 23) /**< gl_context::Current */ +#define _NEW_MULTISAMPLE (1 << 24) /**< gl_context::Multisample */ +#define _NEW_TRACK_MATRIX (1 << 25) /**< gl_context::VertexProgram */ +#define _NEW_PROGRAM (1 << 26) /**< New program/shader state */ +#define _NEW_PROGRAM_CONSTANTS (1 << 27) +#define _NEW_BUFFER_OBJECT (1 << 28) +#define _NEW_ALL ~0 +/*@}*/ + + +/** + * \name Bits to track array state changes + * + * Also used to summarize array enabled. + */ +/*@{*/ +#define _NEW_ARRAY_VERTEX VERT_BIT_POS +#define _NEW_ARRAY_WEIGHT VERT_BIT_WEIGHT +#define _NEW_ARRAY_NORMAL VERT_BIT_NORMAL +#define _NEW_ARRAY_COLOR0 VERT_BIT_COLOR0 +#define _NEW_ARRAY_COLOR1 VERT_BIT_COLOR1 +#define _NEW_ARRAY_FOGCOORD VERT_BIT_FOG +#define _NEW_ARRAY_INDEX VERT_BIT_COLOR_INDEX +#define _NEW_ARRAY_EDGEFLAG VERT_BIT_EDGEFLAG +#define _NEW_ARRAY_POINT_SIZE VERT_BIT_COLOR_INDEX /* aliased */ +#define _NEW_ARRAY_TEXCOORD_0 VERT_BIT_TEX0 +#define _NEW_ARRAY_TEXCOORD_1 VERT_BIT_TEX1 +#define _NEW_ARRAY_TEXCOORD_2 VERT_BIT_TEX2 +#define _NEW_ARRAY_TEXCOORD_3 VERT_BIT_TEX3 +#define _NEW_ARRAY_TEXCOORD_4 VERT_BIT_TEX4 +#define _NEW_ARRAY_TEXCOORD_5 VERT_BIT_TEX5 +#define _NEW_ARRAY_TEXCOORD_6 VERT_BIT_TEX6 +#define _NEW_ARRAY_TEXCOORD_7 VERT_BIT_TEX7 +#define _NEW_ARRAY_ATTRIB_0 VERT_BIT_GENERIC0 /* start at bit 16 */ +#define _NEW_ARRAY_ALL 0xffffffff + + +#define _NEW_ARRAY_TEXCOORD(i) (_NEW_ARRAY_TEXCOORD_0 << (i)) +#define _NEW_ARRAY_ATTRIB(i) (_NEW_ARRAY_ATTRIB_0 << (i)) +/*@}*/ + + + +/** + * \name A bunch of flags that we think might be useful to drivers. + * + * Set in the __struct gl_contextRec::_TriangleCaps bitfield. + */ +/*@{*/ +#define DD_FLATSHADE 0x1 +#define DD_SEPARATE_SPECULAR 0x2 +#define DD_TRI_CULL_FRONT_BACK 0x4 /* special case on some hw */ +#define DD_TRI_LIGHT_TWOSIDE 0x8 +#define DD_TRI_UNFILLED 0x10 +#define DD_TRI_SMOOTH 0x20 +#define DD_TRI_STIPPLE 0x40 +#define DD_TRI_OFFSET 0x80 +#define DD_LINE_SMOOTH 0x100 +#define DD_LINE_STIPPLE 0x200 +#define DD_POINT_SMOOTH 0x400 +#define DD_POINT_ATTEN 0x800 +#define DD_TRI_TWOSTENCIL 0x1000 +/*@}*/ + + +/** + * \name Define the state changes under which each of these bits might change + */ +/*@{*/ +#define _DD_NEW_FLATSHADE _NEW_LIGHT +#define _DD_NEW_SEPARATE_SPECULAR (_NEW_LIGHT | _NEW_FOG | _NEW_PROGRAM) +#define _DD_NEW_TRI_CULL_FRONT_BACK _NEW_POLYGON +#define _DD_NEW_TRI_LIGHT_TWOSIDE _NEW_LIGHT +#define _DD_NEW_TRI_UNFILLED _NEW_POLYGON +#define _DD_NEW_TRI_SMOOTH _NEW_POLYGON +#define _DD_NEW_TRI_STIPPLE _NEW_POLYGON +#define _DD_NEW_TRI_OFFSET _NEW_POLYGON +#define _DD_NEW_LINE_SMOOTH _NEW_LINE +#define _DD_NEW_LINE_STIPPLE _NEW_LINE +#define _DD_NEW_LINE_WIDTH _NEW_LINE +#define _DD_NEW_POINT_SMOOTH _NEW_POINT +#define _DD_NEW_POINT_SIZE _NEW_POINT +#define _DD_NEW_POINT_ATTEN _NEW_POINT +/*@}*/ + + +/** + * Composite state flags + */ +/*@{*/ +#define _MESA_NEW_NEED_EYE_COORDS (_NEW_LIGHT | \ + _NEW_TEXTURE | \ + _NEW_POINT | \ + _NEW_PROGRAM | \ + _NEW_MODELVIEW) + +#define _MESA_NEW_NEED_NORMALS (_NEW_LIGHT | \ + _NEW_TEXTURE) + +#define _MESA_NEW_TRANSFER_STATE (_NEW_PIXEL) +/*@}*/ + + + + +/* This has to be included here. */ +#include "dd.h" + + +/** + * Display list flags. + * Strictly this is a tnl-private concept, but it doesn't seem + * worthwhile adding a tnl private structure just to hold this one bit + * of information: + */ +#define DLIST_DANGLING_REFS 0x1 + + +/** Opaque declaration of display list payload data type */ +union gl_dlist_node; + + +/** + * Provide a location where information about a display list can be + * collected. Could be extended with driverPrivate structures, + * etc. in the future. + */ +struct gl_display_list +{ + GLuint Name; + GLbitfield Flags; /**< DLIST_x flags */ + /** The dlist commands are in a linked list of nodes */ + union gl_dlist_node *Head; +}; + + +/** + * State used during display list compilation and execution. + */ +struct gl_dlist_state +{ + GLuint CallDepth; /**< Current recursion calling depth */ + + struct gl_display_list *CurrentList; /**< List currently being compiled */ + union gl_dlist_node *CurrentBlock; /**< Pointer to current block of nodes */ + GLuint CurrentPos; /**< Index into current block of nodes */ + + GLvertexformat ListVtxfmt; + + GLubyte ActiveAttribSize[VERT_ATTRIB_MAX]; + GLfloat CurrentAttrib[VERT_ATTRIB_MAX][4]; + + GLubyte ActiveMaterialSize[MAT_ATTRIB_MAX]; + GLfloat CurrentMaterial[MAT_ATTRIB_MAX][4]; + + GLubyte ActiveIndex; + GLfloat CurrentIndex; + + GLubyte ActiveEdgeFlag; + GLboolean CurrentEdgeFlag; + + struct { + /* State known to have been set by the currently-compiling display + * list. Used to eliminate some redundant state changes. + */ + GLenum ShadeModel; + } Current; +}; + + +/** + * Enum for the OpenGL APIs we know about and may support. + */ +typedef enum +{ + API_OPENGL, + API_OPENGLES, + API_OPENGLES2 +} gl_api; + + +/** + * Mesa rendering context. + * + * This is the central context data structure for Mesa. Almost all + * OpenGL state is contained in this structure. + * Think of this as a base class from which device drivers will derive + * sub classes. + * + * The struct gl_context typedef names this structure. + */ +struct gl_context +{ + /** State possibly shared with other contexts in the address space */ + struct gl_shared_state *Shared; + + /** \name API function pointer tables */ + /*@{*/ + gl_api API; + struct _glapi_table *Save; /**< Display list save functions */ + struct _glapi_table *Exec; /**< Execute functions */ + struct _glapi_table *CurrentDispatch; /**< == Save or Exec !! */ + /*@}*/ + + struct gl_config Visual; + struct gl_framebuffer *DrawBuffer; /**< buffer for writing */ + struct gl_framebuffer *ReadBuffer; /**< buffer for reading */ + struct gl_framebuffer *WinSysDrawBuffer; /**< set with MakeCurrent */ + struct gl_framebuffer *WinSysReadBuffer; /**< set with MakeCurrent */ + + /** + * Device driver function pointer table + */ + struct dd_function_table Driver; + + void *DriverCtx; /**< Points to device driver context/state */ + + /** Core/Driver constants */ + struct gl_constants Const; + + /** \name The various 4x4 matrix stacks */ + /*@{*/ + struct gl_matrix_stack ModelviewMatrixStack; + struct gl_matrix_stack ProjectionMatrixStack; + struct gl_matrix_stack TextureMatrixStack[MAX_TEXTURE_UNITS]; + struct gl_matrix_stack ProgramMatrixStack[MAX_PROGRAM_MATRICES]; + struct gl_matrix_stack *CurrentStack; /**< Points to one of the above stacks */ + /*@}*/ + + /** Combined modelview and projection matrix */ + GLmatrix _ModelProjectMatrix; + + /** \name Display lists */ + struct gl_dlist_state ListState; + + GLboolean ExecuteFlag; /**< Execute GL commands? */ + GLboolean CompileFlag; /**< Compile GL commands into display list? */ + + /** Extension information */ + struct gl_extensions Extensions; + + /** Version info */ + GLuint VersionMajor, VersionMinor; + char *VersionString; + + /** \name State attribute stack (for glPush/PopAttrib) */ + /*@{*/ + GLuint AttribStackDepth; + struct gl_attrib_node *AttribStack[MAX_ATTRIB_STACK_DEPTH]; + /*@}*/ + + /** \name Renderer attribute groups + * + * We define a struct for each attribute group to make pushing and popping + * attributes easy. Also it's a good organization. + */ + /*@{*/ + struct gl_accum_attrib Accum; /**< Accum buffer attributes */ + struct gl_colorbuffer_attrib Color; /**< Color buffer attributes */ + struct gl_current_attrib Current; /**< Current attributes */ + struct gl_depthbuffer_attrib Depth; /**< Depth buffer attributes */ + struct gl_eval_attrib Eval; /**< Eval attributes */ + struct gl_fog_attrib Fog; /**< Fog attributes */ + struct gl_hint_attrib Hint; /**< Hint attributes */ + struct gl_light_attrib Light; /**< Light attributes */ + struct gl_line_attrib Line; /**< Line attributes */ + struct gl_list_attrib List; /**< List attributes */ + struct gl_multisample_attrib Multisample; + struct gl_pixel_attrib Pixel; /**< Pixel attributes */ + struct gl_point_attrib Point; /**< Point attributes */ + struct gl_polygon_attrib Polygon; /**< Polygon attributes */ + GLuint PolygonStipple[32]; /**< Polygon stipple */ + struct gl_scissor_attrib Scissor; /**< Scissor attributes */ + struct gl_stencil_attrib Stencil; /**< Stencil buffer attributes */ + struct gl_texture_attrib Texture; /**< Texture attributes */ + struct gl_transform_attrib Transform; /**< Transformation attributes */ + struct gl_viewport_attrib Viewport; /**< Viewport attributes */ + /*@}*/ + + /** \name Client attribute stack */ + /*@{*/ + GLuint ClientAttribStackDepth; + struct gl_attrib_node *ClientAttribStack[MAX_CLIENT_ATTRIB_STACK_DEPTH]; + /*@}*/ + + /** \name Client attribute groups */ + /*@{*/ + struct gl_array_attrib Array; /**< Vertex arrays */ + struct gl_pixelstore_attrib Pack; /**< Pixel packing */ + struct gl_pixelstore_attrib Unpack; /**< Pixel unpacking */ + struct gl_pixelstore_attrib DefaultPacking; /**< Default params */ + /*@}*/ + + /** \name Other assorted state (not pushed/popped on attribute stack) */ + /*@{*/ + struct gl_pixelmaps PixelMaps; + + struct gl_evaluators EvalMap; /**< All evaluators */ + struct gl_feedback Feedback; /**< Feedback */ + struct gl_selection Select; /**< Selection */ + + struct gl_program_state Program; /**< general program state */ + struct gl_vertex_program_state VertexProgram; + struct gl_fragment_program_state FragmentProgram; + struct gl_geometry_program_state GeometryProgram; + struct gl_ati_fragment_shader_state ATIFragmentShader; + + struct gl_shader_state Shader; /**< GLSL shader object state */ + struct gl_shader_compiler_options ShaderCompilerOptions[MESA_SHADER_TYPES]; + + struct gl_query_state Query; /**< occlusion, timer queries */ + + struct gl_transform_feedback TransformFeedback; + + struct gl_buffer_object *CopyReadBuffer; /**< GL_ARB_copy_buffer */ + struct gl_buffer_object *CopyWriteBuffer; /**< GL_ARB_copy_buffer */ + /*@}*/ + + struct gl_meta_state *Meta; /**< for "meta" operations */ + + /* GL_EXT_framebuffer_object */ + struct gl_renderbuffer *CurrentRenderbuffer; + + GLenum ErrorValue; /**< Last error code */ + + /** + * Recognize and silence repeated error debug messages in buggy apps. + */ + const char *ErrorDebugFmtString; + GLuint ErrorDebugCount; + + GLenum RenderMode; /**< either GL_RENDER, GL_SELECT, GL_FEEDBACK */ + GLbitfield NewState; /**< bitwise-or of _NEW_* flags */ + + GLboolean ViewportInitialized; /**< has viewport size been initialized? */ + + GLbitfield varying_vp_inputs; /**< mask of VERT_BIT_* flags */ + + /** \name Derived state */ + /*@{*/ + /** Bitwise-or of DD_* flags. Note that this bitfield may be used before + * state validation so they need to always be current. + */ + GLbitfield _TriangleCaps; + GLbitfield _ImageTransferState;/**< bitwise-or of IMAGE_*_BIT flags */ + GLfloat _EyeZDir[3]; + GLfloat _ModelViewInvScale; + GLboolean _NeedEyeCoords; + GLboolean _ForceEyeCoords; + + GLuint TextureStateTimestamp; /**< detect changes to shared state */ + + struct gl_shine_tab *_ShineTable[2]; /**< Active shine tables */ + struct gl_shine_tab *_ShineTabList; /**< MRU list of inactive shine tables */ + /**@}*/ + + struct gl_list_extensions *ListExt; /**< driver dlist extensions */ + + /** \name For debugging/development only */ + /*@{*/ + GLboolean FirstTimeCurrent; + /*@}*/ + + /** software compression/decompression supported or not */ + GLboolean Mesa_DXTn; + + GLboolean TextureFormatSupported[MESA_FORMAT_COUNT]; + + /** + * Use dp4 (rather than mul/mad) instructions for position + * transformation? + */ + GLboolean mvp_with_dp4; + + /** + * \name Hooks for module contexts. + * + * These will eventually live in the driver or elsewhere. + */ + /*@{*/ + void *swrast_context; + void *swsetup_context; + void *swtnl_context; + void *swtnl_im; + struct st_context *st; + void *aelt_context; + /*@}*/ +}; + + +#ifdef DEBUG +extern int MESA_VERBOSE; +extern int MESA_DEBUG_FLAGS; +# define MESA_FUNCTION __FUNCTION__ +#else +# define MESA_VERBOSE 0 +# define MESA_DEBUG_FLAGS 0 +# define MESA_FUNCTION "a function" +# ifndef NDEBUG +# define NDEBUG +# endif +#endif + + +/** The MESA_VERBOSE var is a bitmask of these flags */ +enum _verbose +{ + VERBOSE_VARRAY = 0x0001, + VERBOSE_TEXTURE = 0x0002, + VERBOSE_MATERIAL = 0x0004, + VERBOSE_PIPELINE = 0x0008, + VERBOSE_DRIVER = 0x0010, + VERBOSE_STATE = 0x0020, + VERBOSE_API = 0x0040, + VERBOSE_DISPLAY_LIST = 0x0100, + VERBOSE_LIGHTING = 0x0200, + VERBOSE_PRIMS = 0x0400, + VERBOSE_VERTS = 0x0800, + VERBOSE_DISASSEM = 0x1000, + VERBOSE_DRAW = 0x2000, + VERBOSE_SWAPBUFFERS = 0x4000 +}; + + +/** The MESA_DEBUG_FLAGS var is a bitmask of these flags */ +enum _debug +{ + DEBUG_ALWAYS_FLUSH = 0x1 +}; + + + +#endif /* MTYPES_H */ diff --git a/mesalib/src/mesa/main/pbo.c b/mesalib/src/mesa/main/pbo.c new file mode 100644 index 000000000..dc00d423b --- /dev/null +++ b/mesalib/src/mesa/main/pbo.c @@ -0,0 +1,372 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009-2011 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 + * THE AUTHORS 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 pbo.c + * \brief Functions related to Pixel Buffer Objects. + */ + + + +#include "glheader.h" +#include "bufferobj.h" +#include "image.h" +#include "imports.h" +#include "mtypes.h" +#include "pbo.h" + + + +/** + * When we're about to read pixel data out of a PBO (via glDrawPixels, + * glTexImage, etc) or write data into a PBO (via glReadPixels, + * glGetTexImage, etc) we call this function to check that we're not + * going to read out of bounds. + * + * XXX This would also be a convenient time to check that the PBO isn't + * currently mapped. Whoever calls this function should check for that. + * Remember, we can't use a PBO when it's mapped! + * + * If we're not using a PBO, this is a no-op. + * + * \param width width of image to read/write + * \param height height of image to read/write + * \param depth depth of image to read/write + * \param format format of image to read/write + * \param type datatype of image to read/write + * \param ptr the user-provided pointer/offset + * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would + * go out of bounds. + */ +GLboolean +_mesa_validate_pbo_access(GLuint dimensions, + const struct gl_pixelstore_attrib *pack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *ptr) +{ + GLvoid *start, *end; + const GLubyte *sizeAddr; /* buffer size, cast to a pointer */ + + if (!_mesa_is_bufferobj(pack->BufferObj)) + return GL_TRUE; /* no PBO, OK */ + + if (pack->BufferObj->Size == 0) + /* no buffer! */ + return GL_FALSE; + + /* get address of first pixel we'll read */ + start = _mesa_image_address(dimensions, pack, ptr, width, height, + format, type, 0, 0, 0); + + /* get address just past the last pixel we'll read */ + end = _mesa_image_address(dimensions, pack, ptr, width, height, + format, type, depth-1, height-1, width); + + + sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size; + + if ((const GLubyte *) start > sizeAddr) { + /* This will catch negative values / wrap-around */ + return GL_FALSE; + } + if ((const GLubyte *) end > sizeAddr) { + /* Image read goes beyond end of buffer */ + return GL_FALSE; + } + + /* OK! */ + return GL_TRUE; +} + + +/** + * For commands that read from a PBO (glDrawPixels, glTexImage, + * glPolygonStipple, etc), if we're reading from a PBO, map it read-only + * and return the pointer into the PBO. If we're not reading from a + * PBO, return \p src as-is. + * If non-null return, must call _mesa_unmap_pbo_source() when done. + * + * \return NULL if error, else pointer to start of data + */ +const GLvoid * +_mesa_map_pbo_source(struct gl_context *ctx, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *src) +{ + const GLubyte *buf; + + if (_mesa_is_bufferobj(unpack->BufferObj)) { + /* unpack from PBO */ + buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + GL_READ_ONLY_ARB, + unpack->BufferObj); + if (!buf) + return NULL; + + buf = ADD_POINTERS(buf, src); + } + else { + /* unpack from normal memory */ + buf = src; + } + + return buf; +} + + +/** + * Combine PBO-read validation and mapping. + * If any GL errors are detected, they'll be recorded and NULL returned. + * \sa _mesa_validate_pbo_access + * \sa _mesa_map_pbo_source + * A call to this function should have a matching call to + * _mesa_unmap_pbo_source(). + */ +const GLvoid * +_mesa_map_validate_pbo_source(struct gl_context *ctx, + GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *ptr, + const char *where) +{ + ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); + + if (!_mesa_is_bufferobj(unpack->BufferObj)) { + /* non-PBO access: no validation to be done */ + return ptr; + } + + if (!_mesa_validate_pbo_access(dimensions, unpack, + width, height, depth, format, type, ptr)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(out of bounds PBO access)", where); + return NULL; + } + + if (_mesa_bufferobj_mapped(unpack->BufferObj)) { + /* buffer is already mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); + return NULL; + } + + ptr = _mesa_map_pbo_source(ctx, unpack, ptr); + return ptr; +} + + +/** + * Counterpart to _mesa_map_pbo_source() + */ +void +_mesa_unmap_pbo_source(struct gl_context *ctx, + const struct gl_pixelstore_attrib *unpack) +{ + ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */ + if (_mesa_is_bufferobj(unpack->BufferObj)) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + unpack->BufferObj); + } +} + + +/** + * For commands that write to a PBO (glReadPixels, glGetColorTable, etc), + * if we're writing to a PBO, map it write-only and return the pointer + * into the PBO. If we're not writing to a PBO, return \p dst as-is. + * If non-null return, must call _mesa_unmap_pbo_dest() when done. + * + * \return NULL if error, else pointer to start of data + */ +void * +_mesa_map_pbo_dest(struct gl_context *ctx, + const struct gl_pixelstore_attrib *pack, + GLvoid *dest) +{ + void *buf; + + if (_mesa_is_bufferobj(pack->BufferObj)) { + /* pack into PBO */ + buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + GL_WRITE_ONLY_ARB, + pack->BufferObj); + if (!buf) + return NULL; + + buf = ADD_POINTERS(buf, dest); + } + else { + /* pack to normal memory */ + buf = dest; + } + + return buf; +} + + +/** + * Combine PBO-write validation and mapping. + * If any GL errors are detected, they'll be recorded and NULL returned. + * \sa _mesa_validate_pbo_access + * \sa _mesa_map_pbo_dest + * A call to this function should have a matching call to + * _mesa_unmap_pbo_dest(). + */ +GLvoid * +_mesa_map_validate_pbo_dest(struct gl_context *ctx, + GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, GLvoid *ptr, + const char *where) +{ + ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); + + if (!_mesa_is_bufferobj(unpack->BufferObj)) { + /* non-PBO access: no validation to be done */ + return ptr; + } + + if (!_mesa_validate_pbo_access(dimensions, unpack, + width, height, depth, format, type, ptr)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(out of bounds PBO access)", where); + return NULL; + } + + if (_mesa_bufferobj_mapped(unpack->BufferObj)) { + /* buffer is already mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); + return NULL; + } + + ptr = _mesa_map_pbo_dest(ctx, unpack, ptr); + return ptr; +} + + +/** + * Counterpart to _mesa_map_pbo_dest() + */ +void +_mesa_unmap_pbo_dest(struct gl_context *ctx, + const struct gl_pixelstore_attrib *pack) +{ + ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */ + if (_mesa_is_bufferobj(pack->BufferObj)) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj); + } +} + + + +/** + * Check if an unpack PBO is active prior to fetching a texture image. + * If so, do bounds checking and map the buffer into main memory. + * Any errors detected will be recorded. + * The caller _must_ call _mesa_unmap_teximage_pbo() too! + */ +const GLvoid * +_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *unpack, + const char *funcName) +{ + GLubyte *buf; + + if (!_mesa_is_bufferobj(unpack->BufferObj)) { + /* no PBO */ + return pixels; + } + if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, + format, type, pixels)) { + _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)"); + return NULL; + } + + buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + GL_READ_ONLY_ARB, unpack->BufferObj); + if (!buf) { + _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped)"); + return NULL; + } + + return ADD_POINTERS(buf, pixels); +} + + +/** + * Check if an unpack PBO is active prior to fetching a compressed texture + * image. + * If so, do bounds checking and map the buffer into main memory. + * Any errors detected will be recorded. + * The caller _must_ call _mesa_unmap_teximage_pbo() too! + */ +const GLvoid * +_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx, + GLsizei imageSize, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + const char *funcName) +{ + GLubyte *buf; + + if (!_mesa_is_bufferobj(packing->BufferObj)) { + /* not using a PBO - return pointer unchanged */ + return pixels; + } + if ((const GLubyte *) pixels + imageSize > + ((const GLubyte *) 0) + packing->BufferObj->Size) { + /* out of bounds read! */ + _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)"); + return NULL; + } + + buf = (GLubyte*) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + GL_READ_ONLY_ARB, packing->BufferObj); + if (!buf) { + _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped"); + return NULL; + } + + return ADD_POINTERS(buf, pixels); +} + + +/** + * This function must be called after either of the validate_pbo_*_teximage() + * functions. It unmaps the PBO buffer if it was mapped earlier. + */ +void +_mesa_unmap_teximage_pbo(struct gl_context *ctx, + const struct gl_pixelstore_attrib *unpack) +{ + if (_mesa_is_bufferobj(unpack->BufferObj)) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + unpack->BufferObj); + } +} + + diff --git a/mesalib/src/mesa/main/pbo.h b/mesalib/src/mesa/main/pbo.h new file mode 100644 index 000000000..0cddd72ba --- /dev/null +++ b/mesalib/src/mesa/main/pbo.h @@ -0,0 +1,92 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009-2011 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 + * THE AUTHORS 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 PBO_H +#define PBO_H + + +#include "mtypes.h" + + +extern GLboolean +_mesa_validate_pbo_access(GLuint dimensions, + const struct gl_pixelstore_attrib *pack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *ptr); + +extern const GLvoid * +_mesa_map_pbo_source(struct gl_context *ctx, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *src); + +extern const GLvoid * +_mesa_map_validate_pbo_source(struct gl_context *ctx, + GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *ptr, + const char *where); + +extern void +_mesa_unmap_pbo_source(struct gl_context *ctx, + const struct gl_pixelstore_attrib *unpack); + +extern void * +_mesa_map_pbo_dest(struct gl_context *ctx, + const struct gl_pixelstore_attrib *pack, + GLvoid *dest); + +extern GLvoid * +_mesa_map_validate_pbo_dest(struct gl_context *ctx, + GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, GLvoid *ptr, + const char *where); + +extern void +_mesa_unmap_pbo_dest(struct gl_context *ctx, + const struct gl_pixelstore_attrib *pack); + + +extern const GLvoid * +_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *unpack, + const char *funcName); + +extern const GLvoid * +_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx, + GLsizei imageSize, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + const char *funcName); + +extern void +_mesa_unmap_teximage_pbo(struct gl_context *ctx, + const struct gl_pixelstore_attrib *unpack); + + +#endif diff --git a/mesalib/src/mesa/main/pixel.c b/mesalib/src/mesa/main/pixel.c index 2b4934fd3..195fa234b 100644 --- a/mesalib/src/mesa/main/pixel.c +++ b/mesalib/src/mesa/main/pixel.c @@ -1,701 +1,699 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * 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 pixel.c - * Pixel transfer functions (glPixelZoom, glPixelMap, glPixelTransfer) - */ - -#include "glheader.h" -#include "bufferobj.h" -#include "colormac.h" -#include "context.h" -#include "macros.h" -#include "mfeatures.h" -#include "pixel.h" -#include "mtypes.h" -#include "main/dispatch.h" - - -#if FEATURE_pixel_transfer - - -/**********************************************************************/ -/***** glPixelZoom *****/ -/**********************************************************************/ - -static void GLAPIENTRY -_mesa_PixelZoom( GLfloat xfactor, GLfloat yfactor ) -{ - GET_CURRENT_CONTEXT(ctx); - - if (ctx->Pixel.ZoomX == xfactor && - ctx->Pixel.ZoomY == yfactor) - return; - - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.ZoomX = xfactor; - ctx->Pixel.ZoomY = yfactor; -} - - - -/**********************************************************************/ -/***** glPixelMap *****/ -/**********************************************************************/ - -/** - * Return pointer to a pixelmap by name. - */ -static struct gl_pixelmap * -get_pixelmap(struct gl_context *ctx, GLenum map) -{ - switch (map) { - case GL_PIXEL_MAP_I_TO_I: - return &ctx->PixelMaps.ItoI; - case GL_PIXEL_MAP_S_TO_S: - return &ctx->PixelMaps.StoS; - case GL_PIXEL_MAP_I_TO_R: - return &ctx->PixelMaps.ItoR; - case GL_PIXEL_MAP_I_TO_G: - return &ctx->PixelMaps.ItoG; - case GL_PIXEL_MAP_I_TO_B: - return &ctx->PixelMaps.ItoB; - case GL_PIXEL_MAP_I_TO_A: - return &ctx->PixelMaps.ItoA; - case GL_PIXEL_MAP_R_TO_R: - return &ctx->PixelMaps.RtoR; - case GL_PIXEL_MAP_G_TO_G: - return &ctx->PixelMaps.GtoG; - case GL_PIXEL_MAP_B_TO_B: - return &ctx->PixelMaps.BtoB; - case GL_PIXEL_MAP_A_TO_A: - return &ctx->PixelMaps.AtoA; - default: - return NULL; - } -} - - -/** - * Helper routine used by the other _mesa_PixelMap() functions. - */ -static void -store_pixelmap(struct gl_context *ctx, GLenum map, GLsizei mapsize, - const GLfloat *values) -{ - GLint i; - struct gl_pixelmap *pm = get_pixelmap(ctx, map); - if (!pm) { - _mesa_error(ctx, GL_INVALID_ENUM, "glPixelMap(map)"); - return; - } - - switch (map) { - case GL_PIXEL_MAP_S_TO_S: - /* special case */ - ctx->PixelMaps.StoS.Size = mapsize; - for (i = 0; i < mapsize; i++) { - ctx->PixelMaps.StoS.Map[i] = (GLfloat)IROUND(values[i]); - } - break; - case GL_PIXEL_MAP_I_TO_I: - /* special case */ - ctx->PixelMaps.ItoI.Size = mapsize; - for (i = 0; i < mapsize; i++) { - ctx->PixelMaps.ItoI.Map[i] = values[i]; - } - break; - default: - /* general case */ - pm->Size = mapsize; - for (i = 0; i < mapsize; i++) { - GLfloat val = CLAMP(values[i], 0.0F, 1.0F); - pm->Map[i] = val; - pm->Map8[i] = (GLint) (val * 255.0F); - } - } -} - - -/** - * Convenience wrapper for _mesa_validate_pbo_access() for gl[Get]PixelMap(). - */ -static GLboolean -validate_pbo_access(struct gl_context *ctx, struct gl_pixelstore_attrib *pack, - GLsizei mapsize, GLenum format, GLenum type, - const GLvoid *ptr) -{ - GLboolean ok; - - /* Note, need to use DefaultPacking and Unpack's buffer object */ - _mesa_reference_buffer_object(ctx, - &ctx->DefaultPacking.BufferObj, - pack->BufferObj); - - ok = _mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1, - format, type, ptr); - - /* restore */ - _mesa_reference_buffer_object(ctx, - &ctx->DefaultPacking.BufferObj, - ctx->Shared->NullBufferObj); - - if (!ok) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glPixelMap(invalid PBO access)"); - } - return ok; -} - - -static void GLAPIENTRY -_mesa_PixelMapfv( GLenum map, GLsizei mapsize, const GLfloat *values ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - /* XXX someday, test against ctx->Const.MaxPixelMapTableSize */ - if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) { - _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" ); - return; - } - - if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) { - /* test that mapsize is a power of two */ - if (!_mesa_is_pow_two(mapsize)) { - _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" ); - return; - } - } - - FLUSH_VERTICES(ctx, _NEW_PIXEL); - - if (!validate_pbo_access(ctx, &ctx->Unpack, mapsize, - GL_INTENSITY, GL_FLOAT, values)) { - return; - } - - values = (const GLfloat *) _mesa_map_pbo_source(ctx, &ctx->Unpack, values); - if (!values) { - if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glPixelMapfv(PBO is mapped)"); - } - return; - } - - store_pixelmap(ctx, map, mapsize, values); - - _mesa_unmap_pbo_source(ctx, &ctx->Unpack); -} - - -static void GLAPIENTRY -_mesa_PixelMapuiv(GLenum map, GLsizei mapsize, const GLuint *values ) -{ - GLfloat fvalues[MAX_PIXEL_MAP_TABLE]; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) { - _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" ); - return; - } - - if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) { - /* test that mapsize is a power of two */ - if (!_mesa_is_pow_two(mapsize)) { - _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" ); - return; - } - } - - FLUSH_VERTICES(ctx, _NEW_PIXEL); - - if (!validate_pbo_access(ctx, &ctx->Unpack, mapsize, - GL_INTENSITY, GL_UNSIGNED_INT, values)) { - return; - } - - values = (const GLuint *) _mesa_map_pbo_source(ctx, &ctx->Unpack, values); - if (!values) { - if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glPixelMapuiv(PBO is mapped)"); - } - return; - } - - /* convert to floats */ - if (map == GL_PIXEL_MAP_I_TO_I || map == GL_PIXEL_MAP_S_TO_S) { - GLint i; - for (i = 0; i < mapsize; i++) { - fvalues[i] = (GLfloat) values[i]; - } - } - else { - GLint i; - for (i = 0; i < mapsize; i++) { - fvalues[i] = UINT_TO_FLOAT( values[i] ); - } - } - - _mesa_unmap_pbo_source(ctx, &ctx->Unpack); - - store_pixelmap(ctx, map, mapsize, fvalues); -} - - -static void GLAPIENTRY -_mesa_PixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values ) -{ - GLfloat fvalues[MAX_PIXEL_MAP_TABLE]; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) { - _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapusv(mapsize)" ); - return; - } - - if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) { - /* test that mapsize is a power of two */ - if (!_mesa_is_pow_two(mapsize)) { - _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" ); - return; - } - } - - FLUSH_VERTICES(ctx, _NEW_PIXEL); - - if (!validate_pbo_access(ctx, &ctx->Unpack, mapsize, - GL_INTENSITY, GL_UNSIGNED_SHORT, values)) { - return; - } - - values = (const GLushort *) _mesa_map_pbo_source(ctx, &ctx->Unpack, values); - if (!values) { - if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glPixelMapusv(PBO is mapped)"); - } - return; - } - - /* convert to floats */ - if (map == GL_PIXEL_MAP_I_TO_I || map == GL_PIXEL_MAP_S_TO_S) { - GLint i; - for (i = 0; i < mapsize; i++) { - fvalues[i] = (GLfloat) values[i]; - } - } - else { - GLint i; - for (i = 0; i < mapsize; i++) { - fvalues[i] = USHORT_TO_FLOAT( values[i] ); - } - } - - _mesa_unmap_pbo_source(ctx, &ctx->Unpack); - - store_pixelmap(ctx, map, mapsize, fvalues); -} - - -static void GLAPIENTRY -_mesa_GetPixelMapfv( GLenum map, GLfloat *values ) -{ - GET_CURRENT_CONTEXT(ctx); - GLuint mapsize, i; - const struct gl_pixelmap *pm; - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - pm = get_pixelmap(ctx, map); - if (!pm) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapfv(map)"); - return; - } - - mapsize = pm->Size; - - if (!validate_pbo_access(ctx, &ctx->Pack, mapsize, - GL_INTENSITY, GL_FLOAT, values)) { - return; - } - - values = (GLfloat *) _mesa_map_pbo_dest(ctx, &ctx->Pack, values); - if (!values) { - if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetPixelMapfv(PBO is mapped)"); - } - return; - } - - if (map == GL_PIXEL_MAP_S_TO_S) { - /* special case */ - for (i = 0; i < mapsize; i++) { - values[i] = (GLfloat) ctx->PixelMaps.StoS.Map[i]; - } - } - else { - memcpy(values, pm->Map, mapsize * sizeof(GLfloat)); - } - - _mesa_unmap_pbo_dest(ctx, &ctx->Pack); -} - - -static void GLAPIENTRY -_mesa_GetPixelMapuiv( GLenum map, GLuint *values ) -{ - GET_CURRENT_CONTEXT(ctx); - GLint mapsize, i; - const struct gl_pixelmap *pm; - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - pm = get_pixelmap(ctx, map); - if (!pm) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapuiv(map)"); - return; - } - mapsize = pm->Size; - - if (!validate_pbo_access(ctx, &ctx->Pack, mapsize, - GL_INTENSITY, GL_UNSIGNED_INT, values)) { - return; - } - - values = (GLuint *) _mesa_map_pbo_dest(ctx, &ctx->Pack, values); - if (!values) { - if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetPixelMapuiv(PBO is mapped)"); - } - return; - } - - if (map == GL_PIXEL_MAP_S_TO_S) { - /* special case */ - memcpy(values, ctx->PixelMaps.StoS.Map, mapsize * sizeof(GLint)); - } - else { - for (i = 0; i < mapsize; i++) { - values[i] = FLOAT_TO_UINT( pm->Map[i] ); - } - } - - _mesa_unmap_pbo_dest(ctx, &ctx->Pack); -} - - -static void GLAPIENTRY -_mesa_GetPixelMapusv( GLenum map, GLushort *values ) -{ - GET_CURRENT_CONTEXT(ctx); - GLint mapsize, i; - const struct gl_pixelmap *pm; - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - pm = get_pixelmap(ctx, map); - if (!pm) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapusv(map)"); - return; - } - mapsize = pm->Size; - - if (!validate_pbo_access(ctx, &ctx->Pack, mapsize, - GL_INTENSITY, GL_UNSIGNED_SHORT, values)) { - return; - } - - values = (GLushort *) _mesa_map_pbo_dest(ctx, &ctx->Pack, values); - if (!values) { - if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetPixelMapusv(PBO is mapped)"); - } - return; - } - - switch (map) { - /* special cases */ - case GL_PIXEL_MAP_I_TO_I: - for (i = 0; i < mapsize; i++) { - values[i] = (GLushort) CLAMP(ctx->PixelMaps.ItoI.Map[i], 0.0, 65535.); - } - break; - case GL_PIXEL_MAP_S_TO_S: - for (i = 0; i < mapsize; i++) { - values[i] = (GLushort) CLAMP(ctx->PixelMaps.StoS.Map[i], 0.0, 65535.); - } - break; - default: - for (i = 0; i < mapsize; i++) { - CLAMPED_FLOAT_TO_USHORT(values[i], pm->Map[i] ); - } - } - - _mesa_unmap_pbo_dest(ctx, &ctx->Pack); -} - - - -/**********************************************************************/ -/***** glPixelTransfer *****/ -/**********************************************************************/ - - -/* - * Implements glPixelTransfer[fi] whether called immediately or from a - * display list. - */ -static void GLAPIENTRY -_mesa_PixelTransferf( GLenum pname, GLfloat param ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - switch (pname) { - case GL_MAP_COLOR: - if (ctx->Pixel.MapColorFlag == (param ? GL_TRUE : GL_FALSE)) - return; - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.MapColorFlag = param ? GL_TRUE : GL_FALSE; - break; - case GL_MAP_STENCIL: - if (ctx->Pixel.MapStencilFlag == (param ? GL_TRUE : GL_FALSE)) - return; - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.MapStencilFlag = param ? GL_TRUE : GL_FALSE; - break; - case GL_INDEX_SHIFT: - if (ctx->Pixel.IndexShift == (GLint) param) - return; - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.IndexShift = (GLint) param; - break; - case GL_INDEX_OFFSET: - if (ctx->Pixel.IndexOffset == (GLint) param) - return; - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.IndexOffset = (GLint) param; - break; - case GL_RED_SCALE: - if (ctx->Pixel.RedScale == param) - return; - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.RedScale = param; - break; - case GL_RED_BIAS: - if (ctx->Pixel.RedBias == param) - return; - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.RedBias = param; - break; - case GL_GREEN_SCALE: - if (ctx->Pixel.GreenScale == param) - return; - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.GreenScale = param; - break; - case GL_GREEN_BIAS: - if (ctx->Pixel.GreenBias == param) - return; - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.GreenBias = param; - break; - case GL_BLUE_SCALE: - if (ctx->Pixel.BlueScale == param) - return; - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.BlueScale = param; - break; - case GL_BLUE_BIAS: - if (ctx->Pixel.BlueBias == param) - return; - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.BlueBias = param; - break; - case GL_ALPHA_SCALE: - if (ctx->Pixel.AlphaScale == param) - return; - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.AlphaScale = param; - break; - case GL_ALPHA_BIAS: - if (ctx->Pixel.AlphaBias == param) - return; - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.AlphaBias = param; - break; - case GL_DEPTH_SCALE: - if (ctx->Pixel.DepthScale == param) - return; - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.DepthScale = param; - break; - case GL_DEPTH_BIAS: - if (ctx->Pixel.DepthBias == param) - return; - FLUSH_VERTICES(ctx, _NEW_PIXEL); - ctx->Pixel.DepthBias = param; - break; - default: - _mesa_error( ctx, GL_INVALID_ENUM, "glPixelTransfer(pname)" ); - return; - } -} - - -static void GLAPIENTRY -_mesa_PixelTransferi( GLenum pname, GLint param ) -{ - _mesa_PixelTransferf( pname, (GLfloat) param ); -} - - - -/**********************************************************************/ -/***** State Management *****/ -/**********************************************************************/ - -/* - * Return a bitmask of IMAGE_*_BIT flags which to indicate which - * pixel transfer operations are enabled. - */ -static void -update_image_transfer_state(struct gl_context *ctx) -{ - GLuint mask = 0; - - if (ctx->Pixel.RedScale != 1.0F || ctx->Pixel.RedBias != 0.0F || - ctx->Pixel.GreenScale != 1.0F || ctx->Pixel.GreenBias != 0.0F || - ctx->Pixel.BlueScale != 1.0F || ctx->Pixel.BlueBias != 0.0F || - ctx->Pixel.AlphaScale != 1.0F || ctx->Pixel.AlphaBias != 0.0F) - mask |= IMAGE_SCALE_BIAS_BIT; - - if (ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset) - mask |= IMAGE_SHIFT_OFFSET_BIT; - - if (ctx->Pixel.MapColorFlag) - mask |= IMAGE_MAP_COLOR_BIT; - - ctx->_ImageTransferState = mask; -} - - -/** - * Update mesa pixel transfer derived state. - */ -void _mesa_update_pixel( struct gl_context *ctx, GLuint new_state ) -{ - if (new_state & _MESA_NEW_TRANSFER_STATE) - update_image_transfer_state(ctx); -} - - -void -_mesa_init_pixel_dispatch(struct _glapi_table *disp) -{ - SET_GetPixelMapfv(disp, _mesa_GetPixelMapfv); - SET_GetPixelMapuiv(disp, _mesa_GetPixelMapuiv); - SET_GetPixelMapusv(disp, _mesa_GetPixelMapusv); - SET_PixelMapfv(disp, _mesa_PixelMapfv); - SET_PixelMapuiv(disp, _mesa_PixelMapuiv); - SET_PixelMapusv(disp, _mesa_PixelMapusv); - SET_PixelTransferf(disp, _mesa_PixelTransferf); - SET_PixelTransferi(disp, _mesa_PixelTransferi); - SET_PixelZoom(disp, _mesa_PixelZoom); -} - - -#endif /* FEATURE_pixel_transfer */ - - -/**********************************************************************/ -/***** Initialization *****/ -/**********************************************************************/ - -static void -init_pixelmap(struct gl_pixelmap *map) -{ - map->Size = 1; - map->Map[0] = 0.0; - map->Map8[0] = 0; -} - - -/** - * Initialize the context's PIXEL attribute group. - */ -void -_mesa_init_pixel( struct gl_context *ctx ) -{ - /* Pixel group */ - ctx->Pixel.RedBias = 0.0; - ctx->Pixel.RedScale = 1.0; - ctx->Pixel.GreenBias = 0.0; - ctx->Pixel.GreenScale = 1.0; - ctx->Pixel.BlueBias = 0.0; - ctx->Pixel.BlueScale = 1.0; - ctx->Pixel.AlphaBias = 0.0; - ctx->Pixel.AlphaScale = 1.0; - ctx->Pixel.DepthBias = 0.0; - ctx->Pixel.DepthScale = 1.0; - ctx->Pixel.IndexOffset = 0; - ctx->Pixel.IndexShift = 0; - ctx->Pixel.ZoomX = 1.0; - ctx->Pixel.ZoomY = 1.0; - ctx->Pixel.MapColorFlag = GL_FALSE; - ctx->Pixel.MapStencilFlag = GL_FALSE; - init_pixelmap(&ctx->PixelMaps.StoS); - init_pixelmap(&ctx->PixelMaps.ItoI); - init_pixelmap(&ctx->PixelMaps.ItoR); - init_pixelmap(&ctx->PixelMaps.ItoG); - init_pixelmap(&ctx->PixelMaps.ItoB); - init_pixelmap(&ctx->PixelMaps.ItoA); - init_pixelmap(&ctx->PixelMaps.RtoR); - init_pixelmap(&ctx->PixelMaps.GtoG); - init_pixelmap(&ctx->PixelMaps.BtoB); - init_pixelmap(&ctx->PixelMaps.AtoA); - /* GL_SGI_texture_color_table */ - ASSIGN_4V(ctx->Pixel.TextureColorTableScale, 1.0, 1.0, 1.0, 1.0); - ASSIGN_4V(ctx->Pixel.TextureColorTableBias, 0.0, 0.0, 0.0, 0.0); - - if (ctx->Visual.doubleBufferMode) { - ctx->Pixel.ReadBuffer = GL_BACK; - } - else { - ctx->Pixel.ReadBuffer = GL_FRONT; - } - - /* Miscellaneous */ - ctx->_ImageTransferState = 0; -} +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * 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 pixel.c + * Pixel transfer functions (glPixelZoom, glPixelMap, glPixelTransfer) + */ + +#include "glheader.h" +#include "bufferobj.h" +#include "colormac.h" +#include "context.h" +#include "macros.h" +#include "mfeatures.h" +#include "pixel.h" +#include "pbo.h" +#include "mtypes.h" +#include "main/dispatch.h" + + +#if FEATURE_pixel_transfer + + +/**********************************************************************/ +/***** glPixelZoom *****/ +/**********************************************************************/ + +static void GLAPIENTRY +_mesa_PixelZoom( GLfloat xfactor, GLfloat yfactor ) +{ + GET_CURRENT_CONTEXT(ctx); + + if (ctx->Pixel.ZoomX == xfactor && + ctx->Pixel.ZoomY == yfactor) + return; + + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.ZoomX = xfactor; + ctx->Pixel.ZoomY = yfactor; +} + + + +/**********************************************************************/ +/***** glPixelMap *****/ +/**********************************************************************/ + +/** + * Return pointer to a pixelmap by name. + */ +static struct gl_pixelmap * +get_pixelmap(struct gl_context *ctx, GLenum map) +{ + switch (map) { + case GL_PIXEL_MAP_I_TO_I: + return &ctx->PixelMaps.ItoI; + case GL_PIXEL_MAP_S_TO_S: + return &ctx->PixelMaps.StoS; + case GL_PIXEL_MAP_I_TO_R: + return &ctx->PixelMaps.ItoR; + case GL_PIXEL_MAP_I_TO_G: + return &ctx->PixelMaps.ItoG; + case GL_PIXEL_MAP_I_TO_B: + return &ctx->PixelMaps.ItoB; + case GL_PIXEL_MAP_I_TO_A: + return &ctx->PixelMaps.ItoA; + case GL_PIXEL_MAP_R_TO_R: + return &ctx->PixelMaps.RtoR; + case GL_PIXEL_MAP_G_TO_G: + return &ctx->PixelMaps.GtoG; + case GL_PIXEL_MAP_B_TO_B: + return &ctx->PixelMaps.BtoB; + case GL_PIXEL_MAP_A_TO_A: + return &ctx->PixelMaps.AtoA; + default: + return NULL; + } +} + + +/** + * Helper routine used by the other _mesa_PixelMap() functions. + */ +static void +store_pixelmap(struct gl_context *ctx, GLenum map, GLsizei mapsize, + const GLfloat *values) +{ + GLint i; + struct gl_pixelmap *pm = get_pixelmap(ctx, map); + if (!pm) { + _mesa_error(ctx, GL_INVALID_ENUM, "glPixelMap(map)"); + return; + } + + switch (map) { + case GL_PIXEL_MAP_S_TO_S: + /* special case */ + ctx->PixelMaps.StoS.Size = mapsize; + for (i = 0; i < mapsize; i++) { + ctx->PixelMaps.StoS.Map[i] = (GLfloat)IROUND(values[i]); + } + break; + case GL_PIXEL_MAP_I_TO_I: + /* special case */ + ctx->PixelMaps.ItoI.Size = mapsize; + for (i = 0; i < mapsize; i++) { + ctx->PixelMaps.ItoI.Map[i] = values[i]; + } + break; + default: + /* general case */ + pm->Size = mapsize; + for (i = 0; i < mapsize; i++) { + GLfloat val = CLAMP(values[i], 0.0F, 1.0F); + pm->Map[i] = val; + pm->Map8[i] = (GLint) (val * 255.0F); + } + } +} + + +/** + * Convenience wrapper for _mesa_validate_pbo_access() for gl[Get]PixelMap(). + */ +static GLboolean +validate_pbo_access(struct gl_context *ctx, struct gl_pixelstore_attrib *pack, + GLsizei mapsize, GLenum format, GLenum type, + const GLvoid *ptr) +{ + GLboolean ok; + + /* Note, need to use DefaultPacking and Unpack's buffer object */ + _mesa_reference_buffer_object(ctx, + &ctx->DefaultPacking.BufferObj, + pack->BufferObj); + + ok = _mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1, + format, type, ptr); + + /* restore */ + _mesa_reference_buffer_object(ctx, + &ctx->DefaultPacking.BufferObj, + ctx->Shared->NullBufferObj); + + if (!ok) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glPixelMap(invalid PBO access)"); + } + return ok; +} + + +static void GLAPIENTRY +_mesa_PixelMapfv( GLenum map, GLsizei mapsize, const GLfloat *values ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* XXX someday, test against ctx->Const.MaxPixelMapTableSize */ + if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) { + _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" ); + return; + } + + if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) { + /* test that mapsize is a power of two */ + if (!_mesa_is_pow_two(mapsize)) { + _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" ); + return; + } + } + + FLUSH_VERTICES(ctx, _NEW_PIXEL); + + if (!validate_pbo_access(ctx, &ctx->Unpack, mapsize, + GL_INTENSITY, GL_FLOAT, values)) { + return; + } + + values = (const GLfloat *) _mesa_map_pbo_source(ctx, &ctx->Unpack, values); + if (!values) { + if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glPixelMapfv(PBO is mapped)"); + } + return; + } + + store_pixelmap(ctx, map, mapsize, values); + + _mesa_unmap_pbo_source(ctx, &ctx->Unpack); +} + + +static void GLAPIENTRY +_mesa_PixelMapuiv(GLenum map, GLsizei mapsize, const GLuint *values ) +{ + GLfloat fvalues[MAX_PIXEL_MAP_TABLE]; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) { + _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" ); + return; + } + + if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) { + /* test that mapsize is a power of two */ + if (!_mesa_is_pow_two(mapsize)) { + _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" ); + return; + } + } + + FLUSH_VERTICES(ctx, _NEW_PIXEL); + + if (!validate_pbo_access(ctx, &ctx->Unpack, mapsize, + GL_INTENSITY, GL_UNSIGNED_INT, values)) { + return; + } + + values = (const GLuint *) _mesa_map_pbo_source(ctx, &ctx->Unpack, values); + if (!values) { + if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glPixelMapuiv(PBO is mapped)"); + } + return; + } + + /* convert to floats */ + if (map == GL_PIXEL_MAP_I_TO_I || map == GL_PIXEL_MAP_S_TO_S) { + GLint i; + for (i = 0; i < mapsize; i++) { + fvalues[i] = (GLfloat) values[i]; + } + } + else { + GLint i; + for (i = 0; i < mapsize; i++) { + fvalues[i] = UINT_TO_FLOAT( values[i] ); + } + } + + _mesa_unmap_pbo_source(ctx, &ctx->Unpack); + + store_pixelmap(ctx, map, mapsize, fvalues); +} + + +static void GLAPIENTRY +_mesa_PixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values ) +{ + GLfloat fvalues[MAX_PIXEL_MAP_TABLE]; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) { + _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapusv(mapsize)" ); + return; + } + + if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) { + /* test that mapsize is a power of two */ + if (!_mesa_is_pow_two(mapsize)) { + _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" ); + return; + } + } + + FLUSH_VERTICES(ctx, _NEW_PIXEL); + + if (!validate_pbo_access(ctx, &ctx->Unpack, mapsize, + GL_INTENSITY, GL_UNSIGNED_SHORT, values)) { + return; + } + + values = (const GLushort *) _mesa_map_pbo_source(ctx, &ctx->Unpack, values); + if (!values) { + if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glPixelMapusv(PBO is mapped)"); + } + return; + } + + /* convert to floats */ + if (map == GL_PIXEL_MAP_I_TO_I || map == GL_PIXEL_MAP_S_TO_S) { + GLint i; + for (i = 0; i < mapsize; i++) { + fvalues[i] = (GLfloat) values[i]; + } + } + else { + GLint i; + for (i = 0; i < mapsize; i++) { + fvalues[i] = USHORT_TO_FLOAT( values[i] ); + } + } + + _mesa_unmap_pbo_source(ctx, &ctx->Unpack); + + store_pixelmap(ctx, map, mapsize, fvalues); +} + + +static void GLAPIENTRY +_mesa_GetPixelMapfv( GLenum map, GLfloat *values ) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint mapsize, i; + const struct gl_pixelmap *pm; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + pm = get_pixelmap(ctx, map); + if (!pm) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapfv(map)"); + return; + } + + mapsize = pm->Size; + + if (!validate_pbo_access(ctx, &ctx->Pack, mapsize, + GL_INTENSITY, GL_FLOAT, values)) { + return; + } + + values = (GLfloat *) _mesa_map_pbo_dest(ctx, &ctx->Pack, values); + if (!values) { + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetPixelMapfv(PBO is mapped)"); + } + return; + } + + if (map == GL_PIXEL_MAP_S_TO_S) { + /* special case */ + for (i = 0; i < mapsize; i++) { + values[i] = (GLfloat) ctx->PixelMaps.StoS.Map[i]; + } + } + else { + memcpy(values, pm->Map, mapsize * sizeof(GLfloat)); + } + + _mesa_unmap_pbo_dest(ctx, &ctx->Pack); +} + + +static void GLAPIENTRY +_mesa_GetPixelMapuiv( GLenum map, GLuint *values ) +{ + GET_CURRENT_CONTEXT(ctx); + GLint mapsize, i; + const struct gl_pixelmap *pm; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + pm = get_pixelmap(ctx, map); + if (!pm) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapuiv(map)"); + return; + } + mapsize = pm->Size; + + if (!validate_pbo_access(ctx, &ctx->Pack, mapsize, + GL_INTENSITY, GL_UNSIGNED_INT, values)) { + return; + } + + values = (GLuint *) _mesa_map_pbo_dest(ctx, &ctx->Pack, values); + if (!values) { + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetPixelMapuiv(PBO is mapped)"); + } + return; + } + + if (map == GL_PIXEL_MAP_S_TO_S) { + /* special case */ + memcpy(values, ctx->PixelMaps.StoS.Map, mapsize * sizeof(GLint)); + } + else { + for (i = 0; i < mapsize; i++) { + values[i] = FLOAT_TO_UINT( pm->Map[i] ); + } + } + + _mesa_unmap_pbo_dest(ctx, &ctx->Pack); +} + + +static void GLAPIENTRY +_mesa_GetPixelMapusv( GLenum map, GLushort *values ) +{ + GET_CURRENT_CONTEXT(ctx); + GLint mapsize, i; + const struct gl_pixelmap *pm; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + pm = get_pixelmap(ctx, map); + if (!pm) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapusv(map)"); + return; + } + mapsize = pm->Size; + + if (!validate_pbo_access(ctx, &ctx->Pack, mapsize, + GL_INTENSITY, GL_UNSIGNED_SHORT, values)) { + return; + } + + values = (GLushort *) _mesa_map_pbo_dest(ctx, &ctx->Pack, values); + if (!values) { + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetPixelMapusv(PBO is mapped)"); + } + return; + } + + switch (map) { + /* special cases */ + case GL_PIXEL_MAP_I_TO_I: + for (i = 0; i < mapsize; i++) { + values[i] = (GLushort) CLAMP(ctx->PixelMaps.ItoI.Map[i], 0.0, 65535.); + } + break; + case GL_PIXEL_MAP_S_TO_S: + for (i = 0; i < mapsize; i++) { + values[i] = (GLushort) CLAMP(ctx->PixelMaps.StoS.Map[i], 0.0, 65535.); + } + break; + default: + for (i = 0; i < mapsize; i++) { + CLAMPED_FLOAT_TO_USHORT(values[i], pm->Map[i] ); + } + } + + _mesa_unmap_pbo_dest(ctx, &ctx->Pack); +} + + + +/**********************************************************************/ +/***** glPixelTransfer *****/ +/**********************************************************************/ + + +/* + * Implements glPixelTransfer[fi] whether called immediately or from a + * display list. + */ +static void GLAPIENTRY +_mesa_PixelTransferf( GLenum pname, GLfloat param ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + switch (pname) { + case GL_MAP_COLOR: + if (ctx->Pixel.MapColorFlag == (param ? GL_TRUE : GL_FALSE)) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.MapColorFlag = param ? GL_TRUE : GL_FALSE; + break; + case GL_MAP_STENCIL: + if (ctx->Pixel.MapStencilFlag == (param ? GL_TRUE : GL_FALSE)) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.MapStencilFlag = param ? GL_TRUE : GL_FALSE; + break; + case GL_INDEX_SHIFT: + if (ctx->Pixel.IndexShift == (GLint) param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.IndexShift = (GLint) param; + break; + case GL_INDEX_OFFSET: + if (ctx->Pixel.IndexOffset == (GLint) param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.IndexOffset = (GLint) param; + break; + case GL_RED_SCALE: + if (ctx->Pixel.RedScale == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.RedScale = param; + break; + case GL_RED_BIAS: + if (ctx->Pixel.RedBias == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.RedBias = param; + break; + case GL_GREEN_SCALE: + if (ctx->Pixel.GreenScale == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.GreenScale = param; + break; + case GL_GREEN_BIAS: + if (ctx->Pixel.GreenBias == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.GreenBias = param; + break; + case GL_BLUE_SCALE: + if (ctx->Pixel.BlueScale == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.BlueScale = param; + break; + case GL_BLUE_BIAS: + if (ctx->Pixel.BlueBias == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.BlueBias = param; + break; + case GL_ALPHA_SCALE: + if (ctx->Pixel.AlphaScale == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.AlphaScale = param; + break; + case GL_ALPHA_BIAS: + if (ctx->Pixel.AlphaBias == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.AlphaBias = param; + break; + case GL_DEPTH_SCALE: + if (ctx->Pixel.DepthScale == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.DepthScale = param; + break; + case GL_DEPTH_BIAS: + if (ctx->Pixel.DepthBias == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.DepthBias = param; + break; + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glPixelTransfer(pname)" ); + return; + } +} + + +static void GLAPIENTRY +_mesa_PixelTransferi( GLenum pname, GLint param ) +{ + _mesa_PixelTransferf( pname, (GLfloat) param ); +} + + + +/**********************************************************************/ +/***** State Management *****/ +/**********************************************************************/ + +/* + * Return a bitmask of IMAGE_*_BIT flags which to indicate which + * pixel transfer operations are enabled. + */ +static void +update_image_transfer_state(struct gl_context *ctx) +{ + GLuint mask = 0; + + if (ctx->Pixel.RedScale != 1.0F || ctx->Pixel.RedBias != 0.0F || + ctx->Pixel.GreenScale != 1.0F || ctx->Pixel.GreenBias != 0.0F || + ctx->Pixel.BlueScale != 1.0F || ctx->Pixel.BlueBias != 0.0F || + ctx->Pixel.AlphaScale != 1.0F || ctx->Pixel.AlphaBias != 0.0F) + mask |= IMAGE_SCALE_BIAS_BIT; + + if (ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset) + mask |= IMAGE_SHIFT_OFFSET_BIT; + + if (ctx->Pixel.MapColorFlag) + mask |= IMAGE_MAP_COLOR_BIT; + + ctx->_ImageTransferState = mask; +} + + +/** + * Update mesa pixel transfer derived state. + */ +void _mesa_update_pixel( struct gl_context *ctx, GLuint new_state ) +{ + if (new_state & _MESA_NEW_TRANSFER_STATE) + update_image_transfer_state(ctx); +} + + +void +_mesa_init_pixel_dispatch(struct _glapi_table *disp) +{ + SET_GetPixelMapfv(disp, _mesa_GetPixelMapfv); + SET_GetPixelMapuiv(disp, _mesa_GetPixelMapuiv); + SET_GetPixelMapusv(disp, _mesa_GetPixelMapusv); + SET_PixelMapfv(disp, _mesa_PixelMapfv); + SET_PixelMapuiv(disp, _mesa_PixelMapuiv); + SET_PixelMapusv(disp, _mesa_PixelMapusv); + SET_PixelTransferf(disp, _mesa_PixelTransferf); + SET_PixelTransferi(disp, _mesa_PixelTransferi); + SET_PixelZoom(disp, _mesa_PixelZoom); +} + + +#endif /* FEATURE_pixel_transfer */ + + +/**********************************************************************/ +/***** Initialization *****/ +/**********************************************************************/ + +static void +init_pixelmap(struct gl_pixelmap *map) +{ + map->Size = 1; + map->Map[0] = 0.0; + map->Map8[0] = 0; +} + + +/** + * Initialize the context's PIXEL attribute group. + */ +void +_mesa_init_pixel( struct gl_context *ctx ) +{ + /* Pixel group */ + ctx->Pixel.RedBias = 0.0; + ctx->Pixel.RedScale = 1.0; + ctx->Pixel.GreenBias = 0.0; + ctx->Pixel.GreenScale = 1.0; + ctx->Pixel.BlueBias = 0.0; + ctx->Pixel.BlueScale = 1.0; + ctx->Pixel.AlphaBias = 0.0; + ctx->Pixel.AlphaScale = 1.0; + ctx->Pixel.DepthBias = 0.0; + ctx->Pixel.DepthScale = 1.0; + ctx->Pixel.IndexOffset = 0; + ctx->Pixel.IndexShift = 0; + ctx->Pixel.ZoomX = 1.0; + ctx->Pixel.ZoomY = 1.0; + ctx->Pixel.MapColorFlag = GL_FALSE; + ctx->Pixel.MapStencilFlag = GL_FALSE; + init_pixelmap(&ctx->PixelMaps.StoS); + init_pixelmap(&ctx->PixelMaps.ItoI); + init_pixelmap(&ctx->PixelMaps.ItoR); + init_pixelmap(&ctx->PixelMaps.ItoG); + init_pixelmap(&ctx->PixelMaps.ItoB); + init_pixelmap(&ctx->PixelMaps.ItoA); + init_pixelmap(&ctx->PixelMaps.RtoR); + init_pixelmap(&ctx->PixelMaps.GtoG); + init_pixelmap(&ctx->PixelMaps.BtoB); + init_pixelmap(&ctx->PixelMaps.AtoA); + + if (ctx->Visual.doubleBufferMode) { + ctx->Pixel.ReadBuffer = GL_BACK; + } + else { + ctx->Pixel.ReadBuffer = GL_FRONT; + } + + /* Miscellaneous */ + ctx->_ImageTransferState = 0; +} diff --git a/mesalib/src/mesa/main/polygon.c b/mesalib/src/mesa/main/polygon.c index 71ef929fc..ff4232ecc 100644 --- a/mesalib/src/mesa/main/polygon.c +++ b/mesalib/src/mesa/main/polygon.c @@ -1,322 +1,322 @@ -/** - * \file polygon.c - * Polygon operations. - */ - -/* - * Mesa 3-D graphics library - * Version: 6.5.1 - * - * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#include "glheader.h" -#include "imports.h" -#include "bufferobj.h" -#include "context.h" -#include "image.h" -#include "enums.h" -#include "pack.h" -#include "polygon.h" -#include "mtypes.h" - - -/** - * Specify whether to cull front- or back-facing facets. - * - * \param mode culling mode. - * - * \sa glCullFace(). - * - * Verifies the parameter and updates gl_polygon_attrib::CullFaceMode. On - * change, flushes the vertices and notifies the driver via - * the dd_function_table::CullFace callback. - */ -void GLAPIENTRY -_mesa_CullFace( GLenum mode ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE&VERBOSE_API) - _mesa_debug(ctx, "glCullFace %s\n", _mesa_lookup_enum_by_nr(mode)); - - if (mode!=GL_FRONT && mode!=GL_BACK && mode!=GL_FRONT_AND_BACK) { - _mesa_error( ctx, GL_INVALID_ENUM, "glCullFace" ); - return; - } - - if (ctx->Polygon.CullFaceMode == mode) - return; - - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.CullFaceMode = mode; - - if (ctx->Driver.CullFace) - ctx->Driver.CullFace( ctx, mode ); -} - - -/** - * Define front- and back-facing - * - * \param mode orientation of front-facing polygons. - * - * \sa glFrontFace(). - * - * Verifies the parameter and updates gl_polygon_attrib::FrontFace. On change - * flushes the vertices and notifies the driver via - * the dd_function_table::FrontFace callback. - */ -void GLAPIENTRY -_mesa_FrontFace( GLenum mode ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE&VERBOSE_API) - _mesa_debug(ctx, "glFrontFace %s\n", _mesa_lookup_enum_by_nr(mode)); - - if (mode!=GL_CW && mode!=GL_CCW) { - _mesa_error( ctx, GL_INVALID_ENUM, "glFrontFace" ); - return; - } - - if (ctx->Polygon.FrontFace == mode) - return; - - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.FrontFace = mode; - - ctx->Polygon._FrontBit = (GLboolean) (mode == GL_CW); - - if (ctx->Driver.FrontFace) - ctx->Driver.FrontFace( ctx, mode ); -} - - -/** - * Set the polygon rasterization mode. - * - * \param face the polygons which \p mode applies to. - * \param mode how polygons should be rasterized. - * - * \sa glPolygonMode(). - * - * Verifies the parameters and updates gl_polygon_attrib::FrontMode and - * gl_polygon_attrib::BackMode. On change flushes the vertices and notifies the - * driver via the dd_function_table::PolygonMode callback. - */ -void GLAPIENTRY -_mesa_PolygonMode( GLenum face, GLenum mode ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE&VERBOSE_API) - _mesa_debug(ctx, "glPolygonMode %s %s\n", - _mesa_lookup_enum_by_nr(face), - _mesa_lookup_enum_by_nr(mode)); - - if (mode!=GL_POINT && mode!=GL_LINE && mode!=GL_FILL) { - _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(mode)" ); - return; - } - - switch (face) { - case GL_FRONT: - if (ctx->Polygon.FrontMode == mode) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.FrontMode = mode; - break; - case GL_FRONT_AND_BACK: - if (ctx->Polygon.FrontMode == mode && - ctx->Polygon.BackMode == mode) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.FrontMode = mode; - ctx->Polygon.BackMode = mode; - break; - case GL_BACK: - if (ctx->Polygon.BackMode == mode) - return; - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.BackMode = mode; - break; - default: - _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" ); - return; - } - - if (ctx->Polygon.FrontMode == GL_FILL && ctx->Polygon.BackMode == GL_FILL) - ctx->_TriangleCaps &= ~DD_TRI_UNFILLED; - else - ctx->_TriangleCaps |= DD_TRI_UNFILLED; - - if (ctx->Driver.PolygonMode) - ctx->Driver.PolygonMode(ctx, face, mode); -} - -#if _HAVE_FULL_GL - - -/** - * This routine updates the ctx->Polygon.Stipple state. - * If we're getting the stipple data from a PBO, we map the buffer - * in order to access the data. - * In any case, we obey the current pixel unpacking parameters when fetching - * the stipple data. - * - * In the future, this routine should be used as a fallback, called via - * ctx->Driver.PolygonStipple(). We'll have to update all the DRI drivers - * too. - */ -void -_mesa_polygon_stipple(struct gl_context *ctx, const GLubyte *pattern) -{ - pattern = _mesa_map_validate_pbo_source(ctx, 2, - &ctx->Unpack, 32, 32, 1, - GL_COLOR_INDEX, GL_BITMAP, pattern, - "glPolygonStipple"); - if (!pattern) - return; - - _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack); - - _mesa_unmap_pbo_source(ctx, &ctx->Unpack); -} - - -/** - * Called by glPolygonStipple. - */ -void GLAPIENTRY -_mesa_PolygonStipple( const GLubyte *pattern ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE&VERBOSE_API) - _mesa_debug(ctx, "glPolygonStipple\n"); - - FLUSH_VERTICES(ctx, _NEW_POLYGONSTIPPLE); - - _mesa_polygon_stipple(ctx, pattern); - - if (ctx->Driver.PolygonStipple) - ctx->Driver.PolygonStipple(ctx, pattern); -} - - -/** - * Called by glPolygonStipple. - */ -void GLAPIENTRY -_mesa_GetPolygonStipple( GLubyte *dest ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE&VERBOSE_API) - _mesa_debug(ctx, "glGetPolygonStipple\n"); - - dest = _mesa_map_validate_pbo_dest(ctx, 2, - &ctx->Pack, 32, 32, 1, - GL_COLOR_INDEX, GL_BITMAP, dest, - "glGetPolygonStipple"); - if (!dest) - return; - - _mesa_pack_polygon_stipple(ctx->PolygonStipple, dest, &ctx->Pack); - - _mesa_unmap_pbo_dest(ctx, &ctx->Pack); -} - - -void GLAPIENTRY -_mesa_PolygonOffset( GLfloat factor, GLfloat units ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE&VERBOSE_API) - _mesa_debug(ctx, "glPolygonOffset %f %f\n", factor, units); - - if (ctx->Polygon.OffsetFactor == factor && - ctx->Polygon.OffsetUnits == units) - return; - - FLUSH_VERTICES(ctx, _NEW_POLYGON); - ctx->Polygon.OffsetFactor = factor; - ctx->Polygon.OffsetUnits = units; - - if (ctx->Driver.PolygonOffset) - ctx->Driver.PolygonOffset( ctx, factor, units ); -} - - -void GLAPIENTRY -_mesa_PolygonOffsetEXT( GLfloat factor, GLfloat bias ) -{ - GET_CURRENT_CONTEXT(ctx); - /* XXX mult by DepthMaxF here??? */ - _mesa_PolygonOffset(factor, bias * ctx->DrawBuffer->_DepthMaxF ); -} - -#endif - - -/**********************************************************************/ -/** \name Initialization */ -/*@{*/ - -/** - * Initialize the context polygon state. - * - * \param ctx GL context. - * - * Initializes __struct gl_contextRec::Polygon and __struct gl_contextRec::PolygonStipple - * attribute groups. - */ -void _mesa_init_polygon( struct gl_context * ctx ) -{ - /* Polygon group */ - ctx->Polygon.CullFlag = GL_FALSE; - ctx->Polygon.CullFaceMode = GL_BACK; - ctx->Polygon.FrontFace = GL_CCW; - ctx->Polygon._FrontBit = 0; - ctx->Polygon.FrontMode = GL_FILL; - ctx->Polygon.BackMode = GL_FILL; - ctx->Polygon.SmoothFlag = GL_FALSE; - ctx->Polygon.StippleFlag = GL_FALSE; - ctx->Polygon.OffsetFactor = 0.0F; - ctx->Polygon.OffsetUnits = 0.0F; - ctx->Polygon.OffsetPoint = GL_FALSE; - ctx->Polygon.OffsetLine = GL_FALSE; - ctx->Polygon.OffsetFill = GL_FALSE; - - - /* Polygon Stipple group */ - memset( ctx->PolygonStipple, 0xff, 32*sizeof(GLuint) ); -} - -/*@}*/ +/** + * \file polygon.c + * Polygon operations. + */ + +/* + * Mesa 3-D graphics library + * Version: 6.5.1 + * + * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include "glheader.h" +#include "imports.h" +#include "context.h" +#include "image.h" +#include "enums.h" +#include "pack.h" +#include "pbo.h" +#include "polygon.h" +#include "mtypes.h" + + +/** + * Specify whether to cull front- or back-facing facets. + * + * \param mode culling mode. + * + * \sa glCullFace(). + * + * Verifies the parameter and updates gl_polygon_attrib::CullFaceMode. On + * change, flushes the vertices and notifies the driver via + * the dd_function_table::CullFace callback. + */ +void GLAPIENTRY +_mesa_CullFace( GLenum mode ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE&VERBOSE_API) + _mesa_debug(ctx, "glCullFace %s\n", _mesa_lookup_enum_by_nr(mode)); + + if (mode!=GL_FRONT && mode!=GL_BACK && mode!=GL_FRONT_AND_BACK) { + _mesa_error( ctx, GL_INVALID_ENUM, "glCullFace" ); + return; + } + + if (ctx->Polygon.CullFaceMode == mode) + return; + + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.CullFaceMode = mode; + + if (ctx->Driver.CullFace) + ctx->Driver.CullFace( ctx, mode ); +} + + +/** + * Define front- and back-facing + * + * \param mode orientation of front-facing polygons. + * + * \sa glFrontFace(). + * + * Verifies the parameter and updates gl_polygon_attrib::FrontFace. On change + * flushes the vertices and notifies the driver via + * the dd_function_table::FrontFace callback. + */ +void GLAPIENTRY +_mesa_FrontFace( GLenum mode ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE&VERBOSE_API) + _mesa_debug(ctx, "glFrontFace %s\n", _mesa_lookup_enum_by_nr(mode)); + + if (mode!=GL_CW && mode!=GL_CCW) { + _mesa_error( ctx, GL_INVALID_ENUM, "glFrontFace" ); + return; + } + + if (ctx->Polygon.FrontFace == mode) + return; + + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.FrontFace = mode; + + ctx->Polygon._FrontBit = (GLboolean) (mode == GL_CW); + + if (ctx->Driver.FrontFace) + ctx->Driver.FrontFace( ctx, mode ); +} + + +/** + * Set the polygon rasterization mode. + * + * \param face the polygons which \p mode applies to. + * \param mode how polygons should be rasterized. + * + * \sa glPolygonMode(). + * + * Verifies the parameters and updates gl_polygon_attrib::FrontMode and + * gl_polygon_attrib::BackMode. On change flushes the vertices and notifies the + * driver via the dd_function_table::PolygonMode callback. + */ +void GLAPIENTRY +_mesa_PolygonMode( GLenum face, GLenum mode ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE&VERBOSE_API) + _mesa_debug(ctx, "glPolygonMode %s %s\n", + _mesa_lookup_enum_by_nr(face), + _mesa_lookup_enum_by_nr(mode)); + + if (mode!=GL_POINT && mode!=GL_LINE && mode!=GL_FILL) { + _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(mode)" ); + return; + } + + switch (face) { + case GL_FRONT: + if (ctx->Polygon.FrontMode == mode) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.FrontMode = mode; + break; + case GL_FRONT_AND_BACK: + if (ctx->Polygon.FrontMode == mode && + ctx->Polygon.BackMode == mode) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.FrontMode = mode; + ctx->Polygon.BackMode = mode; + break; + case GL_BACK: + if (ctx->Polygon.BackMode == mode) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.BackMode = mode; + break; + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" ); + return; + } + + if (ctx->Polygon.FrontMode == GL_FILL && ctx->Polygon.BackMode == GL_FILL) + ctx->_TriangleCaps &= ~DD_TRI_UNFILLED; + else + ctx->_TriangleCaps |= DD_TRI_UNFILLED; + + if (ctx->Driver.PolygonMode) + ctx->Driver.PolygonMode(ctx, face, mode); +} + +#if _HAVE_FULL_GL + + +/** + * This routine updates the ctx->Polygon.Stipple state. + * If we're getting the stipple data from a PBO, we map the buffer + * in order to access the data. + * In any case, we obey the current pixel unpacking parameters when fetching + * the stipple data. + * + * In the future, this routine should be used as a fallback, called via + * ctx->Driver.PolygonStipple(). We'll have to update all the DRI drivers + * too. + */ +void +_mesa_polygon_stipple(struct gl_context *ctx, const GLubyte *pattern) +{ + pattern = _mesa_map_validate_pbo_source(ctx, 2, + &ctx->Unpack, 32, 32, 1, + GL_COLOR_INDEX, GL_BITMAP, pattern, + "glPolygonStipple"); + if (!pattern) + return; + + _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack); + + _mesa_unmap_pbo_source(ctx, &ctx->Unpack); +} + + +/** + * Called by glPolygonStipple. + */ +void GLAPIENTRY +_mesa_PolygonStipple( const GLubyte *pattern ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE&VERBOSE_API) + _mesa_debug(ctx, "glPolygonStipple\n"); + + FLUSH_VERTICES(ctx, _NEW_POLYGONSTIPPLE); + + _mesa_polygon_stipple(ctx, pattern); + + if (ctx->Driver.PolygonStipple) + ctx->Driver.PolygonStipple(ctx, pattern); +} + + +/** + * Called by glPolygonStipple. + */ +void GLAPIENTRY +_mesa_GetPolygonStipple( GLubyte *dest ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE&VERBOSE_API) + _mesa_debug(ctx, "glGetPolygonStipple\n"); + + dest = _mesa_map_validate_pbo_dest(ctx, 2, + &ctx->Pack, 32, 32, 1, + GL_COLOR_INDEX, GL_BITMAP, dest, + "glGetPolygonStipple"); + if (!dest) + return; + + _mesa_pack_polygon_stipple(ctx->PolygonStipple, dest, &ctx->Pack); + + _mesa_unmap_pbo_dest(ctx, &ctx->Pack); +} + + +void GLAPIENTRY +_mesa_PolygonOffset( GLfloat factor, GLfloat units ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE&VERBOSE_API) + _mesa_debug(ctx, "glPolygonOffset %f %f\n", factor, units); + + if (ctx->Polygon.OffsetFactor == factor && + ctx->Polygon.OffsetUnits == units) + return; + + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.OffsetFactor = factor; + ctx->Polygon.OffsetUnits = units; + + if (ctx->Driver.PolygonOffset) + ctx->Driver.PolygonOffset( ctx, factor, units ); +} + + +void GLAPIENTRY +_mesa_PolygonOffsetEXT( GLfloat factor, GLfloat bias ) +{ + GET_CURRENT_CONTEXT(ctx); + /* XXX mult by DepthMaxF here??? */ + _mesa_PolygonOffset(factor, bias * ctx->DrawBuffer->_DepthMaxF ); +} + +#endif + + +/**********************************************************************/ +/** \name Initialization */ +/*@{*/ + +/** + * Initialize the context polygon state. + * + * \param ctx GL context. + * + * Initializes __struct gl_contextRec::Polygon and __struct gl_contextRec::PolygonStipple + * attribute groups. + */ +void _mesa_init_polygon( struct gl_context * ctx ) +{ + /* Polygon group */ + ctx->Polygon.CullFlag = GL_FALSE; + ctx->Polygon.CullFaceMode = GL_BACK; + ctx->Polygon.FrontFace = GL_CCW; + ctx->Polygon._FrontBit = 0; + ctx->Polygon.FrontMode = GL_FILL; + ctx->Polygon.BackMode = GL_FILL; + ctx->Polygon.SmoothFlag = GL_FALSE; + ctx->Polygon.StippleFlag = GL_FALSE; + ctx->Polygon.OffsetFactor = 0.0F; + ctx->Polygon.OffsetUnits = 0.0F; + ctx->Polygon.OffsetPoint = GL_FALSE; + ctx->Polygon.OffsetLine = GL_FALSE; + ctx->Polygon.OffsetFill = GL_FALSE; + + + /* Polygon Stipple group */ + memset( ctx->PolygonStipple, 0xff, 32*sizeof(GLuint) ); +} + +/*@}*/ diff --git a/mesalib/src/mesa/main/readpix.c b/mesalib/src/mesa/main/readpix.c index 3f424600c..6e09a52c8 100644 --- a/mesalib/src/mesa/main/readpix.c +++ b/mesalib/src/mesa/main/readpix.c @@ -1,243 +1,244 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * 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 "glheader.h" -#include "imports.h" -#include "bufferobj.h" -#include "context.h" -#include "enums.h" -#include "readpix.h" -#include "framebuffer.h" -#include "formats.h" -#include "image.h" -#include "mtypes.h" -#include "state.h" - - -/** - * Do error checking of the format/type parameters to glReadPixels and - * glDrawPixels. - * \param drawing if GL_TRUE do checking for DrawPixels, else do checking - * for ReadPixels. - * \return GL_TRUE if error detected, GL_FALSE if no errors - */ -GLboolean -_mesa_error_check_format_type(struct gl_context *ctx, GLenum format, GLenum type, - GLboolean drawing) -{ - const char *readDraw = drawing ? "Draw" : "Read"; - const GLboolean reading = !drawing; - - /* state validation should have already been done */ - ASSERT(ctx->NewState == 0x0); - - if (ctx->Extensions.EXT_packed_depth_stencil - && type == GL_UNSIGNED_INT_24_8_EXT - && format != GL_DEPTH_STENCIL_EXT) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "gl%sPixels(format is not GL_DEPTH_STENCIL_EXT)", readDraw); - return GL_TRUE; - } - - /* basic combinations test */ - if (!_mesa_is_legal_format_and_type(ctx, format, type)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "gl%sPixels(format or type)", readDraw); - return GL_TRUE; - } - - /* additional checks */ - switch (format) { - case GL_RG: - case GL_RED: - case GL_GREEN: - case GL_BLUE: - case GL_ALPHA: - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - case GL_RGB: - case GL_BGR: - case GL_RGBA: - case GL_BGRA: - case GL_ABGR_EXT: - 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: - if (!drawing) { - /* reading */ - if (!_mesa_source_buffer_exists(ctx, GL_COLOR)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glReadPixels(no color buffer)"); - return GL_TRUE; - } - } - break; - case GL_COLOR_INDEX: - if (drawing) { - if (ctx->PixelMaps.ItoR.Size == 0 || - ctx->PixelMaps.ItoG.Size == 0 || - ctx->PixelMaps.ItoB.Size == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glDrawPixels(drawing color index pixels into RGB buffer)"); - return GL_TRUE; - } - } - else { - /* reading */ - if (!_mesa_source_buffer_exists(ctx, GL_COLOR)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glReadPixels(no color buffer)"); - return GL_TRUE; - } - /* We no longer support CI-mode color buffers so trying to read - * GL_COLOR_INDEX pixels is always an error. - */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "glReadPixels(color buffer is RGB)"); - return GL_TRUE; - } - break; - case GL_STENCIL_INDEX: - if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) || - (reading && !_mesa_source_buffer_exists(ctx, format))) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "gl%sPixels(no stencil buffer)", readDraw); - return GL_TRUE; - } - break; - case GL_DEPTH_COMPONENT: - if ((drawing && !_mesa_dest_buffer_exists(ctx, format))) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "gl%sPixels(no depth buffer)", readDraw); - return GL_TRUE; - } - break; - case GL_DEPTH_STENCIL_EXT: - if (!ctx->Extensions.EXT_packed_depth_stencil || - type != GL_UNSIGNED_INT_24_8_EXT) { - _mesa_error(ctx, GL_INVALID_ENUM, "gl%sPixels(type)", readDraw); - return GL_TRUE; - } - if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) || - (reading && !_mesa_source_buffer_exists(ctx, format))) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "gl%sPixels(no depth or stencil buffer)", readDraw); - return GL_TRUE; - } - break; - default: - /* this should have been caught in _mesa_is_legal_format_type() */ - _mesa_problem(ctx, "unexpected format in _mesa_%sPixels", readDraw); - return GL_TRUE; - } - - /* no errors */ - return GL_FALSE; -} - - - -void GLAPIENTRY -_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLvoid *pixels ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - FLUSH_CURRENT(ctx, 0); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n", - width, height, - _mesa_lookup_enum_by_nr(format), - _mesa_lookup_enum_by_nr(type), - pixels); - - if (width < 0 || height < 0) { - _mesa_error( ctx, GL_INVALID_VALUE, - "glReadPixels(width=%d height=%d)", width, height ); - return; - } - - if (ctx->NewState) - _mesa_update_state(ctx); - - if (_mesa_error_check_format_type(ctx, format, type, GL_FALSE)) { - /* found an error */ - return; - } - - /* Check that the destination format and source buffer are both - * integer-valued or both non-integer-valued. - */ - if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) { - const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; - const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format); - const GLboolean dstInteger = _mesa_is_integer_format(format); - if (dstInteger != srcInteger) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glReadPixels(integer / non-integer format mismatch"); - return; - } - } - - if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { - _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, - "glReadPixels(incomplete framebuffer)" ); - return; - } - - if (!_mesa_source_buffer_exists(ctx, format)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)"); - return; - } - - if (width == 0 || height == 0) - return; /* nothing to do */ - - if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { - if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1, - format, type, pixels)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glReadPixels(invalid PBO access)"); - return; - } - - if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { - /* buffer is mapped - that's an error */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)"); - return; - } - } - - ctx->Driver.ReadPixels(ctx, x, y, width, height, - format, type, &ctx->Pack, pixels); -} +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * 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 "glheader.h" +#include "imports.h" +#include "bufferobj.h" +#include "context.h" +#include "enums.h" +#include "readpix.h" +#include "framebuffer.h" +#include "formats.h" +#include "image.h" +#include "mtypes.h" +#include "pbo.h" +#include "state.h" + + +/** + * Do error checking of the format/type parameters to glReadPixels and + * glDrawPixels. + * \param drawing if GL_TRUE do checking for DrawPixels, else do checking + * for ReadPixels. + * \return GL_TRUE if error detected, GL_FALSE if no errors + */ +GLboolean +_mesa_error_check_format_type(struct gl_context *ctx, GLenum format, GLenum type, + GLboolean drawing) +{ + const char *readDraw = drawing ? "Draw" : "Read"; + const GLboolean reading = !drawing; + + /* state validation should have already been done */ + ASSERT(ctx->NewState == 0x0); + + if (ctx->Extensions.EXT_packed_depth_stencil + && type == GL_UNSIGNED_INT_24_8_EXT + && format != GL_DEPTH_STENCIL_EXT) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "gl%sPixels(format is not GL_DEPTH_STENCIL_EXT)", readDraw); + return GL_TRUE; + } + + /* basic combinations test */ + if (!_mesa_is_legal_format_and_type(ctx, format, type)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "gl%sPixels(format or type)", readDraw); + return GL_TRUE; + } + + /* additional checks */ + switch (format) { + case GL_RG: + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_RGB: + case GL_BGR: + case GL_RGBA: + case GL_BGRA: + case GL_ABGR_EXT: + 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: + if (!drawing) { + /* reading */ + if (!_mesa_source_buffer_exists(ctx, GL_COLOR)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glReadPixels(no color buffer)"); + return GL_TRUE; + } + } + break; + case GL_COLOR_INDEX: + if (drawing) { + if (ctx->PixelMaps.ItoR.Size == 0 || + ctx->PixelMaps.ItoG.Size == 0 || + ctx->PixelMaps.ItoB.Size == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDrawPixels(drawing color index pixels into RGB buffer)"); + return GL_TRUE; + } + } + else { + /* reading */ + if (!_mesa_source_buffer_exists(ctx, GL_COLOR)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glReadPixels(no color buffer)"); + return GL_TRUE; + } + /* We no longer support CI-mode color buffers so trying to read + * GL_COLOR_INDEX pixels is always an error. + */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glReadPixels(color buffer is RGB)"); + return GL_TRUE; + } + break; + case GL_STENCIL_INDEX: + if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) || + (reading && !_mesa_source_buffer_exists(ctx, format))) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "gl%sPixels(no stencil buffer)", readDraw); + return GL_TRUE; + } + break; + case GL_DEPTH_COMPONENT: + if ((drawing && !_mesa_dest_buffer_exists(ctx, format))) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "gl%sPixels(no depth buffer)", readDraw); + return GL_TRUE; + } + break; + case GL_DEPTH_STENCIL_EXT: + if (!ctx->Extensions.EXT_packed_depth_stencil || + type != GL_UNSIGNED_INT_24_8_EXT) { + _mesa_error(ctx, GL_INVALID_ENUM, "gl%sPixels(type)", readDraw); + return GL_TRUE; + } + if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) || + (reading && !_mesa_source_buffer_exists(ctx, format))) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "gl%sPixels(no depth or stencil buffer)", readDraw); + return GL_TRUE; + } + break; + default: + /* this should have been caught in _mesa_is_legal_format_type() */ + _mesa_problem(ctx, "unexpected format in _mesa_%sPixels", readDraw); + return GL_TRUE; + } + + /* no errors */ + return GL_FALSE; +} + + + +void GLAPIENTRY +_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + FLUSH_CURRENT(ctx, 0); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n", + width, height, + _mesa_lookup_enum_by_nr(format), + _mesa_lookup_enum_by_nr(type), + pixels); + + if (width < 0 || height < 0) { + _mesa_error( ctx, GL_INVALID_VALUE, + "glReadPixels(width=%d height=%d)", width, height ); + return; + } + + if (ctx->NewState) + _mesa_update_state(ctx); + + if (_mesa_error_check_format_type(ctx, format, type, GL_FALSE)) { + /* found an error */ + return; + } + + /* Check that the destination format and source buffer are both + * integer-valued or both non-integer-valued. + */ + if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) { + const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; + const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format); + const GLboolean dstInteger = _mesa_is_integer_format(format); + if (dstInteger != srcInteger) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glReadPixels(integer / non-integer format mismatch"); + return; + } + } + + if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "glReadPixels(incomplete framebuffer)" ); + return; + } + + if (!_mesa_source_buffer_exists(ctx, format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)"); + return; + } + + if (width == 0 || height == 0) + return; /* nothing to do */ + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1, + format, type, pixels)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glReadPixels(invalid PBO access)"); + return; + } + + if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { + /* buffer is mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)"); + return; + } + } + + ctx->Driver.ReadPixels(ctx, x, y, width, height, + format, type, &ctx->Pack, pixels); +} diff --git a/mesalib/src/mesa/main/texcompress_rgtc.c b/mesalib/src/mesa/main/texcompress_rgtc.c index b7725f4a9..2f3a0f214 100644 --- a/mesalib/src/mesa/main/texcompress_rgtc.c +++ b/mesalib/src/mesa/main/texcompress_rgtc.c @@ -46,9 +46,9 @@ #define RGTC_DEBUG 0 -static void encode_rgtc_chan_u(GLubyte *blkaddr, GLubyte srccolors[4][4], - GLint numxpixels, GLint numypixels); -static void encode_rgtc_chan_s(GLbyte *blkaddr, GLbyte srccolors[4][4], +static void unsigned_encode_rgtc_chan(GLubyte *blkaddr, GLubyte srccolors[4][4], + GLint numxpixels, GLint numypixels); +static void signed_encode_rgtc_chan(GLbyte *blkaddr, GLbyte srccolors[4][4], GLint numxpixels, GLint numypixels); static void extractsrc_u( GLubyte srcpixels[4][4], const GLchan *srcaddr, @@ -88,7 +88,7 @@ _mesa_texstore_red_rgtc1(TEXSTORE_PARAMS) const GLchan *tempImage = NULL; int i, j; int numxpixels, numypixels; - const void *srcaddr; + const GLchan *srcaddr; GLubyte srcpixels[4][4]; GLubyte *blkaddr; GLint dstRowDiff; @@ -123,7 +123,7 @@ _mesa_texstore_red_rgtc1(TEXSTORE_PARAMS) if (srcWidth > i + 3) numxpixels = 4; else numxpixels = srcWidth - i; extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1); - encode_rgtc_chan_u(blkaddr, srcpixels, numxpixels, numypixels); + unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); srcaddr += numxpixels; blkaddr += 8; } @@ -177,7 +177,7 @@ _mesa_texstore_signed_red_rgtc1(TEXSTORE_PARAMS) if (srcWidth > i + 3) numxpixels = 4; else numxpixels = srcWidth - i; extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1); - encode_rgtc_chan_s(blkaddr, srcpixels, numxpixels, numypixels); + signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); srcaddr += numxpixels; blkaddr += 8; } @@ -197,7 +197,7 @@ _mesa_texstore_rg_rgtc2(TEXSTORE_PARAMS) const GLchan *tempImage = NULL; int i, j; int numxpixels, numypixels; - const void *srcaddr; + const GLchan *srcaddr; GLubyte srcpixels[4][4]; GLubyte *blkaddr; GLint dstRowDiff; @@ -232,11 +232,11 @@ _mesa_texstore_rg_rgtc2(TEXSTORE_PARAMS) if (srcWidth > i + 3) numxpixels = 4; else numxpixels = srcWidth - i; extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2); - encode_rgtc_chan_u(blkaddr, srcpixels, numxpixels, numypixels); + unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); blkaddr += 8; extractsrc_u(srcpixels, (GLchan *)srcaddr + 1, srcWidth, numxpixels, numypixels, 2); - encode_rgtc_chan_u(blkaddr, srcpixels, numxpixels, numypixels); + unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); blkaddr += 8; @@ -294,11 +294,11 @@ _mesa_texstore_signed_rg_rgtc2(TEXSTORE_PARAMS) else numxpixels = srcWidth - i; extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2); - encode_rgtc_chan_s(blkaddr, srcpixels, numxpixels, numypixels); + signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); blkaddr += 8; extractsrc_s(srcpixels, srcaddr + 1, srcWidth, numxpixels, numypixels, 2); - encode_rgtc_chan_s(blkaddr, srcpixels, numxpixels, numypixels); + signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); blkaddr += 8; srcaddr += numxpixels * 2; @@ -427,696 +427,27 @@ _mesa_fetch_texel_2d_f_signed_rg_rgtc2(const struct gl_texture_image *texImage, texel[ACOMP] = 1.0; } -static void write_rgtc_encoded_channel(GLubyte *blkaddr, - GLubyte alphabase1, - GLubyte alphabase2, - GLubyte alphaenc[16]) -{ - *blkaddr++ = alphabase1; - *blkaddr++ = alphabase2; - *blkaddr++ = alphaenc[0] | (alphaenc[1] << 3) | ((alphaenc[2] & 3) << 6); - *blkaddr++ = (alphaenc[2] >> 2) | (alphaenc[3] << 1) | (alphaenc[4] << 4) | ((alphaenc[5] & 1) << 7); - *blkaddr++ = (alphaenc[5] >> 1) | (alphaenc[6] << 2) | (alphaenc[7] << 5); - *blkaddr++ = alphaenc[8] | (alphaenc[9] << 3) | ((alphaenc[10] & 3) << 6); - *blkaddr++ = (alphaenc[10] >> 2) | (alphaenc[11] << 1) | (alphaenc[12] << 4) | ((alphaenc[13] & 1) << 7); - *blkaddr++ = (alphaenc[13] >> 1) | (alphaenc[14] << 2) | (alphaenc[15] << 5); -} - -static void encode_rgtc_chan_u(GLubyte *blkaddr, GLubyte srccolors[4][4], - GLint numxpixels, GLint numypixels) -{ - GLubyte alphabase[2], alphause[2]; - GLshort alphatest[2] = { 0 }; - GLuint alphablockerror1, alphablockerror2, alphablockerror3; - GLubyte i, j, aindex, acutValues[7]; - GLubyte alphaenc1[16], alphaenc2[16], alphaenc3[16]; - GLboolean alphaabsmin = GL_FALSE; - GLboolean alphaabsmax = GL_FALSE; - GLshort alphadist; - - /* find lowest and highest alpha value in block, alphabase[0] lowest, alphabase[1] highest */ - alphabase[0] = 0xff; alphabase[1] = 0x0; - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if (srccolors[j][i] == 0) - alphaabsmin = GL_TRUE; - else if (srccolors[j][i] == 255) - alphaabsmax = GL_TRUE; - else { - if (srccolors[j][i] > alphabase[1]) - alphabase[1] = srccolors[j][i]; - if (srccolors[j][i] < alphabase[0]) - alphabase[0] = srccolors[j][i]; - } - } - } - - - if ((alphabase[0] > alphabase[1]) && !(alphaabsmin && alphaabsmax)) { /* one color, either max or min */ - /* shortcut here since it is a very common case (and also avoids later problems) */ - /* || (alphabase[0] == alphabase[1] && !alphaabsmin && !alphaabsmax) */ - /* could also thest for alpha0 == alpha1 (and not min/max), but probably not common, so don't bother */ - - *blkaddr++ = srccolors[0][0]; - blkaddr++; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; -#if RGTC_DEBUG - fprintf(stderr, "enc0 used\n"); -#endif - return; - } - - /* find best encoding for alpha0 > alpha1 */ - /* it's possible this encoding is better even if both alphaabsmin and alphaabsmax are true */ - alphablockerror1 = 0x0; - alphablockerror2 = 0xffffffff; - alphablockerror3 = 0xffffffff; - if (alphaabsmin) alphause[0] = 0; - else alphause[0] = alphabase[0]; - if (alphaabsmax) alphause[1] = 255; - else alphause[1] = alphabase[1]; - /* calculate the 7 cut values, just the middle between 2 of the computed alpha values */ - for (aindex = 0; aindex < 7; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphause[0] * (2*aindex + 1) + alphause[1] * (14 - (2*aindex + 1))) / 14; - } - - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i] > acutValues[0]) { - alphaenc1[4*j + i] = 0; - alphadist = srccolors[j][i] - alphause[1]; - } - else if (srccolors[j][i] > acutValues[1]) { - alphaenc1[4*j + i] = 2; - alphadist = srccolors[j][i] - (alphause[1] * 6 + alphause[0] * 1) / 7; - } - else if (srccolors[j][i] > acutValues[2]) { - alphaenc1[4*j + i] = 3; - alphadist = srccolors[j][i] - (alphause[1] * 5 + alphause[0] * 2) / 7; - } - else if (srccolors[j][i] > acutValues[3]) { - alphaenc1[4*j + i] = 4; - alphadist = srccolors[j][i] - (alphause[1] * 4 + alphause[0] * 3) / 7; - } - else if (srccolors[j][i] > acutValues[4]) { - alphaenc1[4*j + i] = 5; - alphadist = srccolors[j][i] - (alphause[1] * 3 + alphause[0] * 4) / 7; - } - else if (srccolors[j][i] > acutValues[5]) { - alphaenc1[4*j + i] = 6; - alphadist = srccolors[j][i] - (alphause[1] * 2 + alphause[0] * 5) / 7; - } - else if (srccolors[j][i] > acutValues[6]) { - alphaenc1[4*j + i] = 7; - alphadist = srccolors[j][i] - (alphause[1] * 1 + alphause[0] * 6) / 7; - } - else { - alphaenc1[4*j + i] = 1; - alphadist = srccolors[j][i] - alphause[0]; - } - alphablockerror1 += alphadist * alphadist; - } - } - -#if RGTC_DEBUG - for (i = 0; i < 16; i++) { - fprintf(stderr, "%d ", alphaenc1[i]); - } - fprintf(stderr, "cutVals "); - for (i = 0; i < 8; i++) { - fprintf(stderr, "%d ", acutValues[i]); - } - fprintf(stderr, "srcVals "); - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - fprintf(stderr, "%d ", srccolors[j][i]); - } - } - fprintf(stderr, "\n"); -#endif - - /* it's not very likely this encoding is better if both alphaabsmin and alphaabsmax - are false but try it anyway */ - if (alphablockerror1 >= 32) { - - /* don't bother if encoding is already very good, this condition should also imply - we have valid alphabase colors which we absolutely need (alphabase[0] <= alphabase[1]) */ - alphablockerror2 = 0; - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphabase[0] * (10 - (2*aindex + 1)) + alphabase[1] * (2*aindex + 1)) / 10; - } - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i] == 0) { - alphaenc2[4*j + i] = 6; - alphadist = 0; - } - else if (srccolors[j][i] == 255) { - alphaenc2[4*j + i] = 7; - alphadist = 0; - } - else if (srccolors[j][i] <= acutValues[0]) { - alphaenc2[4*j + i] = 0; - alphadist = srccolors[j][i] - alphabase[0]; - } - else if (srccolors[j][i] <= acutValues[1]) { - alphaenc2[4*j + i] = 2; - alphadist = srccolors[j][i] - (alphabase[0] * 4 + alphabase[1] * 1) / 5; - } - else if (srccolors[j][i] <= acutValues[2]) { - alphaenc2[4*j + i] = 3; - alphadist = srccolors[j][i] - (alphabase[0] * 3 + alphabase[1] * 2) / 5; - } - else if (srccolors[j][i] <= acutValues[3]) { - alphaenc2[4*j + i] = 4; - alphadist = srccolors[j][i] - (alphabase[0] * 2 + alphabase[1] * 3) / 5; - } - else if (srccolors[j][i] <= acutValues[4]) { - alphaenc2[4*j + i] = 5; - alphadist = srccolors[j][i] - (alphabase[0] * 1 + alphabase[1] * 4) / 5; - } - else { - alphaenc2[4*j + i] = 1; - alphadist = srccolors[j][i] - alphabase[1]; - } - alphablockerror2 += alphadist * alphadist; - } - } - - - /* skip this if the error is already very small - this encoding is MUCH better on average than #2 though, but expensive! */ - if ((alphablockerror2 > 96) && (alphablockerror1 > 96)) { - GLshort blockerrlin1 = 0; - GLshort blockerrlin2 = 0; - GLubyte nralphainrangelow = 0; - GLubyte nralphainrangehigh = 0; - alphatest[0] = 0xff; - alphatest[1] = 0x0; - /* if we have large range it's likely there are values close to 0/255, try to map them to 0/255 */ - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if ((srccolors[j][i] > alphatest[1]) && (srccolors[j][i] < (255 -(alphabase[1] - alphabase[0]) / 28))) - alphatest[1] = srccolors[j][i]; - if ((srccolors[j][i] < alphatest[0]) && (srccolors[j][i] > (alphabase[1] - alphabase[0]) / 28)) - alphatest[0] = srccolors[j][i]; - } - } - /* shouldn't happen too often, don't really care about those degenerated cases */ - if (alphatest[1] <= alphatest[0]) { - alphatest[0] = 1; - alphatest[1] = 254; - } - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; - } - - /* find the "average" difference between the alpha values and the next encoded value. - This is then used to calculate new base values. - Should there be some weighting, i.e. those values closer to alphatest[x] have more weight, - since they will see more improvement, and also because the values in the middle are somewhat - likely to get no improvement at all (because the base values might move in different directions)? - OTOH it would mean the values in the middle are even less likely to get an improvement - */ - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if (srccolors[j][i] <= alphatest[0] / 2) { - } - else if (srccolors[j][i] > ((255 + alphatest[1]) / 2)) { - } - else if (srccolors[j][i] <= acutValues[0]) { - blockerrlin1 += (srccolors[j][i] - alphatest[0]); - nralphainrangelow += 1; - } - else if (srccolors[j][i] <= acutValues[1]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i] <= acutValues[2]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i] <= acutValues[3]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i] <= acutValues[4]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else { - blockerrlin2 += (srccolors[j][i] - alphatest[1]); - nralphainrangehigh += 1; - } - } - } - /* shouldn't happen often, needed to avoid div by zero */ - if (nralphainrangelow == 0) nralphainrangelow = 1; - if (nralphainrangehigh == 0) nralphainrangehigh = 1; - alphatest[0] = alphatest[0] + (blockerrlin1 / nralphainrangelow); -#if RGTC_DEBUG - fprintf(stderr, "block err lin low %d, nr %d\n", blockerrlin1, nralphainrangelow); - fprintf(stderr, "block err lin high %d, nr %d\n", blockerrlin2, nralphainrangehigh); -#endif - /* again shouldn't really happen often... */ - if (alphatest[0] < 0) { - alphatest[0] = 0; - } - alphatest[1] = alphatest[1] + (blockerrlin2 / nralphainrangehigh); - if (alphatest[1] > 255) { - alphatest[1] = 255; - } - - alphablockerror3 = 0; - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; - } - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i] <= alphatest[0] / 2) { - alphaenc3[4*j + i] = 6; - alphadist = srccolors[j][i]; - } - else if (srccolors[j][i] > ((255 + alphatest[1]) / 2)) { - alphaenc3[4*j + i] = 7; - alphadist = 255 - srccolors[j][i]; - } - else if (srccolors[j][i] <= acutValues[0]) { - alphaenc3[4*j + i] = 0; - alphadist = srccolors[j][i] - alphatest[0]; - } - else if (srccolors[j][i] <= acutValues[1]) { - alphaenc3[4*j + i] = 2; - alphadist = srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5; - } - else if (srccolors[j][i] <= acutValues[2]) { - alphaenc3[4*j + i] = 3; - alphadist = srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5; - } - else if (srccolors[j][i] <= acutValues[3]) { - alphaenc3[4*j + i] = 4; - alphadist = srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5; - } - else if (srccolors[j][i] <= acutValues[4]) { - alphaenc3[4*j + i] = 5; - alphadist = srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5; - } - else { - alphaenc3[4*j + i] = 1; - alphadist = srccolors[j][i] - alphatest[1]; - } - alphablockerror3 += alphadist * alphadist; - } - } - } - } - /* write the alpha values and encoding back. */ - if ((alphablockerror1 <= alphablockerror2) && (alphablockerror1 <= alphablockerror3)) { -#if RGTC_DEBUG - if (alphablockerror1 > 96) fprintf(stderr, "enc1 used, error %d\n", alphablockerror1); -#endif - write_rgtc_encoded_channel( blkaddr, alphause[1], alphause[0], alphaenc1 ); - } - else if (alphablockerror2 <= alphablockerror3) { -#if RGTC_DEBUG - if (alphablockerror2 > 96) fprintf(stderr, "enc2 used, error %d\n", alphablockerror2); -#endif - write_rgtc_encoded_channel( blkaddr, alphabase[0], alphabase[1], alphaenc2 ); - } - else { -#if RGTC_DEBUG - fprintf(stderr, "enc3 used, error %d\n", alphablockerror3); -#endif - write_rgtc_encoded_channel( blkaddr, (GLubyte)alphatest[0], (GLubyte)alphatest[1], alphaenc3 ); - } -} - - -static void write_rgtc_encoded_channel_s(GLbyte *blkaddr, - GLbyte alphabase1, - GLbyte alphabase2, - GLbyte alphaenc[16]) -{ - *blkaddr++ = alphabase1; - *blkaddr++ = alphabase2; - *blkaddr++ = alphaenc[0] | (alphaenc[1] << 3) | ((alphaenc[2] & 3) << 6); - *blkaddr++ = (alphaenc[2] >> 2) | (alphaenc[3] << 1) | (alphaenc[4] << 4) | ((alphaenc[5] & 1) << 7); - *blkaddr++ = (alphaenc[5] >> 1) | (alphaenc[6] << 2) | (alphaenc[7] << 5); - *blkaddr++ = alphaenc[8] | (alphaenc[9] << 3) | ((alphaenc[10] & 3) << 6); - *blkaddr++ = (alphaenc[10] >> 2) | (alphaenc[11] << 1) | (alphaenc[12] << 4) | ((alphaenc[13] & 1) << 7); - *blkaddr++ = (alphaenc[13] >> 1) | (alphaenc[14] << 2) | (alphaenc[15] << 5); -} - -static void encode_rgtc_chan_s(GLbyte *blkaddr, GLbyte srccolors[4][4], - GLint numxpixels, GLint numypixels) -{ - GLbyte alphabase[2], alphause[2]; - GLshort alphatest[2] = { 0 }; - GLuint alphablockerror1, alphablockerror2, alphablockerror3; - GLbyte i, j, aindex, acutValues[7]; - GLbyte alphaenc1[16], alphaenc2[16], alphaenc3[16]; - GLboolean alphaabsmin = GL_FALSE; - GLboolean alphaabsmax = GL_FALSE; - GLshort alphadist; - - /* find lowest and highest alpha value in block, alphabase[0] lowest, alphabase[1] highest */ - alphabase[0] = 0xff; alphabase[1] = 0x0; - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if (srccolors[j][i] == 0) - alphaabsmin = GL_TRUE; - else if (srccolors[j][i] == 255) - alphaabsmax = GL_TRUE; - else { - if (srccolors[j][i] > alphabase[1]) - alphabase[1] = srccolors[j][i]; - if (srccolors[j][i] < alphabase[0]) - alphabase[0] = srccolors[j][i]; - } - } - } - - - if ((alphabase[0] > alphabase[1]) && !(alphaabsmin && alphaabsmax)) { /* one color, either max or min */ - /* shortcut here since it is a very common case (and also avoids later problems) */ - /* || (alphabase[0] == alphabase[1] && !alphaabsmin && !alphaabsmax) */ - /* could also thest for alpha0 == alpha1 (and not min/max), but probably not common, so don't bother */ - - *blkaddr++ = srccolors[0][0]; - blkaddr++; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; -#if RGTC_DEBUG - fprintf(stderr, "enc0 used\n"); -#endif - return; - } - - /* find best encoding for alpha0 > alpha1 */ - /* it's possible this encoding is better even if both alphaabsmin and alphaabsmax are true */ - alphablockerror1 = 0x0; - alphablockerror2 = 0xffffffff; - alphablockerror3 = 0xffffffff; - if (alphaabsmin) alphause[0] = 0; - else alphause[0] = alphabase[0]; - if (alphaabsmax) alphause[1] = 255; - else alphause[1] = alphabase[1]; - /* calculate the 7 cut values, just the middle between 2 of the computed alpha values */ - for (aindex = 0; aindex < 7; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphause[0] * (2*aindex + 1) + alphause[1] * (14 - (2*aindex + 1))) / 14; - } +#define TAG(x) unsigned_##x - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i] > acutValues[0]) { - alphaenc1[4*j + i] = 0; - alphadist = srccolors[j][i] - alphause[1]; - } - else if (srccolors[j][i] > acutValues[1]) { - alphaenc1[4*j + i] = 2; - alphadist = srccolors[j][i] - (alphause[1] * 6 + alphause[0] * 1) / 7; - } - else if (srccolors[j][i] > acutValues[2]) { - alphaenc1[4*j + i] = 3; - alphadist = srccolors[j][i] - (alphause[1] * 5 + alphause[0] * 2) / 7; - } - else if (srccolors[j][i] > acutValues[3]) { - alphaenc1[4*j + i] = 4; - alphadist = srccolors[j][i] - (alphause[1] * 4 + alphause[0] * 3) / 7; - } - else if (srccolors[j][i] > acutValues[4]) { - alphaenc1[4*j + i] = 5; - alphadist = srccolors[j][i] - (alphause[1] * 3 + alphause[0] * 4) / 7; - } - else if (srccolors[j][i] > acutValues[5]) { - alphaenc1[4*j + i] = 6; - alphadist = srccolors[j][i] - (alphause[1] * 2 + alphause[0] * 5) / 7; - } - else if (srccolors[j][i] > acutValues[6]) { - alphaenc1[4*j + i] = 7; - alphadist = srccolors[j][i] - (alphause[1] * 1 + alphause[0] * 6) / 7; - } - else { - alphaenc1[4*j + i] = 1; - alphadist = srccolors[j][i] - alphause[0]; - } - alphablockerror1 += alphadist * alphadist; - } - } -#if RGTC_DEBUG - for (i = 0; i < 16; i++) { - fprintf(stderr, "%d ", alphaenc1[i]); - } - fprintf(stderr, "cutVals "); - for (i = 0; i < 8; i++) { - fprintf(stderr, "%d ", acutValues[i]); - } - fprintf(stderr, "srcVals "); - for (j = 0; j < numypixels; j++) - for (i = 0; i < numxpixels; i++) { - fprintf(stderr, "%d ", srccolors[j][i]); - } - - fprintf(stderr, "\n"); -#endif +#define TYPE GLubyte +#define T_MIN 0 +#define T_MAX 0xff - /* it's not very likely this encoding is better if both alphaabsmin and alphaabsmax - are false but try it anyway */ - if (alphablockerror1 >= 32) { - - /* don't bother if encoding is already very good, this condition should also imply - we have valid alphabase colors which we absolutely need (alphabase[0] <= alphabase[1]) */ - alphablockerror2 = 0; - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphabase[0] * (10 - (2*aindex + 1)) + alphabase[1] * (2*aindex + 1)) / 10; - } - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i] == 0) { - alphaenc2[4*j + i] = 6; - alphadist = 0; - } - else if (srccolors[j][i] == 255) { - alphaenc2[4*j + i] = 7; - alphadist = 0; - } - else if (srccolors[j][i] <= acutValues[0]) { - alphaenc2[4*j + i] = 0; - alphadist = srccolors[j][i] - alphabase[0]; - } - else if (srccolors[j][i] <= acutValues[1]) { - alphaenc2[4*j + i] = 2; - alphadist = srccolors[j][i] - (alphabase[0] * 4 + alphabase[1] * 1) / 5; - } - else if (srccolors[j][i] <= acutValues[2]) { - alphaenc2[4*j + i] = 3; - alphadist = srccolors[j][i] - (alphabase[0] * 3 + alphabase[1] * 2) / 5; - } - else if (srccolors[j][i] <= acutValues[3]) { - alphaenc2[4*j + i] = 4; - alphadist = srccolors[j][i] - (alphabase[0] * 2 + alphabase[1] * 3) / 5; - } - else if (srccolors[j][i] <= acutValues[4]) { - alphaenc2[4*j + i] = 5; - alphadist = srccolors[j][i] - (alphabase[0] * 1 + alphabase[1] * 4) / 5; - } - else { - alphaenc2[4*j + i] = 1; - alphadist = srccolors[j][i] - alphabase[1]; - } - alphablockerror2 += alphadist * alphadist; - } - } +#include "texcompress_rgtc_tmp.h" +#undef TAG +#undef TYPE +#undef T_MIN +#undef T_MAX - /* skip this if the error is already very small - this encoding is MUCH better on average than #2 though, but expensive! */ - if ((alphablockerror2 > 96) && (alphablockerror1 > 96)) { - GLshort blockerrlin1 = 0; - GLshort blockerrlin2 = 0; - GLubyte nralphainrangelow = 0; - GLubyte nralphainrangehigh = 0; - alphatest[0] = 0xff; - alphatest[1] = 0x0; - /* if we have large range it's likely there are values close to 0/255, try to map them to 0/255 */ - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if ((srccolors[j][i] > alphatest[1]) && (srccolors[j][i] < (255 -(alphabase[1] - alphabase[0]) / 28))) - alphatest[1] = srccolors[j][i]; - if ((srccolors[j][i] < alphatest[0]) && (srccolors[j][i] > (alphabase[1] - alphabase[0]) / 28)) - alphatest[0] = srccolors[j][i]; - } - } - /* shouldn't happen too often, don't really care about those degenerated cases */ - if (alphatest[1] <= alphatest[0]) { - alphatest[0] = 1; - alphatest[1] = 254; - } - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; - } +#define TAG(x) signed_##x +#define TYPE GLbyte +#define T_MIN (GLbyte)-127 +#define T_MAX (GLbyte)127 - /* find the "average" difference between the alpha values and the next encoded value. - This is then used to calculate new base values. - Should there be some weighting, i.e. those values closer to alphatest[x] have more weight, - since they will see more improvement, and also because the values in the middle are somewhat - likely to get no improvement at all (because the base values might move in different directions)? - OTOH it would mean the values in the middle are even less likely to get an improvement - */ - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if (srccolors[j][i] <= alphatest[0] / 2) { - } - else if (srccolors[j][i] > ((255 + alphatest[1]) / 2)) { - } - else if (srccolors[j][i] <= acutValues[0]) { - blockerrlin1 += (srccolors[j][i] - alphatest[0]); - nralphainrangelow += 1; - } - else if (srccolors[j][i] <= acutValues[1]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i] <= acutValues[2]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i] <= acutValues[3]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i] <= acutValues[4]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else { - blockerrlin2 += (srccolors[j][i] - alphatest[1]); - nralphainrangehigh += 1; - } - } - } - /* shouldn't happen often, needed to avoid div by zero */ - if (nralphainrangelow == 0) nralphainrangelow = 1; - if (nralphainrangehigh == 0) nralphainrangehigh = 1; - alphatest[0] = alphatest[0] + (blockerrlin1 / nralphainrangelow); -#if RGTC_DEBUG - fprintf(stderr, "block err lin low %d, nr %d\n", blockerrlin1, nralphainrangelow); - fprintf(stderr, "block err lin high %d, nr %d\n", blockerrlin2, nralphainrangehigh); -#endif - /* again shouldn't really happen often... */ - if (alphatest[0] < 0) { - alphatest[0] = 0; - } - alphatest[1] = alphatest[1] + (blockerrlin2 / nralphainrangehigh); - if (alphatest[1] > 255) { - alphatest[1] = 255; - } +#include "texcompress_rgtc_tmp.h" - alphablockerror3 = 0; - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; - } - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i] <= alphatest[0] / 2) { - alphaenc3[4*j + i] = 6; - alphadist = srccolors[j][i]; - } - else if (srccolors[j][i] > ((255 + alphatest[1]) / 2)) { - alphaenc3[4*j + i] = 7; - alphadist = 255 - srccolors[j][i]; - } - else if (srccolors[j][i] <= acutValues[0]) { - alphaenc3[4*j + i] = 0; - alphadist = srccolors[j][i] - alphatest[0]; - } - else if (srccolors[j][i] <= acutValues[1]) { - alphaenc3[4*j + i] = 2; - alphadist = srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5; - } - else if (srccolors[j][i] <= acutValues[2]) { - alphaenc3[4*j + i] = 3; - alphadist = srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5; - } - else if (srccolors[j][i] <= acutValues[3]) { - alphaenc3[4*j + i] = 4; - alphadist = srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5; - } - else if (srccolors[j][i] <= acutValues[4]) { - alphaenc3[4*j + i] = 5; - alphadist = srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5; - } - else { - alphaenc3[4*j + i] = 1; - alphadist = srccolors[j][i] - alphatest[1]; - } - alphablockerror3 += alphadist * alphadist; - } - } - } - } - /* write the alpha values and encoding back. */ - if ((alphablockerror1 <= alphablockerror2) && (alphablockerror1 <= alphablockerror3)) { -#if RGTC_DEBUG - if (alphablockerror1 > 96) fprintf(stderr, "enc1 used, error %d\n", alphablockerror1); -#endif - write_rgtc_encoded_channel_s( blkaddr, alphause[1], alphause[0], alphaenc1 ); - } - else if (alphablockerror2 <= alphablockerror3) { -#if RGTC_DEBUG - if (alphablockerror2 > 96) fprintf(stderr, "enc2 used, error %d\n", alphablockerror2); -#endif - write_rgtc_encoded_channel_s( blkaddr, alphabase[0], alphabase[1], alphaenc2 ); - } - else { -#if RGTC_DEBUG - fprintf(stderr, "enc3 used, error %d\n", alphablockerror3); -#endif - write_rgtc_encoded_channel_s( blkaddr, (GLubyte)alphatest[0], (GLubyte)alphatest[1], alphaenc3 ); - } -} +#undef TAG +#undef TYPE +#undef T_MIN +#undef T_MAX diff --git a/mesalib/src/mesa/main/texcompress_rgtc_tmp.h b/mesalib/src/mesa/main/texcompress_rgtc_tmp.h new file mode 100644 index 000000000..0f830a5d9 --- /dev/null +++ b/mesalib/src/mesa/main/texcompress_rgtc_tmp.h @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2011 Red Hat Inc. + * + * block compression parts are: + * Copyright (C) 2004 Roland Scheidegger 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Author: + * Dave Airlie + */ + +/* included by texcompress_rgtc to define byte/ubyte compressors */ + +static void TAG(write_rgtc_encoded_channel)(TYPE *blkaddr, + TYPE alphabase1, + TYPE alphabase2, + TYPE alphaenc[16]) +{ + *blkaddr++ = alphabase1; + *blkaddr++ = alphabase2; + *blkaddr++ = alphaenc[0] | (alphaenc[1] << 3) | ((alphaenc[2] & 3) << 6); + *blkaddr++ = (alphaenc[2] >> 2) | (alphaenc[3] << 1) | (alphaenc[4] << 4) | ((alphaenc[5] & 1) << 7); + *blkaddr++ = (alphaenc[5] >> 1) | (alphaenc[6] << 2) | (alphaenc[7] << 5); + *blkaddr++ = alphaenc[8] | (alphaenc[9] << 3) | ((alphaenc[10] & 3) << 6); + *blkaddr++ = (alphaenc[10] >> 2) | (alphaenc[11] << 1) | (alphaenc[12] << 4) | ((alphaenc[13] & 1) << 7); + *blkaddr++ = (alphaenc[13] >> 1) | (alphaenc[14] << 2) | (alphaenc[15] << 5); +} +static void TAG(encode_rgtc_chan)(TYPE *blkaddr, TYPE srccolors[4][4], + GLint numxpixels, GLint numypixels) +{ + TYPE alphabase[2], alphause[2]; + GLshort alphatest[2] = { 0 }; + GLuint alphablockerror1, alphablockerror2, alphablockerror3; + TYPE i, j, aindex, acutValues[7]; + TYPE alphaenc1[16], alphaenc2[16], alphaenc3[16]; + GLboolean alphaabsmin = GL_FALSE; + GLboolean alphaabsmax = GL_FALSE; + GLshort alphadist; + + /* find lowest and highest alpha value in block, alphabase[0] lowest, alphabase[1] highest */ + alphabase[0] = T_MAX; alphabase[1] = T_MIN; + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + if (srccolors[j][i] == T_MIN) + alphaabsmin = GL_TRUE; + else if (srccolors[j][i] == T_MAX) + alphaabsmax = GL_TRUE; + else { + if (srccolors[j][i] > alphabase[1]) + alphabase[1] = srccolors[j][i]; + if (srccolors[j][i] < alphabase[0]) + alphabase[0] = srccolors[j][i]; + } + } + } + + + if ((alphabase[0] > alphabase[1]) && !(alphaabsmin && alphaabsmax)) { /* one color, either max or min */ + /* shortcut here since it is a very common case (and also avoids later problems) */ + /* || (alphabase[0] == alphabase[1] && !alphaabsmin && !alphaabsmax) */ + /* could also thest for alpha0 == alpha1 (and not min/max), but probably not common, so don't bother */ + + *blkaddr++ = srccolors[0][0]; + blkaddr++; + *blkaddr++ = 0; + *blkaddr++ = 0; + *blkaddr++ = 0; + *blkaddr++ = 0; + *blkaddr++ = 0; + *blkaddr++ = 0; +#if RGTC_DEBUG + fprintf(stderr, "enc0 used\n"); +#endif + return; + } + + /* find best encoding for alpha0 > alpha1 */ + /* it's possible this encoding is better even if both alphaabsmin and alphaabsmax are true */ + alphablockerror1 = 0x0; + alphablockerror2 = 0xffffffff; + alphablockerror3 = 0xffffffff; + if (alphaabsmin) alphause[0] = T_MIN; + else alphause[0] = alphabase[0]; + if (alphaabsmax) alphause[1] = T_MAX; + else alphause[1] = alphabase[1]; + /* calculate the 7 cut values, just the middle between 2 of the computed alpha values */ + for (aindex = 0; aindex < 7; aindex++) { + /* don't forget here is always rounded down */ + acutValues[aindex] = (alphause[0] * (2*aindex + 1) + alphause[1] * (14 - (2*aindex + 1))) / 14; + } + + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + /* maybe it's overkill to have the most complicated calculation just for the error + calculation which we only need to figure out if encoding1 or encoding2 is better... */ + if (srccolors[j][i] > acutValues[0]) { + alphaenc1[4*j + i] = 0; + alphadist = srccolors[j][i] - alphause[1]; + } + else if (srccolors[j][i] > acutValues[1]) { + alphaenc1[4*j + i] = 2; + alphadist = srccolors[j][i] - (alphause[1] * 6 + alphause[0] * 1) / 7; + } + else if (srccolors[j][i] > acutValues[2]) { + alphaenc1[4*j + i] = 3; + alphadist = srccolors[j][i] - (alphause[1] * 5 + alphause[0] * 2) / 7; + } + else if (srccolors[j][i] > acutValues[3]) { + alphaenc1[4*j + i] = 4; + alphadist = srccolors[j][i] - (alphause[1] * 4 + alphause[0] * 3) / 7; + } + else if (srccolors[j][i] > acutValues[4]) { + alphaenc1[4*j + i] = 5; + alphadist = srccolors[j][i] - (alphause[1] * 3 + alphause[0] * 4) / 7; + } + else if (srccolors[j][i] > acutValues[5]) { + alphaenc1[4*j + i] = 6; + alphadist = srccolors[j][i] - (alphause[1] * 2 + alphause[0] * 5) / 7; + } + else if (srccolors[j][i] > acutValues[6]) { + alphaenc1[4*j + i] = 7; + alphadist = srccolors[j][i] - (alphause[1] * 1 + alphause[0] * 6) / 7; + } + else { + alphaenc1[4*j + i] = 1; + alphadist = srccolors[j][i] - alphause[0]; + } + alphablockerror1 += alphadist * alphadist; + } + } + +#if RGTC_DEBUG + for (i = 0; i < 16; i++) { + fprintf(stderr, "%d ", alphaenc1[i]); + } + fprintf(stderr, "cutVals "); + for (i = 0; i < 8; i++) { + fprintf(stderr, "%d ", acutValues[i]); + } + fprintf(stderr, "srcVals "); + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + fprintf(stderr, "%d ", srccolors[j][i]); + } + } + fprintf(stderr, "\n"); +#endif + + /* it's not very likely this encoding is better if both alphaabsmin and alphaabsmax + are false but try it anyway */ + if (alphablockerror1 >= 32) { + + /* don't bother if encoding is already very good, this condition should also imply + we have valid alphabase colors which we absolutely need (alphabase[0] <= alphabase[1]) */ + alphablockerror2 = 0; + for (aindex = 0; aindex < 5; aindex++) { + /* don't forget here is always rounded down */ + acutValues[aindex] = (alphabase[0] * (10 - (2*aindex + 1)) + alphabase[1] * (2*aindex + 1)) / 10; + } + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + /* maybe it's overkill to have the most complicated calculation just for the error + calculation which we only need to figure out if encoding1 or encoding2 is better... */ + if (srccolors[j][i] == T_MIN) { + alphaenc2[4*j + i] = 6; + alphadist = 0; + } + else if (srccolors[j][i] == T_MAX) { + alphaenc2[4*j + i] = 7; + alphadist = 0; + } + else if (srccolors[j][i] <= acutValues[0]) { + alphaenc2[4*j + i] = 0; + alphadist = srccolors[j][i] - alphabase[0]; + } + else if (srccolors[j][i] <= acutValues[1]) { + alphaenc2[4*j + i] = 2; + alphadist = srccolors[j][i] - (alphabase[0] * 4 + alphabase[1] * 1) / 5; + } + else if (srccolors[j][i] <= acutValues[2]) { + alphaenc2[4*j + i] = 3; + alphadist = srccolors[j][i] - (alphabase[0] * 3 + alphabase[1] * 2) / 5; + } + else if (srccolors[j][i] <= acutValues[3]) { + alphaenc2[4*j + i] = 4; + alphadist = srccolors[j][i] - (alphabase[0] * 2 + alphabase[1] * 3) / 5; + } + else if (srccolors[j][i] <= acutValues[4]) { + alphaenc2[4*j + i] = 5; + alphadist = srccolors[j][i] - (alphabase[0] * 1 + alphabase[1] * 4) / 5; + } + else { + alphaenc2[4*j + i] = 1; + alphadist = srccolors[j][i] - alphabase[1]; + } + alphablockerror2 += alphadist * alphadist; + } + } + + + /* skip this if the error is already very small + this encoding is MUCH better on average than #2 though, but expensive! */ + if ((alphablockerror2 > 96) && (alphablockerror1 > 96)) { + GLshort blockerrlin1 = 0; + GLshort blockerrlin2 = 0; + TYPE nralphainrangelow = 0; + TYPE nralphainrangehigh = 0; + alphatest[0] = 0xff; + alphatest[1] = 0x0; + /* if we have large range it's likely there are values close to 0/255, try to map them to 0/255 */ + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + if ((srccolors[j][i] > alphatest[1]) && (srccolors[j][i] < (T_MAX -(alphabase[1] - alphabase[0]) / 28))) + alphatest[1] = srccolors[j][i]; + if ((srccolors[j][i] < alphatest[0]) && (srccolors[j][i] > (alphabase[1] - alphabase[0]) / 28)) + alphatest[0] = srccolors[j][i]; + } + } + /* shouldn't happen too often, don't really care about those degenerated cases */ + if (alphatest[1] <= alphatest[0]) { + alphatest[0] = 1; + alphatest[1] = 254; + } + for (aindex = 0; aindex < 5; aindex++) { + /* don't forget here is always rounded down */ + acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; + } + + /* find the "average" difference between the alpha values and the next encoded value. + This is then used to calculate new base values. + Should there be some weighting, i.e. those values closer to alphatest[x] have more weight, + since they will see more improvement, and also because the values in the middle are somewhat + likely to get no improvement at all (because the base values might move in different directions)? + OTOH it would mean the values in the middle are even less likely to get an improvement + */ + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + if (srccolors[j][i] <= alphatest[0] / 2) { + } + else if (srccolors[j][i] > ((T_MAX + alphatest[1]) / 2)) { + } + else if (srccolors[j][i] <= acutValues[0]) { + blockerrlin1 += (srccolors[j][i] - alphatest[0]); + nralphainrangelow += 1; + } + else if (srccolors[j][i] <= acutValues[1]) { + blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); + blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); + nralphainrangelow += 1; + nralphainrangehigh += 1; + } + else if (srccolors[j][i] <= acutValues[2]) { + blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); + blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); + nralphainrangelow += 1; + nralphainrangehigh += 1; + } + else if (srccolors[j][i] <= acutValues[3]) { + blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); + blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); + nralphainrangelow += 1; + nralphainrangehigh += 1; + } + else if (srccolors[j][i] <= acutValues[4]) { + blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); + blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); + nralphainrangelow += 1; + nralphainrangehigh += 1; + } + else { + blockerrlin2 += (srccolors[j][i] - alphatest[1]); + nralphainrangehigh += 1; + } + } + } + /* shouldn't happen often, needed to avoid div by zero */ + if (nralphainrangelow == 0) nralphainrangelow = 1; + if (nralphainrangehigh == 0) nralphainrangehigh = 1; + alphatest[0] = alphatest[0] + (blockerrlin1 / nralphainrangelow); +#if RGTC_DEBUG + fprintf(stderr, "block err lin low %d, nr %d\n", blockerrlin1, nralphainrangelow); + fprintf(stderr, "block err lin high %d, nr %d\n", blockerrlin2, nralphainrangehigh); +#endif + /* again shouldn't really happen often... */ + if (alphatest[0] < T_MIN) { + alphatest[0] = T_MIN; + } + alphatest[1] = alphatest[1] + (blockerrlin2 / nralphainrangehigh); + if (alphatest[1] > T_MAX) { + alphatest[1] = T_MIN; + } + + alphablockerror3 = 0; + for (aindex = 0; aindex < 5; aindex++) { + /* don't forget here is always rounded down */ + acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; + } + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + /* maybe it's overkill to have the most complicated calculation just for the error + calculation which we only need to figure out if encoding1 or encoding2 is better... */ + if (srccolors[j][i] <= alphatest[0] / 2) { + alphaenc3[4*j + i] = 6; + alphadist = srccolors[j][i]; + } + else if (srccolors[j][i] > ((T_MAX + alphatest[1]) / 2)) { + alphaenc3[4*j + i] = 7; + alphadist = T_MAX - srccolors[j][i]; + } + else if (srccolors[j][i] <= acutValues[0]) { + alphaenc3[4*j + i] = 0; + alphadist = srccolors[j][i] - alphatest[0]; + } + else if (srccolors[j][i] <= acutValues[1]) { + alphaenc3[4*j + i] = 2; + alphadist = srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5; + } + else if (srccolors[j][i] <= acutValues[2]) { + alphaenc3[4*j + i] = 3; + alphadist = srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5; + } + else if (srccolors[j][i] <= acutValues[3]) { + alphaenc3[4*j + i] = 4; + alphadist = srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5; + } + else if (srccolors[j][i] <= acutValues[4]) { + alphaenc3[4*j + i] = 5; + alphadist = srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5; + } + else { + alphaenc3[4*j + i] = 1; + alphadist = srccolors[j][i] - alphatest[1]; + } + alphablockerror3 += alphadist * alphadist; + } + } + } + } + /* write the alpha values and encoding back. */ + if ((alphablockerror1 <= alphablockerror2) && (alphablockerror1 <= alphablockerror3)) { +#if RGTC_DEBUG + if (alphablockerror1 > 96) fprintf(stderr, "enc1 used, error %d\n", alphablockerror1); +#endif + TAG(write_rgtc_encoded_channel)( blkaddr, alphause[1], alphause[0], alphaenc1 ); + } + else if (alphablockerror2 <= alphablockerror3) { +#if RGTC_DEBUG + if (alphablockerror2 > 96) fprintf(stderr, "enc2 used, error %d\n", alphablockerror2); +#endif + TAG(write_rgtc_encoded_channel)( blkaddr, alphabase[0], alphabase[1], alphaenc2 ); + } + else { +#if RGTC_DEBUG + fprintf(stderr, "enc3 used, error %d\n", alphablockerror3); +#endif + TAG(write_rgtc_encoded_channel)( blkaddr, (TYPE)alphatest[0], (TYPE)alphatest[1], alphaenc3 ); + } +} diff --git a/mesalib/src/mesa/main/texgetimage.c b/mesalib/src/mesa/main/texgetimage.c index c3f7d3c32..21d9140c5 100644 --- a/mesalib/src/mesa/main/texgetimage.c +++ b/mesalib/src/mesa/main/texgetimage.c @@ -1,917 +1,918 @@ -/* - * Mesa 3-D graphics library - * Version: 7.7 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * Copyright (c) 2009 VMware, Inc. - * - * 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. - */ - - -/** - * Code for glGetTexImage() and glGetCompressedTexImage(). - */ - - -#include "glheader.h" -#include "bufferobj.h" -#include "enums.h" -#include "context.h" -#include "formats.h" -#include "image.h" -#include "mfeatures.h" -#include "mtypes.h" -#include "pack.h" -#include "texgetimage.h" -#include "teximage.h" - - - -/** - * Can the given type represent negative values? - */ -static INLINE GLboolean -type_with_negative_values(GLenum type) -{ - switch (type) { - case GL_BYTE: - case GL_SHORT: - case GL_INT: - case GL_FLOAT: - case GL_HALF_FLOAT_ARB: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * glGetTexImage for color index pixels. - */ -static void -get_tex_color_index(struct gl_context *ctx, GLuint dimensions, - GLenum format, GLenum type, GLvoid *pixels, - const struct gl_texture_image *texImage) -{ - const GLint width = texImage->Width; - const GLint height = texImage->Height; - const GLint depth = texImage->Depth; - const GLuint indexBits = - _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT); - const GLbitfield transferOps = 0x0; - GLint img, row, col; - - for (img = 0; img < depth; img++) { - for (row = 0; row < height; row++) { - GLuint indexRow[MAX_WIDTH] = { 0 }; - void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, - width, height, format, type, - img, row, 0); - assert(dest); - - if (indexBits == 8) { - const GLubyte *src = (const GLubyte *) texImage->Data; - src += width * (img * texImage->Height + row); - for (col = 0; col < width; col++) { - indexRow[col] = src[col]; - } - } - else if (indexBits == 16) { - const GLushort *src = (const GLushort *) texImage->Data; - src += width * (img * texImage->Height + row); - for (col = 0; col < width; col++) { - indexRow[col] = src[col]; - } - } - else { - _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage"); - } - _mesa_pack_index_span(ctx, width, type, dest, - indexRow, &ctx->Pack, transferOps); - } - } -} - - -/** - * glGetTexImage for depth/Z pixels. - */ -static void -get_tex_depth(struct gl_context *ctx, GLuint dimensions, - GLenum format, GLenum type, GLvoid *pixels, - const struct gl_texture_image *texImage) -{ - const GLint width = texImage->Width; - const GLint height = texImage->Height; - const GLint depth = texImage->Depth; - GLint img, row, col; - GLfloat *depthRow = (GLfloat *) malloc(width * sizeof(GLfloat)); - - if (!depthRow) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); - return; - } - - for (img = 0; img < depth; img++) { - for (row = 0; row < height; row++) { - void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, - width, height, format, type, - img, row, 0); - assert(dest); - - for (col = 0; col < width; col++) { - texImage->FetchTexelf(texImage, col, row, img, depthRow + col); - } - _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack); - } - } - - free(depthRow); -} - - -/** - * glGetTexImage for depth/stencil pixels. - */ -static void -get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions, - GLenum format, GLenum type, GLvoid *pixels, - const struct gl_texture_image *texImage) -{ - const GLint width = texImage->Width; - const GLint height = texImage->Height; - const GLint depth = texImage->Depth; - const GLuint *src = (const GLuint *) texImage->Data; - GLint img, row; - - for (img = 0; img < depth; img++) { - for (row = 0; row < height; row++) { - void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, - width, height, format, type, - img, row, 0); - memcpy(dest, src, width * sizeof(GLuint)); - if (ctx->Pack.SwapBytes) { - _mesa_swap4((GLuint *) dest, width); - } - - src += width * row + width * height * img; - } - } -} - - -/** - * glGetTexImage for YCbCr pixels. - */ -static void -get_tex_ycbcr(struct gl_context *ctx, GLuint dimensions, - GLenum format, GLenum type, GLvoid *pixels, - const struct gl_texture_image *texImage) -{ - const GLint width = texImage->Width; - const GLint height = texImage->Height; - const GLint depth = texImage->Depth; - const GLint rowstride = texImage->RowStride; - const GLushort *src = (const GLushort *) texImage->Data; - GLint img, row; - - for (img = 0; img < depth; img++) { - for (row = 0; row < height; row++) { - void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, - width, height, format, type, - img, row, 0); - memcpy(dest, src, width * sizeof(GLushort)); - - /* check for byte swapping */ - if ((texImage->TexFormat == MESA_FORMAT_YCBCR - && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || - (texImage->TexFormat == MESA_FORMAT_YCBCR_REV - && type == GL_UNSIGNED_SHORT_8_8_MESA)) { - if (!ctx->Pack.SwapBytes) - _mesa_swap2((GLushort *) dest, width); - } - else if (ctx->Pack.SwapBytes) { - _mesa_swap2((GLushort *) dest, width); - } - - src += rowstride; - } - } -} - - -#if FEATURE_EXT_texture_sRGB - - -/** - * Convert a float value from linear space to a - * non-linear sRGB value in [0, 255]. - * Not terribly efficient. - */ -static INLINE GLfloat -linear_to_nonlinear(GLfloat cl) -{ - /* can't have values outside [0, 1] */ - GLfloat cs; - if (cl < 0.0031308f) { - cs = 12.92f * cl; - } - else { - cs = (GLfloat)(1.055 * pow(cl, 0.41666) - 0.055); - } - return cs; -} - - -/** - * glGetTexImagefor sRGB pixels; - */ -static void -get_tex_srgb(struct gl_context *ctx, GLuint dimensions, - GLenum format, GLenum type, GLvoid *pixels, - const struct gl_texture_image *texImage) -{ - const GLint width = texImage->Width; - const GLint height = texImage->Height; - const GLint depth = texImage->Depth; - const GLbitfield transferOps = 0x0; - GLint img, row; - GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat)); - - if (!rgba) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); - return; - } - - for (img = 0; img < depth; img++) { - for (row = 0; row < height; row++) { - void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, - width, height, format, type, - img, row, 0); - - GLint col; - - /* convert row to RGBA format */ - for (col = 0; col < width; col++) { - texImage->FetchTexelf(texImage, col, row, img, rgba[col]); - if (texImage->_BaseFormat == GL_LUMINANCE) { - rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); - rgba[col][GCOMP] = 0.0; - rgba[col][BCOMP] = 0.0; - } - else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { - rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); - rgba[col][GCOMP] = 0.0; - rgba[col][BCOMP] = 0.0; - } - else if (texImage->_BaseFormat == GL_RGB || - texImage->_BaseFormat == GL_RGBA) { - rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); - rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]); - rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]); - } - } - _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, - format, type, dest, - &ctx->Pack, transferOps); - } - } - - free(rgba); -} - - -#else /* FEATURE_EXT_texture_sRGB */ - - -static INLINE void -get_tex_srgb(struct gl_context *ctx, GLuint dimensions, - GLenum format, GLenum type, GLvoid *pixels, - const struct gl_texture_image *texImage) -{ - ASSERT_NO_FEATURE(); -} - - -#endif /* FEATURE_EXT_texture_sRGB */ - - -/** - * glGetTexImagefor RGBA, Luminance, etc. pixels. - * This is the slow way since we use texture sampling. - */ -static void -get_tex_rgba(struct gl_context *ctx, GLuint dimensions, - GLenum format, GLenum type, GLvoid *pixels, - const struct gl_texture_image *texImage) -{ - const GLint width = texImage->Width; - const GLint height = texImage->Height; - const GLint depth = texImage->Depth; - /* Normally, no pixel transfer ops are performed during glGetTexImage. - * The only possible exception is component clamping to [0,1]. - */ - GLbitfield transferOps = 0x0; - GLint img, row; - GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat)); - - if (!rgba) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); - return; - } - - for (img = 0; img < depth; img++) { - for (row = 0; row < height; row++) { - void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, - width, height, format, type, - img, row, 0); - GLint col; - GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); - - /* clamp does not apply to GetTexImage (final conversion)? - * Looks like we need clamp though when going from format - * containing negative values to unsigned format. - */ - if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) { - transferOps |= IMAGE_CLAMP_BIT; - } - else if (!type_with_negative_values(type) && - (dataType == GL_FLOAT || - dataType == GL_SIGNED_NORMALIZED)) { - transferOps |= IMAGE_CLAMP_BIT; - } - - for (col = 0; col < width; col++) { - texImage->FetchTexelf(texImage, col, row, img, rgba[col]); - if (texImage->_BaseFormat == GL_ALPHA) { - rgba[col][RCOMP] = 0.0F; - rgba[col][GCOMP] = 0.0F; - rgba[col][BCOMP] = 0.0F; - } - else if (texImage->_BaseFormat == GL_LUMINANCE) { - rgba[col][GCOMP] = 0.0F; - rgba[col][BCOMP] = 0.0F; - rgba[col][ACOMP] = 1.0F; - } - else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { - rgba[col][GCOMP] = 0.0F; - rgba[col][BCOMP] = 0.0F; - } - else if (texImage->_BaseFormat == GL_INTENSITY) { - rgba[col][GCOMP] = 0.0F; - rgba[col][BCOMP] = 0.0F; - rgba[col][ACOMP] = 1.0F; - } - } - _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, - format, type, dest, - &ctx->Pack, transferOps); - } - } - - free(rgba); -} - - -/** - * Try to do glGetTexImage() with simple memcpy(). - * \return GL_TRUE if done, GL_FALSE otherwise - */ -static GLboolean -get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, GLvoid *pixels, - const struct gl_texture_object *texObj, - const struct gl_texture_image *texImage) -{ - GLboolean memCopy = GL_FALSE; - - /* Texture image should have been mapped already */ - assert(texImage->Data); - - /* - * Check if the src/dst formats are compatible. - * Also note that GL's pixel transfer ops don't apply to glGetTexImage() - * so we don't have to worry about those. - * XXX more format combinations could be supported here. - */ - if ((texObj->Target == GL_TEXTURE_1D || - texObj->Target == GL_TEXTURE_2D || - texObj->Target == GL_TEXTURE_RECTANGLE || - (texObj->Target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && - texObj->Target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) { - if (texImage->TexFormat == MESA_FORMAT_ARGB8888 && - format == GL_BGRA && - type == GL_UNSIGNED_BYTE && - !ctx->Pack.SwapBytes && - _mesa_little_endian()) { - memCopy = GL_TRUE; - } - else if (texImage->TexFormat == MESA_FORMAT_AL88 && - format == GL_LUMINANCE_ALPHA && - type == GL_UNSIGNED_BYTE && - !ctx->Pack.SwapBytes && - _mesa_little_endian()) { - memCopy = GL_TRUE; - } - else if (texImage->TexFormat == MESA_FORMAT_L8 && - format == GL_LUMINANCE && - type == GL_UNSIGNED_BYTE) { - memCopy = GL_TRUE; - } - else if (texImage->TexFormat == MESA_FORMAT_L16 && - format == GL_LUMINANCE && - type == GL_UNSIGNED_SHORT) { - memCopy = GL_TRUE; - } - else if (texImage->TexFormat == MESA_FORMAT_A8 && - format == GL_ALPHA && - type == GL_UNSIGNED_BYTE) { - memCopy = GL_TRUE; - } - else if (texImage->TexFormat == MESA_FORMAT_A16 && - format == GL_ALPHA && - type == GL_UNSIGNED_SHORT) { - memCopy = GL_TRUE; - } - } - - if (memCopy) { - const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat); - const GLuint bytesPerRow = texImage->Width * bpp; - GLubyte *dst = - _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width, - texImage->Height, format, type, 0, 0); - const GLint dstRowStride = - _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type); - const GLubyte *src = texImage->Data; - const GLint srcRowStride = texImage->RowStride * bpp; - GLuint row; - - if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { - memcpy(dst, src, bytesPerRow * texImage->Height); - } - else { - for (row = 0; row < texImage->Height; row++) { - memcpy(dst, src, bytesPerRow); - dst += dstRowStride; - src += srcRowStride; - } - } - } - - return memCopy; -} - - -/** - * This is the software fallback for Driver.GetTexImage(). - * All error checking will have been done before this routine is called. - * The texture image must be mapped. - */ -void -_mesa_get_teximage(struct gl_context *ctx, GLenum target, GLint level, - GLenum format, GLenum type, GLvoid *pixels, - struct gl_texture_object *texObj, - struct gl_texture_image *texImage) -{ - GLuint dimensions; - - /* If we get here, the texture image should be mapped */ - assert(texImage->Data); - - switch (target) { - case GL_TEXTURE_1D: - dimensions = 1; - break; - case GL_TEXTURE_3D: - dimensions = 3; - break; - default: - dimensions = 2; - } - - if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { - /* Packing texture image into a PBO. - * Map the (potentially) VRAM-based buffer into our process space so - * we can write into it with the code below. - * A hardware driver might use a sophisticated blit to move the - * texture data to the PBO if the PBO is in VRAM along with the texture. - */ - GLubyte *buf = (GLubyte *) - ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, - GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); - if (!buf) { - /* out of memory or other unexpected error */ - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)"); - return; - } - /* was an offset into the PBO. - * Now make it a real, client-side pointer inside the mapped region. - */ - pixels = ADD_POINTERS(buf, pixels); - } - - if (get_tex_memcpy(ctx, format, type, pixels, texObj, texImage)) { - /* all done */ - } - else if (format == GL_COLOR_INDEX) { - get_tex_color_index(ctx, dimensions, format, type, pixels, texImage); - } - else if (format == GL_DEPTH_COMPONENT) { - get_tex_depth(ctx, dimensions, format, type, pixels, texImage); - } - else if (format == GL_DEPTH_STENCIL_EXT) { - get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage); - } - else if (format == GL_YCBCR_MESA) { - get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage); - } - else if (_mesa_get_format_color_encoding(texImage->TexFormat) == GL_SRGB) { - get_tex_srgb(ctx, dimensions, format, type, pixels, texImage); - } - else { - get_tex_rgba(ctx, dimensions, format, type, pixels, texImage); - } - - if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, - ctx->Pack.BufferObj); - } -} - - - -/** - * This is the software fallback for Driver.GetCompressedTexImage(). - * All error checking will have been done before this routine is called. - */ -void -_mesa_get_compressed_teximage(struct gl_context *ctx, GLenum target, GLint level, - GLvoid *img, - struct gl_texture_object *texObj, - struct gl_texture_image *texImage) -{ - const GLuint row_stride = _mesa_format_row_stride(texImage->TexFormat, - texImage->Width); - const GLuint row_stride_stored = _mesa_format_row_stride(texImage->TexFormat, - texImage->RowStride); - GLuint i; - - if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { - /* pack texture image into a PBO */ - GLubyte *buf = (GLubyte *) - ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, - GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); - if (!buf) { - /* out of memory or other unexpected error */ - _mesa_error(ctx, GL_OUT_OF_MEMORY, - "glGetCompresssedTexImage(map PBO failed)"); - return; - } - img = ADD_POINTERS(buf, img); - } - - /* no pixelstore or pixel transfer, but respect stride */ - - if (row_stride == row_stride_stored) { - const GLuint size = _mesa_format_image_size(texImage->TexFormat, - texImage->Width, - texImage->Height, - texImage->Depth); - memcpy(img, texImage->Data, size); - } - else { - GLuint bw, bh; - _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); - for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) { - memcpy((GLubyte *)img + i * row_stride, - (GLubyte *)texImage->Data + i * row_stride_stored, - row_stride); - } - } - - if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, - ctx->Pack.BufferObj); - } -} - - - -/** - * Do error checking for a glGetTexImage() call. - * \return GL_TRUE if any error, GL_FALSE if no errors. - */ -static GLboolean -getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, - GLenum format, GLenum type, GLvoid *pixels ) -{ - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - const GLint maxLevels = _mesa_max_texture_levels(ctx, target); - GLenum baseFormat; - - if (maxLevels == 0) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target); - return GL_TRUE; - } - - if (level < 0 || level >= maxLevels) { - _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" ); - return GL_TRUE; - } - - if (_mesa_sizeof_packed_type(type) <= 0) { - _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" ); - return GL_TRUE; - } - - if (_mesa_components_in_format(format) <= 0 || - format == GL_STENCIL_INDEX) { - _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" ); - return GL_TRUE; - } - - if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); - return GL_TRUE; - } - - if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); - return GL_TRUE; - } - - if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); - return GL_TRUE; - } - - if (!ctx->Extensions.EXT_packed_depth_stencil - && _mesa_is_depthstencil_format(format)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); - return GL_TRUE; - } - - if (!ctx->Extensions.ATI_envmap_bumpmap - && _mesa_is_dudv_format(format)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); - return GL_TRUE; - } - - texObj = _mesa_get_current_tex_object(ctx, target); - - if (!texObj || _mesa_is_proxy_texture(target)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); - return GL_TRUE; - } - - texImage = _mesa_select_tex_image(ctx, texObj, target, level); - if (!texImage) { - /* out of memory */ - return GL_TRUE; - } - - baseFormat = _mesa_get_format_base_format(texImage->TexFormat); - - /* Make sure the requested image format is compatible with the - * texture's format. Note that a color index texture can be converted - * to RGBA so that combo is allowed. - */ - if (_mesa_is_color_format(format) - && !_mesa_is_color_format(baseFormat) - && !_mesa_is_index_format(baseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return GL_TRUE; - } - else if (_mesa_is_index_format(format) - && !_mesa_is_index_format(baseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return GL_TRUE; - } - else if (_mesa_is_depth_format(format) - && !_mesa_is_depth_format(baseFormat) - && !_mesa_is_depthstencil_format(baseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return GL_TRUE; - } - else if (_mesa_is_ycbcr_format(format) - && !_mesa_is_ycbcr_format(baseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return GL_TRUE; - } - else if (_mesa_is_depthstencil_format(format) - && !_mesa_is_depthstencil_format(baseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return GL_TRUE; - } - else if (_mesa_is_dudv_format(format) - && !_mesa_is_dudv_format(baseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return GL_TRUE; - } - - if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { - /* packing texture image into a PBO */ - const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; - if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, - texImage->Height, texImage->Depth, - format, type, pixels)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetTexImage(out of bounds PBO write)"); - return GL_TRUE; - } - - /* PBO should not be mapped */ - if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetTexImage(PBO is mapped)"); - return GL_TRUE; - } - } - - return GL_FALSE; -} - - - -/** - * Get texture image. Called by glGetTexImage. - * - * \param target texture target. - * \param level image level. - * \param format pixel data format for returned image. - * \param type pixel data type for returned image. - * \param pixels returned pixel data. - */ -void GLAPIENTRY -_mesa_GetTexImage( GLenum target, GLint level, GLenum format, - GLenum type, GLvoid *pixels ) -{ - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (getteximage_error_check(ctx, target, level, format, type, pixels)) { - return; - } - - if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) { - /* not an error, do nothing */ - return; - } - - texObj = _mesa_get_current_tex_object(ctx, target); - texImage = _mesa_select_tex_image(ctx, texObj, target, level); - - if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { - _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d," - " dstFmt=0x%x, dstType=0x%x\n", - texObj->Name, - _mesa_get_format_name(texImage->TexFormat), - texImage->Width, texImage->Height, - format, type); - } - - _mesa_lock_texture(ctx, texObj); - { - ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels, - texObj, texImage); - } - _mesa_unlock_texture(ctx, texObj); -} - - - -/** - * Do error checking for a glGetCompressedTexImage() call. - * \return GL_TRUE if any error, GL_FALSE if no errors. - */ -static GLboolean -getcompressedteximage_error_check(struct gl_context *ctx, GLenum target, - GLint level, GLvoid *img) -{ - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - const GLint maxLevels = _mesa_max_texture_levels(ctx, target); - - if (maxLevels == 0) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)", - target); - return GL_TRUE; - } - - if (level < 0 || level >= maxLevels) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetCompressedTexImageARB(bad level = %d)", level); - return GL_TRUE; - } - - if (_mesa_is_proxy_texture(target)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetCompressedTexImageARB(bad target = %s)", - _mesa_lookup_enum_by_nr(target)); - return GL_TRUE; - } - - texObj = _mesa_get_current_tex_object(ctx, target); - if (!texObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); - return GL_TRUE; - } - - texImage = _mesa_select_tex_image(ctx, texObj, target, level); - - if (!texImage) { - /* probably invalid mipmap level */ - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetCompressedTexImageARB(level)"); - return GL_TRUE; - } - - if (!_mesa_is_format_compressed(texImage->TexFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetCompressedTexImageARB(texture is not compressed)"); - return GL_TRUE; - } - - if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { - GLuint compressedSize; - - /* make sure PBO is not mapped */ - if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetCompressedTexImage(PBO is mapped)"); - return GL_TRUE; - } - - compressedSize = _mesa_format_image_size(texImage->TexFormat, - texImage->Width, - texImage->Height, - texImage->Depth); - - /* do bounds checking on PBO write */ - if ((const GLubyte *) img + compressedSize > - (const GLubyte *) ctx->Pack.BufferObj->Size) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetCompressedTexImage(out of bounds PBO write)"); - return GL_TRUE; - } - } - - return GL_FALSE; -} - - -void GLAPIENTRY -_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img) -{ - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (getcompressedteximage_error_check(ctx, target, level, img)) { - return; - } - - if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) { - /* not an error, do nothing */ - return; - } - - texObj = _mesa_get_current_tex_object(ctx, target); - texImage = _mesa_select_tex_image(ctx, texObj, target, level); - - if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { - _mesa_debug(ctx, - "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n", - texObj->Name, - _mesa_get_format_name(texImage->TexFormat), - texImage->Width, texImage->Height); - } - - _mesa_lock_texture(ctx, texObj); - { - ctx->Driver.GetCompressedTexImage(ctx, target, level, img, - texObj, texImage); - } - _mesa_unlock_texture(ctx, texObj); -} +/* + * Mesa 3-D graphics library + * Version: 7.7 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (c) 2009 VMware, Inc. + * + * 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. + */ + + +/** + * Code for glGetTexImage() and glGetCompressedTexImage(). + */ + + +#include "glheader.h" +#include "bufferobj.h" +#include "enums.h" +#include "context.h" +#include "formats.h" +#include "image.h" +#include "mfeatures.h" +#include "mtypes.h" +#include "pack.h" +#include "pbo.h" +#include "texgetimage.h" +#include "teximage.h" + + + +/** + * Can the given type represent negative values? + */ +static INLINE GLboolean +type_with_negative_values(GLenum type) +{ + switch (type) { + case GL_BYTE: + case GL_SHORT: + case GL_INT: + case GL_FLOAT: + case GL_HALF_FLOAT_ARB: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * glGetTexImage for color index pixels. + */ +static void +get_tex_color_index(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_image *texImage) +{ + const GLint width = texImage->Width; + const GLint height = texImage->Height; + const GLint depth = texImage->Depth; + const GLuint indexBits = + _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT); + const GLbitfield transferOps = 0x0; + GLint img, row, col; + + for (img = 0; img < depth; img++) { + for (row = 0; row < height; row++) { + GLuint indexRow[MAX_WIDTH] = { 0 }; + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + assert(dest); + + if (indexBits == 8) { + const GLubyte *src = (const GLubyte *) texImage->Data; + src += width * (img * texImage->Height + row); + for (col = 0; col < width; col++) { + indexRow[col] = src[col]; + } + } + else if (indexBits == 16) { + const GLushort *src = (const GLushort *) texImage->Data; + src += width * (img * texImage->Height + row); + for (col = 0; col < width; col++) { + indexRow[col] = src[col]; + } + } + else { + _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage"); + } + _mesa_pack_index_span(ctx, width, type, dest, + indexRow, &ctx->Pack, transferOps); + } + } +} + + +/** + * glGetTexImage for depth/Z pixels. + */ +static void +get_tex_depth(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_image *texImage) +{ + const GLint width = texImage->Width; + const GLint height = texImage->Height; + const GLint depth = texImage->Depth; + GLint img, row, col; + GLfloat *depthRow = (GLfloat *) malloc(width * sizeof(GLfloat)); + + if (!depthRow) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); + return; + } + + for (img = 0; img < depth; img++) { + for (row = 0; row < height; row++) { + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + assert(dest); + + for (col = 0; col < width; col++) { + texImage->FetchTexelf(texImage, col, row, img, depthRow + col); + } + _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack); + } + } + + free(depthRow); +} + + +/** + * glGetTexImage for depth/stencil pixels. + */ +static void +get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_image *texImage) +{ + const GLint width = texImage->Width; + const GLint height = texImage->Height; + const GLint depth = texImage->Depth; + const GLuint *src = (const GLuint *) texImage->Data; + GLint img, row; + + for (img = 0; img < depth; img++) { + for (row = 0; row < height; row++) { + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + memcpy(dest, src, width * sizeof(GLuint)); + if (ctx->Pack.SwapBytes) { + _mesa_swap4((GLuint *) dest, width); + } + + src += width * row + width * height * img; + } + } +} + + +/** + * glGetTexImage for YCbCr pixels. + */ +static void +get_tex_ycbcr(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_image *texImage) +{ + const GLint width = texImage->Width; + const GLint height = texImage->Height; + const GLint depth = texImage->Depth; + const GLint rowstride = texImage->RowStride; + const GLushort *src = (const GLushort *) texImage->Data; + GLint img, row; + + for (img = 0; img < depth; img++) { + for (row = 0; row < height; row++) { + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + memcpy(dest, src, width * sizeof(GLushort)); + + /* check for byte swapping */ + if ((texImage->TexFormat == MESA_FORMAT_YCBCR + && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || + (texImage->TexFormat == MESA_FORMAT_YCBCR_REV + && type == GL_UNSIGNED_SHORT_8_8_MESA)) { + if (!ctx->Pack.SwapBytes) + _mesa_swap2((GLushort *) dest, width); + } + else if (ctx->Pack.SwapBytes) { + _mesa_swap2((GLushort *) dest, width); + } + + src += rowstride; + } + } +} + + +#if FEATURE_EXT_texture_sRGB + + +/** + * Convert a float value from linear space to a + * non-linear sRGB value in [0, 255]. + * Not terribly efficient. + */ +static INLINE GLfloat +linear_to_nonlinear(GLfloat cl) +{ + /* can't have values outside [0, 1] */ + GLfloat cs; + if (cl < 0.0031308f) { + cs = 12.92f * cl; + } + else { + cs = (GLfloat)(1.055 * pow(cl, 0.41666) - 0.055); + } + return cs; +} + + +/** + * glGetTexImagefor sRGB pixels; + */ +static void +get_tex_srgb(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_image *texImage) +{ + const GLint width = texImage->Width; + const GLint height = texImage->Height; + const GLint depth = texImage->Depth; + const GLbitfield transferOps = 0x0; + GLint img, row; + GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat)); + + if (!rgba) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); + return; + } + + for (img = 0; img < depth; img++) { + for (row = 0; row < height; row++) { + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + + GLint col; + + /* convert row to RGBA format */ + for (col = 0; col < width; col++) { + texImage->FetchTexelf(texImage, col, row, img, rgba[col]); + if (texImage->_BaseFormat == GL_LUMINANCE) { + rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); + rgba[col][GCOMP] = 0.0; + rgba[col][BCOMP] = 0.0; + } + else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { + rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); + rgba[col][GCOMP] = 0.0; + rgba[col][BCOMP] = 0.0; + } + else if (texImage->_BaseFormat == GL_RGB || + texImage->_BaseFormat == GL_RGBA) { + rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); + rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]); + rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]); + } + } + _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, + format, type, dest, + &ctx->Pack, transferOps); + } + } + + free(rgba); +} + + +#else /* FEATURE_EXT_texture_sRGB */ + + +static INLINE void +get_tex_srgb(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_image *texImage) +{ + ASSERT_NO_FEATURE(); +} + + +#endif /* FEATURE_EXT_texture_sRGB */ + + +/** + * glGetTexImagefor RGBA, Luminance, etc. pixels. + * This is the slow way since we use texture sampling. + */ +static void +get_tex_rgba(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_image *texImage) +{ + const GLint width = texImage->Width; + const GLint height = texImage->Height; + const GLint depth = texImage->Depth; + /* Normally, no pixel transfer ops are performed during glGetTexImage. + * The only possible exception is component clamping to [0,1]. + */ + GLbitfield transferOps = 0x0; + GLint img, row; + GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat)); + + if (!rgba) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); + return; + } + + for (img = 0; img < depth; img++) { + for (row = 0; row < height; row++) { + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + GLint col; + GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); + + /* clamp does not apply to GetTexImage (final conversion)? + * Looks like we need clamp though when going from format + * containing negative values to unsigned format. + */ + if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) { + transferOps |= IMAGE_CLAMP_BIT; + } + else if (!type_with_negative_values(type) && + (dataType == GL_FLOAT || + dataType == GL_SIGNED_NORMALIZED)) { + transferOps |= IMAGE_CLAMP_BIT; + } + + for (col = 0; col < width; col++) { + texImage->FetchTexelf(texImage, col, row, img, rgba[col]); + if (texImage->_BaseFormat == GL_ALPHA) { + rgba[col][RCOMP] = 0.0F; + rgba[col][GCOMP] = 0.0F; + rgba[col][BCOMP] = 0.0F; + } + else if (texImage->_BaseFormat == GL_LUMINANCE) { + rgba[col][GCOMP] = 0.0F; + rgba[col][BCOMP] = 0.0F; + rgba[col][ACOMP] = 1.0F; + } + else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { + rgba[col][GCOMP] = 0.0F; + rgba[col][BCOMP] = 0.0F; + } + else if (texImage->_BaseFormat == GL_INTENSITY) { + rgba[col][GCOMP] = 0.0F; + rgba[col][BCOMP] = 0.0F; + rgba[col][ACOMP] = 1.0F; + } + } + _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, + format, type, dest, + &ctx->Pack, transferOps); + } + } + + free(rgba); +} + + +/** + * Try to do glGetTexImage() with simple memcpy(). + * \return GL_TRUE if done, GL_FALSE otherwise + */ +static GLboolean +get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_object *texObj, + const struct gl_texture_image *texImage) +{ + GLboolean memCopy = GL_FALSE; + + /* Texture image should have been mapped already */ + assert(texImage->Data); + + /* + * Check if the src/dst formats are compatible. + * Also note that GL's pixel transfer ops don't apply to glGetTexImage() + * so we don't have to worry about those. + * XXX more format combinations could be supported here. + */ + if ((texObj->Target == GL_TEXTURE_1D || + texObj->Target == GL_TEXTURE_2D || + texObj->Target == GL_TEXTURE_RECTANGLE || + (texObj->Target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && + texObj->Target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) { + if (texImage->TexFormat == MESA_FORMAT_ARGB8888 && + format == GL_BGRA && + type == GL_UNSIGNED_BYTE && + !ctx->Pack.SwapBytes && + _mesa_little_endian()) { + memCopy = GL_TRUE; + } + else if (texImage->TexFormat == MESA_FORMAT_AL88 && + format == GL_LUMINANCE_ALPHA && + type == GL_UNSIGNED_BYTE && + !ctx->Pack.SwapBytes && + _mesa_little_endian()) { + memCopy = GL_TRUE; + } + else if (texImage->TexFormat == MESA_FORMAT_L8 && + format == GL_LUMINANCE && + type == GL_UNSIGNED_BYTE) { + memCopy = GL_TRUE; + } + else if (texImage->TexFormat == MESA_FORMAT_L16 && + format == GL_LUMINANCE && + type == GL_UNSIGNED_SHORT) { + memCopy = GL_TRUE; + } + else if (texImage->TexFormat == MESA_FORMAT_A8 && + format == GL_ALPHA && + type == GL_UNSIGNED_BYTE) { + memCopy = GL_TRUE; + } + else if (texImage->TexFormat == MESA_FORMAT_A16 && + format == GL_ALPHA && + type == GL_UNSIGNED_SHORT) { + memCopy = GL_TRUE; + } + } + + if (memCopy) { + const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat); + const GLuint bytesPerRow = texImage->Width * bpp; + GLubyte *dst = + _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width, + texImage->Height, format, type, 0, 0); + const GLint dstRowStride = + _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type); + const GLubyte *src = texImage->Data; + const GLint srcRowStride = texImage->RowStride * bpp; + GLuint row; + + if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { + memcpy(dst, src, bytesPerRow * texImage->Height); + } + else { + for (row = 0; row < texImage->Height; row++) { + memcpy(dst, src, bytesPerRow); + dst += dstRowStride; + src += srcRowStride; + } + } + } + + return memCopy; +} + + +/** + * This is the software fallback for Driver.GetTexImage(). + * All error checking will have been done before this routine is called. + * The texture image must be mapped. + */ +void +_mesa_get_teximage(struct gl_context *ctx, GLenum target, GLint level, + GLenum format, GLenum type, GLvoid *pixels, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + GLuint dimensions; + + /* If we get here, the texture image should be mapped */ + assert(texImage->Data); + + switch (target) { + case GL_TEXTURE_1D: + dimensions = 1; + break; + case GL_TEXTURE_3D: + dimensions = 3; + break; + default: + dimensions = 2; + } + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + /* Packing texture image into a PBO. + * Map the (potentially) VRAM-based buffer into our process space so + * we can write into it with the code below. + * A hardware driver might use a sophisticated blit to move the + * texture data to the PBO if the PBO is in VRAM along with the texture. + */ + GLubyte *buf = (GLubyte *) + ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); + if (!buf) { + /* out of memory or other unexpected error */ + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)"); + return; + } + /* was an offset into the PBO. + * Now make it a real, client-side pointer inside the mapped region. + */ + pixels = ADD_POINTERS(buf, pixels); + } + + if (get_tex_memcpy(ctx, format, type, pixels, texObj, texImage)) { + /* all done */ + } + else if (format == GL_COLOR_INDEX) { + get_tex_color_index(ctx, dimensions, format, type, pixels, texImage); + } + else if (format == GL_DEPTH_COMPONENT) { + get_tex_depth(ctx, dimensions, format, type, pixels, texImage); + } + else if (format == GL_DEPTH_STENCIL_EXT) { + get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage); + } + else if (format == GL_YCBCR_MESA) { + get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage); + } + else if (_mesa_get_format_color_encoding(texImage->TexFormat) == GL_SRGB) { + get_tex_srgb(ctx, dimensions, format, type, pixels, texImage); + } + else { + get_tex_rgba(ctx, dimensions, format, type, pixels, texImage); + } + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + ctx->Pack.BufferObj); + } +} + + + +/** + * This is the software fallback for Driver.GetCompressedTexImage(). + * All error checking will have been done before this routine is called. + */ +void +_mesa_get_compressed_teximage(struct gl_context *ctx, GLenum target, GLint level, + GLvoid *img, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + const GLuint row_stride = _mesa_format_row_stride(texImage->TexFormat, + texImage->Width); + const GLuint row_stride_stored = _mesa_format_row_stride(texImage->TexFormat, + texImage->RowStride); + GLuint i; + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + /* pack texture image into a PBO */ + GLubyte *buf = (GLubyte *) + ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); + if (!buf) { + /* out of memory or other unexpected error */ + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "glGetCompresssedTexImage(map PBO failed)"); + return; + } + img = ADD_POINTERS(buf, img); + } + + /* no pixelstore or pixel transfer, but respect stride */ + + if (row_stride == row_stride_stored) { + const GLuint size = _mesa_format_image_size(texImage->TexFormat, + texImage->Width, + texImage->Height, + texImage->Depth); + memcpy(img, texImage->Data, size); + } + else { + GLuint bw, bh; + _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); + for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) { + memcpy((GLubyte *)img + i * row_stride, + (GLubyte *)texImage->Data + i * row_stride_stored, + row_stride); + } + } + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + ctx->Pack.BufferObj); + } +} + + + +/** + * Do error checking for a glGetTexImage() call. + * \return GL_TRUE if any error, GL_FALSE if no errors. + */ +static GLboolean +getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, + GLenum format, GLenum type, GLvoid *pixels ) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + const GLint maxLevels = _mesa_max_texture_levels(ctx, target); + GLenum baseFormat; + + if (maxLevels == 0) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target); + return GL_TRUE; + } + + if (level < 0 || level >= maxLevels) { + _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" ); + return GL_TRUE; + } + + if (_mesa_sizeof_packed_type(type) <= 0) { + _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" ); + return GL_TRUE; + } + + if (_mesa_components_in_format(format) <= 0 || + format == GL_STENCIL_INDEX) { + _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" ); + return GL_TRUE; + } + + if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); + return GL_TRUE; + } + + if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); + return GL_TRUE; + } + + if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); + return GL_TRUE; + } + + if (!ctx->Extensions.EXT_packed_depth_stencil + && _mesa_is_depthstencil_format(format)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); + return GL_TRUE; + } + + if (!ctx->Extensions.ATI_envmap_bumpmap + && _mesa_is_dudv_format(format)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); + return GL_TRUE; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + + if (!texObj || _mesa_is_proxy_texture(target)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); + return GL_TRUE; + } + + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + if (!texImage) { + /* out of memory */ + return GL_TRUE; + } + + baseFormat = _mesa_get_format_base_format(texImage->TexFormat); + + /* Make sure the requested image format is compatible with the + * texture's format. Note that a color index texture can be converted + * to RGBA so that combo is allowed. + */ + if (_mesa_is_color_format(format) + && !_mesa_is_color_format(baseFormat) + && !_mesa_is_index_format(baseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + return GL_TRUE; + } + else if (_mesa_is_index_format(format) + && !_mesa_is_index_format(baseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + return GL_TRUE; + } + else if (_mesa_is_depth_format(format) + && !_mesa_is_depth_format(baseFormat) + && !_mesa_is_depthstencil_format(baseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + return GL_TRUE; + } + else if (_mesa_is_ycbcr_format(format) + && !_mesa_is_ycbcr_format(baseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + return GL_TRUE; + } + else if (_mesa_is_depthstencil_format(format) + && !_mesa_is_depthstencil_format(baseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + return GL_TRUE; + } + else if (_mesa_is_dudv_format(format) + && !_mesa_is_dudv_format(baseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + return GL_TRUE; + } + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + /* packing texture image into a PBO */ + const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; + if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, + texImage->Height, texImage->Depth, + format, type, pixels)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTexImage(out of bounds PBO write)"); + return GL_TRUE; + } + + /* PBO should not be mapped */ + if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTexImage(PBO is mapped)"); + return GL_TRUE; + } + } + + return GL_FALSE; +} + + + +/** + * Get texture image. Called by glGetTexImage. + * + * \param target texture target. + * \param level image level. + * \param format pixel data format for returned image. + * \param type pixel data type for returned image. + * \param pixels returned pixel data. + */ +void GLAPIENTRY +_mesa_GetTexImage( GLenum target, GLint level, GLenum format, + GLenum type, GLvoid *pixels ) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (getteximage_error_check(ctx, target, level, format, type, pixels)) { + return; + } + + if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) { + /* not an error, do nothing */ + return; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { + _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d," + " dstFmt=0x%x, dstType=0x%x\n", + texObj->Name, + _mesa_get_format_name(texImage->TexFormat), + texImage->Width, texImage->Height, + format, type); + } + + _mesa_lock_texture(ctx, texObj); + { + ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels, + texObj, texImage); + } + _mesa_unlock_texture(ctx, texObj); +} + + + +/** + * Do error checking for a glGetCompressedTexImage() call. + * \return GL_TRUE if any error, GL_FALSE if no errors. + */ +static GLboolean +getcompressedteximage_error_check(struct gl_context *ctx, GLenum target, + GLint level, GLvoid *img) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + const GLint maxLevels = _mesa_max_texture_levels(ctx, target); + + if (maxLevels == 0) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)", + target); + return GL_TRUE; + } + + if (level < 0 || level >= maxLevels) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetCompressedTexImageARB(bad level = %d)", level); + return GL_TRUE; + } + + if (_mesa_is_proxy_texture(target)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetCompressedTexImageARB(bad target = %s)", + _mesa_lookup_enum_by_nr(target)); + return GL_TRUE; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + if (!texObj) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); + return GL_TRUE; + } + + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (!texImage) { + /* probably invalid mipmap level */ + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetCompressedTexImageARB(level)"); + return GL_TRUE; + } + + if (!_mesa_is_format_compressed(texImage->TexFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetCompressedTexImageARB(texture is not compressed)"); + return GL_TRUE; + } + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + GLuint compressedSize; + + /* make sure PBO is not mapped */ + if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetCompressedTexImage(PBO is mapped)"); + return GL_TRUE; + } + + compressedSize = _mesa_format_image_size(texImage->TexFormat, + texImage->Width, + texImage->Height, + texImage->Depth); + + /* do bounds checking on PBO write */ + if ((const GLubyte *) img + compressedSize > + (const GLubyte *) ctx->Pack.BufferObj->Size) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetCompressedTexImage(out of bounds PBO write)"); + return GL_TRUE; + } + } + + return GL_FALSE; +} + + +void GLAPIENTRY +_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (getcompressedteximage_error_check(ctx, target, level, img)) { + return; + } + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) { + /* not an error, do nothing */ + return; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { + _mesa_debug(ctx, + "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n", + texObj->Name, + _mesa_get_format_name(texImage->TexFormat), + texImage->Width, texImage->Height); + } + + _mesa_lock_texture(ctx, texObj); + { + ctx->Driver.GetCompressedTexImage(ctx, target, level, img, + texObj, texImage); + } + _mesa_unlock_texture(ctx, texObj); +} diff --git a/mesalib/src/mesa/main/teximage.c b/mesalib/src/mesa/main/teximage.c index ddad16a8e..d4ae6dd69 100644 --- a/mesalib/src/mesa/main/teximage.c +++ b/mesalib/src/mesa/main/teximage.c @@ -1,3500 +1,3504 @@ -/* - * mesa 3-D graphics library - * Version: 7.6 - * - * 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 teximage.c - * Texture image-related functions. - */ - - -#include "glheader.h" -#include "bufferobj.h" -#include "context.h" -#include "enums.h" -#include "fbobject.h" -#include "framebuffer.h" -#include "hash.h" -#include "image.h" -#include "imports.h" -#include "macros.h" -#include "mfeatures.h" -#include "state.h" -#include "texcompress.h" -#include "texfetch.h" -#include "teximage.h" -#include "texstate.h" -#include "texpal.h" -#include "mtypes.h" - - -/** - * State changes which we care about for glCopyTex[Sub]Image() calls. - * In particular, we care about pixel transfer state and buffer state - * (such as glReadBuffer to make sure we read from the right renderbuffer). - */ -#define NEW_COPY_TEX_STATE (_MESA_NEW_TRANSFER_STATE | \ - _NEW_BUFFERS | \ - _NEW_PIXEL) - - - -/** - * We allocate texture memory on 512-byte boundaries so we can use MMX/SSE - * elsewhere. - */ -void * -_mesa_alloc_texmemory(GLsizei bytes) -{ - return _mesa_align_malloc(bytes, 512); -} - - -/** - * Free texture memory allocated with _mesa_alloc_texmemory() - */ -void -_mesa_free_texmemory(void *m) -{ - _mesa_align_free(m); -} - - -/* - * Compute floor(log_base_2(n)). - * If n < 0 return -1. - */ -static int -logbase2( int n ) -{ - GLint i = 1; - GLint log2 = 0; - - if (n < 0) - return -1; - - if (n == 0) - return 0; - - while ( n > i ) { - i *= 2; - log2++; - } - if (i != n) { - return log2 - 1; - } - else { - return log2; - } -} - - - -/** - * Return the simple base format for a given internal texture format. - * For example, given GL_LUMINANCE12_ALPHA4, return GL_LUMINANCE_ALPHA. - * - * \param ctx GL context. - * \param internalFormat the internal texture format token or 1, 2, 3, or 4. - * - * \return the corresponding \u base internal format (GL_ALPHA, GL_LUMINANCE, - * GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA), or -1 if invalid enum. - * - * This is the format which is used during texture application (i.e. the - * texture format and env mode determine the arithmetic used. - * - * XXX this could be static - */ -GLint -_mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) -{ - switch (internalFormat) { - case GL_ALPHA: - case GL_ALPHA4: - case GL_ALPHA8: - case GL_ALPHA12: - case GL_ALPHA16: - return GL_ALPHA; - case 1: - case GL_LUMINANCE: - case GL_LUMINANCE4: - case GL_LUMINANCE8: - case GL_LUMINANCE12: - case GL_LUMINANCE16: - return GL_LUMINANCE; - 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: - return GL_LUMINANCE_ALPHA; - case GL_INTENSITY: - case GL_INTENSITY4: - case GL_INTENSITY8: - case GL_INTENSITY12: - case GL_INTENSITY16: - return GL_INTENSITY; - case 3: - case GL_RGB: - case GL_R3_G3_B2: - case GL_RGB4: - case GL_RGB5: - case GL_RGB8: - case GL_RGB10: - case GL_RGB12: - case GL_RGB16: - return GL_RGB; - case 4: - case GL_RGBA: - case GL_RGBA2: - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGBA8: - case GL_RGB10_A2: - case GL_RGBA12: - case GL_RGBA16: - return GL_RGBA; - default: - ; /* fallthrough */ - } - - if (ctx->Extensions.EXT_texture_format_BGRA8888) { - switch (internalFormat) { - case GL_BGRA_EXT: - return GL_RGBA; - default: - ; /* fallthrough */ - } - } - - if (ctx->Extensions.EXT_paletted_texture) { - switch (internalFormat) { - 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_COLOR_INDEX; - default: - ; /* fallthrough */ - } - } - - if (ctx->Extensions.ARB_depth_texture) { - switch (internalFormat) { - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT24: - case GL_DEPTH_COMPONENT32: - return GL_DEPTH_COMPONENT; - default: - ; /* fallthrough */ - } - } - - switch (internalFormat) { - case GL_COMPRESSED_ALPHA: - return GL_ALPHA; - case GL_COMPRESSED_LUMINANCE: - return GL_LUMINANCE; - case GL_COMPRESSED_LUMINANCE_ALPHA: - return GL_LUMINANCE_ALPHA; - case GL_COMPRESSED_INTENSITY: - return GL_INTENSITY; - case GL_COMPRESSED_RGB: - return GL_RGB; - case GL_COMPRESSED_RGBA: - return GL_RGBA; - default: - ; /* fallthrough */ - } - - if (ctx->Extensions.TDFX_texture_compression_FXT1) { - switch (internalFormat) { - case GL_COMPRESSED_RGB_FXT1_3DFX: - return GL_RGB; - case GL_COMPRESSED_RGBA_FXT1_3DFX: - return GL_RGBA; - default: - ; /* fallthrough */ - } - } - - if (ctx->Extensions.EXT_texture_compression_s3tc) { - switch (internalFormat) { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - return GL_RGB; - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - return GL_RGBA; - default: - ; /* fallthrough */ - } - } - - if (ctx->Extensions.S3_s3tc) { - switch (internalFormat) { - case GL_RGB_S3TC: - case GL_RGB4_S3TC: - return GL_RGB; - case GL_RGBA_S3TC: - case GL_RGBA4_S3TC: - return GL_RGBA; - default: - ; /* fallthrough */ - } - } - - if (ctx->Extensions.MESA_ycbcr_texture) { - if (internalFormat == GL_YCBCR_MESA) - return GL_YCBCR_MESA; - } - - if (ctx->Extensions.ARB_texture_float) { - switch (internalFormat) { - case GL_ALPHA16F_ARB: - case GL_ALPHA32F_ARB: - return GL_ALPHA; - case GL_RGBA16F_ARB: - case GL_RGBA32F_ARB: - return GL_RGBA; - case GL_RGB16F_ARB: - case GL_RGB32F_ARB: - return GL_RGB; - case GL_INTENSITY16F_ARB: - case GL_INTENSITY32F_ARB: - return GL_INTENSITY; - case GL_LUMINANCE16F_ARB: - case GL_LUMINANCE32F_ARB: - return GL_LUMINANCE; - case GL_LUMINANCE_ALPHA16F_ARB: - case GL_LUMINANCE_ALPHA32F_ARB: - return GL_LUMINANCE_ALPHA; - default: - ; /* fallthrough */ - } - } - - if (ctx->Extensions.ATI_envmap_bumpmap) { - switch (internalFormat) { - case GL_DUDV_ATI: - case GL_DU8DV8_ATI: - return GL_DUDV_ATI; - default: - ; /* fallthrough */ - } - } - - if (ctx->Extensions.MESA_texture_signed_rgba) { - switch (internalFormat) { - case GL_RGBA_SNORM: - case GL_RGBA8_SNORM: - return GL_RGBA; - default: - ; /* fallthrough */ - } - } - - if (ctx->Extensions.EXT_packed_depth_stencil) { - switch (internalFormat) { - case GL_DEPTH_STENCIL_EXT: - case GL_DEPTH24_STENCIL8_EXT: - return GL_DEPTH_STENCIL_EXT; - default: - ; /* fallthrough */ - } - } - -#if FEATURE_EXT_texture_sRGB - if (ctx->Extensions.EXT_texture_sRGB) { - switch (internalFormat) { - case GL_SRGB_EXT: - case GL_SRGB8_EXT: - case GL_COMPRESSED_SRGB_EXT: - case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: - return GL_RGB; - case GL_SRGB_ALPHA_EXT: - case GL_SRGB8_ALPHA8_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: - return GL_RGBA; - case GL_SLUMINANCE_ALPHA_EXT: - case GL_SLUMINANCE8_ALPHA8_EXT: - case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT: - return GL_LUMINANCE_ALPHA; - case GL_SLUMINANCE_EXT: - case GL_SLUMINANCE8_EXT: - case GL_COMPRESSED_SLUMINANCE_EXT: - return GL_LUMINANCE; - default: - ; /* fallthrough */ - } - } -#endif /* FEATURE_EXT_texture_sRGB */ - - if (ctx->Extensions.EXT_texture_integer) { - switch (internalFormat) { - case GL_RGBA8UI_EXT: - case GL_RGBA16UI_EXT: - case GL_RGBA32UI_EXT: - case GL_RGBA8I_EXT: - case GL_RGBA16I_EXT: - case GL_RGBA32I_EXT: - return GL_RGBA; - case GL_RGB8UI_EXT: - case GL_RGB16UI_EXT: - case GL_RGB32UI_EXT: - case GL_RGB8I_EXT: - case GL_RGB16I_EXT: - case GL_RGB32I_EXT: - return GL_RGB; - case GL_ALPHA8UI_EXT: - case GL_ALPHA16UI_EXT: - case GL_ALPHA32UI_EXT: - case GL_ALPHA8I_EXT: - case GL_ALPHA16I_EXT: - case GL_ALPHA32I_EXT: - return GL_ALPHA; - case GL_INTENSITY8UI_EXT: - case GL_INTENSITY16UI_EXT: - case GL_INTENSITY32UI_EXT: - case GL_INTENSITY8I_EXT: - case GL_INTENSITY16I_EXT: - case GL_INTENSITY32I_EXT: - return GL_INTENSITY; - case GL_LUMINANCE8UI_EXT: - case GL_LUMINANCE16UI_EXT: - case GL_LUMINANCE32UI_EXT: - case GL_LUMINANCE8I_EXT: - case GL_LUMINANCE16I_EXT: - case GL_LUMINANCE32I_EXT: - return GL_LUMINANCE; - case GL_LUMINANCE_ALPHA8UI_EXT: - case GL_LUMINANCE_ALPHA16UI_EXT: - case GL_LUMINANCE_ALPHA32UI_EXT: - case GL_LUMINANCE_ALPHA8I_EXT: - case GL_LUMINANCE_ALPHA16I_EXT: - case GL_LUMINANCE_ALPHA32I_EXT: - return GL_LUMINANCE_ALPHA; - default: - ; /* fallthrough */ - } - } - - if (ctx->Extensions.ARB_texture_rg) { - switch (internalFormat) { - case GL_R16F: - /* R16F depends on both ARB_half_float_pixel and ARB_texture_float. - */ - if (!ctx->Extensions.ARB_half_float_pixel) - break; - /* FALLTHROUGH */ - case GL_R32F: - if (!ctx->Extensions.ARB_texture_float) - break; - return GL_RED; - case GL_R8I: - case GL_R8UI: - case GL_R16I: - case GL_R16UI: - case GL_R32I: - case GL_R32UI: - if (!ctx->Extensions.EXT_texture_integer) - break; - /* FALLTHROUGH */ - case GL_R8: - case GL_R16: - case GL_RED: - case GL_COMPRESSED_RED: - return GL_RED; - - case GL_RG16F: - /* RG16F depends on both ARB_half_float_pixel and ARB_texture_float. - */ - if (!ctx->Extensions.ARB_half_float_pixel) - break; - /* FALLTHROUGH */ - case GL_RG32F: - if (!ctx->Extensions.ARB_texture_float) - break; - return GL_RG; - case GL_RG8I: - case GL_RG8UI: - case GL_RG16I: - case GL_RG16UI: - case GL_RG32I: - case GL_RG32UI: - if (!ctx->Extensions.EXT_texture_integer) - break; - /* FALLTHROUGH */ - case GL_RG: - case GL_RG8: - case GL_RG16: - case GL_COMPRESSED_RG: - return GL_RG; - default: - ; /* fallthrough */ - } - } - - if (ctx->Extensions.EXT_texture_shared_exponent) { - switch (internalFormat) { - case GL_RGB9_E5_EXT: - return GL_RGB; - default: - ; /* fallthrough */ - } - } - - if (ctx->Extensions.EXT_packed_float) { - switch (internalFormat) { - case GL_R11F_G11F_B10F_EXT: - return GL_RGB; - default: - ; /* fallthrough */ - } - } - - if (ctx->Extensions.ARB_depth_buffer_float) { - switch (internalFormat) { - case GL_DEPTH_COMPONENT32F: - return GL_DEPTH_COMPONENT; - case GL_DEPTH32F_STENCIL8: - return GL_DEPTH_STENCIL; - default: - ; /* fallthrough */ - } - } - - if (ctx->Extensions.ARB_texture_compression_rgtc) { - switch (internalFormat) { - case GL_COMPRESSED_RED_RGTC1: - case GL_COMPRESSED_SIGNED_RED_RGTC1: - return GL_RED; - case GL_COMPRESSED_RG_RGTC2: - case GL_COMPRESSED_SIGNED_RG_RGTC2: - return GL_RG; - default: - ; /* fallthrough */ - } - } - - return -1; /* error */ -} - - -/** - * For cube map faces, return a face index in [0,5]. - * For other targets return 0; - */ -GLuint -_mesa_tex_target_to_face(GLenum target) -{ - if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && - target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) - return (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; - else - return 0; -} - - - -/** - * Store a gl_texture_image pointer in a gl_texture_object structure - * according to the target and level parameters. - * - * \param tObj texture object. - * \param target texture target. - * \param level image level. - * \param texImage texture image. - * - * This was basically prompted by the introduction of cube maps. - */ -void -_mesa_set_tex_image(struct gl_texture_object *tObj, - GLenum target, GLint level, - struct gl_texture_image *texImage) -{ - const GLuint face = _mesa_tex_target_to_face(target); - - ASSERT(tObj); - ASSERT(texImage); - ASSERT(target != GL_TEXTURE_RECTANGLE_NV || level == 0); - - tObj->Image[face][level] = texImage; - - /* Set the 'back' pointer */ - texImage->TexObject = tObj; -} - - -/** - * Allocate a texture image structure. - * - * Called via ctx->Driver.NewTextureImage() unless overriden by a device - * driver. - * - * \return a pointer to gl_texture_image struct with all fields initialized to - * zero. - */ -struct gl_texture_image * -_mesa_new_texture_image( struct gl_context *ctx ) -{ - (void) ctx; - return CALLOC_STRUCT(gl_texture_image); -} - - -/** - * Free texture image data. - * This function is a fallback called via ctx->Driver.FreeTexImageData(). - * - * \param texImage texture image. - * - * Free the texture image data if it's not marked as client data. - */ -void -_mesa_free_texture_image_data(struct gl_context *ctx, - struct gl_texture_image *texImage) -{ - (void) ctx; - - if (texImage->Data && !texImage->IsClientData) { - /* free the old texture data */ - _mesa_free_texmemory(texImage->Data); - } - - texImage->Data = NULL; -} - - -/** - * Free texture image. - * - * \param texImage texture image. - * - * Free the texture image structure and the associated image data. - */ -void -_mesa_delete_texture_image(struct gl_context *ctx, - struct gl_texture_image *texImage) -{ - /* Free texImage->Data and/or any other driver-specific texture - * image storage. - */ - ASSERT(ctx->Driver.FreeTexImageData); - ctx->Driver.FreeTexImageData( ctx, texImage ); - - ASSERT(texImage->Data == NULL); - if (texImage->ImageOffsets) - free(texImage->ImageOffsets); - free(texImage); -} - - -/** - * Test if a target is a proxy target. - * - * \param target texture target. - * - * \return GL_TRUE if the target is a proxy target, GL_FALSE otherwise. - */ -GLboolean -_mesa_is_proxy_texture(GLenum target) -{ - /* NUM_TEXTURE_TARGETS should match number of terms below */ - assert(NUM_TEXTURE_TARGETS == 7); - - return (target == GL_PROXY_TEXTURE_1D || - target == GL_PROXY_TEXTURE_2D || - target == GL_PROXY_TEXTURE_3D || - target == GL_PROXY_TEXTURE_CUBE_MAP_ARB || - target == GL_PROXY_TEXTURE_RECTANGLE_NV || - target == GL_PROXY_TEXTURE_1D_ARRAY_EXT || - target == GL_PROXY_TEXTURE_2D_ARRAY_EXT); -} - - -/** - * Return the proxy target which corresponds to the given texture target - */ -static GLenum -get_proxy_target(GLenum target) -{ - switch (target) { - case GL_TEXTURE_1D: - case GL_PROXY_TEXTURE_1D: - return GL_PROXY_TEXTURE_1D; - case GL_TEXTURE_2D: - case GL_PROXY_TEXTURE_2D: - return GL_PROXY_TEXTURE_2D; - case GL_TEXTURE_3D: - case GL_PROXY_TEXTURE_3D: - return GL_PROXY_TEXTURE_3D; - case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: - case GL_TEXTURE_CUBE_MAP_ARB: - case GL_PROXY_TEXTURE_CUBE_MAP_ARB: - return GL_PROXY_TEXTURE_CUBE_MAP_ARB; - case GL_TEXTURE_RECTANGLE_NV: - case GL_PROXY_TEXTURE_RECTANGLE_NV: - return GL_PROXY_TEXTURE_RECTANGLE_NV; - case GL_TEXTURE_1D_ARRAY_EXT: - case GL_PROXY_TEXTURE_1D_ARRAY_EXT: - return GL_PROXY_TEXTURE_1D_ARRAY_EXT; - case GL_TEXTURE_2D_ARRAY_EXT: - case GL_PROXY_TEXTURE_2D_ARRAY_EXT: - return GL_PROXY_TEXTURE_2D_ARRAY_EXT; - default: - _mesa_problem(NULL, "unexpected target in get_proxy_target()"); - return 0; - } -} - - -/** - * Get the texture object that corresponds to the target of the given - * texture unit. - * - * \param ctx GL context. - * \param texUnit texture unit. - * \param target texture target. - * - * \return pointer to the texture object on success, or NULL on failure. - * - * \sa gl_texture_unit. - */ -struct gl_texture_object * -_mesa_select_tex_object(struct gl_context *ctx, - const struct gl_texture_unit *texUnit, - GLenum target) -{ - const GLboolean arrayTex = (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); - - switch (target) { - case GL_TEXTURE_1D: - return texUnit->CurrentTex[TEXTURE_1D_INDEX]; - case GL_PROXY_TEXTURE_1D: - return ctx->Texture.ProxyTex[TEXTURE_1D_INDEX]; - case GL_TEXTURE_2D: - return texUnit->CurrentTex[TEXTURE_2D_INDEX]; - case GL_PROXY_TEXTURE_2D: - return ctx->Texture.ProxyTex[TEXTURE_2D_INDEX]; - case GL_TEXTURE_3D: - return texUnit->CurrentTex[TEXTURE_3D_INDEX]; - case GL_PROXY_TEXTURE_3D: - return ctx->Texture.ProxyTex[TEXTURE_3D_INDEX]; - case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: - case GL_TEXTURE_CUBE_MAP_ARB: - return ctx->Extensions.ARB_texture_cube_map - ? texUnit->CurrentTex[TEXTURE_CUBE_INDEX] : NULL; - case GL_PROXY_TEXTURE_CUBE_MAP_ARB: - return ctx->Extensions.ARB_texture_cube_map - ? ctx->Texture.ProxyTex[TEXTURE_CUBE_INDEX] : NULL; - case GL_TEXTURE_RECTANGLE_NV: - return ctx->Extensions.NV_texture_rectangle - ? texUnit->CurrentTex[TEXTURE_RECT_INDEX] : NULL; - case GL_PROXY_TEXTURE_RECTANGLE_NV: - return ctx->Extensions.NV_texture_rectangle - ? ctx->Texture.ProxyTex[TEXTURE_RECT_INDEX] : NULL; - case GL_TEXTURE_1D_ARRAY_EXT: - return arrayTex ? texUnit->CurrentTex[TEXTURE_1D_ARRAY_INDEX] : NULL; - case GL_PROXY_TEXTURE_1D_ARRAY_EXT: - return arrayTex ? ctx->Texture.ProxyTex[TEXTURE_1D_ARRAY_INDEX] : NULL; - case GL_TEXTURE_2D_ARRAY_EXT: - return arrayTex ? texUnit->CurrentTex[TEXTURE_2D_ARRAY_INDEX] : NULL; - case GL_PROXY_TEXTURE_2D_ARRAY_EXT: - return arrayTex ? ctx->Texture.ProxyTex[TEXTURE_2D_ARRAY_INDEX] : NULL; - default: - _mesa_problem(NULL, "bad target in _mesa_select_tex_object()"); - return NULL; - } -} - - -/** - * Return pointer to texture object for given target on current texture unit. - */ -struct gl_texture_object * -_mesa_get_current_tex_object(struct gl_context *ctx, GLenum target) -{ - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - return _mesa_select_tex_object(ctx, texUnit, target); -} - - -/** - * Get a texture image pointer from a texture object, given a texture - * target and mipmap level. The target and level parameters should - * have already been error-checked. - * - * \param ctx GL context. - * \param texObj texture unit. - * \param target texture target. - * \param level image level. - * - * \return pointer to the texture image structure, or NULL on failure. - */ -struct gl_texture_image * -_mesa_select_tex_image(struct gl_context *ctx, - const struct gl_texture_object *texObj, - GLenum target, GLint level) -{ - const GLuint face = _mesa_tex_target_to_face(target); - - ASSERT(texObj); - ASSERT(level >= 0); - ASSERT(level < MAX_TEXTURE_LEVELS); - - return texObj->Image[face][level]; -} - - -/** - * Like _mesa_select_tex_image() but if the image doesn't exist, allocate - * it and install it. Only return NULL if passed a bad parameter or run - * out of memory. - */ -struct gl_texture_image * -_mesa_get_tex_image(struct gl_context *ctx, struct gl_texture_object *texObj, - GLenum target, GLint level) -{ - struct gl_texture_image *texImage; - - if (!texObj) - return NULL; - - texImage = _mesa_select_tex_image(ctx, texObj, target, level); - if (!texImage) { - texImage = ctx->Driver.NewTextureImage(ctx); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture image allocation"); - return NULL; - } - - _mesa_set_tex_image(texObj, target, level, texImage); - } - - return texImage; -} - - -/** - * Return pointer to the specified proxy texture image. - * Note that proxy textures are per-context, not per-texture unit. - * \return pointer to texture image or NULL if invalid target, invalid - * level, or out of memory. - */ -struct gl_texture_image * -_mesa_get_proxy_tex_image(struct gl_context *ctx, GLenum target, GLint level) -{ - struct gl_texture_image *texImage; - GLuint texIndex; - - if (level < 0 ) - return NULL; - - switch (target) { - case GL_PROXY_TEXTURE_1D: - if (level >= ctx->Const.MaxTextureLevels) - return NULL; - texIndex = TEXTURE_1D_INDEX; - break; - case GL_PROXY_TEXTURE_2D: - if (level >= ctx->Const.MaxTextureLevels) - return NULL; - texIndex = TEXTURE_2D_INDEX; - break; - case GL_PROXY_TEXTURE_3D: - if (level >= ctx->Const.Max3DTextureLevels) - return NULL; - texIndex = TEXTURE_3D_INDEX; - break; - case GL_PROXY_TEXTURE_CUBE_MAP: - if (level >= ctx->Const.MaxCubeTextureLevels) - return NULL; - texIndex = TEXTURE_CUBE_INDEX; - break; - case GL_PROXY_TEXTURE_RECTANGLE_NV: - if (level > 0) - return NULL; - texIndex = TEXTURE_RECT_INDEX; - break; - case GL_PROXY_TEXTURE_1D_ARRAY_EXT: - if (level >= ctx->Const.MaxTextureLevels) - return NULL; - texIndex = TEXTURE_1D_ARRAY_INDEX; - break; - case GL_PROXY_TEXTURE_2D_ARRAY_EXT: - if (level >= ctx->Const.MaxTextureLevels) - return NULL; - texIndex = TEXTURE_2D_ARRAY_INDEX; - break; - default: - return NULL; - } - - texImage = ctx->Texture.ProxyTex[texIndex]->Image[0][level]; - if (!texImage) { - texImage = ctx->Driver.NewTextureImage(ctx); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation"); - return NULL; - } - ctx->Texture.ProxyTex[texIndex]->Image[0][level] = texImage; - /* Set the 'back' pointer */ - texImage->TexObject = ctx->Texture.ProxyTex[texIndex]; - } - return texImage; -} - - -/** - * Get the maximum number of allowed mipmap levels. - * - * \param ctx GL context. - * \param target texture target. - * - * \return the maximum number of allowed mipmap levels for the given - * texture target, or zero if passed a bad target. - * - * \sa gl_constants. - */ -GLint -_mesa_max_texture_levels(struct gl_context *ctx, GLenum target) -{ - switch (target) { - case GL_TEXTURE_1D: - case GL_PROXY_TEXTURE_1D: - case GL_TEXTURE_2D: - case GL_PROXY_TEXTURE_2D: - return ctx->Const.MaxTextureLevels; - case GL_TEXTURE_3D: - case GL_PROXY_TEXTURE_3D: - return ctx->Const.Max3DTextureLevels; - case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: - case GL_TEXTURE_CUBE_MAP_ARB: - case GL_PROXY_TEXTURE_CUBE_MAP_ARB: - return ctx->Extensions.ARB_texture_cube_map - ? ctx->Const.MaxCubeTextureLevels : 0; - case GL_TEXTURE_RECTANGLE_NV: - case GL_PROXY_TEXTURE_RECTANGLE_NV: - return ctx->Extensions.NV_texture_rectangle ? 1 : 0; - case GL_TEXTURE_1D_ARRAY_EXT: - case GL_PROXY_TEXTURE_1D_ARRAY_EXT: - case GL_TEXTURE_2D_ARRAY_EXT: - case GL_PROXY_TEXTURE_2D_ARRAY_EXT: - return (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array) - ? ctx->Const.MaxTextureLevels : 0; - default: - return 0; /* bad target */ - } -} - - -/** - * Return number of dimensions per mipmap level for the given texture target. - */ -GLint -_mesa_get_texture_dimensions(GLenum target) -{ - switch (target) { - case GL_TEXTURE_1D: - case GL_PROXY_TEXTURE_1D: - return 1; - case GL_TEXTURE_2D: - case GL_TEXTURE_RECTANGLE: - case GL_TEXTURE_CUBE_MAP: - case GL_PROXY_TEXTURE_2D: - case GL_PROXY_TEXTURE_RECTANGLE: - case GL_PROXY_TEXTURE_CUBE_MAP: - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - case GL_TEXTURE_1D_ARRAY: - case GL_PROXY_TEXTURE_1D_ARRAY: - return 2; - case GL_TEXTURE_3D: - case GL_PROXY_TEXTURE_3D: - case GL_TEXTURE_2D_ARRAY: - case GL_PROXY_TEXTURE_2D_ARRAY: - return 3; - default: - _mesa_problem(NULL, "invalid target 0x%x in get_texture_dimensions()", - target); - return 2; - } -} - - - - -#if 000 /* not used anymore */ -/* - * glTexImage[123]D can accept a NULL image pointer. In this case we - * create a texture image with unspecified image contents per the OpenGL - * spec. - */ -static GLubyte * -make_null_texture(GLint width, GLint height, GLint depth, GLenum format) -{ - const GLint components = _mesa_components_in_format(format); - const GLint numPixels = width * height * depth; - GLubyte *data = (GLubyte *) MALLOC(numPixels * components * sizeof(GLubyte)); - -#ifdef DEBUG - /* - * Let's see if anyone finds this. If glTexImage2D() is called with - * a NULL image pointer then load the texture image with something - * interesting instead of leaving it indeterminate. - */ - if (data) { - static const char message[8][32] = { - " X X XXXXX XXX X ", - " XX XX X X X X X ", - " X X X X X X X ", - " X X XXXX XXX XXXXX ", - " X X X X X X ", - " X X X X X X X ", - " X X XXXXX XXX X X ", - " " - }; - - GLubyte *imgPtr = data; - GLint h, i, j, k; - for (h = 0; h < depth; h++) { - for (i = 0; i < height; i++) { - GLint srcRow = 7 - (i % 8); - for (j = 0; j < width; j++) { - GLint srcCol = j % 32; - GLubyte texel = (message[srcRow][srcCol]=='X') ? 255 : 70; - for (k = 0; k < components; k++) { - *imgPtr++ = texel; - } - } - } - } - } -#endif - - return data; -} -#endif - - - -/** - * Reset the fields of a gl_texture_image struct to zero. - * - * \param img texture image structure. - * - * This is called when a proxy texture test fails, we set all the - * image members (except DriverData) to zero. - * It's also used in glTexImage[123]D as a safeguard to be sure all - * required fields get initialized properly by the Driver.TexImage[123]D - * functions. - */ -static void -clear_teximage_fields(struct gl_texture_image *img) -{ - ASSERT(img); - img->_BaseFormat = 0; - img->InternalFormat = 0; - img->Border = 0; - img->Width = 0; - img->Height = 0; - img->Depth = 0; - img->RowStride = 0; - if (img->ImageOffsets) { - free(img->ImageOffsets); - img->ImageOffsets = NULL; - } - img->Width2 = 0; - img->Height2 = 0; - img->Depth2 = 0; - img->WidthLog2 = 0; - img->HeightLog2 = 0; - img->DepthLog2 = 0; - img->Data = NULL; - img->TexFormat = MESA_FORMAT_NONE; - img->FetchTexelc = NULL; - img->FetchTexelf = NULL; -} - - -/** - * Initialize basic fields of the gl_texture_image struct. - * - * \param ctx GL context. - * \param target texture target (GL_TEXTURE_1D, GL_TEXTURE_RECTANGLE, etc). - * \param img texture image structure to be initialized. - * \param width image width. - * \param height image height. - * \param depth image depth. - * \param border image border. - * \param internalFormat internal format. - * \param format the actual hardware format (one of MESA_FORMAT_*) - * - * Fills in the fields of \p img with the given information. - * Note: width, height and depth include the border. - */ -void -_mesa_init_teximage_fields(struct gl_context *ctx, GLenum target, - struct gl_texture_image *img, - GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLenum internalFormat, - gl_format format) -{ - GLint i, dims; - - ASSERT(img); - ASSERT(width >= 0); - ASSERT(height >= 0); - ASSERT(depth >= 0); - - img->_BaseFormat = _mesa_base_tex_format( ctx, internalFormat ); - ASSERT(img->_BaseFormat > 0); - img->InternalFormat = internalFormat; - img->Border = border; - img->Width = width; - img->Height = height; - img->Depth = depth; - - img->Width2 = width - 2 * border; /* == 1 << img->WidthLog2; */ - img->WidthLog2 = logbase2(img->Width2); - - if (height == 1) { /* 1-D texture */ - img->Height2 = 1; - img->HeightLog2 = 0; - } - else { - img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */ - img->HeightLog2 = logbase2(img->Height2); - } - - if (depth == 1) { /* 2-D texture */ - img->Depth2 = 1; - img->DepthLog2 = 0; - } - else { - img->Depth2 = depth - 2 * border; /* == 1 << img->DepthLog2; */ - img->DepthLog2 = logbase2(img->Depth2); - } - - img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2); - - if ((width == 1 || _mesa_is_pow_two(img->Width2)) && - (height == 1 || _mesa_is_pow_two(img->Height2)) && - (depth == 1 || _mesa_is_pow_two(img->Depth2))) - img->_IsPowerOfTwo = GL_TRUE; - else - img->_IsPowerOfTwo = GL_FALSE; - - /* RowStride and ImageOffsets[] describe how to address texels in 'Data' */ - img->RowStride = width; - /* Allocate the ImageOffsets array and initialize to typical values. - * We allocate the array for 1D/2D textures too in order to avoid special- - * case code in the texstore routines. - */ - if (img->ImageOffsets) - free(img->ImageOffsets); - img->ImageOffsets = (GLuint *) malloc(depth * sizeof(GLuint)); - for (i = 0; i < depth; i++) { - img->ImageOffsets[i] = i * width * height; - } - - /* Compute Width/Height/DepthScale for mipmap lod computation */ - if (target == GL_TEXTURE_RECTANGLE_NV) { - /* scale = 1.0 since texture coords directly map to texels */ - img->WidthScale = 1.0; - img->HeightScale = 1.0; - img->DepthScale = 1.0; - } - else { - img->WidthScale = (GLfloat) img->Width; - img->HeightScale = (GLfloat) img->Height; - img->DepthScale = (GLfloat) img->Depth; - } - - img->TexFormat = format; - - dims = _mesa_get_texture_dimensions(target); - - _mesa_set_fetch_functions(img, dims); -} - - -/** - * Free and clear fields of the gl_texture_image struct. - * - * \param ctx GL context. - * \param texImage texture image structure to be cleared. - * - * After the call, \p texImage will have no data associated with it. Its - * fields are cleared so that its parent object will test incomplete. - */ -void -_mesa_clear_texture_image(struct gl_context *ctx, - struct gl_texture_image *texImage) -{ - ctx->Driver.FreeTexImageData(ctx, texImage); - clear_teximage_fields(texImage); -} - - -/** - * This is the fallback for Driver.TestProxyTexImage(). Test the texture - * level, width, height and depth against the ctx->Const limits for textures. - * - * A hardware driver might override this function if, for example, the - * max 3D texture size is 512x512x64 (i.e. not a cube). - * - * Note that width, height, depth == 0 is not an error. However, a - * texture with zero width/height/depth will be considered "incomplete" - * and texturing will effectively be disabled. - * - * \param target one of GL_PROXY_TEXTURE_1D, GL_PROXY_TEXTURE_2D, - * GL_PROXY_TEXTURE_3D, GL_PROXY_TEXTURE_RECTANGLE_NV, - * GL_PROXY_TEXTURE_CUBE_MAP_ARB. - * \param level as passed to glTexImage - * \param internalFormat as passed to glTexImage - * \param format as passed to glTexImage - * \param type as passed to glTexImage - * \param width as passed to glTexImage - * \param height as passed to glTexImage - * \param depth as passed to glTexImage - * \param border as passed to glTexImage - * \return GL_TRUE if the image is acceptable, GL_FALSE if not acceptable. - */ -GLboolean -_mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level, - GLint internalFormat, GLenum format, GLenum type, - GLint width, GLint height, GLint depth, GLint border) -{ - GLint maxSize; - - (void) internalFormat; - (void) format; - (void) type; - - switch (target) { - case GL_PROXY_TEXTURE_1D: - maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); - if (width < 2 * border || width > 2 + maxSize) - return GL_FALSE; - if (level >= ctx->Const.MaxTextureLevels) - return GL_FALSE; - if (!ctx->Extensions.ARB_texture_non_power_of_two) { - if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) - return GL_FALSE; - } - return GL_TRUE; - - case GL_PROXY_TEXTURE_2D: - maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); - if (width < 2 * border || width > 2 + maxSize) - return GL_FALSE; - if (height < 2 * border || height > 2 + maxSize) - return GL_FALSE; - if (level >= ctx->Const.MaxTextureLevels) - return GL_FALSE; - if (!ctx->Extensions.ARB_texture_non_power_of_two) { - if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) - return GL_FALSE; - if (height > 0 && !_mesa_is_pow_two(height - 2 * border)) - return GL_FALSE; - } - return GL_TRUE; - - case GL_PROXY_TEXTURE_3D: - maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); - if (width < 2 * border || width > 2 + maxSize) - return GL_FALSE; - if (height < 2 * border || height > 2 + maxSize) - return GL_FALSE; - if (depth < 2 * border || depth > 2 + maxSize) - return GL_FALSE; - if (level >= ctx->Const.Max3DTextureLevels) - return GL_FALSE; - if (!ctx->Extensions.ARB_texture_non_power_of_two) { - if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) - return GL_FALSE; - if (height > 0 && !_mesa_is_pow_two(height - 2 * border)) - return GL_FALSE; - if (depth > 0 && !_mesa_is_pow_two(depth - 2 * border)) - return GL_FALSE; - } - return GL_TRUE; - - case GL_PROXY_TEXTURE_RECTANGLE_NV: - maxSize = ctx->Const.MaxTextureRectSize; - if (width < 0 || width > maxSize) - return GL_FALSE; - if (height < 0 || height > maxSize) - return GL_FALSE; - if (level != 0) - return GL_FALSE; - return GL_TRUE; - - case GL_PROXY_TEXTURE_CUBE_MAP_ARB: - maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1); - if (width < 2 * border || width > 2 + maxSize) - return GL_FALSE; - if (height < 2 * border || height > 2 + maxSize) - return GL_FALSE; - if (level >= ctx->Const.MaxCubeTextureLevels) - return GL_FALSE; - if (!ctx->Extensions.ARB_texture_non_power_of_two) { - if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) - return GL_FALSE; - if (height > 0 && !_mesa_is_pow_two(height - 2 * border)) - return GL_FALSE; - } - return GL_TRUE; - - case GL_PROXY_TEXTURE_1D_ARRAY_EXT: - maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); - if (width < 2 * border || width > 2 + maxSize) - return GL_FALSE; - if (height < 1 || height > ctx->Const.MaxArrayTextureLayers) - return GL_FALSE; - if (level >= ctx->Const.MaxTextureLevels) - return GL_FALSE; - if (!ctx->Extensions.ARB_texture_non_power_of_two) { - if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) - return GL_FALSE; - } - return GL_TRUE; - - case GL_PROXY_TEXTURE_2D_ARRAY_EXT: - maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); - if (width < 2 * border || width > 2 + maxSize) - return GL_FALSE; - if (height < 2 * border || height > 2 + maxSize) - return GL_FALSE; - if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers) - return GL_FALSE; - if (level >= ctx->Const.MaxTextureLevels) - return GL_FALSE; - if (!ctx->Extensions.ARB_texture_non_power_of_two) { - if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) - return GL_FALSE; - if (height > 0 && !_mesa_is_pow_two(height - 2 * border)) - return GL_FALSE; - } - return GL_TRUE; - - default: - _mesa_problem(ctx, "Invalid target in _mesa_test_proxy_teximage"); - return GL_FALSE; - } -} - - -/** - * Check if the memory used by the texture would exceed the driver's limit. - * This lets us support a max 3D texture size of 8K (for example) but - * prevents allocating a full 8K x 8K x 8K texture. - * XXX this could be rolled into the proxy texture size test (above) but - * we don't have the actual texture internal format at that point. - */ -static GLboolean -legal_texture_size(struct gl_context *ctx, gl_format format, - GLint width, GLint height, GLint depth) -{ - uint64_t bytes = _mesa_format_image_size64(format, width, height, depth); - uint64_t mbytes = bytes / (1024 * 1024); /* convert to MB */ - return mbytes <= (uint64_t) ctx->Const.MaxTextureMbytes; -} - - - -/** - * Helper function to determine whether a target and specific compression - * format are supported. - */ -static GLboolean -target_can_be_compressed(const struct gl_context *ctx, GLenum target, - GLenum intFormat) -{ - (void) intFormat; /* not used yet */ - - switch (target) { - case GL_TEXTURE_2D: - case GL_PROXY_TEXTURE_2D: - return GL_TRUE; /* true for any compressed format so far */ - case GL_PROXY_TEXTURE_CUBE_MAP: - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - return ctx->Extensions.ARB_texture_cube_map; - case GL_PROXY_TEXTURE_2D_ARRAY_EXT: - case GL_TEXTURE_2D_ARRAY_EXT: - return (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); - default: - return GL_FALSE; - } -} - - -/** - * Check if the given texture target value is legal for a - * glTexImage1/2/3D call. - */ -static GLboolean -legal_teximage_target(struct gl_context *ctx, GLuint dims, GLenum target) -{ - switch (dims) { - case 1: - switch (target) { - case GL_TEXTURE_1D: - case GL_PROXY_TEXTURE_1D: - return GL_TRUE; - default: - return GL_FALSE; - } - case 2: - switch (target) { - case GL_TEXTURE_2D: - case GL_PROXY_TEXTURE_2D: - return GL_TRUE; - case GL_PROXY_TEXTURE_CUBE_MAP: - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - return ctx->Extensions.ARB_texture_cube_map; - case GL_TEXTURE_RECTANGLE_NV: - case GL_PROXY_TEXTURE_RECTANGLE_NV: - return ctx->Extensions.NV_texture_rectangle; - case GL_TEXTURE_1D_ARRAY_EXT: - case GL_PROXY_TEXTURE_1D_ARRAY_EXT: - return (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); - default: - return GL_FALSE; - } - case 3: - switch (target) { - case GL_TEXTURE_3D: - case GL_PROXY_TEXTURE_3D: - return GL_TRUE; - case GL_TEXTURE_2D_ARRAY_EXT: - case GL_PROXY_TEXTURE_2D_ARRAY_EXT: - return (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); - default: - return GL_FALSE; - } - default: - _mesa_problem(ctx, "invalid dims=%u in legal_teximage_target()", dims); - return GL_FALSE; - } -} - - -/** - * Check if the given texture target value is legal for a - * glTexSubImage, glCopyTexSubImage or glCopyTexImage call. - * The difference compared to legal_teximage_target() above is that - * proxy targets are not supported. - */ -static GLboolean -legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target) -{ - switch (dims) { - case 1: - return target == GL_TEXTURE_1D; - case 2: - switch (target) { - case GL_TEXTURE_2D: - return GL_TRUE; - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - return ctx->Extensions.ARB_texture_cube_map; - case GL_TEXTURE_RECTANGLE_NV: - return ctx->Extensions.NV_texture_rectangle; - case GL_TEXTURE_1D_ARRAY_EXT: - return (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); - default: - return GL_FALSE; - } - case 3: - switch (target) { - case GL_TEXTURE_3D: - return GL_TRUE; - case GL_TEXTURE_2D_ARRAY_EXT: - return (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); - default: - return GL_FALSE; - } - default: - _mesa_problem(ctx, "invalid dims=%u in legal_texsubimage_target()", - dims); - return GL_FALSE; - } -} - - -/** - * Test the glTexImage[123]D() parameters for errors. - * - * \param ctx GL context. - * \param dimensions texture image dimensions (must be 1, 2 or 3). - * \param target texture target given by the user. - * \param level image level given by the user. - * \param internalFormat internal format given by the user. - * \param format pixel data format given by the user. - * \param type pixel data type given by the user. - * \param width image width given by the user. - * \param height image height given by the user. - * \param depth image depth given by the user. - * \param border image border given by the user. - * - * \return GL_TRUE if an error was detected, or GL_FALSE if no errors. - * - * Verifies each of the parameters against the constants specified in - * __struct gl_contextRec::Const and the supported extensions, and according - * to the OpenGL specification. - */ -static GLboolean -texture_error_check( struct gl_context *ctx, - GLuint dimensions, GLenum target, - GLint level, GLint internalFormat, - GLenum format, GLenum type, - GLint width, GLint height, - GLint depth, GLint border ) -{ - const GLenum proxyTarget = get_proxy_target(target); - const GLboolean isProxy = target == proxyTarget; - GLboolean sizeOK = GL_TRUE; - GLboolean colorFormat, indexFormat; - - /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */ - if (level < 0 || level >= MAX_TEXTURE_LEVELS) { - if (!isProxy) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexImage%dD(level=%d)", dimensions, level); - } - return GL_TRUE; - } - - /* Check border */ - if (border < 0 || border > 1 || - ((target == GL_TEXTURE_RECTANGLE_NV || - target == GL_PROXY_TEXTURE_RECTANGLE_NV) && border != 0)) { - if (!isProxy) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexImage%dD(border=%d)", dimensions, border); - } - return GL_TRUE; - } - - if (width < 0 || height < 0 || depth < 0) { - if (!isProxy) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexImage%dD(width, height or depth < 0)", dimensions); - } - return GL_TRUE; - } - - /* Do this simple check before calling the TestProxyTexImage() function */ - if (proxyTarget == GL_PROXY_TEXTURE_CUBE_MAP_ARB) { - sizeOK = (width == height); - } - - /* - * Use the proxy texture driver hook to see if the size/level/etc are - * legal. - */ - sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level, - internalFormat, format, - type, width, height, - depth, border); - if (!sizeOK) { - if (!isProxy) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexImage%dD(level=%d, width=%d, height=%d, depth=%d)", - dimensions, level, width, height, depth); - } - return GL_TRUE; - } - - /* Check internalFormat */ - if (_mesa_base_tex_format(ctx, internalFormat) < 0) { - if (!isProxy) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexImage%dD(internalFormat=%s)", - dimensions, _mesa_lookup_enum_by_nr(internalFormat)); - } - return GL_TRUE; - } - - /* Check incoming image format and type */ - if (!_mesa_is_legal_format_and_type(ctx, format, type)) { - /* Normally, GL_INVALID_OPERATION is generated by a format/type - * mismatch (see the 1.2 spec page 94, sec 3.6.4.). But with the - * GL_EXT_texture_integer extension, some combinations should generate - * GL_INVALID_ENUM instead (grr!). - */ - if (!isProxy) { - GLenum error = _mesa_is_integer_format(format) - ? GL_INVALID_ENUM : GL_INVALID_OPERATION; - _mesa_error(ctx, error, - "glTexImage%dD(incompatible format 0x%x, type 0x%x)", - dimensions, format, type); - } - return GL_TRUE; - } - - /* make sure internal format and format basically agree */ - colorFormat = _mesa_is_color_format(format); - indexFormat = _mesa_is_index_format(format); - if ((_mesa_is_color_format(internalFormat) && !colorFormat && !indexFormat) || - (_mesa_is_index_format(internalFormat) && !indexFormat) || - (_mesa_is_depth_format(internalFormat) != _mesa_is_depth_format(format)) || - (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format)) || - (_mesa_is_depthstencil_format(internalFormat) != _mesa_is_depthstencil_format(format)) || - (_mesa_is_dudv_format(internalFormat) != _mesa_is_dudv_format(format))) { - if (!isProxy) - _mesa_error(ctx, GL_INVALID_OPERATION, - "glTexImage%dD(incompatible internalFormat 0x%x, format 0x%x)", - dimensions, internalFormat, format); - return GL_TRUE; - } - - /* additional checks for ycbcr textures */ - if (internalFormat == GL_YCBCR_MESA) { - ASSERT(ctx->Extensions.MESA_ycbcr_texture); - if (type != GL_UNSIGNED_SHORT_8_8_MESA && - type != GL_UNSIGNED_SHORT_8_8_REV_MESA) { - char message[100]; - _mesa_snprintf(message, sizeof(message), - "glTexImage%dD(format/type YCBCR mismatch", dimensions); - _mesa_error(ctx, GL_INVALID_ENUM, "%s", message); - return GL_TRUE; /* error */ - } - if (target != GL_TEXTURE_2D && - target != GL_PROXY_TEXTURE_2D && - target != GL_TEXTURE_RECTANGLE_NV && - target != GL_PROXY_TEXTURE_RECTANGLE_NV) { - if (!isProxy) - _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage(target)"); - return GL_TRUE; - } - if (border != 0) { - if (!isProxy) { - char message[100]; - _mesa_snprintf(message, sizeof(message), - "glTexImage%dD(format=GL_YCBCR_MESA and border=%d)", - dimensions, border); - _mesa_error(ctx, GL_INVALID_VALUE, "%s", message); - } - return GL_TRUE; - } - } - - /* additional checks for depth textures */ - if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT) { - /* Only 1D, 2D and rectangular textures supported, not 3D or cubes */ - if (target != GL_TEXTURE_1D && - target != GL_PROXY_TEXTURE_1D && - target != GL_TEXTURE_2D && - target != GL_PROXY_TEXTURE_2D && - target != GL_TEXTURE_RECTANGLE_ARB && - target != GL_PROXY_TEXTURE_RECTANGLE_ARB) { - if (!isProxy) - _mesa_error(ctx, GL_INVALID_ENUM, - "glTexImage(target/internalFormat)"); - return GL_TRUE; - } - } - - /* additional checks for compressed textures */ - if (_mesa_is_compressed_format(ctx, internalFormat)) { - if (!target_can_be_compressed(ctx, target, internalFormat)) { - if (!isProxy) - _mesa_error(ctx, GL_INVALID_ENUM, - "glTexImage%dD(target)", dimensions); - return GL_TRUE; - } - if (border != 0) { - if (!isProxy) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glTexImage%dD(border!=0)", dimensions); - } - return GL_TRUE; - } - } - - /* additional checks for integer textures */ - if (ctx->Extensions.EXT_texture_integer && - (_mesa_is_integer_format(format) != - _mesa_is_integer_format(internalFormat))) { - if (!isProxy) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glTexImage%dD(integer/non-integer format mismatch)", - dimensions); - } - return GL_TRUE; - } - - /* if we get here, the parameters are OK */ - return GL_FALSE; -} - - -/** - * Test glTexSubImage[123]D() parameters for errors. - * - * \param ctx GL context. - * \param dimensions texture image dimensions (must be 1, 2 or 3). - * \param target texture target given by the user. - * \param level image level given by the user. - * \param xoffset sub-image x offset given by the user. - * \param yoffset sub-image y offset given by the user. - * \param zoffset sub-image z offset given by the user. - * \param format pixel data format given by the user. - * \param type pixel data type given by the user. - * \param width image width given by the user. - * \param height image height given by the user. - * \param depth image depth given by the user. - * - * \return GL_TRUE if an error was detected, or GL_FALSE if no errors. - * - * Verifies each of the parameters against the constants specified in - * __struct gl_contextRec::Const and the supported extensions, and according - * to the OpenGL specification. - */ -static GLboolean -subtexture_error_check( struct gl_context *ctx, GLuint dimensions, - GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLint width, GLint height, GLint depth, - GLenum format, GLenum type ) -{ - /* Basic level check */ - if (level < 0 || level >= MAX_TEXTURE_LEVELS) { - _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage2D(level=%d)", level); - return GL_TRUE; - } - - /* Check for negative sizes */ - if (width < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexSubImage%dD(width=%d)", dimensions, width); - return GL_TRUE; - } - if (height < 0 && dimensions > 1) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexSubImage%dD(height=%d)", dimensions, height); - return GL_TRUE; - } - if (depth < 0 && dimensions > 2) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexSubImage%dD(depth=%d)", dimensions, depth); - return GL_TRUE; - } - - if (!_mesa_is_legal_format_and_type(ctx, format, type)) { - /* As with the glTexImage2D check above, the error code here - * depends on texture integer. - */ - GLenum error = _mesa_is_integer_format(format) - ? GL_INVALID_OPERATION : GL_INVALID_ENUM; - _mesa_error(ctx, error, - "glTexSubImage%dD(incompatible format 0x%x, type 0x%x)", - dimensions, format, type); - return GL_TRUE; - } - - return GL_FALSE; -} - - -/** - * Do second part of glTexSubImage which depends on the destination texture. - * \return GL_TRUE if error recorded, GL_FALSE otherwise - */ -static GLboolean -subtexture_error_check2( struct gl_context *ctx, GLuint dimensions, - GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLint width, GLint height, GLint depth, - GLenum format, GLenum type, - const struct gl_texture_image *destTex ) -{ - if (!destTex) { - /* undefined image level */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glTexSubImage%dD", dimensions); - return GL_TRUE; - } - - if (xoffset < -((GLint)destTex->Border)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(xoffset)", - dimensions); - return GL_TRUE; - } - if (xoffset + width > (GLint) (destTex->Width + destTex->Border)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(xoffset+width)", - dimensions); - return GL_TRUE; - } - if (dimensions > 1) { - if (yoffset < -((GLint)destTex->Border)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(yoffset)", - dimensions); - return GL_TRUE; - } - if (yoffset + height > (GLint) (destTex->Height + destTex->Border)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(yoffset+height)", - dimensions); - return GL_TRUE; - } - } - if (dimensions > 2) { - if (zoffset < -((GLint)destTex->Border)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset)"); - return GL_TRUE; - } - if (zoffset + depth > (GLint) (destTex->Depth + destTex->Border)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset+depth)"); - return GL_TRUE; - } - } - - if (_mesa_is_format_compressed(destTex->TexFormat)) { - GLuint bw, bh; - - /* do tests which depend on compression block size */ - _mesa_get_format_block_size(destTex->TexFormat, &bw, &bh); - - /* offset must be multiple of block size */ - if ((xoffset % bw != 0) || (yoffset % bh != 0)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glTexSubImage%dD(xoffset = %d, yoffset = %d)", - dimensions, xoffset, yoffset); - return GL_TRUE; - } - /* size must be multiple of bw by bh or equal to whole texture size */ - if ((width % bw != 0) && (GLuint) width != destTex->Width) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glTexSubImage%dD(width = %d)", dimensions, width); - return GL_TRUE; - } - if ((height % bh != 0) && (GLuint) height != destTex->Height) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glTexSubImage%dD(height = %d)", dimensions, height); - return GL_TRUE; - } - } - - return GL_FALSE; -} - - -/** - * Test glCopyTexImage[12]D() parameters for errors. - * - * \param ctx GL context. - * \param dimensions texture image dimensions (must be 1, 2 or 3). - * \param target texture target given by the user. - * \param level image level given by the user. - * \param internalFormat internal format given by the user. - * \param width image width given by the user. - * \param height image height given by the user. - * \param border texture border. - * - * \return GL_TRUE if an error was detected, or GL_FALSE if no errors. - * - * Verifies each of the parameters against the constants specified in - * __struct gl_contextRec::Const and the supported extensions, and according - * to the OpenGL specification. - */ -static GLboolean -copytexture_error_check( struct gl_context *ctx, GLuint dimensions, - GLenum target, GLint level, GLint internalFormat, - GLint width, GLint height, GLint border ) -{ - const GLenum proxyTarget = get_proxy_target(target); - const GLenum type = GL_FLOAT; - GLboolean sizeOK; - GLint format; - - /* check target */ - if (!legal_texsubimage_target(ctx, dimensions, target)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage%uD(target=%s)", - dimensions, _mesa_lookup_enum_by_nr(target)); - return GL_TRUE; - } - - /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */ - if (level < 0 || level >= MAX_TEXTURE_LEVELS) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexImage%dD(level=%d)", dimensions, level); - return GL_TRUE; - } - - /* Check that the source buffer is complete */ - if (ctx->ReadBuffer->Name) { - _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer); - if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { - _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, - "glCopyTexImage%dD(invalid readbuffer)", dimensions); - return GL_TRUE; - } - } - - /* Check border */ - if (border < 0 || border > 1 || - ((target == GL_TEXTURE_RECTANGLE_NV || - target == GL_PROXY_TEXTURE_RECTANGLE_NV) && border != 0)) { - return GL_TRUE; - } - - format = _mesa_base_tex_format(ctx, internalFormat); - if (format < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexImage%dD(internalFormat)", dimensions); - return GL_TRUE; - } - - if (!_mesa_source_buffer_exists(ctx, format)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexImage%dD(missing readbuffer)", dimensions); - return GL_TRUE; - } - - /* Do size, level checking */ - sizeOK = (proxyTarget == GL_PROXY_TEXTURE_CUBE_MAP_ARB) - ? (width == height) : 1; - - sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level, - internalFormat, format, - type, width, height, - 1, border); - - if (!sizeOK) { - if (dimensions == 1) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexImage1D(width=%d)", width); - } - else { - ASSERT(dimensions == 2); - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexImage2D(width=%d, height=%d)", width, height); - } - return GL_TRUE; - } - - if (_mesa_is_compressed_format(ctx, internalFormat)) { - if (!target_can_be_compressed(ctx, target, internalFormat)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glCopyTexImage%dD(target)", dimensions); - return GL_TRUE; - } - if (border != 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexImage%dD(border!=0)", dimensions); - return GL_TRUE; - } - } - else if (_mesa_is_depth_format(internalFormat)) { - /* make sure we have depth/stencil buffers */ - if (!ctx->ReadBuffer->_DepthBuffer) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexImage%dD(no depth)", dimensions); - return GL_TRUE; - } - } - else if (_mesa_is_depthstencil_format(internalFormat)) { - /* make sure we have depth/stencil buffers */ - if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexImage%dD(no depth/stencil buffer)", dimensions); - return GL_TRUE; - } - } - - /* if we get here, the parameters are OK */ - return GL_FALSE; -} - - -/** - * Test glCopyTexSubImage[12]D() parameters for errors. - * Note that this is the first part of error checking. - * See also copytexsubimage_error_check2() below for the second part. - * - * \param ctx GL context. - * \param dimensions texture image dimensions (must be 1, 2 or 3). - * \param target texture target given by the user. - * \param level image level given by the user. - * - * \return GL_TRUE if an error was detected, or GL_FALSE if no errors. - */ -static GLboolean -copytexsubimage_error_check1( struct gl_context *ctx, GLuint dimensions, - GLenum target, GLint level) -{ - /* Check that the source buffer is complete */ - if (ctx->ReadBuffer->Name) { - _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer); - if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { - _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, - "glCopyTexImage%dD(invalid readbuffer)", dimensions); - return GL_TRUE; - } - } - - /* check target (proxies not allowed) */ - if (!legal_texsubimage_target(ctx, dimensions, target)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexSubImage%uD(target=%s)", - dimensions, _mesa_lookup_enum_by_nr(target)); - return GL_TRUE; - } - - /* Check level */ - if (level < 0 || level >= MAX_TEXTURE_LEVELS) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexSubImage%dD(level=%d)", dimensions, level); - return GL_TRUE; - } - - return GL_FALSE; -} - - -/** - * Second part of error checking for glCopyTexSubImage[12]D(). - * \param xoffset sub-image x offset given by the user. - * \param yoffset sub-image y offset given by the user. - * \param zoffset sub-image z offset given by the user. - * \param width image width given by the user. - * \param height image height given by the user. - */ -static GLboolean -copytexsubimage_error_check2( struct gl_context *ctx, GLuint dimensions, - GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, - const struct gl_texture_image *teximage ) -{ - /* check that dest tex image exists */ - if (!teximage) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexSubImage%dD(undefined texture level: %d)", - dimensions, level); - return GL_TRUE; - } - - /* Check size */ - if (width < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexSubImage%dD(width=%d)", dimensions, width); - return GL_TRUE; - } - if (dimensions > 1 && height < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexSubImage%dD(height=%d)", dimensions, height); - return GL_TRUE; - } - - /* check x/y offsets */ - if (xoffset < -((GLint)teximage->Border)) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexSubImage%dD(xoffset=%d)", dimensions, xoffset); - return GL_TRUE; - } - if (xoffset + width > (GLint) (teximage->Width + teximage->Border)) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexSubImage%dD(xoffset+width)", dimensions); - return GL_TRUE; - } - if (dimensions > 1) { - if (yoffset < -((GLint)teximage->Border)) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexSubImage%dD(yoffset=%d)", dimensions, yoffset); - return GL_TRUE; - } - /* NOTE: we're adding the border here, not subtracting! */ - if (yoffset + height > (GLint) (teximage->Height + teximage->Border)) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexSubImage%dD(yoffset+height)", dimensions); - return GL_TRUE; - } - } - - /* check z offset */ - if (dimensions > 2) { - if (zoffset < -((GLint)teximage->Border)) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexSubImage%dD(zoffset)", dimensions); - return GL_TRUE; - } - if (zoffset > (GLint) (teximage->Depth + teximage->Border)) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexSubImage%dD(zoffset+depth)", dimensions); - return GL_TRUE; - } - } - - if (_mesa_is_format_compressed(teximage->TexFormat)) { - /* offset must be multiple of 4 */ - if ((xoffset & 3) || (yoffset & 3)) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexSubImage%dD(xoffset or yoffset)", dimensions); - return GL_TRUE; - } - /* size must be multiple of 4 */ - if ((width & 3) != 0 && (GLuint) width != teximage->Width) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexSubImage%dD(width)", dimensions); - return GL_TRUE; - } - if ((height & 3) != 0 && (GLuint) height != teximage->Height) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexSubImage%dD(height)", dimensions); - return GL_TRUE; - } - } - - if (teximage->InternalFormat == GL_YCBCR_MESA) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyTexSubImage2D"); - return GL_TRUE; - } - - if (!_mesa_source_buffer_exists(ctx, teximage->_BaseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexSubImage%dD(missing readbuffer, format=0x%x)", - dimensions, teximage->_BaseFormat); - return GL_TRUE; - } - - if (teximage->_BaseFormat == GL_DEPTH_COMPONENT) { - if (!ctx->ReadBuffer->_DepthBuffer) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexSubImage%dD(no depth buffer)", - dimensions); - return GL_TRUE; - } - } - else if (teximage->_BaseFormat == GL_DEPTH_STENCIL_EXT) { - if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexSubImage%dD(no depth/stencil buffer)", - dimensions); - return GL_TRUE; - } - } - - /* If copying into an integer texture, the source buffer must also be - * integer-valued. - */ - if (_mesa_is_format_integer_color(teximage->TexFormat)) { - struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; - if (!_mesa_is_format_integer_color(rb->Format)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexSubImage%dD(source buffer is not integer format)", - dimensions); - return GL_TRUE; - } - } - - /* if we get here, the parameters are OK */ - return GL_FALSE; -} - - -/** Callback info for walking over FBO hash table */ -struct cb_info -{ - struct gl_context *ctx; - struct gl_texture_object *texObj; - GLuint level, face; -}; - - -/** - * Check render to texture callback. Called from _mesa_HashWalk(). - */ -static void -check_rtt_cb(GLuint key, void *data, void *userData) -{ - struct gl_framebuffer *fb = (struct gl_framebuffer *) data; - const struct cb_info *info = (struct cb_info *) userData; - struct gl_context *ctx = info->ctx; - const struct gl_texture_object *texObj = info->texObj; - const GLuint level = info->level, face = info->face; - - /* If this is a user-created FBO */ - if (fb->Name) { - GLuint i; - /* check if any of the FBO's attachments point to 'texObj' */ - for (i = 0; i < BUFFER_COUNT; i++) { - struct gl_renderbuffer_attachment *att = fb->Attachment + i; - if (att->Type == GL_TEXTURE && - att->Texture == texObj && - att->TextureLevel == level && - att->CubeMapFace == face) { - ASSERT(att->Texture->Image[att->CubeMapFace][att->TextureLevel]); - /* Tell driver about the new renderbuffer texture */ - ctx->Driver.RenderTexture(ctx, ctx->DrawBuffer, att); - /* Mark fb status as indeterminate to force re-validation */ - fb->_Status = 0; - } - } - } -} - - -/** - * When a texture image is specified we have to check if it's bound to - * any framebuffer objects (render to texture) in order to detect changes - * in size or format since that effects FBO completeness. - * Any FBOs rendering into the texture must be re-validated. - */ -static void -update_fbo_texture(struct gl_context *ctx, struct gl_texture_object *texObj, - GLuint face, GLuint level) -{ - /* Only check this texture if it's been marked as RenderToTexture */ - if (texObj->_RenderToTexture) { - struct cb_info info; - info.ctx = ctx; - info.texObj = texObj; - info.level = level; - info.face = face; - _mesa_HashWalk(ctx->Shared->FrameBuffers, check_rtt_cb, &info); - } -} - - -/** - * If the texture object's GenerateMipmap flag is set and we've - * changed the texture base level image, regenerate the rest of the - * mipmap levels now. - */ -static INLINE void -check_gen_mipmap(struct gl_context *ctx, GLenum target, - struct gl_texture_object *texObj, GLint level) -{ - ASSERT(target != GL_TEXTURE_CUBE_MAP); - if (texObj->GenerateMipmap && - level == texObj->BaseLevel && - level < texObj->MaxLevel) { - ASSERT(ctx->Driver.GenerateMipmap); - ctx->Driver.GenerateMipmap(ctx, target, texObj); - } -} - - -/** Debug helper: override the user-requested internal format */ -static GLenum -override_internal_format(GLenum internalFormat, GLint width, GLint height) -{ -#if 0 - if (internalFormat == GL_RGBA16F_ARB || - internalFormat == GL_RGBA32F_ARB) { - printf("Convert rgba float tex to int %d x %d\n", width, height); - return GL_RGBA; - } - else if (internalFormat == GL_RGB16F_ARB || - internalFormat == GL_RGB32F_ARB) { - printf("Convert rgb float tex to int %d x %d\n", width, height); - return GL_RGB; - } - else if (internalFormat == GL_LUMINANCE_ALPHA16F_ARB || - internalFormat == GL_LUMINANCE_ALPHA32F_ARB) { - printf("Convert luminance float tex to int %d x %d\n", width, height); - return GL_LUMINANCE_ALPHA; - } - else if (internalFormat == GL_LUMINANCE16F_ARB || - internalFormat == GL_LUMINANCE32F_ARB) { - printf("Convert luminance float tex to int %d x %d\n", width, height); - return GL_LUMINANCE; - } - else if (internalFormat == GL_ALPHA16F_ARB || - internalFormat == GL_ALPHA32F_ARB) { - printf("Convert luminance float tex to int %d x %d\n", width, height); - return GL_ALPHA; - } - /* - else if (internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) { - internalFormat = GL_RGBA; - } - */ - else { - return internalFormat; - } -#else - return internalFormat; -#endif -} - - -/** - * Choose the actual hardware format for a texture image. - * Try to use the same format as the previous image level when possible. - * Otherwise, ask the driver for the best format. - * It's important to try to choose a consistant format for all levels - * for efficient texture memory layout/allocation. In particular, this - * comes up during automatic mipmap generation. - */ -gl_format -_mesa_choose_texture_format(struct gl_context *ctx, - struct gl_texture_object *texObj, - GLenum target, GLint level, - GLenum internalFormat, GLenum format, GLenum type) -{ - gl_format f; - - /* see if we've already chosen a format for the previous level */ - if (level > 0) { - struct gl_texture_image *prevImage = - _mesa_select_tex_image(ctx, texObj, target, level - 1); - /* See if the prev level is defined and has an internal format which - * matches the new internal format. - */ - if (prevImage && - prevImage->Width > 0 && - prevImage->InternalFormat == internalFormat) { - /* use the same format */ - ASSERT(prevImage->TexFormat != MESA_FORMAT_NONE); - return prevImage->TexFormat; - } - } - - /* choose format from scratch */ - f = ctx->Driver.ChooseTextureFormat(ctx, internalFormat, format, type); - ASSERT(f != MESA_FORMAT_NONE); - return f; -} - - -/** - * Common code to implement all the glTexImage1D/2D/3D functions. - */ -static void -teximage(struct gl_context *ctx, GLuint dims, - GLenum target, GLint level, GLint internalFormat, - GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLenum format, GLenum type, - const GLvoid *pixels) -{ - GLboolean error; - - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) - _mesa_debug(ctx, "glTexImage%uD %s %d %s %d %d %d %d %s %s %p\n", - dims, - _mesa_lookup_enum_by_nr(target), level, - _mesa_lookup_enum_by_nr(internalFormat), - width, height, depth, border, - _mesa_lookup_enum_by_nr(format), - _mesa_lookup_enum_by_nr(type), pixels); - - internalFormat = override_internal_format(internalFormat, width, height); - - /* target error checking */ - if (!legal_teximage_target(ctx, dims, target)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage%uD(target=%s)", - dims, _mesa_lookup_enum_by_nr(target)); - return; - } - - /* general error checking */ - error = texture_error_check(ctx, dims, target, level, internalFormat, - format, type, width, height, depth, border); - - if (_mesa_is_proxy_texture(target)) { - /* Proxy texture: just clear or set state depending on error checking */ - struct gl_texture_image *texImage = - _mesa_get_proxy_tex_image(ctx, target, level); - - if (error) { - /* when error, clear all proxy texture image parameters */ - if (texImage) - clear_teximage_fields(texImage); - } - else { - /* no error, set the tex image parameters */ - struct gl_texture_object *texObj = - _mesa_get_current_tex_object(ctx, target); - gl_format texFormat = _mesa_choose_texture_format(ctx, texObj, - target, level, - internalFormat, - format, type); - - if (legal_texture_size(ctx, texFormat, width, height, depth)) { - _mesa_init_teximage_fields(ctx, target, texImage, width, height, - depth, border, internalFormat, - texFormat); - } - else if (texImage) { - clear_teximage_fields(texImage); - } - } - } - else { - /* non-proxy target */ - const GLuint face = _mesa_tex_target_to_face(target); - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - - if (error) { - return; /* error was recorded */ - } - - if (ctx->NewState & _MESA_NEW_TRANSFER_STATE) - _mesa_update_state(ctx); - - texObj = _mesa_get_current_tex_object(ctx, target); - - _mesa_lock_texture(ctx, texObj); - { - texImage = _mesa_get_tex_image(ctx, texObj, target, level); - - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims); - } - else { - gl_format texFormat; - - if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - - ASSERT(texImage->Data == NULL); - texFormat = _mesa_choose_texture_format(ctx, texObj, target, level, - internalFormat, format, - type); - - if (legal_texture_size(ctx, texFormat, width, height, depth)) { - _mesa_init_teximage_fields(ctx, target, texImage, - width, height, depth, - border, internalFormat, texFormat); - - /* Give the texture to the driver. may be null. */ - ASSERT(ctx->Driver.TexImage3D); - switch (dims) { - case 1: - ctx->Driver.TexImage1D(ctx, target, level, internalFormat, - width, border, format, - type, pixels, &ctx->Unpack, texObj, - texImage); - break; - case 2: - ctx->Driver.TexImage2D(ctx, target, level, internalFormat, - width, height, border, format, - type, pixels, &ctx->Unpack, texObj, - texImage); - break; - case 3: - ctx->Driver.TexImage3D(ctx, target, level, internalFormat, - width, height, depth, border, format, - type, pixels, &ctx->Unpack, texObj, - texImage); - break; - default: - _mesa_problem(ctx, "invalid dims=%u in teximage()", dims); - } - - check_gen_mipmap(ctx, target, texObj, level); - - update_fbo_texture(ctx, texObj, face, level); - - /* state update */ - texObj->_Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; - } - else { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims); - } - } - } - _mesa_unlock_texture(ctx, texObj); - } -} - - -/* - * Called from the API. Note that width includes the border. - */ -void GLAPIENTRY -_mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, - GLsizei width, GLint border, GLenum format, - GLenum type, const GLvoid *pixels ) -{ - GET_CURRENT_CONTEXT(ctx); - teximage(ctx, 1, target, level, internalFormat, width, 1, 1, - border, format, type, pixels); -} - - -void GLAPIENTRY -_mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, - GLsizei width, GLsizei height, GLint border, - GLenum format, GLenum type, - const GLvoid *pixels ) -{ - GET_CURRENT_CONTEXT(ctx); - teximage(ctx, 2, target, level, internalFormat, width, height, 1, - border, format, type, pixels); -} - - -/* - * Called by the API or display list executor. - * Note that width and height include the border. - */ -void GLAPIENTRY -_mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, - GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLenum format, GLenum type, - const GLvoid *pixels ) -{ - GET_CURRENT_CONTEXT(ctx); - teximage(ctx, 3, target, level, internalFormat, width, height, depth, - border, format, type, pixels); -} - - -void GLAPIENTRY -_mesa_TexImage3DEXT( GLenum target, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLenum format, GLenum type, - const GLvoid *pixels ) -{ - _mesa_TexImage3D(target, level, (GLint) internalFormat, width, height, - depth, border, format, type, pixels); -} - - -#if FEATURE_OES_EGL_image -void GLAPIENTRY -_mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image) -{ - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (!ctx->Extensions.OES_EGL_image) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glEGLImageTargetTexture2DOES(unsupported)"); - return; - } - - if (target != GL_TEXTURE_2D) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glEGLImageTargetTexture2D(target=%d)", target); - return; - } - - if (ctx->NewState & _MESA_NEW_TRANSFER_STATE) - _mesa_update_state(ctx); - - texObj = _mesa_get_current_tex_object(ctx, target); - _mesa_lock_texture(ctx, texObj); - - texImage = _mesa_get_tex_image(ctx, texObj, target, 0); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glEGLImageTargetTexture2D"); - } else { - if (texImage->Data) - ctx->Driver.FreeTexImageData( ctx, texImage ); - - ASSERT(texImage->Data == NULL); - ctx->Driver.EGLImageTargetTexture2D(ctx, target, - texObj, texImage, image); - - /* state update */ - texObj->_Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; - } - _mesa_unlock_texture(ctx, texObj); - -} -#endif - - - -/** - * Implement all the glTexSubImage1/2/3D() functions. - */ -static void -texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *pixels ) -{ - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) - _mesa_debug(ctx, "glTexSubImage%uD %s %d %d %d %d %d %d %d %s %s %p\n", - dims, - _mesa_lookup_enum_by_nr(target), level, - xoffset, yoffset, zoffset, width, height, depth, - _mesa_lookup_enum_by_nr(format), - _mesa_lookup_enum_by_nr(type), pixels); - - /* check target (proxies not allowed) */ - if (!legal_texsubimage_target(ctx, dims, target)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%uD(target=%s)", - dims, _mesa_lookup_enum_by_nr(target)); - return; - } - - if (ctx->NewState & _MESA_NEW_TRANSFER_STATE) - _mesa_update_state(ctx); - - if (subtexture_error_check(ctx, dims, target, level, xoffset, yoffset, zoffset, - width, height, depth, format, type)) { - return; /* error was detected */ - } - - texObj = _mesa_get_current_tex_object(ctx, target); - - _mesa_lock_texture(ctx, texObj); - { - texImage = _mesa_select_tex_image(ctx, texObj, target, level); - - if (subtexture_error_check2(ctx, dims, target, level, - xoffset, yoffset, zoffset, - width, height, depth, - format, type, texImage)) { - /* error was recorded */ - } - else if (width > 0 && height > 0 && height > 0) { - /* If we have a border, offset=-1 is legal. Bias by border width. */ - switch (dims) { - case 3: - zoffset += texImage->Border; - /* fall-through */ - case 2: - yoffset += texImage->Border; - /* fall-through */ - case 1: - xoffset += texImage->Border; - } - - switch (dims) { - case 1: - ctx->Driver.TexSubImage1D(ctx, target, level, - xoffset, width, - format, type, pixels, - &ctx->Unpack, texObj, texImage ); - break; - case 2: - ctx->Driver.TexSubImage2D(ctx, target, level, - xoffset, yoffset, width, height, - format, type, pixels, - &ctx->Unpack, texObj, texImage ); - break; - case 3: - ctx->Driver.TexSubImage3D(ctx, target, level, - xoffset, yoffset, zoffset, - width, height, depth, - format, type, pixels, - &ctx->Unpack, texObj, texImage ); - break; - default: - _mesa_problem(ctx, "unexpected dims in subteximage()"); - } - - check_gen_mipmap(ctx, target, texObj, level); - - ctx->NewState |= _NEW_TEXTURE; - } - } - _mesa_unlock_texture(ctx, texObj); -} - - -void GLAPIENTRY -_mesa_TexSubImage1D( GLenum target, GLint level, - GLint xoffset, GLsizei width, - GLenum format, GLenum type, - const GLvoid *pixels ) -{ - GET_CURRENT_CONTEXT(ctx); - texsubimage(ctx, 1, target, level, - xoffset, 0, 0, - width, 1, 1, - format, type, pixels); -} - - -void GLAPIENTRY -_mesa_TexSubImage2D( GLenum target, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - const GLvoid *pixels ) -{ - GET_CURRENT_CONTEXT(ctx); - texsubimage(ctx, 2, target, level, - xoffset, yoffset, 0, - width, height, 1, - format, type, pixels); -} - - - -void GLAPIENTRY -_mesa_TexSubImage3D( GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, - const GLvoid *pixels ) -{ - GET_CURRENT_CONTEXT(ctx); - texsubimage(ctx, 3, target, level, - xoffset, yoffset, zoffset, - width, height, depth, - format, type, pixels); -} - - - -/** - * Implement the glCopyTexImage1/2D() functions. - */ -static void -copyteximage(struct gl_context *ctx, GLuint dims, - GLenum target, GLint level, GLenum internalFormat, - GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) -{ - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - const GLuint face = _mesa_tex_target_to_face(target); - - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) - _mesa_debug(ctx, "glCopyTexImage%uD %s %d %s %d %d %d %d %d\n", - dims, - _mesa_lookup_enum_by_nr(target), level, - _mesa_lookup_enum_by_nr(internalFormat), - x, y, width, height, border); - - if (ctx->NewState & NEW_COPY_TEX_STATE) - _mesa_update_state(ctx); - - if (copytexture_error_check(ctx, dims, target, level, internalFormat, - width, height, border)) - return; - - texObj = _mesa_get_current_tex_object(ctx, target); - - _mesa_lock_texture(ctx, texObj); - { - texImage = _mesa_get_tex_image(ctx, texObj, target, level); - - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims); - } - else { - gl_format texFormat; - - if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - - ASSERT(texImage->Data == NULL); - - texFormat = _mesa_choose_texture_format(ctx, texObj, target, level, - internalFormat, GL_NONE, - GL_NONE); - - if (legal_texture_size(ctx, texFormat, width, height, 1)) { - _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, - border, internalFormat, texFormat); - - ASSERT(ctx->Driver.CopyTexImage2D); - if (dims == 1) - ctx->Driver.CopyTexImage1D(ctx, target, level, internalFormat, - x, y, width, border); - else - ctx->Driver.CopyTexImage2D(ctx, target, level, internalFormat, - x, y, width, height, border); - - check_gen_mipmap(ctx, target, texObj, level); - - update_fbo_texture(ctx, texObj, face, level); - - /* state update */ - texObj->_Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; - } - else { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims); - } - } - } - _mesa_unlock_texture(ctx, texObj); -} - - - -void GLAPIENTRY -_mesa_CopyTexImage1D( GLenum target, GLint level, - GLenum internalFormat, - GLint x, GLint y, - GLsizei width, GLint border ) -{ - GET_CURRENT_CONTEXT(ctx); - copyteximage(ctx, 1, target, level, internalFormat, x, y, width, 1, border); -} - - - -void GLAPIENTRY -_mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat, - GLint x, GLint y, GLsizei width, GLsizei height, - GLint border ) -{ - GET_CURRENT_CONTEXT(ctx); - copyteximage(ctx, 2, target, level, internalFormat, - x, y, width, height, border); -} - - - -/** - * Implementation for glCopyTexSubImage1/2/3D() functions. - */ -static void -copytexsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLint x, GLint y, GLsizei width, GLsizei height) -{ - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) - _mesa_debug(ctx, "glCopyTexSubImage%uD %s %d %d %d %d %d %d %d %d\n", - dims, - _mesa_lookup_enum_by_nr(target), - level, xoffset, yoffset, zoffset, x, y, width, height); - - if (ctx->NewState & NEW_COPY_TEX_STATE) - _mesa_update_state(ctx); - - if (copytexsubimage_error_check1(ctx, dims, target, level)) - return; - - texObj = _mesa_get_current_tex_object(ctx, target); - - _mesa_lock_texture(ctx, texObj); - { - texImage = _mesa_select_tex_image(ctx, texObj, target, level); - - if (copytexsubimage_error_check2(ctx, dims, target, level, xoffset, yoffset, - zoffset, width, height, texImage)) { - /* error was recored */ - } - else { - /* If we have a border, offset=-1 is legal. Bias by border width. */ - switch (dims) { - case 3: - zoffset += texImage->Border; - /* fall-through */ - case 2: - yoffset += texImage->Border; - /* fall-through */ - case 1: - xoffset += texImage->Border; - } - - if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y, - &width, &height)) { - switch (dims) { - case 1: - ctx->Driver.CopyTexSubImage1D(ctx, target, level, - xoffset, x, y, width); - break; - case 2: - ctx->Driver.CopyTexSubImage2D(ctx, target, level, - xoffset, yoffset, - x, y, width, height); - break; - case 3: - ctx->Driver.CopyTexSubImage3D(ctx, target, level, - xoffset, yoffset, zoffset, - x, y, width, height); - break; - default: - _mesa_problem(ctx, "bad dims in copytexsubimage()"); - } - - check_gen_mipmap(ctx, target, texObj, level); - - ctx->NewState |= _NEW_TEXTURE; - } - } - } - _mesa_unlock_texture(ctx, texObj); -} - - -void GLAPIENTRY -_mesa_CopyTexSubImage1D( GLenum target, GLint level, - GLint xoffset, GLint x, GLint y, GLsizei width ) -{ - GET_CURRENT_CONTEXT(ctx); - copytexsubimage(ctx, 1, target, level, xoffset, 0, 0, x, y, width, 1); -} - - - -void GLAPIENTRY -_mesa_CopyTexSubImage2D( GLenum target, GLint level, - GLint xoffset, GLint yoffset, - GLint x, GLint y, GLsizei width, GLsizei height ) -{ - GET_CURRENT_CONTEXT(ctx); - copytexsubimage(ctx, 2, target, level, xoffset, yoffset, 0, x, y, - width, height); -} - - - -void GLAPIENTRY -_mesa_CopyTexSubImage3D( GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLint x, GLint y, GLsizei width, GLsizei height ) -{ - GET_CURRENT_CONTEXT(ctx); - copytexsubimage(ctx, 3, target, level, xoffset, yoffset, zoffset, - x, y, width, height); -} - - - - -/**********************************************************************/ -/****** Compressed Textures ******/ -/**********************************************************************/ - - -/** - * Return expected size of a compressed texture. - */ -static GLuint -compressed_tex_size(GLsizei width, GLsizei height, GLsizei depth, - GLenum glformat) -{ - gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat); - return _mesa_format_image_size(mesaFormat, width, height, depth); -} - - -/* - * Return compressed texture block size, in pixels. - */ -static void -get_compressed_block_size(GLenum glformat, GLuint *bw, GLuint *bh) -{ - gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat); - _mesa_get_format_block_size(mesaFormat, bw, bh); -} - - -/** - * Error checking for glCompressedTexImage[123]D(). - * \return error code or GL_NO_ERROR. - */ -static GLenum -compressed_texture_error_check(struct gl_context *ctx, GLint dimensions, - GLenum target, GLint level, - GLenum internalFormat, GLsizei width, - GLsizei height, GLsizei depth, GLint border, - GLsizei imageSize) -{ - const GLenum proxyTarget = get_proxy_target(target); - const GLint maxLevels = _mesa_max_texture_levels(ctx, target); - GLint expectedSize; - - /* check level */ - if (level < 0 || level >= maxLevels) - return GL_INVALID_VALUE; - - if (!target_can_be_compressed(ctx, target, internalFormat)) { - return GL_INVALID_ENUM; - } - - /* This will detect any invalid internalFormat value */ - if (!_mesa_is_compressed_format(ctx, internalFormat)) - return GL_INVALID_ENUM; - - /* This should really never fail */ - if (_mesa_base_tex_format(ctx, internalFormat) < 0) - return GL_INVALID_ENUM; - - /* No compressed formats support borders at this time */ - if (border != 0) - return GL_INVALID_VALUE; - - /* For cube map, width must equal height */ - if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && - target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB && width != height) - return GL_INVALID_VALUE; - - /* check image size against compression block size */ - { - gl_format texFormat = - ctx->Driver.ChooseTextureFormat(ctx, internalFormat, - GL_NONE, GL_NONE); - GLuint bw, bh; - - _mesa_get_format_block_size(texFormat, &bw, &bh); - if ((width > bw && width % bw > 0) || - (height > bh && height % bh > 0)) { - /* - * Per GL_ARB_texture_compression: GL_INVALID_OPERATION is - * generated [...] if any parameter combinations are not - * supported by the specific compressed internal format. - */ - return GL_INVALID_OPERATION; - } - } - - /* check image sizes */ - if (!ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level, - internalFormat, GL_NONE, GL_NONE, - width, height, depth, border)) { - /* See error comment above */ - return GL_INVALID_OPERATION; - } - - /* check image size in bytes */ - expectedSize = compressed_tex_size(width, height, depth, internalFormat); - if (expectedSize != imageSize) { - /* Per GL_ARB_texture_compression: GL_INVALID_VALUE is generated [...] - * if is not consistent with the format, dimensions, and - * contents of the specified image. - */ - return GL_INVALID_VALUE; - } - - return GL_NO_ERROR; -} - - -/** - * Error checking for glCompressedTexSubImage[123]D(). - * \warning There are some bad assumptions here about the size of compressed - * texture tiles (multiple of 4) used to test the validity of the - * offset and size parameters. - * \return error code or GL_NO_ERROR. - */ -static GLenum -compressed_subtexture_error_check(struct gl_context *ctx, GLint dimensions, - GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLsizei imageSize) -{ - GLint expectedSize, maxLevels = 0, maxTextureSize; - GLuint bw, bh; - (void) zoffset; - - if (dimensions == 1) { - /* 1D compressed textures not allowed */ - return GL_INVALID_ENUM; - } - else if (dimensions == 2) { - if (target == GL_PROXY_TEXTURE_2D) { - maxLevels = ctx->Const.MaxTextureLevels; - } - else if (target == GL_TEXTURE_2D) { - maxLevels = ctx->Const.MaxTextureLevels; - } - else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB) { - if (!ctx->Extensions.ARB_texture_cube_map) - return GL_INVALID_ENUM; /*target*/ - maxLevels = ctx->Const.MaxCubeTextureLevels; - } - else if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && - target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) { - if (!ctx->Extensions.ARB_texture_cube_map) - return GL_INVALID_ENUM; /*target*/ - maxLevels = ctx->Const.MaxCubeTextureLevels; - } - else { - return GL_INVALID_ENUM; /*target*/ - } - } - else if (dimensions == 3) { - /* 3D compressed textures not allowed */ - return GL_INVALID_ENUM; - } - - maxTextureSize = 1 << (maxLevels - 1); - - /* this will catch any invalid compressed format token */ - if (!_mesa_is_compressed_format(ctx, format)) - return GL_INVALID_ENUM; - - if (width < 1 || width > maxTextureSize) - return GL_INVALID_VALUE; - - if ((height < 1 || height > maxTextureSize) - && dimensions > 1) - return GL_INVALID_VALUE; - - if (level < 0 || level >= maxLevels) - return GL_INVALID_VALUE; - - /* - * do checks which depend on compression block size - */ - get_compressed_block_size(format, &bw, &bh); - - if ((xoffset % bw != 0) || (yoffset % bh != 0)) - return GL_INVALID_VALUE; - - if ((width % bw != 0) && width != 2 && width != 1) - return GL_INVALID_VALUE; - - if ((height % bh != 0) && height != 2 && height != 1) - return GL_INVALID_VALUE; - - expectedSize = compressed_tex_size(width, height, depth, format); - if (expectedSize != imageSize) - return GL_INVALID_VALUE; - - return GL_NO_ERROR; -} - - -/** - * Do second part of glCompressedTexSubImage error checking. - * \return GL_TRUE if error found, GL_FALSE otherwise. - */ -static GLboolean -compressed_subtexture_error_check2(struct gl_context *ctx, GLuint dims, - GLsizei width, GLsizei height, - GLsizei depth, GLenum format, - struct gl_texture_image *texImage) -{ - - if ((GLint) format != texImage->InternalFormat) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCompressedTexSubImage%uD(format=0x%x)", dims, format); - return GL_TRUE; - } - - if (((width == 1 || width == 2) && - width != (GLsizei) texImage->Width) || - (width > (GLsizei) texImage->Width)) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCompressedTexSubImage%uD(width=%d)", dims, width); - return GL_TRUE; - } - - if (dims >= 2) { - if (((height == 1 || height == 2) && - height != (GLsizei) texImage->Height) || - (height > (GLsizei) texImage->Height)) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCompressedTexSubImage%uD(height=%d)", dims, height); - return GL_TRUE; - } - } - - if (dims >= 3) { - if (((depth == 1 || depth == 2) && - depth != (GLsizei) texImage->Depth) || - (depth > (GLsizei) texImage->Depth)) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCompressedTexSubImage%uD(depth=%d)", dims, depth); - return GL_TRUE; - } - } - - return GL_FALSE; -} - - -/** - * Implementation of the glCompressedTexImage1/2/3D() functions. - */ -static void -compressedteximage(struct gl_context *ctx, GLuint dims, - GLenum target, GLint level, - GLenum internalFormat, GLsizei width, - GLsizei height, GLsizei depth, GLint border, - GLsizei imageSize, const GLvoid *data) -{ - GLenum error; - - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) - _mesa_debug(ctx, - "glCompressedTexImage%uDARB %s %d %s %d %d %d %d %d %p\n", - dims, - _mesa_lookup_enum_by_nr(target), level, - _mesa_lookup_enum_by_nr(internalFormat), - width, height, depth, border, imageSize, data); - - /* check target */ - if (!legal_teximage_target(ctx, dims, target)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage%uD(target=%s)", - dims, _mesa_lookup_enum_by_nr(target)); - return; - } - - error = compressed_texture_error_check(ctx, dims, target, level, - internalFormat, width, height, depth, - border, imageSize); - -#if FEATURE_ES - /* XXX this is kind of a hack */ - if (error) { - _mesa_error(ctx, error, "glTexImage2D"); - return; - } - - if (dims == 2) { - switch (internalFormat) { - case GL_PALETTE4_RGB8_OES: - case GL_PALETTE4_RGBA8_OES: - case GL_PALETTE4_R5_G6_B5_OES: - case GL_PALETTE4_RGBA4_OES: - case GL_PALETTE4_RGB5_A1_OES: - case GL_PALETTE8_RGB8_OES: - case GL_PALETTE8_RGBA8_OES: - case GL_PALETTE8_R5_G6_B5_OES: - case GL_PALETTE8_RGBA4_OES: - case GL_PALETTE8_RGB5_A1_OES: - _mesa_cpal_compressed_teximage2d(target, level, internalFormat, - width, height, imageSize, data); - return; - } - } -#endif - - if (_mesa_is_proxy_texture(target)) { - /* Proxy texture: just check for errors and update proxy state */ - struct gl_texture_image *texImage; - - if (!error) { - struct gl_texture_object *texObj = - _mesa_get_current_tex_object(ctx, target); - gl_format texFormat = - _mesa_choose_texture_format(ctx, texObj, target, level, - internalFormat, GL_NONE, GL_NONE); - if (!legal_texture_size(ctx, texFormat, width, height, depth)) { - error = GL_OUT_OF_MEMORY; - } - } - - texImage = _mesa_get_proxy_tex_image(ctx, target, level); - if (texImage) { - if (error) { - /* if error, clear all proxy texture image parameters */ - clear_teximage_fields(texImage); - } - else { - /* no error: store the teximage parameters */ - _mesa_init_teximage_fields(ctx, target, texImage, width, height, - depth, border, internalFormat, - MESA_FORMAT_NONE); - } - } - } - else { - /* non-proxy target */ - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - - if (error) { - _mesa_error(ctx, error, "glCompressedTexImage%uD", dims); - return; - } - - texObj = _mesa_get_current_tex_object(ctx, target); - - _mesa_lock_texture(ctx, texObj); - { - texImage = _mesa_get_tex_image(ctx, texObj, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, - "glCompressedTexImage%uD", dims); - } - else { - gl_format texFormat; - - if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - - texFormat = _mesa_choose_texture_format(ctx, texObj, target, level, - internalFormat, GL_NONE, - GL_NONE); - - if (legal_texture_size(ctx, texFormat, width, height, depth)) { - _mesa_init_teximage_fields(ctx, target, texImage, - width, height, depth, - border, internalFormat, texFormat); - - switch (dims) { - case 1: - ASSERT(ctx->Driver.CompressedTexImage1D); - ctx->Driver.CompressedTexImage1D(ctx, target, level, - internalFormat, - width, - border, imageSize, data, - texObj, texImage); - break; - case 2: - ASSERT(ctx->Driver.CompressedTexImage2D); - ctx->Driver.CompressedTexImage2D(ctx, target, level, - internalFormat, - width, height, - border, imageSize, data, - texObj, texImage); - break; - case 3: - ASSERT(ctx->Driver.CompressedTexImage3D); - ctx->Driver.CompressedTexImage3D(ctx, target, level, - internalFormat, - width, height, depth, - border, imageSize, data, - texObj, texImage); - break; - default: - _mesa_problem(ctx, "bad dims in compressedteximage"); - } - - check_gen_mipmap(ctx, target, texObj, level); - - /* state update */ - texObj->_Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; - } - else { - _mesa_error(ctx, GL_OUT_OF_MEMORY, - "glCompressedTexImage%uD", dims); - } - } - } - _mesa_unlock_texture(ctx, texObj); - } -} - - -void GLAPIENTRY -_mesa_CompressedTexImage1DARB(GLenum target, GLint level, - GLenum internalFormat, GLsizei width, - GLint border, GLsizei imageSize, - const GLvoid *data) -{ - GET_CURRENT_CONTEXT(ctx); - compressedteximage(ctx, 1, target, level, internalFormat, - width, 1, 1, border, imageSize, data); -} - - -void GLAPIENTRY -_mesa_CompressedTexImage2DARB(GLenum target, GLint level, - GLenum internalFormat, GLsizei width, - GLsizei height, GLint border, GLsizei imageSize, - const GLvoid *data) -{ - GET_CURRENT_CONTEXT(ctx); - compressedteximage(ctx, 2, target, level, internalFormat, - width, height, 1, border, imageSize, data); -} - - -void GLAPIENTRY -_mesa_CompressedTexImage3DARB(GLenum target, GLint level, - GLenum internalFormat, GLsizei width, - GLsizei height, GLsizei depth, GLint border, - GLsizei imageSize, const GLvoid *data) -{ - GET_CURRENT_CONTEXT(ctx); - compressedteximage(ctx, 3, target, level, internalFormat, - width, height, depth, border, imageSize, data); -} - - -/** - * Common helper for glCompressedTexSubImage1/2/3D(). - */ -static void -compressed_tex_sub_image(GLuint dims, GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLsizei imageSize, const GLvoid *data) -{ - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - GLenum error; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - error = compressed_subtexture_error_check(ctx, dims, target, level, - xoffset, 0, 0, /* pos */ - width, height, depth, /* size */ - format, imageSize); - if (error) { - _mesa_error(ctx, error, "glCompressedTexSubImage%uD", dims); - return; - } - - texObj = _mesa_get_current_tex_object(ctx, target); - - _mesa_lock_texture(ctx, texObj); - { - texImage = _mesa_select_tex_image(ctx, texObj, target, level); - assert(texImage); - - if (compressed_subtexture_error_check2(ctx, dims, width, height, depth, - format, texImage)) { - /* error was recorded */ - } - else if (width > 0 && height > 0 && depth > 0) { - switch (dims) { - case 1: - if (ctx->Driver.CompressedTexSubImage1D) { - ctx->Driver.CompressedTexSubImage1D(ctx, target, level, - xoffset, width, - format, imageSize, data, - texObj, texImage); - } - break; - case 2: - if (ctx->Driver.CompressedTexSubImage2D) { - ctx->Driver.CompressedTexSubImage2D(ctx, target, level, - xoffset, yoffset, - width, height, - format, imageSize, data, - texObj, texImage); - } - break; - case 3: - if (ctx->Driver.CompressedTexSubImage3D) { - ctx->Driver.CompressedTexSubImage3D(ctx, target, level, - xoffset, yoffset, zoffset, - width, height, depth, - format, imageSize, data, - texObj, texImage); - } - break; - default: - ; - } - - check_gen_mipmap(ctx, target, texObj, level); - - ctx->NewState |= _NEW_TEXTURE; - } - } - _mesa_unlock_texture(ctx, texObj); -} - - -void GLAPIENTRY -_mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset, - GLsizei width, GLenum format, - GLsizei imageSize, const GLvoid *data) -{ - compressed_tex_sub_image(1, target, level, xoffset, 0, 0, width, 1, 1, - format, imageSize, data); -} - - -void GLAPIENTRY -_mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset, - GLint yoffset, GLsizei width, GLsizei height, - GLenum format, GLsizei imageSize, - const GLvoid *data) -{ - compressed_tex_sub_image(2, target, level, xoffset, yoffset, 0, - width, height, 1, format, imageSize, data); -} - - -void GLAPIENTRY -_mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset, - GLint yoffset, GLint zoffset, GLsizei width, - GLsizei height, GLsizei depth, GLenum format, - GLsizei imageSize, const GLvoid *data) -{ - compressed_tex_sub_image(3, target, level, xoffset, yoffset, zoffset, - width, height, depth, format, imageSize, data); -} +/* + * mesa 3-D graphics library + * Version: 7.6 + * + * 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 teximage.c + * Texture image-related functions. + */ + + +#include "glheader.h" +#include "bufferobj.h" +#include "context.h" +#include "enums.h" +#include "fbobject.h" +#include "framebuffer.h" +#include "hash.h" +#include "image.h" +#include "imports.h" +#include "macros.h" +#include "mfeatures.h" +#include "state.h" +#include "texcompress.h" +#include "texfetch.h" +#include "teximage.h" +#include "texstate.h" +#include "texpal.h" +#include "mtypes.h" + + +/** + * State changes which we care about for glCopyTex[Sub]Image() calls. + * In particular, we care about pixel transfer state and buffer state + * (such as glReadBuffer to make sure we read from the right renderbuffer). + */ +#define NEW_COPY_TEX_STATE (_MESA_NEW_TRANSFER_STATE | \ + _NEW_BUFFERS | \ + _NEW_PIXEL) + + + +/** + * We allocate texture memory on 512-byte boundaries so we can use MMX/SSE + * elsewhere. + */ +void * +_mesa_alloc_texmemory(GLsizei bytes) +{ + return _mesa_align_malloc(bytes, 512); +} + + +/** + * Free texture memory allocated with _mesa_alloc_texmemory() + */ +void +_mesa_free_texmemory(void *m) +{ + _mesa_align_free(m); +} + + +/* + * Compute floor(log_base_2(n)). + * If n < 0 return -1. + */ +static int +logbase2( int n ) +{ + GLint i = 1; + GLint log2 = 0; + + if (n < 0) + return -1; + + if (n == 0) + return 0; + + while ( n > i ) { + i *= 2; + log2++; + } + if (i != n) { + return log2 - 1; + } + else { + return log2; + } +} + + + +/** + * Return the simple base format for a given internal texture format. + * For example, given GL_LUMINANCE12_ALPHA4, return GL_LUMINANCE_ALPHA. + * + * \param ctx GL context. + * \param internalFormat the internal texture format token or 1, 2, 3, or 4. + * + * \return the corresponding \u base internal format (GL_ALPHA, GL_LUMINANCE, + * GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA), or -1 if invalid enum. + * + * This is the format which is used during texture application (i.e. the + * texture format and env mode determine the arithmetic used. + * + * XXX this could be static + */ +GLint +_mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) +{ + switch (internalFormat) { + case GL_ALPHA: + case GL_ALPHA4: + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16: + return GL_ALPHA; + case 1: + case GL_LUMINANCE: + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + return GL_LUMINANCE; + 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: + return GL_LUMINANCE_ALPHA; + case GL_INTENSITY: + case GL_INTENSITY4: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + return GL_INTENSITY; + case 3: + case GL_RGB: + case GL_R3_G3_B2: + case GL_RGB4: + case GL_RGB5: + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + return GL_RGB; + case 4: + case GL_RGBA: + case GL_RGBA2: + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGBA8: + case GL_RGB10_A2: + case GL_RGBA12: + case GL_RGBA16: + return GL_RGBA; + default: + ; /* fallthrough */ + } + + if (ctx->Extensions.EXT_texture_format_BGRA8888) { + switch (internalFormat) { + case GL_BGRA_EXT: + return GL_RGBA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.EXT_paletted_texture) { + switch (internalFormat) { + 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_COLOR_INDEX; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.ARB_depth_texture) { + switch (internalFormat) { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH_COMPONENT32: + return GL_DEPTH_COMPONENT; + default: + ; /* fallthrough */ + } + } + + switch (internalFormat) { + case GL_COMPRESSED_ALPHA: + return GL_ALPHA; + case GL_COMPRESSED_LUMINANCE: + return GL_LUMINANCE; + case GL_COMPRESSED_LUMINANCE_ALPHA: + return GL_LUMINANCE_ALPHA; + case GL_COMPRESSED_INTENSITY: + return GL_INTENSITY; + case GL_COMPRESSED_RGB: + return GL_RGB; + case GL_COMPRESSED_RGBA: + return GL_RGBA; + default: + ; /* fallthrough */ + } + + if (ctx->Extensions.TDFX_texture_compression_FXT1) { + switch (internalFormat) { + case GL_COMPRESSED_RGB_FXT1_3DFX: + return GL_RGB; + case GL_COMPRESSED_RGBA_FXT1_3DFX: + return GL_RGBA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.EXT_texture_compression_s3tc) { + switch (internalFormat) { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + return GL_RGB; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + return GL_RGBA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.S3_s3tc) { + switch (internalFormat) { + case GL_RGB_S3TC: + case GL_RGB4_S3TC: + return GL_RGB; + case GL_RGBA_S3TC: + case GL_RGBA4_S3TC: + return GL_RGBA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.MESA_ycbcr_texture) { + if (internalFormat == GL_YCBCR_MESA) + return GL_YCBCR_MESA; + } + + if (ctx->Extensions.ARB_texture_float) { + switch (internalFormat) { + case GL_ALPHA16F_ARB: + case GL_ALPHA32F_ARB: + return GL_ALPHA; + case GL_RGBA16F_ARB: + case GL_RGBA32F_ARB: + return GL_RGBA; + case GL_RGB16F_ARB: + case GL_RGB32F_ARB: + return GL_RGB; + case GL_INTENSITY16F_ARB: + case GL_INTENSITY32F_ARB: + return GL_INTENSITY; + case GL_LUMINANCE16F_ARB: + case GL_LUMINANCE32F_ARB: + return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA16F_ARB: + case GL_LUMINANCE_ALPHA32F_ARB: + return GL_LUMINANCE_ALPHA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.ATI_envmap_bumpmap) { + switch (internalFormat) { + case GL_DUDV_ATI: + case GL_DU8DV8_ATI: + return GL_DUDV_ATI; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.MESA_texture_signed_rgba) { + switch (internalFormat) { + case GL_RGBA_SNORM: + case GL_RGBA8_SNORM: + return GL_RGBA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.EXT_packed_depth_stencil) { + switch (internalFormat) { + case GL_DEPTH_STENCIL_EXT: + case GL_DEPTH24_STENCIL8_EXT: + return GL_DEPTH_STENCIL_EXT; + default: + ; /* fallthrough */ + } + } + +#if FEATURE_EXT_texture_sRGB + if (ctx->Extensions.EXT_texture_sRGB) { + switch (internalFormat) { + case GL_SRGB_EXT: + case GL_SRGB8_EXT: + case GL_COMPRESSED_SRGB_EXT: + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + return GL_RGB; + case GL_SRGB_ALPHA_EXT: + case GL_SRGB8_ALPHA8_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: + return GL_RGBA; + case GL_SLUMINANCE_ALPHA_EXT: + case GL_SLUMINANCE8_ALPHA8_EXT: + case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT: + return GL_LUMINANCE_ALPHA; + case GL_SLUMINANCE_EXT: + case GL_SLUMINANCE8_EXT: + case GL_COMPRESSED_SLUMINANCE_EXT: + return GL_LUMINANCE; + default: + ; /* fallthrough */ + } + } +#endif /* FEATURE_EXT_texture_sRGB */ + + if (ctx->Extensions.EXT_texture_integer) { + switch (internalFormat) { + case GL_RGBA8UI_EXT: + case GL_RGBA16UI_EXT: + case GL_RGBA32UI_EXT: + case GL_RGBA8I_EXT: + case GL_RGBA16I_EXT: + case GL_RGBA32I_EXT: + return GL_RGBA; + case GL_RGB8UI_EXT: + case GL_RGB16UI_EXT: + case GL_RGB32UI_EXT: + case GL_RGB8I_EXT: + case GL_RGB16I_EXT: + case GL_RGB32I_EXT: + return GL_RGB; + case GL_ALPHA8UI_EXT: + case GL_ALPHA16UI_EXT: + case GL_ALPHA32UI_EXT: + case GL_ALPHA8I_EXT: + case GL_ALPHA16I_EXT: + case GL_ALPHA32I_EXT: + return GL_ALPHA; + case GL_INTENSITY8UI_EXT: + case GL_INTENSITY16UI_EXT: + case GL_INTENSITY32UI_EXT: + case GL_INTENSITY8I_EXT: + case GL_INTENSITY16I_EXT: + case GL_INTENSITY32I_EXT: + return GL_INTENSITY; + case GL_LUMINANCE8UI_EXT: + case GL_LUMINANCE16UI_EXT: + case GL_LUMINANCE32UI_EXT: + case GL_LUMINANCE8I_EXT: + case GL_LUMINANCE16I_EXT: + case GL_LUMINANCE32I_EXT: + return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA8UI_EXT: + case GL_LUMINANCE_ALPHA16UI_EXT: + case GL_LUMINANCE_ALPHA32UI_EXT: + case GL_LUMINANCE_ALPHA8I_EXT: + case GL_LUMINANCE_ALPHA16I_EXT: + case GL_LUMINANCE_ALPHA32I_EXT: + return GL_LUMINANCE_ALPHA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.ARB_texture_rg) { + switch (internalFormat) { + case GL_R16F: + /* R16F depends on both ARB_half_float_pixel and ARB_texture_float. + */ + if (!ctx->Extensions.ARB_half_float_pixel) + break; + /* FALLTHROUGH */ + case GL_R32F: + if (!ctx->Extensions.ARB_texture_float) + break; + return GL_RED; + case GL_R8I: + case GL_R8UI: + case GL_R16I: + case GL_R16UI: + case GL_R32I: + case GL_R32UI: + if (!ctx->Extensions.EXT_texture_integer) + break; + /* FALLTHROUGH */ + case GL_R8: + case GL_R16: + case GL_RED: + case GL_COMPRESSED_RED: + return GL_RED; + + case GL_RG16F: + /* RG16F depends on both ARB_half_float_pixel and ARB_texture_float. + */ + if (!ctx->Extensions.ARB_half_float_pixel) + break; + /* FALLTHROUGH */ + case GL_RG32F: + if (!ctx->Extensions.ARB_texture_float) + break; + return GL_RG; + case GL_RG8I: + case GL_RG8UI: + case GL_RG16I: + case GL_RG16UI: + case GL_RG32I: + case GL_RG32UI: + if (!ctx->Extensions.EXT_texture_integer) + break; + /* FALLTHROUGH */ + case GL_RG: + case GL_RG8: + case GL_RG16: + case GL_COMPRESSED_RG: + return GL_RG; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.EXT_texture_shared_exponent) { + switch (internalFormat) { + case GL_RGB9_E5_EXT: + return GL_RGB; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.EXT_packed_float) { + switch (internalFormat) { + case GL_R11F_G11F_B10F_EXT: + return GL_RGB; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.ARB_depth_buffer_float) { + switch (internalFormat) { + case GL_DEPTH_COMPONENT32F: + return GL_DEPTH_COMPONENT; + case GL_DEPTH32F_STENCIL8: + return GL_DEPTH_STENCIL; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.ARB_texture_compression_rgtc) { + switch (internalFormat) { + case GL_COMPRESSED_RED_RGTC1: + case GL_COMPRESSED_SIGNED_RED_RGTC1: + return GL_RED; + case GL_COMPRESSED_RG_RGTC2: + case GL_COMPRESSED_SIGNED_RG_RGTC2: + return GL_RG; + default: + ; /* fallthrough */ + } + } + + return -1; /* error */ +} + + +/** + * For cube map faces, return a face index in [0,5]. + * For other targets return 0; + */ +GLuint +_mesa_tex_target_to_face(GLenum target) +{ + if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) + return (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + else + return 0; +} + + + +/** + * Store a gl_texture_image pointer in a gl_texture_object structure + * according to the target and level parameters. + * + * \param tObj texture object. + * \param target texture target. + * \param level image level. + * \param texImage texture image. + * + * This was basically prompted by the introduction of cube maps. + */ +void +_mesa_set_tex_image(struct gl_texture_object *tObj, + GLenum target, GLint level, + struct gl_texture_image *texImage) +{ + const GLuint face = _mesa_tex_target_to_face(target); + + ASSERT(tObj); + ASSERT(texImage); + ASSERT(target != GL_TEXTURE_RECTANGLE_NV || level == 0); + + tObj->Image[face][level] = texImage; + + /* Set the 'back' pointer */ + texImage->TexObject = tObj; +} + + +/** + * Allocate a texture image structure. + * + * Called via ctx->Driver.NewTextureImage() unless overriden by a device + * driver. + * + * \return a pointer to gl_texture_image struct with all fields initialized to + * zero. + */ +struct gl_texture_image * +_mesa_new_texture_image( struct gl_context *ctx ) +{ + (void) ctx; + return CALLOC_STRUCT(gl_texture_image); +} + + +/** + * Free texture image data. + * This function is a fallback called via ctx->Driver.FreeTexImageData(). + * + * \param texImage texture image. + * + * Free the texture image data if it's not marked as client data. + */ +void +_mesa_free_texture_image_data(struct gl_context *ctx, + struct gl_texture_image *texImage) +{ + (void) ctx; + + if (texImage->Data && !texImage->IsClientData) { + /* free the old texture data */ + _mesa_free_texmemory(texImage->Data); + } + + texImage->Data = NULL; +} + + +/** + * Free texture image. + * + * \param texImage texture image. + * + * Free the texture image structure and the associated image data. + */ +void +_mesa_delete_texture_image(struct gl_context *ctx, + struct gl_texture_image *texImage) +{ + /* Free texImage->Data and/or any other driver-specific texture + * image storage. + */ + ASSERT(ctx->Driver.FreeTexImageData); + ctx->Driver.FreeTexImageData( ctx, texImage ); + + ASSERT(texImage->Data == NULL); + if (texImage->ImageOffsets) + free(texImage->ImageOffsets); + free(texImage); +} + + +/** + * Test if a target is a proxy target. + * + * \param target texture target. + * + * \return GL_TRUE if the target is a proxy target, GL_FALSE otherwise. + */ +GLboolean +_mesa_is_proxy_texture(GLenum target) +{ + /* NUM_TEXTURE_TARGETS should match number of terms below */ + assert(NUM_TEXTURE_TARGETS == 7); + + return (target == GL_PROXY_TEXTURE_1D || + target == GL_PROXY_TEXTURE_2D || + target == GL_PROXY_TEXTURE_3D || + target == GL_PROXY_TEXTURE_CUBE_MAP_ARB || + target == GL_PROXY_TEXTURE_RECTANGLE_NV || + target == GL_PROXY_TEXTURE_1D_ARRAY_EXT || + target == GL_PROXY_TEXTURE_2D_ARRAY_EXT); +} + + +/** + * Return the proxy target which corresponds to the given texture target + */ +static GLenum +get_proxy_target(GLenum target) +{ + switch (target) { + case GL_TEXTURE_1D: + case GL_PROXY_TEXTURE_1D: + return GL_PROXY_TEXTURE_1D; + case GL_TEXTURE_2D: + case GL_PROXY_TEXTURE_2D: + return GL_PROXY_TEXTURE_2D; + case GL_TEXTURE_3D: + case GL_PROXY_TEXTURE_3D: + return GL_PROXY_TEXTURE_3D; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_ARB: + case GL_PROXY_TEXTURE_CUBE_MAP_ARB: + return GL_PROXY_TEXTURE_CUBE_MAP_ARB; + case GL_TEXTURE_RECTANGLE_NV: + case GL_PROXY_TEXTURE_RECTANGLE_NV: + return GL_PROXY_TEXTURE_RECTANGLE_NV; + case GL_TEXTURE_1D_ARRAY_EXT: + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + return GL_PROXY_TEXTURE_1D_ARRAY_EXT; + case GL_TEXTURE_2D_ARRAY_EXT: + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + return GL_PROXY_TEXTURE_2D_ARRAY_EXT; + default: + _mesa_problem(NULL, "unexpected target in get_proxy_target()"); + return 0; + } +} + + +/** + * Get the texture object that corresponds to the target of the given + * texture unit. + * + * \param ctx GL context. + * \param texUnit texture unit. + * \param target texture target. + * + * \return pointer to the texture object on success, or NULL on failure. + * + * \sa gl_texture_unit. + */ +struct gl_texture_object * +_mesa_select_tex_object(struct gl_context *ctx, + const struct gl_texture_unit *texUnit, + GLenum target) +{ + const GLboolean arrayTex = (ctx->Extensions.MESA_texture_array || + ctx->Extensions.EXT_texture_array); + + switch (target) { + case GL_TEXTURE_1D: + return texUnit->CurrentTex[TEXTURE_1D_INDEX]; + case GL_PROXY_TEXTURE_1D: + return ctx->Texture.ProxyTex[TEXTURE_1D_INDEX]; + case GL_TEXTURE_2D: + return texUnit->CurrentTex[TEXTURE_2D_INDEX]; + case GL_PROXY_TEXTURE_2D: + return ctx->Texture.ProxyTex[TEXTURE_2D_INDEX]; + case GL_TEXTURE_3D: + return texUnit->CurrentTex[TEXTURE_3D_INDEX]; + case GL_PROXY_TEXTURE_3D: + return ctx->Texture.ProxyTex[TEXTURE_3D_INDEX]; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_ARB: + return ctx->Extensions.ARB_texture_cube_map + ? texUnit->CurrentTex[TEXTURE_CUBE_INDEX] : NULL; + case GL_PROXY_TEXTURE_CUBE_MAP_ARB: + return ctx->Extensions.ARB_texture_cube_map + ? ctx->Texture.ProxyTex[TEXTURE_CUBE_INDEX] : NULL; + case GL_TEXTURE_RECTANGLE_NV: + return ctx->Extensions.NV_texture_rectangle + ? texUnit->CurrentTex[TEXTURE_RECT_INDEX] : NULL; + case GL_PROXY_TEXTURE_RECTANGLE_NV: + return ctx->Extensions.NV_texture_rectangle + ? ctx->Texture.ProxyTex[TEXTURE_RECT_INDEX] : NULL; + case GL_TEXTURE_1D_ARRAY_EXT: + return arrayTex ? texUnit->CurrentTex[TEXTURE_1D_ARRAY_INDEX] : NULL; + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + return arrayTex ? ctx->Texture.ProxyTex[TEXTURE_1D_ARRAY_INDEX] : NULL; + case GL_TEXTURE_2D_ARRAY_EXT: + return arrayTex ? texUnit->CurrentTex[TEXTURE_2D_ARRAY_INDEX] : NULL; + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + return arrayTex ? ctx->Texture.ProxyTex[TEXTURE_2D_ARRAY_INDEX] : NULL; + default: + _mesa_problem(NULL, "bad target in _mesa_select_tex_object()"); + return NULL; + } +} + + +/** + * Return pointer to texture object for given target on current texture unit. + */ +struct gl_texture_object * +_mesa_get_current_tex_object(struct gl_context *ctx, GLenum target) +{ + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + return _mesa_select_tex_object(ctx, texUnit, target); +} + + +/** + * Get a texture image pointer from a texture object, given a texture + * target and mipmap level. The target and level parameters should + * have already been error-checked. + * + * \param ctx GL context. + * \param texObj texture unit. + * \param target texture target. + * \param level image level. + * + * \return pointer to the texture image structure, or NULL on failure. + */ +struct gl_texture_image * +_mesa_select_tex_image(struct gl_context *ctx, + const struct gl_texture_object *texObj, + GLenum target, GLint level) +{ + const GLuint face = _mesa_tex_target_to_face(target); + + ASSERT(texObj); + ASSERT(level >= 0); + ASSERT(level < MAX_TEXTURE_LEVELS); + + return texObj->Image[face][level]; +} + + +/** + * Like _mesa_select_tex_image() but if the image doesn't exist, allocate + * it and install it. Only return NULL if passed a bad parameter or run + * out of memory. + */ +struct gl_texture_image * +_mesa_get_tex_image(struct gl_context *ctx, struct gl_texture_object *texObj, + GLenum target, GLint level) +{ + struct gl_texture_image *texImage; + + if (!texObj) + return NULL; + + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + if (!texImage) { + texImage = ctx->Driver.NewTextureImage(ctx); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture image allocation"); + return NULL; + } + + _mesa_set_tex_image(texObj, target, level, texImage); + } + + return texImage; +} + + +/** + * Return pointer to the specified proxy texture image. + * Note that proxy textures are per-context, not per-texture unit. + * \return pointer to texture image or NULL if invalid target, invalid + * level, or out of memory. + */ +struct gl_texture_image * +_mesa_get_proxy_tex_image(struct gl_context *ctx, GLenum target, GLint level) +{ + struct gl_texture_image *texImage; + GLuint texIndex; + + if (level < 0 ) + return NULL; + + switch (target) { + case GL_PROXY_TEXTURE_1D: + if (level >= ctx->Const.MaxTextureLevels) + return NULL; + texIndex = TEXTURE_1D_INDEX; + break; + case GL_PROXY_TEXTURE_2D: + if (level >= ctx->Const.MaxTextureLevels) + return NULL; + texIndex = TEXTURE_2D_INDEX; + break; + case GL_PROXY_TEXTURE_3D: + if (level >= ctx->Const.Max3DTextureLevels) + return NULL; + texIndex = TEXTURE_3D_INDEX; + break; + case GL_PROXY_TEXTURE_CUBE_MAP: + if (level >= ctx->Const.MaxCubeTextureLevels) + return NULL; + texIndex = TEXTURE_CUBE_INDEX; + break; + case GL_PROXY_TEXTURE_RECTANGLE_NV: + if (level > 0) + return NULL; + texIndex = TEXTURE_RECT_INDEX; + break; + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + if (level >= ctx->Const.MaxTextureLevels) + return NULL; + texIndex = TEXTURE_1D_ARRAY_INDEX; + break; + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + if (level >= ctx->Const.MaxTextureLevels) + return NULL; + texIndex = TEXTURE_2D_ARRAY_INDEX; + break; + default: + return NULL; + } + + texImage = ctx->Texture.ProxyTex[texIndex]->Image[0][level]; + if (!texImage) { + texImage = ctx->Driver.NewTextureImage(ctx); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation"); + return NULL; + } + ctx->Texture.ProxyTex[texIndex]->Image[0][level] = texImage; + /* Set the 'back' pointer */ + texImage->TexObject = ctx->Texture.ProxyTex[texIndex]; + } + return texImage; +} + + +/** + * Get the maximum number of allowed mipmap levels. + * + * \param ctx GL context. + * \param target texture target. + * + * \return the maximum number of allowed mipmap levels for the given + * texture target, or zero if passed a bad target. + * + * \sa gl_constants. + */ +GLint +_mesa_max_texture_levels(struct gl_context *ctx, GLenum target) +{ + switch (target) { + case GL_TEXTURE_1D: + case GL_PROXY_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_PROXY_TEXTURE_2D: + return ctx->Const.MaxTextureLevels; + case GL_TEXTURE_3D: + case GL_PROXY_TEXTURE_3D: + return ctx->Const.Max3DTextureLevels; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_ARB: + case GL_PROXY_TEXTURE_CUBE_MAP_ARB: + return ctx->Extensions.ARB_texture_cube_map + ? ctx->Const.MaxCubeTextureLevels : 0; + case GL_TEXTURE_RECTANGLE_NV: + case GL_PROXY_TEXTURE_RECTANGLE_NV: + return ctx->Extensions.NV_texture_rectangle ? 1 : 0; + case GL_TEXTURE_1D_ARRAY_EXT: + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + case GL_TEXTURE_2D_ARRAY_EXT: + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + return (ctx->Extensions.MESA_texture_array || + ctx->Extensions.EXT_texture_array) + ? ctx->Const.MaxTextureLevels : 0; + default: + return 0; /* bad target */ + } +} + + +/** + * Return number of dimensions per mipmap level for the given texture target. + */ +GLint +_mesa_get_texture_dimensions(GLenum target) +{ + switch (target) { + case GL_TEXTURE_1D: + case GL_PROXY_TEXTURE_1D: + return 1; + case GL_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE: + case GL_TEXTURE_CUBE_MAP: + case GL_PROXY_TEXTURE_2D: + case GL_PROXY_TEXTURE_RECTANGLE: + case GL_PROXY_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + case GL_TEXTURE_1D_ARRAY: + case GL_PROXY_TEXTURE_1D_ARRAY: + return 2; + case GL_TEXTURE_3D: + case GL_PROXY_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + case GL_PROXY_TEXTURE_2D_ARRAY: + return 3; + default: + _mesa_problem(NULL, "invalid target 0x%x in get_texture_dimensions()", + target); + return 2; + } +} + + + + +#if 000 /* not used anymore */ +/* + * glTexImage[123]D can accept a NULL image pointer. In this case we + * create a texture image with unspecified image contents per the OpenGL + * spec. + */ +static GLubyte * +make_null_texture(GLint width, GLint height, GLint depth, GLenum format) +{ + const GLint components = _mesa_components_in_format(format); + const GLint numPixels = width * height * depth; + GLubyte *data = (GLubyte *) MALLOC(numPixels * components * sizeof(GLubyte)); + +#ifdef DEBUG + /* + * Let's see if anyone finds this. If glTexImage2D() is called with + * a NULL image pointer then load the texture image with something + * interesting instead of leaving it indeterminate. + */ + if (data) { + static const char message[8][32] = { + " X X XXXXX XXX X ", + " XX XX X X X X X ", + " X X X X X X X ", + " X X XXXX XXX XXXXX ", + " X X X X X X ", + " X X X X X X X ", + " X X XXXXX XXX X X ", + " " + }; + + GLubyte *imgPtr = data; + GLint h, i, j, k; + for (h = 0; h < depth; h++) { + for (i = 0; i < height; i++) { + GLint srcRow = 7 - (i % 8); + for (j = 0; j < width; j++) { + GLint srcCol = j % 32; + GLubyte texel = (message[srcRow][srcCol]=='X') ? 255 : 70; + for (k = 0; k < components; k++) { + *imgPtr++ = texel; + } + } + } + } + } +#endif + + return data; +} +#endif + + + +/** + * Reset the fields of a gl_texture_image struct to zero. + * + * \param img texture image structure. + * + * This is called when a proxy texture test fails, we set all the + * image members (except DriverData) to zero. + * It's also used in glTexImage[123]D as a safeguard to be sure all + * required fields get initialized properly by the Driver.TexImage[123]D + * functions. + */ +static void +clear_teximage_fields(struct gl_texture_image *img) +{ + ASSERT(img); + img->_BaseFormat = 0; + img->InternalFormat = 0; + img->Border = 0; + img->Width = 0; + img->Height = 0; + img->Depth = 0; + img->RowStride = 0; + if (img->ImageOffsets) { + free(img->ImageOffsets); + img->ImageOffsets = NULL; + } + img->Width2 = 0; + img->Height2 = 0; + img->Depth2 = 0; + img->WidthLog2 = 0; + img->HeightLog2 = 0; + img->DepthLog2 = 0; + img->Data = NULL; + img->TexFormat = MESA_FORMAT_NONE; + img->FetchTexelc = NULL; + img->FetchTexelf = NULL; +} + + +/** + * Initialize basic fields of the gl_texture_image struct. + * + * \param ctx GL context. + * \param target texture target (GL_TEXTURE_1D, GL_TEXTURE_RECTANGLE, etc). + * \param img texture image structure to be initialized. + * \param width image width. + * \param height image height. + * \param depth image depth. + * \param border image border. + * \param internalFormat internal format. + * \param format the actual hardware format (one of MESA_FORMAT_*) + * + * Fills in the fields of \p img with the given information. + * Note: width, height and depth include the border. + */ +void +_mesa_init_teximage_fields(struct gl_context *ctx, GLenum target, + struct gl_texture_image *img, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum internalFormat, + gl_format format) +{ + GLint i, dims; + + ASSERT(img); + ASSERT(width >= 0); + ASSERT(height >= 0); + ASSERT(depth >= 0); + + img->_BaseFormat = _mesa_base_tex_format( ctx, internalFormat ); + ASSERT(img->_BaseFormat > 0); + img->InternalFormat = internalFormat; + img->Border = border; + img->Width = width; + img->Height = height; + img->Depth = depth; + + img->Width2 = width - 2 * border; /* == 1 << img->WidthLog2; */ + img->WidthLog2 = logbase2(img->Width2); + + if (height == 1) { /* 1-D texture */ + img->Height2 = 1; + img->HeightLog2 = 0; + } + else { + img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */ + img->HeightLog2 = logbase2(img->Height2); + } + + if (depth == 1) { /* 2-D texture */ + img->Depth2 = 1; + img->DepthLog2 = 0; + } + else { + img->Depth2 = depth - 2 * border; /* == 1 << img->DepthLog2; */ + img->DepthLog2 = logbase2(img->Depth2); + } + + img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2); + + if ((width == 1 || _mesa_is_pow_two(img->Width2)) && + (height == 1 || _mesa_is_pow_two(img->Height2)) && + (depth == 1 || _mesa_is_pow_two(img->Depth2))) + img->_IsPowerOfTwo = GL_TRUE; + else + img->_IsPowerOfTwo = GL_FALSE; + + /* RowStride and ImageOffsets[] describe how to address texels in 'Data' */ + img->RowStride = width; + /* Allocate the ImageOffsets array and initialize to typical values. + * We allocate the array for 1D/2D textures too in order to avoid special- + * case code in the texstore routines. + */ + if (img->ImageOffsets) + free(img->ImageOffsets); + img->ImageOffsets = (GLuint *) malloc(depth * sizeof(GLuint)); + for (i = 0; i < depth; i++) { + img->ImageOffsets[i] = i * width * height; + } + + /* Compute Width/Height/DepthScale for mipmap lod computation */ + if (target == GL_TEXTURE_RECTANGLE_NV) { + /* scale = 1.0 since texture coords directly map to texels */ + img->WidthScale = 1.0; + img->HeightScale = 1.0; + img->DepthScale = 1.0; + } + else { + img->WidthScale = (GLfloat) img->Width; + img->HeightScale = (GLfloat) img->Height; + img->DepthScale = (GLfloat) img->Depth; + } + + img->TexFormat = format; + + dims = _mesa_get_texture_dimensions(target); + + _mesa_set_fetch_functions(img, dims); +} + + +/** + * Free and clear fields of the gl_texture_image struct. + * + * \param ctx GL context. + * \param texImage texture image structure to be cleared. + * + * After the call, \p texImage will have no data associated with it. Its + * fields are cleared so that its parent object will test incomplete. + */ +void +_mesa_clear_texture_image(struct gl_context *ctx, + struct gl_texture_image *texImage) +{ + ctx->Driver.FreeTexImageData(ctx, texImage); + clear_teximage_fields(texImage); +} + + +/** + * This is the fallback for Driver.TestProxyTexImage(). Test the texture + * level, width, height and depth against the ctx->Const limits for textures. + * + * A hardware driver might override this function if, for example, the + * max 3D texture size is 512x512x64 (i.e. not a cube). + * + * Note that width, height, depth == 0 is not an error. However, a + * texture with zero width/height/depth will be considered "incomplete" + * and texturing will effectively be disabled. + * + * \param target one of GL_PROXY_TEXTURE_1D, GL_PROXY_TEXTURE_2D, + * GL_PROXY_TEXTURE_3D, GL_PROXY_TEXTURE_RECTANGLE_NV, + * GL_PROXY_TEXTURE_CUBE_MAP_ARB. + * \param level as passed to glTexImage + * \param internalFormat as passed to glTexImage + * \param format as passed to glTexImage + * \param type as passed to glTexImage + * \param width as passed to glTexImage + * \param height as passed to glTexImage + * \param depth as passed to glTexImage + * \param border as passed to glTexImage + * \return GL_TRUE if the image is acceptable, GL_FALSE if not acceptable. + */ +GLboolean +_mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level, + GLint internalFormat, GLenum format, GLenum type, + GLint width, GLint height, GLint depth, GLint border) +{ + GLint maxSize; + + (void) internalFormat; + (void) format; + (void) type; + + switch (target) { + case GL_PROXY_TEXTURE_1D: + maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); + if (width < 2 * border || width > 2 + maxSize) + return GL_FALSE; + if (level >= ctx->Const.MaxTextureLevels) + return GL_FALSE; + if (!ctx->Extensions.ARB_texture_non_power_of_two) { + if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) + return GL_FALSE; + } + return GL_TRUE; + + case GL_PROXY_TEXTURE_2D: + maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); + if (width < 2 * border || width > 2 + maxSize) + return GL_FALSE; + if (height < 2 * border || height > 2 + maxSize) + return GL_FALSE; + if (level >= ctx->Const.MaxTextureLevels) + return GL_FALSE; + if (!ctx->Extensions.ARB_texture_non_power_of_two) { + if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) + return GL_FALSE; + if (height > 0 && !_mesa_is_pow_two(height - 2 * border)) + return GL_FALSE; + } + return GL_TRUE; + + case GL_PROXY_TEXTURE_3D: + maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); + if (width < 2 * border || width > 2 + maxSize) + return GL_FALSE; + if (height < 2 * border || height > 2 + maxSize) + return GL_FALSE; + if (depth < 2 * border || depth > 2 + maxSize) + return GL_FALSE; + if (level >= ctx->Const.Max3DTextureLevels) + return GL_FALSE; + if (!ctx->Extensions.ARB_texture_non_power_of_two) { + if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) + return GL_FALSE; + if (height > 0 && !_mesa_is_pow_two(height - 2 * border)) + return GL_FALSE; + if (depth > 0 && !_mesa_is_pow_two(depth - 2 * border)) + return GL_FALSE; + } + return GL_TRUE; + + case GL_PROXY_TEXTURE_RECTANGLE_NV: + maxSize = ctx->Const.MaxTextureRectSize; + if (width < 0 || width > maxSize) + return GL_FALSE; + if (height < 0 || height > maxSize) + return GL_FALSE; + if (level != 0) + return GL_FALSE; + return GL_TRUE; + + case GL_PROXY_TEXTURE_CUBE_MAP_ARB: + maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1); + if (width < 2 * border || width > 2 + maxSize) + return GL_FALSE; + if (height < 2 * border || height > 2 + maxSize) + return GL_FALSE; + if (level >= ctx->Const.MaxCubeTextureLevels) + return GL_FALSE; + if (!ctx->Extensions.ARB_texture_non_power_of_two) { + if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) + return GL_FALSE; + if (height > 0 && !_mesa_is_pow_two(height - 2 * border)) + return GL_FALSE; + } + return GL_TRUE; + + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); + if (width < 2 * border || width > 2 + maxSize) + return GL_FALSE; + if (height < 1 || height > ctx->Const.MaxArrayTextureLayers) + return GL_FALSE; + if (level >= ctx->Const.MaxTextureLevels) + return GL_FALSE; + if (!ctx->Extensions.ARB_texture_non_power_of_two) { + if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) + return GL_FALSE; + } + return GL_TRUE; + + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); + if (width < 2 * border || width > 2 + maxSize) + return GL_FALSE; + if (height < 2 * border || height > 2 + maxSize) + return GL_FALSE; + if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers) + return GL_FALSE; + if (level >= ctx->Const.MaxTextureLevels) + return GL_FALSE; + if (!ctx->Extensions.ARB_texture_non_power_of_two) { + if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) + return GL_FALSE; + if (height > 0 && !_mesa_is_pow_two(height - 2 * border)) + return GL_FALSE; + } + return GL_TRUE; + + default: + _mesa_problem(ctx, "Invalid target in _mesa_test_proxy_teximage"); + return GL_FALSE; + } +} + + +/** + * Check if the memory used by the texture would exceed the driver's limit. + * This lets us support a max 3D texture size of 8K (for example) but + * prevents allocating a full 8K x 8K x 8K texture. + * XXX this could be rolled into the proxy texture size test (above) but + * we don't have the actual texture internal format at that point. + */ +static GLboolean +legal_texture_size(struct gl_context *ctx, gl_format format, + GLint width, GLint height, GLint depth) +{ + uint64_t bytes = _mesa_format_image_size64(format, width, height, depth); + uint64_t mbytes = bytes / (1024 * 1024); /* convert to MB */ + return mbytes <= (uint64_t) ctx->Const.MaxTextureMbytes; +} + + + +/** + * Helper function to determine whether a target and specific compression + * format are supported. + */ +static GLboolean +target_can_be_compressed(const struct gl_context *ctx, GLenum target, + GLenum intFormat) +{ + (void) intFormat; /* not used yet */ + + switch (target) { + case GL_TEXTURE_2D: + case GL_PROXY_TEXTURE_2D: + return GL_TRUE; /* true for any compressed format so far */ + case GL_PROXY_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + return ctx->Extensions.ARB_texture_cube_map; + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + case GL_TEXTURE_2D_ARRAY_EXT: + return (ctx->Extensions.MESA_texture_array || + ctx->Extensions.EXT_texture_array); + default: + return GL_FALSE; + } +} + + +/** + * Check if the given texture target value is legal for a + * glTexImage1/2/3D call. + */ +static GLboolean +legal_teximage_target(struct gl_context *ctx, GLuint dims, GLenum target) +{ + switch (dims) { + case 1: + switch (target) { + case GL_TEXTURE_1D: + case GL_PROXY_TEXTURE_1D: + return GL_TRUE; + default: + return GL_FALSE; + } + case 2: + switch (target) { + case GL_TEXTURE_2D: + case GL_PROXY_TEXTURE_2D: + return GL_TRUE; + case GL_PROXY_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + return ctx->Extensions.ARB_texture_cube_map; + case GL_TEXTURE_RECTANGLE_NV: + case GL_PROXY_TEXTURE_RECTANGLE_NV: + return ctx->Extensions.NV_texture_rectangle; + case GL_TEXTURE_1D_ARRAY_EXT: + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + return (ctx->Extensions.MESA_texture_array || + ctx->Extensions.EXT_texture_array); + default: + return GL_FALSE; + } + case 3: + switch (target) { + case GL_TEXTURE_3D: + case GL_PROXY_TEXTURE_3D: + return GL_TRUE; + case GL_TEXTURE_2D_ARRAY_EXT: + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + return (ctx->Extensions.MESA_texture_array || + ctx->Extensions.EXT_texture_array); + default: + return GL_FALSE; + } + default: + _mesa_problem(ctx, "invalid dims=%u in legal_teximage_target()", dims); + return GL_FALSE; + } +} + + +/** + * Check if the given texture target value is legal for a + * glTexSubImage, glCopyTexSubImage or glCopyTexImage call. + * The difference compared to legal_teximage_target() above is that + * proxy targets are not supported. + */ +static GLboolean +legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target) +{ + switch (dims) { + case 1: + return target == GL_TEXTURE_1D; + case 2: + switch (target) { + case GL_TEXTURE_2D: + return GL_TRUE; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + return ctx->Extensions.ARB_texture_cube_map; + case GL_TEXTURE_RECTANGLE_NV: + return ctx->Extensions.NV_texture_rectangle; + case GL_TEXTURE_1D_ARRAY_EXT: + return (ctx->Extensions.MESA_texture_array || + ctx->Extensions.EXT_texture_array); + default: + return GL_FALSE; + } + case 3: + switch (target) { + case GL_TEXTURE_3D: + return GL_TRUE; + case GL_TEXTURE_2D_ARRAY_EXT: + return (ctx->Extensions.MESA_texture_array || + ctx->Extensions.EXT_texture_array); + default: + return GL_FALSE; + } + default: + _mesa_problem(ctx, "invalid dims=%u in legal_texsubimage_target()", + dims); + return GL_FALSE; + } +} + + +/** + * Test the glTexImage[123]D() parameters for errors. + * + * \param ctx GL context. + * \param dimensions texture image dimensions (must be 1, 2 or 3). + * \param target texture target given by the user. + * \param level image level given by the user. + * \param internalFormat internal format given by the user. + * \param format pixel data format given by the user. + * \param type pixel data type given by the user. + * \param width image width given by the user. + * \param height image height given by the user. + * \param depth image depth given by the user. + * \param border image border given by the user. + * + * \return GL_TRUE if an error was detected, or GL_FALSE if no errors. + * + * Verifies each of the parameters against the constants specified in + * __struct gl_contextRec::Const and the supported extensions, and according + * to the OpenGL specification. + */ +static GLboolean +texture_error_check( struct gl_context *ctx, + GLuint dimensions, GLenum target, + GLint level, GLint internalFormat, + GLenum format, GLenum type, + GLint width, GLint height, + GLint depth, GLint border ) +{ + const GLenum proxyTarget = get_proxy_target(target); + const GLboolean isProxy = target == proxyTarget; + GLboolean sizeOK = GL_TRUE; + GLboolean colorFormat, indexFormat; + + /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */ + if (level < 0 || level >= MAX_TEXTURE_LEVELS) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexImage%dD(level=%d)", dimensions, level); + } + return GL_TRUE; + } + + /* Check border */ + if (border < 0 || border > 1 || + ((target == GL_TEXTURE_RECTANGLE_NV || + target == GL_PROXY_TEXTURE_RECTANGLE_NV) && border != 0)) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexImage%dD(border=%d)", dimensions, border); + } + return GL_TRUE; + } + + if (width < 0 || height < 0 || depth < 0) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexImage%dD(width, height or depth < 0)", dimensions); + } + return GL_TRUE; + } + + /* Do this simple check before calling the TestProxyTexImage() function */ + if (proxyTarget == GL_PROXY_TEXTURE_CUBE_MAP_ARB) { + sizeOK = (width == height); + } + + /* + * Use the proxy texture driver hook to see if the size/level/etc are + * legal. + */ + sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level, + internalFormat, format, + type, width, height, + depth, border); + if (!sizeOK) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexImage%dD(level=%d, width=%d, height=%d, depth=%d)", + dimensions, level, width, height, depth); + } + return GL_TRUE; + } + + /* Check internalFormat */ + if (_mesa_base_tex_format(ctx, internalFormat) < 0) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexImage%dD(internalFormat=%s)", + dimensions, _mesa_lookup_enum_by_nr(internalFormat)); + } + return GL_TRUE; + } + + /* Check incoming image format and type */ + if (!_mesa_is_legal_format_and_type(ctx, format, type)) { + /* Normally, GL_INVALID_OPERATION is generated by a format/type + * mismatch (see the 1.2 spec page 94, sec 3.6.4.). But with the + * GL_EXT_texture_integer extension, some combinations should generate + * GL_INVALID_ENUM instead (grr!). + */ + if (!isProxy) { + GLenum error = _mesa_is_integer_format(format) + ? GL_INVALID_ENUM : GL_INVALID_OPERATION; + _mesa_error(ctx, error, + "glTexImage%dD(incompatible format 0x%x, type 0x%x)", + dimensions, format, type); + } + return GL_TRUE; + } + + /* make sure internal format and format basically agree */ + colorFormat = _mesa_is_color_format(format); + indexFormat = _mesa_is_index_format(format); + if ((_mesa_is_color_format(internalFormat) && !colorFormat && !indexFormat) || + (_mesa_is_index_format(internalFormat) && !indexFormat) || + (_mesa_is_depth_format(internalFormat) != _mesa_is_depth_format(format)) || + (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format)) || + (_mesa_is_depthstencil_format(internalFormat) != _mesa_is_depthstencil_format(format)) || + (_mesa_is_dudv_format(internalFormat) != _mesa_is_dudv_format(format))) { + if (!isProxy) + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexImage%dD(incompatible internalFormat 0x%x, format 0x%x)", + dimensions, internalFormat, format); + return GL_TRUE; + } + + /* additional checks for ycbcr textures */ + if (internalFormat == GL_YCBCR_MESA) { + ASSERT(ctx->Extensions.MESA_ycbcr_texture); + if (type != GL_UNSIGNED_SHORT_8_8_MESA && + type != GL_UNSIGNED_SHORT_8_8_REV_MESA) { + char message[100]; + _mesa_snprintf(message, sizeof(message), + "glTexImage%dD(format/type YCBCR mismatch", dimensions); + _mesa_error(ctx, GL_INVALID_ENUM, "%s", message); + return GL_TRUE; /* error */ + } + if (target != GL_TEXTURE_2D && + target != GL_PROXY_TEXTURE_2D && + target != GL_TEXTURE_RECTANGLE_NV && + target != GL_PROXY_TEXTURE_RECTANGLE_NV) { + if (!isProxy) + _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage(target)"); + return GL_TRUE; + } + if (border != 0) { + if (!isProxy) { + char message[100]; + _mesa_snprintf(message, sizeof(message), + "glTexImage%dD(format=GL_YCBCR_MESA and border=%d)", + dimensions, border); + _mesa_error(ctx, GL_INVALID_VALUE, "%s", message); + } + return GL_TRUE; + } + } + + /* additional checks for depth textures */ + if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT) { + /* Only 1D, 2D and rectangular textures supported, not 3D or cubes */ + if (target != GL_TEXTURE_1D && + target != GL_PROXY_TEXTURE_1D && + target != GL_TEXTURE_2D && + target != GL_PROXY_TEXTURE_2D && + target != GL_TEXTURE_RECTANGLE_ARB && + target != GL_PROXY_TEXTURE_RECTANGLE_ARB) { + if (!isProxy) + _mesa_error(ctx, GL_INVALID_ENUM, + "glTexImage(target/internalFormat)"); + return GL_TRUE; + } + } + + /* additional checks for compressed textures */ + if (_mesa_is_compressed_format(ctx, internalFormat)) { + if (!target_can_be_compressed(ctx, target, internalFormat)) { + if (!isProxy) + _mesa_error(ctx, GL_INVALID_ENUM, + "glTexImage%dD(target)", dimensions); + return GL_TRUE; + } + if (border != 0) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexImage%dD(border!=0)", dimensions); + } + return GL_TRUE; + } + } + + /* additional checks for integer textures */ + if (ctx->Extensions.EXT_texture_integer && + (_mesa_is_integer_format(format) != + _mesa_is_integer_format(internalFormat))) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexImage%dD(integer/non-integer format mismatch)", + dimensions); + } + return GL_TRUE; + } + + /* if we get here, the parameters are OK */ + return GL_FALSE; +} + + +/** + * Test glTexSubImage[123]D() parameters for errors. + * + * \param ctx GL context. + * \param dimensions texture image dimensions (must be 1, 2 or 3). + * \param target texture target given by the user. + * \param level image level given by the user. + * \param xoffset sub-image x offset given by the user. + * \param yoffset sub-image y offset given by the user. + * \param zoffset sub-image z offset given by the user. + * \param format pixel data format given by the user. + * \param type pixel data type given by the user. + * \param width image width given by the user. + * \param height image height given by the user. + * \param depth image depth given by the user. + * + * \return GL_TRUE if an error was detected, or GL_FALSE if no errors. + * + * Verifies each of the parameters against the constants specified in + * __struct gl_contextRec::Const and the supported extensions, and according + * to the OpenGL specification. + */ +static GLboolean +subtexture_error_check( struct gl_context *ctx, GLuint dimensions, + GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint width, GLint height, GLint depth, + GLenum format, GLenum type ) +{ + /* Basic level check */ + if (level < 0 || level >= MAX_TEXTURE_LEVELS) { + _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage2D(level=%d)", level); + return GL_TRUE; + } + + /* Check for negative sizes */ + if (width < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexSubImage%dD(width=%d)", dimensions, width); + return GL_TRUE; + } + if (height < 0 && dimensions > 1) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexSubImage%dD(height=%d)", dimensions, height); + return GL_TRUE; + } + if (depth < 0 && dimensions > 2) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexSubImage%dD(depth=%d)", dimensions, depth); + return GL_TRUE; + } + + if (!_mesa_is_legal_format_and_type(ctx, format, type)) { + /* As with the glTexImage2D check above, the error code here + * depends on texture integer. + */ + GLenum error = _mesa_is_integer_format(format) + ? GL_INVALID_OPERATION : GL_INVALID_ENUM; + _mesa_error(ctx, error, + "glTexSubImage%dD(incompatible format 0x%x, type 0x%x)", + dimensions, format, type); + return GL_TRUE; + } + + return GL_FALSE; +} + + +/** + * Do second part of glTexSubImage which depends on the destination texture. + * \return GL_TRUE if error recorded, GL_FALSE otherwise + */ +static GLboolean +subtexture_error_check2( struct gl_context *ctx, GLuint dimensions, + GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint width, GLint height, GLint depth, + GLenum format, GLenum type, + const struct gl_texture_image *destTex ) +{ + if (!destTex) { + /* undefined image level */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glTexSubImage%dD", dimensions); + return GL_TRUE; + } + + if (xoffset < -((GLint)destTex->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(xoffset)", + dimensions); + return GL_TRUE; + } + if (xoffset + width > (GLint) (destTex->Width + destTex->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(xoffset+width)", + dimensions); + return GL_TRUE; + } + if (dimensions > 1) { + if (yoffset < -((GLint)destTex->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(yoffset)", + dimensions); + return GL_TRUE; + } + if (yoffset + height > (GLint) (destTex->Height + destTex->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(yoffset+height)", + dimensions); + return GL_TRUE; + } + } + if (dimensions > 2) { + if (zoffset < -((GLint)destTex->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset)"); + return GL_TRUE; + } + if (zoffset + depth > (GLint) (destTex->Depth + destTex->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset+depth)"); + return GL_TRUE; + } + } + + if (_mesa_is_format_compressed(destTex->TexFormat)) { + GLuint bw, bh; + + /* do tests which depend on compression block size */ + _mesa_get_format_block_size(destTex->TexFormat, &bw, &bh); + + /* offset must be multiple of block size */ + if ((xoffset % bw != 0) || (yoffset % bh != 0)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexSubImage%dD(xoffset = %d, yoffset = %d)", + dimensions, xoffset, yoffset); + return GL_TRUE; + } + /* size must be multiple of bw by bh or equal to whole texture size */ + if ((width % bw != 0) && (GLuint) width != destTex->Width) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexSubImage%dD(width = %d)", dimensions, width); + return GL_TRUE; + } + if ((height % bh != 0) && (GLuint) height != destTex->Height) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexSubImage%dD(height = %d)", dimensions, height); + return GL_TRUE; + } + } + + return GL_FALSE; +} + + +/** + * Test glCopyTexImage[12]D() parameters for errors. + * + * \param ctx GL context. + * \param dimensions texture image dimensions (must be 1, 2 or 3). + * \param target texture target given by the user. + * \param level image level given by the user. + * \param internalFormat internal format given by the user. + * \param width image width given by the user. + * \param height image height given by the user. + * \param border texture border. + * + * \return GL_TRUE if an error was detected, or GL_FALSE if no errors. + * + * Verifies each of the parameters against the constants specified in + * __struct gl_contextRec::Const and the supported extensions, and according + * to the OpenGL specification. + */ +static GLboolean +copytexture_error_check( struct gl_context *ctx, GLuint dimensions, + GLenum target, GLint level, GLint internalFormat, + GLint width, GLint height, GLint border ) +{ + const GLenum proxyTarget = get_proxy_target(target); + const GLenum type = GL_FLOAT; + GLboolean sizeOK; + GLint format; + + /* check target */ + if (!legal_texsubimage_target(ctx, dimensions, target)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage%uD(target=%s)", + dimensions, _mesa_lookup_enum_by_nr(target)); + return GL_TRUE; + } + + /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */ + if (level < 0 || level >= MAX_TEXTURE_LEVELS) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexImage%dD(level=%d)", dimensions, level); + return GL_TRUE; + } + + /* Check that the source buffer is complete */ + if (ctx->ReadBuffer->Name) { + if (ctx->ReadBuffer->_Status == 0) { + _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer); + } + if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "glCopyTexImage%dD(invalid readbuffer)", dimensions); + return GL_TRUE; + } + } + + /* Check border */ + if (border < 0 || border > 1 || + ((target == GL_TEXTURE_RECTANGLE_NV || + target == GL_PROXY_TEXTURE_RECTANGLE_NV) && border != 0)) { + return GL_TRUE; + } + + format = _mesa_base_tex_format(ctx, internalFormat); + if (format < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexImage%dD(internalFormat)", dimensions); + return GL_TRUE; + } + + if (!_mesa_source_buffer_exists(ctx, format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%dD(missing readbuffer)", dimensions); + return GL_TRUE; + } + + /* Do size, level checking */ + sizeOK = (proxyTarget == GL_PROXY_TEXTURE_CUBE_MAP_ARB) + ? (width == height) : 1; + + sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level, + internalFormat, format, + type, width, height, + 1, border); + + if (!sizeOK) { + if (dimensions == 1) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexImage1D(width=%d)", width); + } + else { + ASSERT(dimensions == 2); + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexImage2D(width=%d, height=%d)", width, height); + } + return GL_TRUE; + } + + if (_mesa_is_compressed_format(ctx, internalFormat)) { + if (!target_can_be_compressed(ctx, target, internalFormat)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glCopyTexImage%dD(target)", dimensions); + return GL_TRUE; + } + if (border != 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%dD(border!=0)", dimensions); + return GL_TRUE; + } + } + else if (_mesa_is_depth_format(internalFormat)) { + /* make sure we have depth/stencil buffers */ + if (!ctx->ReadBuffer->_DepthBuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%dD(no depth)", dimensions); + return GL_TRUE; + } + } + else if (_mesa_is_depthstencil_format(internalFormat)) { + /* make sure we have depth/stencil buffers */ + if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%dD(no depth/stencil buffer)", dimensions); + return GL_TRUE; + } + } + + /* if we get here, the parameters are OK */ + return GL_FALSE; +} + + +/** + * Test glCopyTexSubImage[12]D() parameters for errors. + * Note that this is the first part of error checking. + * See also copytexsubimage_error_check2() below for the second part. + * + * \param ctx GL context. + * \param dimensions texture image dimensions (must be 1, 2 or 3). + * \param target texture target given by the user. + * \param level image level given by the user. + * + * \return GL_TRUE if an error was detected, or GL_FALSE if no errors. + */ +static GLboolean +copytexsubimage_error_check1( struct gl_context *ctx, GLuint dimensions, + GLenum target, GLint level) +{ + /* Check that the source buffer is complete */ + if (ctx->ReadBuffer->Name) { + if (ctx->ReadBuffer->_Status == 0) { + _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer); + } + if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "glCopyTexImage%dD(invalid readbuffer)", dimensions); + return GL_TRUE; + } + } + + /* check target (proxies not allowed) */ + if (!legal_texsubimage_target(ctx, dimensions, target)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexSubImage%uD(target=%s)", + dimensions, _mesa_lookup_enum_by_nr(target)); + return GL_TRUE; + } + + /* Check level */ + if (level < 0 || level >= MAX_TEXTURE_LEVELS) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(level=%d)", dimensions, level); + return GL_TRUE; + } + + return GL_FALSE; +} + + +/** + * Second part of error checking for glCopyTexSubImage[12]D(). + * \param xoffset sub-image x offset given by the user. + * \param yoffset sub-image y offset given by the user. + * \param zoffset sub-image z offset given by the user. + * \param width image width given by the user. + * \param height image height given by the user. + */ +static GLboolean +copytexsubimage_error_check2( struct gl_context *ctx, GLuint dimensions, + GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, + const struct gl_texture_image *teximage ) +{ + /* check that dest tex image exists */ + if (!teximage) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexSubImage%dD(undefined texture level: %d)", + dimensions, level); + return GL_TRUE; + } + + /* Check size */ + if (width < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(width=%d)", dimensions, width); + return GL_TRUE; + } + if (dimensions > 1 && height < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(height=%d)", dimensions, height); + return GL_TRUE; + } + + /* check x/y offsets */ + if (xoffset < -((GLint)teximage->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(xoffset=%d)", dimensions, xoffset); + return GL_TRUE; + } + if (xoffset + width > (GLint) (teximage->Width + teximage->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(xoffset+width)", dimensions); + return GL_TRUE; + } + if (dimensions > 1) { + if (yoffset < -((GLint)teximage->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(yoffset=%d)", dimensions, yoffset); + return GL_TRUE; + } + /* NOTE: we're adding the border here, not subtracting! */ + if (yoffset + height > (GLint) (teximage->Height + teximage->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(yoffset+height)", dimensions); + return GL_TRUE; + } + } + + /* check z offset */ + if (dimensions > 2) { + if (zoffset < -((GLint)teximage->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(zoffset)", dimensions); + return GL_TRUE; + } + if (zoffset > (GLint) (teximage->Depth + teximage->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(zoffset+depth)", dimensions); + return GL_TRUE; + } + } + + if (_mesa_is_format_compressed(teximage->TexFormat)) { + /* offset must be multiple of 4 */ + if ((xoffset & 3) || (yoffset & 3)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(xoffset or yoffset)", dimensions); + return GL_TRUE; + } + /* size must be multiple of 4 */ + if ((width & 3) != 0 && (GLuint) width != teximage->Width) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(width)", dimensions); + return GL_TRUE; + } + if ((height & 3) != 0 && (GLuint) height != teximage->Height) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(height)", dimensions); + return GL_TRUE; + } + } + + if (teximage->InternalFormat == GL_YCBCR_MESA) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyTexSubImage2D"); + return GL_TRUE; + } + + if (!_mesa_source_buffer_exists(ctx, teximage->_BaseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexSubImage%dD(missing readbuffer, format=0x%x)", + dimensions, teximage->_BaseFormat); + return GL_TRUE; + } + + if (teximage->_BaseFormat == GL_DEPTH_COMPONENT) { + if (!ctx->ReadBuffer->_DepthBuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexSubImage%dD(no depth buffer)", + dimensions); + return GL_TRUE; + } + } + else if (teximage->_BaseFormat == GL_DEPTH_STENCIL_EXT) { + if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexSubImage%dD(no depth/stencil buffer)", + dimensions); + return GL_TRUE; + } + } + + /* If copying into an integer texture, the source buffer must also be + * integer-valued. + */ + if (_mesa_is_format_integer_color(teximage->TexFormat)) { + struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; + if (!_mesa_is_format_integer_color(rb->Format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexSubImage%dD(source buffer is not integer format)", + dimensions); + return GL_TRUE; + } + } + + /* if we get here, the parameters are OK */ + return GL_FALSE; +} + + +/** Callback info for walking over FBO hash table */ +struct cb_info +{ + struct gl_context *ctx; + struct gl_texture_object *texObj; + GLuint level, face; +}; + + +/** + * Check render to texture callback. Called from _mesa_HashWalk(). + */ +static void +check_rtt_cb(GLuint key, void *data, void *userData) +{ + struct gl_framebuffer *fb = (struct gl_framebuffer *) data; + const struct cb_info *info = (struct cb_info *) userData; + struct gl_context *ctx = info->ctx; + const struct gl_texture_object *texObj = info->texObj; + const GLuint level = info->level, face = info->face; + + /* If this is a user-created FBO */ + if (fb->Name) { + GLuint i; + /* check if any of the FBO's attachments point to 'texObj' */ + for (i = 0; i < BUFFER_COUNT; i++) { + struct gl_renderbuffer_attachment *att = fb->Attachment + i; + if (att->Type == GL_TEXTURE && + att->Texture == texObj && + att->TextureLevel == level && + att->CubeMapFace == face) { + ASSERT(att->Texture->Image[att->CubeMapFace][att->TextureLevel]); + /* Tell driver about the new renderbuffer texture */ + ctx->Driver.RenderTexture(ctx, ctx->DrawBuffer, att); + /* Mark fb status as indeterminate to force re-validation */ + fb->_Status = 0; + } + } + } +} + + +/** + * When a texture image is specified we have to check if it's bound to + * any framebuffer objects (render to texture) in order to detect changes + * in size or format since that effects FBO completeness. + * Any FBOs rendering into the texture must be re-validated. + */ +static void +update_fbo_texture(struct gl_context *ctx, struct gl_texture_object *texObj, + GLuint face, GLuint level) +{ + /* Only check this texture if it's been marked as RenderToTexture */ + if (texObj->_RenderToTexture) { + struct cb_info info; + info.ctx = ctx; + info.texObj = texObj; + info.level = level; + info.face = face; + _mesa_HashWalk(ctx->Shared->FrameBuffers, check_rtt_cb, &info); + } +} + + +/** + * If the texture object's GenerateMipmap flag is set and we've + * changed the texture base level image, regenerate the rest of the + * mipmap levels now. + */ +static INLINE void +check_gen_mipmap(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj, GLint level) +{ + ASSERT(target != GL_TEXTURE_CUBE_MAP); + if (texObj->GenerateMipmap && + level == texObj->BaseLevel && + level < texObj->MaxLevel) { + ASSERT(ctx->Driver.GenerateMipmap); + ctx->Driver.GenerateMipmap(ctx, target, texObj); + } +} + + +/** Debug helper: override the user-requested internal format */ +static GLenum +override_internal_format(GLenum internalFormat, GLint width, GLint height) +{ +#if 0 + if (internalFormat == GL_RGBA16F_ARB || + internalFormat == GL_RGBA32F_ARB) { + printf("Convert rgba float tex to int %d x %d\n", width, height); + return GL_RGBA; + } + else if (internalFormat == GL_RGB16F_ARB || + internalFormat == GL_RGB32F_ARB) { + printf("Convert rgb float tex to int %d x %d\n", width, height); + return GL_RGB; + } + else if (internalFormat == GL_LUMINANCE_ALPHA16F_ARB || + internalFormat == GL_LUMINANCE_ALPHA32F_ARB) { + printf("Convert luminance float tex to int %d x %d\n", width, height); + return GL_LUMINANCE_ALPHA; + } + else if (internalFormat == GL_LUMINANCE16F_ARB || + internalFormat == GL_LUMINANCE32F_ARB) { + printf("Convert luminance float tex to int %d x %d\n", width, height); + return GL_LUMINANCE; + } + else if (internalFormat == GL_ALPHA16F_ARB || + internalFormat == GL_ALPHA32F_ARB) { + printf("Convert luminance float tex to int %d x %d\n", width, height); + return GL_ALPHA; + } + /* + else if (internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) { + internalFormat = GL_RGBA; + } + */ + else { + return internalFormat; + } +#else + return internalFormat; +#endif +} + + +/** + * Choose the actual hardware format for a texture image. + * Try to use the same format as the previous image level when possible. + * Otherwise, ask the driver for the best format. + * It's important to try to choose a consistant format for all levels + * for efficient texture memory layout/allocation. In particular, this + * comes up during automatic mipmap generation. + */ +gl_format +_mesa_choose_texture_format(struct gl_context *ctx, + struct gl_texture_object *texObj, + GLenum target, GLint level, + GLenum internalFormat, GLenum format, GLenum type) +{ + gl_format f; + + /* see if we've already chosen a format for the previous level */ + if (level > 0) { + struct gl_texture_image *prevImage = + _mesa_select_tex_image(ctx, texObj, target, level - 1); + /* See if the prev level is defined and has an internal format which + * matches the new internal format. + */ + if (prevImage && + prevImage->Width > 0 && + prevImage->InternalFormat == internalFormat) { + /* use the same format */ + ASSERT(prevImage->TexFormat != MESA_FORMAT_NONE); + return prevImage->TexFormat; + } + } + + /* choose format from scratch */ + f = ctx->Driver.ChooseTextureFormat(ctx, internalFormat, format, type); + ASSERT(f != MESA_FORMAT_NONE); + return f; +} + + +/** + * Common code to implement all the glTexImage1D/2D/3D functions. + */ +static void +teximage(struct gl_context *ctx, GLuint dims, + GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, + const GLvoid *pixels) +{ + GLboolean error; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) + _mesa_debug(ctx, "glTexImage%uD %s %d %s %d %d %d %d %s %s %p\n", + dims, + _mesa_lookup_enum_by_nr(target), level, + _mesa_lookup_enum_by_nr(internalFormat), + width, height, depth, border, + _mesa_lookup_enum_by_nr(format), + _mesa_lookup_enum_by_nr(type), pixels); + + internalFormat = override_internal_format(internalFormat, width, height); + + /* target error checking */ + if (!legal_teximage_target(ctx, dims, target)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage%uD(target=%s)", + dims, _mesa_lookup_enum_by_nr(target)); + return; + } + + /* general error checking */ + error = texture_error_check(ctx, dims, target, level, internalFormat, + format, type, width, height, depth, border); + + if (_mesa_is_proxy_texture(target)) { + /* Proxy texture: just clear or set state depending on error checking */ + struct gl_texture_image *texImage = + _mesa_get_proxy_tex_image(ctx, target, level); + + if (error) { + /* when error, clear all proxy texture image parameters */ + if (texImage) + clear_teximage_fields(texImage); + } + else { + /* no error, set the tex image parameters */ + struct gl_texture_object *texObj = + _mesa_get_current_tex_object(ctx, target); + gl_format texFormat = _mesa_choose_texture_format(ctx, texObj, + target, level, + internalFormat, + format, type); + + if (legal_texture_size(ctx, texFormat, width, height, depth)) { + _mesa_init_teximage_fields(ctx, target, texImage, width, height, + depth, border, internalFormat, + texFormat); + } + else if (texImage) { + clear_teximage_fields(texImage); + } + } + } + else { + /* non-proxy target */ + const GLuint face = _mesa_tex_target_to_face(target); + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + + if (error) { + return; /* error was recorded */ + } + + if (ctx->NewState & _MESA_NEW_TRANSFER_STATE) + _mesa_update_state(ctx); + + texObj = _mesa_get_current_tex_object(ctx, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims); + } + else { + gl_format texFormat; + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + + ASSERT(texImage->Data == NULL); + texFormat = _mesa_choose_texture_format(ctx, texObj, target, level, + internalFormat, format, + type); + + if (legal_texture_size(ctx, texFormat, width, height, depth)) { + _mesa_init_teximage_fields(ctx, target, texImage, + width, height, depth, + border, internalFormat, texFormat); + + /* Give the texture to the driver. may be null. */ + ASSERT(ctx->Driver.TexImage3D); + switch (dims) { + case 1: + ctx->Driver.TexImage1D(ctx, target, level, internalFormat, + width, border, format, + type, pixels, &ctx->Unpack, texObj, + texImage); + break; + case 2: + ctx->Driver.TexImage2D(ctx, target, level, internalFormat, + width, height, border, format, + type, pixels, &ctx->Unpack, texObj, + texImage); + break; + case 3: + ctx->Driver.TexImage3D(ctx, target, level, internalFormat, + width, height, depth, border, format, + type, pixels, &ctx->Unpack, texObj, + texImage); + break; + default: + _mesa_problem(ctx, "invalid dims=%u in teximage()", dims); + } + + check_gen_mipmap(ctx, target, texObj, level); + + update_fbo_texture(ctx, texObj, face, level); + + /* state update */ + texObj->_Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims); + } + } + } + _mesa_unlock_texture(ctx, texObj); + } +} + + +/* + * Called from the API. Note that width includes the border. + */ +void GLAPIENTRY +_mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLint border, GLenum format, + GLenum type, const GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + teximage(ctx, 1, target, level, internalFormat, width, 1, 1, + border, format, type, pixels); +} + + +void GLAPIENTRY +_mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, + const GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + teximage(ctx, 2, target, level, internalFormat, width, height, 1, + border, format, type, pixels); +} + + +/* + * Called by the API or display list executor. + * Note that width and height include the border. + */ +void GLAPIENTRY +_mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, + const GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + teximage(ctx, 3, target, level, internalFormat, width, height, depth, + border, format, type, pixels); +} + + +void GLAPIENTRY +_mesa_TexImage3DEXT( GLenum target, GLint level, GLenum internalFormat, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, + const GLvoid *pixels ) +{ + _mesa_TexImage3D(target, level, (GLint) internalFormat, width, height, + depth, border, format, type, pixels); +} + + +#if FEATURE_OES_EGL_image +void GLAPIENTRY +_mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (!ctx->Extensions.OES_EGL_image) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glEGLImageTargetTexture2DOES(unsupported)"); + return; + } + + if (target != GL_TEXTURE_2D) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glEGLImageTargetTexture2D(target=%d)", target); + return; + } + + if (ctx->NewState & _MESA_NEW_TRANSFER_STATE) + _mesa_update_state(ctx); + + texObj = _mesa_get_current_tex_object(ctx, target); + _mesa_lock_texture(ctx, texObj); + + texImage = _mesa_get_tex_image(ctx, texObj, target, 0); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glEGLImageTargetTexture2D"); + } else { + if (texImage->Data) + ctx->Driver.FreeTexImageData( ctx, texImage ); + + ASSERT(texImage->Data == NULL); + ctx->Driver.EGLImageTargetTexture2D(ctx, target, + texObj, texImage, image); + + /* state update */ + texObj->_Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + _mesa_unlock_texture(ctx, texObj); + +} +#endif + + + +/** + * Implement all the glTexSubImage1/2/3D() functions. + */ +static void +texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *pixels ) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) + _mesa_debug(ctx, "glTexSubImage%uD %s %d %d %d %d %d %d %d %s %s %p\n", + dims, + _mesa_lookup_enum_by_nr(target), level, + xoffset, yoffset, zoffset, width, height, depth, + _mesa_lookup_enum_by_nr(format), + _mesa_lookup_enum_by_nr(type), pixels); + + /* check target (proxies not allowed) */ + if (!legal_texsubimage_target(ctx, dims, target)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%uD(target=%s)", + dims, _mesa_lookup_enum_by_nr(target)); + return; + } + + if (ctx->NewState & _MESA_NEW_TRANSFER_STATE) + _mesa_update_state(ctx); + + if (subtexture_error_check(ctx, dims, target, level, xoffset, yoffset, zoffset, + width, height, depth, format, type)) { + return; /* error was detected */ + } + + texObj = _mesa_get_current_tex_object(ctx, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (subtexture_error_check2(ctx, dims, target, level, + xoffset, yoffset, zoffset, + width, height, depth, + format, type, texImage)) { + /* error was recorded */ + } + else if (width > 0 && height > 0 && height > 0) { + /* If we have a border, offset=-1 is legal. Bias by border width. */ + switch (dims) { + case 3: + zoffset += texImage->Border; + /* fall-through */ + case 2: + yoffset += texImage->Border; + /* fall-through */ + case 1: + xoffset += texImage->Border; + } + + switch (dims) { + case 1: + ctx->Driver.TexSubImage1D(ctx, target, level, + xoffset, width, + format, type, pixels, + &ctx->Unpack, texObj, texImage ); + break; + case 2: + ctx->Driver.TexSubImage2D(ctx, target, level, + xoffset, yoffset, width, height, + format, type, pixels, + &ctx->Unpack, texObj, texImage ); + break; + case 3: + ctx->Driver.TexSubImage3D(ctx, target, level, + xoffset, yoffset, zoffset, + width, height, depth, + format, type, pixels, + &ctx->Unpack, texObj, texImage ); + break; + default: + _mesa_problem(ctx, "unexpected dims in subteximage()"); + } + + check_gen_mipmap(ctx, target, texObj, level); + + ctx->NewState |= _NEW_TEXTURE; + } + } + _mesa_unlock_texture(ctx, texObj); +} + + +void GLAPIENTRY +_mesa_TexSubImage1D( GLenum target, GLint level, + GLint xoffset, GLsizei width, + GLenum format, GLenum type, + const GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + texsubimage(ctx, 1, target, level, + xoffset, 0, 0, + width, 1, 1, + format, type, pixels); +} + + +void GLAPIENTRY +_mesa_TexSubImage2D( GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + texsubimage(ctx, 2, target, level, + xoffset, yoffset, 0, + width, height, 1, + format, type, pixels); +} + + + +void GLAPIENTRY +_mesa_TexSubImage3D( GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + const GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + texsubimage(ctx, 3, target, level, + xoffset, yoffset, zoffset, + width, height, depth, + format, type, pixels); +} + + + +/** + * Implement the glCopyTexImage1/2D() functions. + */ +static void +copyteximage(struct gl_context *ctx, GLuint dims, + GLenum target, GLint level, GLenum internalFormat, + GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + const GLuint face = _mesa_tex_target_to_face(target); + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) + _mesa_debug(ctx, "glCopyTexImage%uD %s %d %s %d %d %d %d %d\n", + dims, + _mesa_lookup_enum_by_nr(target), level, + _mesa_lookup_enum_by_nr(internalFormat), + x, y, width, height, border); + + if (ctx->NewState & NEW_COPY_TEX_STATE) + _mesa_update_state(ctx); + + if (copytexture_error_check(ctx, dims, target, level, internalFormat, + width, height, border)) + return; + + texObj = _mesa_get_current_tex_object(ctx, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims); + } + else { + gl_format texFormat; + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + + ASSERT(texImage->Data == NULL); + + texFormat = _mesa_choose_texture_format(ctx, texObj, target, level, + internalFormat, GL_NONE, + GL_NONE); + + if (legal_texture_size(ctx, texFormat, width, height, 1)) { + _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, + border, internalFormat, texFormat); + + ASSERT(ctx->Driver.CopyTexImage2D); + if (dims == 1) + ctx->Driver.CopyTexImage1D(ctx, target, level, internalFormat, + x, y, width, border); + else + ctx->Driver.CopyTexImage2D(ctx, target, level, internalFormat, + x, y, width, height, border); + + check_gen_mipmap(ctx, target, texObj, level); + + update_fbo_texture(ctx, texObj, face, level); + + /* state update */ + texObj->_Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims); + } + } + } + _mesa_unlock_texture(ctx, texObj); +} + + + +void GLAPIENTRY +_mesa_CopyTexImage1D( GLenum target, GLint level, + GLenum internalFormat, + GLint x, GLint y, + GLsizei width, GLint border ) +{ + GET_CURRENT_CONTEXT(ctx); + copyteximage(ctx, 1, target, level, internalFormat, x, y, width, 1, border); +} + + + +void GLAPIENTRY +_mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat, + GLint x, GLint y, GLsizei width, GLsizei height, + GLint border ) +{ + GET_CURRENT_CONTEXT(ctx); + copyteximage(ctx, 2, target, level, internalFormat, + x, y, width, height, border); +} + + + +/** + * Implementation for glCopyTexSubImage1/2/3D() functions. + */ +static void +copytexsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) + _mesa_debug(ctx, "glCopyTexSubImage%uD %s %d %d %d %d %d %d %d %d\n", + dims, + _mesa_lookup_enum_by_nr(target), + level, xoffset, yoffset, zoffset, x, y, width, height); + + if (ctx->NewState & NEW_COPY_TEX_STATE) + _mesa_update_state(ctx); + + if (copytexsubimage_error_check1(ctx, dims, target, level)) + return; + + texObj = _mesa_get_current_tex_object(ctx, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (copytexsubimage_error_check2(ctx, dims, target, level, xoffset, yoffset, + zoffset, width, height, texImage)) { + /* error was recored */ + } + else { + /* If we have a border, offset=-1 is legal. Bias by border width. */ + switch (dims) { + case 3: + zoffset += texImage->Border; + /* fall-through */ + case 2: + yoffset += texImage->Border; + /* fall-through */ + case 1: + xoffset += texImage->Border; + } + + if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y, + &width, &height)) { + switch (dims) { + case 1: + ctx->Driver.CopyTexSubImage1D(ctx, target, level, + xoffset, x, y, width); + break; + case 2: + ctx->Driver.CopyTexSubImage2D(ctx, target, level, + xoffset, yoffset, + x, y, width, height); + break; + case 3: + ctx->Driver.CopyTexSubImage3D(ctx, target, level, + xoffset, yoffset, zoffset, + x, y, width, height); + break; + default: + _mesa_problem(ctx, "bad dims in copytexsubimage()"); + } + + check_gen_mipmap(ctx, target, texObj, level); + + ctx->NewState |= _NEW_TEXTURE; + } + } + } + _mesa_unlock_texture(ctx, texObj); +} + + +void GLAPIENTRY +_mesa_CopyTexSubImage1D( GLenum target, GLint level, + GLint xoffset, GLint x, GLint y, GLsizei width ) +{ + GET_CURRENT_CONTEXT(ctx); + copytexsubimage(ctx, 1, target, level, xoffset, 0, 0, x, y, width, 1); +} + + + +void GLAPIENTRY +_mesa_CopyTexSubImage2D( GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLint x, GLint y, GLsizei width, GLsizei height ) +{ + GET_CURRENT_CONTEXT(ctx); + copytexsubimage(ctx, 2, target, level, xoffset, yoffset, 0, x, y, + width, height); +} + + + +void GLAPIENTRY +_mesa_CopyTexSubImage3D( GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height ) +{ + GET_CURRENT_CONTEXT(ctx); + copytexsubimage(ctx, 3, target, level, xoffset, yoffset, zoffset, + x, y, width, height); +} + + + + +/**********************************************************************/ +/****** Compressed Textures ******/ +/**********************************************************************/ + + +/** + * Return expected size of a compressed texture. + */ +static GLuint +compressed_tex_size(GLsizei width, GLsizei height, GLsizei depth, + GLenum glformat) +{ + gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat); + return _mesa_format_image_size(mesaFormat, width, height, depth); +} + + +/* + * Return compressed texture block size, in pixels. + */ +static void +get_compressed_block_size(GLenum glformat, GLuint *bw, GLuint *bh) +{ + gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat); + _mesa_get_format_block_size(mesaFormat, bw, bh); +} + + +/** + * Error checking for glCompressedTexImage[123]D(). + * \return error code or GL_NO_ERROR. + */ +static GLenum +compressed_texture_error_check(struct gl_context *ctx, GLint dimensions, + GLenum target, GLint level, + GLenum internalFormat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, + GLsizei imageSize) +{ + const GLenum proxyTarget = get_proxy_target(target); + const GLint maxLevels = _mesa_max_texture_levels(ctx, target); + GLint expectedSize; + + /* check level */ + if (level < 0 || level >= maxLevels) + return GL_INVALID_VALUE; + + if (!target_can_be_compressed(ctx, target, internalFormat)) { + return GL_INVALID_ENUM; + } + + /* This will detect any invalid internalFormat value */ + if (!_mesa_is_compressed_format(ctx, internalFormat)) + return GL_INVALID_ENUM; + + /* This should really never fail */ + if (_mesa_base_tex_format(ctx, internalFormat) < 0) + return GL_INVALID_ENUM; + + /* No compressed formats support borders at this time */ + if (border != 0) + return GL_INVALID_VALUE; + + /* For cube map, width must equal height */ + if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB && width != height) + return GL_INVALID_VALUE; + + /* check image size against compression block size */ + { + gl_format texFormat = + ctx->Driver.ChooseTextureFormat(ctx, internalFormat, + GL_NONE, GL_NONE); + GLuint bw, bh; + + _mesa_get_format_block_size(texFormat, &bw, &bh); + if ((width > bw && width % bw > 0) || + (height > bh && height % bh > 0)) { + /* + * Per GL_ARB_texture_compression: GL_INVALID_OPERATION is + * generated [...] if any parameter combinations are not + * supported by the specific compressed internal format. + */ + return GL_INVALID_OPERATION; + } + } + + /* check image sizes */ + if (!ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level, + internalFormat, GL_NONE, GL_NONE, + width, height, depth, border)) { + /* See error comment above */ + return GL_INVALID_OPERATION; + } + + /* check image size in bytes */ + expectedSize = compressed_tex_size(width, height, depth, internalFormat); + if (expectedSize != imageSize) { + /* Per GL_ARB_texture_compression: GL_INVALID_VALUE is generated [...] + * if is not consistent with the format, dimensions, and + * contents of the specified image. + */ + return GL_INVALID_VALUE; + } + + return GL_NO_ERROR; +} + + +/** + * Error checking for glCompressedTexSubImage[123]D(). + * \warning There are some bad assumptions here about the size of compressed + * texture tiles (multiple of 4) used to test the validity of the + * offset and size parameters. + * \return error code or GL_NO_ERROR. + */ +static GLenum +compressed_subtexture_error_check(struct gl_context *ctx, GLint dimensions, + GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLsizei imageSize) +{ + GLint expectedSize, maxLevels = 0, maxTextureSize; + GLuint bw, bh; + (void) zoffset; + + if (dimensions == 1) { + /* 1D compressed textures not allowed */ + return GL_INVALID_ENUM; + } + else if (dimensions == 2) { + if (target == GL_PROXY_TEXTURE_2D) { + maxLevels = ctx->Const.MaxTextureLevels; + } + else if (target == GL_TEXTURE_2D) { + maxLevels = ctx->Const.MaxTextureLevels; + } + else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB) { + if (!ctx->Extensions.ARB_texture_cube_map) + return GL_INVALID_ENUM; /*target*/ + maxLevels = ctx->Const.MaxCubeTextureLevels; + } + else if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) { + if (!ctx->Extensions.ARB_texture_cube_map) + return GL_INVALID_ENUM; /*target*/ + maxLevels = ctx->Const.MaxCubeTextureLevels; + } + else { + return GL_INVALID_ENUM; /*target*/ + } + } + else if (dimensions == 3) { + /* 3D compressed textures not allowed */ + return GL_INVALID_ENUM; + } + + maxTextureSize = 1 << (maxLevels - 1); + + /* this will catch any invalid compressed format token */ + if (!_mesa_is_compressed_format(ctx, format)) + return GL_INVALID_ENUM; + + if (width < 1 || width > maxTextureSize) + return GL_INVALID_VALUE; + + if ((height < 1 || height > maxTextureSize) + && dimensions > 1) + return GL_INVALID_VALUE; + + if (level < 0 || level >= maxLevels) + return GL_INVALID_VALUE; + + /* + * do checks which depend on compression block size + */ + get_compressed_block_size(format, &bw, &bh); + + if ((xoffset % bw != 0) || (yoffset % bh != 0)) + return GL_INVALID_VALUE; + + if ((width % bw != 0) && width != 2 && width != 1) + return GL_INVALID_VALUE; + + if ((height % bh != 0) && height != 2 && height != 1) + return GL_INVALID_VALUE; + + expectedSize = compressed_tex_size(width, height, depth, format); + if (expectedSize != imageSize) + return GL_INVALID_VALUE; + + return GL_NO_ERROR; +} + + +/** + * Do second part of glCompressedTexSubImage error checking. + * \return GL_TRUE if error found, GL_FALSE otherwise. + */ +static GLboolean +compressed_subtexture_error_check2(struct gl_context *ctx, GLuint dims, + GLsizei width, GLsizei height, + GLsizei depth, GLenum format, + struct gl_texture_image *texImage) +{ + + if ((GLint) format != texImage->InternalFormat) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTexSubImage%uD(format=0x%x)", dims, format); + return GL_TRUE; + } + + if (((width == 1 || width == 2) && + width != (GLsizei) texImage->Width) || + (width > (GLsizei) texImage->Width)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCompressedTexSubImage%uD(width=%d)", dims, width); + return GL_TRUE; + } + + if (dims >= 2) { + if (((height == 1 || height == 2) && + height != (GLsizei) texImage->Height) || + (height > (GLsizei) texImage->Height)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCompressedTexSubImage%uD(height=%d)", dims, height); + return GL_TRUE; + } + } + + if (dims >= 3) { + if (((depth == 1 || depth == 2) && + depth != (GLsizei) texImage->Depth) || + (depth > (GLsizei) texImage->Depth)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCompressedTexSubImage%uD(depth=%d)", dims, depth); + return GL_TRUE; + } + } + + return GL_FALSE; +} + + +/** + * Implementation of the glCompressedTexImage1/2/3D() functions. + */ +static void +compressedteximage(struct gl_context *ctx, GLuint dims, + GLenum target, GLint level, + GLenum internalFormat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, + GLsizei imageSize, const GLvoid *data) +{ + GLenum error; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) + _mesa_debug(ctx, + "glCompressedTexImage%uDARB %s %d %s %d %d %d %d %d %p\n", + dims, + _mesa_lookup_enum_by_nr(target), level, + _mesa_lookup_enum_by_nr(internalFormat), + width, height, depth, border, imageSize, data); + + /* check target */ + if (!legal_teximage_target(ctx, dims, target)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage%uD(target=%s)", + dims, _mesa_lookup_enum_by_nr(target)); + return; + } + + error = compressed_texture_error_check(ctx, dims, target, level, + internalFormat, width, height, depth, + border, imageSize); + +#if FEATURE_ES + /* XXX this is kind of a hack */ + if (error) { + _mesa_error(ctx, error, "glTexImage2D"); + return; + } + + if (dims == 2) { + switch (internalFormat) { + case GL_PALETTE4_RGB8_OES: + case GL_PALETTE4_RGBA8_OES: + case GL_PALETTE4_R5_G6_B5_OES: + case GL_PALETTE4_RGBA4_OES: + case GL_PALETTE4_RGB5_A1_OES: + case GL_PALETTE8_RGB8_OES: + case GL_PALETTE8_RGBA8_OES: + case GL_PALETTE8_R5_G6_B5_OES: + case GL_PALETTE8_RGBA4_OES: + case GL_PALETTE8_RGB5_A1_OES: + _mesa_cpal_compressed_teximage2d(target, level, internalFormat, + width, height, imageSize, data); + return; + } + } +#endif + + if (_mesa_is_proxy_texture(target)) { + /* Proxy texture: just check for errors and update proxy state */ + struct gl_texture_image *texImage; + + if (!error) { + struct gl_texture_object *texObj = + _mesa_get_current_tex_object(ctx, target); + gl_format texFormat = + _mesa_choose_texture_format(ctx, texObj, target, level, + internalFormat, GL_NONE, GL_NONE); + if (!legal_texture_size(ctx, texFormat, width, height, depth)) { + error = GL_OUT_OF_MEMORY; + } + } + + texImage = _mesa_get_proxy_tex_image(ctx, target, level); + if (texImage) { + if (error) { + /* if error, clear all proxy texture image parameters */ + clear_teximage_fields(texImage); + } + else { + /* no error: store the teximage parameters */ + _mesa_init_teximage_fields(ctx, target, texImage, width, height, + depth, border, internalFormat, + MESA_FORMAT_NONE); + } + } + } + else { + /* non-proxy target */ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + + if (error) { + _mesa_error(ctx, error, "glCompressedTexImage%uD", dims); + return; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "glCompressedTexImage%uD", dims); + } + else { + gl_format texFormat; + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + ASSERT(texImage->Data == NULL); + + texFormat = _mesa_choose_texture_format(ctx, texObj, target, level, + internalFormat, GL_NONE, + GL_NONE); + + if (legal_texture_size(ctx, texFormat, width, height, depth)) { + _mesa_init_teximage_fields(ctx, target, texImage, + width, height, depth, + border, internalFormat, texFormat); + + switch (dims) { + case 1: + ASSERT(ctx->Driver.CompressedTexImage1D); + ctx->Driver.CompressedTexImage1D(ctx, target, level, + internalFormat, + width, + border, imageSize, data, + texObj, texImage); + break; + case 2: + ASSERT(ctx->Driver.CompressedTexImage2D); + ctx->Driver.CompressedTexImage2D(ctx, target, level, + internalFormat, + width, height, + border, imageSize, data, + texObj, texImage); + break; + case 3: + ASSERT(ctx->Driver.CompressedTexImage3D); + ctx->Driver.CompressedTexImage3D(ctx, target, level, + internalFormat, + width, height, depth, + border, imageSize, data, + texObj, texImage); + break; + default: + _mesa_problem(ctx, "bad dims in compressedteximage"); + } + + check_gen_mipmap(ctx, target, texObj, level); + + /* state update */ + texObj->_Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "glCompressedTexImage%uD", dims); + } + } + } + _mesa_unlock_texture(ctx, texObj); + } +} + + +void GLAPIENTRY +_mesa_CompressedTexImage1DARB(GLenum target, GLint level, + GLenum internalFormat, GLsizei width, + GLint border, GLsizei imageSize, + const GLvoid *data) +{ + GET_CURRENT_CONTEXT(ctx); + compressedteximage(ctx, 1, target, level, internalFormat, + width, 1, 1, border, imageSize, data); +} + + +void GLAPIENTRY +_mesa_CompressedTexImage2DARB(GLenum target, GLint level, + GLenum internalFormat, GLsizei width, + GLsizei height, GLint border, GLsizei imageSize, + const GLvoid *data) +{ + GET_CURRENT_CONTEXT(ctx); + compressedteximage(ctx, 2, target, level, internalFormat, + width, height, 1, border, imageSize, data); +} + + +void GLAPIENTRY +_mesa_CompressedTexImage3DARB(GLenum target, GLint level, + GLenum internalFormat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, + GLsizei imageSize, const GLvoid *data) +{ + GET_CURRENT_CONTEXT(ctx); + compressedteximage(ctx, 3, target, level, internalFormat, + width, height, depth, border, imageSize, data); +} + + +/** + * Common helper for glCompressedTexSubImage1/2/3D(). + */ +static void +compressed_tex_sub_image(GLuint dims, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLsizei imageSize, const GLvoid *data) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GLenum error; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + error = compressed_subtexture_error_check(ctx, dims, target, level, + xoffset, 0, 0, /* pos */ + width, height, depth, /* size */ + format, imageSize); + if (error) { + _mesa_error(ctx, error, "glCompressedTexSubImage%uD", dims); + return; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + assert(texImage); + + if (compressed_subtexture_error_check2(ctx, dims, width, height, depth, + format, texImage)) { + /* error was recorded */ + } + else if (width > 0 && height > 0 && depth > 0) { + switch (dims) { + case 1: + if (ctx->Driver.CompressedTexSubImage1D) { + ctx->Driver.CompressedTexSubImage1D(ctx, target, level, + xoffset, width, + format, imageSize, data, + texObj, texImage); + } + break; + case 2: + if (ctx->Driver.CompressedTexSubImage2D) { + ctx->Driver.CompressedTexSubImage2D(ctx, target, level, + xoffset, yoffset, + width, height, + format, imageSize, data, + texObj, texImage); + } + break; + case 3: + if (ctx->Driver.CompressedTexSubImage3D) { + ctx->Driver.CompressedTexSubImage3D(ctx, target, level, + xoffset, yoffset, zoffset, + width, height, depth, + format, imageSize, data, + texObj, texImage); + } + break; + default: + ; + } + + check_gen_mipmap(ctx, target, texObj, level); + + ctx->NewState |= _NEW_TEXTURE; + } + } + _mesa_unlock_texture(ctx, texObj); +} + + +void GLAPIENTRY +_mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset, + GLsizei width, GLenum format, + GLsizei imageSize, const GLvoid *data) +{ + compressed_tex_sub_image(1, target, level, xoffset, 0, 0, width, 1, 1, + format, imageSize, data); +} + + +void GLAPIENTRY +_mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, + const GLvoid *data) +{ + compressed_tex_sub_image(2, target, level, xoffset, yoffset, 0, + width, height, 1, format, imageSize, data); +} + + +void GLAPIENTRY +_mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, + GLsizei imageSize, const GLvoid *data) +{ + compressed_tex_sub_image(3, target, level, xoffset, yoffset, zoffset, + width, height, depth, format, imageSize, data); +} diff --git a/mesalib/src/mesa/main/texstate.c b/mesalib/src/mesa/main/texstate.c index d86a5a5ec..41d531f59 100644 --- a/mesalib/src/mesa/main/texstate.c +++ b/mesalib/src/mesa/main/texstate.c @@ -1,844 +1,841 @@ -/* - * Mesa 3-D graphics library - * Version: 7.5 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file texstate.c - * - * Texture state handling. - */ - -#include "glheader.h" -#include "mfeatures.h" -#include "colormac.h" -#include "colortab.h" -#include "context.h" -#include "enums.h" -#include "macros.h" -#include "texobj.h" -#include "teximage.h" -#include "texstate.h" -#include "mtypes.h" - - - -/** - * Default texture combine environment state. This is used to initialize - * a context's texture units and as the basis for converting "classic" - * texture environmnets to ARB_texture_env_combine style values. - */ -static const struct gl_tex_env_combine_state default_combine_state = { - GL_MODULATE, GL_MODULATE, - { GL_TEXTURE, GL_PREVIOUS, GL_CONSTANT, GL_CONSTANT }, - { GL_TEXTURE, GL_PREVIOUS, GL_CONSTANT, GL_CONSTANT }, - { GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_ALPHA, GL_SRC_ALPHA }, - { GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA }, - 0, 0, - 2, 2 -}; - - - -/** - * Used by glXCopyContext to copy texture state from one context to another. - */ -void -_mesa_copy_texture_state( const struct gl_context *src, struct gl_context *dst ) -{ - GLuint u, tex; - - ASSERT(src); - ASSERT(dst); - - dst->Texture.CurrentUnit = src->Texture.CurrentUnit; - dst->Texture._GenFlags = src->Texture._GenFlags; - dst->Texture._TexGenEnabled = src->Texture._TexGenEnabled; - dst->Texture._TexMatEnabled = src->Texture._TexMatEnabled; - dst->Texture.SharedPalette = src->Texture.SharedPalette; - - /* per-unit state */ - for (u = 0; u < src->Const.MaxCombinedTextureImageUnits; u++) { - dst->Texture.Unit[u].Enabled = src->Texture.Unit[u].Enabled; - dst->Texture.Unit[u].EnvMode = src->Texture.Unit[u].EnvMode; - COPY_4V(dst->Texture.Unit[u].EnvColor, src->Texture.Unit[u].EnvColor); - dst->Texture.Unit[u].TexGenEnabled = src->Texture.Unit[u].TexGenEnabled; - dst->Texture.Unit[u].GenS = src->Texture.Unit[u].GenS; - dst->Texture.Unit[u].GenT = src->Texture.Unit[u].GenT; - dst->Texture.Unit[u].GenR = src->Texture.Unit[u].GenR; - dst->Texture.Unit[u].GenQ = src->Texture.Unit[u].GenQ; - dst->Texture.Unit[u].LodBias = src->Texture.Unit[u].LodBias; - - /* GL_EXT_texture_env_combine */ - dst->Texture.Unit[u].Combine = src->Texture.Unit[u].Combine; - - /* GL_ATI_envmap_bumpmap - need this? */ - dst->Texture.Unit[u].BumpTarget = src->Texture.Unit[u].BumpTarget; - COPY_4V(dst->Texture.Unit[u].RotMatrix, src->Texture.Unit[u].RotMatrix); - - /* - * XXX strictly speaking, we should compare texture names/ids and - * bind textures in the dest context according to id. For now, only - * copy bindings if the contexts share the same pool of textures to - * avoid refcounting bugs. - */ - if (dst->Shared == src->Shared) { - /* copy texture object bindings, not contents of texture objects */ - _mesa_lock_context_textures(dst); - - for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { - _mesa_reference_texobj(&dst->Texture.Unit[u].CurrentTex[tex], - src->Texture.Unit[u].CurrentTex[tex]); - } - _mesa_unlock_context_textures(dst); - } - } -} - - -/* - * For debugging - */ -void -_mesa_print_texunit_state( struct gl_context *ctx, GLuint unit ) -{ - const struct gl_texture_unit *texUnit = ctx->Texture.Unit + unit; - printf("Texture Unit %d\n", unit); - printf(" GL_TEXTURE_ENV_MODE = %s\n", _mesa_lookup_enum_by_nr(texUnit->EnvMode)); - printf(" GL_COMBINE_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.ModeRGB)); - printf(" GL_COMBINE_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.ModeA)); - printf(" GL_SOURCE0_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceRGB[0])); - printf(" GL_SOURCE1_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceRGB[1])); - printf(" GL_SOURCE2_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceRGB[2])); - printf(" GL_SOURCE0_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceA[0])); - printf(" GL_SOURCE1_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceA[1])); - printf(" GL_SOURCE2_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceA[2])); - printf(" GL_OPERAND0_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandRGB[0])); - printf(" GL_OPERAND1_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandRGB[1])); - printf(" GL_OPERAND2_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandRGB[2])); - printf(" GL_OPERAND0_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandA[0])); - printf(" GL_OPERAND1_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandA[1])); - printf(" GL_OPERAND2_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandA[2])); - printf(" GL_RGB_SCALE = %d\n", 1 << texUnit->Combine.ScaleShiftRGB); - printf(" GL_ALPHA_SCALE = %d\n", 1 << texUnit->Combine.ScaleShiftA); - printf(" GL_TEXTURE_ENV_COLOR = (%f, %f, %f, %f)\n", texUnit->EnvColor[0], texUnit->EnvColor[1], texUnit->EnvColor[2], texUnit->EnvColor[3]); -} - - - -/**********************************************************************/ -/* Texture Environment */ -/**********************************************************************/ - -/** - * Convert "classic" texture environment to ARB_texture_env_combine style - * environments. - * - * \param state texture_env_combine state vector to be filled-in. - * \param mode Classic texture environment mode (i.e., \c GL_REPLACE, - * \c GL_BLEND, \c GL_DECAL, etc.). - * \param texBaseFormat Base format of the texture associated with the - * texture unit. - */ -static void -calculate_derived_texenv( struct gl_tex_env_combine_state *state, - GLenum mode, GLenum texBaseFormat ) -{ - GLenum mode_rgb; - GLenum mode_a; - - *state = default_combine_state; - - switch (texBaseFormat) { - case GL_ALPHA: - state->SourceRGB[0] = GL_PREVIOUS; - break; - - case GL_LUMINANCE_ALPHA: - case GL_INTENSITY: - case GL_RGBA: - break; - - case GL_LUMINANCE: - case GL_RED: - case GL_RG: - case GL_RGB: - case GL_YCBCR_MESA: - case GL_DUDV_ATI: - state->SourceA[0] = GL_PREVIOUS; - break; - - default: - _mesa_problem(NULL, - "Invalid texBaseFormat 0x%x in calculate_derived_texenv", - texBaseFormat); - return; - } - - if (mode == GL_REPLACE_EXT) - mode = GL_REPLACE; - - switch (mode) { - case GL_REPLACE: - case GL_MODULATE: - mode_rgb = (texBaseFormat == GL_ALPHA) ? GL_REPLACE : mode; - mode_a = mode; - break; - - case GL_DECAL: - mode_rgb = GL_INTERPOLATE; - mode_a = GL_REPLACE; - - state->SourceA[0] = GL_PREVIOUS; - - /* Having alpha / luminance / intensity textures replace using the - * incoming fragment color matches the definition in NV_texture_shader. - * The 1.5 spec simply marks these as "undefined". - */ - switch (texBaseFormat) { - case GL_ALPHA: - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - case GL_INTENSITY: - state->SourceRGB[0] = GL_PREVIOUS; - break; - case GL_RED: - case GL_RG: - case GL_RGB: - case GL_YCBCR_MESA: - case GL_DUDV_ATI: - mode_rgb = GL_REPLACE; - break; - case GL_RGBA: - state->SourceRGB[2] = GL_TEXTURE; - break; - } - break; - - case GL_BLEND: - mode_rgb = GL_INTERPOLATE; - mode_a = GL_MODULATE; - - switch (texBaseFormat) { - case GL_ALPHA: - mode_rgb = GL_REPLACE; - break; - case GL_INTENSITY: - mode_a = GL_INTERPOLATE; - state->SourceA[0] = GL_CONSTANT; - state->OperandA[2] = GL_SRC_ALPHA; - /* FALLTHROUGH */ - case GL_LUMINANCE: - case GL_RED: - case GL_RG: - case GL_RGB: - case GL_LUMINANCE_ALPHA: - case GL_RGBA: - case GL_YCBCR_MESA: - case GL_DUDV_ATI: - state->SourceRGB[2] = GL_TEXTURE; - state->SourceA[2] = GL_TEXTURE; - state->SourceRGB[0] = GL_CONSTANT; - state->OperandRGB[2] = GL_SRC_COLOR; - break; - } - break; - - case GL_ADD: - mode_rgb = (texBaseFormat == GL_ALPHA) ? GL_REPLACE : GL_ADD; - mode_a = (texBaseFormat == GL_INTENSITY) ? GL_ADD : GL_MODULATE; - break; - - default: - _mesa_problem(NULL, - "Invalid texture env mode 0x%x in calculate_derived_texenv", - mode); - return; - } - - state->ModeRGB = (state->SourceRGB[0] != GL_PREVIOUS) - ? mode_rgb : GL_REPLACE; - state->ModeA = (state->SourceA[0] != GL_PREVIOUS) - ? mode_a : GL_REPLACE; -} - - - - -/* GL_ARB_multitexture */ -void GLAPIENTRY -_mesa_ActiveTextureARB(GLenum texture) -{ - const GLuint texUnit = texture - GL_TEXTURE0; - GLuint k; - GET_CURRENT_CONTEXT(ctx); - - /* See OpenGL spec for glActiveTexture: */ - k = MAX2(ctx->Const.MaxCombinedTextureImageUnits, - ctx->Const.MaxTextureCoordUnits); - - ASSERT(k <= Elements(ctx->Texture.Unit)); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) - _mesa_debug(ctx, "glActiveTexture %s\n", - _mesa_lookup_enum_by_nr(texture)); - - if (texUnit >= k) { - _mesa_error(ctx, GL_INVALID_ENUM, "glActiveTexture(texture=%s)", - _mesa_lookup_enum_by_nr(texture)); - return; - } - - if (ctx->Texture.CurrentUnit == texUnit) - return; - - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - - ctx->Texture.CurrentUnit = texUnit; - if (ctx->Transform.MatrixMode == GL_TEXTURE) { - /* update current stack pointer */ - ctx->CurrentStack = &ctx->TextureMatrixStack[texUnit]; - } -} - - -/* GL_ARB_multitexture */ -void GLAPIENTRY -_mesa_ClientActiveTextureARB(GLenum texture) -{ - GET_CURRENT_CONTEXT(ctx); - GLuint texUnit = texture - GL_TEXTURE0; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) - _mesa_debug(ctx, "glClientActiveTexture %s\n", - _mesa_lookup_enum_by_nr(texture)); - - if (texUnit >= ctx->Const.MaxTextureCoordUnits) { - _mesa_error(ctx, GL_INVALID_ENUM, "glClientActiveTexture(texture)"); - return; - } - - if (ctx->Array.ActiveTexture == texUnit) - return; - - FLUSH_VERTICES(ctx, _NEW_ARRAY); - ctx->Array.ActiveTexture = texUnit; -} - - - -/**********************************************************************/ -/***** State management *****/ -/**********************************************************************/ - - -/** - * \note This routine refers to derived texture attribute values to - * compute the ENABLE_TEXMAT flags, but is only called on - * _NEW_TEXTURE_MATRIX. On changes to _NEW_TEXTURE, the ENABLE_TEXMAT - * flags are updated by _mesa_update_textures(), below. - * - * \param ctx GL context. - */ -static void -update_texture_matrices( struct gl_context *ctx ) -{ - GLuint u; - - ctx->Texture._TexMatEnabled = 0x0; - - for (u = 0; u < ctx->Const.MaxTextureCoordUnits; u++) { - ASSERT(u < Elements(ctx->TextureMatrixStack)); - if (_math_matrix_is_dirty(ctx->TextureMatrixStack[u].Top)) { - _math_matrix_analyse( ctx->TextureMatrixStack[u].Top ); - - if (ctx->Texture.Unit[u]._ReallyEnabled && - ctx->TextureMatrixStack[u].Top->type != MATRIX_IDENTITY) - ctx->Texture._TexMatEnabled |= ENABLE_TEXMAT(u); - } - } -} - - -/** - * Examine texture unit's combine/env state to update derived state. - */ -static void -update_tex_combine(struct gl_context *ctx, struct gl_texture_unit *texUnit) -{ - struct gl_tex_env_combine_state *combine; - - /* Set the texUnit->_CurrentCombine field to point to the user's combiner - * state, or the combiner state which is derived from traditional texenv - * mode. - */ - if (texUnit->EnvMode == GL_COMBINE || - texUnit->EnvMode == GL_COMBINE4_NV) { - texUnit->_CurrentCombine = & texUnit->Combine; - } - else { - const struct gl_texture_object *texObj = texUnit->_Current; - GLenum format = texObj->Image[0][texObj->BaseLevel]->_BaseFormat; - if (format == GL_COLOR_INDEX) { - format = GL_RGBA; /* a bit of a hack */ - } - else if (format == GL_DEPTH_COMPONENT || - format == GL_DEPTH_STENCIL_EXT) { - format = texObj->DepthMode; - } - calculate_derived_texenv(&texUnit->_EnvMode, texUnit->EnvMode, format); - texUnit->_CurrentCombine = & texUnit->_EnvMode; - } - - combine = texUnit->_CurrentCombine; - - /* Determine number of source RGB terms in the combiner function */ - switch (combine->ModeRGB) { - case GL_REPLACE: - combine->_NumArgsRGB = 1; - break; - case GL_ADD: - case GL_ADD_SIGNED: - if (texUnit->EnvMode == GL_COMBINE4_NV) - combine->_NumArgsRGB = 4; - else - combine->_NumArgsRGB = 2; - break; - case GL_MODULATE: - case GL_SUBTRACT: - case GL_DOT3_RGB: - case GL_DOT3_RGBA: - case GL_DOT3_RGB_EXT: - case GL_DOT3_RGBA_EXT: - combine->_NumArgsRGB = 2; - break; - case GL_INTERPOLATE: - case GL_MODULATE_ADD_ATI: - case GL_MODULATE_SIGNED_ADD_ATI: - case GL_MODULATE_SUBTRACT_ATI: - combine->_NumArgsRGB = 3; - break; - case GL_BUMP_ENVMAP_ATI: - /* no real arguments for this case */ - combine->_NumArgsRGB = 0; - break; - default: - combine->_NumArgsRGB = 0; - _mesa_problem(ctx, "invalid RGB combine mode in update_texture_state"); - return; - } - - /* Determine number of source Alpha terms in the combiner function */ - switch (combine->ModeA) { - case GL_REPLACE: - combine->_NumArgsA = 1; - break; - case GL_ADD: - case GL_ADD_SIGNED: - if (texUnit->EnvMode == GL_COMBINE4_NV) - combine->_NumArgsA = 4; - else - combine->_NumArgsA = 2; - break; - case GL_MODULATE: - case GL_SUBTRACT: - combine->_NumArgsA = 2; - break; - case GL_INTERPOLATE: - case GL_MODULATE_ADD_ATI: - case GL_MODULATE_SIGNED_ADD_ATI: - case GL_MODULATE_SUBTRACT_ATI: - combine->_NumArgsA = 3; - break; - default: - combine->_NumArgsA = 0; - _mesa_problem(ctx, "invalid Alpha combine mode in update_texture_state"); - break; - } -} - - -/** - * \note This routine refers to derived texture matrix values to - * compute the ENABLE_TEXMAT flags, but is only called on - * _NEW_TEXTURE. On changes to _NEW_TEXTURE_MATRIX, the ENABLE_TEXMAT - * flags are updated by _mesa_update_texture_matrices, above. - * - * \param ctx GL context. - */ -static void -update_texture_state( struct gl_context *ctx ) -{ - GLuint unit; - struct gl_fragment_program *fprog = NULL; - struct gl_vertex_program *vprog = NULL; - GLbitfield enabledFragUnits = 0x0; - - if (ctx->Shader.CurrentVertexProgram && - ctx->Shader.CurrentVertexProgram->LinkStatus) { - vprog = ctx->Shader.CurrentVertexProgram->VertexProgram; - } else if (ctx->VertexProgram._Enabled) { - /* XXX enable this if/when non-shader vertex programs get - * texture fetches: - vprog = ctx->VertexProgram.Current; - */ - } - - if (ctx->Shader.CurrentFragmentProgram && - ctx->Shader.CurrentFragmentProgram->LinkStatus) { - fprog = ctx->Shader.CurrentFragmentProgram->FragmentProgram; - } - else if (ctx->FragmentProgram._Enabled) { - fprog = ctx->FragmentProgram.Current; - } - - /* FINISHME: Geometry shader texture accesses should also be considered - * FINISHME: here. - */ - - /* TODO: only set this if there are actual changes */ - ctx->NewState |= _NEW_TEXTURE; - - ctx->Texture._EnabledUnits = 0x0; - ctx->Texture._GenFlags = 0x0; - ctx->Texture._TexMatEnabled = 0x0; - ctx->Texture._TexGenEnabled = 0x0; - - /* - * Update texture unit state. - */ - for (unit = 0; unit < ctx->Const.MaxCombinedTextureImageUnits; unit++) { - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - GLbitfield enabledVertTargets = 0x0; - GLbitfield enabledFragTargets = 0x0; - GLbitfield enabledTargets = 0x0; - GLuint texIndex; - - /* Get the bitmask of texture target enables. - * enableBits will be a mask of the TEXTURE_*_BIT flags indicating - * which texture targets are enabled (fixed function) or referenced - * by a fragment program/program. When multiple flags are set, we'll - * settle on the one with highest priority (see below). - */ - if (vprog) { - enabledVertTargets |= vprog->Base.TexturesUsed[unit]; - } - - if (fprog) { - enabledFragTargets |= fprog->Base.TexturesUsed[unit]; - } - else { - /* fixed-function fragment program */ - enabledFragTargets |= texUnit->Enabled; - } - - enabledTargets = enabledVertTargets | enabledFragTargets; - - texUnit->_ReallyEnabled = 0x0; - - if (enabledTargets == 0x0) { - /* neither vertex nor fragment processing uses this unit */ - continue; - } - - /* Look for the highest priority texture target that's enabled (or used - * by the vert/frag shaders) and "complete". That's the one we'll use - * for texturing. If we're using vert/frag program we're guaranteed - * that bitcount(enabledBits) <= 1. - * Note that the TEXTURE_x_INDEX values are in high to low priority. - */ - for (texIndex = 0; texIndex < NUM_TEXTURE_TARGETS; texIndex++) { - if (enabledTargets & (1 << texIndex)) { - struct gl_texture_object *texObj = texUnit->CurrentTex[texIndex]; - if (!texObj->_Complete) { - _mesa_test_texobj_completeness(ctx, texObj); - } - if (texObj->_Complete) { - texUnit->_ReallyEnabled = 1 << texIndex; - _mesa_reference_texobj(&texUnit->_Current, texObj); - break; - } - } - } - - if (!texUnit->_ReallyEnabled) { - if (fprog) { - /* If we get here it means the shader is expecting a texture - * object, but there isn't one (or it's incomplete). Use the - * fallback texture. - */ - struct gl_texture_object *texObj = _mesa_get_fallback_texture(ctx); - texUnit->_ReallyEnabled = 1 << TEXTURE_2D_INDEX; - _mesa_reference_texobj(&texUnit->_Current, texObj); - } - else { - /* fixed-function: texture unit is really disabled */ - continue; - } - } - - /* if we get here, we know this texture unit is enabled */ - - ctx->Texture._EnabledUnits |= (1 << unit); - - if (enabledFragTargets) - enabledFragUnits |= (1 << unit); - - update_tex_combine(ctx, texUnit); - } - - - /* Determine which texture coordinate sets are actually needed */ - if (fprog) { - const GLuint coordMask = (1 << MAX_TEXTURE_COORD_UNITS) - 1; - ctx->Texture._EnabledCoordUnits - = (fprog->Base.InputsRead >> FRAG_ATTRIB_TEX0) & coordMask; - } - else { - ctx->Texture._EnabledCoordUnits = enabledFragUnits; - } - - /* Setup texgen for those texture coordinate sets that are in use */ - for (unit = 0; unit < ctx->Const.MaxTextureCoordUnits; unit++) { - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - - texUnit->_GenFlags = 0x0; - - if (!(ctx->Texture._EnabledCoordUnits & (1 << unit))) - continue; - - if (texUnit->TexGenEnabled) { - if (texUnit->TexGenEnabled & S_BIT) { - texUnit->_GenFlags |= texUnit->GenS._ModeBit; - } - if (texUnit->TexGenEnabled & T_BIT) { - texUnit->_GenFlags |= texUnit->GenT._ModeBit; - } - if (texUnit->TexGenEnabled & R_BIT) { - texUnit->_GenFlags |= texUnit->GenR._ModeBit; - } - if (texUnit->TexGenEnabled & Q_BIT) { - texUnit->_GenFlags |= texUnit->GenQ._ModeBit; - } - - ctx->Texture._TexGenEnabled |= ENABLE_TEXGEN(unit); - ctx->Texture._GenFlags |= texUnit->_GenFlags; - } - - ASSERT(unit < Elements(ctx->TextureMatrixStack)); - if (ctx->TextureMatrixStack[unit].Top->type != MATRIX_IDENTITY) - ctx->Texture._TexMatEnabled |= ENABLE_TEXMAT(unit); - } -} - - -/** - * Update texture-related derived state. - */ -void -_mesa_update_texture( struct gl_context *ctx, GLuint new_state ) -{ - if (new_state & _NEW_TEXTURE_MATRIX) - update_texture_matrices( ctx ); - - if (new_state & (_NEW_TEXTURE | _NEW_PROGRAM)) - update_texture_state( ctx ); -} - - -/**********************************************************************/ -/***** Initialization *****/ -/**********************************************************************/ - -/** - * Allocate the proxy textures for the given context. - * - * \param ctx the context to allocate proxies for. - * - * \return GL_TRUE on success, or GL_FALSE on failure - * - * If run out of memory part way through the allocations, clean up and return - * GL_FALSE. - */ -static GLboolean -alloc_proxy_textures( struct gl_context *ctx ) -{ - static const GLenum targets[] = { - GL_TEXTURE_1D, - GL_TEXTURE_2D, - GL_TEXTURE_3D, - GL_TEXTURE_CUBE_MAP_ARB, - GL_TEXTURE_RECTANGLE_NV, - GL_TEXTURE_1D_ARRAY_EXT, - GL_TEXTURE_2D_ARRAY_EXT - }; - GLint tgt; - - ASSERT(Elements(targets) == NUM_TEXTURE_TARGETS); - - for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { - if (!(ctx->Texture.ProxyTex[tgt] - = ctx->Driver.NewTextureObject(ctx, 0, targets[tgt]))) { - /* out of memory, free what we did allocate */ - while (--tgt >= 0) { - ctx->Driver.DeleteTexture(ctx, ctx->Texture.ProxyTex[tgt]); - } - return GL_FALSE; - } - } - - assert(ctx->Texture.ProxyTex[0]->RefCount == 1); /* sanity check */ - return GL_TRUE; -} - - -/** - * Initialize a texture unit. - * - * \param ctx GL context. - * \param unit texture unit number to be initialized. - */ -static void -init_texture_unit( struct gl_context *ctx, GLuint unit ) -{ - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - GLuint tex; - - texUnit->EnvMode = GL_MODULATE; - ASSIGN_4V( texUnit->EnvColor, 0.0, 0.0, 0.0, 0.0 ); - - texUnit->Combine = default_combine_state; - texUnit->_EnvMode = default_combine_state; - texUnit->_CurrentCombine = & texUnit->_EnvMode; - texUnit->BumpTarget = GL_TEXTURE0; - - texUnit->TexGenEnabled = 0x0; - texUnit->GenS.Mode = GL_EYE_LINEAR; - texUnit->GenT.Mode = GL_EYE_LINEAR; - texUnit->GenR.Mode = GL_EYE_LINEAR; - texUnit->GenQ.Mode = GL_EYE_LINEAR; - texUnit->GenS._ModeBit = TEXGEN_EYE_LINEAR; - texUnit->GenT._ModeBit = TEXGEN_EYE_LINEAR; - texUnit->GenR._ModeBit = TEXGEN_EYE_LINEAR; - texUnit->GenQ._ModeBit = TEXGEN_EYE_LINEAR; - - /* Yes, these plane coefficients are correct! */ - ASSIGN_4V( texUnit->GenS.ObjectPlane, 1.0, 0.0, 0.0, 0.0 ); - ASSIGN_4V( texUnit->GenT.ObjectPlane, 0.0, 1.0, 0.0, 0.0 ); - ASSIGN_4V( texUnit->GenR.ObjectPlane, 0.0, 0.0, 0.0, 0.0 ); - ASSIGN_4V( texUnit->GenQ.ObjectPlane, 0.0, 0.0, 0.0, 0.0 ); - ASSIGN_4V( texUnit->GenS.EyePlane, 1.0, 0.0, 0.0, 0.0 ); - ASSIGN_4V( texUnit->GenT.EyePlane, 0.0, 1.0, 0.0, 0.0 ); - ASSIGN_4V( texUnit->GenR.EyePlane, 0.0, 0.0, 0.0, 0.0 ); - ASSIGN_4V( texUnit->GenQ.EyePlane, 0.0, 0.0, 0.0, 0.0 ); - - /* no mention of this in spec, but maybe id matrix expected? */ - ASSIGN_4V( texUnit->RotMatrix, 1.0, 0.0, 0.0, 1.0 ); - - /* initialize current texture object ptrs to the shared default objects */ - for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { - _mesa_reference_texobj(&texUnit->CurrentTex[tex], - ctx->Shared->DefaultTex[tex]); - } -} - - -/** - * Initialize texture state for the given context. - */ -GLboolean -_mesa_init_texture(struct gl_context *ctx) -{ - GLuint u; - - /* Texture group */ - ctx->Texture.CurrentUnit = 0; /* multitexture */ - ctx->Texture._EnabledUnits = 0x0; - ctx->Texture.SharedPalette = GL_FALSE; - _mesa_init_colortable(&ctx->Texture.Palette); - - for (u = 0; u < Elements(ctx->Texture.Unit); u++) - init_texture_unit(ctx, u); - - /* After we're done initializing the context's texture state the default - * texture objects' refcounts should be at least - * MAX_COMBINED_TEXTURE_IMAGE_UNITS + 1. - */ - assert(ctx->Shared->DefaultTex[TEXTURE_1D_INDEX]->RefCount - >= MAX_COMBINED_TEXTURE_IMAGE_UNITS + 1); - - /* Allocate proxy textures */ - if (!alloc_proxy_textures( ctx )) - return GL_FALSE; - - return GL_TRUE; -} - - -/** - * Free dynamically-allocted texture data attached to the given context. - */ -void -_mesa_free_texture_data(struct gl_context *ctx) -{ - GLuint u, tgt; - - /* unreference current textures */ - for (u = 0; u < Elements(ctx->Texture.Unit); u++) { - /* The _Current texture could account for another reference */ - _mesa_reference_texobj(&ctx->Texture.Unit[u]._Current, NULL); - - for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { - _mesa_reference_texobj(&ctx->Texture.Unit[u].CurrentTex[tgt], NULL); - } - } - - /* Free proxy texture objects */ - for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) - ctx->Driver.DeleteTexture(ctx, ctx->Texture.ProxyTex[tgt]); - - for (u = 0; u < Elements(ctx->Texture.Unit); u++) - _mesa_free_colortable_data(&ctx->Texture.Unit[u].ColorTable); -} - - -/** - * Update the default texture objects in the given context to reference those - * specified in the shared state and release those referencing the old - * shared state. - */ -void -_mesa_update_default_objects_texture(struct gl_context *ctx) -{ - GLuint u, tex; - - for (u = 0; u < Elements(ctx->Texture.Unit); u++) { - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[u]; - for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { - _mesa_reference_texobj(&texUnit->CurrentTex[tex], - ctx->Shared->DefaultTex[tex]); - } - } -} +/* + * Mesa 3-D graphics library + * Version: 7.5 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file texstate.c + * + * Texture state handling. + */ + +#include "glheader.h" +#include "mfeatures.h" +#include "colormac.h" +#include "colortab.h" +#include "context.h" +#include "enums.h" +#include "macros.h" +#include "texobj.h" +#include "teximage.h" +#include "texstate.h" +#include "mtypes.h" + + + +/** + * Default texture combine environment state. This is used to initialize + * a context's texture units and as the basis for converting "classic" + * texture environmnets to ARB_texture_env_combine style values. + */ +static const struct gl_tex_env_combine_state default_combine_state = { + GL_MODULATE, GL_MODULATE, + { GL_TEXTURE, GL_PREVIOUS, GL_CONSTANT, GL_CONSTANT }, + { GL_TEXTURE, GL_PREVIOUS, GL_CONSTANT, GL_CONSTANT }, + { GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_ALPHA, GL_SRC_ALPHA }, + { GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA }, + 0, 0, + 2, 2 +}; + + + +/** + * Used by glXCopyContext to copy texture state from one context to another. + */ +void +_mesa_copy_texture_state( const struct gl_context *src, struct gl_context *dst ) +{ + GLuint u, tex; + + ASSERT(src); + ASSERT(dst); + + dst->Texture.CurrentUnit = src->Texture.CurrentUnit; + dst->Texture._GenFlags = src->Texture._GenFlags; + dst->Texture._TexGenEnabled = src->Texture._TexGenEnabled; + dst->Texture._TexMatEnabled = src->Texture._TexMatEnabled; + dst->Texture.SharedPalette = src->Texture.SharedPalette; + + /* per-unit state */ + for (u = 0; u < src->Const.MaxCombinedTextureImageUnits; u++) { + dst->Texture.Unit[u].Enabled = src->Texture.Unit[u].Enabled; + dst->Texture.Unit[u].EnvMode = src->Texture.Unit[u].EnvMode; + COPY_4V(dst->Texture.Unit[u].EnvColor, src->Texture.Unit[u].EnvColor); + dst->Texture.Unit[u].TexGenEnabled = src->Texture.Unit[u].TexGenEnabled; + dst->Texture.Unit[u].GenS = src->Texture.Unit[u].GenS; + dst->Texture.Unit[u].GenT = src->Texture.Unit[u].GenT; + dst->Texture.Unit[u].GenR = src->Texture.Unit[u].GenR; + dst->Texture.Unit[u].GenQ = src->Texture.Unit[u].GenQ; + dst->Texture.Unit[u].LodBias = src->Texture.Unit[u].LodBias; + + /* GL_EXT_texture_env_combine */ + dst->Texture.Unit[u].Combine = src->Texture.Unit[u].Combine; + + /* GL_ATI_envmap_bumpmap - need this? */ + dst->Texture.Unit[u].BumpTarget = src->Texture.Unit[u].BumpTarget; + COPY_4V(dst->Texture.Unit[u].RotMatrix, src->Texture.Unit[u].RotMatrix); + + /* + * XXX strictly speaking, we should compare texture names/ids and + * bind textures in the dest context according to id. For now, only + * copy bindings if the contexts share the same pool of textures to + * avoid refcounting bugs. + */ + if (dst->Shared == src->Shared) { + /* copy texture object bindings, not contents of texture objects */ + _mesa_lock_context_textures(dst); + + for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { + _mesa_reference_texobj(&dst->Texture.Unit[u].CurrentTex[tex], + src->Texture.Unit[u].CurrentTex[tex]); + } + _mesa_unlock_context_textures(dst); + } + } +} + + +/* + * For debugging + */ +void +_mesa_print_texunit_state( struct gl_context *ctx, GLuint unit ) +{ + const struct gl_texture_unit *texUnit = ctx->Texture.Unit + unit; + printf("Texture Unit %d\n", unit); + printf(" GL_TEXTURE_ENV_MODE = %s\n", _mesa_lookup_enum_by_nr(texUnit->EnvMode)); + printf(" GL_COMBINE_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.ModeRGB)); + printf(" GL_COMBINE_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.ModeA)); + printf(" GL_SOURCE0_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceRGB[0])); + printf(" GL_SOURCE1_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceRGB[1])); + printf(" GL_SOURCE2_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceRGB[2])); + printf(" GL_SOURCE0_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceA[0])); + printf(" GL_SOURCE1_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceA[1])); + printf(" GL_SOURCE2_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceA[2])); + printf(" GL_OPERAND0_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandRGB[0])); + printf(" GL_OPERAND1_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandRGB[1])); + printf(" GL_OPERAND2_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandRGB[2])); + printf(" GL_OPERAND0_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandA[0])); + printf(" GL_OPERAND1_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandA[1])); + printf(" GL_OPERAND2_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandA[2])); + printf(" GL_RGB_SCALE = %d\n", 1 << texUnit->Combine.ScaleShiftRGB); + printf(" GL_ALPHA_SCALE = %d\n", 1 << texUnit->Combine.ScaleShiftA); + printf(" GL_TEXTURE_ENV_COLOR = (%f, %f, %f, %f)\n", texUnit->EnvColor[0], texUnit->EnvColor[1], texUnit->EnvColor[2], texUnit->EnvColor[3]); +} + + + +/**********************************************************************/ +/* Texture Environment */ +/**********************************************************************/ + +/** + * Convert "classic" texture environment to ARB_texture_env_combine style + * environments. + * + * \param state texture_env_combine state vector to be filled-in. + * \param mode Classic texture environment mode (i.e., \c GL_REPLACE, + * \c GL_BLEND, \c GL_DECAL, etc.). + * \param texBaseFormat Base format of the texture associated with the + * texture unit. + */ +static void +calculate_derived_texenv( struct gl_tex_env_combine_state *state, + GLenum mode, GLenum texBaseFormat ) +{ + GLenum mode_rgb; + GLenum mode_a; + + *state = default_combine_state; + + switch (texBaseFormat) { + case GL_ALPHA: + state->SourceRGB[0] = GL_PREVIOUS; + break; + + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + case GL_RGBA: + break; + + case GL_LUMINANCE: + case GL_RED: + case GL_RG: + case GL_RGB: + case GL_YCBCR_MESA: + case GL_DUDV_ATI: + state->SourceA[0] = GL_PREVIOUS; + break; + + default: + _mesa_problem(NULL, + "Invalid texBaseFormat 0x%x in calculate_derived_texenv", + texBaseFormat); + return; + } + + if (mode == GL_REPLACE_EXT) + mode = GL_REPLACE; + + switch (mode) { + case GL_REPLACE: + case GL_MODULATE: + mode_rgb = (texBaseFormat == GL_ALPHA) ? GL_REPLACE : mode; + mode_a = mode; + break; + + case GL_DECAL: + mode_rgb = GL_INTERPOLATE; + mode_a = GL_REPLACE; + + state->SourceA[0] = GL_PREVIOUS; + + /* Having alpha / luminance / intensity textures replace using the + * incoming fragment color matches the definition in NV_texture_shader. + * The 1.5 spec simply marks these as "undefined". + */ + switch (texBaseFormat) { + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + state->SourceRGB[0] = GL_PREVIOUS; + break; + case GL_RED: + case GL_RG: + case GL_RGB: + case GL_YCBCR_MESA: + case GL_DUDV_ATI: + mode_rgb = GL_REPLACE; + break; + case GL_RGBA: + state->SourceRGB[2] = GL_TEXTURE; + break; + } + break; + + case GL_BLEND: + mode_rgb = GL_INTERPOLATE; + mode_a = GL_MODULATE; + + switch (texBaseFormat) { + case GL_ALPHA: + mode_rgb = GL_REPLACE; + break; + case GL_INTENSITY: + mode_a = GL_INTERPOLATE; + state->SourceA[0] = GL_CONSTANT; + state->OperandA[2] = GL_SRC_ALPHA; + /* FALLTHROUGH */ + case GL_LUMINANCE: + case GL_RED: + case GL_RG: + case GL_RGB: + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + case GL_YCBCR_MESA: + case GL_DUDV_ATI: + state->SourceRGB[2] = GL_TEXTURE; + state->SourceA[2] = GL_TEXTURE; + state->SourceRGB[0] = GL_CONSTANT; + state->OperandRGB[2] = GL_SRC_COLOR; + break; + } + break; + + case GL_ADD: + mode_rgb = (texBaseFormat == GL_ALPHA) ? GL_REPLACE : GL_ADD; + mode_a = (texBaseFormat == GL_INTENSITY) ? GL_ADD : GL_MODULATE; + break; + + default: + _mesa_problem(NULL, + "Invalid texture env mode 0x%x in calculate_derived_texenv", + mode); + return; + } + + state->ModeRGB = (state->SourceRGB[0] != GL_PREVIOUS) + ? mode_rgb : GL_REPLACE; + state->ModeA = (state->SourceA[0] != GL_PREVIOUS) + ? mode_a : GL_REPLACE; +} + + + + +/* GL_ARB_multitexture */ +void GLAPIENTRY +_mesa_ActiveTextureARB(GLenum texture) +{ + const GLuint texUnit = texture - GL_TEXTURE0; + GLuint k; + GET_CURRENT_CONTEXT(ctx); + + /* See OpenGL spec for glActiveTexture: */ + k = MAX2(ctx->Const.MaxCombinedTextureImageUnits, + ctx->Const.MaxTextureCoordUnits); + + ASSERT(k <= Elements(ctx->Texture.Unit)); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) + _mesa_debug(ctx, "glActiveTexture %s\n", + _mesa_lookup_enum_by_nr(texture)); + + if (texUnit >= k) { + _mesa_error(ctx, GL_INVALID_ENUM, "glActiveTexture(texture=%s)", + _mesa_lookup_enum_by_nr(texture)); + return; + } + + if (ctx->Texture.CurrentUnit == texUnit) + return; + + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + + ctx->Texture.CurrentUnit = texUnit; + if (ctx->Transform.MatrixMode == GL_TEXTURE) { + /* update current stack pointer */ + ctx->CurrentStack = &ctx->TextureMatrixStack[texUnit]; + } +} + + +/* GL_ARB_multitexture */ +void GLAPIENTRY +_mesa_ClientActiveTextureARB(GLenum texture) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint texUnit = texture - GL_TEXTURE0; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) + _mesa_debug(ctx, "glClientActiveTexture %s\n", + _mesa_lookup_enum_by_nr(texture)); + + if (texUnit >= ctx->Const.MaxTextureCoordUnits) { + _mesa_error(ctx, GL_INVALID_ENUM, "glClientActiveTexture(texture)"); + return; + } + + if (ctx->Array.ActiveTexture == texUnit) + return; + + FLUSH_VERTICES(ctx, _NEW_ARRAY); + ctx->Array.ActiveTexture = texUnit; +} + + + +/**********************************************************************/ +/***** State management *****/ +/**********************************************************************/ + + +/** + * \note This routine refers to derived texture attribute values to + * compute the ENABLE_TEXMAT flags, but is only called on + * _NEW_TEXTURE_MATRIX. On changes to _NEW_TEXTURE, the ENABLE_TEXMAT + * flags are updated by _mesa_update_textures(), below. + * + * \param ctx GL context. + */ +static void +update_texture_matrices( struct gl_context *ctx ) +{ + GLuint u; + + ctx->Texture._TexMatEnabled = 0x0; + + for (u = 0; u < ctx->Const.MaxTextureCoordUnits; u++) { + ASSERT(u < Elements(ctx->TextureMatrixStack)); + if (_math_matrix_is_dirty(ctx->TextureMatrixStack[u].Top)) { + _math_matrix_analyse( ctx->TextureMatrixStack[u].Top ); + + if (ctx->Texture.Unit[u]._ReallyEnabled && + ctx->TextureMatrixStack[u].Top->type != MATRIX_IDENTITY) + ctx->Texture._TexMatEnabled |= ENABLE_TEXMAT(u); + } + } +} + + +/** + * Examine texture unit's combine/env state to update derived state. + */ +static void +update_tex_combine(struct gl_context *ctx, struct gl_texture_unit *texUnit) +{ + struct gl_tex_env_combine_state *combine; + + /* Set the texUnit->_CurrentCombine field to point to the user's combiner + * state, or the combiner state which is derived from traditional texenv + * mode. + */ + if (texUnit->EnvMode == GL_COMBINE || + texUnit->EnvMode == GL_COMBINE4_NV) { + texUnit->_CurrentCombine = & texUnit->Combine; + } + else { + const struct gl_texture_object *texObj = texUnit->_Current; + GLenum format = texObj->Image[0][texObj->BaseLevel]->_BaseFormat; + if (format == GL_COLOR_INDEX) { + format = GL_RGBA; /* a bit of a hack */ + } + else if (format == GL_DEPTH_COMPONENT || + format == GL_DEPTH_STENCIL_EXT) { + format = texObj->DepthMode; + } + calculate_derived_texenv(&texUnit->_EnvMode, texUnit->EnvMode, format); + texUnit->_CurrentCombine = & texUnit->_EnvMode; + } + + combine = texUnit->_CurrentCombine; + + /* Determine number of source RGB terms in the combiner function */ + switch (combine->ModeRGB) { + case GL_REPLACE: + combine->_NumArgsRGB = 1; + break; + case GL_ADD: + case GL_ADD_SIGNED: + if (texUnit->EnvMode == GL_COMBINE4_NV) + combine->_NumArgsRGB = 4; + else + combine->_NumArgsRGB = 2; + break; + case GL_MODULATE: + case GL_SUBTRACT: + case GL_DOT3_RGB: + case GL_DOT3_RGBA: + case GL_DOT3_RGB_EXT: + case GL_DOT3_RGBA_EXT: + combine->_NumArgsRGB = 2; + break; + case GL_INTERPOLATE: + case GL_MODULATE_ADD_ATI: + case GL_MODULATE_SIGNED_ADD_ATI: + case GL_MODULATE_SUBTRACT_ATI: + combine->_NumArgsRGB = 3; + break; + case GL_BUMP_ENVMAP_ATI: + /* no real arguments for this case */ + combine->_NumArgsRGB = 0; + break; + default: + combine->_NumArgsRGB = 0; + _mesa_problem(ctx, "invalid RGB combine mode in update_texture_state"); + return; + } + + /* Determine number of source Alpha terms in the combiner function */ + switch (combine->ModeA) { + case GL_REPLACE: + combine->_NumArgsA = 1; + break; + case GL_ADD: + case GL_ADD_SIGNED: + if (texUnit->EnvMode == GL_COMBINE4_NV) + combine->_NumArgsA = 4; + else + combine->_NumArgsA = 2; + break; + case GL_MODULATE: + case GL_SUBTRACT: + combine->_NumArgsA = 2; + break; + case GL_INTERPOLATE: + case GL_MODULATE_ADD_ATI: + case GL_MODULATE_SIGNED_ADD_ATI: + case GL_MODULATE_SUBTRACT_ATI: + combine->_NumArgsA = 3; + break; + default: + combine->_NumArgsA = 0; + _mesa_problem(ctx, "invalid Alpha combine mode in update_texture_state"); + break; + } +} + + +/** + * \note This routine refers to derived texture matrix values to + * compute the ENABLE_TEXMAT flags, but is only called on + * _NEW_TEXTURE. On changes to _NEW_TEXTURE_MATRIX, the ENABLE_TEXMAT + * flags are updated by _mesa_update_texture_matrices, above. + * + * \param ctx GL context. + */ +static void +update_texture_state( struct gl_context *ctx ) +{ + GLuint unit; + struct gl_fragment_program *fprog = NULL; + struct gl_vertex_program *vprog = NULL; + GLbitfield enabledFragUnits = 0x0; + + if (ctx->Shader.CurrentVertexProgram && + ctx->Shader.CurrentVertexProgram->LinkStatus) { + vprog = ctx->Shader.CurrentVertexProgram->VertexProgram; + } else if (ctx->VertexProgram._Enabled) { + /* XXX enable this if/when non-shader vertex programs get + * texture fetches: + vprog = ctx->VertexProgram.Current; + */ + } + + if (ctx->Shader.CurrentFragmentProgram && + ctx->Shader.CurrentFragmentProgram->LinkStatus) { + fprog = ctx->Shader.CurrentFragmentProgram->FragmentProgram; + } + else if (ctx->FragmentProgram._Enabled) { + fprog = ctx->FragmentProgram.Current; + } + + /* FINISHME: Geometry shader texture accesses should also be considered + * FINISHME: here. + */ + + /* TODO: only set this if there are actual changes */ + ctx->NewState |= _NEW_TEXTURE; + + ctx->Texture._EnabledUnits = 0x0; + ctx->Texture._GenFlags = 0x0; + ctx->Texture._TexMatEnabled = 0x0; + ctx->Texture._TexGenEnabled = 0x0; + + /* + * Update texture unit state. + */ + for (unit = 0; unit < ctx->Const.MaxCombinedTextureImageUnits; unit++) { + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + GLbitfield enabledVertTargets = 0x0; + GLbitfield enabledFragTargets = 0x0; + GLbitfield enabledTargets = 0x0; + GLuint texIndex; + + /* Get the bitmask of texture target enables. + * enableBits will be a mask of the TEXTURE_*_BIT flags indicating + * which texture targets are enabled (fixed function) or referenced + * by a fragment program/program. When multiple flags are set, we'll + * settle on the one with highest priority (see below). + */ + if (vprog) { + enabledVertTargets |= vprog->Base.TexturesUsed[unit]; + } + + if (fprog) { + enabledFragTargets |= fprog->Base.TexturesUsed[unit]; + } + else { + /* fixed-function fragment program */ + enabledFragTargets |= texUnit->Enabled; + } + + enabledTargets = enabledVertTargets | enabledFragTargets; + + texUnit->_ReallyEnabled = 0x0; + + if (enabledTargets == 0x0) { + /* neither vertex nor fragment processing uses this unit */ + continue; + } + + /* Look for the highest priority texture target that's enabled (or used + * by the vert/frag shaders) and "complete". That's the one we'll use + * for texturing. If we're using vert/frag program we're guaranteed + * that bitcount(enabledBits) <= 1. + * Note that the TEXTURE_x_INDEX values are in high to low priority. + */ + for (texIndex = 0; texIndex < NUM_TEXTURE_TARGETS; texIndex++) { + if (enabledTargets & (1 << texIndex)) { + struct gl_texture_object *texObj = texUnit->CurrentTex[texIndex]; + if (!texObj->_Complete) { + _mesa_test_texobj_completeness(ctx, texObj); + } + if (texObj->_Complete) { + texUnit->_ReallyEnabled = 1 << texIndex; + _mesa_reference_texobj(&texUnit->_Current, texObj); + break; + } + } + } + + if (!texUnit->_ReallyEnabled) { + if (fprog) { + /* If we get here it means the shader is expecting a texture + * object, but there isn't one (or it's incomplete). Use the + * fallback texture. + */ + struct gl_texture_object *texObj = _mesa_get_fallback_texture(ctx); + texUnit->_ReallyEnabled = 1 << TEXTURE_2D_INDEX; + _mesa_reference_texobj(&texUnit->_Current, texObj); + } + else { + /* fixed-function: texture unit is really disabled */ + continue; + } + } + + /* if we get here, we know this texture unit is enabled */ + + ctx->Texture._EnabledUnits |= (1 << unit); + + if (enabledFragTargets) + enabledFragUnits |= (1 << unit); + + update_tex_combine(ctx, texUnit); + } + + + /* Determine which texture coordinate sets are actually needed */ + if (fprog) { + const GLuint coordMask = (1 << MAX_TEXTURE_COORD_UNITS) - 1; + ctx->Texture._EnabledCoordUnits + = (fprog->Base.InputsRead >> FRAG_ATTRIB_TEX0) & coordMask; + } + else { + ctx->Texture._EnabledCoordUnits = enabledFragUnits; + } + + /* Setup texgen for those texture coordinate sets that are in use */ + for (unit = 0; unit < ctx->Const.MaxTextureCoordUnits; unit++) { + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + + texUnit->_GenFlags = 0x0; + + if (!(ctx->Texture._EnabledCoordUnits & (1 << unit))) + continue; + + if (texUnit->TexGenEnabled) { + if (texUnit->TexGenEnabled & S_BIT) { + texUnit->_GenFlags |= texUnit->GenS._ModeBit; + } + if (texUnit->TexGenEnabled & T_BIT) { + texUnit->_GenFlags |= texUnit->GenT._ModeBit; + } + if (texUnit->TexGenEnabled & R_BIT) { + texUnit->_GenFlags |= texUnit->GenR._ModeBit; + } + if (texUnit->TexGenEnabled & Q_BIT) { + texUnit->_GenFlags |= texUnit->GenQ._ModeBit; + } + + ctx->Texture._TexGenEnabled |= ENABLE_TEXGEN(unit); + ctx->Texture._GenFlags |= texUnit->_GenFlags; + } + + ASSERT(unit < Elements(ctx->TextureMatrixStack)); + if (ctx->TextureMatrixStack[unit].Top->type != MATRIX_IDENTITY) + ctx->Texture._TexMatEnabled |= ENABLE_TEXMAT(unit); + } +} + + +/** + * Update texture-related derived state. + */ +void +_mesa_update_texture( struct gl_context *ctx, GLuint new_state ) +{ + if (new_state & _NEW_TEXTURE_MATRIX) + update_texture_matrices( ctx ); + + if (new_state & (_NEW_TEXTURE | _NEW_PROGRAM)) + update_texture_state( ctx ); +} + + +/**********************************************************************/ +/***** Initialization *****/ +/**********************************************************************/ + +/** + * Allocate the proxy textures for the given context. + * + * \param ctx the context to allocate proxies for. + * + * \return GL_TRUE on success, or GL_FALSE on failure + * + * If run out of memory part way through the allocations, clean up and return + * GL_FALSE. + */ +static GLboolean +alloc_proxy_textures( struct gl_context *ctx ) +{ + static const GLenum targets[] = { + GL_TEXTURE_1D, + GL_TEXTURE_2D, + GL_TEXTURE_3D, + GL_TEXTURE_CUBE_MAP_ARB, + GL_TEXTURE_RECTANGLE_NV, + GL_TEXTURE_1D_ARRAY_EXT, + GL_TEXTURE_2D_ARRAY_EXT + }; + GLint tgt; + + ASSERT(Elements(targets) == NUM_TEXTURE_TARGETS); + + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + if (!(ctx->Texture.ProxyTex[tgt] + = ctx->Driver.NewTextureObject(ctx, 0, targets[tgt]))) { + /* out of memory, free what we did allocate */ + while (--tgt >= 0) { + ctx->Driver.DeleteTexture(ctx, ctx->Texture.ProxyTex[tgt]); + } + return GL_FALSE; + } + } + + assert(ctx->Texture.ProxyTex[0]->RefCount == 1); /* sanity check */ + return GL_TRUE; +} + + +/** + * Initialize a texture unit. + * + * \param ctx GL context. + * \param unit texture unit number to be initialized. + */ +static void +init_texture_unit( struct gl_context *ctx, GLuint unit ) +{ + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + GLuint tex; + + texUnit->EnvMode = GL_MODULATE; + ASSIGN_4V( texUnit->EnvColor, 0.0, 0.0, 0.0, 0.0 ); + + texUnit->Combine = default_combine_state; + texUnit->_EnvMode = default_combine_state; + texUnit->_CurrentCombine = & texUnit->_EnvMode; + texUnit->BumpTarget = GL_TEXTURE0; + + texUnit->TexGenEnabled = 0x0; + texUnit->GenS.Mode = GL_EYE_LINEAR; + texUnit->GenT.Mode = GL_EYE_LINEAR; + texUnit->GenR.Mode = GL_EYE_LINEAR; + texUnit->GenQ.Mode = GL_EYE_LINEAR; + texUnit->GenS._ModeBit = TEXGEN_EYE_LINEAR; + texUnit->GenT._ModeBit = TEXGEN_EYE_LINEAR; + texUnit->GenR._ModeBit = TEXGEN_EYE_LINEAR; + texUnit->GenQ._ModeBit = TEXGEN_EYE_LINEAR; + + /* Yes, these plane coefficients are correct! */ + ASSIGN_4V( texUnit->GenS.ObjectPlane, 1.0, 0.0, 0.0, 0.0 ); + ASSIGN_4V( texUnit->GenT.ObjectPlane, 0.0, 1.0, 0.0, 0.0 ); + ASSIGN_4V( texUnit->GenR.ObjectPlane, 0.0, 0.0, 0.0, 0.0 ); + ASSIGN_4V( texUnit->GenQ.ObjectPlane, 0.0, 0.0, 0.0, 0.0 ); + ASSIGN_4V( texUnit->GenS.EyePlane, 1.0, 0.0, 0.0, 0.0 ); + ASSIGN_4V( texUnit->GenT.EyePlane, 0.0, 1.0, 0.0, 0.0 ); + ASSIGN_4V( texUnit->GenR.EyePlane, 0.0, 0.0, 0.0, 0.0 ); + ASSIGN_4V( texUnit->GenQ.EyePlane, 0.0, 0.0, 0.0, 0.0 ); + + /* no mention of this in spec, but maybe id matrix expected? */ + ASSIGN_4V( texUnit->RotMatrix, 1.0, 0.0, 0.0, 1.0 ); + + /* initialize current texture object ptrs to the shared default objects */ + for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { + _mesa_reference_texobj(&texUnit->CurrentTex[tex], + ctx->Shared->DefaultTex[tex]); + } +} + + +/** + * Initialize texture state for the given context. + */ +GLboolean +_mesa_init_texture(struct gl_context *ctx) +{ + GLuint u; + + /* Texture group */ + ctx->Texture.CurrentUnit = 0; /* multitexture */ + ctx->Texture._EnabledUnits = 0x0; + ctx->Texture.SharedPalette = GL_FALSE; + _mesa_init_colortable(&ctx->Texture.Palette); + + for (u = 0; u < Elements(ctx->Texture.Unit); u++) + init_texture_unit(ctx, u); + + /* After we're done initializing the context's texture state the default + * texture objects' refcounts should be at least + * MAX_COMBINED_TEXTURE_IMAGE_UNITS + 1. + */ + assert(ctx->Shared->DefaultTex[TEXTURE_1D_INDEX]->RefCount + >= MAX_COMBINED_TEXTURE_IMAGE_UNITS + 1); + + /* Allocate proxy textures */ + if (!alloc_proxy_textures( ctx )) + return GL_FALSE; + + return GL_TRUE; +} + + +/** + * Free dynamically-allocted texture data attached to the given context. + */ +void +_mesa_free_texture_data(struct gl_context *ctx) +{ + GLuint u, tgt; + + /* unreference current textures */ + for (u = 0; u < Elements(ctx->Texture.Unit); u++) { + /* The _Current texture could account for another reference */ + _mesa_reference_texobj(&ctx->Texture.Unit[u]._Current, NULL); + + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + _mesa_reference_texobj(&ctx->Texture.Unit[u].CurrentTex[tgt], NULL); + } + } + + /* Free proxy texture objects */ + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) + ctx->Driver.DeleteTexture(ctx, ctx->Texture.ProxyTex[tgt]); +} + + +/** + * Update the default texture objects in the given context to reference those + * specified in the shared state and release those referencing the old + * shared state. + */ +void +_mesa_update_default_objects_texture(struct gl_context *ctx) +{ + GLuint u, tex; + + for (u = 0; u < Elements(ctx->Texture.Unit); u++) { + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[u]; + for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { + _mesa_reference_texobj(&texUnit->CurrentTex[tex], + ctx->Shared->DefaultTex[tex]); + } + } +} diff --git a/mesalib/src/mesa/main/texstore.c b/mesalib/src/mesa/main/texstore.c index 8a3e5f779..cd30fa021 100644 --- a/mesalib/src/mesa/main/texstore.c +++ b/mesalib/src/mesa/main/texstore.c @@ -61,6 +61,7 @@ #include "mfeatures.h" #include "mtypes.h" #include "pack.h" +#include "pbo.h" #include "imports.h" #include "pack.h" #include "texcompress.h" @@ -4200,94 +4201,6 @@ _mesa_texstore(TEXSTORE_PARAMS) } -/** - * Check if an unpack PBO is active prior to fetching a texture image. - * If so, do bounds checking and map the buffer into main memory. - * Any errors detected will be recorded. - * The caller _must_ call _mesa_unmap_teximage_pbo() too! - */ -const GLvoid * -_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *pixels, - const struct gl_pixelstore_attrib *unpack, - const char *funcName) -{ - GLubyte *buf; - - if (!_mesa_is_bufferobj(unpack->BufferObj)) { - /* no PBO */ - return pixels; - } - if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, - format, type, pixels)) { - _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)"); - return NULL; - } - - buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, - GL_READ_ONLY_ARB, unpack->BufferObj); - if (!buf) { - _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped)"); - return NULL; - } - - return ADD_POINTERS(buf, pixels); -} - - -/** - * Check if an unpack PBO is active prior to fetching a compressed texture - * image. - * If so, do bounds checking and map the buffer into main memory. - * Any errors detected will be recorded. - * The caller _must_ call _mesa_unmap_teximage_pbo() too! - */ -const GLvoid * -_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx, - GLsizei imageSize, const GLvoid *pixels, - const struct gl_pixelstore_attrib *packing, - const char *funcName) -{ - GLubyte *buf; - - if (!_mesa_is_bufferobj(packing->BufferObj)) { - /* not using a PBO - return pointer unchanged */ - return pixels; - } - if ((const GLubyte *) pixels + imageSize > - ((const GLubyte *) 0) + packing->BufferObj->Size) { - /* out of bounds read! */ - _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)"); - return NULL; - } - - buf = (GLubyte*) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, - GL_READ_ONLY_ARB, packing->BufferObj); - if (!buf) { - _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped"); - return NULL; - } - - return ADD_POINTERS(buf, pixels); -} - - -/** - * This function must be called after either of the validate_pbo_*_teximage() - * functions. It unmaps the PBO buffer if it was mapped earlier. - */ -void -_mesa_unmap_teximage_pbo(struct gl_context *ctx, - const struct gl_pixelstore_attrib *unpack) -{ - if (_mesa_is_bufferobj(unpack->BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, - unpack->BufferObj); - } -} - - /** Return texture size in bytes */ static GLuint texture_size(const struct gl_texture_image *texImage) diff --git a/mesalib/src/mesa/main/texstore.h b/mesalib/src/mesa/main/texstore.h index 2f3c4e821..d56318709 100644 --- a/mesalib/src/mesa/main/texstore.h +++ b/mesalib/src/mesa/main/texstore.h @@ -206,22 +206,4 @@ _mesa_store_compressed_texsubimage3d(struct gl_context *ctx, GLenum target, struct gl_texture_image *texImage); -extern const GLvoid * -_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *pixels, - const struct gl_pixelstore_attrib *unpack, - const char *funcName); - -extern const GLvoid * -_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx, - GLsizei imageSize, const GLvoid *pixels, - const struct gl_pixelstore_attrib *packing, - const char *funcName); - -extern void -_mesa_unmap_teximage_pbo(struct gl_context *ctx, - const struct gl_pixelstore_attrib *unpack); - - #endif diff --git a/mesalib/src/mesa/sources.mak b/mesalib/src/mesa/sources.mak index bdf4126cf..a8c0bbd2b 100644 --- a/mesalib/src/mesa/sources.mak +++ b/mesalib/src/mesa/sources.mak @@ -59,6 +59,7 @@ MAIN_SOURCES = \ main/multisample.c \ main/nvprogram.c \ main/pack.c \ + main/pbo.c \ main/pixel.c \ main/pixelstore.c \ main/pixeltransfer.c \ diff --git a/mesalib/src/mesa/state_tracker/st_cb_bitmap.c b/mesalib/src/mesa/state_tracker/st_cb_bitmap.c index 0ea567155..149f1ca44 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_bitmap.c +++ b/mesalib/src/mesa/state_tracker/st_cb_bitmap.c @@ -35,6 +35,7 @@ #include "main/bufferobj.h" #include "main/macros.h" #include "main/mfeatures.h" +#include "main/pbo.h" #include "program/program.h" #include "program/prog_print.h" diff --git a/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c b/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c index 2c4746622..c2b4e1808 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c +++ b/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c @@ -1,1487 +1,1488 @@ -/************************************************************************** - * - * 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: - * Brian Paul - */ - -#include "main/imports.h" -#include "main/image.h" -#include "main/bufferobj.h" -#include "main/macros.h" -#include "main/mfeatures.h" -#include "main/mtypes.h" -#include "main/pack.h" -#include "main/texformat.h" -#include "main/texstore.h" -#include "program/program.h" -#include "program/prog_print.h" -#include "program/prog_instruction.h" - -#include "st_atom.h" -#include "st_atom_constbuf.h" -#include "st_cb_drawpixels.h" -#include "st_cb_readpixels.h" -#include "st_cb_fbo.h" -#include "st_context.h" -#include "st_debug.h" -#include "st_format.h" -#include "st_program.h" -#include "st_texture.h" - -#include "pipe/p_context.h" -#include "pipe/p_defines.h" -#include "tgsi/tgsi_ureg.h" -#include "util/u_draw_quad.h" -#include "util/u_format.h" -#include "util/u_inlines.h" -#include "util/u_math.h" -#include "util/u_tile.h" -#include "cso_cache/cso_context.h" - - -#if FEATURE_drawpix - -/** - * Check if the given program is: - * 0: MOVE result.color, fragment.color; - * 1: END; - */ -static GLboolean -is_passthrough_program(const struct gl_fragment_program *prog) -{ - if (prog->Base.NumInstructions == 2) { - const struct prog_instruction *inst = prog->Base.Instructions; - if (inst[0].Opcode == OPCODE_MOV && - inst[1].Opcode == OPCODE_END && - inst[0].DstReg.File == PROGRAM_OUTPUT && - inst[0].DstReg.Index == FRAG_RESULT_COLOR && - inst[0].DstReg.WriteMask == WRITEMASK_XYZW && - inst[0].SrcReg[0].File == PROGRAM_INPUT && - inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 && - inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) { - return GL_TRUE; - } - } - return GL_FALSE; -} - - - -/** - * Make fragment shader for glDraw/CopyPixels. This shader is made - * by combining the pixel transfer shader with the user-defined shader. - * \param fpIn the current/incoming fragment program - * \param fpOut returns the combined fragment program - */ -void -st_make_drawpix_fragment_program(struct st_context *st, - struct gl_fragment_program *fpIn, - struct gl_fragment_program **fpOut) -{ - struct gl_program *newProg; - - if (is_passthrough_program(fpIn)) { - newProg = (struct gl_program *) _mesa_clone_fragment_program(st->ctx, - &st->pixel_xfer.program->Base); - } - else { -#if 0 - /* debug */ - printf("Base program:\n"); - _mesa_print_program(&fpIn->Base); - printf("DrawPix program:\n"); - _mesa_print_program(&st->pixel_xfer.program->Base.Base); -#endif - newProg = _mesa_combine_programs(st->ctx, - &st->pixel_xfer.program->Base.Base, - &fpIn->Base); - } - -#if 0 - /* debug */ - printf("Combined DrawPixels program:\n"); - _mesa_print_program(newProg); - printf("InputsRead: 0x%x\n", newProg->InputsRead); - printf("OutputsWritten: 0x%x\n", newProg->OutputsWritten); - _mesa_print_parameter_list(newProg->Parameters); -#endif - - *fpOut = (struct gl_fragment_program *) newProg; -} - - -/** - * Create fragment program that does a TEX() instruction to get a Z and/or - * stencil value value, then writes to FRAG_RESULT_DEPTH/FRAG_RESULT_STENCIL. - * Used for glDrawPixels(GL_DEPTH_COMPONENT / GL_STENCIL_INDEX). - * Pass fragment color through as-is. - * \return pointer to the gl_fragment program - */ -struct gl_fragment_program * -st_make_drawpix_z_stencil_program(struct st_context *st, - GLboolean write_depth, - GLboolean write_stencil) -{ - struct gl_context *ctx = st->ctx; - struct gl_program *p; - struct gl_fragment_program *fp; - GLuint ic = 0; - const GLuint shaderIndex = write_depth * 2 + write_stencil; - - assert(shaderIndex < Elements(st->drawpix.shaders)); - - if (st->drawpix.shaders[shaderIndex]) { - /* already have the proper shader */ - return st->drawpix.shaders[shaderIndex]; - } - - /* - * Create shader now - */ - p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); - if (!p) - return NULL; - - p->NumInstructions = write_depth ? 2 : 1; - p->NumInstructions += write_stencil ? 1 : 0; - - p->Instructions = _mesa_alloc_instructions(p->NumInstructions); - if (!p->Instructions) { - ctx->Driver.DeleteProgram(ctx, p); - return NULL; - } - _mesa_init_instructions(p->Instructions, p->NumInstructions); - - if (write_depth) { - /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */ - p->Instructions[ic].Opcode = OPCODE_TEX; - p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; - p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPTH; - p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z; - p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; - p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; - p->Instructions[ic].TexSrcUnit = 0; - p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; - ic++; - } - - if (write_stencil) { - /* TEX result.stencil, fragment.texcoord[0], texture[0], 2D; */ - p->Instructions[ic].Opcode = OPCODE_TEX; - p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; - p->Instructions[ic].DstReg.Index = FRAG_RESULT_STENCIL; - p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Y; - p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; - p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; - p->Instructions[ic].TexSrcUnit = 1; - p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; - ic++; - } - - /* END; */ - p->Instructions[ic++].Opcode = OPCODE_END; - - assert(ic == p->NumInstructions); - - p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0; - p->OutputsWritten = 0; - if (write_depth) - p->OutputsWritten |= (1 << FRAG_RESULT_DEPTH); - if (write_stencil) - p->OutputsWritten |= (1 << FRAG_RESULT_STENCIL); - - p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ - if (write_stencil) - p->SamplersUsed |= 1 << 1; - - fp = (struct gl_fragment_program *) p; - - /* save the new shader */ - st->drawpix.shaders[shaderIndex] = fp; - - return fp; -} - - -/** - * Create a simple vertex shader that just passes through the - * vertex position and texcoord (and optionally, color). - */ -static void * -make_passthrough_vertex_shader(struct st_context *st, - GLboolean passColor) -{ - if (!st->drawpix.vert_shaders[passColor]) { - struct ureg_program *ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); - - if (ureg == NULL) - return NULL; - - /* MOV result.pos, vertex.pos; */ - ureg_MOV(ureg, - ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, 0 ), - ureg_DECL_vs_input( ureg, 0 )); - - /* MOV result.texcoord0, vertex.attr[1]; */ - ureg_MOV(ureg, - ureg_DECL_output( ureg, TGSI_SEMANTIC_GENERIC, 0 ), - ureg_DECL_vs_input( ureg, 1 )); - - if (passColor) { - /* MOV result.color0, vertex.attr[2]; */ - ureg_MOV(ureg, - ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, 0 ), - ureg_DECL_vs_input( ureg, 2 )); - } - - ureg_END( ureg ); - - st->drawpix.vert_shaders[passColor] = - ureg_create_shader_and_destroy( ureg, st->pipe ); - } - - return st->drawpix.vert_shaders[passColor]; -} - - -/** - * Return a texture base format for drawing/copying an image - * of the given format. - */ -static GLenum -base_format(GLenum format) -{ - switch (format) { - case GL_DEPTH_COMPONENT: - return GL_DEPTH_COMPONENT; - case GL_DEPTH_STENCIL: - return GL_DEPTH_STENCIL; - case GL_STENCIL_INDEX: - return GL_STENCIL_INDEX; - default: - return GL_RGBA; - } -} - - -/** - * Return a texture internalFormat for drawing/copying an image - * of the given format and type. - */ -static GLenum -internal_format(GLenum format, GLenum type) -{ - switch (format) { - case GL_DEPTH_COMPONENT: - return GL_DEPTH_COMPONENT; - case GL_DEPTH_STENCIL: - return GL_DEPTH_STENCIL; - case GL_STENCIL_INDEX: - return GL_STENCIL_INDEX; - default: - if (_mesa_is_integer_format(format)) { - switch (type) { - case GL_BYTE: - return GL_RGBA8I; - case GL_UNSIGNED_BYTE: - return GL_RGBA8UI; - case GL_SHORT: - return GL_RGBA16I; - case GL_UNSIGNED_SHORT: - return GL_RGBA16UI; - case GL_INT: - return GL_RGBA32I; - case GL_UNSIGNED_INT: - return GL_RGBA32UI; - default: - assert(0 && "Unexpected type in internal_format()"); - return GL_RGBA_INTEGER; - } - } - else { - return GL_RGBA; - } - } -} - - -/** - * Create a temporary texture to hold an image of the given size. - * If width, height are not POT and the driver only handles POT textures, - * allocate the next larger size of texture that is POT. - */ -static struct pipe_resource * -alloc_texture(struct st_context *st, GLsizei width, GLsizei height, - enum pipe_format texFormat) -{ - struct pipe_resource *pt; - - pt = st_texture_create(st, st->internal_target, texFormat, 0, - width, height, 1, 1, PIPE_BIND_SAMPLER_VIEW); - - return pt; -} - - -/** - * Make texture containing an image for glDrawPixels image. - * If 'pixels' is NULL, leave the texture image data undefined. - */ -static struct pipe_resource * -make_texture(struct st_context *st, - GLsizei width, GLsizei height, GLenum format, GLenum type, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *pixels) -{ - struct gl_context *ctx = st->ctx; - struct pipe_context *pipe = st->pipe; - gl_format mformat; - struct pipe_resource *pt; - enum pipe_format pipeFormat; - GLuint cpp; - GLenum baseFormat, intFormat; - - baseFormat = base_format(format); - intFormat = internal_format(format, type); - - mformat = st_ChooseTextureFormat_renderable(ctx, intFormat, - format, type, GL_FALSE); - assert(mformat); - - pipeFormat = st_mesa_format_to_pipe_format(mformat); - assert(pipeFormat); - cpp = util_format_get_blocksize(pipeFormat); - - pixels = _mesa_map_pbo_source(ctx, unpack, pixels); - if (!pixels) - return NULL; - - /* alloc temporary texture */ - pt = alloc_texture(st, width, height, pipeFormat); - if (!pt) { - _mesa_unmap_pbo_source(ctx, unpack); - return NULL; - } - - { - struct pipe_transfer *transfer; - static const GLuint dstImageOffsets = 0; - GLboolean success; - GLubyte *dest; - const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; - - /* we'll do pixel transfer in a fragment shader */ - ctx->_ImageTransferState = 0x0; - - transfer = pipe_get_transfer(st->pipe, pt, 0, 0, - PIPE_TRANSFER_WRITE, 0, 0, - width, height); - - /* map texture transfer */ - dest = pipe_transfer_map(pipe, transfer); - - - /* Put image into texture transfer. - * Note that the image is actually going to be upside down in - * the texture. We deal with that with texcoords. - */ - success = _mesa_texstore(ctx, 2, /* dims */ - baseFormat, /* baseInternalFormat */ - mformat, /* gl_format */ - dest, /* dest */ - 0, 0, 0, /* dstX/Y/Zoffset */ - transfer->stride, /* dstRowStride, bytes */ - &dstImageOffsets, /* dstImageOffsets */ - width, height, 1, /* size */ - format, type, /* src format/type */ - pixels, /* data source */ - unpack); - - /* unmap */ - pipe_transfer_unmap(pipe, transfer); - pipe->transfer_destroy(pipe, transfer); - - assert(success); - - /* restore */ - ctx->_ImageTransferState = imageTransferStateSave; - } - - _mesa_unmap_pbo_source(ctx, unpack); - - return pt; -} - - -/** - * Draw quad with texcoords and optional color. - * Coords are gallium window coords with y=0=top. - * \param color may be null - * \param invertTex if true, flip texcoords vertically - */ -static void -draw_quad(struct gl_context *ctx, GLfloat x0, GLfloat y0, GLfloat z, - GLfloat x1, GLfloat y1, const GLfloat *color, - GLboolean invertTex, GLfloat maxXcoord, GLfloat maxYcoord) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */ - - /* setup vertex data */ - { - const struct gl_framebuffer *fb = st->ctx->DrawBuffer; - const GLfloat fb_width = (GLfloat) fb->Width; - const GLfloat fb_height = (GLfloat) fb->Height; - const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f; - const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f; - const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f; - const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f; - const GLfloat sLeft = 0.0f, sRight = maxXcoord; - const GLfloat tTop = invertTex ? maxYcoord : 0.0f; - const GLfloat tBot = invertTex ? 0.0f : maxYcoord; - GLuint i; - - /* upper-left */ - verts[0][0][0] = clip_x0; /* v[0].attr[0].x */ - verts[0][0][1] = clip_y0; /* v[0].attr[0].y */ - - /* upper-right */ - verts[1][0][0] = clip_x1; - verts[1][0][1] = clip_y0; - - /* lower-right */ - verts[2][0][0] = clip_x1; - verts[2][0][1] = clip_y1; - - /* lower-left */ - verts[3][0][0] = clip_x0; - verts[3][0][1] = clip_y1; - - verts[0][1][0] = sLeft; /* v[0].attr[1].S */ - verts[0][1][1] = tTop; /* v[0].attr[1].T */ - verts[1][1][0] = sRight; - verts[1][1][1] = tTop; - verts[2][1][0] = sRight; - verts[2][1][1] = tBot; - verts[3][1][0] = sLeft; - verts[3][1][1] = tBot; - - /* same for all verts: */ - if (color) { - for (i = 0; i < 4; i++) { - verts[i][0][2] = z; /* v[i].attr[0].z */ - verts[i][0][3] = 1.0f; /* v[i].attr[0].w */ - verts[i][2][0] = color[0]; /* v[i].attr[2].r */ - verts[i][2][1] = color[1]; /* v[i].attr[2].g */ - verts[i][2][2] = color[2]; /* v[i].attr[2].b */ - verts[i][2][3] = color[3]; /* v[i].attr[2].a */ - verts[i][1][2] = 0.0f; /* v[i].attr[1].R */ - verts[i][1][3] = 1.0f; /* v[i].attr[1].Q */ - } - } - else { - for (i = 0; i < 4; i++) { - verts[i][0][2] = z; /*Z*/ - verts[i][0][3] = 1.0f; /*W*/ - verts[i][1][2] = 0.0f; /*R*/ - verts[i][1][3] = 1.0f; /*Q*/ - } - } - } - - { - struct pipe_resource *buf; - - /* allocate/load buffer object with vertex data */ - buf = pipe_buffer_create(pipe->screen, - PIPE_BIND_VERTEX_BUFFER, - PIPE_USAGE_STATIC, - sizeof(verts)); - pipe_buffer_write(st->pipe, buf, 0, sizeof(verts), verts); - - util_draw_vertex_buffer(pipe, st->cso_context, buf, 0, - PIPE_PRIM_QUADS, - 4, /* verts */ - 3); /* attribs/vert */ - pipe_resource_reference(&buf, NULL); - } -} - - - -static void -draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, - GLsizei width, GLsizei height, - GLfloat zoomX, GLfloat zoomY, - struct pipe_sampler_view **sv, - int num_sampler_view, - void *driver_vp, - void *driver_fp, - const GLfloat *color, - GLboolean invertTex, - GLboolean write_depth, GLboolean write_stencil) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - struct cso_context *cso = st->cso_context; - GLfloat x0, y0, x1, y1; - GLsizei maxSize; - boolean normalized = sv[0]->texture->target != PIPE_TEXTURE_RECT; - - /* limit checks */ - /* XXX if DrawPixels image is larger than max texture size, break - * it up into chunks. - */ - maxSize = 1 << (pipe->screen->get_param(pipe->screen, - PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); - assert(width <= maxSize); - assert(height <= maxSize); - - cso_save_rasterizer(cso); - cso_save_viewport(cso); - cso_save_samplers(cso); - cso_save_fragment_sampler_views(cso); - cso_save_fragment_shader(cso); - cso_save_vertex_shader(cso); - cso_save_vertex_elements(cso); - cso_save_vertex_buffers(cso); - if (write_stencil) { - cso_save_depth_stencil_alpha(cso); - cso_save_blend(cso); - } - - /* rasterizer state: just scissor */ - { - struct pipe_rasterizer_state rasterizer; - memset(&rasterizer, 0, sizeof(rasterizer)); - rasterizer.gl_rasterization_rules = 1; - rasterizer.scissor = ctx->Scissor.Enabled; - cso_set_rasterizer(cso, &rasterizer); - } - - if (write_stencil) { - /* Stencil writing bypasses the normal fragment pipeline to - * disable color writing and set stencil test to always pass. - */ - struct pipe_depth_stencil_alpha_state dsa; - struct pipe_blend_state blend; - - /* depth/stencil */ - memset(&dsa, 0, sizeof(dsa)); - dsa.stencil[0].enabled = 1; - dsa.stencil[0].func = PIPE_FUNC_ALWAYS; - dsa.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; - dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; - if (write_depth) { - /* writing depth+stencil: depth test always passes */ - dsa.depth.enabled = 1; - dsa.depth.writemask = ctx->Depth.Mask; - dsa.depth.func = PIPE_FUNC_ALWAYS; - } - cso_set_depth_stencil_alpha(cso, &dsa); - - /* blend (colormask) */ - memset(&blend, 0, sizeof(blend)); - cso_set_blend(cso, &blend); - } - - /* fragment shader state: TEX lookup program */ - cso_set_fragment_shader_handle(cso, driver_fp); - - /* vertex shader state: position + texcoord pass-through */ - cso_set_vertex_shader_handle(cso, driver_vp); - - - /* texture sampling state: */ - { - struct pipe_sampler_state sampler; - memset(&sampler, 0, sizeof(sampler)); - sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; - sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; - sampler.wrap_r = PIPE_TEX_WRAP_CLAMP; - sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; - sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; - sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; - sampler.normalized_coords = normalized; - - cso_single_sampler(cso, 0, &sampler); - if (num_sampler_view > 1) { - cso_single_sampler(cso, 1, &sampler); - } - cso_single_sampler_done(cso); - } - - /* viewport state: viewport matching window dims */ - { - const float w = (float) ctx->DrawBuffer->Width; - const float h = (float) ctx->DrawBuffer->Height; - struct pipe_viewport_state vp; - vp.scale[0] = 0.5f * w; - vp.scale[1] = -0.5f * h; - vp.scale[2] = 0.5f; - vp.scale[3] = 1.0f; - vp.translate[0] = 0.5f * w; - vp.translate[1] = 0.5f * h; - vp.translate[2] = 0.5f; - vp.translate[3] = 0.0f; - cso_set_viewport(cso, &vp); - } - - cso_set_vertex_elements(cso, 3, st->velems_util_draw); - - /* texture state: */ - cso_set_fragment_sampler_views(cso, num_sampler_view, sv); - - /* Compute Gallium window coords (y=0=top) with pixel zoom. - * Recall that these coords are transformed by the current - * vertex shader and viewport transformation. - */ - if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { - y = ctx->DrawBuffer->Height - (int) (y + height * ctx->Pixel.ZoomY); - invertTex = !invertTex; - } - - x0 = (GLfloat) x; - x1 = x + width * ctx->Pixel.ZoomX; - y0 = (GLfloat) y; - y1 = y + height * ctx->Pixel.ZoomY; - - /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ - z = z * 2.0 - 1.0; - - draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex, - normalized ? ((GLfloat) width / sv[0]->texture->width0) : (GLfloat)width, - normalized ? ((GLfloat) height / sv[0]->texture->height0) : (GLfloat)height); - - /* restore state */ - cso_restore_rasterizer(cso); - cso_restore_viewport(cso); - cso_restore_samplers(cso); - cso_restore_fragment_sampler_views(cso); - cso_restore_fragment_shader(cso); - cso_restore_vertex_shader(cso); - cso_restore_vertex_elements(cso); - cso_restore_vertex_buffers(cso); - if (write_stencil) { - cso_restore_depth_stencil_alpha(cso); - cso_restore_blend(cso); - } -} - - -/** - * Software fallback to do glDrawPixels(GL_STENCIL_INDEX) when we - * can't use a fragment shader to write stencil values. - */ -static void -draw_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, - GLsizei width, GLsizei height, GLenum format, GLenum type, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *pixels) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - struct st_renderbuffer *strb; - enum pipe_transfer_usage usage; - struct pipe_transfer *pt; - const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; - GLint skipPixels; - ubyte *stmap; - struct gl_pixelstore_attrib clippedUnpack = *unpack; - - if (!zoom) { - if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, - &clippedUnpack)) { - /* totally clipped */ - return; - } - } - - strb = st_renderbuffer(ctx->DrawBuffer-> - Attachment[BUFFER_STENCIL].Renderbuffer); - - if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { - y = ctx->DrawBuffer->Height - y - height; - } - - if(format != GL_DEPTH_STENCIL && - util_format_get_component_bits(strb->format, - UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) - usage = PIPE_TRANSFER_READ_WRITE; - else - usage = PIPE_TRANSFER_WRITE; - - pt = pipe_get_transfer(st_context(ctx)->pipe, strb->texture, 0, 0, - usage, x, y, - width, height); - - stmap = pipe_transfer_map(pipe, pt); - - pixels = _mesa_map_pbo_source(ctx, &clippedUnpack, pixels); - assert(pixels); - - /* if width > MAX_WIDTH, have to process image in chunks */ - skipPixels = 0; - while (skipPixels < width) { - const GLint spanX = skipPixels; - const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); - GLint row; - for (row = 0; row < height; row++) { - GLubyte sValues[MAX_WIDTH]; - GLuint zValues[MAX_WIDTH]; - GLenum destType = GL_UNSIGNED_BYTE; - const GLvoid *source = _mesa_image_address2d(&clippedUnpack, pixels, - width, height, - format, type, - row, skipPixels); - _mesa_unpack_stencil_span(ctx, spanWidth, destType, sValues, - type, source, &clippedUnpack, - ctx->_ImageTransferState); - - if (format == GL_DEPTH_STENCIL) { - _mesa_unpack_depth_span(ctx, spanWidth, GL_UNSIGNED_INT, zValues, - (1 << 24) - 1, type, source, - &clippedUnpack); - } - - if (zoom) { - _mesa_problem(ctx, "Gallium glDrawPixels(GL_STENCIL) with " - "zoom not complete"); - } - - { - GLint spanY; - - if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { - spanY = height - row - 1; - } - else { - spanY = row; - } - - /* now pack the stencil (and Z) values in the dest format */ - switch (pt->resource->format) { - case PIPE_FORMAT_S8_USCALED: - { - ubyte *dest = stmap + spanY * pt->stride + spanX; - assert(usage == PIPE_TRANSFER_WRITE); - memcpy(dest, sValues, spanWidth); - } - break; - case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - if (format == GL_DEPTH_STENCIL) { - uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); - GLint k; - assert(usage == PIPE_TRANSFER_WRITE); - for (k = 0; k < spanWidth; k++) { - dest[k] = zValues[k] | (sValues[k] << 24); - } - } - else { - uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); - GLint k; - assert(usage == PIPE_TRANSFER_READ_WRITE); - for (k = 0; k < spanWidth; k++) { - dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24); - } - } - break; - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - if (format == GL_DEPTH_STENCIL) { - uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); - GLint k; - assert(usage == PIPE_TRANSFER_WRITE); - for (k = 0; k < spanWidth; k++) { - dest[k] = (zValues[k] << 8) | (sValues[k] & 0xff); - } - } - else { - uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); - GLint k; - assert(usage == PIPE_TRANSFER_READ_WRITE); - for (k = 0; k < spanWidth; k++) { - dest[k] = (dest[k] & 0xffffff00) | (sValues[k] & 0xff); - } - } - break; - default: - assert(0); - } - } - } - skipPixels += spanWidth; - } - - _mesa_unmap_pbo_source(ctx, &clippedUnpack); - - /* unmap the stencil buffer */ - pipe_transfer_unmap(pipe, pt); - pipe->transfer_destroy(pipe, pt); -} - - -/** - * Get fragment program variant for a glDrawPixels or glCopyPixels - * command for RGBA data. - */ -static struct st_fp_variant * -get_color_fp_variant(struct st_context *st) -{ - struct gl_context *ctx = st->ctx; - struct st_fp_variant_key key; - struct st_fp_variant *fpv; - - memset(&key, 0, sizeof(key)); - - key.st = st; - key.drawpixels = 1; - key.scaleAndBias = (ctx->Pixel.RedBias != 0.0 || - ctx->Pixel.RedScale != 1.0 || - ctx->Pixel.GreenBias != 0.0 || - ctx->Pixel.GreenScale != 1.0 || - ctx->Pixel.BlueBias != 0.0 || - ctx->Pixel.BlueScale != 1.0 || - ctx->Pixel.AlphaBias != 0.0 || - ctx->Pixel.AlphaScale != 1.0); - key.pixelMaps = ctx->Pixel.MapColorFlag; - - fpv = st_get_fp_variant(st, st->fp, &key); - - return fpv; -} - - -/** - * Get fragment program variant for a glDrawPixels or glCopyPixels - * command for depth/stencil data. - */ -static struct st_fp_variant * -get_depth_stencil_fp_variant(struct st_context *st, GLboolean write_depth, - GLboolean write_stencil) -{ - struct st_fp_variant_key key; - struct st_fp_variant *fpv; - - memset(&key, 0, sizeof(key)); - - key.st = st; - key.drawpixels = 1; - key.drawpixels_z = write_depth; - key.drawpixels_stencil = write_stencil; - - fpv = st_get_fp_variant(st, st->fp, &key); - - return fpv; -} - - -/** - * Called via ctx->Driver.DrawPixels() - */ -static void -st_DrawPixels(struct gl_context *ctx, GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) -{ - void *driver_vp, *driver_fp; - struct st_context *st = st_context(ctx); - const GLfloat *color; - struct pipe_context *pipe = st->pipe; - GLboolean write_stencil = GL_FALSE, write_depth = GL_FALSE; - struct pipe_sampler_view *sv[2]; - int num_sampler_view = 1; - enum pipe_format stencil_format = PIPE_FORMAT_NONE; - struct st_fp_variant *fpv; - - if (format == GL_DEPTH_STENCIL) - write_stencil = write_depth = GL_TRUE; - else if (format == GL_STENCIL_INDEX) - write_stencil = GL_TRUE; - else if (format == GL_DEPTH_COMPONENT) - write_depth = GL_TRUE; - - if (write_stencil) { - enum pipe_format tex_format; - /* can we write to stencil if not fallback */ - if (!pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) - goto stencil_fallback; - - tex_format = st_choose_format(st->pipe->screen, base_format(format), - PIPE_TEXTURE_2D, - 0, PIPE_BIND_SAMPLER_VIEW); - if (tex_format == PIPE_FORMAT_Z24_UNORM_S8_USCALED) - stencil_format = PIPE_FORMAT_X24S8_USCALED; - else if (tex_format == PIPE_FORMAT_S8_USCALED_Z24_UNORM) - stencil_format = PIPE_FORMAT_S8X24_USCALED; - else - stencil_format = PIPE_FORMAT_S8_USCALED; - if (stencil_format == PIPE_FORMAT_NONE) - goto stencil_fallback; - } - - /* Mesa state should be up to date by now */ - assert(ctx->NewState == 0x0); - - st_validate_state(st); - - /* - * Get vertex/fragment shaders - */ - if (write_depth || write_stencil) { - fpv = get_depth_stencil_fp_variant(st, write_depth, write_stencil); - - driver_fp = fpv->driver_shader; - - driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); - - color = ctx->Current.RasterColor; - } - else { - fpv = get_color_fp_variant(st); - - driver_fp = fpv->driver_shader; - - driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); - - color = NULL; - if (st->pixel_xfer.pixelmap_enabled) { - sv[1] = st->pixel_xfer.pixelmap_sampler_view; - num_sampler_view++; - } - } - - /* update fragment program constants */ - st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); - - /* draw with textured quad */ - { - struct pipe_resource *pt - = make_texture(st, width, height, format, type, unpack, pixels); - if (pt) { - sv[0] = st_create_texture_sampler_view(st->pipe, pt); - - if (sv[0]) { - if (write_stencil) { - sv[1] = st_create_texture_sampler_view_format(st->pipe, pt, - stencil_format); - num_sampler_view++; - } - - draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], - width, height, - ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, - sv, - num_sampler_view, - driver_vp, - driver_fp, - color, GL_FALSE, write_depth, write_stencil); - pipe_sampler_view_reference(&sv[0], NULL); - if (num_sampler_view > 1) - pipe_sampler_view_reference(&sv[1], NULL); - } - pipe_resource_reference(&pt, NULL); - } - } - return; - -stencil_fallback: - draw_stencil_pixels(ctx, x, y, width, height, format, type, - unpack, pixels); -} - - - -/** - * Software fallback for glCopyPixels(GL_STENCIL). - */ -static void -copy_stencil_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, - GLsizei width, GLsizei height, - GLint dstx, GLint dsty) -{ - struct st_renderbuffer *rbDraw; - struct pipe_context *pipe = st_context(ctx)->pipe; - enum pipe_transfer_usage usage; - struct pipe_transfer *ptDraw; - ubyte *drawMap; - ubyte *buffer; - int i; - - buffer = malloc(width * height * sizeof(ubyte)); - if (!buffer) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)"); - return; - } - - /* Get the dest renderbuffer. If there's a wrapper, use the - * underlying renderbuffer. - */ - rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer); - if (rbDraw->Base.Wrapped) - rbDraw = st_renderbuffer(rbDraw->Base.Wrapped); - - /* this will do stencil pixel transfer ops */ - st_read_stencil_pixels(ctx, srcx, srcy, width, height, - GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, - &ctx->DefaultPacking, buffer); - - if (0) { - /* debug code: dump stencil values */ - GLint row, col; - for (row = 0; row < height; row++) { - printf("%3d: ", row); - for (col = 0; col < width; col++) { - printf("%02x ", buffer[col + row * width]); - } - printf("\n"); - } - } - - if (util_format_get_component_bits(rbDraw->format, - UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) - usage = PIPE_TRANSFER_READ_WRITE; - else - usage = PIPE_TRANSFER_WRITE; - - if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { - dsty = rbDraw->Base.Height - dsty - height; - } - - ptDraw = pipe_get_transfer(st_context(ctx)->pipe, - rbDraw->texture, 0, 0, - usage, dstx, dsty, - width, height); - - assert(util_format_get_blockwidth(ptDraw->resource->format) == 1); - assert(util_format_get_blockheight(ptDraw->resource->format) == 1); - - /* map the stencil buffer */ - drawMap = pipe_transfer_map(pipe, ptDraw); - - /* draw */ - /* XXX PixelZoom not handled yet */ - for (i = 0; i < height; i++) { - ubyte *dst; - const ubyte *src; - int y; - - y = i; - - if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { - y = height - y - 1; - } - - dst = drawMap + y * ptDraw->stride; - src = buffer + i * width; - - switch (ptDraw->resource->format) { - case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - { - uint *dst4 = (uint *) dst; - int j; - assert(usage == PIPE_TRANSFER_READ_WRITE); - for (j = 0; j < width; j++) { - *dst4 = (*dst4 & 0xffffff) | (src[j] << 24); - dst4++; - } - } - break; - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - { - uint *dst4 = (uint *) dst; - int j; - assert(usage == PIPE_TRANSFER_READ_WRITE); - for (j = 0; j < width; j++) { - *dst4 = (*dst4 & 0xffffff00) | (src[j] & 0xff); - dst4++; - } - } - break; - case PIPE_FORMAT_S8_USCALED: - assert(usage == PIPE_TRANSFER_WRITE); - memcpy(dst, src, width); - break; - default: - assert(0); - } - } - - free(buffer); - - /* unmap the stencil buffer */ - pipe_transfer_unmap(pipe, ptDraw); - pipe->transfer_destroy(pipe, ptDraw); -} - - -/** Do the src/dest regions overlap? */ -static GLboolean -regions_overlap(GLint srcX, GLint srcY, GLint dstX, GLint dstY, - GLsizei width, GLsizei height) -{ - if (srcX + width <= dstX || - dstX + width <= srcX || - srcY + height <= dstY || - dstY + height <= srcY) - return GL_FALSE; - else - return GL_TRUE; -} - - -/** - * Try to do a glCopyPixels for simple cases with a blit by calling - * pipe->resource_copy_region(). - * - * We can do this when we're copying color pixels (depth/stencil - * eventually) with no pixel zoom, no pixel transfer ops, no - * per-fragment ops, the src/dest regions don't overlap and the - * src/dest pixel formats are the same. - */ -static GLboolean -blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, - GLsizei width, GLsizei height, - GLint dstx, GLint dsty, GLenum type) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - struct gl_pixelstore_attrib pack, unpack; - GLint readX, readY, readW, readH; - - if (type == GL_COLOR && - ctx->Pixel.ZoomX == 1.0 && - ctx->Pixel.ZoomY == 1.0 && - ctx->_ImageTransferState == 0x0 && - !ctx->Color.BlendEnabled && - !ctx->Color.AlphaEnabled && - !ctx->Depth.Test && - !ctx->Fog.Enabled && - !ctx->Stencil.Enabled && - !ctx->FragmentProgram.Enabled && - !ctx->VertexProgram.Enabled && - !ctx->Shader.CurrentFragmentProgram && - st_fb_orientation(ctx->ReadBuffer) == st_fb_orientation(ctx->DrawBuffer) && - ctx->DrawBuffer->_NumColorDrawBuffers == 1) { - struct st_renderbuffer *rbRead, *rbDraw; - GLint drawX, drawY; - - /* - * Clip the read region against the src buffer bounds. - * We'll still allocate a temporary buffer/texture for the original - * src region size but we'll only read the region which is on-screen. - * This may mean that we draw garbage pixels into the dest region, but - * that's expected. - */ - readX = srcx; - readY = srcy; - readW = width; - readH = height; - pack = ctx->DefaultPacking; - if (!_mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack)) - return GL_TRUE; /* all done */ - - /* clip against dest buffer bounds and scissor box */ - drawX = dstx + pack.SkipPixels; - drawY = dsty + pack.SkipRows; - unpack = pack; - if (!_mesa_clip_drawpixels(ctx, &drawX, &drawY, &readW, &readH, &unpack)) - return GL_TRUE; /* all done */ - - readX = readX - pack.SkipPixels + unpack.SkipPixels; - readY = readY - pack.SkipRows + unpack.SkipRows; - - rbRead = st_get_color_read_renderbuffer(ctx); - rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); - - if ((rbRead != rbDraw || - !regions_overlap(readX, readY, drawX, drawY, readW, readH)) && - rbRead->Base.Format == rbDraw->Base.Format) { - struct pipe_box srcBox; - - /* flip src/dst position if needed */ - if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { - /* both buffers will have the same orientation */ - readY = ctx->ReadBuffer->Height - readY - readH; - drawY = ctx->DrawBuffer->Height - drawY - readH; - } - - u_box_2d(readX, readY, readW, readH, &srcBox); - - pipe->resource_copy_region(pipe, - rbDraw->texture, 0, drawX, drawY, 0, - rbRead->texture, 0, &srcBox); - return GL_TRUE; - } - } - - return GL_FALSE; -} - - -static void -st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, - GLsizei width, GLsizei height, - GLint dstx, GLint dsty, GLenum type) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - struct pipe_screen *screen = pipe->screen; - struct st_renderbuffer *rbRead; - void *driver_vp, *driver_fp; - struct pipe_resource *pt; - struct pipe_sampler_view *sv[2]; - int num_sampler_view = 1; - GLfloat *color; - enum pipe_format srcFormat, texFormat; - GLboolean invertTex = GL_FALSE; - GLint readX, readY, readW, readH; - GLuint sample_count; - struct gl_pixelstore_attrib pack = ctx->DefaultPacking; - struct st_fp_variant *fpv; - - st_validate_state(st); - - if (type == GL_STENCIL) { - /* can't use texturing to do stencil */ - copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); - return; - } - - if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type)) - return; - - /* - * The subsequent code implements glCopyPixels by copying the source - * pixels into a temporary texture that's then applied to a textured quad. - * When we draw the textured quad, all the usual per-fragment operations - * are handled. - */ - - - /* - * Get vertex/fragment shaders - */ - if (type == GL_COLOR) { - rbRead = st_get_color_read_renderbuffer(ctx); - color = NULL; - - fpv = get_color_fp_variant(st); - driver_fp = fpv->driver_shader; - - driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); - - if (st->pixel_xfer.pixelmap_enabled) { - sv[1] = st->pixel_xfer.pixelmap_sampler_view; - num_sampler_view++; - } - } - else { - assert(type == GL_DEPTH); - rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); - color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; - - fpv = get_depth_stencil_fp_variant(st, GL_TRUE, GL_FALSE); - driver_fp = fpv->driver_shader; - - driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); - } - - /* update fragment program constants */ - st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); - - - if (rbRead->Base.Wrapped) - rbRead = st_renderbuffer(rbRead->Base.Wrapped); - - sample_count = rbRead->texture->nr_samples; - /* I believe this would be legal, presumably would need to do a resolve - for color, and for depth/stencil spec says to just use one of the - depth/stencil samples per pixel? Need some transfer clarifications. */ - assert(sample_count < 2); - - srcFormat = rbRead->texture->format; - - if (screen->is_format_supported(screen, srcFormat, st->internal_target, - sample_count, - PIPE_BIND_SAMPLER_VIEW, 0)) { - texFormat = srcFormat; - } - else { - /* srcFormat can't be used as a texture format */ - if (type == GL_DEPTH) { - texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT, - st->internal_target, sample_count, - PIPE_BIND_DEPTH_STENCIL); - assert(texFormat != PIPE_FORMAT_NONE); - } - else { - /* default color format */ - texFormat = st_choose_format(screen, GL_RGBA, st->internal_target, - sample_count, PIPE_BIND_SAMPLER_VIEW); - assert(texFormat != PIPE_FORMAT_NONE); - } - } - - /* Invert src region if needed */ - if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { - srcy = ctx->ReadBuffer->Height - srcy - height; - invertTex = !invertTex; - } - - /* Clip the read region against the src buffer bounds. - * We'll still allocate a temporary buffer/texture for the original - * src region size but we'll only read the region which is on-screen. - * This may mean that we draw garbage pixels into the dest region, but - * that's expected. - */ - readX = srcx; - readY = srcy; - readW = width; - readH = height; - _mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack); - readW = MAX2(0, readW); - readH = MAX2(0, readH); - - /* alloc temporary texture */ - pt = alloc_texture(st, width, height, texFormat); - if (!pt) - return; - - sv[0] = st_create_texture_sampler_view(st->pipe, pt); - if (!sv[0]) { - pipe_resource_reference(&pt, NULL); - return; - } - - /* Make temporary texture which is a copy of the src region. - */ - if (srcFormat == texFormat) { - struct pipe_box src_box; - u_box_2d(readX, readY, readW, readH, &src_box); - /* copy source framebuffer surface into mipmap/texture */ - pipe->resource_copy_region(pipe, - pt, /* dest tex */ - 0, - pack.SkipPixels, pack.SkipRows, 0, /* dest pos */ - rbRead->texture, /* src tex */ - 0, - &src_box); - - } - else { - /* CPU-based fallback/conversion */ - struct pipe_transfer *ptRead = - pipe_get_transfer(st->pipe, rbRead->texture, - 0, 0, /* level, layer */ - PIPE_TRANSFER_READ, - readX, readY, readW, readH); - struct pipe_transfer *ptTex; - enum pipe_transfer_usage transfer_usage; - - if (ST_DEBUG & DEBUG_FALLBACK) - debug_printf("%s: fallback processing\n", __FUNCTION__); - - if (type == GL_DEPTH && util_format_is_depth_and_stencil(pt->format)) - transfer_usage = PIPE_TRANSFER_READ_WRITE; - else - transfer_usage = PIPE_TRANSFER_WRITE; - - ptTex = pipe_get_transfer(st->pipe, pt, 0, 0, transfer_usage, - 0, 0, width, height); - - /* copy image from ptRead surface to ptTex surface */ - if (type == GL_COLOR) { - /* alternate path using get/put_tile() */ - GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); - enum pipe_format readFormat, drawFormat; - readFormat = util_format_linear(rbRead->texture->format); - drawFormat = util_format_linear(pt->format); - pipe_get_tile_rgba_format(pipe, ptRead, 0, 0, readW, readH, - readFormat, buf); - pipe_put_tile_rgba_format(pipe, ptTex, pack.SkipPixels, pack.SkipRows, - readW, readH, drawFormat, buf); - free(buf); - } - else { - /* GL_DEPTH */ - GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint)); - pipe_get_tile_z(pipe, ptRead, 0, 0, readW, readH, buf); - pipe_put_tile_z(pipe, ptTex, pack.SkipPixels, pack.SkipRows, - readW, readH, buf); - free(buf); - } - - pipe->transfer_destroy(pipe, ptRead); - pipe->transfer_destroy(pipe, ptTex); - } - - /* OK, the texture 'pt' contains the src image/pixels. Now draw a - * textured quad with that texture. - */ - draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], - width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, - sv, - num_sampler_view, - driver_vp, - driver_fp, - color, invertTex, GL_FALSE, GL_FALSE); - - pipe_resource_reference(&pt, NULL); - pipe_sampler_view_reference(&sv[0], NULL); -} - - - -void st_init_drawpixels_functions(struct dd_function_table *functions) -{ - functions->DrawPixels = st_DrawPixels; - functions->CopyPixels = st_CopyPixels; -} - - -void -st_destroy_drawpix(struct st_context *st) -{ - GLuint i; - - for (i = 0; i < Elements(st->drawpix.shaders); i++) { - if (st->drawpix.shaders[i]) - _mesa_reference_fragprog(st->ctx, &st->drawpix.shaders[i], NULL); - } - - st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL); - if (st->drawpix.vert_shaders[0]) - ureg_free_tokens(st->drawpix.vert_shaders[0]); - if (st->drawpix.vert_shaders[1]) - ureg_free_tokens(st->drawpix.vert_shaders[1]); -} - -#endif /* FEATURE_drawpix */ +/************************************************************************** + * + * 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: + * Brian Paul + */ + +#include "main/imports.h" +#include "main/image.h" +#include "main/bufferobj.h" +#include "main/macros.h" +#include "main/mfeatures.h" +#include "main/mtypes.h" +#include "main/pack.h" +#include "main/pbo.h" +#include "main/texformat.h" +#include "main/texstore.h" +#include "program/program.h" +#include "program/prog_print.h" +#include "program/prog_instruction.h" + +#include "st_atom.h" +#include "st_atom_constbuf.h" +#include "st_cb_drawpixels.h" +#include "st_cb_readpixels.h" +#include "st_cb_fbo.h" +#include "st_context.h" +#include "st_debug.h" +#include "st_format.h" +#include "st_program.h" +#include "st_texture.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "tgsi/tgsi_ureg.h" +#include "util/u_draw_quad.h" +#include "util/u_format.h" +#include "util/u_inlines.h" +#include "util/u_math.h" +#include "util/u_tile.h" +#include "cso_cache/cso_context.h" + + +#if FEATURE_drawpix + +/** + * Check if the given program is: + * 0: MOVE result.color, fragment.color; + * 1: END; + */ +static GLboolean +is_passthrough_program(const struct gl_fragment_program *prog) +{ + if (prog->Base.NumInstructions == 2) { + const struct prog_instruction *inst = prog->Base.Instructions; + if (inst[0].Opcode == OPCODE_MOV && + inst[1].Opcode == OPCODE_END && + inst[0].DstReg.File == PROGRAM_OUTPUT && + inst[0].DstReg.Index == FRAG_RESULT_COLOR && + inst[0].DstReg.WriteMask == WRITEMASK_XYZW && + inst[0].SrcReg[0].File == PROGRAM_INPUT && + inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 && + inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) { + return GL_TRUE; + } + } + return GL_FALSE; +} + + + +/** + * Make fragment shader for glDraw/CopyPixels. This shader is made + * by combining the pixel transfer shader with the user-defined shader. + * \param fpIn the current/incoming fragment program + * \param fpOut returns the combined fragment program + */ +void +st_make_drawpix_fragment_program(struct st_context *st, + struct gl_fragment_program *fpIn, + struct gl_fragment_program **fpOut) +{ + struct gl_program *newProg; + + if (is_passthrough_program(fpIn)) { + newProg = (struct gl_program *) _mesa_clone_fragment_program(st->ctx, + &st->pixel_xfer.program->Base); + } + else { +#if 0 + /* debug */ + printf("Base program:\n"); + _mesa_print_program(&fpIn->Base); + printf("DrawPix program:\n"); + _mesa_print_program(&st->pixel_xfer.program->Base.Base); +#endif + newProg = _mesa_combine_programs(st->ctx, + &st->pixel_xfer.program->Base.Base, + &fpIn->Base); + } + +#if 0 + /* debug */ + printf("Combined DrawPixels program:\n"); + _mesa_print_program(newProg); + printf("InputsRead: 0x%x\n", newProg->InputsRead); + printf("OutputsWritten: 0x%x\n", newProg->OutputsWritten); + _mesa_print_parameter_list(newProg->Parameters); +#endif + + *fpOut = (struct gl_fragment_program *) newProg; +} + + +/** + * Create fragment program that does a TEX() instruction to get a Z and/or + * stencil value value, then writes to FRAG_RESULT_DEPTH/FRAG_RESULT_STENCIL. + * Used for glDrawPixels(GL_DEPTH_COMPONENT / GL_STENCIL_INDEX). + * Pass fragment color through as-is. + * \return pointer to the gl_fragment program + */ +struct gl_fragment_program * +st_make_drawpix_z_stencil_program(struct st_context *st, + GLboolean write_depth, + GLboolean write_stencil) +{ + struct gl_context *ctx = st->ctx; + struct gl_program *p; + struct gl_fragment_program *fp; + GLuint ic = 0; + const GLuint shaderIndex = write_depth * 2 + write_stencil; + + assert(shaderIndex < Elements(st->drawpix.shaders)); + + if (st->drawpix.shaders[shaderIndex]) { + /* already have the proper shader */ + return st->drawpix.shaders[shaderIndex]; + } + + /* + * Create shader now + */ + p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); + if (!p) + return NULL; + + p->NumInstructions = write_depth ? 2 : 1; + p->NumInstructions += write_stencil ? 1 : 0; + + p->Instructions = _mesa_alloc_instructions(p->NumInstructions); + if (!p->Instructions) { + ctx->Driver.DeleteProgram(ctx, p); + return NULL; + } + _mesa_init_instructions(p->Instructions, p->NumInstructions); + + if (write_depth) { + /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */ + p->Instructions[ic].Opcode = OPCODE_TEX; + p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; + p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPTH; + p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z; + p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; + p->Instructions[ic].TexSrcUnit = 0; + p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + } + + if (write_stencil) { + /* TEX result.stencil, fragment.texcoord[0], texture[0], 2D; */ + p->Instructions[ic].Opcode = OPCODE_TEX; + p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; + p->Instructions[ic].DstReg.Index = FRAG_RESULT_STENCIL; + p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Y; + p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; + p->Instructions[ic].TexSrcUnit = 1; + p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + } + + /* END; */ + p->Instructions[ic++].Opcode = OPCODE_END; + + assert(ic == p->NumInstructions); + + p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0; + p->OutputsWritten = 0; + if (write_depth) + p->OutputsWritten |= (1 << FRAG_RESULT_DEPTH); + if (write_stencil) + p->OutputsWritten |= (1 << FRAG_RESULT_STENCIL); + + p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ + if (write_stencil) + p->SamplersUsed |= 1 << 1; + + fp = (struct gl_fragment_program *) p; + + /* save the new shader */ + st->drawpix.shaders[shaderIndex] = fp; + + return fp; +} + + +/** + * Create a simple vertex shader that just passes through the + * vertex position and texcoord (and optionally, color). + */ +static void * +make_passthrough_vertex_shader(struct st_context *st, + GLboolean passColor) +{ + if (!st->drawpix.vert_shaders[passColor]) { + struct ureg_program *ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); + + if (ureg == NULL) + return NULL; + + /* MOV result.pos, vertex.pos; */ + ureg_MOV(ureg, + ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, 0 ), + ureg_DECL_vs_input( ureg, 0 )); + + /* MOV result.texcoord0, vertex.attr[1]; */ + ureg_MOV(ureg, + ureg_DECL_output( ureg, TGSI_SEMANTIC_GENERIC, 0 ), + ureg_DECL_vs_input( ureg, 1 )); + + if (passColor) { + /* MOV result.color0, vertex.attr[2]; */ + ureg_MOV(ureg, + ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, 0 ), + ureg_DECL_vs_input( ureg, 2 )); + } + + ureg_END( ureg ); + + st->drawpix.vert_shaders[passColor] = + ureg_create_shader_and_destroy( ureg, st->pipe ); + } + + return st->drawpix.vert_shaders[passColor]; +} + + +/** + * Return a texture base format for drawing/copying an image + * of the given format. + */ +static GLenum +base_format(GLenum format) +{ + switch (format) { + case GL_DEPTH_COMPONENT: + return GL_DEPTH_COMPONENT; + case GL_DEPTH_STENCIL: + return GL_DEPTH_STENCIL; + case GL_STENCIL_INDEX: + return GL_STENCIL_INDEX; + default: + return GL_RGBA; + } +} + + +/** + * Return a texture internalFormat for drawing/copying an image + * of the given format and type. + */ +static GLenum +internal_format(GLenum format, GLenum type) +{ + switch (format) { + case GL_DEPTH_COMPONENT: + return GL_DEPTH_COMPONENT; + case GL_DEPTH_STENCIL: + return GL_DEPTH_STENCIL; + case GL_STENCIL_INDEX: + return GL_STENCIL_INDEX; + default: + if (_mesa_is_integer_format(format)) { + switch (type) { + case GL_BYTE: + return GL_RGBA8I; + case GL_UNSIGNED_BYTE: + return GL_RGBA8UI; + case GL_SHORT: + return GL_RGBA16I; + case GL_UNSIGNED_SHORT: + return GL_RGBA16UI; + case GL_INT: + return GL_RGBA32I; + case GL_UNSIGNED_INT: + return GL_RGBA32UI; + default: + assert(0 && "Unexpected type in internal_format()"); + return GL_RGBA_INTEGER; + } + } + else { + return GL_RGBA; + } + } +} + + +/** + * Create a temporary texture to hold an image of the given size. + * If width, height are not POT and the driver only handles POT textures, + * allocate the next larger size of texture that is POT. + */ +static struct pipe_resource * +alloc_texture(struct st_context *st, GLsizei width, GLsizei height, + enum pipe_format texFormat) +{ + struct pipe_resource *pt; + + pt = st_texture_create(st, st->internal_target, texFormat, 0, + width, height, 1, 1, PIPE_BIND_SAMPLER_VIEW); + + return pt; +} + + +/** + * Make texture containing an image for glDrawPixels image. + * If 'pixels' is NULL, leave the texture image data undefined. + */ +static struct pipe_resource * +make_texture(struct st_context *st, + GLsizei width, GLsizei height, GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels) +{ + struct gl_context *ctx = st->ctx; + struct pipe_context *pipe = st->pipe; + gl_format mformat; + struct pipe_resource *pt; + enum pipe_format pipeFormat; + GLuint cpp; + GLenum baseFormat, intFormat; + + baseFormat = base_format(format); + intFormat = internal_format(format, type); + + mformat = st_ChooseTextureFormat_renderable(ctx, intFormat, + format, type, GL_FALSE); + assert(mformat); + + pipeFormat = st_mesa_format_to_pipe_format(mformat); + assert(pipeFormat); + cpp = util_format_get_blocksize(pipeFormat); + + pixels = _mesa_map_pbo_source(ctx, unpack, pixels); + if (!pixels) + return NULL; + + /* alloc temporary texture */ + pt = alloc_texture(st, width, height, pipeFormat); + if (!pt) { + _mesa_unmap_pbo_source(ctx, unpack); + return NULL; + } + + { + struct pipe_transfer *transfer; + static const GLuint dstImageOffsets = 0; + GLboolean success; + GLubyte *dest; + const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; + + /* we'll do pixel transfer in a fragment shader */ + ctx->_ImageTransferState = 0x0; + + transfer = pipe_get_transfer(st->pipe, pt, 0, 0, + PIPE_TRANSFER_WRITE, 0, 0, + width, height); + + /* map texture transfer */ + dest = pipe_transfer_map(pipe, transfer); + + + /* Put image into texture transfer. + * Note that the image is actually going to be upside down in + * the texture. We deal with that with texcoords. + */ + success = _mesa_texstore(ctx, 2, /* dims */ + baseFormat, /* baseInternalFormat */ + mformat, /* gl_format */ + dest, /* dest */ + 0, 0, 0, /* dstX/Y/Zoffset */ + transfer->stride, /* dstRowStride, bytes */ + &dstImageOffsets, /* dstImageOffsets */ + width, height, 1, /* size */ + format, type, /* src format/type */ + pixels, /* data source */ + unpack); + + /* unmap */ + pipe_transfer_unmap(pipe, transfer); + pipe->transfer_destroy(pipe, transfer); + + assert(success); + + /* restore */ + ctx->_ImageTransferState = imageTransferStateSave; + } + + _mesa_unmap_pbo_source(ctx, unpack); + + return pt; +} + + +/** + * Draw quad with texcoords and optional color. + * Coords are gallium window coords with y=0=top. + * \param color may be null + * \param invertTex if true, flip texcoords vertically + */ +static void +draw_quad(struct gl_context *ctx, GLfloat x0, GLfloat y0, GLfloat z, + GLfloat x1, GLfloat y1, const GLfloat *color, + GLboolean invertTex, GLfloat maxXcoord, GLfloat maxYcoord) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */ + + /* setup vertex data */ + { + const struct gl_framebuffer *fb = st->ctx->DrawBuffer; + const GLfloat fb_width = (GLfloat) fb->Width; + const GLfloat fb_height = (GLfloat) fb->Height; + const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f; + const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f; + const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f; + const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f; + const GLfloat sLeft = 0.0f, sRight = maxXcoord; + const GLfloat tTop = invertTex ? maxYcoord : 0.0f; + const GLfloat tBot = invertTex ? 0.0f : maxYcoord; + GLuint i; + + /* upper-left */ + verts[0][0][0] = clip_x0; /* v[0].attr[0].x */ + verts[0][0][1] = clip_y0; /* v[0].attr[0].y */ + + /* upper-right */ + verts[1][0][0] = clip_x1; + verts[1][0][1] = clip_y0; + + /* lower-right */ + verts[2][0][0] = clip_x1; + verts[2][0][1] = clip_y1; + + /* lower-left */ + verts[3][0][0] = clip_x0; + verts[3][0][1] = clip_y1; + + verts[0][1][0] = sLeft; /* v[0].attr[1].S */ + verts[0][1][1] = tTop; /* v[0].attr[1].T */ + verts[1][1][0] = sRight; + verts[1][1][1] = tTop; + verts[2][1][0] = sRight; + verts[2][1][1] = tBot; + verts[3][1][0] = sLeft; + verts[3][1][1] = tBot; + + /* same for all verts: */ + if (color) { + for (i = 0; i < 4; i++) { + verts[i][0][2] = z; /* v[i].attr[0].z */ + verts[i][0][3] = 1.0f; /* v[i].attr[0].w */ + verts[i][2][0] = color[0]; /* v[i].attr[2].r */ + verts[i][2][1] = color[1]; /* v[i].attr[2].g */ + verts[i][2][2] = color[2]; /* v[i].attr[2].b */ + verts[i][2][3] = color[3]; /* v[i].attr[2].a */ + verts[i][1][2] = 0.0f; /* v[i].attr[1].R */ + verts[i][1][3] = 1.0f; /* v[i].attr[1].Q */ + } + } + else { + for (i = 0; i < 4; i++) { + verts[i][0][2] = z; /*Z*/ + verts[i][0][3] = 1.0f; /*W*/ + verts[i][1][2] = 0.0f; /*R*/ + verts[i][1][3] = 1.0f; /*Q*/ + } + } + } + + { + struct pipe_resource *buf; + + /* allocate/load buffer object with vertex data */ + buf = pipe_buffer_create(pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STATIC, + sizeof(verts)); + pipe_buffer_write(st->pipe, buf, 0, sizeof(verts), verts); + + util_draw_vertex_buffer(pipe, st->cso_context, buf, 0, + PIPE_PRIM_QUADS, + 4, /* verts */ + 3); /* attribs/vert */ + pipe_resource_reference(&buf, NULL); + } +} + + + +static void +draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, + GLsizei width, GLsizei height, + GLfloat zoomX, GLfloat zoomY, + struct pipe_sampler_view **sv, + int num_sampler_view, + void *driver_vp, + void *driver_fp, + const GLfloat *color, + GLboolean invertTex, + GLboolean write_depth, GLboolean write_stencil) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct cso_context *cso = st->cso_context; + GLfloat x0, y0, x1, y1; + GLsizei maxSize; + boolean normalized = sv[0]->texture->target != PIPE_TEXTURE_RECT; + + /* limit checks */ + /* XXX if DrawPixels image is larger than max texture size, break + * it up into chunks. + */ + maxSize = 1 << (pipe->screen->get_param(pipe->screen, + PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); + assert(width <= maxSize); + assert(height <= maxSize); + + cso_save_rasterizer(cso); + cso_save_viewport(cso); + cso_save_samplers(cso); + cso_save_fragment_sampler_views(cso); + cso_save_fragment_shader(cso); + cso_save_vertex_shader(cso); + cso_save_vertex_elements(cso); + cso_save_vertex_buffers(cso); + if (write_stencil) { + cso_save_depth_stencil_alpha(cso); + cso_save_blend(cso); + } + + /* rasterizer state: just scissor */ + { + struct pipe_rasterizer_state rasterizer; + memset(&rasterizer, 0, sizeof(rasterizer)); + rasterizer.gl_rasterization_rules = 1; + rasterizer.scissor = ctx->Scissor.Enabled; + cso_set_rasterizer(cso, &rasterizer); + } + + if (write_stencil) { + /* Stencil writing bypasses the normal fragment pipeline to + * disable color writing and set stencil test to always pass. + */ + struct pipe_depth_stencil_alpha_state dsa; + struct pipe_blend_state blend; + + /* depth/stencil */ + memset(&dsa, 0, sizeof(dsa)); + dsa.stencil[0].enabled = 1; + dsa.stencil[0].func = PIPE_FUNC_ALWAYS; + dsa.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; + if (write_depth) { + /* writing depth+stencil: depth test always passes */ + dsa.depth.enabled = 1; + dsa.depth.writemask = ctx->Depth.Mask; + dsa.depth.func = PIPE_FUNC_ALWAYS; + } + cso_set_depth_stencil_alpha(cso, &dsa); + + /* blend (colormask) */ + memset(&blend, 0, sizeof(blend)); + cso_set_blend(cso, &blend); + } + + /* fragment shader state: TEX lookup program */ + cso_set_fragment_shader_handle(cso, driver_fp); + + /* vertex shader state: position + texcoord pass-through */ + cso_set_vertex_shader_handle(cso, driver_vp); + + + /* texture sampling state: */ + { + struct pipe_sampler_state sampler; + memset(&sampler, 0, sizeof(sampler)); + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP; + sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.normalized_coords = normalized; + + cso_single_sampler(cso, 0, &sampler); + if (num_sampler_view > 1) { + cso_single_sampler(cso, 1, &sampler); + } + cso_single_sampler_done(cso); + } + + /* viewport state: viewport matching window dims */ + { + const float w = (float) ctx->DrawBuffer->Width; + const float h = (float) ctx->DrawBuffer->Height; + struct pipe_viewport_state vp; + vp.scale[0] = 0.5f * w; + vp.scale[1] = -0.5f * h; + vp.scale[2] = 0.5f; + vp.scale[3] = 1.0f; + vp.translate[0] = 0.5f * w; + vp.translate[1] = 0.5f * h; + vp.translate[2] = 0.5f; + vp.translate[3] = 0.0f; + cso_set_viewport(cso, &vp); + } + + cso_set_vertex_elements(cso, 3, st->velems_util_draw); + + /* texture state: */ + cso_set_fragment_sampler_views(cso, num_sampler_view, sv); + + /* Compute Gallium window coords (y=0=top) with pixel zoom. + * Recall that these coords are transformed by the current + * vertex shader and viewport transformation. + */ + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { + y = ctx->DrawBuffer->Height - (int) (y + height * ctx->Pixel.ZoomY); + invertTex = !invertTex; + } + + x0 = (GLfloat) x; + x1 = x + width * ctx->Pixel.ZoomX; + y0 = (GLfloat) y; + y1 = y + height * ctx->Pixel.ZoomY; + + /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ + z = z * 2.0 - 1.0; + + draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex, + normalized ? ((GLfloat) width / sv[0]->texture->width0) : (GLfloat)width, + normalized ? ((GLfloat) height / sv[0]->texture->height0) : (GLfloat)height); + + /* restore state */ + cso_restore_rasterizer(cso); + cso_restore_viewport(cso); + cso_restore_samplers(cso); + cso_restore_fragment_sampler_views(cso); + cso_restore_fragment_shader(cso); + cso_restore_vertex_shader(cso); + cso_restore_vertex_elements(cso); + cso_restore_vertex_buffers(cso); + if (write_stencil) { + cso_restore_depth_stencil_alpha(cso); + cso_restore_blend(cso); + } +} + + +/** + * Software fallback to do glDrawPixels(GL_STENCIL_INDEX) when we + * can't use a fragment shader to write stencil values. + */ +static void +draw_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct st_renderbuffer *strb; + enum pipe_transfer_usage usage; + struct pipe_transfer *pt; + const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; + GLint skipPixels; + ubyte *stmap; + struct gl_pixelstore_attrib clippedUnpack = *unpack; + + if (!zoom) { + if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, + &clippedUnpack)) { + /* totally clipped */ + return; + } + } + + strb = st_renderbuffer(ctx->DrawBuffer-> + Attachment[BUFFER_STENCIL].Renderbuffer); + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + y = ctx->DrawBuffer->Height - y - height; + } + + if(format != GL_DEPTH_STENCIL && + util_format_get_component_bits(strb->format, + UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) + usage = PIPE_TRANSFER_READ_WRITE; + else + usage = PIPE_TRANSFER_WRITE; + + pt = pipe_get_transfer(st_context(ctx)->pipe, strb->texture, 0, 0, + usage, x, y, + width, height); + + stmap = pipe_transfer_map(pipe, pt); + + pixels = _mesa_map_pbo_source(ctx, &clippedUnpack, pixels); + assert(pixels); + + /* if width > MAX_WIDTH, have to process image in chunks */ + skipPixels = 0; + while (skipPixels < width) { + const GLint spanX = skipPixels; + const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); + GLint row; + for (row = 0; row < height; row++) { + GLubyte sValues[MAX_WIDTH]; + GLuint zValues[MAX_WIDTH]; + GLenum destType = GL_UNSIGNED_BYTE; + const GLvoid *source = _mesa_image_address2d(&clippedUnpack, pixels, + width, height, + format, type, + row, skipPixels); + _mesa_unpack_stencil_span(ctx, spanWidth, destType, sValues, + type, source, &clippedUnpack, + ctx->_ImageTransferState); + + if (format == GL_DEPTH_STENCIL) { + _mesa_unpack_depth_span(ctx, spanWidth, GL_UNSIGNED_INT, zValues, + (1 << 24) - 1, type, source, + &clippedUnpack); + } + + if (zoom) { + _mesa_problem(ctx, "Gallium glDrawPixels(GL_STENCIL) with " + "zoom not complete"); + } + + { + GLint spanY; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + spanY = height - row - 1; + } + else { + spanY = row; + } + + /* now pack the stencil (and Z) values in the dest format */ + switch (pt->resource->format) { + case PIPE_FORMAT_S8_USCALED: + { + ubyte *dest = stmap + spanY * pt->stride + spanX; + assert(usage == PIPE_TRANSFER_WRITE); + memcpy(dest, sValues, spanWidth); + } + break; + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + if (format == GL_DEPTH_STENCIL) { + uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); + GLint k; + assert(usage == PIPE_TRANSFER_WRITE); + for (k = 0; k < spanWidth; k++) { + dest[k] = zValues[k] | (sValues[k] << 24); + } + } + else { + uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); + GLint k; + assert(usage == PIPE_TRANSFER_READ_WRITE); + for (k = 0; k < spanWidth; k++) { + dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24); + } + } + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + if (format == GL_DEPTH_STENCIL) { + uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); + GLint k; + assert(usage == PIPE_TRANSFER_WRITE); + for (k = 0; k < spanWidth; k++) { + dest[k] = (zValues[k] << 8) | (sValues[k] & 0xff); + } + } + else { + uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); + GLint k; + assert(usage == PIPE_TRANSFER_READ_WRITE); + for (k = 0; k < spanWidth; k++) { + dest[k] = (dest[k] & 0xffffff00) | (sValues[k] & 0xff); + } + } + break; + default: + assert(0); + } + } + } + skipPixels += spanWidth; + } + + _mesa_unmap_pbo_source(ctx, &clippedUnpack); + + /* unmap the stencil buffer */ + pipe_transfer_unmap(pipe, pt); + pipe->transfer_destroy(pipe, pt); +} + + +/** + * Get fragment program variant for a glDrawPixels or glCopyPixels + * command for RGBA data. + */ +static struct st_fp_variant * +get_color_fp_variant(struct st_context *st) +{ + struct gl_context *ctx = st->ctx; + struct st_fp_variant_key key; + struct st_fp_variant *fpv; + + memset(&key, 0, sizeof(key)); + + key.st = st; + key.drawpixels = 1; + key.scaleAndBias = (ctx->Pixel.RedBias != 0.0 || + ctx->Pixel.RedScale != 1.0 || + ctx->Pixel.GreenBias != 0.0 || + ctx->Pixel.GreenScale != 1.0 || + ctx->Pixel.BlueBias != 0.0 || + ctx->Pixel.BlueScale != 1.0 || + ctx->Pixel.AlphaBias != 0.0 || + ctx->Pixel.AlphaScale != 1.0); + key.pixelMaps = ctx->Pixel.MapColorFlag; + + fpv = st_get_fp_variant(st, st->fp, &key); + + return fpv; +} + + +/** + * Get fragment program variant for a glDrawPixels or glCopyPixels + * command for depth/stencil data. + */ +static struct st_fp_variant * +get_depth_stencil_fp_variant(struct st_context *st, GLboolean write_depth, + GLboolean write_stencil) +{ + struct st_fp_variant_key key; + struct st_fp_variant *fpv; + + memset(&key, 0, sizeof(key)); + + key.st = st; + key.drawpixels = 1; + key.drawpixels_z = write_depth; + key.drawpixels_stencil = write_stencil; + + fpv = st_get_fp_variant(st, st->fp, &key); + + return fpv; +} + + +/** + * Called via ctx->Driver.DrawPixels() + */ +static void +st_DrawPixels(struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) +{ + void *driver_vp, *driver_fp; + struct st_context *st = st_context(ctx); + const GLfloat *color; + struct pipe_context *pipe = st->pipe; + GLboolean write_stencil = GL_FALSE, write_depth = GL_FALSE; + struct pipe_sampler_view *sv[2]; + int num_sampler_view = 1; + enum pipe_format stencil_format = PIPE_FORMAT_NONE; + struct st_fp_variant *fpv; + + if (format == GL_DEPTH_STENCIL) + write_stencil = write_depth = GL_TRUE; + else if (format == GL_STENCIL_INDEX) + write_stencil = GL_TRUE; + else if (format == GL_DEPTH_COMPONENT) + write_depth = GL_TRUE; + + if (write_stencil) { + enum pipe_format tex_format; + /* can we write to stencil if not fallback */ + if (!pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) + goto stencil_fallback; + + tex_format = st_choose_format(st->pipe->screen, base_format(format), + PIPE_TEXTURE_2D, + 0, PIPE_BIND_SAMPLER_VIEW); + if (tex_format == PIPE_FORMAT_Z24_UNORM_S8_USCALED) + stencil_format = PIPE_FORMAT_X24S8_USCALED; + else if (tex_format == PIPE_FORMAT_S8_USCALED_Z24_UNORM) + stencil_format = PIPE_FORMAT_S8X24_USCALED; + else + stencil_format = PIPE_FORMAT_S8_USCALED; + if (stencil_format == PIPE_FORMAT_NONE) + goto stencil_fallback; + } + + /* Mesa state should be up to date by now */ + assert(ctx->NewState == 0x0); + + st_validate_state(st); + + /* + * Get vertex/fragment shaders + */ + if (write_depth || write_stencil) { + fpv = get_depth_stencil_fp_variant(st, write_depth, write_stencil); + + driver_fp = fpv->driver_shader; + + driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); + + color = ctx->Current.RasterColor; + } + else { + fpv = get_color_fp_variant(st); + + driver_fp = fpv->driver_shader; + + driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); + + color = NULL; + if (st->pixel_xfer.pixelmap_enabled) { + sv[1] = st->pixel_xfer.pixelmap_sampler_view; + num_sampler_view++; + } + } + + /* update fragment program constants */ + st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); + + /* draw with textured quad */ + { + struct pipe_resource *pt + = make_texture(st, width, height, format, type, unpack, pixels); + if (pt) { + sv[0] = st_create_texture_sampler_view(st->pipe, pt); + + if (sv[0]) { + if (write_stencil) { + sv[1] = st_create_texture_sampler_view_format(st->pipe, pt, + stencil_format); + num_sampler_view++; + } + + draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], + width, height, + ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, + sv, + num_sampler_view, + driver_vp, + driver_fp, + color, GL_FALSE, write_depth, write_stencil); + pipe_sampler_view_reference(&sv[0], NULL); + if (num_sampler_view > 1) + pipe_sampler_view_reference(&sv[1], NULL); + } + pipe_resource_reference(&pt, NULL); + } + } + return; + +stencil_fallback: + draw_stencil_pixels(ctx, x, y, width, height, format, type, + unpack, pixels); +} + + + +/** + * Software fallback for glCopyPixels(GL_STENCIL). + */ +static void +copy_stencil_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, + GLsizei width, GLsizei height, + GLint dstx, GLint dsty) +{ + struct st_renderbuffer *rbDraw; + struct pipe_context *pipe = st_context(ctx)->pipe; + enum pipe_transfer_usage usage; + struct pipe_transfer *ptDraw; + ubyte *drawMap; + ubyte *buffer; + int i; + + buffer = malloc(width * height * sizeof(ubyte)); + if (!buffer) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)"); + return; + } + + /* Get the dest renderbuffer. If there's a wrapper, use the + * underlying renderbuffer. + */ + rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer); + if (rbDraw->Base.Wrapped) + rbDraw = st_renderbuffer(rbDraw->Base.Wrapped); + + /* this will do stencil pixel transfer ops */ + st_read_stencil_pixels(ctx, srcx, srcy, width, height, + GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, + &ctx->DefaultPacking, buffer); + + if (0) { + /* debug code: dump stencil values */ + GLint row, col; + for (row = 0; row < height; row++) { + printf("%3d: ", row); + for (col = 0; col < width; col++) { + printf("%02x ", buffer[col + row * width]); + } + printf("\n"); + } + } + + if (util_format_get_component_bits(rbDraw->format, + UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) + usage = PIPE_TRANSFER_READ_WRITE; + else + usage = PIPE_TRANSFER_WRITE; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + dsty = rbDraw->Base.Height - dsty - height; + } + + ptDraw = pipe_get_transfer(st_context(ctx)->pipe, + rbDraw->texture, 0, 0, + usage, dstx, dsty, + width, height); + + assert(util_format_get_blockwidth(ptDraw->resource->format) == 1); + assert(util_format_get_blockheight(ptDraw->resource->format) == 1); + + /* map the stencil buffer */ + drawMap = pipe_transfer_map(pipe, ptDraw); + + /* draw */ + /* XXX PixelZoom not handled yet */ + for (i = 0; i < height; i++) { + ubyte *dst; + const ubyte *src; + int y; + + y = i; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + y = height - y - 1; + } + + dst = drawMap + y * ptDraw->stride; + src = buffer + i * width; + + switch (ptDraw->resource->format) { + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + { + uint *dst4 = (uint *) dst; + int j; + assert(usage == PIPE_TRANSFER_READ_WRITE); + for (j = 0; j < width; j++) { + *dst4 = (*dst4 & 0xffffff) | (src[j] << 24); + dst4++; + } + } + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + { + uint *dst4 = (uint *) dst; + int j; + assert(usage == PIPE_TRANSFER_READ_WRITE); + for (j = 0; j < width; j++) { + *dst4 = (*dst4 & 0xffffff00) | (src[j] & 0xff); + dst4++; + } + } + break; + case PIPE_FORMAT_S8_USCALED: + assert(usage == PIPE_TRANSFER_WRITE); + memcpy(dst, src, width); + break; + default: + assert(0); + } + } + + free(buffer); + + /* unmap the stencil buffer */ + pipe_transfer_unmap(pipe, ptDraw); + pipe->transfer_destroy(pipe, ptDraw); +} + + +/** Do the src/dest regions overlap? */ +static GLboolean +regions_overlap(GLint srcX, GLint srcY, GLint dstX, GLint dstY, + GLsizei width, GLsizei height) +{ + if (srcX + width <= dstX || + dstX + width <= srcX || + srcY + height <= dstY || + dstY + height <= srcY) + return GL_FALSE; + else + return GL_TRUE; +} + + +/** + * Try to do a glCopyPixels for simple cases with a blit by calling + * pipe->resource_copy_region(). + * + * We can do this when we're copying color pixels (depth/stencil + * eventually) with no pixel zoom, no pixel transfer ops, no + * per-fragment ops, the src/dest regions don't overlap and the + * src/dest pixel formats are the same. + */ +static GLboolean +blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, + GLsizei width, GLsizei height, + GLint dstx, GLint dsty, GLenum type) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct gl_pixelstore_attrib pack, unpack; + GLint readX, readY, readW, readH; + + if (type == GL_COLOR && + ctx->Pixel.ZoomX == 1.0 && + ctx->Pixel.ZoomY == 1.0 && + ctx->_ImageTransferState == 0x0 && + !ctx->Color.BlendEnabled && + !ctx->Color.AlphaEnabled && + !ctx->Depth.Test && + !ctx->Fog.Enabled && + !ctx->Stencil.Enabled && + !ctx->FragmentProgram.Enabled && + !ctx->VertexProgram.Enabled && + !ctx->Shader.CurrentFragmentProgram && + st_fb_orientation(ctx->ReadBuffer) == st_fb_orientation(ctx->DrawBuffer) && + ctx->DrawBuffer->_NumColorDrawBuffers == 1) { + struct st_renderbuffer *rbRead, *rbDraw; + GLint drawX, drawY; + + /* + * Clip the read region against the src buffer bounds. + * We'll still allocate a temporary buffer/texture for the original + * src region size but we'll only read the region which is on-screen. + * This may mean that we draw garbage pixels into the dest region, but + * that's expected. + */ + readX = srcx; + readY = srcy; + readW = width; + readH = height; + pack = ctx->DefaultPacking; + if (!_mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack)) + return GL_TRUE; /* all done */ + + /* clip against dest buffer bounds and scissor box */ + drawX = dstx + pack.SkipPixels; + drawY = dsty + pack.SkipRows; + unpack = pack; + if (!_mesa_clip_drawpixels(ctx, &drawX, &drawY, &readW, &readH, &unpack)) + return GL_TRUE; /* all done */ + + readX = readX - pack.SkipPixels + unpack.SkipPixels; + readY = readY - pack.SkipRows + unpack.SkipRows; + + rbRead = st_get_color_read_renderbuffer(ctx); + rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); + + if ((rbRead != rbDraw || + !regions_overlap(readX, readY, drawX, drawY, readW, readH)) && + rbRead->Base.Format == rbDraw->Base.Format) { + struct pipe_box srcBox; + + /* flip src/dst position if needed */ + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + /* both buffers will have the same orientation */ + readY = ctx->ReadBuffer->Height - readY - readH; + drawY = ctx->DrawBuffer->Height - drawY - readH; + } + + u_box_2d(readX, readY, readW, readH, &srcBox); + + pipe->resource_copy_region(pipe, + rbDraw->texture, 0, drawX, drawY, 0, + rbRead->texture, 0, &srcBox); + return GL_TRUE; + } + } + + return GL_FALSE; +} + + +static void +st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, + GLsizei width, GLsizei height, + GLint dstx, GLint dsty, GLenum type) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + struct st_renderbuffer *rbRead; + void *driver_vp, *driver_fp; + struct pipe_resource *pt; + struct pipe_sampler_view *sv[2]; + int num_sampler_view = 1; + GLfloat *color; + enum pipe_format srcFormat, texFormat; + GLboolean invertTex = GL_FALSE; + GLint readX, readY, readW, readH; + GLuint sample_count; + struct gl_pixelstore_attrib pack = ctx->DefaultPacking; + struct st_fp_variant *fpv; + + st_validate_state(st); + + if (type == GL_STENCIL) { + /* can't use texturing to do stencil */ + copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); + return; + } + + if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type)) + return; + + /* + * The subsequent code implements glCopyPixels by copying the source + * pixels into a temporary texture that's then applied to a textured quad. + * When we draw the textured quad, all the usual per-fragment operations + * are handled. + */ + + + /* + * Get vertex/fragment shaders + */ + if (type == GL_COLOR) { + rbRead = st_get_color_read_renderbuffer(ctx); + color = NULL; + + fpv = get_color_fp_variant(st); + driver_fp = fpv->driver_shader; + + driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); + + if (st->pixel_xfer.pixelmap_enabled) { + sv[1] = st->pixel_xfer.pixelmap_sampler_view; + num_sampler_view++; + } + } + else { + assert(type == GL_DEPTH); + rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); + color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; + + fpv = get_depth_stencil_fp_variant(st, GL_TRUE, GL_FALSE); + driver_fp = fpv->driver_shader; + + driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); + } + + /* update fragment program constants */ + st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); + + + if (rbRead->Base.Wrapped) + rbRead = st_renderbuffer(rbRead->Base.Wrapped); + + sample_count = rbRead->texture->nr_samples; + /* I believe this would be legal, presumably would need to do a resolve + for color, and for depth/stencil spec says to just use one of the + depth/stencil samples per pixel? Need some transfer clarifications. */ + assert(sample_count < 2); + + srcFormat = rbRead->texture->format; + + if (screen->is_format_supported(screen, srcFormat, st->internal_target, + sample_count, + PIPE_BIND_SAMPLER_VIEW, 0)) { + texFormat = srcFormat; + } + else { + /* srcFormat can't be used as a texture format */ + if (type == GL_DEPTH) { + texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT, + st->internal_target, sample_count, + PIPE_BIND_DEPTH_STENCIL); + assert(texFormat != PIPE_FORMAT_NONE); + } + else { + /* default color format */ + texFormat = st_choose_format(screen, GL_RGBA, st->internal_target, + sample_count, PIPE_BIND_SAMPLER_VIEW); + assert(texFormat != PIPE_FORMAT_NONE); + } + } + + /* Invert src region if needed */ + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + srcy = ctx->ReadBuffer->Height - srcy - height; + invertTex = !invertTex; + } + + /* Clip the read region against the src buffer bounds. + * We'll still allocate a temporary buffer/texture for the original + * src region size but we'll only read the region which is on-screen. + * This may mean that we draw garbage pixels into the dest region, but + * that's expected. + */ + readX = srcx; + readY = srcy; + readW = width; + readH = height; + _mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack); + readW = MAX2(0, readW); + readH = MAX2(0, readH); + + /* alloc temporary texture */ + pt = alloc_texture(st, width, height, texFormat); + if (!pt) + return; + + sv[0] = st_create_texture_sampler_view(st->pipe, pt); + if (!sv[0]) { + pipe_resource_reference(&pt, NULL); + return; + } + + /* Make temporary texture which is a copy of the src region. + */ + if (srcFormat == texFormat) { + struct pipe_box src_box; + u_box_2d(readX, readY, readW, readH, &src_box); + /* copy source framebuffer surface into mipmap/texture */ + pipe->resource_copy_region(pipe, + pt, /* dest tex */ + 0, + pack.SkipPixels, pack.SkipRows, 0, /* dest pos */ + rbRead->texture, /* src tex */ + 0, + &src_box); + + } + else { + /* CPU-based fallback/conversion */ + struct pipe_transfer *ptRead = + pipe_get_transfer(st->pipe, rbRead->texture, + 0, 0, /* level, layer */ + PIPE_TRANSFER_READ, + readX, readY, readW, readH); + struct pipe_transfer *ptTex; + enum pipe_transfer_usage transfer_usage; + + if (ST_DEBUG & DEBUG_FALLBACK) + debug_printf("%s: fallback processing\n", __FUNCTION__); + + if (type == GL_DEPTH && util_format_is_depth_and_stencil(pt->format)) + transfer_usage = PIPE_TRANSFER_READ_WRITE; + else + transfer_usage = PIPE_TRANSFER_WRITE; + + ptTex = pipe_get_transfer(st->pipe, pt, 0, 0, transfer_usage, + 0, 0, width, height); + + /* copy image from ptRead surface to ptTex surface */ + if (type == GL_COLOR) { + /* alternate path using get/put_tile() */ + GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + enum pipe_format readFormat, drawFormat; + readFormat = util_format_linear(rbRead->texture->format); + drawFormat = util_format_linear(pt->format); + pipe_get_tile_rgba_format(pipe, ptRead, 0, 0, readW, readH, + readFormat, buf); + pipe_put_tile_rgba_format(pipe, ptTex, pack.SkipPixels, pack.SkipRows, + readW, readH, drawFormat, buf); + free(buf); + } + else { + /* GL_DEPTH */ + GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint)); + pipe_get_tile_z(pipe, ptRead, 0, 0, readW, readH, buf); + pipe_put_tile_z(pipe, ptTex, pack.SkipPixels, pack.SkipRows, + readW, readH, buf); + free(buf); + } + + pipe->transfer_destroy(pipe, ptRead); + pipe->transfer_destroy(pipe, ptTex); + } + + /* OK, the texture 'pt' contains the src image/pixels. Now draw a + * textured quad with that texture. + */ + draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], + width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, + sv, + num_sampler_view, + driver_vp, + driver_fp, + color, invertTex, GL_FALSE, GL_FALSE); + + pipe_resource_reference(&pt, NULL); + pipe_sampler_view_reference(&sv[0], NULL); +} + + + +void st_init_drawpixels_functions(struct dd_function_table *functions) +{ + functions->DrawPixels = st_DrawPixels; + functions->CopyPixels = st_CopyPixels; +} + + +void +st_destroy_drawpix(struct st_context *st) +{ + GLuint i; + + for (i = 0; i < Elements(st->drawpix.shaders); i++) { + if (st->drawpix.shaders[i]) + _mesa_reference_fragprog(st->ctx, &st->drawpix.shaders[i], NULL); + } + + st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL); + if (st->drawpix.vert_shaders[0]) + ureg_free_tokens(st->drawpix.vert_shaders[0]); + if (st->drawpix.vert_shaders[1]) + ureg_free_tokens(st->drawpix.vert_shaders[1]); +} + +#endif /* FEATURE_drawpix */ diff --git a/mesalib/src/mesa/state_tracker/st_cb_readpixels.c b/mesalib/src/mesa/state_tracker/st_cb_readpixels.c index 570873916..f8da2a4d1 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_readpixels.c +++ b/mesalib/src/mesa/state_tracker/st_cb_readpixels.c @@ -1,560 +1,561 @@ -/************************************************************************** - * - * 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. - * - **************************************************************************/ - - -/** - * glReadPixels interface to pipe - * - * \author Brian Paul - */ - - -#include "main/imports.h" -#include "main/bufferobj.h" -#include "main/context.h" -#include "main/image.h" -#include "main/pack.h" - -#include "pipe/p_context.h" -#include "pipe/p_defines.h" -#include "util/u_format.h" -#include "util/u_inlines.h" -#include "util/u_tile.h" - -#include "st_debug.h" -#include "st_context.h" -#include "st_atom.h" -#include "st_cb_bitmap.h" -#include "st_cb_readpixels.h" -#include "st_cb_fbo.h" - -/** - * Special case for reading stencil buffer. - * For color/depth we use get_tile(). For stencil, map the stencil buffer. - */ -void -st_read_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - const struct gl_pixelstore_attrib *packing, - GLvoid *pixels) -{ - struct gl_framebuffer *fb = ctx->ReadBuffer; - struct pipe_context *pipe = st_context(ctx)->pipe; - struct st_renderbuffer *strb = st_renderbuffer(fb->_StencilBuffer); - struct pipe_transfer *pt; - ubyte *stmap; - GLint j; - - if (strb->Base.Wrapped) { - strb = st_renderbuffer(strb->Base.Wrapped); - } - - if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { - y = ctx->DrawBuffer->Height - y - height; - } - - /* Create a read transfer from the renderbuffer's texture */ - - pt = pipe_get_transfer(pipe, strb->texture, - 0, 0, - PIPE_TRANSFER_READ, - x, y, width, height); - - /* map the stencil buffer */ - stmap = pipe_transfer_map(pipe, pt); - - /* width should never be > MAX_WIDTH since we did clipping earlier */ - ASSERT(width <= MAX_WIDTH); - - /* process image row by row */ - for (j = 0; j < height; j++) { - GLvoid *dest; - GLstencil sValues[MAX_WIDTH]; - GLfloat zValues[MAX_WIDTH]; - GLint srcY; - - if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { - srcY = height - j - 1; - } - else { - srcY = j; - } - - /* get stencil (and Z) values */ - switch (pt->resource->format) { - case PIPE_FORMAT_S8_USCALED: - { - const ubyte *src = stmap + srcY * pt->stride; - memcpy(sValues, src, width); - } - break; - case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - if (format == GL_DEPTH_STENCIL) { - const uint *src = (uint *) (stmap + srcY * pt->stride); - const GLfloat scale = 1.0f / (0xffffff); - GLint k; - for (k = 0; k < width; k++) { - sValues[k] = src[k] >> 24; - zValues[k] = (src[k] & 0xffffff) * scale; - } - } - else { - const uint *src = (uint *) (stmap + srcY * pt->stride); - GLint k; - for (k = 0; k < width; k++) { - sValues[k] = src[k] >> 24; - } - } - break; - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - if (format == GL_DEPTH_STENCIL) { - const uint *src = (uint *) (stmap + srcY * pt->stride); - const GLfloat scale = 1.0f / (0xffffff); - GLint k; - for (k = 0; k < width; k++) { - sValues[k] = src[k] & 0xff; - zValues[k] = (src[k] >> 8) * scale; - } - } - else { - const uint *src = (uint *) (stmap + srcY * pt->stride); - GLint k; - for (k = 0; k < width; k++) { - sValues[k] = src[k] & 0xff; - } - } - break; - default: - assert(0); - } - - /* store */ - dest = _mesa_image_address2d(packing, pixels, width, height, - format, type, j, 0); - if (format == GL_DEPTH_STENCIL) { - _mesa_pack_depth_stencil_span(ctx, width, dest, - zValues, sValues, packing); - } - else { - _mesa_pack_stencil_span(ctx, width, type, dest, sValues, packing); - } - } - - /* unmap the stencil buffer */ - pipe_transfer_unmap(pipe, pt); - pipe->transfer_destroy(pipe, pt); -} - - -/** - * Return renderbuffer to use for reading color pixels for glRead/CopyPixel - * commands. - */ -struct st_renderbuffer * -st_get_color_read_renderbuffer(struct gl_context *ctx) -{ - struct gl_framebuffer *fb = ctx->ReadBuffer; - struct st_renderbuffer *strb = - st_renderbuffer(fb->_ColorReadBuffer); - - return strb; -} - - -/** - * Try to do glReadPixels in a fast manner for common cases. - * \return GL_TRUE for success, GL_FALSE for failure - */ -static GLboolean -st_fast_readpixels(struct gl_context *ctx, struct st_renderbuffer *strb, - GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, - const struct gl_pixelstore_attrib *pack, - GLvoid *dest) -{ - enum combination { - A8R8G8B8_UNORM_TO_RGBA_UBYTE, - A8R8G8B8_UNORM_TO_RGB_UBYTE, - A8R8G8B8_UNORM_TO_BGRA_UINT - } combo; - - if (ctx->_ImageTransferState) - return GL_FALSE; - - if (strb->format == PIPE_FORMAT_B8G8R8A8_UNORM && - format == GL_RGBA && type == GL_UNSIGNED_BYTE) { - combo = A8R8G8B8_UNORM_TO_RGBA_UBYTE; - } - else if (strb->format == PIPE_FORMAT_B8G8R8A8_UNORM && - format == GL_RGB && type == GL_UNSIGNED_BYTE) { - combo = A8R8G8B8_UNORM_TO_RGB_UBYTE; - } - else if (strb->format == PIPE_FORMAT_B8G8R8A8_UNORM && - format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) { - combo = A8R8G8B8_UNORM_TO_BGRA_UINT; - } - else { - return GL_FALSE; - } - - /*printf("st_fast_readpixels combo %d\n", (GLint) combo);*/ - - { - struct pipe_context *pipe = st_context(ctx)->pipe; - struct pipe_transfer *trans; - const GLubyte *map; - GLubyte *dst; - GLint row, col, dy, dstStride; - - if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { - /* convert GL Y to Gallium Y */ - y = strb->texture->height0 - y - height; - } - - trans = pipe_get_transfer(pipe, strb->texture, - 0, 0, - PIPE_TRANSFER_READ, - x, y, width, height); - if (!trans) { - return GL_FALSE; - } - - map = pipe_transfer_map(pipe, trans); - if (!map) { - pipe->transfer_destroy(pipe, trans); - return GL_FALSE; - } - - /* We always write to the user/dest buffer from low addr to high addr - * but the read order depends on renderbuffer orientation - */ - if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { - /* read source rows from bottom to top */ - y = height - 1; - dy = -1; - } - else { - /* read source rows from top to bottom */ - y = 0; - dy = 1; - } - - dst = _mesa_image_address2d(pack, dest, width, height, - format, type, 0, 0); - dstStride = _mesa_image_row_stride(pack, width, format, type); - - switch (combo) { - case A8R8G8B8_UNORM_TO_RGBA_UBYTE: - for (row = 0; row < height; row++) { - const GLubyte *src = map + y * trans->stride; - for (col = 0; col < width; col++) { - GLuint pixel = ((GLuint *) src)[col]; - dst[col*4+0] = (pixel >> 16) & 0xff; - dst[col*4+1] = (pixel >> 8) & 0xff; - dst[col*4+2] = (pixel >> 0) & 0xff; - dst[col*4+3] = (pixel >> 24) & 0xff; - } - dst += dstStride; - y += dy; - } - break; - case A8R8G8B8_UNORM_TO_RGB_UBYTE: - for (row = 0; row < height; row++) { - const GLubyte *src = map + y * trans->stride; - for (col = 0; col < width; col++) { - GLuint pixel = ((GLuint *) src)[col]; - dst[col*3+0] = (pixel >> 16) & 0xff; - dst[col*3+1] = (pixel >> 8) & 0xff; - dst[col*3+2] = (pixel >> 0) & 0xff; - } - dst += dstStride; - y += dy; - } - break; - case A8R8G8B8_UNORM_TO_BGRA_UINT: - for (row = 0; row < height; row++) { - const GLubyte *src = map + y * trans->stride; - memcpy(dst, src, 4 * width); - dst += dstStride; - y += dy; - } - break; - default: - ; /* nothing */ - } - - pipe_transfer_unmap(pipe, trans); - pipe->transfer_destroy(pipe, trans); - } - - return GL_TRUE; -} - - -/** - * Do glReadPixels by getting rows from the framebuffer transfer with - * get_tile(). Convert to requested format/type with Mesa image routines. - * Image transfer ops are done in software too. - */ -static void -st_readpixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, - const struct gl_pixelstore_attrib *pack, - GLvoid *dest) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - GLfloat (*temp)[4]; - const GLbitfield transferOps = ctx->_ImageTransferState; - GLsizei i, j; - GLint yStep, dfStride; - GLfloat *df; - struct st_renderbuffer *strb; - struct gl_pixelstore_attrib clippedPacking = *pack; - struct pipe_transfer *trans; - enum pipe_format pformat; - - assert(ctx->ReadBuffer->Width > 0); - - st_validate_state(st); - - /* Do all needed clipping here, so that we can forget about it later */ - if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) { - /* The ReadPixels transfer is totally outside the window bounds */ - return; - } - - st_flush_bitmap_cache(st); - - dest = _mesa_map_pbo_dest(ctx, &clippedPacking, dest); - if (!dest) - return; - - if (format == GL_STENCIL_INDEX || - format == GL_DEPTH_STENCIL) { - st_read_stencil_pixels(ctx, x, y, width, height, - format, type, pack, dest); - return; - } - else if (format == GL_DEPTH_COMPONENT) { - strb = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); - if (strb->Base.Wrapped) { - strb = st_renderbuffer(strb->Base.Wrapped); - } - } - else { - /* Read color buffer */ - strb = st_get_color_read_renderbuffer(ctx); - } - - if (!strb) - return; - - /* try a fast-path readpixels before anything else */ - if (st_fast_readpixels(ctx, strb, x, y, width, height, - format, type, pack, dest)) { - /* success! */ - _mesa_unmap_pbo_dest(ctx, &clippedPacking); - return; - } - - /* allocate temp pixel row buffer */ - temp = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat)); - if (!temp) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); - return; - } - - if (format == GL_RGBA && type == GL_FLOAT) { - /* write tile(row) directly into user's buffer */ - df = (GLfloat *) _mesa_image_address2d(&clippedPacking, dest, width, - height, format, type, 0, 0); - dfStride = width * 4; - } - else { - /* write tile(row) into temp row buffer */ - df = (GLfloat *) temp; - dfStride = 0; - } - - if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { - /* convert GL Y to Gallium Y */ - y = strb->Base.Height - y - height; - } - - /* Create a read transfer from the renderbuffer's texture */ - trans = pipe_get_transfer(pipe, strb->texture, - 0, 0, - PIPE_TRANSFER_READ, - x, y, width, height); - - /* determine bottom-to-top vs. top-to-bottom order */ - if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { - y = height - 1; - yStep = -1; - } - else { - y = 0; - yStep = 1; - } - - /* possibly convert sRGB format to linear RGB format */ - pformat = util_format_linear(trans->resource->format); - - if (ST_DEBUG & DEBUG_FALLBACK) - debug_printf("%s: fallback processing\n", __FUNCTION__); - - /* - * Copy pixels from pipe_transfer to user memory - */ - { - /* dest of first pixel in client memory */ - GLubyte *dst = _mesa_image_address2d(&clippedPacking, dest, width, - height, format, type, 0, 0); - /* dest row stride */ - const GLint dstStride = _mesa_image_row_stride(&clippedPacking, width, - format, type); - - if (pformat == PIPE_FORMAT_Z24_UNORM_S8_USCALED || - pformat == PIPE_FORMAT_Z24X8_UNORM) { - if (format == GL_DEPTH_COMPONENT) { - for (i = 0; i < height; i++) { - GLuint ztemp[MAX_WIDTH]; - GLfloat zfloat[MAX_WIDTH]; - const double scale = 1.0 / ((1 << 24) - 1); - pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0); - y += yStep; - for (j = 0; j < width; j++) { - zfloat[j] = (float) (scale * (ztemp[j] & 0xffffff)); - } - _mesa_pack_depth_span(ctx, width, dst, type, - zfloat, &clippedPacking); - dst += dstStride; - } - } - else { - /* XXX: unreachable code -- should be before st_read_stencil_pixels */ - assert(format == GL_DEPTH_STENCIL_EXT); - for (i = 0; i < height; i++) { - GLuint *zshort = (GLuint *)dst; - pipe_get_tile_raw(pipe, trans, 0, y, width, 1, dst, 0); - y += yStep; - /* Reverse into 24/8 */ - for (j = 0; j < width; j++) { - zshort[j] = (zshort[j] << 8) | (zshort[j] >> 24); - } - dst += dstStride; - } - } - } - else if (pformat == PIPE_FORMAT_S8_USCALED_Z24_UNORM || - pformat == PIPE_FORMAT_X8Z24_UNORM) { - if (format == GL_DEPTH_COMPONENT) { - for (i = 0; i < height; i++) { - GLuint ztemp[MAX_WIDTH]; - GLfloat zfloat[MAX_WIDTH]; - const double scale = 1.0 / ((1 << 24) - 1); - pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0); - y += yStep; - for (j = 0; j < width; j++) { - zfloat[j] = (float) (scale * ((ztemp[j] >> 8) & 0xffffff)); - } - _mesa_pack_depth_span(ctx, width, dst, type, - zfloat, &clippedPacking); - dst += dstStride; - } - } - else { - /* XXX: unreachable code -- should be before st_read_stencil_pixels */ - assert(format == GL_DEPTH_STENCIL_EXT); - for (i = 0; i < height; i++) { - pipe_get_tile_raw(pipe, trans, 0, y, width, 1, dst, 0); - y += yStep; - dst += dstStride; - } - } - } - else if (pformat == PIPE_FORMAT_Z16_UNORM) { - for (i = 0; i < height; i++) { - GLushort ztemp[MAX_WIDTH]; - GLfloat zfloat[MAX_WIDTH]; - const double scale = 1.0 / 0xffff; - pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0); - y += yStep; - for (j = 0; j < width; j++) { - zfloat[j] = (float) (scale * ztemp[j]); - } - _mesa_pack_depth_span(ctx, width, dst, type, - zfloat, &clippedPacking); - dst += dstStride; - } - } - else if (pformat == PIPE_FORMAT_Z32_UNORM) { - for (i = 0; i < height; i++) { - GLuint ztemp[MAX_WIDTH]; - GLfloat zfloat[MAX_WIDTH]; - const double scale = 1.0 / 0xffffffff; - pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0); - y += yStep; - for (j = 0; j < width; j++) { - zfloat[j] = (float) (scale * ztemp[j]); - } - _mesa_pack_depth_span(ctx, width, dst, type, - zfloat, &clippedPacking); - dst += dstStride; - } - } - else { - /* RGBA format */ - /* Do a row at a time to flip image data vertically */ - for (i = 0; i < height; i++) { - pipe_get_tile_rgba_format(pipe, trans, 0, y, width, 1, - pformat, df); - y += yStep; - df += dfStride; - if (!dfStride) { - _mesa_pack_rgba_span_float(ctx, width, temp, format, type, dst, - &clippedPacking, transferOps); - dst += dstStride; - } - } - } - } - - free(temp); - - pipe->transfer_destroy(pipe, trans); - - _mesa_unmap_pbo_dest(ctx, &clippedPacking); -} - - -void st_init_readpixels_functions(struct dd_function_table *functions) -{ - functions->ReadPixels = st_readpixels; -} +/************************************************************************** + * + * 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. + * + **************************************************************************/ + + +/** + * glReadPixels interface to pipe + * + * \author Brian Paul + */ + + +#include "main/imports.h" +#include "main/bufferobj.h" +#include "main/context.h" +#include "main/image.h" +#include "main/pack.h" +#include "main/pbo.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "util/u_format.h" +#include "util/u_inlines.h" +#include "util/u_tile.h" + +#include "st_debug.h" +#include "st_context.h" +#include "st_atom.h" +#include "st_cb_bitmap.h" +#include "st_cb_readpixels.h" +#include "st_cb_fbo.h" + +/** + * Special case for reading stencil buffer. + * For color/depth we use get_tile(). For stencil, map the stencil buffer. + */ +void +st_read_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *packing, + GLvoid *pixels) +{ + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_renderbuffer *strb = st_renderbuffer(fb->_StencilBuffer); + struct pipe_transfer *pt; + ubyte *stmap; + GLint j; + + if (strb->Base.Wrapped) { + strb = st_renderbuffer(strb->Base.Wrapped); + } + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + y = ctx->DrawBuffer->Height - y - height; + } + + /* Create a read transfer from the renderbuffer's texture */ + + pt = pipe_get_transfer(pipe, strb->texture, + 0, 0, + PIPE_TRANSFER_READ, + x, y, width, height); + + /* map the stencil buffer */ + stmap = pipe_transfer_map(pipe, pt); + + /* width should never be > MAX_WIDTH since we did clipping earlier */ + ASSERT(width <= MAX_WIDTH); + + /* process image row by row */ + for (j = 0; j < height; j++) { + GLvoid *dest; + GLstencil sValues[MAX_WIDTH]; + GLfloat zValues[MAX_WIDTH]; + GLint srcY; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + srcY = height - j - 1; + } + else { + srcY = j; + } + + /* get stencil (and Z) values */ + switch (pt->resource->format) { + case PIPE_FORMAT_S8_USCALED: + { + const ubyte *src = stmap + srcY * pt->stride; + memcpy(sValues, src, width); + } + break; + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + if (format == GL_DEPTH_STENCIL) { + const uint *src = (uint *) (stmap + srcY * pt->stride); + const GLfloat scale = 1.0f / (0xffffff); + GLint k; + for (k = 0; k < width; k++) { + sValues[k] = src[k] >> 24; + zValues[k] = (src[k] & 0xffffff) * scale; + } + } + else { + const uint *src = (uint *) (stmap + srcY * pt->stride); + GLint k; + for (k = 0; k < width; k++) { + sValues[k] = src[k] >> 24; + } + } + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + if (format == GL_DEPTH_STENCIL) { + const uint *src = (uint *) (stmap + srcY * pt->stride); + const GLfloat scale = 1.0f / (0xffffff); + GLint k; + for (k = 0; k < width; k++) { + sValues[k] = src[k] & 0xff; + zValues[k] = (src[k] >> 8) * scale; + } + } + else { + const uint *src = (uint *) (stmap + srcY * pt->stride); + GLint k; + for (k = 0; k < width; k++) { + sValues[k] = src[k] & 0xff; + } + } + break; + default: + assert(0); + } + + /* store */ + dest = _mesa_image_address2d(packing, pixels, width, height, + format, type, j, 0); + if (format == GL_DEPTH_STENCIL) { + _mesa_pack_depth_stencil_span(ctx, width, dest, + zValues, sValues, packing); + } + else { + _mesa_pack_stencil_span(ctx, width, type, dest, sValues, packing); + } + } + + /* unmap the stencil buffer */ + pipe_transfer_unmap(pipe, pt); + pipe->transfer_destroy(pipe, pt); +} + + +/** + * Return renderbuffer to use for reading color pixels for glRead/CopyPixel + * commands. + */ +struct st_renderbuffer * +st_get_color_read_renderbuffer(struct gl_context *ctx) +{ + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct st_renderbuffer *strb = + st_renderbuffer(fb->_ColorReadBuffer); + + return strb; +} + + +/** + * Try to do glReadPixels in a fast manner for common cases. + * \return GL_TRUE for success, GL_FALSE for failure + */ +static GLboolean +st_fast_readpixels(struct gl_context *ctx, struct st_renderbuffer *strb, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *dest) +{ + enum combination { + A8R8G8B8_UNORM_TO_RGBA_UBYTE, + A8R8G8B8_UNORM_TO_RGB_UBYTE, + A8R8G8B8_UNORM_TO_BGRA_UINT + } combo; + + if (ctx->_ImageTransferState) + return GL_FALSE; + + if (strb->format == PIPE_FORMAT_B8G8R8A8_UNORM && + format == GL_RGBA && type == GL_UNSIGNED_BYTE) { + combo = A8R8G8B8_UNORM_TO_RGBA_UBYTE; + } + else if (strb->format == PIPE_FORMAT_B8G8R8A8_UNORM && + format == GL_RGB && type == GL_UNSIGNED_BYTE) { + combo = A8R8G8B8_UNORM_TO_RGB_UBYTE; + } + else if (strb->format == PIPE_FORMAT_B8G8R8A8_UNORM && + format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) { + combo = A8R8G8B8_UNORM_TO_BGRA_UINT; + } + else { + return GL_FALSE; + } + + /*printf("st_fast_readpixels combo %d\n", (GLint) combo);*/ + + { + struct pipe_context *pipe = st_context(ctx)->pipe; + struct pipe_transfer *trans; + const GLubyte *map; + GLubyte *dst; + GLint row, col, dy, dstStride; + + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + /* convert GL Y to Gallium Y */ + y = strb->texture->height0 - y - height; + } + + trans = pipe_get_transfer(pipe, strb->texture, + 0, 0, + PIPE_TRANSFER_READ, + x, y, width, height); + if (!trans) { + return GL_FALSE; + } + + map = pipe_transfer_map(pipe, trans); + if (!map) { + pipe->transfer_destroy(pipe, trans); + return GL_FALSE; + } + + /* We always write to the user/dest buffer from low addr to high addr + * but the read order depends on renderbuffer orientation + */ + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + /* read source rows from bottom to top */ + y = height - 1; + dy = -1; + } + else { + /* read source rows from top to bottom */ + y = 0; + dy = 1; + } + + dst = _mesa_image_address2d(pack, dest, width, height, + format, type, 0, 0); + dstStride = _mesa_image_row_stride(pack, width, format, type); + + switch (combo) { + case A8R8G8B8_UNORM_TO_RGBA_UBYTE: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * trans->stride; + for (col = 0; col < width; col++) { + GLuint pixel = ((GLuint *) src)[col]; + dst[col*4+0] = (pixel >> 16) & 0xff; + dst[col*4+1] = (pixel >> 8) & 0xff; + dst[col*4+2] = (pixel >> 0) & 0xff; + dst[col*4+3] = (pixel >> 24) & 0xff; + } + dst += dstStride; + y += dy; + } + break; + case A8R8G8B8_UNORM_TO_RGB_UBYTE: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * trans->stride; + for (col = 0; col < width; col++) { + GLuint pixel = ((GLuint *) src)[col]; + dst[col*3+0] = (pixel >> 16) & 0xff; + dst[col*3+1] = (pixel >> 8) & 0xff; + dst[col*3+2] = (pixel >> 0) & 0xff; + } + dst += dstStride; + y += dy; + } + break; + case A8R8G8B8_UNORM_TO_BGRA_UINT: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * trans->stride; + memcpy(dst, src, 4 * width); + dst += dstStride; + y += dy; + } + break; + default: + ; /* nothing */ + } + + pipe_transfer_unmap(pipe, trans); + pipe->transfer_destroy(pipe, trans); + } + + return GL_TRUE; +} + + +/** + * Do glReadPixels by getting rows from the framebuffer transfer with + * get_tile(). Convert to requested format/type with Mesa image routines. + * Image transfer ops are done in software too. + */ +static void +st_readpixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *dest) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + GLfloat (*temp)[4]; + const GLbitfield transferOps = ctx->_ImageTransferState; + GLsizei i, j; + GLint yStep, dfStride; + GLfloat *df; + struct st_renderbuffer *strb; + struct gl_pixelstore_attrib clippedPacking = *pack; + struct pipe_transfer *trans; + enum pipe_format pformat; + + assert(ctx->ReadBuffer->Width > 0); + + st_validate_state(st); + + /* Do all needed clipping here, so that we can forget about it later */ + if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) { + /* The ReadPixels transfer is totally outside the window bounds */ + return; + } + + st_flush_bitmap_cache(st); + + dest = _mesa_map_pbo_dest(ctx, &clippedPacking, dest); + if (!dest) + return; + + if (format == GL_STENCIL_INDEX || + format == GL_DEPTH_STENCIL) { + st_read_stencil_pixels(ctx, x, y, width, height, + format, type, pack, dest); + return; + } + else if (format == GL_DEPTH_COMPONENT) { + strb = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); + if (strb->Base.Wrapped) { + strb = st_renderbuffer(strb->Base.Wrapped); + } + } + else { + /* Read color buffer */ + strb = st_get_color_read_renderbuffer(ctx); + } + + if (!strb) + return; + + /* try a fast-path readpixels before anything else */ + if (st_fast_readpixels(ctx, strb, x, y, width, height, + format, type, pack, dest)) { + /* success! */ + _mesa_unmap_pbo_dest(ctx, &clippedPacking); + return; + } + + /* allocate temp pixel row buffer */ + temp = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat)); + if (!temp) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); + return; + } + + if (format == GL_RGBA && type == GL_FLOAT) { + /* write tile(row) directly into user's buffer */ + df = (GLfloat *) _mesa_image_address2d(&clippedPacking, dest, width, + height, format, type, 0, 0); + dfStride = width * 4; + } + else { + /* write tile(row) into temp row buffer */ + df = (GLfloat *) temp; + dfStride = 0; + } + + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + /* convert GL Y to Gallium Y */ + y = strb->Base.Height - y - height; + } + + /* Create a read transfer from the renderbuffer's texture */ + trans = pipe_get_transfer(pipe, strb->texture, + 0, 0, + PIPE_TRANSFER_READ, + x, y, width, height); + + /* determine bottom-to-top vs. top-to-bottom order */ + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + y = height - 1; + yStep = -1; + } + else { + y = 0; + yStep = 1; + } + + /* possibly convert sRGB format to linear RGB format */ + pformat = util_format_linear(trans->resource->format); + + if (ST_DEBUG & DEBUG_FALLBACK) + debug_printf("%s: fallback processing\n", __FUNCTION__); + + /* + * Copy pixels from pipe_transfer to user memory + */ + { + /* dest of first pixel in client memory */ + GLubyte *dst = _mesa_image_address2d(&clippedPacking, dest, width, + height, format, type, 0, 0); + /* dest row stride */ + const GLint dstStride = _mesa_image_row_stride(&clippedPacking, width, + format, type); + + if (pformat == PIPE_FORMAT_Z24_UNORM_S8_USCALED || + pformat == PIPE_FORMAT_Z24X8_UNORM) { + if (format == GL_DEPTH_COMPONENT) { + for (i = 0; i < height; i++) { + GLuint ztemp[MAX_WIDTH]; + GLfloat zfloat[MAX_WIDTH]; + const double scale = 1.0 / ((1 << 24) - 1); + pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0); + y += yStep; + for (j = 0; j < width; j++) { + zfloat[j] = (float) (scale * (ztemp[j] & 0xffffff)); + } + _mesa_pack_depth_span(ctx, width, dst, type, + zfloat, &clippedPacking); + dst += dstStride; + } + } + else { + /* XXX: unreachable code -- should be before st_read_stencil_pixels */ + assert(format == GL_DEPTH_STENCIL_EXT); + for (i = 0; i < height; i++) { + GLuint *zshort = (GLuint *)dst; + pipe_get_tile_raw(pipe, trans, 0, y, width, 1, dst, 0); + y += yStep; + /* Reverse into 24/8 */ + for (j = 0; j < width; j++) { + zshort[j] = (zshort[j] << 8) | (zshort[j] >> 24); + } + dst += dstStride; + } + } + } + else if (pformat == PIPE_FORMAT_S8_USCALED_Z24_UNORM || + pformat == PIPE_FORMAT_X8Z24_UNORM) { + if (format == GL_DEPTH_COMPONENT) { + for (i = 0; i < height; i++) { + GLuint ztemp[MAX_WIDTH]; + GLfloat zfloat[MAX_WIDTH]; + const double scale = 1.0 / ((1 << 24) - 1); + pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0); + y += yStep; + for (j = 0; j < width; j++) { + zfloat[j] = (float) (scale * ((ztemp[j] >> 8) & 0xffffff)); + } + _mesa_pack_depth_span(ctx, width, dst, type, + zfloat, &clippedPacking); + dst += dstStride; + } + } + else { + /* XXX: unreachable code -- should be before st_read_stencil_pixels */ + assert(format == GL_DEPTH_STENCIL_EXT); + for (i = 0; i < height; i++) { + pipe_get_tile_raw(pipe, trans, 0, y, width, 1, dst, 0); + y += yStep; + dst += dstStride; + } + } + } + else if (pformat == PIPE_FORMAT_Z16_UNORM) { + for (i = 0; i < height; i++) { + GLushort ztemp[MAX_WIDTH]; + GLfloat zfloat[MAX_WIDTH]; + const double scale = 1.0 / 0xffff; + pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0); + y += yStep; + for (j = 0; j < width; j++) { + zfloat[j] = (float) (scale * ztemp[j]); + } + _mesa_pack_depth_span(ctx, width, dst, type, + zfloat, &clippedPacking); + dst += dstStride; + } + } + else if (pformat == PIPE_FORMAT_Z32_UNORM) { + for (i = 0; i < height; i++) { + GLuint ztemp[MAX_WIDTH]; + GLfloat zfloat[MAX_WIDTH]; + const double scale = 1.0 / 0xffffffff; + pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0); + y += yStep; + for (j = 0; j < width; j++) { + zfloat[j] = (float) (scale * ztemp[j]); + } + _mesa_pack_depth_span(ctx, width, dst, type, + zfloat, &clippedPacking); + dst += dstStride; + } + } + else { + /* RGBA format */ + /* Do a row at a time to flip image data vertically */ + for (i = 0; i < height; i++) { + pipe_get_tile_rgba_format(pipe, trans, 0, y, width, 1, + pformat, df); + y += yStep; + df += dfStride; + if (!dfStride) { + _mesa_pack_rgba_span_float(ctx, width, temp, format, type, dst, + &clippedPacking, transferOps); + dst += dstStride; + } + } + } + } + + free(temp); + + pipe->transfer_destroy(pipe, trans); + + _mesa_unmap_pbo_dest(ctx, &clippedPacking); +} + + +void st_init_readpixels_functions(struct dd_function_table *functions) +{ + functions->ReadPixels = st_readpixels; +} diff --git a/mesalib/src/mesa/state_tracker/st_cb_texture.c b/mesalib/src/mesa/state_tracker/st_cb_texture.c index 08c498b14..c3c4246d1 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_texture.c +++ b/mesalib/src/mesa/state_tracker/st_cb_texture.c @@ -35,6 +35,7 @@ #include "main/macros.h" #include "main/mipmap.h" #include "main/pack.h" +#include "main/pbo.h" #include "main/pixeltransfer.h" #include "main/texcompress.h" #include "main/texfetch.h" diff --git a/mesalib/src/mesa/swrast/s_bitmap.c b/mesalib/src/mesa/swrast/s_bitmap.c index 9b52e9053..18f1c1866 100644 --- a/mesalib/src/mesa/swrast/s_bitmap.c +++ b/mesalib/src/mesa/swrast/s_bitmap.c @@ -1,222 +1,223 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * 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 swrast/s_bitmap.c - * \brief glBitmap rendering. - * \author Brian Paul - */ - -#include "main/glheader.h" -#include "main/bufferobj.h" -#include "main/condrender.h" -#include "main/image.h" -#include "main/macros.h" - -#include "s_context.h" -#include "s_span.h" - - - -/** - * Render a bitmap. - * Called via ctx->Driver.Bitmap() - * All parameter error checking will have been done before this is called. - */ -void -_swrast_Bitmap( struct gl_context *ctx, GLint px, GLint py, - GLsizei width, GLsizei height, - const struct gl_pixelstore_attrib *unpack, - const GLubyte *bitmap ) -{ - GLint row, col; - GLuint count = 0; - SWspan span; - - ASSERT(ctx->RenderMode == GL_RENDER); - - if (!_mesa_check_conditional_render(ctx)) - return; /* don't draw */ - - bitmap = (const GLubyte *) _mesa_map_pbo_source(ctx, unpack, bitmap); - if (!bitmap) - return; - - swrast_render_start(ctx); - - if (SWRAST_CONTEXT(ctx)->NewState) - _swrast_validate_derived( ctx ); - - INIT_SPAN(span, GL_BITMAP); - span.end = width; - span.arrayMask = SPAN_XY; - _swrast_span_default_attribs(ctx, &span); - - for (row = 0; row < height; row++) { - const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack, - bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0); - - if (unpack->LsbFirst) { - /* Lsb first */ - GLubyte mask = 1U << (unpack->SkipPixels & 0x7); - for (col = 0; col < width; col++) { - if (*src & mask) { - span.array->x[count] = px + col; - span.array->y[count] = py + row; - count++; - } - 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) { - span.array->x[count] = px + col; - span.array->y[count] = py + row; - count++; - } - if (mask == 1U) { - src++; - mask = 128U; - } - else { - mask = mask >> 1; - } - } - - /* get ready for next row */ - if (mask != 128) - src++; - } - - if (count + width >= MAX_WIDTH || row + 1 == height) { - /* flush the span */ - span.end = count; - _swrast_write_rgba_span(ctx, &span); - span.end = 0; - count = 0; - } - } - - swrast_render_finish(ctx); - - _mesa_unmap_pbo_source(ctx, unpack); -} - - -#if 0 -/* - * XXX this is another way to implement Bitmap. Use horizontal runs of - * fragments, initializing the mask array to indicate which fragments to - * draw or skip. - */ -void -_swrast_Bitmap( struct gl_context *ctx, GLint px, GLint py, - GLsizei width, GLsizei height, - const struct gl_pixelstore_attrib *unpack, - const GLubyte *bitmap ) -{ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - GLint row, col; - SWspan span; - - ASSERT(ctx->RenderMode == GL_RENDER); - ASSERT(bitmap); - - swrast_render_start(ctx); - - if (SWRAST_CONTEXT(ctx)->NewState) - _swrast_validate_derived( ctx ); - - INIT_SPAN(span, GL_BITMAP); - span.end = width; - span.arrayMask = SPAN_MASK; - _swrast_span_default_attribs(ctx, &span); - - /*span.arrayMask |= SPAN_MASK;*/ /* we'll init span.mask[] */ - span.x = px; - span.y = py; - /*span.end = width;*/ - - for (row=0; rowLsbFirst) { - /* Lsb first */ - GLubyte mask = 1U << (unpack->SkipPixels & 0x7); - for (col=0; colmask[col] = (*src & mask) ? GL_TRUE : GL_FALSE; - if (mask == 128U) { - src++; - mask = 1U; - } - else { - mask = mask << 1; - } - } - - _swrast_write_rgba_span(ctx, &span); - - /* get ready for next row */ - if (mask != 1) - src++; - } - else { - /* Msb first */ - GLubyte mask = 128U >> (unpack->SkipPixels & 0x7); - for (col=0; colmask[col] = (*src & mask) ? GL_TRUE : GL_FALSE; - if (mask == 1U) { - src++; - mask = 128U; - } - else { - mask = mask >> 1; - } - } - - _swrast_write_rgba_span(ctx, &span); - - /* get ready for next row */ - if (mask != 128) - src++; - } - } - - swrast_render_finish(ctx); -} -#endif +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * 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 swrast/s_bitmap.c + * \brief glBitmap rendering. + * \author Brian Paul + */ + +#include "main/glheader.h" +#include "main/bufferobj.h" +#include "main/condrender.h" +#include "main/image.h" +#include "main/macros.h" +#include "main/pbo.h" + +#include "s_context.h" +#include "s_span.h" + + + +/** + * Render a bitmap. + * Called via ctx->Driver.Bitmap() + * All parameter error checking will have been done before this is called. + */ +void +_swrast_Bitmap( struct gl_context *ctx, GLint px, GLint py, + GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap ) +{ + GLint row, col; + GLuint count = 0; + SWspan span; + + ASSERT(ctx->RenderMode == GL_RENDER); + + if (!_mesa_check_conditional_render(ctx)) + return; /* don't draw */ + + bitmap = (const GLubyte *) _mesa_map_pbo_source(ctx, unpack, bitmap); + if (!bitmap) + return; + + swrast_render_start(ctx); + + if (SWRAST_CONTEXT(ctx)->NewState) + _swrast_validate_derived( ctx ); + + INIT_SPAN(span, GL_BITMAP); + span.end = width; + span.arrayMask = SPAN_XY; + _swrast_span_default_attribs(ctx, &span); + + for (row = 0; row < height; row++) { + const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack, + bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0); + + if (unpack->LsbFirst) { + /* Lsb first */ + GLubyte mask = 1U << (unpack->SkipPixels & 0x7); + for (col = 0; col < width; col++) { + if (*src & mask) { + span.array->x[count] = px + col; + span.array->y[count] = py + row; + count++; + } + 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) { + span.array->x[count] = px + col; + span.array->y[count] = py + row; + count++; + } + if (mask == 1U) { + src++; + mask = 128U; + } + else { + mask = mask >> 1; + } + } + + /* get ready for next row */ + if (mask != 128) + src++; + } + + if (count + width >= MAX_WIDTH || row + 1 == height) { + /* flush the span */ + span.end = count; + _swrast_write_rgba_span(ctx, &span); + span.end = 0; + count = 0; + } + } + + swrast_render_finish(ctx); + + _mesa_unmap_pbo_source(ctx, unpack); +} + + +#if 0 +/* + * XXX this is another way to implement Bitmap. Use horizontal runs of + * fragments, initializing the mask array to indicate which fragments to + * draw or skip. + */ +void +_swrast_Bitmap( struct gl_context *ctx, GLint px, GLint py, + GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap ) +{ + SWcontext *swrast = SWRAST_CONTEXT(ctx); + GLint row, col; + SWspan span; + + ASSERT(ctx->RenderMode == GL_RENDER); + ASSERT(bitmap); + + swrast_render_start(ctx); + + if (SWRAST_CONTEXT(ctx)->NewState) + _swrast_validate_derived( ctx ); + + INIT_SPAN(span, GL_BITMAP); + span.end = width; + span.arrayMask = SPAN_MASK; + _swrast_span_default_attribs(ctx, &span); + + /*span.arrayMask |= SPAN_MASK;*/ /* we'll init span.mask[] */ + span.x = px; + span.y = py; + /*span.end = width;*/ + + for (row=0; rowLsbFirst) { + /* Lsb first */ + GLubyte mask = 1U << (unpack->SkipPixels & 0x7); + for (col=0; colmask[col] = (*src & mask) ? GL_TRUE : GL_FALSE; + if (mask == 128U) { + src++; + mask = 1U; + } + else { + mask = mask << 1; + } + } + + _swrast_write_rgba_span(ctx, &span); + + /* get ready for next row */ + if (mask != 1) + src++; + } + else { + /* Msb first */ + GLubyte mask = 128U >> (unpack->SkipPixels & 0x7); + for (col=0; colmask[col] = (*src & mask) ? GL_TRUE : GL_FALSE; + if (mask == 1U) { + src++; + mask = 128U; + } + else { + mask = mask >> 1; + } + } + + _swrast_write_rgba_span(ctx, &span); + + /* get ready for next row */ + if (mask != 128) + src++; + } + } + + swrast_render_finish(ctx); +} +#endif diff --git a/mesalib/src/mesa/swrast/s_drawpix.c b/mesalib/src/mesa/swrast/s_drawpix.c index cca75784a..11c63457f 100644 --- a/mesalib/src/mesa/swrast/s_drawpix.c +++ b/mesalib/src/mesa/swrast/s_drawpix.c @@ -1,752 +1,753 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#include "main/glheader.h" -#include "main/bufferobj.h" -#include "main/condrender.h" -#include "main/context.h" -#include "main/image.h" -#include "main/imports.h" -#include "main/macros.h" -#include "main/pack.h" -#include "main/pixeltransfer.h" -#include "main/state.h" - -#include "s_context.h" -#include "s_span.h" -#include "s_stencil.h" -#include "s_zoom.h" - - - -/** - * Try to do a fast and simple RGB(a) glDrawPixels. - * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead - */ -static GLboolean -fast_draw_rgba_pixels(struct gl_context *ctx, GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - const struct gl_pixelstore_attrib *userUnpack, - const GLvoid *pixels) -{ - const GLint imgX = x, imgY = y; - struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; - GLenum rbType; - SWcontext *swrast = SWRAST_CONTEXT(ctx); - SWspan span; - GLboolean simpleZoom; - GLint yStep; /* +1 or -1 */ - struct gl_pixelstore_attrib unpack; - GLint destX, destY, drawWidth, drawHeight; /* post clipping */ - - if (!rb) - return GL_TRUE; /* no-op */ - - rbType = rb->DataType; - - if ((swrast->_RasterMask & ~CLIP_BIT) || - ctx->Texture._EnabledCoordUnits || - userUnpack->SwapBytes || - ctx->_ImageTransferState) { - /* can't handle any of those conditions */ - return GL_FALSE; - } - - INIT_SPAN(span, GL_BITMAP); - span.arrayMask = SPAN_RGBA; - span.arrayAttribs = FRAG_BIT_COL0; - _swrast_span_default_attribs(ctx, &span); - - /* copy input params since clipping may change them */ - unpack = *userUnpack; - destX = x; - destY = y; - drawWidth = width; - drawHeight = height; - - /* check for simple zooming and clipping */ - if (ctx->Pixel.ZoomX == 1.0F && - (ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F)) { - if (!_mesa_clip_drawpixels(ctx, &destX, &destY, - &drawWidth, &drawHeight, &unpack)) { - /* image was completely clipped: no-op, all done */ - return GL_TRUE; - } - simpleZoom = GL_TRUE; - yStep = (GLint) ctx->Pixel.ZoomY; - ASSERT(yStep == 1 || yStep == -1); - } - else { - /* non-simple zooming */ - simpleZoom = GL_FALSE; - yStep = 1; - if (unpack.RowLength == 0) - unpack.RowLength = width; - } - - /* - * Ready to draw! - */ - - if (format == GL_RGBA && type == rbType) { - const GLubyte *src - = (const GLubyte *) _mesa_image_address2d(&unpack, pixels, width, - height, format, type, 0, 0); - const GLint srcStride = _mesa_image_row_stride(&unpack, width, - format, type); - if (simpleZoom) { - GLint row; - for (row = 0; row < drawHeight; row++) { - rb->PutRow(ctx, rb, drawWidth, destX, destY, src, NULL); - src += srcStride; - destY += yStep; - } - } - else { - /* with zooming */ - GLint row; - for (row = 0; row < drawHeight; row++) { - span.x = destX; - span.y = destY + row; - span.end = drawWidth; - span.array->ChanType = rbType; - _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, src); - src += srcStride; - } - span.array->ChanType = CHAN_TYPE; - } - return GL_TRUE; - } - - if (format == GL_RGB && type == rbType) { - const GLubyte *src - = (const GLubyte *) _mesa_image_address2d(&unpack, pixels, width, - height, format, type, 0, 0); - const GLint srcStride = _mesa_image_row_stride(&unpack, width, - format, type); - if (simpleZoom) { - GLint row; - for (row = 0; row < drawHeight; row++) { - rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, src, NULL); - src += srcStride; - destY += yStep; - } - } - else { - /* with zooming */ - GLint row; - for (row = 0; row < drawHeight; row++) { - span.x = destX; - span.y = destY; - span.end = drawWidth; - span.array->ChanType = rbType; - _swrast_write_zoomed_rgb_span(ctx, imgX, imgY, &span, src); - src += srcStride; - destY++; - } - span.array->ChanType = CHAN_TYPE; - } - return GL_TRUE; - } - - /* Remaining cases haven't been tested with alignment != 1 */ - if (userUnpack->Alignment != 1) - return GL_FALSE; - - if (format == GL_LUMINANCE && type == CHAN_TYPE && rbType == CHAN_TYPE) { - const GLchan *src = (const GLchan *) pixels - + (unpack.SkipRows * unpack.RowLength + unpack.SkipPixels); - if (simpleZoom) { - /* no zooming */ - GLint row; - ASSERT(drawWidth <= MAX_WIDTH); - for (row = 0; row < drawHeight; row++) { - GLchan rgb[MAX_WIDTH][3]; - GLint i; - for (i = 0;iPutRowRGB(ctx, rb, drawWidth, destX, destY, rgb, NULL); - src += unpack.RowLength; - destY += yStep; - } - } - else { - /* with zooming */ - GLint row; - ASSERT(drawWidth <= MAX_WIDTH); - for (row = 0; row < drawHeight; row++) { - GLchan rgb[MAX_WIDTH][3]; - GLint i; - for (i = 0;irgba[i][0] = *ptr; - span.array->rgba[i][1] = *ptr; - span.array->rgba[i][2] = *ptr++; - span.array->rgba[i][3] = *ptr++; - } - rb->PutRow(ctx, rb, drawWidth, destX, destY, - span.array->rgba, NULL); - src += unpack.RowLength*2; - destY += yStep; - } - } - else { - /* with zooming */ - GLint row; - ASSERT(drawWidth <= MAX_WIDTH); - for (row = 0; row < drawHeight; row++) { - const GLchan *ptr = src; - GLint i; - for (i = 0;irgba[i][0] = *ptr; - span.array->rgba[i][1] = *ptr; - span.array->rgba[i][2] = *ptr++; - span.array->rgba[i][3] = *ptr++; - } - span.x = destX; - span.y = destY; - span.end = drawWidth; - _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, - span.array->rgba); - src += unpack.RowLength*2; - destY++; - } - } - return GL_TRUE; - } - - if (format == GL_COLOR_INDEX && type == GL_UNSIGNED_BYTE) { - const GLubyte *src = (const GLubyte *) pixels - + unpack.SkipRows * unpack.RowLength + unpack.SkipPixels; - if (rbType == GL_UNSIGNED_BYTE) { - /* convert ubyte/CI data to ubyte/RGBA */ - if (simpleZoom) { - GLint row; - for (row = 0; row < drawHeight; row++) { - ASSERT(drawWidth <= MAX_WIDTH); - _mesa_map_ci8_to_rgba8(ctx, drawWidth, src, - span.array->rgba8); - rb->PutRow(ctx, rb, drawWidth, destX, destY, - span.array->rgba8, NULL); - src += unpack.RowLength; - destY += yStep; - } - } - else { - /* ubyte/CI to ubyte/RGBA with zooming */ - GLint row; - for (row = 0; row < drawHeight; row++) { - ASSERT(drawWidth <= MAX_WIDTH); - _mesa_map_ci8_to_rgba8(ctx, drawWidth, src, - span.array->rgba8); - span.x = destX; - span.y = destY; - span.end = drawWidth; - _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, - span.array->rgba8); - src += unpack.RowLength; - destY++; - } - } - return GL_TRUE; - } - } - - /* can't handle this pixel format and/or data type */ - return GL_FALSE; -} - - - -/* - * Draw stencil image. - */ -static void -draw_stencil_pixels( struct gl_context *ctx, GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum type, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *pixels ) -{ - const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; - GLint skipPixels; - - /* if width > MAX_WIDTH, have to process image in chunks */ - skipPixels = 0; - while (skipPixels < width) { - const GLint spanX = x + skipPixels; - const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); - GLint row; - for (row = 0; row < height; row++) { - const GLint spanY = y + row; - GLstencil values[MAX_WIDTH]; - GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte)) - ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; - const GLvoid *source = _mesa_image_address2d(unpack, pixels, - width, height, - GL_COLOR_INDEX, type, - row, skipPixels); - _mesa_unpack_stencil_span(ctx, spanWidth, destType, values, - type, source, unpack, - ctx->_ImageTransferState); - if (zoom) { - _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth, - spanX, spanY, values); - } - else { - _swrast_write_stencil_span(ctx, spanWidth, spanX, spanY, values); - } - } - skipPixels += spanWidth; - } -} - - -/* - * Draw depth image. - */ -static void -draw_depth_pixels( struct gl_context *ctx, GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum type, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *pixels ) -{ - const GLboolean scaleOrBias - = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; - const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; - SWspan span; - - INIT_SPAN(span, GL_BITMAP); - span.arrayMask = SPAN_Z; - _swrast_span_default_attribs(ctx, &span); - - if (type == GL_UNSIGNED_SHORT - && ctx->DrawBuffer->Visual.depthBits == 16 - && !scaleOrBias - && !zoom - && width <= MAX_WIDTH - && !unpack->SwapBytes) { - /* Special case: directly write 16-bit depth values */ - GLint row; - for (row = 0; row < height; row++) { - const GLushort *zSrc = (const GLushort *) - _mesa_image_address2d(unpack, pixels, width, height, - GL_DEPTH_COMPONENT, type, row, 0); - GLint i; - for (i = 0; i < width; i++) - span.array->z[i] = zSrc[i]; - span.x = x; - span.y = y + row; - span.end = width; - _swrast_write_rgba_span(ctx, &span); - } - } - else if (type == GL_UNSIGNED_INT - && !scaleOrBias - && !zoom - && width <= MAX_WIDTH - && !unpack->SwapBytes) { - /* Special case: shift 32-bit values down to Visual.depthBits */ - const GLint shift = 32 - ctx->DrawBuffer->Visual.depthBits; - GLint row; - for (row = 0; row < height; row++) { - const GLuint *zSrc = (const GLuint *) - _mesa_image_address2d(unpack, pixels, width, height, - GL_DEPTH_COMPONENT, type, row, 0); - if (shift == 0) { - memcpy(span.array->z, zSrc, width * sizeof(GLuint)); - } - else { - GLint col; - for (col = 0; col < width; col++) - span.array->z[col] = zSrc[col] >> shift; - } - span.x = x; - span.y = y + row; - span.end = width; - _swrast_write_rgba_span(ctx, &span); - } - } - else { - /* General case */ - const GLuint depthMax = ctx->DrawBuffer->_DepthMax; - GLint skipPixels = 0; - - /* in case width > MAX_WIDTH do the copy in chunks */ - while (skipPixels < width) { - const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); - GLint row; - ASSERT(span.end <= MAX_WIDTH); - for (row = 0; row < height; row++) { - const GLvoid *zSrc = _mesa_image_address2d(unpack, - pixels, width, height, - GL_DEPTH_COMPONENT, type, - row, skipPixels); - - /* Set these for each row since the _swrast_write_* function may - * change them while clipping. - */ - span.x = x + skipPixels; - span.y = y + row; - span.end = spanWidth; - - _mesa_unpack_depth_span(ctx, spanWidth, - GL_UNSIGNED_INT, span.array->z, depthMax, - type, zSrc, unpack); - if (zoom) { - _swrast_write_zoomed_depth_span(ctx, x, y, &span); - } - else { - _swrast_write_rgba_span(ctx, &span); - } - } - skipPixels += spanWidth; - } - } -} - - - -/** - * Draw RGBA image. - */ -static void -draw_rgba_pixels( struct gl_context *ctx, GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *pixels ) -{ - const GLint imgX = x, imgY = y; - const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; - GLfloat *convImage = NULL; - GLbitfield transferOps = ctx->_ImageTransferState; - SWspan span; - - /* Try an optimized glDrawPixels first */ - if (fast_draw_rgba_pixels(ctx, x, y, width, height, format, type, - unpack, pixels)) { - return; - } - - INIT_SPAN(span, GL_BITMAP); - _swrast_span_default_attribs(ctx, &span); - span.arrayMask = SPAN_RGBA; - span.arrayAttribs = FRAG_BIT_COL0; /* we're fill in COL0 attrib values */ - - if (ctx->DrawBuffer->_NumColorDrawBuffers > 0 && - ctx->DrawBuffer->_ColorDrawBuffers[0]->DataType != GL_FLOAT && - ctx->Color.ClampFragmentColor != GL_FALSE) { - /* need to clamp colors before applying fragment ops */ - transferOps |= IMAGE_CLAMP_BIT; - } - - /* - * General solution - */ - { - const GLbitfield interpMask = span.interpMask; - const GLbitfield arrayMask = span.arrayMask; - const GLint srcStride - = _mesa_image_row_stride(unpack, width, format, type); - GLint skipPixels = 0; - /* use span array for temp color storage */ - GLfloat *rgba = (GLfloat *) span.array->attribs[FRAG_ATTRIB_COL0]; - - /* if the span is wider than MAX_WIDTH we have to do it in chunks */ - while (skipPixels < width) { - const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); - const GLubyte *source - = (const GLubyte *) _mesa_image_address2d(unpack, pixels, - width, height, format, - type, 0, skipPixels); - GLint row; - - for (row = 0; row < height; row++) { - /* get image row as float/RGBA */ - _mesa_unpack_color_span_float(ctx, spanWidth, GL_RGBA, rgba, - format, type, source, unpack, - transferOps); - /* Set these for each row since the _swrast_write_* functions - * may change them while clipping/rendering. - */ - span.array->ChanType = GL_FLOAT; - span.x = x + skipPixels; - span.y = y + row; - span.end = spanWidth; - span.arrayMask = arrayMask; - span.interpMask = interpMask; - if (zoom) { - _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, rgba); - } - else { - _swrast_write_rgba_span(ctx, &span); - } - - source += srcStride; - } /* for row */ - - skipPixels += spanWidth; - } /* while skipPixels < width */ - - /* XXX this is ugly/temporary, to undo above change */ - span.array->ChanType = CHAN_TYPE; - } - - if (convImage) { - free(convImage); - } -} - - -/** - * This is a bit different from drawing GL_DEPTH_COMPONENT pixels. - * The only per-pixel operations that apply are depth scale/bias, - * stencil offset/shift, GL_DEPTH_WRITEMASK and GL_STENCIL_WRITEMASK, - * and pixel zoom. - * Also, only the depth buffer and stencil buffers are touched, not the - * color buffer(s). - */ -static void -draw_depth_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, - GLsizei width, GLsizei height, GLenum type, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *pixels) -{ - const GLint imgX = x, imgY = y; - const GLboolean scaleOrBias - = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; - const GLuint depthMax = ctx->DrawBuffer->_DepthMax; - const GLuint stencilMask = ctx->Stencil.WriteMask[0]; - const GLuint stencilType = (STENCIL_BITS == 8) ? - GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; - const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; - struct gl_renderbuffer *depthRb, *stencilRb; - struct gl_pixelstore_attrib clippedUnpack = *unpack; - - if (!zoom) { - if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, - &clippedUnpack)) { - /* totally clipped */ - return; - } - } - - depthRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; - stencilRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; - ASSERT(depthRb); - ASSERT(stencilRb); - - if (depthRb->_BaseFormat == GL_DEPTH_STENCIL_EXT && - stencilRb->_BaseFormat == GL_DEPTH_STENCIL_EXT && - depthRb == stencilRb && - !scaleOrBias && - !zoom && - ctx->Depth.Mask && - (stencilMask & 0xff) == 0xff) { - /* This is the ideal case. - * Drawing GL_DEPTH_STENCIL pixels into a combined depth/stencil buffer. - * Plus, no pixel transfer ops, zooming, or masking needed. - */ - GLint i; - for (i = 0; i < height; i++) { - const GLuint *src = (const GLuint *) - _mesa_image_address2d(&clippedUnpack, pixels, width, height, - GL_DEPTH_STENCIL_EXT, type, i, 0); - depthRb->PutRow(ctx, depthRb, width, x, y + i, src, NULL); - } - } - else { - /* sub-optimal cases: - * Separate depth/stencil buffers, or pixel transfer ops required. - */ - /* XXX need to handle very wide images (skippixels) */ - GLint i; - - depthRb = ctx->DrawBuffer->_DepthBuffer; - stencilRb = ctx->DrawBuffer->_StencilBuffer; - - for (i = 0; i < height; i++) { - const GLuint *depthStencilSrc = (const GLuint *) - _mesa_image_address2d(&clippedUnpack, pixels, width, height, - GL_DEPTH_STENCIL_EXT, type, i, 0); - - if (ctx->Depth.Mask) { - if (!scaleOrBias && ctx->DrawBuffer->Visual.depthBits == 24) { - /* fast path 24-bit zbuffer */ - GLuint zValues[MAX_WIDTH]; - GLint j; - ASSERT(depthRb->DataType == GL_UNSIGNED_INT); - for (j = 0; j < width; j++) { - zValues[j] = depthStencilSrc[j] >> 8; - } - if (zoom) - _swrast_write_zoomed_z_span(ctx, imgX, imgY, width, - x, y + i, zValues); - else - depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues,NULL); - } - else if (!scaleOrBias && ctx->DrawBuffer->Visual.depthBits == 16) { - /* fast path 16-bit zbuffer */ - GLushort zValues[MAX_WIDTH]; - GLint j; - ASSERT(depthRb->DataType == GL_UNSIGNED_SHORT); - for (j = 0; j < width; j++) { - zValues[j] = depthStencilSrc[j] >> 16; - } - if (zoom) - _swrast_write_zoomed_z_span(ctx, imgX, imgY, width, - x, y + i, zValues); - else - depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues,NULL); - } - else { - /* general case */ - GLuint zValues[MAX_WIDTH]; /* 16 or 32-bit Z value storage */ - _mesa_unpack_depth_span(ctx, width, - depthRb->DataType, zValues, depthMax, - type, depthStencilSrc, &clippedUnpack); - if (zoom) { - _swrast_write_zoomed_z_span(ctx, imgX, imgY, width, x, - y + i, zValues); - } - else { - depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues,NULL); - } - } - } - - if (stencilMask != 0x0) { - GLstencil stencilValues[MAX_WIDTH]; - /* get stencil values, with shift/offset/mapping */ - _mesa_unpack_stencil_span(ctx, width, stencilType, stencilValues, - type, depthStencilSrc, &clippedUnpack, - ctx->_ImageTransferState); - if (zoom) - _swrast_write_zoomed_stencil_span(ctx, imgX, imgY, width, - x, y + i, stencilValues); - else - _swrast_write_stencil_span(ctx, width, x, y + i, stencilValues); - } - } - } -} - - -/** - * Execute software-based glDrawPixels. - * By time we get here, all error checking will have been done. - */ -void -_swrast_DrawPixels( struct gl_context *ctx, - GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *pixels ) -{ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - GLboolean save_vp_override = ctx->VertexProgram._Overriden; - - if (!_mesa_check_conditional_render(ctx)) - return; /* don't draw */ - - /* We are creating fragments directly, without going through vertex - * programs. - * - * This override flag tells the fragment processing code that its input - * comes from a non-standard source, and it may therefore not rely on - * optimizations that assume e.g. constant color if there is no color - * vertex array. - */ - _mesa_set_vp_override(ctx, GL_TRUE); - - swrast_render_start(ctx); - - if (ctx->NewState) - _mesa_update_state(ctx); - - if (swrast->NewState) - _swrast_validate_derived( ctx ); - - pixels = _mesa_map_pbo_source(ctx, unpack, pixels); - if (!pixels) { - swrast_render_finish(ctx); - _mesa_set_vp_override(ctx, save_vp_override); - return; - } - - /* - * By time we get here, all error checking should have been done. - */ - switch (format) { - case GL_STENCIL_INDEX: - draw_stencil_pixels( ctx, x, y, width, height, type, unpack, pixels ); - break; - case GL_DEPTH_COMPONENT: - draw_depth_pixels( ctx, x, y, width, height, type, unpack, pixels ); - break; - case GL_DEPTH_STENCIL_EXT: - draw_depth_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels); - break; - default: - /* all other formats should be color formats */ - draw_rgba_pixels(ctx, x, y, width, height, format, type, unpack, pixels); - } - - swrast_render_finish(ctx); - _mesa_set_vp_override(ctx, save_vp_override); - - _mesa_unmap_pbo_source(ctx, unpack); -} +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include "main/glheader.h" +#include "main/bufferobj.h" +#include "main/condrender.h" +#include "main/context.h" +#include "main/image.h" +#include "main/imports.h" +#include "main/macros.h" +#include "main/pack.h" +#include "main/pbo.h" +#include "main/pixeltransfer.h" +#include "main/state.h" + +#include "s_context.h" +#include "s_span.h" +#include "s_stencil.h" +#include "s_zoom.h" + + + +/** + * Try to do a fast and simple RGB(a) glDrawPixels. + * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead + */ +static GLboolean +fast_draw_rgba_pixels(struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *userUnpack, + const GLvoid *pixels) +{ + const GLint imgX = x, imgY = y; + struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; + GLenum rbType; + SWcontext *swrast = SWRAST_CONTEXT(ctx); + SWspan span; + GLboolean simpleZoom; + GLint yStep; /* +1 or -1 */ + struct gl_pixelstore_attrib unpack; + GLint destX, destY, drawWidth, drawHeight; /* post clipping */ + + if (!rb) + return GL_TRUE; /* no-op */ + + rbType = rb->DataType; + + if ((swrast->_RasterMask & ~CLIP_BIT) || + ctx->Texture._EnabledCoordUnits || + userUnpack->SwapBytes || + ctx->_ImageTransferState) { + /* can't handle any of those conditions */ + return GL_FALSE; + } + + INIT_SPAN(span, GL_BITMAP); + span.arrayMask = SPAN_RGBA; + span.arrayAttribs = FRAG_BIT_COL0; + _swrast_span_default_attribs(ctx, &span); + + /* copy input params since clipping may change them */ + unpack = *userUnpack; + destX = x; + destY = y; + drawWidth = width; + drawHeight = height; + + /* check for simple zooming and clipping */ + if (ctx->Pixel.ZoomX == 1.0F && + (ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F)) { + if (!_mesa_clip_drawpixels(ctx, &destX, &destY, + &drawWidth, &drawHeight, &unpack)) { + /* image was completely clipped: no-op, all done */ + return GL_TRUE; + } + simpleZoom = GL_TRUE; + yStep = (GLint) ctx->Pixel.ZoomY; + ASSERT(yStep == 1 || yStep == -1); + } + else { + /* non-simple zooming */ + simpleZoom = GL_FALSE; + yStep = 1; + if (unpack.RowLength == 0) + unpack.RowLength = width; + } + + /* + * Ready to draw! + */ + + if (format == GL_RGBA && type == rbType) { + const GLubyte *src + = (const GLubyte *) _mesa_image_address2d(&unpack, pixels, width, + height, format, type, 0, 0); + const GLint srcStride = _mesa_image_row_stride(&unpack, width, + format, type); + if (simpleZoom) { + GLint row; + for (row = 0; row < drawHeight; row++) { + rb->PutRow(ctx, rb, drawWidth, destX, destY, src, NULL); + src += srcStride; + destY += yStep; + } + } + else { + /* with zooming */ + GLint row; + for (row = 0; row < drawHeight; row++) { + span.x = destX; + span.y = destY + row; + span.end = drawWidth; + span.array->ChanType = rbType; + _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, src); + src += srcStride; + } + span.array->ChanType = CHAN_TYPE; + } + return GL_TRUE; + } + + if (format == GL_RGB && type == rbType) { + const GLubyte *src + = (const GLubyte *) _mesa_image_address2d(&unpack, pixels, width, + height, format, type, 0, 0); + const GLint srcStride = _mesa_image_row_stride(&unpack, width, + format, type); + if (simpleZoom) { + GLint row; + for (row = 0; row < drawHeight; row++) { + rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, src, NULL); + src += srcStride; + destY += yStep; + } + } + else { + /* with zooming */ + GLint row; + for (row = 0; row < drawHeight; row++) { + span.x = destX; + span.y = destY; + span.end = drawWidth; + span.array->ChanType = rbType; + _swrast_write_zoomed_rgb_span(ctx, imgX, imgY, &span, src); + src += srcStride; + destY++; + } + span.array->ChanType = CHAN_TYPE; + } + return GL_TRUE; + } + + /* Remaining cases haven't been tested with alignment != 1 */ + if (userUnpack->Alignment != 1) + return GL_FALSE; + + if (format == GL_LUMINANCE && type == CHAN_TYPE && rbType == CHAN_TYPE) { + const GLchan *src = (const GLchan *) pixels + + (unpack.SkipRows * unpack.RowLength + unpack.SkipPixels); + if (simpleZoom) { + /* no zooming */ + GLint row; + ASSERT(drawWidth <= MAX_WIDTH); + for (row = 0; row < drawHeight; row++) { + GLchan rgb[MAX_WIDTH][3]; + GLint i; + for (i = 0;iPutRowRGB(ctx, rb, drawWidth, destX, destY, rgb, NULL); + src += unpack.RowLength; + destY += yStep; + } + } + else { + /* with zooming */ + GLint row; + ASSERT(drawWidth <= MAX_WIDTH); + for (row = 0; row < drawHeight; row++) { + GLchan rgb[MAX_WIDTH][3]; + GLint i; + for (i = 0;irgba[i][0] = *ptr; + span.array->rgba[i][1] = *ptr; + span.array->rgba[i][2] = *ptr++; + span.array->rgba[i][3] = *ptr++; + } + rb->PutRow(ctx, rb, drawWidth, destX, destY, + span.array->rgba, NULL); + src += unpack.RowLength*2; + destY += yStep; + } + } + else { + /* with zooming */ + GLint row; + ASSERT(drawWidth <= MAX_WIDTH); + for (row = 0; row < drawHeight; row++) { + const GLchan *ptr = src; + GLint i; + for (i = 0;irgba[i][0] = *ptr; + span.array->rgba[i][1] = *ptr; + span.array->rgba[i][2] = *ptr++; + span.array->rgba[i][3] = *ptr++; + } + span.x = destX; + span.y = destY; + span.end = drawWidth; + _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, + span.array->rgba); + src += unpack.RowLength*2; + destY++; + } + } + return GL_TRUE; + } + + if (format == GL_COLOR_INDEX && type == GL_UNSIGNED_BYTE) { + const GLubyte *src = (const GLubyte *) pixels + + unpack.SkipRows * unpack.RowLength + unpack.SkipPixels; + if (rbType == GL_UNSIGNED_BYTE) { + /* convert ubyte/CI data to ubyte/RGBA */ + if (simpleZoom) { + GLint row; + for (row = 0; row < drawHeight; row++) { + ASSERT(drawWidth <= MAX_WIDTH); + _mesa_map_ci8_to_rgba8(ctx, drawWidth, src, + span.array->rgba8); + rb->PutRow(ctx, rb, drawWidth, destX, destY, + span.array->rgba8, NULL); + src += unpack.RowLength; + destY += yStep; + } + } + else { + /* ubyte/CI to ubyte/RGBA with zooming */ + GLint row; + for (row = 0; row < drawHeight; row++) { + ASSERT(drawWidth <= MAX_WIDTH); + _mesa_map_ci8_to_rgba8(ctx, drawWidth, src, + span.array->rgba8); + span.x = destX; + span.y = destY; + span.end = drawWidth; + _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, + span.array->rgba8); + src += unpack.RowLength; + destY++; + } + } + return GL_TRUE; + } + } + + /* can't handle this pixel format and/or data type */ + return GL_FALSE; +} + + + +/* + * Draw stencil image. + */ +static void +draw_stencil_pixels( struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels ) +{ + const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; + GLint skipPixels; + + /* if width > MAX_WIDTH, have to process image in chunks */ + skipPixels = 0; + while (skipPixels < width) { + const GLint spanX = x + skipPixels; + const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); + GLint row; + for (row = 0; row < height; row++) { + const GLint spanY = y + row; + GLstencil values[MAX_WIDTH]; + GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte)) + ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; + const GLvoid *source = _mesa_image_address2d(unpack, pixels, + width, height, + GL_COLOR_INDEX, type, + row, skipPixels); + _mesa_unpack_stencil_span(ctx, spanWidth, destType, values, + type, source, unpack, + ctx->_ImageTransferState); + if (zoom) { + _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth, + spanX, spanY, values); + } + else { + _swrast_write_stencil_span(ctx, spanWidth, spanX, spanY, values); + } + } + skipPixels += spanWidth; + } +} + + +/* + * Draw depth image. + */ +static void +draw_depth_pixels( struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels ) +{ + const GLboolean scaleOrBias + = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; + const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; + SWspan span; + + INIT_SPAN(span, GL_BITMAP); + span.arrayMask = SPAN_Z; + _swrast_span_default_attribs(ctx, &span); + + if (type == GL_UNSIGNED_SHORT + && ctx->DrawBuffer->Visual.depthBits == 16 + && !scaleOrBias + && !zoom + && width <= MAX_WIDTH + && !unpack->SwapBytes) { + /* Special case: directly write 16-bit depth values */ + GLint row; + for (row = 0; row < height; row++) { + const GLushort *zSrc = (const GLushort *) + _mesa_image_address2d(unpack, pixels, width, height, + GL_DEPTH_COMPONENT, type, row, 0); + GLint i; + for (i = 0; i < width; i++) + span.array->z[i] = zSrc[i]; + span.x = x; + span.y = y + row; + span.end = width; + _swrast_write_rgba_span(ctx, &span); + } + } + else if (type == GL_UNSIGNED_INT + && !scaleOrBias + && !zoom + && width <= MAX_WIDTH + && !unpack->SwapBytes) { + /* Special case: shift 32-bit values down to Visual.depthBits */ + const GLint shift = 32 - ctx->DrawBuffer->Visual.depthBits; + GLint row; + for (row = 0; row < height; row++) { + const GLuint *zSrc = (const GLuint *) + _mesa_image_address2d(unpack, pixels, width, height, + GL_DEPTH_COMPONENT, type, row, 0); + if (shift == 0) { + memcpy(span.array->z, zSrc, width * sizeof(GLuint)); + } + else { + GLint col; + for (col = 0; col < width; col++) + span.array->z[col] = zSrc[col] >> shift; + } + span.x = x; + span.y = y + row; + span.end = width; + _swrast_write_rgba_span(ctx, &span); + } + } + else { + /* General case */ + const GLuint depthMax = ctx->DrawBuffer->_DepthMax; + GLint skipPixels = 0; + + /* in case width > MAX_WIDTH do the copy in chunks */ + while (skipPixels < width) { + const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); + GLint row; + ASSERT(span.end <= MAX_WIDTH); + for (row = 0; row < height; row++) { + const GLvoid *zSrc = _mesa_image_address2d(unpack, + pixels, width, height, + GL_DEPTH_COMPONENT, type, + row, skipPixels); + + /* Set these for each row since the _swrast_write_* function may + * change them while clipping. + */ + span.x = x + skipPixels; + span.y = y + row; + span.end = spanWidth; + + _mesa_unpack_depth_span(ctx, spanWidth, + GL_UNSIGNED_INT, span.array->z, depthMax, + type, zSrc, unpack); + if (zoom) { + _swrast_write_zoomed_depth_span(ctx, x, y, &span); + } + else { + _swrast_write_rgba_span(ctx, &span); + } + } + skipPixels += spanWidth; + } + } +} + + + +/** + * Draw RGBA image. + */ +static void +draw_rgba_pixels( struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels ) +{ + const GLint imgX = x, imgY = y; + const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; + GLfloat *convImage = NULL; + GLbitfield transferOps = ctx->_ImageTransferState; + SWspan span; + + /* Try an optimized glDrawPixels first */ + if (fast_draw_rgba_pixels(ctx, x, y, width, height, format, type, + unpack, pixels)) { + return; + } + + INIT_SPAN(span, GL_BITMAP); + _swrast_span_default_attribs(ctx, &span); + span.arrayMask = SPAN_RGBA; + span.arrayAttribs = FRAG_BIT_COL0; /* we're fill in COL0 attrib values */ + + if (ctx->DrawBuffer->_NumColorDrawBuffers > 0 && + ctx->DrawBuffer->_ColorDrawBuffers[0]->DataType != GL_FLOAT && + ctx->Color.ClampFragmentColor != GL_FALSE) { + /* need to clamp colors before applying fragment ops */ + transferOps |= IMAGE_CLAMP_BIT; + } + + /* + * General solution + */ + { + const GLbitfield interpMask = span.interpMask; + const GLbitfield arrayMask = span.arrayMask; + const GLint srcStride + = _mesa_image_row_stride(unpack, width, format, type); + GLint skipPixels = 0; + /* use span array for temp color storage */ + GLfloat *rgba = (GLfloat *) span.array->attribs[FRAG_ATTRIB_COL0]; + + /* if the span is wider than MAX_WIDTH we have to do it in chunks */ + while (skipPixels < width) { + const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); + const GLubyte *source + = (const GLubyte *) _mesa_image_address2d(unpack, pixels, + width, height, format, + type, 0, skipPixels); + GLint row; + + for (row = 0; row < height; row++) { + /* get image row as float/RGBA */ + _mesa_unpack_color_span_float(ctx, spanWidth, GL_RGBA, rgba, + format, type, source, unpack, + transferOps); + /* Set these for each row since the _swrast_write_* functions + * may change them while clipping/rendering. + */ + span.array->ChanType = GL_FLOAT; + span.x = x + skipPixels; + span.y = y + row; + span.end = spanWidth; + span.arrayMask = arrayMask; + span.interpMask = interpMask; + if (zoom) { + _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, rgba); + } + else { + _swrast_write_rgba_span(ctx, &span); + } + + source += srcStride; + } /* for row */ + + skipPixels += spanWidth; + } /* while skipPixels < width */ + + /* XXX this is ugly/temporary, to undo above change */ + span.array->ChanType = CHAN_TYPE; + } + + if (convImage) { + free(convImage); + } +} + + +/** + * This is a bit different from drawing GL_DEPTH_COMPONENT pixels. + * The only per-pixel operations that apply are depth scale/bias, + * stencil offset/shift, GL_DEPTH_WRITEMASK and GL_STENCIL_WRITEMASK, + * and pixel zoom. + * Also, only the depth buffer and stencil buffers are touched, not the + * color buffer(s). + */ +static void +draw_depth_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels) +{ + const GLint imgX = x, imgY = y; + const GLboolean scaleOrBias + = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; + const GLuint depthMax = ctx->DrawBuffer->_DepthMax; + const GLuint stencilMask = ctx->Stencil.WriteMask[0]; + const GLuint stencilType = (STENCIL_BITS == 8) ? + GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; + const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; + struct gl_renderbuffer *depthRb, *stencilRb; + struct gl_pixelstore_attrib clippedUnpack = *unpack; + + if (!zoom) { + if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, + &clippedUnpack)) { + /* totally clipped */ + return; + } + } + + depthRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; + stencilRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; + ASSERT(depthRb); + ASSERT(stencilRb); + + if (depthRb->_BaseFormat == GL_DEPTH_STENCIL_EXT && + stencilRb->_BaseFormat == GL_DEPTH_STENCIL_EXT && + depthRb == stencilRb && + !scaleOrBias && + !zoom && + ctx->Depth.Mask && + (stencilMask & 0xff) == 0xff) { + /* This is the ideal case. + * Drawing GL_DEPTH_STENCIL pixels into a combined depth/stencil buffer. + * Plus, no pixel transfer ops, zooming, or masking needed. + */ + GLint i; + for (i = 0; i < height; i++) { + const GLuint *src = (const GLuint *) + _mesa_image_address2d(&clippedUnpack, pixels, width, height, + GL_DEPTH_STENCIL_EXT, type, i, 0); + depthRb->PutRow(ctx, depthRb, width, x, y + i, src, NULL); + } + } + else { + /* sub-optimal cases: + * Separate depth/stencil buffers, or pixel transfer ops required. + */ + /* XXX need to handle very wide images (skippixels) */ + GLint i; + + depthRb = ctx->DrawBuffer->_DepthBuffer; + stencilRb = ctx->DrawBuffer->_StencilBuffer; + + for (i = 0; i < height; i++) { + const GLuint *depthStencilSrc = (const GLuint *) + _mesa_image_address2d(&clippedUnpack, pixels, width, height, + GL_DEPTH_STENCIL_EXT, type, i, 0); + + if (ctx->Depth.Mask) { + if (!scaleOrBias && ctx->DrawBuffer->Visual.depthBits == 24) { + /* fast path 24-bit zbuffer */ + GLuint zValues[MAX_WIDTH]; + GLint j; + ASSERT(depthRb->DataType == GL_UNSIGNED_INT); + for (j = 0; j < width; j++) { + zValues[j] = depthStencilSrc[j] >> 8; + } + if (zoom) + _swrast_write_zoomed_z_span(ctx, imgX, imgY, width, + x, y + i, zValues); + else + depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues,NULL); + } + else if (!scaleOrBias && ctx->DrawBuffer->Visual.depthBits == 16) { + /* fast path 16-bit zbuffer */ + GLushort zValues[MAX_WIDTH]; + GLint j; + ASSERT(depthRb->DataType == GL_UNSIGNED_SHORT); + for (j = 0; j < width; j++) { + zValues[j] = depthStencilSrc[j] >> 16; + } + if (zoom) + _swrast_write_zoomed_z_span(ctx, imgX, imgY, width, + x, y + i, zValues); + else + depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues,NULL); + } + else { + /* general case */ + GLuint zValues[MAX_WIDTH]; /* 16 or 32-bit Z value storage */ + _mesa_unpack_depth_span(ctx, width, + depthRb->DataType, zValues, depthMax, + type, depthStencilSrc, &clippedUnpack); + if (zoom) { + _swrast_write_zoomed_z_span(ctx, imgX, imgY, width, x, + y + i, zValues); + } + else { + depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues,NULL); + } + } + } + + if (stencilMask != 0x0) { + GLstencil stencilValues[MAX_WIDTH]; + /* get stencil values, with shift/offset/mapping */ + _mesa_unpack_stencil_span(ctx, width, stencilType, stencilValues, + type, depthStencilSrc, &clippedUnpack, + ctx->_ImageTransferState); + if (zoom) + _swrast_write_zoomed_stencil_span(ctx, imgX, imgY, width, + x, y + i, stencilValues); + else + _swrast_write_stencil_span(ctx, width, x, y + i, stencilValues); + } + } + } +} + + +/** + * Execute software-based glDrawPixels. + * By time we get here, all error checking will have been done. + */ +void +_swrast_DrawPixels( struct gl_context *ctx, + GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels ) +{ + SWcontext *swrast = SWRAST_CONTEXT(ctx); + GLboolean save_vp_override = ctx->VertexProgram._Overriden; + + if (!_mesa_check_conditional_render(ctx)) + return; /* don't draw */ + + /* We are creating fragments directly, without going through vertex + * programs. + * + * This override flag tells the fragment processing code that its input + * comes from a non-standard source, and it may therefore not rely on + * optimizations that assume e.g. constant color if there is no color + * vertex array. + */ + _mesa_set_vp_override(ctx, GL_TRUE); + + swrast_render_start(ctx); + + if (ctx->NewState) + _mesa_update_state(ctx); + + if (swrast->NewState) + _swrast_validate_derived( ctx ); + + pixels = _mesa_map_pbo_source(ctx, unpack, pixels); + if (!pixels) { + swrast_render_finish(ctx); + _mesa_set_vp_override(ctx, save_vp_override); + return; + } + + /* + * By time we get here, all error checking should have been done. + */ + switch (format) { + case GL_STENCIL_INDEX: + draw_stencil_pixels( ctx, x, y, width, height, type, unpack, pixels ); + break; + case GL_DEPTH_COMPONENT: + draw_depth_pixels( ctx, x, y, width, height, type, unpack, pixels ); + break; + case GL_DEPTH_STENCIL_EXT: + draw_depth_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels); + break; + default: + /* all other formats should be color formats */ + draw_rgba_pixels(ctx, x, y, width, height, format, type, unpack, pixels); + } + + swrast_render_finish(ctx); + _mesa_set_vp_override(ctx, save_vp_override); + + _mesa_unmap_pbo_source(ctx, unpack); +} diff --git a/mesalib/src/mesa/swrast/s_readpix.c b/mesalib/src/mesa/swrast/s_readpix.c index 61399010b..5c8d7e9c5 100644 --- a/mesalib/src/mesa/swrast/s_readpix.c +++ b/mesalib/src/mesa/swrast/s_readpix.c @@ -1,508 +1,508 @@ -/* - * Mesa 3-D graphics library - * Version: 7.0.3 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#include "main/glheader.h" -#include "main/bufferobj.h" -#include "main/colormac.h" -#include "main/feedback.h" -#include "main/formats.h" -#include "main/image.h" -#include "main/imports.h" -#include "main/macros.h" -#include "main/pack.h" -#include "main/state.h" - -#include "s_context.h" -#include "s_depth.h" -#include "s_span.h" -#include "s_stencil.h" - - -/** - * Read pixels for format=GL_DEPTH_COMPONENT. - */ -static void -read_depth_pixels( struct gl_context *ctx, - GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum type, GLvoid *pixels, - const struct gl_pixelstore_attrib *packing ) -{ - struct gl_framebuffer *fb = ctx->ReadBuffer; - struct gl_renderbuffer *rb = fb->_DepthBuffer; - const GLboolean biasOrScale - = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; - - if (!rb) - return; - - /* clipping should have been done already */ - ASSERT(x >= 0); - ASSERT(y >= 0); - ASSERT(x + width <= (GLint) rb->Width); - ASSERT(y + height <= (GLint) rb->Height); - /* width should never be > MAX_WIDTH since we did clipping earlier */ - ASSERT(width <= MAX_WIDTH); - - if (type == GL_UNSIGNED_SHORT && fb->Visual.depthBits == 16 - && !biasOrScale && !packing->SwapBytes) { - /* Special case: directly read 16-bit unsigned depth values. */ - GLint j; - ASSERT(rb->Format == MESA_FORMAT_Z16); - ASSERT(rb->DataType == GL_UNSIGNED_SHORT); - for (j = 0; j < height; j++, y++) { - void *dest =_mesa_image_address2d(packing, pixels, width, height, - GL_DEPTH_COMPONENT, type, j, 0); - rb->GetRow(ctx, rb, width, x, y, dest); - } - } - else if (type == GL_UNSIGNED_INT && fb->Visual.depthBits == 24 - && !biasOrScale && !packing->SwapBytes) { - /* Special case: directly read 24-bit unsigned depth values. */ - GLint j; - ASSERT(rb->Format == MESA_FORMAT_X8_Z24 || - rb->Format == MESA_FORMAT_S8_Z24 || - rb->Format == MESA_FORMAT_Z24_X8 || - rb->Format == MESA_FORMAT_Z24_S8); - ASSERT(rb->DataType == GL_UNSIGNED_INT || - rb->DataType == GL_UNSIGNED_INT_24_8); - for (j = 0; j < height; j++, y++) { - GLuint *dest = (GLuint *) - _mesa_image_address2d(packing, pixels, width, height, - GL_DEPTH_COMPONENT, type, j, 0); - GLint k; - rb->GetRow(ctx, rb, width, x, y, dest); - /* convert range from 24-bit to 32-bit */ - if (rb->Format == MESA_FORMAT_X8_Z24 || - rb->Format == MESA_FORMAT_S8_Z24) { - for (k = 0; k < width; k++) { - /* Note: put MSByte of 24-bit value into LSByte */ - dest[k] = (dest[k] << 8) | ((dest[k] >> 16) & 0xff); - } - } - else { - for (k = 0; k < width; k++) { - /* Note: fill in LSByte by replication */ - dest[k] = dest[k] | ((dest[k] >> 8) & 0xff); - } - } - } - } - else if (type == GL_UNSIGNED_INT && fb->Visual.depthBits == 32 - && !biasOrScale && !packing->SwapBytes) { - /* Special case: directly read 32-bit unsigned depth values. */ - GLint j; - ASSERT(rb->Format == MESA_FORMAT_Z32); - ASSERT(rb->DataType == GL_UNSIGNED_INT); - for (j = 0; j < height; j++, y++) { - void *dest = _mesa_image_address2d(packing, pixels, width, height, - GL_DEPTH_COMPONENT, type, j, 0); - rb->GetRow(ctx, rb, width, x, y, dest); - } - } - else { - /* General case (slower) */ - GLint j; - for (j = 0; j < height; j++, y++) { - GLfloat depthValues[MAX_WIDTH]; - GLvoid *dest = _mesa_image_address2d(packing, pixels, width, height, - GL_DEPTH_COMPONENT, type, j, 0); - _swrast_read_depth_span_float(ctx, rb, width, x, y, depthValues); - _mesa_pack_depth_span(ctx, width, dest, type, depthValues, packing); - } - } -} - - -/** - * Read pixels for format=GL_STENCIL_INDEX. - */ -static void -read_stencil_pixels( struct gl_context *ctx, - GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum type, GLvoid *pixels, - const struct gl_pixelstore_attrib *packing ) -{ - struct gl_framebuffer *fb = ctx->ReadBuffer; - struct gl_renderbuffer *rb = fb->_StencilBuffer; - GLint j; - - if (!rb) - return; - - /* width should never be > MAX_WIDTH since we did clipping earlier */ - ASSERT(width <= MAX_WIDTH); - - /* process image row by row */ - for (j=0;jReadBuffer->_ColorReadBuffer; - - if (!rb) - return GL_FALSE; - - ASSERT(rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB || - rb->_BaseFormat == GL_ALPHA); - - /* clipping should have already been done */ - ASSERT(x + width <= (GLint) rb->Width); - ASSERT(y + height <= (GLint) rb->Height); - - /* check for things we can't handle here */ - if (transferOps || - packing->SwapBytes || - packing->LsbFirst) { - return GL_FALSE; - } - - if (format == GL_RGBA && rb->DataType == type) { - const GLint dstStride = _mesa_image_row_stride(packing, width, - format, type); - GLubyte *dest - = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, - format, type, 0, 0); - GLint row; - ASSERT(rb->GetRow); - for (row = 0; row < height; row++) { - rb->GetRow(ctx, rb, width, x, y + row, dest); - dest += dstStride; - } - return GL_TRUE; - } - - if (format == GL_RGB && - rb->DataType == GL_UNSIGNED_BYTE && - type == GL_UNSIGNED_BYTE) { - const GLint dstStride = _mesa_image_row_stride(packing, width, - format, type); - GLubyte *dest - = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, - format, type, 0, 0); - GLint row; - ASSERT(rb->GetRow); - for (row = 0; row < height; row++) { - GLubyte tempRow[MAX_WIDTH][4]; - GLint col; - rb->GetRow(ctx, rb, width, x, y + row, tempRow); - /* convert RGBA to RGB */ - for (col = 0; col < width; col++) { - dest[col * 3 + 0] = tempRow[col][0]; - dest[col * 3 + 1] = tempRow[col][1]; - dest[col * 3 + 2] = tempRow[col][2]; - } - dest += dstStride; - } - return GL_TRUE; - } - - /* not handled */ - return GL_FALSE; -} - - -/** - * When we're using a low-precision color buffer (like 16-bit 5/6/5) - * we have to adjust our color values a bit to pass conformance. - * The problem is when a 5 or 6-bit color value is converted to an 8-bit - * value and then a floating point value, the floating point values don't - * increment uniformly as the 5 or 6-bit value is incremented. - * - * This function adjusts floating point values to compensate. - */ -static void -adjust_colors(const struct gl_framebuffer *fb, GLuint n, GLfloat rgba[][4]) -{ - const GLuint rShift = 8 - fb->Visual.redBits; - const GLuint gShift = 8 - fb->Visual.greenBits; - const GLuint bShift = 8 - fb->Visual.blueBits; - GLfloat rScale = 1.0F / (GLfloat) ((1 << fb->Visual.redBits ) - 1); - GLfloat gScale = 1.0F / (GLfloat) ((1 << fb->Visual.greenBits) - 1); - GLfloat bScale = 1.0F / (GLfloat) ((1 << fb->Visual.blueBits ) - 1); - GLuint i; - - if (fb->Visual.redBits == 0) - rScale = 0; - if (fb->Visual.greenBits == 0) - gScale = 0; - if (fb->Visual.blueBits == 0) - bScale = 0; - - for (i = 0; i < n; i++) { - GLint r, g, b; - /* convert float back to ubyte */ - CLAMPED_FLOAT_TO_UBYTE(r, rgba[i][RCOMP]); - CLAMPED_FLOAT_TO_UBYTE(g, rgba[i][GCOMP]); - CLAMPED_FLOAT_TO_UBYTE(b, rgba[i][BCOMP]); - /* using only the N most significant bits of the ubyte value, convert to - * float in [0,1]. - */ - rgba[i][RCOMP] = (GLfloat) (r >> rShift) * rScale; - rgba[i][GCOMP] = (GLfloat) (g >> gShift) * gScale; - rgba[i][BCOMP] = (GLfloat) (b >> bShift) * bScale; - } -} - - - -/* - * Read R, G, B, A, RGB, L, or LA pixels. - */ -static void -read_rgba_pixels( struct gl_context *ctx, - GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum format, GLenum type, GLvoid *pixels, - const struct gl_pixelstore_attrib *packing ) -{ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - GLbitfield transferOps = ctx->_ImageTransferState; - struct gl_framebuffer *fb = ctx->ReadBuffer; - struct gl_renderbuffer *rb = fb->_ColorReadBuffer; - - if (!rb) - return; - - if (type == GL_FLOAT && ((ctx->Color.ClampReadColor == GL_TRUE) || - (ctx->Color.ClampReadColor == GL_FIXED_ONLY_ARB && - rb->DataType != GL_FLOAT))) - transferOps |= IMAGE_CLAMP_BIT; - - /* Try optimized path first */ - if (fast_read_rgba_pixels(ctx, x, y, width, height, - format, type, pixels, packing, transferOps)) { - return; /* done! */ - } - - /* width should never be > MAX_WIDTH since we did clipping earlier */ - ASSERT(width <= MAX_WIDTH); - - do { - const GLint dstStride - = _mesa_image_row_stride(packing, width, format, type); - GLfloat (*rgba)[4] = swrast->SpanArrays->attribs[FRAG_ATTRIB_COL0]; - GLint row; - GLubyte *dst - = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, - format, type, 0, 0); - - for (row = 0; row < height; row++, y++) { - - /* Get float rgba pixels */ - _swrast_read_rgba_span(ctx, rb, width, x, y, GL_FLOAT, rgba); - - /* apply fudge factor for shallow color buffers */ - if (fb->Visual.redBits < 8 || - fb->Visual.greenBits < 8 || - fb->Visual.blueBits < 8) { - adjust_colors(fb, width, rgba); - } - - /* pack the row of RGBA pixels into user's buffer */ - _mesa_pack_rgba_span_float(ctx, width, rgba, format, type, dst, - packing, transferOps); - - dst += dstStride; - } - } while (0); -} - - -/** - * Read combined depth/stencil values. - * We'll have already done error checking to be sure the expected - * depth and stencil buffers really exist. - */ -static void -read_depth_stencil_pixels(struct gl_context *ctx, - GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum type, GLvoid *pixels, - const struct gl_pixelstore_attrib *packing ) -{ - const GLboolean scaleOrBias - = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; - const GLboolean stencilTransfer = ctx->Pixel.IndexShift - || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag; - struct gl_renderbuffer *depthRb, *stencilRb; - - depthRb = ctx->ReadBuffer->_DepthBuffer; - stencilRb = ctx->ReadBuffer->_StencilBuffer; - - if (!depthRb || !stencilRb) - return; - - depthRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; - stencilRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; - - if (depthRb->_BaseFormat == GL_DEPTH_STENCIL_EXT && - stencilRb->_BaseFormat == GL_DEPTH_STENCIL_EXT && - depthRb == stencilRb && - !scaleOrBias && - !stencilTransfer) { - /* This is the ideal case. - * Reading GL_DEPTH_STENCIL pixels from combined depth/stencil buffer. - * Plus, no pixel transfer ops to worry about! - */ - GLint i; - GLint dstStride = _mesa_image_row_stride(packing, width, - GL_DEPTH_STENCIL_EXT, type); - GLubyte *dst = (GLubyte *) _mesa_image_address2d(packing, pixels, - width, height, - GL_DEPTH_STENCIL_EXT, - type, 0, 0); - for (i = 0; i < height; i++) { - depthRb->GetRow(ctx, depthRb, width, x, y + i, dst); - dst += dstStride; - } - } - else { - /* Reading GL_DEPTH_STENCIL pixels from separate depth/stencil buffers, - * or we need pixel transfer. - */ - GLint i; - depthRb = ctx->ReadBuffer->_DepthBuffer; - stencilRb = ctx->ReadBuffer->_StencilBuffer; - - for (i = 0; i < height; i++) { - GLstencil stencilVals[MAX_WIDTH]; - - GLuint *depthStencilDst = (GLuint *) - _mesa_image_address2d(packing, pixels, width, height, - GL_DEPTH_STENCIL_EXT, type, i, 0); - - _swrast_read_stencil_span(ctx, stencilRb, width, - x, y + i, stencilVals); - - if (!scaleOrBias && !stencilTransfer - && ctx->ReadBuffer->Visual.depthBits == 24) { - /* ideal case */ - GLuint zVals[MAX_WIDTH]; /* 24-bit values! */ - GLint j; - ASSERT(depthRb->DataType == GL_UNSIGNED_INT); - /* note, we've already been clipped */ - depthRb->GetRow(ctx, depthRb, width, x, y + i, zVals); - for (j = 0; j < width; j++) { - depthStencilDst[j] = (zVals[j] << 8) | (stencilVals[j] & 0xff); - } - } - else { - /* general case */ - GLfloat depthVals[MAX_WIDTH]; - _swrast_read_depth_span_float(ctx, depthRb, width, x, y + i, - depthVals); - _mesa_pack_depth_stencil_span(ctx, width, depthStencilDst, - depthVals, stencilVals, packing); - } - } - } -} - - - -/** - * Software fallback routine for ctx->Driver.ReadPixels(). - * By time we get here, all error checking will have been done. - */ -void -_swrast_ReadPixels( struct gl_context *ctx, - GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, - const struct gl_pixelstore_attrib *packing, - GLvoid *pixels ) -{ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - struct gl_pixelstore_attrib clippedPacking = *packing; - - if (ctx->NewState) - _mesa_update_state(ctx); - - /* Need to do swrast_render_start() before clipping or anything else - * since this is where a driver may grab the hw lock and get an updated - * window size. - */ - swrast_render_start(ctx); - - if (swrast->NewState) - _swrast_validate_derived( ctx ); - - /* Do all needed clipping here, so that we can forget about it later */ - if (_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) { - - pixels = _mesa_map_pbo_dest(ctx, &clippedPacking, pixels); - - if (pixels) { - switch (format) { - case GL_STENCIL_INDEX: - read_stencil_pixels(ctx, x, y, width, height, type, pixels, - &clippedPacking); - break; - case GL_DEPTH_COMPONENT: - read_depth_pixels(ctx, x, y, width, height, type, pixels, - &clippedPacking); - break; - case GL_DEPTH_STENCIL_EXT: - read_depth_stencil_pixels(ctx, x, y, width, height, type, pixels, - &clippedPacking); - break; - default: - /* all other formats should be color formats */ - read_rgba_pixels(ctx, x, y, width, height, format, type, pixels, - &clippedPacking); - } - - _mesa_unmap_pbo_dest(ctx, &clippedPacking); - } - } - - swrast_render_finish(ctx); -} +/* + * Mesa 3-D graphics library + * Version: 7.0.3 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include "main/glheader.h" +#include "main/colormac.h" +#include "main/feedback.h" +#include "main/formats.h" +#include "main/image.h" +#include "main/imports.h" +#include "main/macros.h" +#include "main/pack.h" +#include "main/pbo.h" +#include "main/state.h" + +#include "s_context.h" +#include "s_depth.h" +#include "s_span.h" +#include "s_stencil.h" + + +/** + * Read pixels for format=GL_DEPTH_COMPONENT. + */ +static void +read_depth_pixels( struct gl_context *ctx, + GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum type, GLvoid *pixels, + const struct gl_pixelstore_attrib *packing ) +{ + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct gl_renderbuffer *rb = fb->_DepthBuffer; + const GLboolean biasOrScale + = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; + + if (!rb) + return; + + /* clipping should have been done already */ + ASSERT(x >= 0); + ASSERT(y >= 0); + ASSERT(x + width <= (GLint) rb->Width); + ASSERT(y + height <= (GLint) rb->Height); + /* width should never be > MAX_WIDTH since we did clipping earlier */ + ASSERT(width <= MAX_WIDTH); + + if (type == GL_UNSIGNED_SHORT && fb->Visual.depthBits == 16 + && !biasOrScale && !packing->SwapBytes) { + /* Special case: directly read 16-bit unsigned depth values. */ + GLint j; + ASSERT(rb->Format == MESA_FORMAT_Z16); + ASSERT(rb->DataType == GL_UNSIGNED_SHORT); + for (j = 0; j < height; j++, y++) { + void *dest =_mesa_image_address2d(packing, pixels, width, height, + GL_DEPTH_COMPONENT, type, j, 0); + rb->GetRow(ctx, rb, width, x, y, dest); + } + } + else if (type == GL_UNSIGNED_INT && fb->Visual.depthBits == 24 + && !biasOrScale && !packing->SwapBytes) { + /* Special case: directly read 24-bit unsigned depth values. */ + GLint j; + ASSERT(rb->Format == MESA_FORMAT_X8_Z24 || + rb->Format == MESA_FORMAT_S8_Z24 || + rb->Format == MESA_FORMAT_Z24_X8 || + rb->Format == MESA_FORMAT_Z24_S8); + ASSERT(rb->DataType == GL_UNSIGNED_INT || + rb->DataType == GL_UNSIGNED_INT_24_8); + for (j = 0; j < height; j++, y++) { + GLuint *dest = (GLuint *) + _mesa_image_address2d(packing, pixels, width, height, + GL_DEPTH_COMPONENT, type, j, 0); + GLint k; + rb->GetRow(ctx, rb, width, x, y, dest); + /* convert range from 24-bit to 32-bit */ + if (rb->Format == MESA_FORMAT_X8_Z24 || + rb->Format == MESA_FORMAT_S8_Z24) { + for (k = 0; k < width; k++) { + /* Note: put MSByte of 24-bit value into LSByte */ + dest[k] = (dest[k] << 8) | ((dest[k] >> 16) & 0xff); + } + } + else { + for (k = 0; k < width; k++) { + /* Note: fill in LSByte by replication */ + dest[k] = dest[k] | ((dest[k] >> 8) & 0xff); + } + } + } + } + else if (type == GL_UNSIGNED_INT && fb->Visual.depthBits == 32 + && !biasOrScale && !packing->SwapBytes) { + /* Special case: directly read 32-bit unsigned depth values. */ + GLint j; + ASSERT(rb->Format == MESA_FORMAT_Z32); + ASSERT(rb->DataType == GL_UNSIGNED_INT); + for (j = 0; j < height; j++, y++) { + void *dest = _mesa_image_address2d(packing, pixels, width, height, + GL_DEPTH_COMPONENT, type, j, 0); + rb->GetRow(ctx, rb, width, x, y, dest); + } + } + else { + /* General case (slower) */ + GLint j; + for (j = 0; j < height; j++, y++) { + GLfloat depthValues[MAX_WIDTH]; + GLvoid *dest = _mesa_image_address2d(packing, pixels, width, height, + GL_DEPTH_COMPONENT, type, j, 0); + _swrast_read_depth_span_float(ctx, rb, width, x, y, depthValues); + _mesa_pack_depth_span(ctx, width, dest, type, depthValues, packing); + } + } +} + + +/** + * Read pixels for format=GL_STENCIL_INDEX. + */ +static void +read_stencil_pixels( struct gl_context *ctx, + GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum type, GLvoid *pixels, + const struct gl_pixelstore_attrib *packing ) +{ + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct gl_renderbuffer *rb = fb->_StencilBuffer; + GLint j; + + if (!rb) + return; + + /* width should never be > MAX_WIDTH since we did clipping earlier */ + ASSERT(width <= MAX_WIDTH); + + /* process image row by row */ + for (j=0;jReadBuffer->_ColorReadBuffer; + + if (!rb) + return GL_FALSE; + + ASSERT(rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB || + rb->_BaseFormat == GL_ALPHA); + + /* clipping should have already been done */ + ASSERT(x + width <= (GLint) rb->Width); + ASSERT(y + height <= (GLint) rb->Height); + + /* check for things we can't handle here */ + if (transferOps || + packing->SwapBytes || + packing->LsbFirst) { + return GL_FALSE; + } + + if (format == GL_RGBA && rb->DataType == type) { + const GLint dstStride = _mesa_image_row_stride(packing, width, + format, type); + GLubyte *dest + = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, + format, type, 0, 0); + GLint row; + ASSERT(rb->GetRow); + for (row = 0; row < height; row++) { + rb->GetRow(ctx, rb, width, x, y + row, dest); + dest += dstStride; + } + return GL_TRUE; + } + + if (format == GL_RGB && + rb->DataType == GL_UNSIGNED_BYTE && + type == GL_UNSIGNED_BYTE) { + const GLint dstStride = _mesa_image_row_stride(packing, width, + format, type); + GLubyte *dest + = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, + format, type, 0, 0); + GLint row; + ASSERT(rb->GetRow); + for (row = 0; row < height; row++) { + GLubyte tempRow[MAX_WIDTH][4]; + GLint col; + rb->GetRow(ctx, rb, width, x, y + row, tempRow); + /* convert RGBA to RGB */ + for (col = 0; col < width; col++) { + dest[col * 3 + 0] = tempRow[col][0]; + dest[col * 3 + 1] = tempRow[col][1]; + dest[col * 3 + 2] = tempRow[col][2]; + } + dest += dstStride; + } + return GL_TRUE; + } + + /* not handled */ + return GL_FALSE; +} + + +/** + * When we're using a low-precision color buffer (like 16-bit 5/6/5) + * we have to adjust our color values a bit to pass conformance. + * The problem is when a 5 or 6-bit color value is converted to an 8-bit + * value and then a floating point value, the floating point values don't + * increment uniformly as the 5 or 6-bit value is incremented. + * + * This function adjusts floating point values to compensate. + */ +static void +adjust_colors(const struct gl_framebuffer *fb, GLuint n, GLfloat rgba[][4]) +{ + const GLuint rShift = 8 - fb->Visual.redBits; + const GLuint gShift = 8 - fb->Visual.greenBits; + const GLuint bShift = 8 - fb->Visual.blueBits; + GLfloat rScale = 1.0F / (GLfloat) ((1 << fb->Visual.redBits ) - 1); + GLfloat gScale = 1.0F / (GLfloat) ((1 << fb->Visual.greenBits) - 1); + GLfloat bScale = 1.0F / (GLfloat) ((1 << fb->Visual.blueBits ) - 1); + GLuint i; + + if (fb->Visual.redBits == 0) + rScale = 0; + if (fb->Visual.greenBits == 0) + gScale = 0; + if (fb->Visual.blueBits == 0) + bScale = 0; + + for (i = 0; i < n; i++) { + GLint r, g, b; + /* convert float back to ubyte */ + CLAMPED_FLOAT_TO_UBYTE(r, rgba[i][RCOMP]); + CLAMPED_FLOAT_TO_UBYTE(g, rgba[i][GCOMP]); + CLAMPED_FLOAT_TO_UBYTE(b, rgba[i][BCOMP]); + /* using only the N most significant bits of the ubyte value, convert to + * float in [0,1]. + */ + rgba[i][RCOMP] = (GLfloat) (r >> rShift) * rScale; + rgba[i][GCOMP] = (GLfloat) (g >> gShift) * gScale; + rgba[i][BCOMP] = (GLfloat) (b >> bShift) * bScale; + } +} + + + +/* + * Read R, G, B, A, RGB, L, or LA pixels. + */ +static void +read_rgba_pixels( struct gl_context *ctx, + GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_pixelstore_attrib *packing ) +{ + SWcontext *swrast = SWRAST_CONTEXT(ctx); + GLbitfield transferOps = ctx->_ImageTransferState; + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct gl_renderbuffer *rb = fb->_ColorReadBuffer; + + if (!rb) + return; + + if (type == GL_FLOAT && ((ctx->Color.ClampReadColor == GL_TRUE) || + (ctx->Color.ClampReadColor == GL_FIXED_ONLY_ARB && + rb->DataType != GL_FLOAT))) + transferOps |= IMAGE_CLAMP_BIT; + + /* Try optimized path first */ + if (fast_read_rgba_pixels(ctx, x, y, width, height, + format, type, pixels, packing, transferOps)) { + return; /* done! */ + } + + /* width should never be > MAX_WIDTH since we did clipping earlier */ + ASSERT(width <= MAX_WIDTH); + + do { + const GLint dstStride + = _mesa_image_row_stride(packing, width, format, type); + GLfloat (*rgba)[4] = swrast->SpanArrays->attribs[FRAG_ATTRIB_COL0]; + GLint row; + GLubyte *dst + = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, + format, type, 0, 0); + + for (row = 0; row < height; row++, y++) { + + /* Get float rgba pixels */ + _swrast_read_rgba_span(ctx, rb, width, x, y, GL_FLOAT, rgba); + + /* apply fudge factor for shallow color buffers */ + if (fb->Visual.redBits < 8 || + fb->Visual.greenBits < 8 || + fb->Visual.blueBits < 8) { + adjust_colors(fb, width, rgba); + } + + /* pack the row of RGBA pixels into user's buffer */ + _mesa_pack_rgba_span_float(ctx, width, rgba, format, type, dst, + packing, transferOps); + + dst += dstStride; + } + } while (0); +} + + +/** + * Read combined depth/stencil values. + * We'll have already done error checking to be sure the expected + * depth and stencil buffers really exist. + */ +static void +read_depth_stencil_pixels(struct gl_context *ctx, + GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum type, GLvoid *pixels, + const struct gl_pixelstore_attrib *packing ) +{ + const GLboolean scaleOrBias + = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; + const GLboolean stencilTransfer = ctx->Pixel.IndexShift + || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag; + struct gl_renderbuffer *depthRb, *stencilRb; + + depthRb = ctx->ReadBuffer->_DepthBuffer; + stencilRb = ctx->ReadBuffer->_StencilBuffer; + + if (!depthRb || !stencilRb) + return; + + depthRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; + stencilRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; + + if (depthRb->_BaseFormat == GL_DEPTH_STENCIL_EXT && + stencilRb->_BaseFormat == GL_DEPTH_STENCIL_EXT && + depthRb == stencilRb && + !scaleOrBias && + !stencilTransfer) { + /* This is the ideal case. + * Reading GL_DEPTH_STENCIL pixels from combined depth/stencil buffer. + * Plus, no pixel transfer ops to worry about! + */ + GLint i; + GLint dstStride = _mesa_image_row_stride(packing, width, + GL_DEPTH_STENCIL_EXT, type); + GLubyte *dst = (GLubyte *) _mesa_image_address2d(packing, pixels, + width, height, + GL_DEPTH_STENCIL_EXT, + type, 0, 0); + for (i = 0; i < height; i++) { + depthRb->GetRow(ctx, depthRb, width, x, y + i, dst); + dst += dstStride; + } + } + else { + /* Reading GL_DEPTH_STENCIL pixels from separate depth/stencil buffers, + * or we need pixel transfer. + */ + GLint i; + depthRb = ctx->ReadBuffer->_DepthBuffer; + stencilRb = ctx->ReadBuffer->_StencilBuffer; + + for (i = 0; i < height; i++) { + GLstencil stencilVals[MAX_WIDTH]; + + GLuint *depthStencilDst = (GLuint *) + _mesa_image_address2d(packing, pixels, width, height, + GL_DEPTH_STENCIL_EXT, type, i, 0); + + _swrast_read_stencil_span(ctx, stencilRb, width, + x, y + i, stencilVals); + + if (!scaleOrBias && !stencilTransfer + && ctx->ReadBuffer->Visual.depthBits == 24) { + /* ideal case */ + GLuint zVals[MAX_WIDTH]; /* 24-bit values! */ + GLint j; + ASSERT(depthRb->DataType == GL_UNSIGNED_INT); + /* note, we've already been clipped */ + depthRb->GetRow(ctx, depthRb, width, x, y + i, zVals); + for (j = 0; j < width; j++) { + depthStencilDst[j] = (zVals[j] << 8) | (stencilVals[j] & 0xff); + } + } + else { + /* general case */ + GLfloat depthVals[MAX_WIDTH]; + _swrast_read_depth_span_float(ctx, depthRb, width, x, y + i, + depthVals); + _mesa_pack_depth_stencil_span(ctx, width, depthStencilDst, + depthVals, stencilVals, packing); + } + } + } +} + + + +/** + * Software fallback routine for ctx->Driver.ReadPixels(). + * By time we get here, all error checking will have been done. + */ +void +_swrast_ReadPixels( struct gl_context *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *packing, + GLvoid *pixels ) +{ + SWcontext *swrast = SWRAST_CONTEXT(ctx); + struct gl_pixelstore_attrib clippedPacking = *packing; + + if (ctx->NewState) + _mesa_update_state(ctx); + + /* Need to do swrast_render_start() before clipping or anything else + * since this is where a driver may grab the hw lock and get an updated + * window size. + */ + swrast_render_start(ctx); + + if (swrast->NewState) + _swrast_validate_derived( ctx ); + + /* Do all needed clipping here, so that we can forget about it later */ + if (_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) { + + pixels = _mesa_map_pbo_dest(ctx, &clippedPacking, pixels); + + if (pixels) { + switch (format) { + case GL_STENCIL_INDEX: + read_stencil_pixels(ctx, x, y, width, height, type, pixels, + &clippedPacking); + break; + case GL_DEPTH_COMPONENT: + read_depth_pixels(ctx, x, y, width, height, type, pixels, + &clippedPacking); + break; + case GL_DEPTH_STENCIL_EXT: + read_depth_stencil_pixels(ctx, x, y, width, height, type, pixels, + &clippedPacking); + break; + default: + /* all other formats should be color formats */ + read_rgba_pixels(ctx, x, y, width, height, format, type, pixels, + &clippedPacking); + } + + _mesa_unmap_pbo_dest(ctx, &clippedPacking); + } + } + + swrast_render_finish(ctx); +} diff --git a/mesalib/src/mesa/swrast/s_texcombine.c b/mesalib/src/mesa/swrast/s_texcombine.c index 672cd77bf..0c8cc9ff3 100644 --- a/mesalib/src/mesa/swrast/s_texcombine.c +++ b/mesalib/src/mesa/swrast/s_texcombine.c @@ -1,742 +1,737 @@ -/* - * 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. - */ - - -#include "main/glheader.h" -#include "main/context.h" -#include "main/colormac.h" -#include "main/imports.h" -#include "main/pixeltransfer.h" -#include "program/prog_instruction.h" - -#include "s_context.h" -#include "s_texcombine.h" - - -/** - * Pointer to array of float[4] - * This type makes the code below more concise and avoids a lot of casting. - */ -typedef float (*float4_array)[4]; - - -/** - * Return array of texels for given unit. - */ -static INLINE float4_array -get_texel_array(SWcontext *swrast, GLuint unit) -{ - return (float4_array) (swrast->TexelBuffer + unit * MAX_WIDTH * 4); -} - - - -/** - * Do texture application for: - * GL_EXT_texture_env_combine - * GL_ARB_texture_env_combine - * GL_EXT_texture_env_dot3 - * GL_ARB_texture_env_dot3 - * GL_ATI_texture_env_combine3 - * GL_NV_texture_env_combine4 - * conventional GL texture env modes - * - * \param ctx rendering context - * \param unit the texture combiner unit - * \param n number of fragments to process (span width) - * \param primary_rgba incoming fragment color array - * \param texelBuffer pointer to texel colors for all texture units - * - * \param rgba incoming/result fragment colors - */ -static void -texture_combine( struct gl_context *ctx, GLuint unit, GLuint n, - const float4_array primary_rgba, - const GLfloat *texelBuffer, - GLchan (*rgbaChan)[4] ) -{ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - const struct gl_texture_unit *textureUnit = &(ctx->Texture.Unit[unit]); - const struct gl_tex_env_combine_state *combine = textureUnit->_CurrentCombine; - float4_array argRGB[MAX_COMBINER_TERMS]; - float4_array argA[MAX_COMBINER_TERMS]; - const GLfloat scaleRGB = (GLfloat) (1 << combine->ScaleShiftRGB); - const GLfloat scaleA = (GLfloat) (1 << combine->ScaleShiftA); - const GLuint numArgsRGB = combine->_NumArgsRGB; - const GLuint numArgsA = combine->_NumArgsA; - float4_array ccolor[4], rgba; - GLuint i, term; - - /* alloc temp pixel buffers */ - rgba = (float4_array) malloc(4 * n * sizeof(GLfloat)); - if (!rgba) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine"); - return; - } - - for (i = 0; i < numArgsRGB || i < numArgsA; i++) { - ccolor[i] = (float4_array) malloc(4 * n * sizeof(GLfloat)); - if (!ccolor[i]) { - while (i) { - free(ccolor[i]); - i--; - } - _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine"); - return; - } - } - - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = CHAN_TO_FLOAT(rgbaChan[i][RCOMP]); - rgba[i][GCOMP] = CHAN_TO_FLOAT(rgbaChan[i][GCOMP]); - rgba[i][BCOMP] = CHAN_TO_FLOAT(rgbaChan[i][BCOMP]); - rgba[i][ACOMP] = CHAN_TO_FLOAT(rgbaChan[i][ACOMP]); - } - - /* - printf("modeRGB 0x%x modeA 0x%x srcRGB1 0x%x srcA1 0x%x srcRGB2 0x%x srcA2 0x%x\n", - combine->ModeRGB, - combine->ModeA, - combine->SourceRGB[0], - combine->SourceA[0], - combine->SourceRGB[1], - combine->SourceA[1]); - */ - - /* - * Do operand setup for up to 4 operands. Loop over the terms. - */ - for (term = 0; term < numArgsRGB; term++) { - const GLenum srcRGB = combine->SourceRGB[term]; - const GLenum operandRGB = combine->OperandRGB[term]; - - switch (srcRGB) { - case GL_TEXTURE: - argRGB[term] = get_texel_array(swrast, unit); - break; - case GL_PRIMARY_COLOR: - argRGB[term] = primary_rgba; - break; - case GL_PREVIOUS: - argRGB[term] = rgba; - break; - case GL_CONSTANT: - { - float4_array c = ccolor[term]; - GLfloat red = textureUnit->EnvColor[0]; - GLfloat green = textureUnit->EnvColor[1]; - GLfloat blue = textureUnit->EnvColor[2]; - GLfloat alpha = textureUnit->EnvColor[3]; - for (i = 0; i < n; i++) { - ASSIGN_4V(c[i], red, green, blue, alpha); - } - argRGB[term] = ccolor[term]; - } - break; - /* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources. - */ - case GL_ZERO: - { - float4_array c = ccolor[term]; - for (i = 0; i < n; i++) { - ASSIGN_4V(c[i], 0.0F, 0.0F, 0.0F, 0.0F); - } - argRGB[term] = ccolor[term]; - } - break; - case GL_ONE: - { - float4_array c = ccolor[term]; - for (i = 0; i < n; i++) { - ASSIGN_4V(c[i], 1.0F, 1.0F, 1.0F, 1.0F); - } - argRGB[term] = ccolor[term]; - } - break; - default: - /* ARB_texture_env_crossbar source */ - { - const GLuint srcUnit = srcRGB - GL_TEXTURE0; - ASSERT(srcUnit < ctx->Const.MaxTextureUnits); - if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled) - goto end; - argRGB[term] = get_texel_array(swrast, srcUnit); - } - } - - if (operandRGB != GL_SRC_COLOR) { - float4_array src = argRGB[term]; - float4_array dst = ccolor[term]; - - /* point to new arg[term] storage */ - argRGB[term] = ccolor[term]; - - switch (operandRGB) { - case GL_ONE_MINUS_SRC_COLOR: - for (i = 0; i < n; i++) { - dst[i][RCOMP] = 1.0F - src[i][RCOMP]; - dst[i][GCOMP] = 1.0F - src[i][GCOMP]; - dst[i][BCOMP] = 1.0F - src[i][BCOMP]; - } - break; - case GL_SRC_ALPHA: - for (i = 0; i < n; i++) { - dst[i][RCOMP] = - dst[i][GCOMP] = - dst[i][BCOMP] = src[i][ACOMP]; - } - break; - case GL_ONE_MINUS_SRC_ALPHA: - for (i = 0; i < n; i++) { - dst[i][RCOMP] = - dst[i][GCOMP] = - dst[i][BCOMP] = 1.0F - src[i][ACOMP]; - } - break; - default: - _mesa_problem(ctx, "Bad operandRGB"); - } - } - } - - /* - * Set up the argA[term] pointers - */ - for (term = 0; term < numArgsA; term++) { - const GLenum srcA = combine->SourceA[term]; - const GLenum operandA = combine->OperandA[term]; - - switch (srcA) { - case GL_TEXTURE: - argA[term] = get_texel_array(swrast, unit); - break; - case GL_PRIMARY_COLOR: - argA[term] = primary_rgba; - break; - case GL_PREVIOUS: - argA[term] = rgba; - break; - case GL_CONSTANT: - { - float4_array c = ccolor[term]; - GLfloat alpha = textureUnit->EnvColor[3]; - for (i = 0; i < n; i++) - c[i][ACOMP] = alpha; - argA[term] = ccolor[term]; - } - break; - /* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources. - */ - case GL_ZERO: - { - float4_array c = ccolor[term]; - for (i = 0; i < n; i++) - c[i][ACOMP] = 0.0F; - argA[term] = ccolor[term]; - } - break; - case GL_ONE: - { - float4_array c = ccolor[term]; - for (i = 0; i < n; i++) - c[i][ACOMP] = 1.0F; - argA[term] = ccolor[term]; - } - break; - default: - /* ARB_texture_env_crossbar source */ - { - const GLuint srcUnit = srcA - GL_TEXTURE0; - ASSERT(srcUnit < ctx->Const.MaxTextureUnits); - if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled) - goto end; - argA[term] = get_texel_array(swrast, srcUnit); - } - } - - if (operandA == GL_ONE_MINUS_SRC_ALPHA) { - float4_array src = argA[term]; - float4_array dst = ccolor[term]; - argA[term] = ccolor[term]; - for (i = 0; i < n; i++) { - dst[i][ACOMP] = 1.0F - src[i][ACOMP]; - } - } - } - - /* RGB channel combine */ - { - float4_array arg0 = argRGB[0]; - float4_array arg1 = argRGB[1]; - float4_array arg2 = argRGB[2]; - float4_array arg3 = argRGB[3]; - - switch (combine->ModeRGB) { - case GL_REPLACE: - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = arg0[i][RCOMP] * scaleRGB; - rgba[i][GCOMP] = arg0[i][GCOMP] * scaleRGB; - rgba[i][BCOMP] = arg0[i][BCOMP] * scaleRGB; - } - break; - case GL_MODULATE: - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = arg0[i][RCOMP] * arg1[i][RCOMP] * scaleRGB; - rgba[i][GCOMP] = arg0[i][GCOMP] * arg1[i][GCOMP] * scaleRGB; - rgba[i][BCOMP] = arg0[i][BCOMP] * arg1[i][BCOMP] * scaleRGB; - } - break; - case GL_ADD: - if (textureUnit->EnvMode == GL_COMBINE4_NV) { - /* (a * b) + (c * d) */ - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = (arg0[i][RCOMP] * arg1[i][RCOMP] + - arg2[i][RCOMP] * arg3[i][RCOMP]) * scaleRGB; - rgba[i][GCOMP] = (arg0[i][GCOMP] * arg1[i][GCOMP] + - arg2[i][GCOMP] * arg3[i][GCOMP]) * scaleRGB; - rgba[i][BCOMP] = (arg0[i][BCOMP] * arg1[i][BCOMP] + - arg2[i][BCOMP] * arg3[i][BCOMP]) * scaleRGB; - } - } - else { - /* 2-term addition */ - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP]) * scaleRGB; - rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP]) * scaleRGB; - rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP]) * scaleRGB; - } - } - break; - case GL_ADD_SIGNED: - if (textureUnit->EnvMode == GL_COMBINE4_NV) { - /* (a * b) + (c * d) - 0.5 */ - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = (arg0[i][RCOMP] * arg1[i][RCOMP] + - arg2[i][RCOMP] * arg3[i][RCOMP] - 0.5F) * scaleRGB; - rgba[i][GCOMP] = (arg0[i][GCOMP] * arg1[i][GCOMP] + - arg2[i][GCOMP] * arg3[i][GCOMP] - 0.5F) * scaleRGB; - rgba[i][BCOMP] = (arg0[i][BCOMP] * arg1[i][BCOMP] + - arg2[i][BCOMP] * arg3[i][BCOMP] - 0.5F) * scaleRGB; - } - } - else { - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP] - 0.5F) * scaleRGB; - rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP] - 0.5F) * scaleRGB; - rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP] - 0.5F) * scaleRGB; - } - } - break; - case GL_INTERPOLATE: - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = (arg0[i][RCOMP] * arg2[i][RCOMP] + - arg1[i][RCOMP] * (1.0F - arg2[i][RCOMP])) * scaleRGB; - rgba[i][GCOMP] = (arg0[i][GCOMP] * arg2[i][GCOMP] + - arg1[i][GCOMP] * (1.0F - arg2[i][GCOMP])) * scaleRGB; - rgba[i][BCOMP] = (arg0[i][BCOMP] * arg2[i][BCOMP] + - arg1[i][BCOMP] * (1.0F - arg2[i][BCOMP])) * scaleRGB; - } - break; - case GL_SUBTRACT: - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = (arg0[i][RCOMP] - arg1[i][RCOMP]) * scaleRGB; - rgba[i][GCOMP] = (arg0[i][GCOMP] - arg1[i][GCOMP]) * scaleRGB; - rgba[i][BCOMP] = (arg0[i][BCOMP] - arg1[i][BCOMP]) * scaleRGB; - } - break; - case GL_DOT3_RGB_EXT: - case GL_DOT3_RGBA_EXT: - /* Do not scale the result by 1 2 or 4 */ - for (i = 0; i < n; i++) { - GLfloat dot = ((arg0[i][RCOMP] - 0.5F) * (arg1[i][RCOMP] - 0.5F) + - (arg0[i][GCOMP] - 0.5F) * (arg1[i][GCOMP] - 0.5F) + - (arg0[i][BCOMP] - 0.5F) * (arg1[i][BCOMP] - 0.5F)) - * 4.0F; - dot = CLAMP(dot, 0.0F, 1.0F); - rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = dot; - } - break; - case GL_DOT3_RGB: - case GL_DOT3_RGBA: - /* DO scale the result by 1 2 or 4 */ - for (i = 0; i < n; i++) { - GLfloat dot = ((arg0[i][RCOMP] - 0.5F) * (arg1[i][RCOMP] - 0.5F) + - (arg0[i][GCOMP] - 0.5F) * (arg1[i][GCOMP] - 0.5F) + - (arg0[i][BCOMP] - 0.5F) * (arg1[i][BCOMP] - 0.5F)) - * 4.0F * scaleRGB; - dot = CLAMP(dot, 0.0F, 1.0F); - rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = dot; - } - break; - case GL_MODULATE_ADD_ATI: - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) + - arg1[i][RCOMP]) * scaleRGB; - rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) + - arg1[i][GCOMP]) * scaleRGB; - rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) + - arg1[i][BCOMP]) * scaleRGB; - } - break; - case GL_MODULATE_SIGNED_ADD_ATI: - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) + - arg1[i][RCOMP] - 0.5F) * scaleRGB; - rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) + - arg1[i][GCOMP] - 0.5F) * scaleRGB; - rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) + - arg1[i][BCOMP] - 0.5F) * scaleRGB; - } - break; - case GL_MODULATE_SUBTRACT_ATI: - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) - - arg1[i][RCOMP]) * scaleRGB; - rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) - - arg1[i][GCOMP]) * scaleRGB; - rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) - - arg1[i][BCOMP]) * scaleRGB; - } - break; - case GL_BUMP_ENVMAP_ATI: - /* this produces a fixed rgba color, and the coord calc is done elsewhere */ - for (i = 0; i < n; i++) { - /* rgba result is 0,0,0,1 */ - rgba[i][RCOMP] = 0.0; - rgba[i][GCOMP] = 0.0; - rgba[i][BCOMP] = 0.0; - rgba[i][ACOMP] = 1.0; - } - goto end; /* no alpha processing */ - default: - _mesa_problem(ctx, "invalid combine mode"); - } - } - - /* Alpha channel combine */ - { - float4_array arg0 = argA[0]; - float4_array arg1 = argA[1]; - float4_array arg2 = argA[2]; - float4_array arg3 = argA[3]; - - switch (combine->ModeA) { - case GL_REPLACE: - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = arg0[i][ACOMP] * scaleA; - } - break; - case GL_MODULATE: - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = arg0[i][ACOMP] * arg1[i][ACOMP] * scaleA; - } - break; - case GL_ADD: - if (textureUnit->EnvMode == GL_COMBINE4_NV) { - /* (a * b) + (c * d) */ - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = (arg0[i][ACOMP] * arg1[i][ACOMP] + - arg2[i][ACOMP] * arg3[i][ACOMP]) * scaleA; - } - } - else { - /* two-term add */ - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP]) * scaleA; - } - } - break; - case GL_ADD_SIGNED: - if (textureUnit->EnvMode == GL_COMBINE4_NV) { - /* (a * b) + (c * d) - 0.5 */ - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = (arg0[i][ACOMP] * arg1[i][ACOMP] + - arg2[i][ACOMP] * arg3[i][ACOMP] - - 0.5F) * scaleA; - } - } - else { - /* a + b - 0.5 */ - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP] - 0.5F) * scaleA; - } - } - break; - case GL_INTERPOLATE: - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = (arg0[i][ACOMP] * arg2[i][ACOMP] + - arg1[i][ACOMP] * (1.0F - arg2[i][ACOMP])) - * scaleA; - } - break; - case GL_SUBTRACT: - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = (arg0[i][ACOMP] - arg1[i][ACOMP]) * scaleA; - } - break; - case GL_MODULATE_ADD_ATI: - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) - + arg1[i][ACOMP]) * scaleA; - } - break; - case GL_MODULATE_SIGNED_ADD_ATI: - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) + - arg1[i][ACOMP] - 0.5F) * scaleA; - } - break; - case GL_MODULATE_SUBTRACT_ATI: - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) - - arg1[i][ACOMP]) * scaleA; - } - break; - default: - _mesa_problem(ctx, "invalid combine mode"); - } - } - - /* Fix the alpha component for GL_DOT3_RGBA_EXT/ARB combining. - * This is kind of a kludge. It would have been better if the spec - * were written such that the GL_COMBINE_ALPHA value could be set to - * GL_DOT3. - */ - if (combine->ModeRGB == GL_DOT3_RGBA_EXT || - combine->ModeRGB == GL_DOT3_RGBA) { - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = rgba[i][RCOMP]; - } - } - - for (i = 0; i < n; i++) { - UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][RCOMP], rgba[i][RCOMP]); - UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][GCOMP], rgba[i][GCOMP]); - UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][BCOMP], rgba[i][BCOMP]); - UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][ACOMP], rgba[i][ACOMP]); - } - -end: - for (i = 0; i < numArgsRGB || i < numArgsA; i++) { - free(ccolor[i]); - } - free(rgba); -} - - -/** - * Apply X/Y/Z/W/0/1 swizzle to an array of colors/texels. - * See GL_EXT_texture_swizzle. - */ -static void -swizzle_texels(GLuint swizzle, GLuint count, float4_array texels) -{ - const GLuint swzR = GET_SWZ(swizzle, 0); - const GLuint swzG = GET_SWZ(swizzle, 1); - const GLuint swzB = GET_SWZ(swizzle, 2); - const GLuint swzA = GET_SWZ(swizzle, 3); - GLfloat vector[6]; - GLuint i; - - vector[SWIZZLE_ZERO] = 0; - vector[SWIZZLE_ONE] = 1.0F; - - for (i = 0; i < count; i++) { - vector[SWIZZLE_X] = texels[i][0]; - vector[SWIZZLE_Y] = texels[i][1]; - vector[SWIZZLE_Z] = texels[i][2]; - vector[SWIZZLE_W] = texels[i][3]; - texels[i][RCOMP] = vector[swzR]; - texels[i][GCOMP] = vector[swzG]; - texels[i][BCOMP] = vector[swzB]; - texels[i][ACOMP] = vector[swzA]; - } -} - - -/** - * Apply texture mapping to a span of fragments. - */ -void -_swrast_texture_span( struct gl_context *ctx, SWspan *span ) -{ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - float4_array primary_rgba; - GLuint unit; - - primary_rgba = (float4_array) malloc(span->end * 4 * sizeof(GLfloat)); - - if (!primary_rgba) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_span"); - return; - } - - ASSERT(span->end <= MAX_WIDTH); - - /* - * Save copy of the incoming fragment colors (the GL_PRIMARY_COLOR) - */ - if (swrast->_TextureCombinePrimary) { - GLuint i; - for (i = 0; i < span->end; i++) { - primary_rgba[i][RCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][RCOMP]); - primary_rgba[i][GCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][GCOMP]); - primary_rgba[i][BCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][BCOMP]); - primary_rgba[i][ACOMP] = CHAN_TO_FLOAT(span->array->rgba[i][ACOMP]); - } - } - - /* First must sample all bump maps */ - for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { - const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - - if (texUnit->_ReallyEnabled && - texUnit->_CurrentCombine->ModeRGB == GL_BUMP_ENVMAP_ATI) { - const GLfloat (*texcoords)[4] = (const GLfloat (*)[4]) - span->array->attribs[FRAG_ATTRIB_TEX0 + unit]; - float4_array targetcoords = - span->array->attribs[FRAG_ATTRIB_TEX0 + - ctx->Texture.Unit[unit].BumpTarget - GL_TEXTURE0]; - - const struct gl_texture_object *curObj = texUnit->_Current; - GLfloat *lambda = span->array->lambda[unit]; - float4_array texels = get_texel_array(swrast, unit); - GLuint i; - GLfloat rotMatrix00 = ctx->Texture.Unit[unit].RotMatrix[0]; - GLfloat rotMatrix01 = ctx->Texture.Unit[unit].RotMatrix[1]; - GLfloat rotMatrix10 = ctx->Texture.Unit[unit].RotMatrix[2]; - GLfloat rotMatrix11 = ctx->Texture.Unit[unit].RotMatrix[3]; - - /* adjust texture lod (lambda) */ - if (span->arrayMask & SPAN_LAMBDA) { - if (texUnit->LodBias + curObj->LodBias != 0.0F) { - /* apply LOD bias, but don't clamp yet */ - const GLfloat bias = CLAMP(texUnit->LodBias + curObj->LodBias, - -ctx->Const.MaxTextureLodBias, - ctx->Const.MaxTextureLodBias); - GLuint i; - for (i = 0; i < span->end; i++) { - lambda[i] += bias; - } - } - - if (curObj->MinLod != -1000.0 || curObj->MaxLod != 1000.0) { - /* apply LOD clamping to lambda */ - const GLfloat min = curObj->MinLod; - const GLfloat max = curObj->MaxLod; - GLuint i; - for (i = 0; i < span->end; i++) { - GLfloat l = lambda[i]; - lambda[i] = CLAMP(l, min, max); - } - } - } - - /* Sample the texture (span->end = number of fragments) */ - swrast->TextureSample[unit]( ctx, texUnit->_Current, span->end, - texcoords, lambda, texels ); - - /* manipulate the span values of the bump target - not sure this can work correctly even ignoring - the problem that channel is unsigned */ - for (i = 0; i < span->end; i++) { - targetcoords[i][0] += (texels[i][0] * rotMatrix00 + texels[i][1] * - rotMatrix01) / targetcoords[i][3]; - targetcoords[i][1] += (texels[i][0] * rotMatrix10 + texels[i][1] * - rotMatrix11) / targetcoords[i][3]; - } - } - } - - /* - * Must do all texture sampling before combining in order to - * accomodate GL_ARB_texture_env_crossbar. - */ - for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { - const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; - if (texUnit->_ReallyEnabled && - texUnit->_CurrentCombine->ModeRGB != GL_BUMP_ENVMAP_ATI) { - const GLfloat (*texcoords)[4] = (const GLfloat (*)[4]) - span->array->attribs[FRAG_ATTRIB_TEX0 + unit]; - const struct gl_texture_object *curObj = texUnit->_Current; - GLfloat *lambda = span->array->lambda[unit]; - float4_array texels = get_texel_array(swrast, unit); - - /* adjust texture lod (lambda) */ - if (span->arrayMask & SPAN_LAMBDA) { - if (texUnit->LodBias + curObj->LodBias != 0.0F) { - /* apply LOD bias, but don't clamp yet */ - const GLfloat bias = CLAMP(texUnit->LodBias + curObj->LodBias, - -ctx->Const.MaxTextureLodBias, - ctx->Const.MaxTextureLodBias); - GLuint i; - for (i = 0; i < span->end; i++) { - lambda[i] += bias; - } - } - - if (curObj->MinLod != -1000.0 || curObj->MaxLod != 1000.0) { - /* apply LOD clamping to lambda */ - const GLfloat min = curObj->MinLod; - const GLfloat max = curObj->MaxLod; - GLuint i; - for (i = 0; i < span->end; i++) { - GLfloat l = lambda[i]; - lambda[i] = CLAMP(l, min, max); - } - } - } - - /* Sample the texture (span->end = number of fragments) */ - swrast->TextureSample[unit]( ctx, texUnit->_Current, span->end, - texcoords, lambda, texels ); - - /* GL_SGI_texture_color_table */ - if (texUnit->ColorTableEnabled) { - _mesa_lookup_rgba_float(&texUnit->ColorTable, span->end, texels); - } - - /* GL_EXT_texture_swizzle */ - if (curObj->_Swizzle != SWIZZLE_NOOP) { - swizzle_texels(curObj->_Swizzle, span->end, texels); - } - } - } - - /* - * OK, now apply the texture (aka texture combine/blend). - * We modify the span->color.rgba values. - */ - for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { - if (ctx->Texture.Unit[unit]._ReallyEnabled) { - texture_combine( ctx, unit, span->end, - primary_rgba, - swrast->TexelBuffer, - span->array->rgba ); - } - } - - free(primary_rgba); -} +/* + * 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. + */ + + +#include "main/glheader.h" +#include "main/context.h" +#include "main/colormac.h" +#include "main/imports.h" +#include "main/pixeltransfer.h" +#include "program/prog_instruction.h" + +#include "s_context.h" +#include "s_texcombine.h" + + +/** + * Pointer to array of float[4] + * This type makes the code below more concise and avoids a lot of casting. + */ +typedef float (*float4_array)[4]; + + +/** + * Return array of texels for given unit. + */ +static INLINE float4_array +get_texel_array(SWcontext *swrast, GLuint unit) +{ + return (float4_array) (swrast->TexelBuffer + unit * MAX_WIDTH * 4); +} + + + +/** + * Do texture application for: + * GL_EXT_texture_env_combine + * GL_ARB_texture_env_combine + * GL_EXT_texture_env_dot3 + * GL_ARB_texture_env_dot3 + * GL_ATI_texture_env_combine3 + * GL_NV_texture_env_combine4 + * conventional GL texture env modes + * + * \param ctx rendering context + * \param unit the texture combiner unit + * \param n number of fragments to process (span width) + * \param primary_rgba incoming fragment color array + * \param texelBuffer pointer to texel colors for all texture units + * + * \param rgba incoming/result fragment colors + */ +static void +texture_combine( struct gl_context *ctx, GLuint unit, GLuint n, + const float4_array primary_rgba, + const GLfloat *texelBuffer, + GLchan (*rgbaChan)[4] ) +{ + SWcontext *swrast = SWRAST_CONTEXT(ctx); + const struct gl_texture_unit *textureUnit = &(ctx->Texture.Unit[unit]); + const struct gl_tex_env_combine_state *combine = textureUnit->_CurrentCombine; + float4_array argRGB[MAX_COMBINER_TERMS]; + float4_array argA[MAX_COMBINER_TERMS]; + const GLfloat scaleRGB = (GLfloat) (1 << combine->ScaleShiftRGB); + const GLfloat scaleA = (GLfloat) (1 << combine->ScaleShiftA); + const GLuint numArgsRGB = combine->_NumArgsRGB; + const GLuint numArgsA = combine->_NumArgsA; + float4_array ccolor[4], rgba; + GLuint i, term; + + /* alloc temp pixel buffers */ + rgba = (float4_array) malloc(4 * n * sizeof(GLfloat)); + if (!rgba) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine"); + return; + } + + for (i = 0; i < numArgsRGB || i < numArgsA; i++) { + ccolor[i] = (float4_array) malloc(4 * n * sizeof(GLfloat)); + if (!ccolor[i]) { + while (i) { + free(ccolor[i]); + i--; + } + _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine"); + return; + } + } + + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = CHAN_TO_FLOAT(rgbaChan[i][RCOMP]); + rgba[i][GCOMP] = CHAN_TO_FLOAT(rgbaChan[i][GCOMP]); + rgba[i][BCOMP] = CHAN_TO_FLOAT(rgbaChan[i][BCOMP]); + rgba[i][ACOMP] = CHAN_TO_FLOAT(rgbaChan[i][ACOMP]); + } + + /* + printf("modeRGB 0x%x modeA 0x%x srcRGB1 0x%x srcA1 0x%x srcRGB2 0x%x srcA2 0x%x\n", + combine->ModeRGB, + combine->ModeA, + combine->SourceRGB[0], + combine->SourceA[0], + combine->SourceRGB[1], + combine->SourceA[1]); + */ + + /* + * Do operand setup for up to 4 operands. Loop over the terms. + */ + for (term = 0; term < numArgsRGB; term++) { + const GLenum srcRGB = combine->SourceRGB[term]; + const GLenum operandRGB = combine->OperandRGB[term]; + + switch (srcRGB) { + case GL_TEXTURE: + argRGB[term] = get_texel_array(swrast, unit); + break; + case GL_PRIMARY_COLOR: + argRGB[term] = primary_rgba; + break; + case GL_PREVIOUS: + argRGB[term] = rgba; + break; + case GL_CONSTANT: + { + float4_array c = ccolor[term]; + GLfloat red = textureUnit->EnvColor[0]; + GLfloat green = textureUnit->EnvColor[1]; + GLfloat blue = textureUnit->EnvColor[2]; + GLfloat alpha = textureUnit->EnvColor[3]; + for (i = 0; i < n; i++) { + ASSIGN_4V(c[i], red, green, blue, alpha); + } + argRGB[term] = ccolor[term]; + } + break; + /* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources. + */ + case GL_ZERO: + { + float4_array c = ccolor[term]; + for (i = 0; i < n; i++) { + ASSIGN_4V(c[i], 0.0F, 0.0F, 0.0F, 0.0F); + } + argRGB[term] = ccolor[term]; + } + break; + case GL_ONE: + { + float4_array c = ccolor[term]; + for (i = 0; i < n; i++) { + ASSIGN_4V(c[i], 1.0F, 1.0F, 1.0F, 1.0F); + } + argRGB[term] = ccolor[term]; + } + break; + default: + /* ARB_texture_env_crossbar source */ + { + const GLuint srcUnit = srcRGB - GL_TEXTURE0; + ASSERT(srcUnit < ctx->Const.MaxTextureUnits); + if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled) + goto end; + argRGB[term] = get_texel_array(swrast, srcUnit); + } + } + + if (operandRGB != GL_SRC_COLOR) { + float4_array src = argRGB[term]; + float4_array dst = ccolor[term]; + + /* point to new arg[term] storage */ + argRGB[term] = ccolor[term]; + + switch (operandRGB) { + case GL_ONE_MINUS_SRC_COLOR: + for (i = 0; i < n; i++) { + dst[i][RCOMP] = 1.0F - src[i][RCOMP]; + dst[i][GCOMP] = 1.0F - src[i][GCOMP]; + dst[i][BCOMP] = 1.0F - src[i][BCOMP]; + } + break; + case GL_SRC_ALPHA: + for (i = 0; i < n; i++) { + dst[i][RCOMP] = + dst[i][GCOMP] = + dst[i][BCOMP] = src[i][ACOMP]; + } + break; + case GL_ONE_MINUS_SRC_ALPHA: + for (i = 0; i < n; i++) { + dst[i][RCOMP] = + dst[i][GCOMP] = + dst[i][BCOMP] = 1.0F - src[i][ACOMP]; + } + break; + default: + _mesa_problem(ctx, "Bad operandRGB"); + } + } + } + + /* + * Set up the argA[term] pointers + */ + for (term = 0; term < numArgsA; term++) { + const GLenum srcA = combine->SourceA[term]; + const GLenum operandA = combine->OperandA[term]; + + switch (srcA) { + case GL_TEXTURE: + argA[term] = get_texel_array(swrast, unit); + break; + case GL_PRIMARY_COLOR: + argA[term] = primary_rgba; + break; + case GL_PREVIOUS: + argA[term] = rgba; + break; + case GL_CONSTANT: + { + float4_array c = ccolor[term]; + GLfloat alpha = textureUnit->EnvColor[3]; + for (i = 0; i < n; i++) + c[i][ACOMP] = alpha; + argA[term] = ccolor[term]; + } + break; + /* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources. + */ + case GL_ZERO: + { + float4_array c = ccolor[term]; + for (i = 0; i < n; i++) + c[i][ACOMP] = 0.0F; + argA[term] = ccolor[term]; + } + break; + case GL_ONE: + { + float4_array c = ccolor[term]; + for (i = 0; i < n; i++) + c[i][ACOMP] = 1.0F; + argA[term] = ccolor[term]; + } + break; + default: + /* ARB_texture_env_crossbar source */ + { + const GLuint srcUnit = srcA - GL_TEXTURE0; + ASSERT(srcUnit < ctx->Const.MaxTextureUnits); + if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled) + goto end; + argA[term] = get_texel_array(swrast, srcUnit); + } + } + + if (operandA == GL_ONE_MINUS_SRC_ALPHA) { + float4_array src = argA[term]; + float4_array dst = ccolor[term]; + argA[term] = ccolor[term]; + for (i = 0; i < n; i++) { + dst[i][ACOMP] = 1.0F - src[i][ACOMP]; + } + } + } + + /* RGB channel combine */ + { + float4_array arg0 = argRGB[0]; + float4_array arg1 = argRGB[1]; + float4_array arg2 = argRGB[2]; + float4_array arg3 = argRGB[3]; + + switch (combine->ModeRGB) { + case GL_REPLACE: + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = arg0[i][RCOMP] * scaleRGB; + rgba[i][GCOMP] = arg0[i][GCOMP] * scaleRGB; + rgba[i][BCOMP] = arg0[i][BCOMP] * scaleRGB; + } + break; + case GL_MODULATE: + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = arg0[i][RCOMP] * arg1[i][RCOMP] * scaleRGB; + rgba[i][GCOMP] = arg0[i][GCOMP] * arg1[i][GCOMP] * scaleRGB; + rgba[i][BCOMP] = arg0[i][BCOMP] * arg1[i][BCOMP] * scaleRGB; + } + break; + case GL_ADD: + if (textureUnit->EnvMode == GL_COMBINE4_NV) { + /* (a * b) + (c * d) */ + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = (arg0[i][RCOMP] * arg1[i][RCOMP] + + arg2[i][RCOMP] * arg3[i][RCOMP]) * scaleRGB; + rgba[i][GCOMP] = (arg0[i][GCOMP] * arg1[i][GCOMP] + + arg2[i][GCOMP] * arg3[i][GCOMP]) * scaleRGB; + rgba[i][BCOMP] = (arg0[i][BCOMP] * arg1[i][BCOMP] + + arg2[i][BCOMP] * arg3[i][BCOMP]) * scaleRGB; + } + } + else { + /* 2-term addition */ + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP]) * scaleRGB; + rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP]) * scaleRGB; + rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP]) * scaleRGB; + } + } + break; + case GL_ADD_SIGNED: + if (textureUnit->EnvMode == GL_COMBINE4_NV) { + /* (a * b) + (c * d) - 0.5 */ + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = (arg0[i][RCOMP] * arg1[i][RCOMP] + + arg2[i][RCOMP] * arg3[i][RCOMP] - 0.5F) * scaleRGB; + rgba[i][GCOMP] = (arg0[i][GCOMP] * arg1[i][GCOMP] + + arg2[i][GCOMP] * arg3[i][GCOMP] - 0.5F) * scaleRGB; + rgba[i][BCOMP] = (arg0[i][BCOMP] * arg1[i][BCOMP] + + arg2[i][BCOMP] * arg3[i][BCOMP] - 0.5F) * scaleRGB; + } + } + else { + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP] - 0.5F) * scaleRGB; + rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP] - 0.5F) * scaleRGB; + rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP] - 0.5F) * scaleRGB; + } + } + break; + case GL_INTERPOLATE: + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = (arg0[i][RCOMP] * arg2[i][RCOMP] + + arg1[i][RCOMP] * (1.0F - arg2[i][RCOMP])) * scaleRGB; + rgba[i][GCOMP] = (arg0[i][GCOMP] * arg2[i][GCOMP] + + arg1[i][GCOMP] * (1.0F - arg2[i][GCOMP])) * scaleRGB; + rgba[i][BCOMP] = (arg0[i][BCOMP] * arg2[i][BCOMP] + + arg1[i][BCOMP] * (1.0F - arg2[i][BCOMP])) * scaleRGB; + } + break; + case GL_SUBTRACT: + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = (arg0[i][RCOMP] - arg1[i][RCOMP]) * scaleRGB; + rgba[i][GCOMP] = (arg0[i][GCOMP] - arg1[i][GCOMP]) * scaleRGB; + rgba[i][BCOMP] = (arg0[i][BCOMP] - arg1[i][BCOMP]) * scaleRGB; + } + break; + case GL_DOT3_RGB_EXT: + case GL_DOT3_RGBA_EXT: + /* Do not scale the result by 1 2 or 4 */ + for (i = 0; i < n; i++) { + GLfloat dot = ((arg0[i][RCOMP] - 0.5F) * (arg1[i][RCOMP] - 0.5F) + + (arg0[i][GCOMP] - 0.5F) * (arg1[i][GCOMP] - 0.5F) + + (arg0[i][BCOMP] - 0.5F) * (arg1[i][BCOMP] - 0.5F)) + * 4.0F; + dot = CLAMP(dot, 0.0F, 1.0F); + rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = dot; + } + break; + case GL_DOT3_RGB: + case GL_DOT3_RGBA: + /* DO scale the result by 1 2 or 4 */ + for (i = 0; i < n; i++) { + GLfloat dot = ((arg0[i][RCOMP] - 0.5F) * (arg1[i][RCOMP] - 0.5F) + + (arg0[i][GCOMP] - 0.5F) * (arg1[i][GCOMP] - 0.5F) + + (arg0[i][BCOMP] - 0.5F) * (arg1[i][BCOMP] - 0.5F)) + * 4.0F * scaleRGB; + dot = CLAMP(dot, 0.0F, 1.0F); + rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = dot; + } + break; + case GL_MODULATE_ADD_ATI: + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) + + arg1[i][RCOMP]) * scaleRGB; + rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) + + arg1[i][GCOMP]) * scaleRGB; + rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) + + arg1[i][BCOMP]) * scaleRGB; + } + break; + case GL_MODULATE_SIGNED_ADD_ATI: + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) + + arg1[i][RCOMP] - 0.5F) * scaleRGB; + rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) + + arg1[i][GCOMP] - 0.5F) * scaleRGB; + rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) + + arg1[i][BCOMP] - 0.5F) * scaleRGB; + } + break; + case GL_MODULATE_SUBTRACT_ATI: + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) - + arg1[i][RCOMP]) * scaleRGB; + rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) - + arg1[i][GCOMP]) * scaleRGB; + rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) - + arg1[i][BCOMP]) * scaleRGB; + } + break; + case GL_BUMP_ENVMAP_ATI: + /* this produces a fixed rgba color, and the coord calc is done elsewhere */ + for (i = 0; i < n; i++) { + /* rgba result is 0,0,0,1 */ + rgba[i][RCOMP] = 0.0; + rgba[i][GCOMP] = 0.0; + rgba[i][BCOMP] = 0.0; + rgba[i][ACOMP] = 1.0; + } + goto end; /* no alpha processing */ + default: + _mesa_problem(ctx, "invalid combine mode"); + } + } + + /* Alpha channel combine */ + { + float4_array arg0 = argA[0]; + float4_array arg1 = argA[1]; + float4_array arg2 = argA[2]; + float4_array arg3 = argA[3]; + + switch (combine->ModeA) { + case GL_REPLACE: + for (i = 0; i < n; i++) { + rgba[i][ACOMP] = arg0[i][ACOMP] * scaleA; + } + break; + case GL_MODULATE: + for (i = 0; i < n; i++) { + rgba[i][ACOMP] = arg0[i][ACOMP] * arg1[i][ACOMP] * scaleA; + } + break; + case GL_ADD: + if (textureUnit->EnvMode == GL_COMBINE4_NV) { + /* (a * b) + (c * d) */ + for (i = 0; i < n; i++) { + rgba[i][ACOMP] = (arg0[i][ACOMP] * arg1[i][ACOMP] + + arg2[i][ACOMP] * arg3[i][ACOMP]) * scaleA; + } + } + else { + /* two-term add */ + for (i = 0; i < n; i++) { + rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP]) * scaleA; + } + } + break; + case GL_ADD_SIGNED: + if (textureUnit->EnvMode == GL_COMBINE4_NV) { + /* (a * b) + (c * d) - 0.5 */ + for (i = 0; i < n; i++) { + rgba[i][ACOMP] = (arg0[i][ACOMP] * arg1[i][ACOMP] + + arg2[i][ACOMP] * arg3[i][ACOMP] - + 0.5F) * scaleA; + } + } + else { + /* a + b - 0.5 */ + for (i = 0; i < n; i++) { + rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP] - 0.5F) * scaleA; + } + } + break; + case GL_INTERPOLATE: + for (i = 0; i < n; i++) { + rgba[i][ACOMP] = (arg0[i][ACOMP] * arg2[i][ACOMP] + + arg1[i][ACOMP] * (1.0F - arg2[i][ACOMP])) + * scaleA; + } + break; + case GL_SUBTRACT: + for (i = 0; i < n; i++) { + rgba[i][ACOMP] = (arg0[i][ACOMP] - arg1[i][ACOMP]) * scaleA; + } + break; + case GL_MODULATE_ADD_ATI: + for (i = 0; i < n; i++) { + rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) + + arg1[i][ACOMP]) * scaleA; + } + break; + case GL_MODULATE_SIGNED_ADD_ATI: + for (i = 0; i < n; i++) { + rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) + + arg1[i][ACOMP] - 0.5F) * scaleA; + } + break; + case GL_MODULATE_SUBTRACT_ATI: + for (i = 0; i < n; i++) { + rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) + - arg1[i][ACOMP]) * scaleA; + } + break; + default: + _mesa_problem(ctx, "invalid combine mode"); + } + } + + /* Fix the alpha component for GL_DOT3_RGBA_EXT/ARB combining. + * This is kind of a kludge. It would have been better if the spec + * were written such that the GL_COMBINE_ALPHA value could be set to + * GL_DOT3. + */ + if (combine->ModeRGB == GL_DOT3_RGBA_EXT || + combine->ModeRGB == GL_DOT3_RGBA) { + for (i = 0; i < n; i++) { + rgba[i][ACOMP] = rgba[i][RCOMP]; + } + } + + for (i = 0; i < n; i++) { + UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][RCOMP], rgba[i][RCOMP]); + UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][GCOMP], rgba[i][GCOMP]); + UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][BCOMP], rgba[i][BCOMP]); + UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][ACOMP], rgba[i][ACOMP]); + } + +end: + for (i = 0; i < numArgsRGB || i < numArgsA; i++) { + free(ccolor[i]); + } + free(rgba); +} + + +/** + * Apply X/Y/Z/W/0/1 swizzle to an array of colors/texels. + * See GL_EXT_texture_swizzle. + */ +static void +swizzle_texels(GLuint swizzle, GLuint count, float4_array texels) +{ + const GLuint swzR = GET_SWZ(swizzle, 0); + const GLuint swzG = GET_SWZ(swizzle, 1); + const GLuint swzB = GET_SWZ(swizzle, 2); + const GLuint swzA = GET_SWZ(swizzle, 3); + GLfloat vector[6]; + GLuint i; + + vector[SWIZZLE_ZERO] = 0; + vector[SWIZZLE_ONE] = 1.0F; + + for (i = 0; i < count; i++) { + vector[SWIZZLE_X] = texels[i][0]; + vector[SWIZZLE_Y] = texels[i][1]; + vector[SWIZZLE_Z] = texels[i][2]; + vector[SWIZZLE_W] = texels[i][3]; + texels[i][RCOMP] = vector[swzR]; + texels[i][GCOMP] = vector[swzG]; + texels[i][BCOMP] = vector[swzB]; + texels[i][ACOMP] = vector[swzA]; + } +} + + +/** + * Apply texture mapping to a span of fragments. + */ +void +_swrast_texture_span( struct gl_context *ctx, SWspan *span ) +{ + SWcontext *swrast = SWRAST_CONTEXT(ctx); + float4_array primary_rgba; + GLuint unit; + + primary_rgba = (float4_array) malloc(span->end * 4 * sizeof(GLfloat)); + + if (!primary_rgba) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_span"); + return; + } + + ASSERT(span->end <= MAX_WIDTH); + + /* + * Save copy of the incoming fragment colors (the GL_PRIMARY_COLOR) + */ + if (swrast->_TextureCombinePrimary) { + GLuint i; + for (i = 0; i < span->end; i++) { + primary_rgba[i][RCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][RCOMP]); + primary_rgba[i][GCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][GCOMP]); + primary_rgba[i][BCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][BCOMP]); + primary_rgba[i][ACOMP] = CHAN_TO_FLOAT(span->array->rgba[i][ACOMP]); + } + } + + /* First must sample all bump maps */ + for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + + if (texUnit->_ReallyEnabled && + texUnit->_CurrentCombine->ModeRGB == GL_BUMP_ENVMAP_ATI) { + const GLfloat (*texcoords)[4] = (const GLfloat (*)[4]) + span->array->attribs[FRAG_ATTRIB_TEX0 + unit]; + float4_array targetcoords = + span->array->attribs[FRAG_ATTRIB_TEX0 + + ctx->Texture.Unit[unit].BumpTarget - GL_TEXTURE0]; + + const struct gl_texture_object *curObj = texUnit->_Current; + GLfloat *lambda = span->array->lambda[unit]; + float4_array texels = get_texel_array(swrast, unit); + GLuint i; + GLfloat rotMatrix00 = ctx->Texture.Unit[unit].RotMatrix[0]; + GLfloat rotMatrix01 = ctx->Texture.Unit[unit].RotMatrix[1]; + GLfloat rotMatrix10 = ctx->Texture.Unit[unit].RotMatrix[2]; + GLfloat rotMatrix11 = ctx->Texture.Unit[unit].RotMatrix[3]; + + /* adjust texture lod (lambda) */ + if (span->arrayMask & SPAN_LAMBDA) { + if (texUnit->LodBias + curObj->LodBias != 0.0F) { + /* apply LOD bias, but don't clamp yet */ + const GLfloat bias = CLAMP(texUnit->LodBias + curObj->LodBias, + -ctx->Const.MaxTextureLodBias, + ctx->Const.MaxTextureLodBias); + GLuint i; + for (i = 0; i < span->end; i++) { + lambda[i] += bias; + } + } + + if (curObj->MinLod != -1000.0 || curObj->MaxLod != 1000.0) { + /* apply LOD clamping to lambda */ + const GLfloat min = curObj->MinLod; + const GLfloat max = curObj->MaxLod; + GLuint i; + for (i = 0; i < span->end; i++) { + GLfloat l = lambda[i]; + lambda[i] = CLAMP(l, min, max); + } + } + } + + /* Sample the texture (span->end = number of fragments) */ + swrast->TextureSample[unit]( ctx, texUnit->_Current, span->end, + texcoords, lambda, texels ); + + /* manipulate the span values of the bump target + not sure this can work correctly even ignoring + the problem that channel is unsigned */ + for (i = 0; i < span->end; i++) { + targetcoords[i][0] += (texels[i][0] * rotMatrix00 + texels[i][1] * + rotMatrix01) / targetcoords[i][3]; + targetcoords[i][1] += (texels[i][0] * rotMatrix10 + texels[i][1] * + rotMatrix11) / targetcoords[i][3]; + } + } + } + + /* + * Must do all texture sampling before combining in order to + * accomodate GL_ARB_texture_env_crossbar. + */ + for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + if (texUnit->_ReallyEnabled && + texUnit->_CurrentCombine->ModeRGB != GL_BUMP_ENVMAP_ATI) { + const GLfloat (*texcoords)[4] = (const GLfloat (*)[4]) + span->array->attribs[FRAG_ATTRIB_TEX0 + unit]; + const struct gl_texture_object *curObj = texUnit->_Current; + GLfloat *lambda = span->array->lambda[unit]; + float4_array texels = get_texel_array(swrast, unit); + + /* adjust texture lod (lambda) */ + if (span->arrayMask & SPAN_LAMBDA) { + if (texUnit->LodBias + curObj->LodBias != 0.0F) { + /* apply LOD bias, but don't clamp yet */ + const GLfloat bias = CLAMP(texUnit->LodBias + curObj->LodBias, + -ctx->Const.MaxTextureLodBias, + ctx->Const.MaxTextureLodBias); + GLuint i; + for (i = 0; i < span->end; i++) { + lambda[i] += bias; + } + } + + if (curObj->MinLod != -1000.0 || curObj->MaxLod != 1000.0) { + /* apply LOD clamping to lambda */ + const GLfloat min = curObj->MinLod; + const GLfloat max = curObj->MaxLod; + GLuint i; + for (i = 0; i < span->end; i++) { + GLfloat l = lambda[i]; + lambda[i] = CLAMP(l, min, max); + } + } + } + + /* Sample the texture (span->end = number of fragments) */ + swrast->TextureSample[unit]( ctx, texUnit->_Current, span->end, + texcoords, lambda, texels ); + + /* GL_EXT_texture_swizzle */ + if (curObj->_Swizzle != SWIZZLE_NOOP) { + swizzle_texels(curObj->_Swizzle, span->end, texels); + } + } + } + + /* + * OK, now apply the texture (aka texture combine/blend). + * We modify the span->color.rgba values. + */ + for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { + if (ctx->Texture.Unit[unit]._ReallyEnabled) { + texture_combine( ctx, unit, span->end, + primary_rgba, + swrast->TexelBuffer, + span->array->rgba ); + } + } + + free(primary_rgba); +} diff --git a/mesalib/src/mesa/vbo/vbo_exec_array.c b/mesalib/src/mesa/vbo/vbo_exec_array.c index 457343a1a..5818b134d 100644 --- a/mesalib/src/mesa/vbo/vbo_exec_array.c +++ b/mesalib/src/mesa/vbo/vbo_exec_array.c @@ -52,6 +52,7 @@ check_buffers_are_unmapped(const struct gl_client_array **inputs) if (inputs[i]) { struct gl_buffer_object *obj = inputs[i]->BufferObj; assert(!_mesa_bufferobj_mapped(obj)); + (void) obj; } } #endif -- cgit v1.2.3