aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2011-03-17 13:49:22 +0000
committermarha <marha@users.sourceforge.net>2011-03-17 13:49:22 +0000
commitd7f1bd4112420f1d4b41c5409074eca6b34bf507 (patch)
treee3673d73657946b3122f5ff05bf19dff5ddeaff6 /mesalib/src
parent5e633abcca598289d0423d89bb400b41e6417259 (diff)
downloadvcxsrv-d7f1bd4112420f1d4b41c5409074eca6b34bf507.tar.gz
vcxsrv-d7f1bd4112420f1d4b41c5409074eca6b34bf507.tar.bz2
vcxsrv-d7f1bd4112420f1d4b41c5409074eca6b34bf507.zip
xserver libX11 mesa git updaet 17 Mar 2011
Diffstat (limited to 'mesalib/src')
-rw-r--r--mesalib/src/glsl/Makefile2
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp7001
-rw-r--r--mesalib/src/glsl/glsl_symbol_table.cpp1
-rw-r--r--mesalib/src/glsl/ir.cpp3144
-rw-r--r--mesalib/src/mesa/Makefile2
-rw-r--r--mesalib/src/mesa/main/extensions.c1898
-rw-r--r--mesalib/src/mesa/main/mtypes.h6724
-rw-r--r--mesalib/src/mesa/main/texobj.c2532
-rw-r--r--mesalib/src/mesa/program/program.c2154
-rw-r--r--mesalib/src/mesa/state_tracker/st_atom_pixeltransfer.c708
-rw-r--r--mesalib/src/mesa/state_tracker/st_cb_drawpixels.c2976
-rw-r--r--mesalib/src/mesa/state_tracker/st_program.c2
12 files changed, 13606 insertions, 13538 deletions
diff --git a/mesalib/src/glsl/Makefile b/mesalib/src/glsl/Makefile
index cd7c41a2a..e4b992dbc 100644
--- a/mesalib/src/glsl/Makefile
+++ b/mesalib/src/glsl/Makefile
@@ -204,7 +204,7 @@ glcpp/glcpp-parse.c: glcpp/glcpp-parse.y
bison -v -o "$@" --defines=glcpp/glcpp-parse.h $<
builtin_compiler: $(GLSL2_OBJECTS) $(OBJECTS) builtin_stubs.o
- $(APP_CXX) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $(OBJECTS) $(GLSL2_OBJECTS) builtin_stubs.o -o $@
+ $(APP_CXX) $(INCLUDES) $(CXXFLAGS) $(LDFLAGS) $(OBJECTS) $(GLSL2_OBJECTS) builtin_stubs.o -o $@
builtin_function.cpp: builtins/profiles/* builtins/ir/* builtins/tools/generate_builtins.py builtins/tools/texture_builtins.py builtin_compiler
@echo Regenerating builtin_function.cpp...
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp
index b8a812d94..cdb16fd49 100644
--- a/mesalib/src/glsl/ast_to_hir.cpp
+++ b/mesalib/src/glsl/ast_to_hir.cpp
@@ -1,3499 +1,3502 @@
-/*
- * Copyright © 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 (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.
- */
-
-/**
- * \file ast_to_hir.c
- * Convert abstract syntax to to high-level intermediate reprensentation (HIR).
- *
- * During the conversion to HIR, the majority of the symantic checking is
- * preformed on the program. This includes:
- *
- * * Symbol table management
- * * Type checking
- * * Function binding
- *
- * The majority of this work could be done during parsing, and the parser could
- * probably generate HIR directly. However, this results in frequent changes
- * to the parser code. Since we do not assume that every system this complier
- * is built on will have Flex and Bison installed, we have to store the code
- * generated by these tools in our version control system. In other parts of
- * the system we've seen problems where a parser was changed but the generated
- * code was not committed, merge conflicts where created because two developers
- * had slightly different versions of Bison installed, etc.
- *
- * I have also noticed that running Bison generated parsers in GDB is very
- * irritating. When you get a segfault on '$$ = $1->foo', you can't very
- * well 'print $1' in GDB.
- *
- * As a result, my preference is to put as little C code as possible in the
- * parser (and lexer) sources.
- */
-
-#include "main/core.h" /* for struct gl_extensions */
-#include "glsl_symbol_table.h"
-#include "glsl_parser_extras.h"
-#include "ast.h"
-#include "glsl_types.h"
-#include "ir.h"
-
-void
-_mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
-{
- _mesa_glsl_initialize_variables(instructions, state);
- _mesa_glsl_initialize_functions(state);
-
- state->symbols->language_version = state->language_version;
-
- state->current_function = NULL;
-
- /* Section 4.2 of the GLSL 1.20 specification states:
- * "The built-in functions are scoped in a scope outside the global scope
- * users declare global variables in. That is, a shader's global scope,
- * available for user-defined functions and global variables, is nested
- * inside the scope containing the built-in functions."
- *
- * Since built-in functions like ftransform() access built-in variables,
- * it follows that those must be in the outer scope as well.
- *
- * We push scope here to create this nesting effect...but don't pop.
- * This way, a shader's globals are still in the symbol table for use
- * by the linker.
- */
- state->symbols->push_scope();
-
- foreach_list_typed (ast_node, ast, link, & state->translation_unit)
- ast->hir(instructions, state);
-}
-
-
-/**
- * If a conversion is available, convert one operand to a different type
- *
- * The \c from \c ir_rvalue is converted "in place".
- *
- * \param to Type that the operand it to be converted to
- * \param from Operand that is being converted
- * \param state GLSL compiler state
- *
- * \return
- * If a conversion is possible (or unnecessary), \c true is returned.
- * Otherwise \c false is returned.
- */
-bool
-apply_implicit_conversion(const glsl_type *to, ir_rvalue * &from,
- struct _mesa_glsl_parse_state *state)
-{
- void *ctx = state;
- if (to->base_type == from->type->base_type)
- return true;
-
- /* This conversion was added in GLSL 1.20. If the compilation mode is
- * GLSL 1.10, the conversion is skipped.
- */
- if (state->language_version < 120)
- return false;
-
- /* From page 27 (page 33 of the PDF) of the GLSL 1.50 spec:
- *
- * "There are no implicit array or structure conversions. For
- * example, an array of int cannot be implicitly converted to an
- * array of float. There are no implicit conversions between
- * signed and unsigned integers."
- */
- /* FINISHME: The above comment is partially a lie. There is int/uint
- * FINISHME: conversion for immediate constants.
- */
- if (!to->is_float() || !from->type->is_numeric())
- return false;
-
- /* Convert to a floating point type with the same number of components
- * as the original type - i.e. int to float, not int to vec4.
- */
- to = glsl_type::get_instance(GLSL_TYPE_FLOAT, from->type->vector_elements,
- from->type->matrix_columns);
-
- switch (from->type->base_type) {
- case GLSL_TYPE_INT:
- from = new(ctx) ir_expression(ir_unop_i2f, to, from, NULL);
- break;
- case GLSL_TYPE_UINT:
- from = new(ctx) ir_expression(ir_unop_u2f, to, from, NULL);
- break;
- case GLSL_TYPE_BOOL:
- from = new(ctx) ir_expression(ir_unop_b2f, to, from, NULL);
- break;
- default:
- assert(0);
- }
-
- return true;
-}
-
-
-static const struct glsl_type *
-arithmetic_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b,
- bool multiply,
- struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
-{
- const glsl_type *type_a = value_a->type;
- const glsl_type *type_b = value_b->type;
-
- /* From GLSL 1.50 spec, page 56:
- *
- * "The arithmetic binary operators add (+), subtract (-),
- * multiply (*), and divide (/) operate on integer and
- * floating-point scalars, vectors, and matrices."
- */
- if (!type_a->is_numeric() || !type_b->is_numeric()) {
- _mesa_glsl_error(loc, state,
- "Operands to arithmetic operators must be numeric");
- return glsl_type::error_type;
- }
-
-
- /* "If one operand is floating-point based and the other is
- * not, then the conversions from Section 4.1.10 "Implicit
- * Conversions" are applied to the non-floating-point-based operand."
- */
- if (!apply_implicit_conversion(type_a, value_b, state)
- && !apply_implicit_conversion(type_b, value_a, state)) {
- _mesa_glsl_error(loc, state,
- "Could not implicitly convert operands to "
- "arithmetic operator");
- return glsl_type::error_type;
- }
- type_a = value_a->type;
- type_b = value_b->type;
-
- /* "If the operands are integer types, they must both be signed or
- * both be unsigned."
- *
- * From this rule and the preceeding conversion it can be inferred that
- * both types must be GLSL_TYPE_FLOAT, or GLSL_TYPE_UINT, or GLSL_TYPE_INT.
- * The is_numeric check above already filtered out the case where either
- * type is not one of these, so now the base types need only be tested for
- * equality.
- */
- if (type_a->base_type != type_b->base_type) {
- _mesa_glsl_error(loc, state,
- "base type mismatch for arithmetic operator");
- return glsl_type::error_type;
- }
-
- /* "All arithmetic binary operators result in the same fundamental type
- * (signed integer, unsigned integer, or floating-point) as the
- * operands they operate on, after operand type conversion. After
- * conversion, the following cases are valid
- *
- * * The two operands are scalars. In this case the operation is
- * applied, resulting in a scalar."
- */
- if (type_a->is_scalar() && type_b->is_scalar())
- return type_a;
-
- /* "* One operand is a scalar, and the other is a vector or matrix.
- * In this case, the scalar operation is applied independently to each
- * component of the vector or matrix, resulting in the same size
- * vector or matrix."
- */
- if (type_a->is_scalar()) {
- if (!type_b->is_scalar())
- return type_b;
- } else if (type_b->is_scalar()) {
- return type_a;
- }
-
- /* All of the combinations of <scalar, scalar>, <vector, scalar>,
- * <scalar, vector>, <scalar, matrix>, and <matrix, scalar> have been
- * handled.
- */
- assert(!type_a->is_scalar());
- assert(!type_b->is_scalar());
-
- /* "* The two operands are vectors of the same size. In this case, the
- * operation is done component-wise resulting in the same size
- * vector."
- */
- if (type_a->is_vector() && type_b->is_vector()) {
- if (type_a == type_b) {
- return type_a;
- } else {
- _mesa_glsl_error(loc, state,
- "vector size mismatch for arithmetic operator");
- return glsl_type::error_type;
- }
- }
-
- /* All of the combinations of <scalar, scalar>, <vector, scalar>,
- * <scalar, vector>, <scalar, matrix>, <matrix, scalar>, and
- * <vector, vector> have been handled. At least one of the operands must
- * be matrix. Further, since there are no integer matrix types, the base
- * type of both operands must be float.
- */
- assert(type_a->is_matrix() || type_b->is_matrix());
- assert(type_a->base_type == GLSL_TYPE_FLOAT);
- assert(type_b->base_type == GLSL_TYPE_FLOAT);
-
- /* "* The operator is add (+), subtract (-), or divide (/), and the
- * operands are matrices with the same number of rows and the same
- * number of columns. In this case, the operation is done component-
- * wise resulting in the same size matrix."
- * * The operator is multiply (*), where both operands are matrices or
- * one operand is a vector and the other a matrix. A right vector
- * operand is treated as a column vector and a left vector operand as a
- * row vector. In all these cases, it is required that the number of
- * columns of the left operand is equal to the number of rows of the
- * right operand. Then, the multiply (*) operation does a linear
- * algebraic multiply, yielding an object that has the same number of
- * rows as the left operand and the same number of columns as the right
- * operand. Section 5.10 "Vector and Matrix Operations" explains in
- * more detail how vectors and matrices are operated on."
- */
- if (! multiply) {
- if (type_a == type_b)
- return type_a;
- } else {
- if (type_a->is_matrix() && type_b->is_matrix()) {
- /* Matrix multiply. The columns of A must match the rows of B. Given
- * the other previously tested constraints, this means the vector type
- * of a row from A must be the same as the vector type of a column from
- * B.
- */
- if (type_a->row_type() == type_b->column_type()) {
- /* The resulting matrix has the number of columns of matrix B and
- * the number of rows of matrix A. We get the row count of A by
- * looking at the size of a vector that makes up a column. The
- * transpose (size of a row) is done for B.
- */
- const glsl_type *const type =
- glsl_type::get_instance(type_a->base_type,
- type_a->column_type()->vector_elements,
- type_b->row_type()->vector_elements);
- assert(type != glsl_type::error_type);
-
- return type;
- }
- } else if (type_a->is_matrix()) {
- /* A is a matrix and B is a column vector. Columns of A must match
- * rows of B. Given the other previously tested constraints, this
- * means the vector type of a row from A must be the same as the
- * vector the type of B.
- */
- if (type_a->row_type() == type_b) {
- /* The resulting vector has a number of elements equal to
- * the number of rows of matrix A. */
- const glsl_type *const type =
- glsl_type::get_instance(type_a->base_type,
- type_a->column_type()->vector_elements,
- 1);
- assert(type != glsl_type::error_type);
-
- return type;
- }
- } else {
- assert(type_b->is_matrix());
-
- /* A is a row vector and B is a matrix. Columns of A must match rows
- * of B. Given the other previously tested constraints, this means
- * the type of A must be the same as the vector type of a column from
- * B.
- */
- if (type_a == type_b->column_type()) {
- /* The resulting vector has a number of elements equal to
- * the number of columns of matrix B. */
- const glsl_type *const type =
- glsl_type::get_instance(type_a->base_type,
- type_b->row_type()->vector_elements,
- 1);
- assert(type != glsl_type::error_type);
-
- return type;
- }
- }
-
- _mesa_glsl_error(loc, state, "size mismatch for matrix multiplication");
- return glsl_type::error_type;
- }
-
-
- /* "All other cases are illegal."
- */
- _mesa_glsl_error(loc, state, "type mismatch");
- return glsl_type::error_type;
-}
-
-
-static const struct glsl_type *
-unary_arithmetic_result_type(const struct glsl_type *type,
- struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
-{
- /* From GLSL 1.50 spec, page 57:
- *
- * "The arithmetic unary operators negate (-), post- and pre-increment
- * and decrement (-- and ++) operate on integer or floating-point
- * values (including vectors and matrices). All unary operators work
- * component-wise on their operands. These result with the same type
- * they operated on."
- */
- if (!type->is_numeric()) {
- _mesa_glsl_error(loc, state,
- "Operands to arithmetic operators must be numeric");
- return glsl_type::error_type;
- }
-
- return type;
-}
-
-/**
- * \brief Return the result type of a bit-logic operation.
- *
- * If the given types to the bit-logic operator are invalid, return
- * glsl_type::error_type.
- *
- * \param type_a Type of LHS of bit-logic op
- * \param type_b Type of RHS of bit-logic op
- */
-static const struct glsl_type *
-bit_logic_result_type(const struct glsl_type *type_a,
- const struct glsl_type *type_b,
- ast_operators op,
- struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
-{
- if (state->language_version < 130) {
- _mesa_glsl_error(loc, state, "bit operations require GLSL 1.30");
- return glsl_type::error_type;
- }
-
- /* From page 50 (page 56 of PDF) of GLSL 1.30 spec:
- *
- * "The bitwise operators and (&), exclusive-or (^), and inclusive-or
- * (|). The operands must be of type signed or unsigned integers or
- * integer vectors."
- */
- if (!type_a->is_integer()) {
- _mesa_glsl_error(loc, state, "LHS of `%s' must be an integer",
- ast_expression::operator_string(op));
- return glsl_type::error_type;
- }
- if (!type_b->is_integer()) {
- _mesa_glsl_error(loc, state, "RHS of `%s' must be an integer",
- ast_expression::operator_string(op));
- return glsl_type::error_type;
- }
-
- /* "The fundamental types of the operands (signed or unsigned) must
- * match,"
- */
- if (type_a->base_type != type_b->base_type) {
- _mesa_glsl_error(loc, state, "operands of `%s' must have the same "
- "base type", ast_expression::operator_string(op));
- return glsl_type::error_type;
- }
-
- /* "The operands cannot be vectors of differing size." */
- if (type_a->is_vector() &&
- type_b->is_vector() &&
- type_a->vector_elements != type_b->vector_elements) {
- _mesa_glsl_error(loc, state, "operands of `%s' cannot be vectors of "
- "different sizes", ast_expression::operator_string(op));
- return glsl_type::error_type;
- }
-
- /* "If one operand is a scalar and the other a vector, the scalar is
- * applied component-wise to the vector, resulting in the same type as
- * the vector. The fundamental types of the operands [...] will be the
- * resulting fundamental type."
- */
- if (type_a->is_scalar())
- return type_b;
- else
- return type_a;
-}
-
-static const struct glsl_type *
-modulus_result_type(const struct glsl_type *type_a,
- const struct glsl_type *type_b,
- struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
-{
- if (state->language_version < 130) {
- _mesa_glsl_error(loc, state,
- "operator '%%' is reserved in %s",
- state->version_string);
- return glsl_type::error_type;
- }
-
- /* From GLSL 1.50 spec, page 56:
- * "The operator modulus (%) operates on signed or unsigned integers or
- * integer vectors. The operand types must both be signed or both be
- * unsigned."
- */
- if (!type_a->is_integer() || !type_b->is_integer()
- || (type_a->base_type != type_b->base_type)) {
- _mesa_glsl_error(loc, state, "type mismatch");
- return glsl_type::error_type;
- }
-
- /* "The operands cannot be vectors of differing size. If one operand is
- * a scalar and the other vector, then the scalar is applied component-
- * wise to the vector, resulting in the same type as the vector. If both
- * are vectors of the same size, the result is computed component-wise."
- */
- if (type_a->is_vector()) {
- if (!type_b->is_vector()
- || (type_a->vector_elements == type_b->vector_elements))
- return type_a;
- } else
- return type_b;
-
- /* "The operator modulus (%) is not defined for any other data types
- * (non-integer types)."
- */
- _mesa_glsl_error(loc, state, "type mismatch");
- return glsl_type::error_type;
-}
-
-
-static const struct glsl_type *
-relational_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b,
- struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
-{
- const glsl_type *type_a = value_a->type;
- const glsl_type *type_b = value_b->type;
-
- /* From GLSL 1.50 spec, page 56:
- * "The relational operators greater than (>), less than (<), greater
- * than or equal (>=), and less than or equal (<=) operate only on
- * scalar integer and scalar floating-point expressions."
- */
- if (!type_a->is_numeric()
- || !type_b->is_numeric()
- || !type_a->is_scalar()
- || !type_b->is_scalar()) {
- _mesa_glsl_error(loc, state,
- "Operands to relational operators must be scalar and "
- "numeric");
- return glsl_type::error_type;
- }
-
- /* "Either the operands' types must match, or the conversions from
- * Section 4.1.10 "Implicit Conversions" will be applied to the integer
- * operand, after which the types must match."
- */
- if (!apply_implicit_conversion(type_a, value_b, state)
- && !apply_implicit_conversion(type_b, value_a, state)) {
- _mesa_glsl_error(loc, state,
- "Could not implicitly convert operands to "
- "relational operator");
- return glsl_type::error_type;
- }
- type_a = value_a->type;
- type_b = value_b->type;
-
- if (type_a->base_type != type_b->base_type) {
- _mesa_glsl_error(loc, state, "base type mismatch");
- return glsl_type::error_type;
- }
-
- /* "The result is scalar Boolean."
- */
- return glsl_type::bool_type;
-}
-
-/**
- * \brief Return the result type of a bit-shift operation.
- *
- * If the given types to the bit-shift operator are invalid, return
- * glsl_type::error_type.
- *
- * \param type_a Type of LHS of bit-shift op
- * \param type_b Type of RHS of bit-shift op
- */
-static const struct glsl_type *
-shift_result_type(const struct glsl_type *type_a,
- const struct glsl_type *type_b,
- ast_operators op,
- struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
-{
- if (state->language_version < 130) {
- _mesa_glsl_error(loc, state, "bit operations require GLSL 1.30");
- return glsl_type::error_type;
- }
-
- /* From page 50 (page 56 of the PDF) of the GLSL 1.30 spec:
- *
- * "The shift operators (<<) and (>>). For both operators, the operands
- * must be signed or unsigned integers or integer vectors. One operand
- * can be signed while the other is unsigned."
- */
- if (!type_a->is_integer()) {
- _mesa_glsl_error(loc, state, "LHS of operator %s must be an integer or "
- "integer vector", ast_expression::operator_string(op));
- return glsl_type::error_type;
-
- }
- if (!type_b->is_integer()) {
- _mesa_glsl_error(loc, state, "RHS of operator %s must be an integer or "
- "integer vector", ast_expression::operator_string(op));
- return glsl_type::error_type;
- }
-
- /* "If the first operand is a scalar, the second operand has to be
- * a scalar as well."
- */
- if (type_a->is_scalar() && !type_b->is_scalar()) {
- _mesa_glsl_error(loc, state, "If the first operand of %s is scalar, the "
- "second must be scalar as well",
- ast_expression::operator_string(op));
- return glsl_type::error_type;
- }
-
- /* If both operands are vectors, check that they have same number of
- * elements.
- */
- if (type_a->is_vector() &&
- type_b->is_vector() &&
- type_a->vector_elements != type_b->vector_elements) {
- _mesa_glsl_error(loc, state, "Vector operands to operator %s must "
- "have same number of elements",
- ast_expression::operator_string(op));
- return glsl_type::error_type;
- }
-
- /* "In all cases, the resulting type will be the same type as the left
- * operand."
- */
- return type_a;
-}
-
-/**
- * Validates that a value can be assigned to a location with a specified type
- *
- * Validates that \c rhs can be assigned to some location. If the types are
- * not an exact match but an automatic conversion is possible, \c rhs will be
- * converted.
- *
- * \return
- * \c NULL if \c rhs cannot be assigned to a location with type \c lhs_type.
- * Otherwise the actual RHS to be assigned will be returned. This may be
- * \c rhs, or it may be \c rhs after some type conversion.
- *
- * \note
- * In addition to being used for assignments, this function is used to
- * type-check return values.
- */
-ir_rvalue *
-validate_assignment(struct _mesa_glsl_parse_state *state,
- const glsl_type *lhs_type, ir_rvalue *rhs)
-{
- /* If there is already some error in the RHS, just return it. Anything
- * else will lead to an avalanche of error message back to the user.
- */
- if (rhs->type->is_error())
- return rhs;
-
- /* If the types are identical, the assignment can trivially proceed.
- */
- if (rhs->type == lhs_type)
- return rhs;
-
- /* If the array element types are the same and the size of the LHS is zero,
- * the assignment is okay.
- *
- * Note: Whole-array assignments are not permitted in GLSL 1.10, but this
- * is handled by ir_dereference::is_lvalue.
- */
- if (lhs_type->is_array() && rhs->type->is_array()
- && (lhs_type->element_type() == rhs->type->element_type())
- && (lhs_type->array_size() == 0)) {
- return rhs;
- }
-
- /* Check for implicit conversion in GLSL 1.20 */
- if (apply_implicit_conversion(lhs_type, rhs, state)) {
- if (rhs->type == lhs_type)
- return rhs;
- }
-
- return NULL;
-}
-
-ir_rvalue *
-do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
- ir_rvalue *lhs, ir_rvalue *rhs,
- YYLTYPE lhs_loc)
-{
- void *ctx = state;
- bool error_emitted = (lhs->type->is_error() || rhs->type->is_error());
-
- if (!error_emitted) {
- if (lhs->variable_referenced() != NULL
- && lhs->variable_referenced()->read_only) {
- _mesa_glsl_error(&lhs_loc, state,
- "assignment to read-only variable '%s'",
- lhs->variable_referenced()->name);
- error_emitted = true;
-
- } else if (!lhs->is_lvalue()) {
- _mesa_glsl_error(& lhs_loc, state, "non-lvalue in assignment");
- error_emitted = true;
- }
-
- if (state->es_shader && lhs->type->is_array()) {
- _mesa_glsl_error(&lhs_loc, state, "whole array assignment is not "
- "allowed in GLSL ES 1.00.");
- error_emitted = true;
- }
- }
-
- ir_rvalue *new_rhs = validate_assignment(state, lhs->type, rhs);
- if (new_rhs == NULL) {
- _mesa_glsl_error(& lhs_loc, state, "type mismatch");
- } else {
- rhs = new_rhs;
-
- /* If the LHS array was not declared with a size, it takes it size from
- * the RHS. If the LHS is an l-value and a whole array, it must be a
- * dereference of a variable. Any other case would require that the LHS
- * is either not an l-value or not a whole array.
- */
- if (lhs->type->array_size() == 0) {
- ir_dereference *const d = lhs->as_dereference();
-
- assert(d != NULL);
-
- ir_variable *const var = d->variable_referenced();
-
- assert(var != NULL);
-
- if (var->max_array_access >= unsigned(rhs->type->array_size())) {
- /* FINISHME: This should actually log the location of the RHS. */
- _mesa_glsl_error(& lhs_loc, state, "array size must be > %u due to "
- "previous access",
- var->max_array_access);
- }
-
- var->type = glsl_type::get_array_instance(lhs->type->element_type(),
- rhs->type->array_size());
- d->type = var->type;
- }
- }
-
- /* Most callers of do_assignment (assign, add_assign, pre_inc/dec,
- * but not post_inc) need the converted assigned value as an rvalue
- * to handle things like:
- *
- * i = j += 1;
- *
- * So we always just store the computed value being assigned to a
- * temporary and return a deref of that temporary. If the rvalue
- * ends up not being used, the temp will get copy-propagated out.
- */
- ir_variable *var = new(ctx) ir_variable(rhs->type, "assignment_tmp",
- ir_var_temporary);
- ir_dereference_variable *deref_var = new(ctx) ir_dereference_variable(var);
- instructions->push_tail(var);
- instructions->push_tail(new(ctx) ir_assignment(deref_var,
- rhs,
- NULL));
- deref_var = new(ctx) ir_dereference_variable(var);
-
- if (!error_emitted)
- instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var, NULL));
-
- return new(ctx) ir_dereference_variable(var);
-}
-
-static ir_rvalue *
-get_lvalue_copy(exec_list *instructions, ir_rvalue *lvalue)
-{
- void *ctx = ralloc_parent(lvalue);
- ir_variable *var;
-
- var = new(ctx) ir_variable(lvalue->type, "_post_incdec_tmp",
- ir_var_temporary);
- instructions->push_tail(var);
- var->mode = ir_var_auto;
-
- instructions->push_tail(new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var),
- lvalue, NULL));
-
- /* Once we've created this temporary, mark it read only so it's no
- * longer considered an lvalue.
- */
- var->read_only = true;
-
- return new(ctx) ir_dereference_variable(var);
-}
-
-
-ir_rvalue *
-ast_node::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- (void) instructions;
- (void) state;
-
- return NULL;
-}
-
-static void
-mark_whole_array_access(ir_rvalue *access)
-{
- ir_dereference_variable *deref = access->as_dereference_variable();
-
- if (deref) {
- deref->var->max_array_access = deref->type->length - 1;
- }
-}
-
-static ir_rvalue *
-do_comparison(void *mem_ctx, int operation, ir_rvalue *op0, ir_rvalue *op1)
-{
- int join_op;
- ir_rvalue *cmp = NULL;
-
- if (operation == ir_binop_all_equal)
- join_op = ir_binop_logic_and;
- else
- join_op = ir_binop_logic_or;
-
- switch (op0->type->base_type) {
- case GLSL_TYPE_FLOAT:
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT:
- case GLSL_TYPE_BOOL:
- return new(mem_ctx) ir_expression(operation, op0, op1);
-
- case GLSL_TYPE_ARRAY: {
- for (unsigned int i = 0; i < op0->type->length; i++) {
- ir_rvalue *e0, *e1, *result;
-
- e0 = new(mem_ctx) ir_dereference_array(op0->clone(mem_ctx, NULL),
- new(mem_ctx) ir_constant(i));
- e1 = new(mem_ctx) ir_dereference_array(op1->clone(mem_ctx, NULL),
- new(mem_ctx) ir_constant(i));
- result = do_comparison(mem_ctx, operation, e0, e1);
-
- if (cmp) {
- cmp = new(mem_ctx) ir_expression(join_op, cmp, result);
- } else {
- cmp = result;
- }
- }
-
- mark_whole_array_access(op0);
- mark_whole_array_access(op1);
- break;
- }
-
- case GLSL_TYPE_STRUCT: {
- for (unsigned int i = 0; i < op0->type->length; i++) {
- ir_rvalue *e0, *e1, *result;
- const char *field_name = op0->type->fields.structure[i].name;
-
- e0 = new(mem_ctx) ir_dereference_record(op0->clone(mem_ctx, NULL),
- field_name);
- e1 = new(mem_ctx) ir_dereference_record(op1->clone(mem_ctx, NULL),
- field_name);
- result = do_comparison(mem_ctx, operation, e0, e1);
-
- if (cmp) {
- cmp = new(mem_ctx) ir_expression(join_op, cmp, result);
- } else {
- cmp = result;
- }
- }
- break;
- }
-
- case GLSL_TYPE_ERROR:
- case GLSL_TYPE_VOID:
- case GLSL_TYPE_SAMPLER:
- /* I assume a comparison of a struct containing a sampler just
- * ignores the sampler present in the type.
- */
- break;
-
- default:
- assert(!"Should not get here.");
- break;
- }
-
- if (cmp == NULL)
- cmp = new(mem_ctx) ir_constant(true);
-
- return cmp;
-}
-
-ir_rvalue *
-ast_expression::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- void *ctx = state;
- static const int operations[AST_NUM_OPERATORS] = {
- -1, /* ast_assign doesn't convert to ir_expression. */
- -1, /* ast_plus doesn't convert to ir_expression. */
- ir_unop_neg,
- ir_binop_add,
- ir_binop_sub,
- ir_binop_mul,
- ir_binop_div,
- ir_binop_mod,
- ir_binop_lshift,
- ir_binop_rshift,
- ir_binop_less,
- ir_binop_greater,
- ir_binop_lequal,
- ir_binop_gequal,
- ir_binop_all_equal,
- ir_binop_any_nequal,
- ir_binop_bit_and,
- ir_binop_bit_xor,
- ir_binop_bit_or,
- ir_unop_bit_not,
- ir_binop_logic_and,
- ir_binop_logic_xor,
- ir_binop_logic_or,
- ir_unop_logic_not,
-
- /* Note: The following block of expression types actually convert
- * to multiple IR instructions.
- */
- ir_binop_mul, /* ast_mul_assign */
- ir_binop_div, /* ast_div_assign */
- ir_binop_mod, /* ast_mod_assign */
- ir_binop_add, /* ast_add_assign */
- ir_binop_sub, /* ast_sub_assign */
- ir_binop_lshift, /* ast_ls_assign */
- ir_binop_rshift, /* ast_rs_assign */
- ir_binop_bit_and, /* ast_and_assign */
- ir_binop_bit_xor, /* ast_xor_assign */
- ir_binop_bit_or, /* ast_or_assign */
-
- -1, /* ast_conditional doesn't convert to ir_expression. */
- ir_binop_add, /* ast_pre_inc. */
- ir_binop_sub, /* ast_pre_dec. */
- ir_binop_add, /* ast_post_inc. */
- ir_binop_sub, /* ast_post_dec. */
- -1, /* ast_field_selection doesn't conv to ir_expression. */
- -1, /* ast_array_index doesn't convert to ir_expression. */
- -1, /* ast_function_call doesn't conv to ir_expression. */
- -1, /* ast_identifier doesn't convert to ir_expression. */
- -1, /* ast_int_constant doesn't convert to ir_expression. */
- -1, /* ast_uint_constant doesn't conv to ir_expression. */
- -1, /* ast_float_constant doesn't conv to ir_expression. */
- -1, /* ast_bool_constant doesn't conv to ir_expression. */
- -1, /* ast_sequence doesn't convert to ir_expression. */
- };
- ir_rvalue *result = NULL;
- ir_rvalue *op[3];
- const struct glsl_type *type = glsl_type::error_type;
- bool error_emitted = false;
- YYLTYPE loc;
-
- loc = this->get_location();
-
- switch (this->oper) {
- case ast_assign: {
- op[0] = this->subexpressions[0]->hir(instructions, state);
- op[1] = this->subexpressions[1]->hir(instructions, state);
-
- result = do_assignment(instructions, state, op[0], op[1],
- this->subexpressions[0]->get_location());
- error_emitted = result->type->is_error();
- type = result->type;
- break;
- }
-
- case ast_plus:
- op[0] = this->subexpressions[0]->hir(instructions, state);
-
- type = unary_arithmetic_result_type(op[0]->type, state, & loc);
-
- error_emitted = type->is_error();
-
- result = op[0];
- break;
-
- case ast_neg:
- op[0] = this->subexpressions[0]->hir(instructions, state);
-
- type = unary_arithmetic_result_type(op[0]->type, state, & loc);
-
- error_emitted = type->is_error();
-
- result = new(ctx) ir_expression(operations[this->oper], type,
- op[0], NULL);
- break;
-
- case ast_add:
- case ast_sub:
- case ast_mul:
- case ast_div:
- op[0] = this->subexpressions[0]->hir(instructions, state);
- op[1] = this->subexpressions[1]->hir(instructions, state);
-
- type = arithmetic_result_type(op[0], op[1],
- (this->oper == ast_mul),
- state, & loc);
- error_emitted = type->is_error();
-
- result = new(ctx) ir_expression(operations[this->oper], type,
- op[0], op[1]);
- break;
-
- case ast_mod:
- op[0] = this->subexpressions[0]->hir(instructions, state);
- op[1] = this->subexpressions[1]->hir(instructions, state);
-
- type = modulus_result_type(op[0]->type, op[1]->type, state, & loc);
-
- assert(operations[this->oper] == ir_binop_mod);
-
- result = new(ctx) ir_expression(operations[this->oper], type,
- op[0], op[1]);
- error_emitted = type->is_error();
- break;
-
- case ast_lshift:
- case ast_rshift:
- if (state->language_version < 130) {
- _mesa_glsl_error(&loc, state, "operator %s requires GLSL 1.30",
- operator_string(this->oper));
- error_emitted = true;
- }
-
- op[0] = this->subexpressions[0]->hir(instructions, state);
- op[1] = this->subexpressions[1]->hir(instructions, state);
- type = shift_result_type(op[0]->type, op[1]->type, this->oper, state,
- &loc);
- result = new(ctx) ir_expression(operations[this->oper], type,
- op[0], op[1]);
- error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
- break;
-
- case ast_less:
- case ast_greater:
- case ast_lequal:
- case ast_gequal:
- op[0] = this->subexpressions[0]->hir(instructions, state);
- op[1] = this->subexpressions[1]->hir(instructions, state);
-
- type = relational_result_type(op[0], op[1], state, & loc);
-
- /* The relational operators must either generate an error or result
- * in a scalar boolean. See page 57 of the GLSL 1.50 spec.
- */
- assert(type->is_error()
- || ((type->base_type == GLSL_TYPE_BOOL)
- && type->is_scalar()));
-
- result = new(ctx) ir_expression(operations[this->oper], type,
- op[0], op[1]);
- error_emitted = type->is_error();
- break;
-
- case ast_nequal:
- case ast_equal:
- op[0] = this->subexpressions[0]->hir(instructions, state);
- op[1] = this->subexpressions[1]->hir(instructions, state);
-
- /* From page 58 (page 64 of the PDF) of the GLSL 1.50 spec:
- *
- * "The equality operators equal (==), and not equal (!=)
- * operate on all types. They result in a scalar Boolean. If
- * the operand types do not match, then there must be a
- * conversion from Section 4.1.10 "Implicit Conversions"
- * applied to one operand that can make them match, in which
- * case this conversion is done."
- */
- if ((!apply_implicit_conversion(op[0]->type, op[1], state)
- && !apply_implicit_conversion(op[1]->type, op[0], state))
- || (op[0]->type != op[1]->type)) {
- _mesa_glsl_error(& loc, state, "operands of `%s' must have the same "
- "type", (this->oper == ast_equal) ? "==" : "!=");
- error_emitted = true;
- } else if ((state->language_version <= 110)
- && (op[0]->type->is_array() || op[1]->type->is_array())) {
- _mesa_glsl_error(& loc, state, "array comparisons forbidden in "
- "GLSL 1.10");
- error_emitted = true;
- }
-
- result = do_comparison(ctx, operations[this->oper], op[0], op[1]);
- type = glsl_type::bool_type;
-
- assert(error_emitted || (result->type == glsl_type::bool_type));
- break;
-
- case ast_bit_and:
- case ast_bit_xor:
- case ast_bit_or:
- op[0] = this->subexpressions[0]->hir(instructions, state);
- op[1] = this->subexpressions[1]->hir(instructions, state);
- type = bit_logic_result_type(op[0]->type, op[1]->type, this->oper,
- state, &loc);
- result = new(ctx) ir_expression(operations[this->oper], type,
- op[0], op[1]);
- error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
- break;
-
- case ast_bit_not:
- op[0] = this->subexpressions[0]->hir(instructions, state);
-
- if (state->language_version < 130) {
- _mesa_glsl_error(&loc, state, "bit-wise operations require GLSL 1.30");
- error_emitted = true;
- }
-
- if (!op[0]->type->is_integer()) {
- _mesa_glsl_error(&loc, state, "operand of `~' must be an integer");
- error_emitted = true;
- }
-
- type = op[0]->type;
- result = new(ctx) ir_expression(ir_unop_bit_not, type, op[0], NULL);
- break;
-
- case ast_logic_and: {
- op[0] = this->subexpressions[0]->hir(instructions, state);
-
- if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) {
- YYLTYPE loc = this->subexpressions[0]->get_location();
-
- _mesa_glsl_error(& loc, state, "LHS of `%s' must be scalar boolean",
- operator_string(this->oper));
- error_emitted = true;
- }
-
- ir_constant *op0_const = op[0]->constant_expression_value();
- if (op0_const) {
- if (op0_const->value.b[0]) {
- op[1] = this->subexpressions[1]->hir(instructions, state);
-
- if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
- YYLTYPE loc = this->subexpressions[1]->get_location();
-
- _mesa_glsl_error(& loc, state,
- "RHS of `%s' must be scalar boolean",
- operator_string(this->oper));
- error_emitted = true;
- }
- result = op[1];
- } else {
- result = op0_const;
- }
- type = glsl_type::bool_type;
- } else {
- ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type,
- "and_tmp",
- ir_var_temporary);
- instructions->push_tail(tmp);
-
- ir_if *const stmt = new(ctx) ir_if(op[0]);
- instructions->push_tail(stmt);
-
- op[1] = this->subexpressions[1]->hir(&stmt->then_instructions, state);
-
- if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
- YYLTYPE loc = this->subexpressions[1]->get_location();
-
- _mesa_glsl_error(& loc, state,
- "RHS of `%s' must be scalar boolean",
- operator_string(this->oper));
- error_emitted = true;
- }
-
- ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp);
- ir_assignment *const then_assign =
- new(ctx) ir_assignment(then_deref, op[1], NULL);
- stmt->then_instructions.push_tail(then_assign);
-
- ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp);
- ir_assignment *const else_assign =
- new(ctx) ir_assignment(else_deref, new(ctx) ir_constant(false), NULL);
- stmt->else_instructions.push_tail(else_assign);
-
- result = new(ctx) ir_dereference_variable(tmp);
- type = tmp->type;
- }
- break;
- }
-
- case ast_logic_or: {
- op[0] = this->subexpressions[0]->hir(instructions, state);
-
- if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) {
- YYLTYPE loc = this->subexpressions[0]->get_location();
-
- _mesa_glsl_error(& loc, state, "LHS of `%s' must be scalar boolean",
- operator_string(this->oper));
- error_emitted = true;
- }
-
- ir_constant *op0_const = op[0]->constant_expression_value();
- if (op0_const) {
- if (op0_const->value.b[0]) {
- result = op0_const;
- } else {
- op[1] = this->subexpressions[1]->hir(instructions, state);
-
- if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
- YYLTYPE loc = this->subexpressions[1]->get_location();
-
- _mesa_glsl_error(& loc, state,
- "RHS of `%s' must be scalar boolean",
- operator_string(this->oper));
- error_emitted = true;
- }
- result = op[1];
- }
- type = glsl_type::bool_type;
- } else {
- ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type,
- "or_tmp",
- ir_var_temporary);
- instructions->push_tail(tmp);
-
- ir_if *const stmt = new(ctx) ir_if(op[0]);
- instructions->push_tail(stmt);
-
- op[1] = this->subexpressions[1]->hir(&stmt->else_instructions, state);
-
- if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
- YYLTYPE loc = this->subexpressions[1]->get_location();
-
- _mesa_glsl_error(& loc, state, "RHS of `%s' must be scalar boolean",
- operator_string(this->oper));
- error_emitted = true;
- }
-
- ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp);
- ir_assignment *const then_assign =
- new(ctx) ir_assignment(then_deref, new(ctx) ir_constant(true), NULL);
- stmt->then_instructions.push_tail(then_assign);
-
- ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp);
- ir_assignment *const else_assign =
- new(ctx) ir_assignment(else_deref, op[1], NULL);
- stmt->else_instructions.push_tail(else_assign);
-
- result = new(ctx) ir_dereference_variable(tmp);
- type = tmp->type;
- }
- break;
- }
-
- case ast_logic_xor:
- op[0] = this->subexpressions[0]->hir(instructions, state);
- op[1] = this->subexpressions[1]->hir(instructions, state);
-
-
- result = new(ctx) ir_expression(operations[this->oper], glsl_type::bool_type,
- op[0], op[1]);
- type = glsl_type::bool_type;
- break;
-
- case ast_logic_not:
- op[0] = this->subexpressions[0]->hir(instructions, state);
-
- if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) {
- YYLTYPE loc = this->subexpressions[0]->get_location();
-
- _mesa_glsl_error(& loc, state,
- "operand of `!' must be scalar boolean");
- error_emitted = true;
- }
-
- result = new(ctx) ir_expression(operations[this->oper], glsl_type::bool_type,
- op[0], NULL);
- type = glsl_type::bool_type;
- break;
-
- case ast_mul_assign:
- case ast_div_assign:
- case ast_add_assign:
- case ast_sub_assign: {
- op[0] = this->subexpressions[0]->hir(instructions, state);
- op[1] = this->subexpressions[1]->hir(instructions, state);
-
- type = arithmetic_result_type(op[0], op[1],
- (this->oper == ast_mul_assign),
- state, & loc);
-
- ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper], type,
- op[0], op[1]);
-
- result = do_assignment(instructions, state,
- op[0]->clone(ctx, NULL), temp_rhs,
- this->subexpressions[0]->get_location());
- type = result->type;
- error_emitted = (op[0]->type->is_error());
-
- /* GLSL 1.10 does not allow array assignment. However, we don't have to
- * explicitly test for this because none of the binary expression
- * operators allow array operands either.
- */
-
- break;
- }
-
- case ast_mod_assign: {
- op[0] = this->subexpressions[0]->hir(instructions, state);
- op[1] = this->subexpressions[1]->hir(instructions, state);
-
- type = modulus_result_type(op[0]->type, op[1]->type, state, & loc);
-
- assert(operations[this->oper] == ir_binop_mod);
-
- ir_rvalue *temp_rhs;
- temp_rhs = new(ctx) ir_expression(operations[this->oper], type,
- op[0], op[1]);
-
- result = do_assignment(instructions, state,
- op[0]->clone(ctx, NULL), temp_rhs,
- this->subexpressions[0]->get_location());
- type = result->type;
- error_emitted = type->is_error();
- break;
- }
-
- case ast_ls_assign:
- case ast_rs_assign: {
- op[0] = this->subexpressions[0]->hir(instructions, state);
- op[1] = this->subexpressions[1]->hir(instructions, state);
- type = shift_result_type(op[0]->type, op[1]->type, this->oper, state,
- &loc);
- ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
- type, op[0], op[1]);
- result = do_assignment(instructions, state, op[0]->clone(ctx, NULL),
- temp_rhs,
- this->subexpressions[0]->get_location());
- error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
- break;
- }
-
- case ast_and_assign:
- case ast_xor_assign:
- case ast_or_assign: {
- op[0] = this->subexpressions[0]->hir(instructions, state);
- op[1] = this->subexpressions[1]->hir(instructions, state);
- type = bit_logic_result_type(op[0]->type, op[1]->type, this->oper,
- state, &loc);
- ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
- type, op[0], op[1]);
- result = do_assignment(instructions, state, op[0]->clone(ctx, NULL),
- temp_rhs,
- this->subexpressions[0]->get_location());
- error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
- break;
- }
-
- case ast_conditional: {
- op[0] = this->subexpressions[0]->hir(instructions, state);
-
- /* From page 59 (page 65 of the PDF) of the GLSL 1.50 spec:
- *
- * "The ternary selection operator (?:). It operates on three
- * expressions (exp1 ? exp2 : exp3). This operator evaluates the
- * first expression, which must result in a scalar Boolean."
- */
- if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) {
- YYLTYPE loc = this->subexpressions[0]->get_location();
-
- _mesa_glsl_error(& loc, state, "?: condition must be scalar boolean");
- error_emitted = true;
- }
-
- /* The :? operator is implemented by generating an anonymous temporary
- * followed by an if-statement. The last instruction in each branch of
- * the if-statement assigns a value to the anonymous temporary. This
- * temporary is the r-value of the expression.
- */
- exec_list then_instructions;
- exec_list else_instructions;
-
- op[1] = this->subexpressions[1]->hir(&then_instructions, state);
- op[2] = this->subexpressions[2]->hir(&else_instructions, state);
-
- /* From page 59 (page 65 of the PDF) of the GLSL 1.50 spec:
- *
- * "The second and third expressions can be any type, as
- * long their types match, or there is a conversion in
- * Section 4.1.10 "Implicit Conversions" that can be applied
- * to one of the expressions to make their types match. This
- * resulting matching type is the type of the entire
- * expression."
- */
- if ((!apply_implicit_conversion(op[1]->type, op[2], state)
- && !apply_implicit_conversion(op[2]->type, op[1], state))
- || (op[1]->type != op[2]->type)) {
- YYLTYPE loc = this->subexpressions[1]->get_location();
-
- _mesa_glsl_error(& loc, state, "Second and third operands of ?: "
- "operator must have matching types.");
- error_emitted = true;
- type = glsl_type::error_type;
- } else {
- type = op[1]->type;
- }
-
- /* From page 33 (page 39 of the PDF) of the GLSL 1.10 spec:
- *
- * "The second and third expressions must be the same type, but can
- * be of any type other than an array."
- */
- if ((state->language_version <= 110) && type->is_array()) {
- _mesa_glsl_error(& loc, state, "Second and third operands of ?: "
- "operator must not be arrays.");
- error_emitted = true;
- }
-
- ir_constant *cond_val = op[0]->constant_expression_value();
- ir_constant *then_val = op[1]->constant_expression_value();
- ir_constant *else_val = op[2]->constant_expression_value();
-
- if (then_instructions.is_empty()
- && else_instructions.is_empty()
- && (cond_val != NULL) && (then_val != NULL) && (else_val != NULL)) {
- result = (cond_val->value.b[0]) ? then_val : else_val;
- } else {
- ir_variable *const tmp =
- new(ctx) ir_variable(type, "conditional_tmp", ir_var_temporary);
- instructions->push_tail(tmp);
-
- ir_if *const stmt = new(ctx) ir_if(op[0]);
- instructions->push_tail(stmt);
-
- then_instructions.move_nodes_to(& stmt->then_instructions);
- ir_dereference *const then_deref =
- new(ctx) ir_dereference_variable(tmp);
- ir_assignment *const then_assign =
- new(ctx) ir_assignment(then_deref, op[1], NULL);
- stmt->then_instructions.push_tail(then_assign);
-
- else_instructions.move_nodes_to(& stmt->else_instructions);
- ir_dereference *const else_deref =
- new(ctx) ir_dereference_variable(tmp);
- ir_assignment *const else_assign =
- new(ctx) ir_assignment(else_deref, op[2], NULL);
- stmt->else_instructions.push_tail(else_assign);
-
- result = new(ctx) ir_dereference_variable(tmp);
- }
- break;
- }
-
- case ast_pre_inc:
- case ast_pre_dec: {
- op[0] = this->subexpressions[0]->hir(instructions, state);
- if (op[0]->type->base_type == GLSL_TYPE_FLOAT)
- op[1] = new(ctx) ir_constant(1.0f);
- else
- op[1] = new(ctx) ir_constant(1);
-
- type = arithmetic_result_type(op[0], op[1], false, state, & loc);
-
- ir_rvalue *temp_rhs;
- temp_rhs = new(ctx) ir_expression(operations[this->oper], type,
- op[0], op[1]);
-
- result = do_assignment(instructions, state,
- op[0]->clone(ctx, NULL), temp_rhs,
- this->subexpressions[0]->get_location());
- type = result->type;
- error_emitted = op[0]->type->is_error();
- break;
- }
-
- case ast_post_inc:
- case ast_post_dec: {
- op[0] = this->subexpressions[0]->hir(instructions, state);
- if (op[0]->type->base_type == GLSL_TYPE_FLOAT)
- op[1] = new(ctx) ir_constant(1.0f);
- else
- op[1] = new(ctx) ir_constant(1);
-
- error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
-
- type = arithmetic_result_type(op[0], op[1], false, state, & loc);
-
- ir_rvalue *temp_rhs;
- temp_rhs = new(ctx) ir_expression(operations[this->oper], type,
- op[0], op[1]);
-
- /* Get a temporary of a copy of the lvalue before it's modified.
- * This may get thrown away later.
- */
- result = get_lvalue_copy(instructions, op[0]->clone(ctx, NULL));
-
- (void)do_assignment(instructions, state,
- op[0]->clone(ctx, NULL), temp_rhs,
- this->subexpressions[0]->get_location());
-
- type = result->type;
- error_emitted = op[0]->type->is_error();
- break;
- }
-
- case ast_field_selection:
- result = _mesa_ast_field_selection_to_hir(this, instructions, state);
- type = result->type;
- break;
-
- case ast_array_index: {
- YYLTYPE index_loc = subexpressions[1]->get_location();
-
- op[0] = subexpressions[0]->hir(instructions, state);
- op[1] = subexpressions[1]->hir(instructions, state);
-
- error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
-
- ir_rvalue *const array = op[0];
-
- result = new(ctx) ir_dereference_array(op[0], op[1]);
-
- /* Do not use op[0] after this point. Use array.
- */
- op[0] = NULL;
-
-
- if (error_emitted)
- break;
-
- if (!array->type->is_array()
- && !array->type->is_matrix()
- && !array->type->is_vector()) {
- _mesa_glsl_error(& index_loc, state,
- "cannot dereference non-array / non-matrix / "
- "non-vector");
- error_emitted = true;
- }
-
- if (!op[1]->type->is_integer()) {
- _mesa_glsl_error(& index_loc, state,
- "array index must be integer type");
- error_emitted = true;
- } else if (!op[1]->type->is_scalar()) {
- _mesa_glsl_error(& index_loc, state,
- "array index must be scalar");
- error_emitted = true;
- }
-
- /* If the array index is a constant expression and the array has a
- * declared size, ensure that the access is in-bounds. If the array
- * index is not a constant expression, ensure that the array has a
- * declared size.
- */
- ir_constant *const const_index = op[1]->constant_expression_value();
- if (const_index != NULL) {
- const int idx = const_index->value.i[0];
- const char *type_name;
- unsigned bound = 0;
-
- if (array->type->is_matrix()) {
- type_name = "matrix";
- } else if (array->type->is_vector()) {
- type_name = "vector";
- } else {
- type_name = "array";
- }
-
- /* From page 24 (page 30 of the PDF) of the GLSL 1.50 spec:
- *
- * "It is illegal to declare an array with a size, and then
- * later (in the same shader) index the same array with an
- * integral constant expression greater than or equal to the
- * declared size. It is also illegal to index an array with a
- * negative constant expression."
- */
- if (array->type->is_matrix()) {
- if (array->type->row_type()->vector_elements <= idx) {
- bound = array->type->row_type()->vector_elements;
- }
- } else if (array->type->is_vector()) {
- if (array->type->vector_elements <= idx) {
- bound = array->type->vector_elements;
- }
- } else {
- if ((array->type->array_size() > 0)
- && (array->type->array_size() <= idx)) {
- bound = array->type->array_size();
- }
- }
-
- if (bound > 0) {
- _mesa_glsl_error(& loc, state, "%s index must be < %u",
- type_name, bound);
- error_emitted = true;
- } else if (idx < 0) {
- _mesa_glsl_error(& loc, state, "%s index must be >= 0",
- type_name);
- error_emitted = true;
- }
-
- if (array->type->is_array()) {
- /* If the array is a variable dereference, it dereferences the
- * whole array, by definition. Use this to get the variable.
- *
- * FINISHME: Should some methods for getting / setting / testing
- * FINISHME: array access limits be added to ir_dereference?
- */
- ir_variable *const v = array->whole_variable_referenced();
- if ((v != NULL) && (unsigned(idx) > v->max_array_access))
- v->max_array_access = idx;
- }
- } else if (array->type->array_size() == 0) {
- _mesa_glsl_error(&loc, state, "unsized array index must be constant");
- } else {
- if (array->type->is_array()) {
- /* whole_variable_referenced can return NULL if the array is a
- * member of a structure. In this case it is safe to not update
- * the max_array_access field because it is never used for fields
- * of structures.
- */
- ir_variable *v = array->whole_variable_referenced();
- if (v != NULL)
- v->max_array_access = array->type->array_size();
- }
- }
-
- /* From page 23 (29 of the PDF) of the GLSL 1.30 spec:
- *
- * "Samplers aggregated into arrays within a shader (using square
- * brackets [ ]) can only be indexed with integral constant
- * expressions [...]."
- *
- * This restriction was added in GLSL 1.30. Shaders using earlier version
- * of the language should not be rejected by the compiler front-end for
- * using this construct. This allows useful things such as using a loop
- * counter as the index to an array of samplers. If the loop in unrolled,
- * the code should compile correctly. Instead, emit a warning.
- */
- if (array->type->is_array() &&
- array->type->element_type()->is_sampler() &&
- const_index == NULL) {
-
- if (state->language_version == 100) {
- _mesa_glsl_warning(&loc, state,
- "sampler arrays indexed with non-constant "
- "expressions is optional in GLSL ES 1.00");
- } else if (state->language_version < 130) {
- _mesa_glsl_warning(&loc, state,
- "sampler arrays indexed with non-constant "
- "expressions is forbidden in GLSL 1.30 and "
- "later");
- } else {
- _mesa_glsl_error(&loc, state,
- "sampler arrays indexed with non-constant "
- "expressions is forbidden in GLSL 1.30 and "
- "later");
- error_emitted = true;
- }
- }
-
- if (error_emitted)
- result->type = glsl_type::error_type;
-
- type = result->type;
- break;
- }
-
- case ast_function_call:
- /* Should *NEVER* get here. ast_function_call should always be handled
- * by ast_function_expression::hir.
- */
- assert(0);
- break;
-
- case ast_identifier: {
- /* ast_identifier can appear several places in a full abstract syntax
- * tree. This particular use must be at location specified in the grammar
- * as 'variable_identifier'.
- */
- ir_variable *var =
- state->symbols->get_variable(this->primary_expression.identifier);
-
- result = new(ctx) ir_dereference_variable(var);
-
- if (var != NULL) {
- var->used = true;
- type = result->type;
- } else {
- _mesa_glsl_error(& loc, state, "`%s' undeclared",
- this->primary_expression.identifier);
-
- error_emitted = true;
- }
- break;
- }
-
- case ast_int_constant:
- type = glsl_type::int_type;
- result = new(ctx) ir_constant(this->primary_expression.int_constant);
- break;
-
- case ast_uint_constant:
- type = glsl_type::uint_type;
- result = new(ctx) ir_constant(this->primary_expression.uint_constant);
- break;
-
- case ast_float_constant:
- type = glsl_type::float_type;
- result = new(ctx) ir_constant(this->primary_expression.float_constant);
- break;
-
- case ast_bool_constant:
- type = glsl_type::bool_type;
- result = new(ctx) ir_constant(bool(this->primary_expression.bool_constant));
- break;
-
- case ast_sequence: {
- /* It should not be possible to generate a sequence in the AST without
- * any expressions in it.
- */
- assert(!this->expressions.is_empty());
-
- /* The r-value of a sequence is the last expression in the sequence. If
- * the other expressions in the sequence do not have side-effects (and
- * therefore add instructions to the instruction list), they get dropped
- * on the floor.
- */
- foreach_list_typed (ast_node, ast, link, &this->expressions)
- result = ast->hir(instructions, state);
-
- type = result->type;
-
- /* Any errors should have already been emitted in the loop above.
- */
- error_emitted = true;
- break;
- }
- }
-
- if (type->is_error() && !error_emitted)
- _mesa_glsl_error(& loc, state, "type mismatch");
-
- return result;
-}
-
-
-ir_rvalue *
-ast_expression_statement::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- /* It is possible to have expression statements that don't have an
- * expression. This is the solitary semicolon:
- *
- * for (i = 0; i < 5; i++)
- * ;
- *
- * In this case the expression will be NULL. Test for NULL and don't do
- * anything in that case.
- */
- if (expression != NULL)
- expression->hir(instructions, state);
-
- /* Statements do not have r-values.
- */
- return NULL;
-}
-
-
-ir_rvalue *
-ast_compound_statement::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- if (new_scope)
- state->symbols->push_scope();
-
- foreach_list_typed (ast_node, ast, link, &this->statements)
- ast->hir(instructions, state);
-
- if (new_scope)
- state->symbols->pop_scope();
-
- /* Compound statements do not have r-values.
- */
- return NULL;
-}
-
-
-static const glsl_type *
-process_array_type(YYLTYPE *loc, const glsl_type *base, ast_node *array_size,
- struct _mesa_glsl_parse_state *state)
-{
- unsigned length = 0;
-
- /* FINISHME: Reject delcarations of multidimensional arrays. */
-
- if (array_size != NULL) {
- exec_list dummy_instructions;
- ir_rvalue *const ir = array_size->hir(& dummy_instructions, state);
- YYLTYPE loc = array_size->get_location();
-
- /* FINISHME: Verify that the grammar forbids side-effects in array
- * FINISHME: sizes. i.e., 'vec4 [x = 12] data'
- */
- assert(dummy_instructions.is_empty());
-
- if (ir != NULL) {
- if (!ir->type->is_integer()) {
- _mesa_glsl_error(& loc, state, "array size must be integer type");
- } else if (!ir->type->is_scalar()) {
- _mesa_glsl_error(& loc, state, "array size must be scalar type");
- } else {
- ir_constant *const size = ir->constant_expression_value();
-
- if (size == NULL) {
- _mesa_glsl_error(& loc, state, "array size must be a "
- "constant valued expression");
- } else if (size->value.i[0] <= 0) {
- _mesa_glsl_error(& loc, state, "array size must be > 0");
- } else {
- assert(size->type == ir->type);
- length = size->value.u[0];
- }
- }
- }
- } else if (state->es_shader) {
- /* Section 10.17 of the GLSL ES 1.00 specification states that unsized
- * array declarations have been removed from the language.
- */
- _mesa_glsl_error(loc, state, "unsized array declarations are not "
- "allowed in GLSL ES 1.00.");
- }
-
- return glsl_type::get_array_instance(base, length);
-}
-
-
-const glsl_type *
-ast_type_specifier::glsl_type(const char **name,
- struct _mesa_glsl_parse_state *state) const
-{
- const struct glsl_type *type;
-
- type = state->symbols->get_type(this->type_name);
- *name = this->type_name;
-
- if (this->is_array) {
- YYLTYPE loc = this->get_location();
- type = process_array_type(&loc, type, this->array_size, state);
- }
-
- return type;
-}
-
-
-static void
-apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
- ir_variable *var,
- struct _mesa_glsl_parse_state *state,
- YYLTYPE *loc)
-{
- if (qual->flags.q.invariant) {
- if (var->used) {
- _mesa_glsl_error(loc, state,
- "variable `%s' may not be redeclared "
- "`invariant' after being used",
- var->name);
- } else {
- var->invariant = 1;
- }
- }
-
- if (qual->flags.q.constant || qual->flags.q.attribute
- || qual->flags.q.uniform
- || (qual->flags.q.varying && (state->target == fragment_shader)))
- var->read_only = 1;
-
- if (qual->flags.q.centroid)
- var->centroid = 1;
-
- if (qual->flags.q.attribute && state->target != vertex_shader) {
- var->type = glsl_type::error_type;
- _mesa_glsl_error(loc, state,
- "`attribute' variables may not be declared in the "
- "%s shader",
- _mesa_glsl_shader_target_name(state->target));
- }
-
- /* From page 25 (page 31 of the PDF) of the GLSL 1.10 spec:
- *
- * "The varying qualifier can be used only with the data types
- * float, vec2, vec3, vec4, mat2, mat3, and mat4, or arrays of
- * these."
- */
- if (qual->flags.q.varying) {
- const glsl_type *non_array_type;
-
- if (var->type && var->type->is_array())
- non_array_type = var->type->fields.array;
- else
- non_array_type = var->type;
-
- if (non_array_type && non_array_type->base_type != GLSL_TYPE_FLOAT) {
- var->type = glsl_type::error_type;
- _mesa_glsl_error(loc, state,
- "varying variables must be of base type float");
- }
- }
-
- /* If there is no qualifier that changes the mode of the variable, leave
- * the setting alone.
- */
- if (qual->flags.q.in && qual->flags.q.out)
- var->mode = ir_var_inout;
- else if (qual->flags.q.attribute || qual->flags.q.in
- || (qual->flags.q.varying && (state->target == fragment_shader)))
- var->mode = ir_var_in;
- else if (qual->flags.q.out
- || (qual->flags.q.varying && (state->target == vertex_shader)))
- var->mode = ir_var_out;
- else if (qual->flags.q.uniform)
- var->mode = ir_var_uniform;
-
- if (state->all_invariant && (state->current_function == NULL)) {
- switch (state->target) {
- case vertex_shader:
- if (var->mode == ir_var_out)
- var->invariant = true;
- break;
- case geometry_shader:
- if ((var->mode == ir_var_in) || (var->mode == ir_var_out))
- var->invariant = true;
- break;
- case fragment_shader:
- if (var->mode == ir_var_in)
- var->invariant = true;
- break;
- }
- }
-
- if (qual->flags.q.flat)
- var->interpolation = ir_var_flat;
- else if (qual->flags.q.noperspective)
- var->interpolation = ir_var_noperspective;
- else
- var->interpolation = ir_var_smooth;
-
- var->pixel_center_integer = qual->flags.q.pixel_center_integer;
- var->origin_upper_left = qual->flags.q.origin_upper_left;
- if ((qual->flags.q.origin_upper_left || qual->flags.q.pixel_center_integer)
- && (strcmp(var->name, "gl_FragCoord") != 0)) {
- const char *const qual_string = (qual->flags.q.origin_upper_left)
- ? "origin_upper_left" : "pixel_center_integer";
-
- _mesa_glsl_error(loc, state,
- "layout qualifier `%s' can only be applied to "
- "fragment shader input `gl_FragCoord'",
- qual_string);
- }
-
- if (qual->flags.q.explicit_location) {
- const bool global_scope = (state->current_function == NULL);
- bool fail = false;
- const char *string = "";
-
- /* In the vertex shader only shader inputs can be given explicit
- * locations.
- *
- * In the fragment shader only shader outputs can be given explicit
- * locations.
- */
- switch (state->target) {
- case vertex_shader:
- if (!global_scope || (var->mode != ir_var_in)) {
- fail = true;
- string = "input";
- }
- break;
-
- case geometry_shader:
- _mesa_glsl_error(loc, state,
- "geometry shader variables cannot be given "
- "explicit locations\n");
- break;
-
- case fragment_shader:
- if (!global_scope || (var->mode != ir_var_in)) {
- fail = true;
- string = "output";
- }
- break;
- };
-
- if (fail) {
- _mesa_glsl_error(loc, state,
- "only %s shader %s variables can be given an "
- "explicit location\n",
- _mesa_glsl_shader_target_name(state->target),
- string);
- } else {
- var->explicit_location = true;
-
- /* This bit of silliness is needed because invalid explicit locations
- * are supposed to be flagged during linking. Small negative values
- * biased by VERT_ATTRIB_GENERIC0 or FRAG_RESULT_DATA0 could alias
- * built-in values (e.g., -16+VERT_ATTRIB_GENERIC0 = VERT_ATTRIB_POS).
- * The linker needs to be able to differentiate these cases. This
- * ensures that negative values stay negative.
- */
- if (qual->location >= 0) {
- var->location = (state->target == vertex_shader)
- ? (qual->location + VERT_ATTRIB_GENERIC0)
- : (qual->location + FRAG_RESULT_DATA0);
- } else {
- var->location = qual->location;
- }
- }
- }
-
- /* Does the declaration use the 'layout' keyword?
- */
- const bool uses_layout = qual->flags.q.pixel_center_integer
- || qual->flags.q.origin_upper_left
- || qual->flags.q.explicit_location;
-
- /* Does the declaration use the deprecated 'attribute' or 'varying'
- * keywords?
- */
- const bool uses_deprecated_qualifier = qual->flags.q.attribute
- || qual->flags.q.varying;
-
- /* Is the 'layout' keyword used with parameters that allow relaxed checking.
- * Many implementations of GL_ARB_fragment_coord_conventions_enable and some
- * implementations (only Mesa?) GL_ARB_explicit_attrib_location_enable
- * allowed the layout qualifier to be used with 'varying' and 'attribute'.
- * These extensions and all following extensions that add the 'layout'
- * keyword have been modified to require the use of 'in' or 'out'.
- *
- * The following extension do not allow the deprecated keywords:
- *
- * GL_AMD_conservative_depth
- * GL_ARB_gpu_shader5
- * GL_ARB_separate_shader_objects
- * GL_ARB_tesselation_shader
- * GL_ARB_transform_feedback3
- * GL_ARB_uniform_buffer_object
- *
- * It is unknown whether GL_EXT_shader_image_load_store or GL_NV_gpu_shader5
- * allow layout with the deprecated keywords.
- */
- const bool relaxed_layout_qualifier_checking =
- state->ARB_fragment_coord_conventions_enable;
-
- if (uses_layout && uses_deprecated_qualifier) {
- if (relaxed_layout_qualifier_checking) {
- _mesa_glsl_warning(loc, state,
- "`layout' qualifier may not be used with "
- "`attribute' or `varying'");
- } else {
- _mesa_glsl_error(loc, state,
- "`layout' qualifier may not be used with "
- "`attribute' or `varying'");
- }
- }
-
- /* Layout qualifiers for gl_FragDepth, which are enabled by extension
- * AMD_conservative_depth.
- */
- int depth_layout_count = qual->flags.q.depth_any
- + qual->flags.q.depth_greater
- + qual->flags.q.depth_less
- + qual->flags.q.depth_unchanged;
- if (depth_layout_count > 0
- && !state->AMD_conservative_depth_enable) {
- _mesa_glsl_error(loc, state,
- "extension GL_AMD_conservative_depth must be enabled "
- "to use depth layout qualifiers");
- } else if (depth_layout_count > 0
- && strcmp(var->name, "gl_FragDepth") != 0) {
- _mesa_glsl_error(loc, state,
- "depth layout qualifiers can be applied only to "
- "gl_FragDepth");
- } else if (depth_layout_count > 1
- && strcmp(var->name, "gl_FragDepth") == 0) {
- _mesa_glsl_error(loc, state,
- "at most one depth layout qualifier can be applied to "
- "gl_FragDepth");
- }
- if (qual->flags.q.depth_any)
- var->depth_layout = ir_depth_layout_any;
- else if (qual->flags.q.depth_greater)
- var->depth_layout = ir_depth_layout_greater;
- else if (qual->flags.q.depth_less)
- var->depth_layout = ir_depth_layout_less;
- else if (qual->flags.q.depth_unchanged)
- var->depth_layout = ir_depth_layout_unchanged;
- else
- var->depth_layout = ir_depth_layout_none;
-
- if (var->type->is_array() && state->language_version != 110) {
- var->array_lvalue = true;
- }
-}
-
-/**
- * Get the variable that is being redeclared by this declaration
- *
- * Semantic checks to verify the validity of the redeclaration are also
- * performed. If semantic checks fail, compilation error will be emitted via
- * \c _mesa_glsl_error, but a non-\c NULL pointer will still be returned.
- *
- * \returns
- * A pointer to an existing variable in the current scope if the declaration
- * is a redeclaration, \c NULL otherwise.
- */
-ir_variable *
-get_variable_being_redeclared(ir_variable *var, ast_declaration *decl,
- struct _mesa_glsl_parse_state *state)
-{
- /* Check if this declaration is actually a re-declaration, either to
- * resize an array or add qualifiers to an existing variable.
- *
- * This is allowed for variables in the current scope, or when at
- * global scope (for built-ins in the implicit outer scope).
- */
- ir_variable *earlier = state->symbols->get_variable(decl->identifier);
- if (earlier == NULL ||
- (state->current_function != NULL &&
- !state->symbols->name_declared_this_scope(decl->identifier))) {
- return NULL;
- }
-
-
- YYLTYPE loc = decl->get_location();
-
- /* From page 24 (page 30 of the PDF) of the GLSL 1.50 spec,
- *
- * "It is legal to declare an array without a size and then
- * later re-declare the same name as an array of the same
- * type and specify a size."
- */
- if ((earlier->type->array_size() == 0)
- && var->type->is_array()
- && (var->type->element_type() == earlier->type->element_type())) {
- /* FINISHME: This doesn't match the qualifiers on the two
- * FINISHME: declarations. It's not 100% clear whether this is
- * FINISHME: required or not.
- */
-
- /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec:
- *
- * "The size [of gl_TexCoord] can be at most
- * gl_MaxTextureCoords."
- */
- const unsigned size = unsigned(var->type->array_size());
- if ((strcmp("gl_TexCoord", var->name) == 0)
- && (size > state->Const.MaxTextureCoords)) {
- _mesa_glsl_error(& loc, state, "`gl_TexCoord' array size cannot "
- "be larger than gl_MaxTextureCoords (%u)\n",
- state->Const.MaxTextureCoords);
- } else if ((size > 0) && (size <= earlier->max_array_access)) {
- _mesa_glsl_error(& loc, state, "array size must be > %u due to "
- "previous access",
- earlier->max_array_access);
- }
-
- earlier->type = var->type;
- delete var;
- var = NULL;
- } else if (state->ARB_fragment_coord_conventions_enable
- && strcmp(var->name, "gl_FragCoord") == 0
- && earlier->type == var->type
- && earlier->mode == var->mode) {
- /* Allow redeclaration of gl_FragCoord for ARB_fcc layout
- * qualifiers.
- */
- earlier->origin_upper_left = var->origin_upper_left;
- earlier->pixel_center_integer = var->pixel_center_integer;
-
- /* According to section 4.3.7 of the GLSL 1.30 spec,
- * the following built-in varaibles can be redeclared with an
- * interpolation qualifier:
- * * gl_FrontColor
- * * gl_BackColor
- * * gl_FrontSecondaryColor
- * * gl_BackSecondaryColor
- * * gl_Color
- * * gl_SecondaryColor
- */
- } else if (state->language_version >= 130
- && (strcmp(var->name, "gl_FrontColor") == 0
- || strcmp(var->name, "gl_BackColor") == 0
- || strcmp(var->name, "gl_FrontSecondaryColor") == 0
- || strcmp(var->name, "gl_BackSecondaryColor") == 0
- || strcmp(var->name, "gl_Color") == 0
- || strcmp(var->name, "gl_SecondaryColor") == 0)
- && earlier->type == var->type
- && earlier->mode == var->mode) {
- earlier->interpolation = var->interpolation;
-
- /* Layout qualifiers for gl_FragDepth. */
- } else if (state->AMD_conservative_depth_enable
- && strcmp(var->name, "gl_FragDepth") == 0
- && earlier->type == var->type
- && earlier->mode == var->mode) {
-
- /** From the AMD_conservative_depth spec:
- * Within any shader, the first redeclarations of gl_FragDepth
- * must appear before any use of gl_FragDepth.
- */
- if (earlier->used) {
- _mesa_glsl_error(&loc, state,
- "the first redeclaration of gl_FragDepth "
- "must appear before any use of gl_FragDepth");
- }
-
- /* Prevent inconsistent redeclaration of depth layout qualifier. */
- if (earlier->depth_layout != ir_depth_layout_none
- && earlier->depth_layout != var->depth_layout) {
- _mesa_glsl_error(&loc, state,
- "gl_FragDepth: depth layout is declared here "
- "as '%s, but it was previously declared as "
- "'%s'",
- depth_layout_string(var->depth_layout),
- depth_layout_string(earlier->depth_layout));
- }
-
- earlier->depth_layout = var->depth_layout;
-
- } else {
- _mesa_glsl_error(&loc, state, "`%s' redeclared", decl->identifier);
- }
-
- return earlier;
-}
-
-/**
- * Generate the IR for an initializer in a variable declaration
- */
-ir_rvalue *
-process_initializer(ir_variable *var, ast_declaration *decl,
- ast_fully_specified_type *type,
- exec_list *initializer_instructions,
- struct _mesa_glsl_parse_state *state)
-{
- ir_rvalue *result = NULL;
-
- YYLTYPE initializer_loc = decl->initializer->get_location();
-
- /* From page 24 (page 30 of the PDF) of the GLSL 1.10 spec:
- *
- * "All uniform variables are read-only and are initialized either
- * directly by an application via API commands, or indirectly by
- * OpenGL."
- */
- if ((state->language_version <= 110)
- && (var->mode == ir_var_uniform)) {
- _mesa_glsl_error(& initializer_loc, state,
- "cannot initialize uniforms in GLSL 1.10");
- }
-
- if (var->type->is_sampler()) {
- _mesa_glsl_error(& initializer_loc, state,
- "cannot initialize samplers");
- }
-
- if ((var->mode == ir_var_in) && (state->current_function == NULL)) {
- _mesa_glsl_error(& initializer_loc, state,
- "cannot initialize %s shader input / %s",
- _mesa_glsl_shader_target_name(state->target),
- (state->target == vertex_shader)
- ? "attribute" : "varying");
- }
-
- ir_dereference *const lhs = new(state) ir_dereference_variable(var);
- ir_rvalue *rhs = decl->initializer->hir(initializer_instructions,
- state);
-
- /* Calculate the constant value if this is a const or uniform
- * declaration.
- */
- if (type->qualifier.flags.q.constant
- || type->qualifier.flags.q.uniform) {
- ir_rvalue *new_rhs = validate_assignment(state, var->type, rhs);
- if (new_rhs != NULL) {
- rhs = new_rhs;
-
- ir_constant *constant_value = rhs->constant_expression_value();
- if (!constant_value) {
- _mesa_glsl_error(& initializer_loc, state,
- "initializer of %s variable `%s' must be a "
- "constant expression",
- (type->qualifier.flags.q.constant)
- ? "const" : "uniform",
- decl->identifier);
- if (var->type->is_numeric()) {
- /* Reduce cascading errors. */
- var->constant_value = ir_constant::zero(state, var->type);
- }
- } else {
- rhs = constant_value;
- var->constant_value = constant_value;
- }
- } else {
- _mesa_glsl_error(&initializer_loc, state,
- "initializer of type %s cannot be assigned to "
- "variable of type %s",
- rhs->type->name, var->type->name);
- if (var->type->is_numeric()) {
- /* Reduce cascading errors. */
- var->constant_value = ir_constant::zero(state, var->type);
- }
- }
- }
-
- if (rhs && !rhs->type->is_error()) {
- bool temp = var->read_only;
- if (type->qualifier.flags.q.constant)
- var->read_only = false;
-
- /* Never emit code to initialize a uniform.
- */
- const glsl_type *initializer_type;
- if (!type->qualifier.flags.q.uniform) {
- result = do_assignment(initializer_instructions, state,
- lhs, rhs,
- type->get_location());
- initializer_type = result->type;
- } else
- initializer_type = rhs->type;
-
- /* If the declared variable is an unsized array, it must inherrit
- * its full type from the initializer. A declaration such as
- *
- * uniform float a[] = float[](1.0, 2.0, 3.0, 3.0);
- *
- * becomes
- *
- * uniform float a[4] = float[](1.0, 2.0, 3.0, 3.0);
- *
- * The assignment generated in the if-statement (below) will also
- * automatically handle this case for non-uniforms.
- *
- * If the declared variable is not an array, the types must
- * already match exactly. As a result, the type assignment
- * here can be done unconditionally. For non-uniforms the call
- * to do_assignment can change the type of the initializer (via
- * the implicit conversion rules). For uniforms the initializer
- * must be a constant expression, and the type of that expression
- * was validated above.
- */
- var->type = initializer_type;
-
- var->read_only = temp;
- }
-
- return result;
-}
-
-ir_rvalue *
-ast_declarator_list::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- void *ctx = state;
- const struct glsl_type *decl_type;
- const char *type_name = NULL;
- ir_rvalue *result = NULL;
- YYLTYPE loc = this->get_location();
-
- /* From page 46 (page 52 of the PDF) of the GLSL 1.50 spec:
- *
- * "To ensure that a particular output variable is invariant, it is
- * necessary to use the invariant qualifier. It can either be used to
- * qualify a previously declared variable as being invariant
- *
- * invariant gl_Position; // make existing gl_Position be invariant"
- *
- * In these cases the parser will set the 'invariant' flag in the declarator
- * list, and the type will be NULL.
- */
- if (this->invariant) {
- assert(this->type == NULL);
-
- if (state->current_function != NULL) {
- _mesa_glsl_error(& loc, state,
- "All uses of `invariant' keyword must be at global "
- "scope\n");
- }
-
- foreach_list_typed (ast_declaration, decl, link, &this->declarations) {
- assert(!decl->is_array);
- assert(decl->array_size == NULL);
- assert(decl->initializer == NULL);
-
- ir_variable *const earlier =
- state->symbols->get_variable(decl->identifier);
- if (earlier == NULL) {
- _mesa_glsl_error(& loc, state,
- "Undeclared variable `%s' cannot be marked "
- "invariant\n", decl->identifier);
- } else if ((state->target == vertex_shader)
- && (earlier->mode != ir_var_out)) {
- _mesa_glsl_error(& loc, state,
- "`%s' cannot be marked invariant, vertex shader "
- "outputs only\n", decl->identifier);
- } else if ((state->target == fragment_shader)
- && (earlier->mode != ir_var_in)) {
- _mesa_glsl_error(& loc, state,
- "`%s' cannot be marked invariant, fragment shader "
- "inputs only\n", decl->identifier);
- } else if (earlier->used) {
- _mesa_glsl_error(& loc, state,
- "variable `%s' may not be redeclared "
- "`invariant' after being used",
- earlier->name);
- } else {
- earlier->invariant = true;
- }
- }
-
- /* Invariant redeclarations do not have r-values.
- */
- return NULL;
- }
-
- assert(this->type != NULL);
- assert(!this->invariant);
-
- /* The type specifier may contain a structure definition. Process that
- * before any of the variable declarations.
- */
- (void) this->type->specifier->hir(instructions, state);
-
- decl_type = this->type->specifier->glsl_type(& type_name, state);
- if (this->declarations.is_empty()) {
- /* The only valid case where the declaration list can be empty is when
- * the declaration is setting the default precision of a built-in type
- * (e.g., 'precision highp vec4;').
- */
-
- if (decl_type != NULL) {
- } else {
- _mesa_glsl_error(& loc, state, "incomplete declaration");
- }
- }
-
- foreach_list_typed (ast_declaration, decl, link, &this->declarations) {
- const struct glsl_type *var_type;
- ir_variable *var;
-
- /* FINISHME: Emit a warning if a variable declaration shadows a
- * FINISHME: declaration at a higher scope.
- */
-
- if ((decl_type == NULL) || decl_type->is_void()) {
- if (type_name != NULL) {
- _mesa_glsl_error(& loc, state,
- "invalid type `%s' in declaration of `%s'",
- type_name, decl->identifier);
- } else {
- _mesa_glsl_error(& loc, state,
- "invalid type in declaration of `%s'",
- decl->identifier);
- }
- continue;
- }
-
- if (decl->is_array) {
- var_type = process_array_type(&loc, decl_type, decl->array_size,
- state);
- } else {
- var_type = decl_type;
- }
-
- var = new(ctx) ir_variable(var_type, decl->identifier, ir_var_auto);
-
- /* From page 22 (page 28 of the PDF) of the GLSL 1.10 specification;
- *
- * "Global variables can only use the qualifiers const,
- * attribute, uni form, or varying. Only one may be
- * specified.
- *
- * Local variables can only use the qualifier const."
- *
- * This is relaxed in GLSL 1.30. It is also relaxed by any extension
- * that adds the 'layout' keyword.
- */
- if ((state->language_version < 130)
- && !state->ARB_explicit_attrib_location_enable
- && !state->ARB_fragment_coord_conventions_enable) {
- if (this->type->qualifier.flags.q.out) {
- _mesa_glsl_error(& loc, state,
- "`out' qualifier in declaration of `%s' "
- "only valid for function parameters in %s.",
- decl->identifier, state->version_string);
- }
- if (this->type->qualifier.flags.q.in) {
- _mesa_glsl_error(& loc, state,
- "`in' qualifier in declaration of `%s' "
- "only valid for function parameters in %s.",
- decl->identifier, state->version_string);
- }
- /* FINISHME: Test for other invalid qualifiers. */
- }
-
- apply_type_qualifier_to_variable(& this->type->qualifier, var, state,
- & loc);
-
- if (this->type->qualifier.flags.q.invariant) {
- if ((state->target == vertex_shader) && !(var->mode == ir_var_out ||
- var->mode == ir_var_inout)) {
- /* FINISHME: Note that this doesn't work for invariant on
- * a function signature outval
- */
- _mesa_glsl_error(& loc, state,
- "`%s' cannot be marked invariant, vertex shader "
- "outputs only\n", var->name);
- } else if ((state->target == fragment_shader) &&
- !(var->mode == ir_var_in || var->mode == ir_var_inout)) {
- /* FINISHME: Note that this doesn't work for invariant on
- * a function signature inval
- */
- _mesa_glsl_error(& loc, state,
- "`%s' cannot be marked invariant, fragment shader "
- "inputs only\n", var->name);
- }
- }
-
- if (state->current_function != NULL) {
- const char *mode = NULL;
- const char *extra = "";
-
- /* There is no need to check for 'inout' here because the parser will
- * only allow that in function parameter lists.
- */
- if (this->type->qualifier.flags.q.attribute) {
- mode = "attribute";
- } else if (this->type->qualifier.flags.q.uniform) {
- mode = "uniform";
- } else if (this->type->qualifier.flags.q.varying) {
- mode = "varying";
- } else if (this->type->qualifier.flags.q.in) {
- mode = "in";
- extra = " or in function parameter list";
- } else if (this->type->qualifier.flags.q.out) {
- mode = "out";
- extra = " or in function parameter list";
- }
-
- if (mode) {
- _mesa_glsl_error(& loc, state,
- "%s variable `%s' must be declared at "
- "global scope%s",
- mode, var->name, extra);
- }
- } else if (var->mode == ir_var_in) {
- var->read_only = true;
-
- if (state->target == vertex_shader) {
- bool error_emitted = false;
-
- /* From page 31 (page 37 of the PDF) of the GLSL 1.50 spec:
- *
- * "Vertex shader inputs can only be float, floating-point
- * vectors, matrices, signed and unsigned integers and integer
- * vectors. Vertex shader inputs can also form arrays of these
- * types, but not structures."
- *
- * From page 31 (page 27 of the PDF) of the GLSL 1.30 spec:
- *
- * "Vertex shader inputs can only be float, floating-point
- * vectors, matrices, signed and unsigned integers and integer
- * vectors. They cannot be arrays or structures."
- *
- * From page 23 (page 29 of the PDF) of the GLSL 1.20 spec:
- *
- * "The attribute qualifier can be used only with float,
- * floating-point vectors, and matrices. Attribute variables
- * cannot be declared as arrays or structures."
- */
- const glsl_type *check_type = var->type->is_array()
- ? var->type->fields.array : var->type;
-
- switch (check_type->base_type) {
- case GLSL_TYPE_FLOAT:
- break;
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT:
- if (state->language_version > 120)
- break;
- /* FALLTHROUGH */
- default:
- _mesa_glsl_error(& loc, state,
- "vertex shader input / attribute cannot have "
- "type %s`%s'",
- var->type->is_array() ? "array of " : "",
- check_type->name);
- error_emitted = true;
- }
-
- if (!error_emitted && (state->language_version <= 130)
- && var->type->is_array()) {
- _mesa_glsl_error(& loc, state,
- "vertex shader input / attribute cannot have "
- "array type");
- error_emitted = true;
- }
- }
- }
-
- /* Integer vertex outputs must be qualified with 'flat'.
- *
- * From section 4.3.6 of the GLSL 1.30 spec:
- * "If a vertex output is a signed or unsigned integer or integer
- * vector, then it must be qualified with the interpolation qualifier
- * flat."
- */
- if (state->language_version >= 130
- && state->target == vertex_shader
- && state->current_function == NULL
- && var->type->is_integer()
- && var->mode == ir_var_out
- && var->interpolation != ir_var_flat) {
-
- _mesa_glsl_error(&loc, state, "If a vertex output is an integer, "
- "then it must be qualified with 'flat'");
- }
-
-
- /* Interpolation qualifiers cannot be applied to 'centroid' and
- * 'centroid varying'.
- *
- * From page 29 (page 35 of the PDF) of the GLSL 1.30 spec:
- * "interpolation qualifiers may only precede the qualifiers in,
- * centroid in, out, or centroid out in a declaration. They do not apply
- * to the deprecated storage qualifiers varying or centroid varying."
- */
- if (state->language_version >= 130
- && this->type->qualifier.has_interpolation()
- && this->type->qualifier.flags.q.varying) {
-
- const char *i = this->type->qualifier.interpolation_string();
- assert(i != NULL);
- const char *s;
- if (this->type->qualifier.flags.q.centroid)
- s = "centroid varying";
- else
- s = "varying";
-
- _mesa_glsl_error(&loc, state,
- "qualifier '%s' cannot be applied to the "
- "deprecated storage qualifier '%s'", i, s);
- }
-
-
- /* Interpolation qualifiers can only apply to vertex shader outputs and
- * fragment shader inputs.
- *
- * From page 29 (page 35 of the PDF) of the GLSL 1.30 spec:
- * "Outputs from a vertex shader (out) and inputs to a fragment
- * shader (in) can be further qualified with one or more of these
- * interpolation qualifiers"
- */
- if (state->language_version >= 130
- && this->type->qualifier.has_interpolation()) {
-
- const char *i = this->type->qualifier.interpolation_string();
- assert(i != NULL);
-
- switch (state->target) {
- case vertex_shader:
- if (this->type->qualifier.flags.q.in) {
- _mesa_glsl_error(&loc, state,
- "qualifier '%s' cannot be applied to vertex "
- "shader inputs", i);
- }
- break;
- case fragment_shader:
- if (this->type->qualifier.flags.q.out) {
- _mesa_glsl_error(&loc, state,
- "qualifier '%s' cannot be applied to fragment "
- "shader outputs", i);
- }
- break;
- default:
- assert(0);
- }
- }
-
-
- /* From section 4.3.4 of the GLSL 1.30 spec:
- * "It is an error to use centroid in in a vertex shader."
- */
- if (state->language_version >= 130
- && this->type->qualifier.flags.q.centroid
- && this->type->qualifier.flags.q.in
- && state->target == vertex_shader) {
-
- _mesa_glsl_error(&loc, state,
- "'centroid in' cannot be used in a vertex shader");
- }
-
-
- /* Precision qualifiers exists only in GLSL versions 1.00 and >= 1.30.
- */
- if (this->type->specifier->precision != ast_precision_none
- && state->language_version != 100
- && state->language_version < 130) {
-
- _mesa_glsl_error(&loc, state,
- "precision qualifiers are supported only in GLSL ES "
- "1.00, and GLSL 1.30 and later");
- }
-
-
- /* Precision qualifiers only apply to floating point and integer types.
- *
- * From section 4.5.2 of the GLSL 1.30 spec:
- * "Any floating point or any integer declaration can have the type
- * preceded by one of these precision qualifiers [...] Literal
- * constants do not have precision qualifiers. Neither do Boolean
- * variables.
- */
- if (this->type->specifier->precision != ast_precision_none
- && !var->type->is_float()
- && !var->type->is_integer()
- && !(var->type->is_array()
- && (var->type->fields.array->is_float()
- || var->type->fields.array->is_integer()))) {
-
- _mesa_glsl_error(&loc, state,
- "precision qualifiers apply only to floating point "
- "and integer types");
- }
-
- /* Process the initializer and add its instructions to a temporary
- * list. This list will be added to the instruction stream (below) after
- * the declaration is added. This is done because in some cases (such as
- * redeclarations) the declaration may not actually be added to the
- * instruction stream.
- */
- exec_list initializer_instructions;
- ir_variable *earlier = get_variable_being_redeclared(var, decl, state);
-
- if (decl->initializer != NULL) {
- result = process_initializer((earlier == NULL) ? var : earlier,
- decl, this->type,
- &initializer_instructions, state);
- }
-
- /* From page 23 (page 29 of the PDF) of the GLSL 1.10 spec:
- *
- * "It is an error to write to a const variable outside of
- * its declaration, so they must be initialized when
- * declared."
- */
- if (this->type->qualifier.flags.q.constant && decl->initializer == NULL) {
- _mesa_glsl_error(& loc, state,
- "const declaration of `%s' must be initialized",
- decl->identifier);
- }
-
- /* If the declaration is not a redeclaration, there are a few additional
- * semantic checks that must be applied. In addition, variable that was
- * created for the declaration should be added to the IR stream.
- */
- if (earlier == NULL) {
- /* From page 15 (page 21 of the PDF) of the GLSL 1.10 spec,
- *
- * "Identifiers starting with "gl_" are reserved for use by
- * OpenGL, and may not be declared in a shader as either a
- * variable or a function."
- */
- if (strncmp(decl->identifier, "gl_", 3) == 0)
- _mesa_glsl_error(& loc, state,
- "identifier `%s' uses reserved `gl_' prefix",
- decl->identifier);
-
- /* Add the variable to the symbol table. Note that the initializer's
- * IR was already processed earlier (though it hasn't been emitted
- * yet), without the variable in scope.
- *
- * This differs from most C-like languages, but it follows the GLSL
- * specification. From page 28 (page 34 of the PDF) of the GLSL 1.50
- * spec:
- *
- * "Within a declaration, the scope of a name starts immediately
- * after the initializer if present or immediately after the name
- * being declared if not."
- */
- if (!state->symbols->add_variable(var)) {
- YYLTYPE loc = this->get_location();
- _mesa_glsl_error(&loc, state, "name `%s' already taken in the "
- "current scope", decl->identifier);
- continue;
- }
-
- /* Push the variable declaration to the top. It means that all the
- * variable declarations will appear in a funny last-to-first order,
- * but otherwise we run into trouble if a function is prototyped, a
- * global var is decled, then the function is defined with usage of
- * the global var. See glslparsertest's CorrectModule.frag.
- */
- instructions->push_head(var);
- }
-
- instructions->append_list(&initializer_instructions);
- }
-
-
- /* Generally, variable declarations do not have r-values. However,
- * one is used for the declaration in
- *
- * while (bool b = some_condition()) {
- * ...
- * }
- *
- * so we return the rvalue from the last seen declaration here.
- */
- return result;
-}
-
-
-ir_rvalue *
-ast_parameter_declarator::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- void *ctx = state;
- const struct glsl_type *type;
- const char *name = NULL;
- YYLTYPE loc = this->get_location();
-
- type = this->type->specifier->glsl_type(& name, state);
-
- if (type == NULL) {
- if (name != NULL) {
- _mesa_glsl_error(& loc, state,
- "invalid type `%s' in declaration of `%s'",
- name, this->identifier);
- } else {
- _mesa_glsl_error(& loc, state,
- "invalid type in declaration of `%s'",
- this->identifier);
- }
-
- type = glsl_type::error_type;
- }
-
- /* From page 62 (page 68 of the PDF) of the GLSL 1.50 spec:
- *
- * "Functions that accept no input arguments need not use void in the
- * argument list because prototypes (or definitions) are required and
- * therefore there is no ambiguity when an empty argument list "( )" is
- * declared. The idiom "(void)" as a parameter list is provided for
- * convenience."
- *
- * Placing this check here prevents a void parameter being set up
- * for a function, which avoids tripping up checks for main taking
- * parameters and lookups of an unnamed symbol.
- */
- if (type->is_void()) {
- if (this->identifier != NULL)
- _mesa_glsl_error(& loc, state,
- "named parameter cannot have type `void'");
-
- is_void = true;
- return NULL;
- }
-
- if (formal_parameter && (this->identifier == NULL)) {
- _mesa_glsl_error(& loc, state, "formal parameter lacks a name");
- return NULL;
- }
-
- /* This only handles "vec4 foo[..]". The earlier specifier->glsl_type(...)
- * call already handled the "vec4[..] foo" case.
- */
- if (this->is_array) {
- type = process_array_type(&loc, type, this->array_size, state);
- }
-
- if (type->array_size() == 0) {
- _mesa_glsl_error(&loc, state, "arrays passed as parameters must have "
- "a declared size.");
- type = glsl_type::error_type;
- }
-
- is_void = false;
- ir_variable *var = new(ctx) ir_variable(type, this->identifier, ir_var_in);
-
- /* Apply any specified qualifiers to the parameter declaration. Note that
- * for function parameters the default mode is 'in'.
- */
- apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc);
-
- instructions->push_tail(var);
-
- /* Parameter declarations do not have r-values.
- */
- return NULL;
-}
-
-
-void
-ast_parameter_declarator::parameters_to_hir(exec_list *ast_parameters,
- bool formal,
- exec_list *ir_parameters,
- _mesa_glsl_parse_state *state)
-{
- ast_parameter_declarator *void_param = NULL;
- unsigned count = 0;
-
- foreach_list_typed (ast_parameter_declarator, param, link, ast_parameters) {
- param->formal_parameter = formal;
- param->hir(ir_parameters, state);
-
- if (param->is_void)
- void_param = param;
-
- count++;
- }
-
- if ((void_param != NULL) && (count > 1)) {
- YYLTYPE loc = void_param->get_location();
-
- _mesa_glsl_error(& loc, state,
- "`void' parameter must be only parameter");
- }
-}
-
-
-void
-emit_function(_mesa_glsl_parse_state *state, exec_list *instructions,
- ir_function *f)
-{
- /* Emit the new function header */
- if (state->current_function == NULL) {
- instructions->push_tail(f);
- } else {
- /* IR invariants disallow function declarations or definitions nested
- * within other function definitions. Insert the new ir_function
- * block in the instruction sequence before the ir_function block
- * containing the current ir_function_signature.
- */
- ir_function *const curr =
- const_cast<ir_function *>(state->current_function->function());
-
- curr->insert_before(f);
- }
-}
-
-
-ir_rvalue *
-ast_function::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- void *ctx = state;
- ir_function *f = NULL;
- ir_function_signature *sig = NULL;
- exec_list hir_parameters;
-
- const char *const name = identifier;
-
- /* From page 21 (page 27 of the PDF) of the GLSL 1.20 spec,
- *
- * "Function declarations (prototypes) cannot occur inside of functions;
- * they must be at global scope, or for the built-in functions, outside
- * the global scope."
- *
- * From page 27 (page 33 of the PDF) of the GLSL ES 1.00.16 spec,
- *
- * "User defined functions may only be defined within the global scope."
- *
- * Note that this language does not appear in GLSL 1.10.
- */
- if ((state->current_function != NULL) && (state->language_version != 110)) {
- YYLTYPE loc = this->get_location();
- _mesa_glsl_error(&loc, state,
- "declaration of function `%s' not allowed within "
- "function body", name);
- }
-
- /* From page 15 (page 21 of the PDF) of the GLSL 1.10 spec,
- *
- * "Identifiers starting with "gl_" are reserved for use by
- * OpenGL, and may not be declared in a shader as either a
- * variable or a function."
- */
- if (strncmp(name, "gl_", 3) == 0) {
- YYLTYPE loc = this->get_location();
- _mesa_glsl_error(&loc, state,
- "identifier `%s' uses reserved `gl_' prefix", name);
- }
-
- /* Convert the list of function parameters to HIR now so that they can be
- * used below to compare this function's signature with previously seen
- * signatures for functions with the same name.
- */
- ast_parameter_declarator::parameters_to_hir(& this->parameters,
- is_definition,
- & hir_parameters, state);
-
- const char *return_type_name;
- const glsl_type *return_type =
- this->return_type->specifier->glsl_type(& return_type_name, state);
-
- if (!return_type) {
- YYLTYPE loc = this->get_location();
- _mesa_glsl_error(&loc, state,
- "function `%s' has undeclared return type `%s'",
- name, return_type_name);
- return_type = glsl_type::error_type;
- }
-
- /* From page 56 (page 62 of the PDF) of the GLSL 1.30 spec:
- * "No qualifier is allowed on the return type of a function."
- */
- if (this->return_type->has_qualifiers()) {
- YYLTYPE loc = this->get_location();
- _mesa_glsl_error(& loc, state,
- "function `%s' return type has qualifiers", name);
- }
-
- /* Verify that this function's signature either doesn't match a previously
- * seen signature for a function with the same name, or, if a match is found,
- * that the previously seen signature does not have an associated definition.
- */
- f = state->symbols->get_function(name);
- if (f != NULL && (state->es_shader || f->has_user_signature())) {
- sig = f->exact_matching_signature(&hir_parameters);
- if (sig != NULL) {
- const char *badvar = sig->qualifiers_match(&hir_parameters);
- if (badvar != NULL) {
- YYLTYPE loc = this->get_location();
-
- _mesa_glsl_error(&loc, state, "function `%s' parameter `%s' "
- "qualifiers don't match prototype", name, badvar);
- }
-
- if (sig->return_type != return_type) {
- YYLTYPE loc = this->get_location();
-
- _mesa_glsl_error(&loc, state, "function `%s' return type doesn't "
- "match prototype", name);
- }
-
- if (is_definition && sig->is_defined) {
- YYLTYPE loc = this->get_location();
-
- _mesa_glsl_error(& loc, state, "function `%s' redefined", name);
- }
- }
- } else {
- f = new(ctx) ir_function(name);
- if (!state->symbols->add_function(f)) {
- /* This function name shadows a non-function use of the same name. */
- YYLTYPE loc = this->get_location();
-
- _mesa_glsl_error(&loc, state, "function name `%s' conflicts with "
- "non-function", name);
- return NULL;
- }
-
- emit_function(state, instructions, f);
- }
-
- /* Verify the return type of main() */
- if (strcmp(name, "main") == 0) {
- if (! return_type->is_void()) {
- YYLTYPE loc = this->get_location();
-
- _mesa_glsl_error(& loc, state, "main() must return void");
- }
-
- if (!hir_parameters.is_empty()) {
- YYLTYPE loc = this->get_location();
-
- _mesa_glsl_error(& loc, state, "main() must not take any parameters");
- }
- }
-
- /* Finish storing the information about this new function in its signature.
- */
- if (sig == NULL) {
- sig = new(ctx) ir_function_signature(return_type);
- f->add_signature(sig);
- }
-
- sig->replace_parameters(&hir_parameters);
- signature = sig;
-
- /* Function declarations (prototypes) do not have r-values.
- */
- return NULL;
-}
-
-
-ir_rvalue *
-ast_function_definition::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- prototype->is_definition = true;
- prototype->hir(instructions, state);
-
- ir_function_signature *signature = prototype->signature;
- if (signature == NULL)
- return NULL;
-
- assert(state->current_function == NULL);
- state->current_function = signature;
- state->found_return = false;
-
- /* Duplicate parameters declared in the prototype as concrete variables.
- * Add these to the symbol table.
- */
- state->symbols->push_scope();
- foreach_iter(exec_list_iterator, iter, signature->parameters) {
- ir_variable *const var = ((ir_instruction *) iter.get())->as_variable();
-
- assert(var != NULL);
-
- /* The only way a parameter would "exist" is if two parameters have
- * the same name.
- */
- if (state->symbols->name_declared_this_scope(var->name)) {
- YYLTYPE loc = this->get_location();
-
- _mesa_glsl_error(& loc, state, "parameter `%s' redeclared", var->name);
- } else {
- state->symbols->add_variable(var);
- }
- }
-
- /* Convert the body of the function to HIR. */
- this->body->hir(&signature->body, state);
- signature->is_defined = true;
-
- state->symbols->pop_scope();
-
- assert(state->current_function == signature);
- state->current_function = NULL;
-
- if (!signature->return_type->is_void() && !state->found_return) {
- YYLTYPE loc = this->get_location();
- _mesa_glsl_error(& loc, state, "function `%s' has non-void return type "
- "%s, but no return statement",
- signature->function_name(),
- signature->return_type->name);
- }
-
- /* Function definitions do not have r-values.
- */
- return NULL;
-}
-
-
-ir_rvalue *
-ast_jump_statement::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- void *ctx = state;
-
- switch (mode) {
- case ast_return: {
- ir_return *inst;
- assert(state->current_function);
-
- if (opt_return_value) {
- ir_rvalue *const ret = opt_return_value->hir(instructions, state);
-
- /* The value of the return type can be NULL if the shader says
- * 'return foo();' and foo() is a function that returns void.
- *
- * NOTE: The GLSL spec doesn't say that this is an error. The type
- * of the return value is void. If the return type of the function is
- * also void, then this should compile without error. Seriously.
- */
- const glsl_type *const ret_type =
- (ret == NULL) ? glsl_type::void_type : ret->type;
-
- /* Implicit conversions are not allowed for return values. */
- if (state->current_function->return_type != ret_type) {
- YYLTYPE loc = this->get_location();
-
- _mesa_glsl_error(& loc, state,
- "`return' with wrong type %s, in function `%s' "
- "returning %s",
- ret_type->name,
- state->current_function->function_name(),
- state->current_function->return_type->name);
- }
-
- inst = new(ctx) ir_return(ret);
- } else {
- if (state->current_function->return_type->base_type !=
- GLSL_TYPE_VOID) {
- YYLTYPE loc = this->get_location();
-
- _mesa_glsl_error(& loc, state,
- "`return' with no value, in function %s returning "
- "non-void",
- state->current_function->function_name());
- }
- inst = new(ctx) ir_return;
- }
-
- state->found_return = true;
- instructions->push_tail(inst);
- break;
- }
-
- case ast_discard:
- if (state->target != fragment_shader) {
- YYLTYPE loc = this->get_location();
-
- _mesa_glsl_error(& loc, state,
- "`discard' may only appear in a fragment shader");
- }
- instructions->push_tail(new(ctx) ir_discard);
- break;
-
- case ast_break:
- case ast_continue:
- /* FINISHME: Handle switch-statements. They cannot contain 'continue',
- * FINISHME: and they use a different IR instruction for 'break'.
- */
- /* FINISHME: Correctly handle the nesting. If a switch-statement is
- * FINISHME: inside a loop, a 'continue' is valid and will bind to the
- * FINISHME: loop.
- */
- if (state->loop_or_switch_nesting == NULL) {
- YYLTYPE loc = this->get_location();
-
- _mesa_glsl_error(& loc, state,
- "`%s' may only appear in a loop",
- (mode == ast_break) ? "break" : "continue");
- } else {
- ir_loop *const loop = state->loop_or_switch_nesting->as_loop();
-
- /* Inline the for loop expression again, since we don't know
- * where near the end of the loop body the normal copy of it
- * is going to be placed.
- */
- if (mode == ast_continue &&
- state->loop_or_switch_nesting_ast->rest_expression) {
- state->loop_or_switch_nesting_ast->rest_expression->hir(instructions,
- state);
- }
-
- if (loop != NULL) {
- ir_loop_jump *const jump =
- new(ctx) ir_loop_jump((mode == ast_break)
- ? ir_loop_jump::jump_break
- : ir_loop_jump::jump_continue);
- instructions->push_tail(jump);
- }
- }
-
- break;
- }
-
- /* Jump instructions do not have r-values.
- */
- return NULL;
-}
-
-
-ir_rvalue *
-ast_selection_statement::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- void *ctx = state;
-
- ir_rvalue *const condition = this->condition->hir(instructions, state);
-
- /* From page 66 (page 72 of the PDF) of the GLSL 1.50 spec:
- *
- * "Any expression whose type evaluates to a Boolean can be used as the
- * conditional expression bool-expression. Vector types are not accepted
- * as the expression to if."
- *
- * The checks are separated so that higher quality diagnostics can be
- * generated for cases where both rules are violated.
- */
- if (!condition->type->is_boolean() || !condition->type->is_scalar()) {
- YYLTYPE loc = this->condition->get_location();
-
- _mesa_glsl_error(& loc, state, "if-statement condition must be scalar "
- "boolean");
- }
-
- ir_if *const stmt = new(ctx) ir_if(condition);
-
- if (then_statement != NULL) {
- state->symbols->push_scope();
- then_statement->hir(& stmt->then_instructions, state);
- state->symbols->pop_scope();
- }
-
- if (else_statement != NULL) {
- state->symbols->push_scope();
- else_statement->hir(& stmt->else_instructions, state);
- state->symbols->pop_scope();
- }
-
- instructions->push_tail(stmt);
-
- /* if-statements do not have r-values.
- */
- return NULL;
-}
-
-
-void
-ast_iteration_statement::condition_to_hir(ir_loop *stmt,
- struct _mesa_glsl_parse_state *state)
-{
- void *ctx = state;
-
- if (condition != NULL) {
- ir_rvalue *const cond =
- condition->hir(& stmt->body_instructions, state);
-
- if ((cond == NULL)
- || !cond->type->is_boolean() || !cond->type->is_scalar()) {
- YYLTYPE loc = condition->get_location();
-
- _mesa_glsl_error(& loc, state,
- "loop condition must be scalar boolean");
- } else {
- /* As the first code in the loop body, generate a block that looks
- * like 'if (!condition) break;' as the loop termination condition.
- */
- ir_rvalue *const not_cond =
- new(ctx) ir_expression(ir_unop_logic_not, glsl_type::bool_type, cond,
- NULL);
-
- ir_if *const if_stmt = new(ctx) ir_if(not_cond);
-
- ir_jump *const break_stmt =
- new(ctx) ir_loop_jump(ir_loop_jump::jump_break);
-
- if_stmt->then_instructions.push_tail(break_stmt);
- stmt->body_instructions.push_tail(if_stmt);
- }
- }
-}
-
-
-ir_rvalue *
-ast_iteration_statement::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- void *ctx = state;
-
- /* For-loops and while-loops start a new scope, but do-while loops do not.
- */
- if (mode != ast_do_while)
- state->symbols->push_scope();
-
- if (init_statement != NULL)
- init_statement->hir(instructions, state);
-
- ir_loop *const stmt = new(ctx) ir_loop();
- instructions->push_tail(stmt);
-
- /* Track the current loop and / or switch-statement nesting.
- */
- ir_instruction *const nesting = state->loop_or_switch_nesting;
- ast_iteration_statement *nesting_ast = state->loop_or_switch_nesting_ast;
-
- state->loop_or_switch_nesting = stmt;
- state->loop_or_switch_nesting_ast = this;
-
- if (mode != ast_do_while)
- condition_to_hir(stmt, state);
-
- if (body != NULL)
- body->hir(& stmt->body_instructions, state);
-
- if (rest_expression != NULL)
- rest_expression->hir(& stmt->body_instructions, state);
-
- if (mode == ast_do_while)
- condition_to_hir(stmt, state);
-
- if (mode != ast_do_while)
- state->symbols->pop_scope();
-
- /* Restore previous nesting before returning.
- */
- state->loop_or_switch_nesting = nesting;
- state->loop_or_switch_nesting_ast = nesting_ast;
-
- /* Loops do not have r-values.
- */
- return NULL;
-}
-
-
-ir_rvalue *
-ast_type_specifier::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- if (!this->is_precision_statement && this->structure == NULL)
- return NULL;
-
- YYLTYPE loc = this->get_location();
-
- if (this->precision != ast_precision_none
- && state->language_version != 100
- && state->language_version < 130) {
- _mesa_glsl_error(&loc, state,
- "precision qualifiers exist only in "
- "GLSL ES 1.00, and GLSL 1.30 and later");
- return NULL;
- }
- if (this->precision != ast_precision_none
- && this->structure != NULL) {
- _mesa_glsl_error(&loc, state,
- "precision qualifiers do not apply to structures");
- return NULL;
- }
-
- /* If this is a precision statement, check that the type to which it is
- * applied is either float or int.
- *
- * From section 4.5.3 of the GLSL 1.30 spec:
- * "The precision statement
- * precision precision-qualifier type;
- * can be used to establish a default precision qualifier. The type
- * field can be either int or float [...]. Any other types or
- * qualifiers will result in an error.
- */
- if (this->is_precision_statement) {
- assert(this->precision != ast_precision_none);
- assert(this->structure == NULL); /* The check for structures was
- * performed above. */
- if (this->is_array) {
- _mesa_glsl_error(&loc, state,
- "default precision statements do not apply to "
- "arrays");
- return NULL;
- }
- if (this->type_specifier != ast_float
- && this->type_specifier != ast_int) {
- _mesa_glsl_error(&loc, state,
- "default precision statements apply only to types "
- "float and int");
- return NULL;
- }
-
- /* FINISHME: Translate precision statements into IR. */
- return NULL;
- }
-
- if (this->structure != NULL)
- return this->structure->hir(instructions, state);
-
- return NULL;
-}
-
-
-ir_rvalue *
-ast_struct_specifier::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
-{
- unsigned decl_count = 0;
-
- /* Make an initial pass over the list of structure fields to determine how
- * many there are. Each element in this list is an ast_declarator_list.
- * This means that we actually need to count the number of elements in the
- * 'declarations' list in each of the elements.
- */
- foreach_list_typed (ast_declarator_list, decl_list, link,
- &this->declarations) {
- foreach_list_const (decl_ptr, & decl_list->declarations) {
- decl_count++;
- }
- }
-
- /* Allocate storage for the structure fields and process the field
- * declarations. As the declarations are processed, try to also convert
- * the types to HIR. This ensures that structure definitions embedded in
- * other structure definitions are processed.
- */
- glsl_struct_field *const fields = ralloc_array(state, glsl_struct_field,
- decl_count);
-
- unsigned i = 0;
- foreach_list_typed (ast_declarator_list, decl_list, link,
- &this->declarations) {
- const char *type_name;
-
- decl_list->type->specifier->hir(instructions, state);
-
- /* Section 10.9 of the GLSL ES 1.00 specification states that
- * embedded structure definitions have been removed from the language.
- */
- if (state->es_shader && decl_list->type->specifier->structure != NULL) {
- YYLTYPE loc = this->get_location();
- _mesa_glsl_error(&loc, state, "Embedded structure definitions are "
- "not allowed in GLSL ES 1.00.");
- }
-
- const glsl_type *decl_type =
- decl_list->type->specifier->glsl_type(& type_name, state);
-
- foreach_list_typed (ast_declaration, decl, link,
- &decl_list->declarations) {
- const struct glsl_type *field_type = decl_type;
- if (decl->is_array) {
- YYLTYPE loc = decl->get_location();
- field_type = process_array_type(&loc, decl_type, decl->array_size,
- state);
- }
- fields[i].type = (field_type != NULL)
- ? field_type : glsl_type::error_type;
- fields[i].name = decl->identifier;
- i++;
- }
- }
-
- assert(i == decl_count);
-
- const glsl_type *t =
- glsl_type::get_record_instance(fields, decl_count, this->name);
-
- YYLTYPE loc = this->get_location();
- if (!state->symbols->add_type(name, t)) {
- _mesa_glsl_error(& loc, state, "struct `%s' previously defined", name);
- } else {
- 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;
- state->num_user_structures++;
- }
- }
-
- /* Structure type definitions do not have r-values.
- */
- return NULL;
-}
+/*
+ * Copyright © 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 (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.
+ */
+
+/**
+ * \file ast_to_hir.c
+ * Convert abstract syntax to to high-level intermediate reprensentation (HIR).
+ *
+ * During the conversion to HIR, the majority of the symantic checking is
+ * preformed on the program. This includes:
+ *
+ * * Symbol table management
+ * * Type checking
+ * * Function binding
+ *
+ * The majority of this work could be done during parsing, and the parser could
+ * probably generate HIR directly. However, this results in frequent changes
+ * to the parser code. Since we do not assume that every system this complier
+ * is built on will have Flex and Bison installed, we have to store the code
+ * generated by these tools in our version control system. In other parts of
+ * the system we've seen problems where a parser was changed but the generated
+ * code was not committed, merge conflicts where created because two developers
+ * had slightly different versions of Bison installed, etc.
+ *
+ * I have also noticed that running Bison generated parsers in GDB is very
+ * irritating. When you get a segfault on '$$ = $1->foo', you can't very
+ * well 'print $1' in GDB.
+ *
+ * As a result, my preference is to put as little C code as possible in the
+ * parser (and lexer) sources.
+ */
+
+#include "main/core.h" /* for struct gl_extensions */
+#include "glsl_symbol_table.h"
+#include "glsl_parser_extras.h"
+#include "ast.h"
+#include "glsl_types.h"
+#include "ir.h"
+
+void
+_mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
+{
+ _mesa_glsl_initialize_variables(instructions, state);
+ _mesa_glsl_initialize_functions(state);
+
+ state->symbols->language_version = state->language_version;
+
+ state->current_function = NULL;
+
+ /* Section 4.2 of the GLSL 1.20 specification states:
+ * "The built-in functions are scoped in a scope outside the global scope
+ * users declare global variables in. That is, a shader's global scope,
+ * available for user-defined functions and global variables, is nested
+ * inside the scope containing the built-in functions."
+ *
+ * Since built-in functions like ftransform() access built-in variables,
+ * it follows that those must be in the outer scope as well.
+ *
+ * We push scope here to create this nesting effect...but don't pop.
+ * This way, a shader's globals are still in the symbol table for use
+ * by the linker.
+ */
+ state->symbols->push_scope();
+
+ foreach_list_typed (ast_node, ast, link, & state->translation_unit)
+ ast->hir(instructions, state);
+}
+
+
+/**
+ * If a conversion is available, convert one operand to a different type
+ *
+ * The \c from \c ir_rvalue is converted "in place".
+ *
+ * \param to Type that the operand it to be converted to
+ * \param from Operand that is being converted
+ * \param state GLSL compiler state
+ *
+ * \return
+ * If a conversion is possible (or unnecessary), \c true is returned.
+ * Otherwise \c false is returned.
+ */
+bool
+apply_implicit_conversion(const glsl_type *to, ir_rvalue * &from,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+ if (to->base_type == from->type->base_type)
+ return true;
+
+ /* This conversion was added in GLSL 1.20. If the compilation mode is
+ * GLSL 1.10, the conversion is skipped.
+ */
+ if (state->language_version < 120)
+ return false;
+
+ /* From page 27 (page 33 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "There are no implicit array or structure conversions. For
+ * example, an array of int cannot be implicitly converted to an
+ * array of float. There are no implicit conversions between
+ * signed and unsigned integers."
+ */
+ /* FINISHME: The above comment is partially a lie. There is int/uint
+ * FINISHME: conversion for immediate constants.
+ */
+ if (!to->is_float() || !from->type->is_numeric())
+ return false;
+
+ /* Convert to a floating point type with the same number of components
+ * as the original type - i.e. int to float, not int to vec4.
+ */
+ to = glsl_type::get_instance(GLSL_TYPE_FLOAT, from->type->vector_elements,
+ from->type->matrix_columns);
+
+ switch (from->type->base_type) {
+ case GLSL_TYPE_INT:
+ from = new(ctx) ir_expression(ir_unop_i2f, to, from, NULL);
+ break;
+ case GLSL_TYPE_UINT:
+ from = new(ctx) ir_expression(ir_unop_u2f, to, from, NULL);
+ break;
+ case GLSL_TYPE_BOOL:
+ from = new(ctx) ir_expression(ir_unop_b2f, to, from, NULL);
+ break;
+ default:
+ assert(0);
+ }
+
+ return true;
+}
+
+
+static const struct glsl_type *
+arithmetic_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b,
+ bool multiply,
+ struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
+{
+ const glsl_type *type_a = value_a->type;
+ const glsl_type *type_b = value_b->type;
+
+ /* From GLSL 1.50 spec, page 56:
+ *
+ * "The arithmetic binary operators add (+), subtract (-),
+ * multiply (*), and divide (/) operate on integer and
+ * floating-point scalars, vectors, and matrices."
+ */
+ if (!type_a->is_numeric() || !type_b->is_numeric()) {
+ _mesa_glsl_error(loc, state,
+ "Operands to arithmetic operators must be numeric");
+ return glsl_type::error_type;
+ }
+
+
+ /* "If one operand is floating-point based and the other is
+ * not, then the conversions from Section 4.1.10 "Implicit
+ * Conversions" are applied to the non-floating-point-based operand."
+ */
+ if (!apply_implicit_conversion(type_a, value_b, state)
+ && !apply_implicit_conversion(type_b, value_a, state)) {
+ _mesa_glsl_error(loc, state,
+ "Could not implicitly convert operands to "
+ "arithmetic operator");
+ return glsl_type::error_type;
+ }
+ type_a = value_a->type;
+ type_b = value_b->type;
+
+ /* "If the operands are integer types, they must both be signed or
+ * both be unsigned."
+ *
+ * From this rule and the preceeding conversion it can be inferred that
+ * both types must be GLSL_TYPE_FLOAT, or GLSL_TYPE_UINT, or GLSL_TYPE_INT.
+ * The is_numeric check above already filtered out the case where either
+ * type is not one of these, so now the base types need only be tested for
+ * equality.
+ */
+ if (type_a->base_type != type_b->base_type) {
+ _mesa_glsl_error(loc, state,
+ "base type mismatch for arithmetic operator");
+ return glsl_type::error_type;
+ }
+
+ /* "All arithmetic binary operators result in the same fundamental type
+ * (signed integer, unsigned integer, or floating-point) as the
+ * operands they operate on, after operand type conversion. After
+ * conversion, the following cases are valid
+ *
+ * * The two operands are scalars. In this case the operation is
+ * applied, resulting in a scalar."
+ */
+ if (type_a->is_scalar() && type_b->is_scalar())
+ return type_a;
+
+ /* "* One operand is a scalar, and the other is a vector or matrix.
+ * In this case, the scalar operation is applied independently to each
+ * component of the vector or matrix, resulting in the same size
+ * vector or matrix."
+ */
+ if (type_a->is_scalar()) {
+ if (!type_b->is_scalar())
+ return type_b;
+ } else if (type_b->is_scalar()) {
+ return type_a;
+ }
+
+ /* All of the combinations of <scalar, scalar>, <vector, scalar>,
+ * <scalar, vector>, <scalar, matrix>, and <matrix, scalar> have been
+ * handled.
+ */
+ assert(!type_a->is_scalar());
+ assert(!type_b->is_scalar());
+
+ /* "* The two operands are vectors of the same size. In this case, the
+ * operation is done component-wise resulting in the same size
+ * vector."
+ */
+ if (type_a->is_vector() && type_b->is_vector()) {
+ if (type_a == type_b) {
+ return type_a;
+ } else {
+ _mesa_glsl_error(loc, state,
+ "vector size mismatch for arithmetic operator");
+ return glsl_type::error_type;
+ }
+ }
+
+ /* All of the combinations of <scalar, scalar>, <vector, scalar>,
+ * <scalar, vector>, <scalar, matrix>, <matrix, scalar>, and
+ * <vector, vector> have been handled. At least one of the operands must
+ * be matrix. Further, since there are no integer matrix types, the base
+ * type of both operands must be float.
+ */
+ assert(type_a->is_matrix() || type_b->is_matrix());
+ assert(type_a->base_type == GLSL_TYPE_FLOAT);
+ assert(type_b->base_type == GLSL_TYPE_FLOAT);
+
+ /* "* The operator is add (+), subtract (-), or divide (/), and the
+ * operands are matrices with the same number of rows and the same
+ * number of columns. In this case, the operation is done component-
+ * wise resulting in the same size matrix."
+ * * The operator is multiply (*), where both operands are matrices or
+ * one operand is a vector and the other a matrix. A right vector
+ * operand is treated as a column vector and a left vector operand as a
+ * row vector. In all these cases, it is required that the number of
+ * columns of the left operand is equal to the number of rows of the
+ * right operand. Then, the multiply (*) operation does a linear
+ * algebraic multiply, yielding an object that has the same number of
+ * rows as the left operand and the same number of columns as the right
+ * operand. Section 5.10 "Vector and Matrix Operations" explains in
+ * more detail how vectors and matrices are operated on."
+ */
+ if (! multiply) {
+ if (type_a == type_b)
+ return type_a;
+ } else {
+ if (type_a->is_matrix() && type_b->is_matrix()) {
+ /* Matrix multiply. The columns of A must match the rows of B. Given
+ * the other previously tested constraints, this means the vector type
+ * of a row from A must be the same as the vector type of a column from
+ * B.
+ */
+ if (type_a->row_type() == type_b->column_type()) {
+ /* The resulting matrix has the number of columns of matrix B and
+ * the number of rows of matrix A. We get the row count of A by
+ * looking at the size of a vector that makes up a column. The
+ * transpose (size of a row) is done for B.
+ */
+ const glsl_type *const type =
+ glsl_type::get_instance(type_a->base_type,
+ type_a->column_type()->vector_elements,
+ type_b->row_type()->vector_elements);
+ assert(type != glsl_type::error_type);
+
+ return type;
+ }
+ } else if (type_a->is_matrix()) {
+ /* A is a matrix and B is a column vector. Columns of A must match
+ * rows of B. Given the other previously tested constraints, this
+ * means the vector type of a row from A must be the same as the
+ * vector the type of B.
+ */
+ if (type_a->row_type() == type_b) {
+ /* The resulting vector has a number of elements equal to
+ * the number of rows of matrix A. */
+ const glsl_type *const type =
+ glsl_type::get_instance(type_a->base_type,
+ type_a->column_type()->vector_elements,
+ 1);
+ assert(type != glsl_type::error_type);
+
+ return type;
+ }
+ } else {
+ assert(type_b->is_matrix());
+
+ /* A is a row vector and B is a matrix. Columns of A must match rows
+ * of B. Given the other previously tested constraints, this means
+ * the type of A must be the same as the vector type of a column from
+ * B.
+ */
+ if (type_a == type_b->column_type()) {
+ /* The resulting vector has a number of elements equal to
+ * the number of columns of matrix B. */
+ const glsl_type *const type =
+ glsl_type::get_instance(type_a->base_type,
+ type_b->row_type()->vector_elements,
+ 1);
+ assert(type != glsl_type::error_type);
+
+ return type;
+ }
+ }
+
+ _mesa_glsl_error(loc, state, "size mismatch for matrix multiplication");
+ return glsl_type::error_type;
+ }
+
+
+ /* "All other cases are illegal."
+ */
+ _mesa_glsl_error(loc, state, "type mismatch");
+ return glsl_type::error_type;
+}
+
+
+static const struct glsl_type *
+unary_arithmetic_result_type(const struct glsl_type *type,
+ struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
+{
+ /* From GLSL 1.50 spec, page 57:
+ *
+ * "The arithmetic unary operators negate (-), post- and pre-increment
+ * and decrement (-- and ++) operate on integer or floating-point
+ * values (including vectors and matrices). All unary operators work
+ * component-wise on their operands. These result with the same type
+ * they operated on."
+ */
+ if (!type->is_numeric()) {
+ _mesa_glsl_error(loc, state,
+ "Operands to arithmetic operators must be numeric");
+ return glsl_type::error_type;
+ }
+
+ return type;
+}
+
+/**
+ * \brief Return the result type of a bit-logic operation.
+ *
+ * If the given types to the bit-logic operator are invalid, return
+ * glsl_type::error_type.
+ *
+ * \param type_a Type of LHS of bit-logic op
+ * \param type_b Type of RHS of bit-logic op
+ */
+static const struct glsl_type *
+bit_logic_result_type(const struct glsl_type *type_a,
+ const struct glsl_type *type_b,
+ ast_operators op,
+ struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
+{
+ if (state->language_version < 130) {
+ _mesa_glsl_error(loc, state, "bit operations require GLSL 1.30");
+ return glsl_type::error_type;
+ }
+
+ /* From page 50 (page 56 of PDF) of GLSL 1.30 spec:
+ *
+ * "The bitwise operators and (&), exclusive-or (^), and inclusive-or
+ * (|). The operands must be of type signed or unsigned integers or
+ * integer vectors."
+ */
+ if (!type_a->is_integer()) {
+ _mesa_glsl_error(loc, state, "LHS of `%s' must be an integer",
+ ast_expression::operator_string(op));
+ return glsl_type::error_type;
+ }
+ if (!type_b->is_integer()) {
+ _mesa_glsl_error(loc, state, "RHS of `%s' must be an integer",
+ ast_expression::operator_string(op));
+ return glsl_type::error_type;
+ }
+
+ /* "The fundamental types of the operands (signed or unsigned) must
+ * match,"
+ */
+ if (type_a->base_type != type_b->base_type) {
+ _mesa_glsl_error(loc, state, "operands of `%s' must have the same "
+ "base type", ast_expression::operator_string(op));
+ return glsl_type::error_type;
+ }
+
+ /* "The operands cannot be vectors of differing size." */
+ if (type_a->is_vector() &&
+ type_b->is_vector() &&
+ type_a->vector_elements != type_b->vector_elements) {
+ _mesa_glsl_error(loc, state, "operands of `%s' cannot be vectors of "
+ "different sizes", ast_expression::operator_string(op));
+ return glsl_type::error_type;
+ }
+
+ /* "If one operand is a scalar and the other a vector, the scalar is
+ * applied component-wise to the vector, resulting in the same type as
+ * the vector. The fundamental types of the operands [...] will be the
+ * resulting fundamental type."
+ */
+ if (type_a->is_scalar())
+ return type_b;
+ else
+ return type_a;
+}
+
+static const struct glsl_type *
+modulus_result_type(const struct glsl_type *type_a,
+ const struct glsl_type *type_b,
+ struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
+{
+ if (state->language_version < 130) {
+ _mesa_glsl_error(loc, state,
+ "operator '%%' is reserved in %s",
+ state->version_string);
+ return glsl_type::error_type;
+ }
+
+ /* From GLSL 1.50 spec, page 56:
+ * "The operator modulus (%) operates on signed or unsigned integers or
+ * integer vectors. The operand types must both be signed or both be
+ * unsigned."
+ */
+ if (!type_a->is_integer() || !type_b->is_integer()
+ || (type_a->base_type != type_b->base_type)) {
+ _mesa_glsl_error(loc, state, "type mismatch");
+ return glsl_type::error_type;
+ }
+
+ /* "The operands cannot be vectors of differing size. If one operand is
+ * a scalar and the other vector, then the scalar is applied component-
+ * wise to the vector, resulting in the same type as the vector. If both
+ * are vectors of the same size, the result is computed component-wise."
+ */
+ if (type_a->is_vector()) {
+ if (!type_b->is_vector()
+ || (type_a->vector_elements == type_b->vector_elements))
+ return type_a;
+ } else
+ return type_b;
+
+ /* "The operator modulus (%) is not defined for any other data types
+ * (non-integer types)."
+ */
+ _mesa_glsl_error(loc, state, "type mismatch");
+ return glsl_type::error_type;
+}
+
+
+static const struct glsl_type *
+relational_result_type(ir_rvalue * &value_a, ir_rvalue * &value_b,
+ struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
+{
+ const glsl_type *type_a = value_a->type;
+ const glsl_type *type_b = value_b->type;
+
+ /* From GLSL 1.50 spec, page 56:
+ * "The relational operators greater than (>), less than (<), greater
+ * than or equal (>=), and less than or equal (<=) operate only on
+ * scalar integer and scalar floating-point expressions."
+ */
+ if (!type_a->is_numeric()
+ || !type_b->is_numeric()
+ || !type_a->is_scalar()
+ || !type_b->is_scalar()) {
+ _mesa_glsl_error(loc, state,
+ "Operands to relational operators must be scalar and "
+ "numeric");
+ return glsl_type::error_type;
+ }
+
+ /* "Either the operands' types must match, or the conversions from
+ * Section 4.1.10 "Implicit Conversions" will be applied to the integer
+ * operand, after which the types must match."
+ */
+ if (!apply_implicit_conversion(type_a, value_b, state)
+ && !apply_implicit_conversion(type_b, value_a, state)) {
+ _mesa_glsl_error(loc, state,
+ "Could not implicitly convert operands to "
+ "relational operator");
+ return glsl_type::error_type;
+ }
+ type_a = value_a->type;
+ type_b = value_b->type;
+
+ if (type_a->base_type != type_b->base_type) {
+ _mesa_glsl_error(loc, state, "base type mismatch");
+ return glsl_type::error_type;
+ }
+
+ /* "The result is scalar Boolean."
+ */
+ return glsl_type::bool_type;
+}
+
+/**
+ * \brief Return the result type of a bit-shift operation.
+ *
+ * If the given types to the bit-shift operator are invalid, return
+ * glsl_type::error_type.
+ *
+ * \param type_a Type of LHS of bit-shift op
+ * \param type_b Type of RHS of bit-shift op
+ */
+static const struct glsl_type *
+shift_result_type(const struct glsl_type *type_a,
+ const struct glsl_type *type_b,
+ ast_operators op,
+ struct _mesa_glsl_parse_state *state, YYLTYPE *loc)
+{
+ if (state->language_version < 130) {
+ _mesa_glsl_error(loc, state, "bit operations require GLSL 1.30");
+ return glsl_type::error_type;
+ }
+
+ /* From page 50 (page 56 of the PDF) of the GLSL 1.30 spec:
+ *
+ * "The shift operators (<<) and (>>). For both operators, the operands
+ * must be signed or unsigned integers or integer vectors. One operand
+ * can be signed while the other is unsigned."
+ */
+ if (!type_a->is_integer()) {
+ _mesa_glsl_error(loc, state, "LHS of operator %s must be an integer or "
+ "integer vector", ast_expression::operator_string(op));
+ return glsl_type::error_type;
+
+ }
+ if (!type_b->is_integer()) {
+ _mesa_glsl_error(loc, state, "RHS of operator %s must be an integer or "
+ "integer vector", ast_expression::operator_string(op));
+ return glsl_type::error_type;
+ }
+
+ /* "If the first operand is a scalar, the second operand has to be
+ * a scalar as well."
+ */
+ if (type_a->is_scalar() && !type_b->is_scalar()) {
+ _mesa_glsl_error(loc, state, "If the first operand of %s is scalar, the "
+ "second must be scalar as well",
+ ast_expression::operator_string(op));
+ return glsl_type::error_type;
+ }
+
+ /* If both operands are vectors, check that they have same number of
+ * elements.
+ */
+ if (type_a->is_vector() &&
+ type_b->is_vector() &&
+ type_a->vector_elements != type_b->vector_elements) {
+ _mesa_glsl_error(loc, state, "Vector operands to operator %s must "
+ "have same number of elements",
+ ast_expression::operator_string(op));
+ return glsl_type::error_type;
+ }
+
+ /* "In all cases, the resulting type will be the same type as the left
+ * operand."
+ */
+ return type_a;
+}
+
+/**
+ * Validates that a value can be assigned to a location with a specified type
+ *
+ * Validates that \c rhs can be assigned to some location. If the types are
+ * not an exact match but an automatic conversion is possible, \c rhs will be
+ * converted.
+ *
+ * \return
+ * \c NULL if \c rhs cannot be assigned to a location with type \c lhs_type.
+ * Otherwise the actual RHS to be assigned will be returned. This may be
+ * \c rhs, or it may be \c rhs after some type conversion.
+ *
+ * \note
+ * In addition to being used for assignments, this function is used to
+ * type-check return values.
+ */
+ir_rvalue *
+validate_assignment(struct _mesa_glsl_parse_state *state,
+ const glsl_type *lhs_type, ir_rvalue *rhs,
+ bool is_initializer)
+{
+ /* If there is already some error in the RHS, just return it. Anything
+ * else will lead to an avalanche of error message back to the user.
+ */
+ if (rhs->type->is_error())
+ return rhs;
+
+ /* If the types are identical, the assignment can trivially proceed.
+ */
+ if (rhs->type == lhs_type)
+ return rhs;
+
+ /* If the array element types are the same and the size of the LHS is zero,
+ * the assignment is okay for initializers embedded in variable
+ * declarations.
+ *
+ * Note: Whole-array assignments are not permitted in GLSL 1.10, but this
+ * is handled by ir_dereference::is_lvalue.
+ */
+ if (is_initializer && lhs_type->is_array() && rhs->type->is_array()
+ && (lhs_type->element_type() == rhs->type->element_type())
+ && (lhs_type->array_size() == 0)) {
+ return rhs;
+ }
+
+ /* Check for implicit conversion in GLSL 1.20 */
+ if (apply_implicit_conversion(lhs_type, rhs, state)) {
+ if (rhs->type == lhs_type)
+ return rhs;
+ }
+
+ return NULL;
+}
+
+ir_rvalue *
+do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
+ ir_rvalue *lhs, ir_rvalue *rhs, bool is_initializer,
+ YYLTYPE lhs_loc)
+{
+ void *ctx = state;
+ bool error_emitted = (lhs->type->is_error() || rhs->type->is_error());
+
+ if (!error_emitted) {
+ if (lhs->variable_referenced() != NULL
+ && lhs->variable_referenced()->read_only) {
+ _mesa_glsl_error(&lhs_loc, state,
+ "assignment to read-only variable '%s'",
+ lhs->variable_referenced()->name);
+ error_emitted = true;
+
+ } else if (!lhs->is_lvalue()) {
+ _mesa_glsl_error(& lhs_loc, state, "non-lvalue in assignment");
+ error_emitted = true;
+ }
+
+ if (state->es_shader && lhs->type->is_array()) {
+ _mesa_glsl_error(&lhs_loc, state, "whole array assignment is not "
+ "allowed in GLSL ES 1.00.");
+ error_emitted = true;
+ }
+ }
+
+ ir_rvalue *new_rhs =
+ validate_assignment(state, lhs->type, rhs, is_initializer);
+ if (new_rhs == NULL) {
+ _mesa_glsl_error(& lhs_loc, state, "type mismatch");
+ } else {
+ rhs = new_rhs;
+
+ /* If the LHS array was not declared with a size, it takes it size from
+ * the RHS. If the LHS is an l-value and a whole array, it must be a
+ * dereference of a variable. Any other case would require that the LHS
+ * is either not an l-value or not a whole array.
+ */
+ if (lhs->type->array_size() == 0) {
+ ir_dereference *const d = lhs->as_dereference();
+
+ assert(d != NULL);
+
+ ir_variable *const var = d->variable_referenced();
+
+ assert(var != NULL);
+
+ if (var->max_array_access >= unsigned(rhs->type->array_size())) {
+ /* FINISHME: This should actually log the location of the RHS. */
+ _mesa_glsl_error(& lhs_loc, state, "array size must be > %u due to "
+ "previous access",
+ var->max_array_access);
+ }
+
+ var->type = glsl_type::get_array_instance(lhs->type->element_type(),
+ rhs->type->array_size());
+ d->type = var->type;
+ }
+ }
+
+ /* Most callers of do_assignment (assign, add_assign, pre_inc/dec,
+ * but not post_inc) need the converted assigned value as an rvalue
+ * to handle things like:
+ *
+ * i = j += 1;
+ *
+ * So we always just store the computed value being assigned to a
+ * temporary and return a deref of that temporary. If the rvalue
+ * ends up not being used, the temp will get copy-propagated out.
+ */
+ ir_variable *var = new(ctx) ir_variable(rhs->type, "assignment_tmp",
+ ir_var_temporary);
+ ir_dereference_variable *deref_var = new(ctx) ir_dereference_variable(var);
+ instructions->push_tail(var);
+ instructions->push_tail(new(ctx) ir_assignment(deref_var,
+ rhs,
+ NULL));
+ deref_var = new(ctx) ir_dereference_variable(var);
+
+ if (!error_emitted)
+ instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var, NULL));
+
+ return new(ctx) ir_dereference_variable(var);
+}
+
+static ir_rvalue *
+get_lvalue_copy(exec_list *instructions, ir_rvalue *lvalue)
+{
+ void *ctx = ralloc_parent(lvalue);
+ ir_variable *var;
+
+ var = new(ctx) ir_variable(lvalue->type, "_post_incdec_tmp",
+ ir_var_temporary);
+ instructions->push_tail(var);
+ var->mode = ir_var_auto;
+
+ instructions->push_tail(new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var),
+ lvalue, NULL));
+
+ /* Once we've created this temporary, mark it read only so it's no
+ * longer considered an lvalue.
+ */
+ var->read_only = true;
+
+ return new(ctx) ir_dereference_variable(var);
+}
+
+
+ir_rvalue *
+ast_node::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ (void) instructions;
+ (void) state;
+
+ return NULL;
+}
+
+static void
+mark_whole_array_access(ir_rvalue *access)
+{
+ ir_dereference_variable *deref = access->as_dereference_variable();
+
+ if (deref) {
+ deref->var->max_array_access = deref->type->length - 1;
+ }
+}
+
+static ir_rvalue *
+do_comparison(void *mem_ctx, int operation, ir_rvalue *op0, ir_rvalue *op1)
+{
+ int join_op;
+ ir_rvalue *cmp = NULL;
+
+ if (operation == ir_binop_all_equal)
+ join_op = ir_binop_logic_and;
+ else
+ join_op = ir_binop_logic_or;
+
+ switch (op0->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_BOOL:
+ return new(mem_ctx) ir_expression(operation, op0, op1);
+
+ case GLSL_TYPE_ARRAY: {
+ for (unsigned int i = 0; i < op0->type->length; i++) {
+ ir_rvalue *e0, *e1, *result;
+
+ e0 = new(mem_ctx) ir_dereference_array(op0->clone(mem_ctx, NULL),
+ new(mem_ctx) ir_constant(i));
+ e1 = new(mem_ctx) ir_dereference_array(op1->clone(mem_ctx, NULL),
+ new(mem_ctx) ir_constant(i));
+ result = do_comparison(mem_ctx, operation, e0, e1);
+
+ if (cmp) {
+ cmp = new(mem_ctx) ir_expression(join_op, cmp, result);
+ } else {
+ cmp = result;
+ }
+ }
+
+ mark_whole_array_access(op0);
+ mark_whole_array_access(op1);
+ break;
+ }
+
+ case GLSL_TYPE_STRUCT: {
+ for (unsigned int i = 0; i < op0->type->length; i++) {
+ ir_rvalue *e0, *e1, *result;
+ const char *field_name = op0->type->fields.structure[i].name;
+
+ e0 = new(mem_ctx) ir_dereference_record(op0->clone(mem_ctx, NULL),
+ field_name);
+ e1 = new(mem_ctx) ir_dereference_record(op1->clone(mem_ctx, NULL),
+ field_name);
+ result = do_comparison(mem_ctx, operation, e0, e1);
+
+ if (cmp) {
+ cmp = new(mem_ctx) ir_expression(join_op, cmp, result);
+ } else {
+ cmp = result;
+ }
+ }
+ break;
+ }
+
+ case GLSL_TYPE_ERROR:
+ case GLSL_TYPE_VOID:
+ case GLSL_TYPE_SAMPLER:
+ /* I assume a comparison of a struct containing a sampler just
+ * ignores the sampler present in the type.
+ */
+ break;
+
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+
+ if (cmp == NULL)
+ cmp = new(mem_ctx) ir_constant(true);
+
+ return cmp;
+}
+
+ir_rvalue *
+ast_expression::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+ static const int operations[AST_NUM_OPERATORS] = {
+ -1, /* ast_assign doesn't convert to ir_expression. */
+ -1, /* ast_plus doesn't convert to ir_expression. */
+ ir_unop_neg,
+ ir_binop_add,
+ ir_binop_sub,
+ ir_binop_mul,
+ ir_binop_div,
+ ir_binop_mod,
+ ir_binop_lshift,
+ ir_binop_rshift,
+ ir_binop_less,
+ ir_binop_greater,
+ ir_binop_lequal,
+ ir_binop_gequal,
+ ir_binop_all_equal,
+ ir_binop_any_nequal,
+ ir_binop_bit_and,
+ ir_binop_bit_xor,
+ ir_binop_bit_or,
+ ir_unop_bit_not,
+ ir_binop_logic_and,
+ ir_binop_logic_xor,
+ ir_binop_logic_or,
+ ir_unop_logic_not,
+
+ /* Note: The following block of expression types actually convert
+ * to multiple IR instructions.
+ */
+ ir_binop_mul, /* ast_mul_assign */
+ ir_binop_div, /* ast_div_assign */
+ ir_binop_mod, /* ast_mod_assign */
+ ir_binop_add, /* ast_add_assign */
+ ir_binop_sub, /* ast_sub_assign */
+ ir_binop_lshift, /* ast_ls_assign */
+ ir_binop_rshift, /* ast_rs_assign */
+ ir_binop_bit_and, /* ast_and_assign */
+ ir_binop_bit_xor, /* ast_xor_assign */
+ ir_binop_bit_or, /* ast_or_assign */
+
+ -1, /* ast_conditional doesn't convert to ir_expression. */
+ ir_binop_add, /* ast_pre_inc. */
+ ir_binop_sub, /* ast_pre_dec. */
+ ir_binop_add, /* ast_post_inc. */
+ ir_binop_sub, /* ast_post_dec. */
+ -1, /* ast_field_selection doesn't conv to ir_expression. */
+ -1, /* ast_array_index doesn't convert to ir_expression. */
+ -1, /* ast_function_call doesn't conv to ir_expression. */
+ -1, /* ast_identifier doesn't convert to ir_expression. */
+ -1, /* ast_int_constant doesn't convert to ir_expression. */
+ -1, /* ast_uint_constant doesn't conv to ir_expression. */
+ -1, /* ast_float_constant doesn't conv to ir_expression. */
+ -1, /* ast_bool_constant doesn't conv to ir_expression. */
+ -1, /* ast_sequence doesn't convert to ir_expression. */
+ };
+ ir_rvalue *result = NULL;
+ ir_rvalue *op[3];
+ const struct glsl_type *type = glsl_type::error_type;
+ bool error_emitted = false;
+ YYLTYPE loc;
+
+ loc = this->get_location();
+
+ switch (this->oper) {
+ case ast_assign: {
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
+
+ result = do_assignment(instructions, state, op[0], op[1], false,
+ this->subexpressions[0]->get_location());
+ error_emitted = result->type->is_error();
+ type = result->type;
+ break;
+ }
+
+ case ast_plus:
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+
+ type = unary_arithmetic_result_type(op[0]->type, state, & loc);
+
+ error_emitted = type->is_error();
+
+ result = op[0];
+ break;
+
+ case ast_neg:
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+
+ type = unary_arithmetic_result_type(op[0]->type, state, & loc);
+
+ error_emitted = type->is_error();
+
+ result = new(ctx) ir_expression(operations[this->oper], type,
+ op[0], NULL);
+ break;
+
+ case ast_add:
+ case ast_sub:
+ case ast_mul:
+ case ast_div:
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
+
+ type = arithmetic_result_type(op[0], op[1],
+ (this->oper == ast_mul),
+ state, & loc);
+ error_emitted = type->is_error();
+
+ result = new(ctx) ir_expression(operations[this->oper], type,
+ op[0], op[1]);
+ break;
+
+ case ast_mod:
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
+
+ type = modulus_result_type(op[0]->type, op[1]->type, state, & loc);
+
+ assert(operations[this->oper] == ir_binop_mod);
+
+ result = new(ctx) ir_expression(operations[this->oper], type,
+ op[0], op[1]);
+ error_emitted = type->is_error();
+ break;
+
+ case ast_lshift:
+ case ast_rshift:
+ if (state->language_version < 130) {
+ _mesa_glsl_error(&loc, state, "operator %s requires GLSL 1.30",
+ operator_string(this->oper));
+ error_emitted = true;
+ }
+
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
+ type = shift_result_type(op[0]->type, op[1]->type, this->oper, state,
+ &loc);
+ result = new(ctx) ir_expression(operations[this->oper], type,
+ op[0], op[1]);
+ error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
+ break;
+
+ case ast_less:
+ case ast_greater:
+ case ast_lequal:
+ case ast_gequal:
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
+
+ type = relational_result_type(op[0], op[1], state, & loc);
+
+ /* The relational operators must either generate an error or result
+ * in a scalar boolean. See page 57 of the GLSL 1.50 spec.
+ */
+ assert(type->is_error()
+ || ((type->base_type == GLSL_TYPE_BOOL)
+ && type->is_scalar()));
+
+ result = new(ctx) ir_expression(operations[this->oper], type,
+ op[0], op[1]);
+ error_emitted = type->is_error();
+ break;
+
+ case ast_nequal:
+ case ast_equal:
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
+
+ /* From page 58 (page 64 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "The equality operators equal (==), and not equal (!=)
+ * operate on all types. They result in a scalar Boolean. If
+ * the operand types do not match, then there must be a
+ * conversion from Section 4.1.10 "Implicit Conversions"
+ * applied to one operand that can make them match, in which
+ * case this conversion is done."
+ */
+ if ((!apply_implicit_conversion(op[0]->type, op[1], state)
+ && !apply_implicit_conversion(op[1]->type, op[0], state))
+ || (op[0]->type != op[1]->type)) {
+ _mesa_glsl_error(& loc, state, "operands of `%s' must have the same "
+ "type", (this->oper == ast_equal) ? "==" : "!=");
+ error_emitted = true;
+ } else if ((state->language_version <= 110)
+ && (op[0]->type->is_array() || op[1]->type->is_array())) {
+ _mesa_glsl_error(& loc, state, "array comparisons forbidden in "
+ "GLSL 1.10");
+ error_emitted = true;
+ }
+
+ result = do_comparison(ctx, operations[this->oper], op[0], op[1]);
+ type = glsl_type::bool_type;
+
+ assert(error_emitted || (result->type == glsl_type::bool_type));
+ break;
+
+ case ast_bit_and:
+ case ast_bit_xor:
+ case ast_bit_or:
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
+ type = bit_logic_result_type(op[0]->type, op[1]->type, this->oper,
+ state, &loc);
+ result = new(ctx) ir_expression(operations[this->oper], type,
+ op[0], op[1]);
+ error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
+ break;
+
+ case ast_bit_not:
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+
+ if (state->language_version < 130) {
+ _mesa_glsl_error(&loc, state, "bit-wise operations require GLSL 1.30");
+ error_emitted = true;
+ }
+
+ if (!op[0]->type->is_integer()) {
+ _mesa_glsl_error(&loc, state, "operand of `~' must be an integer");
+ error_emitted = true;
+ }
+
+ type = op[0]->type;
+ result = new(ctx) ir_expression(ir_unop_bit_not, type, op[0], NULL);
+ break;
+
+ case ast_logic_and: {
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+
+ if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) {
+ YYLTYPE loc = this->subexpressions[0]->get_location();
+
+ _mesa_glsl_error(& loc, state, "LHS of `%s' must be scalar boolean",
+ operator_string(this->oper));
+ error_emitted = true;
+ }
+
+ ir_constant *op0_const = op[0]->constant_expression_value();
+ if (op0_const) {
+ if (op0_const->value.b[0]) {
+ op[1] = this->subexpressions[1]->hir(instructions, state);
+
+ if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
+ YYLTYPE loc = this->subexpressions[1]->get_location();
+
+ _mesa_glsl_error(& loc, state,
+ "RHS of `%s' must be scalar boolean",
+ operator_string(this->oper));
+ error_emitted = true;
+ }
+ result = op[1];
+ } else {
+ result = op0_const;
+ }
+ type = glsl_type::bool_type;
+ } else {
+ ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type,
+ "and_tmp",
+ ir_var_temporary);
+ instructions->push_tail(tmp);
+
+ ir_if *const stmt = new(ctx) ir_if(op[0]);
+ instructions->push_tail(stmt);
+
+ op[1] = this->subexpressions[1]->hir(&stmt->then_instructions, state);
+
+ if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
+ YYLTYPE loc = this->subexpressions[1]->get_location();
+
+ _mesa_glsl_error(& loc, state,
+ "RHS of `%s' must be scalar boolean",
+ operator_string(this->oper));
+ error_emitted = true;
+ }
+
+ ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp);
+ ir_assignment *const then_assign =
+ new(ctx) ir_assignment(then_deref, op[1], NULL);
+ stmt->then_instructions.push_tail(then_assign);
+
+ ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp);
+ ir_assignment *const else_assign =
+ new(ctx) ir_assignment(else_deref, new(ctx) ir_constant(false), NULL);
+ stmt->else_instructions.push_tail(else_assign);
+
+ result = new(ctx) ir_dereference_variable(tmp);
+ type = tmp->type;
+ }
+ break;
+ }
+
+ case ast_logic_or: {
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+
+ if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) {
+ YYLTYPE loc = this->subexpressions[0]->get_location();
+
+ _mesa_glsl_error(& loc, state, "LHS of `%s' must be scalar boolean",
+ operator_string(this->oper));
+ error_emitted = true;
+ }
+
+ ir_constant *op0_const = op[0]->constant_expression_value();
+ if (op0_const) {
+ if (op0_const->value.b[0]) {
+ result = op0_const;
+ } else {
+ op[1] = this->subexpressions[1]->hir(instructions, state);
+
+ if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
+ YYLTYPE loc = this->subexpressions[1]->get_location();
+
+ _mesa_glsl_error(& loc, state,
+ "RHS of `%s' must be scalar boolean",
+ operator_string(this->oper));
+ error_emitted = true;
+ }
+ result = op[1];
+ }
+ type = glsl_type::bool_type;
+ } else {
+ ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type,
+ "or_tmp",
+ ir_var_temporary);
+ instructions->push_tail(tmp);
+
+ ir_if *const stmt = new(ctx) ir_if(op[0]);
+ instructions->push_tail(stmt);
+
+ op[1] = this->subexpressions[1]->hir(&stmt->else_instructions, state);
+
+ if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) {
+ YYLTYPE loc = this->subexpressions[1]->get_location();
+
+ _mesa_glsl_error(& loc, state, "RHS of `%s' must be scalar boolean",
+ operator_string(this->oper));
+ error_emitted = true;
+ }
+
+ ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp);
+ ir_assignment *const then_assign =
+ new(ctx) ir_assignment(then_deref, new(ctx) ir_constant(true), NULL);
+ stmt->then_instructions.push_tail(then_assign);
+
+ ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp);
+ ir_assignment *const else_assign =
+ new(ctx) ir_assignment(else_deref, op[1], NULL);
+ stmt->else_instructions.push_tail(else_assign);
+
+ result = new(ctx) ir_dereference_variable(tmp);
+ type = tmp->type;
+ }
+ break;
+ }
+
+ case ast_logic_xor:
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
+
+
+ result = new(ctx) ir_expression(operations[this->oper], glsl_type::bool_type,
+ op[0], op[1]);
+ type = glsl_type::bool_type;
+ break;
+
+ case ast_logic_not:
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+
+ if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) {
+ YYLTYPE loc = this->subexpressions[0]->get_location();
+
+ _mesa_glsl_error(& loc, state,
+ "operand of `!' must be scalar boolean");
+ error_emitted = true;
+ }
+
+ result = new(ctx) ir_expression(operations[this->oper], glsl_type::bool_type,
+ op[0], NULL);
+ type = glsl_type::bool_type;
+ break;
+
+ case ast_mul_assign:
+ case ast_div_assign:
+ case ast_add_assign:
+ case ast_sub_assign: {
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
+
+ type = arithmetic_result_type(op[0], op[1],
+ (this->oper == ast_mul_assign),
+ state, & loc);
+
+ ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper], type,
+ op[0], op[1]);
+
+ result = do_assignment(instructions, state,
+ op[0]->clone(ctx, NULL), temp_rhs, false,
+ this->subexpressions[0]->get_location());
+ type = result->type;
+ error_emitted = (op[0]->type->is_error());
+
+ /* GLSL 1.10 does not allow array assignment. However, we don't have to
+ * explicitly test for this because none of the binary expression
+ * operators allow array operands either.
+ */
+
+ break;
+ }
+
+ case ast_mod_assign: {
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
+
+ type = modulus_result_type(op[0]->type, op[1]->type, state, & loc);
+
+ assert(operations[this->oper] == ir_binop_mod);
+
+ ir_rvalue *temp_rhs;
+ temp_rhs = new(ctx) ir_expression(operations[this->oper], type,
+ op[0], op[1]);
+
+ result = do_assignment(instructions, state,
+ op[0]->clone(ctx, NULL), temp_rhs, false,
+ this->subexpressions[0]->get_location());
+ type = result->type;
+ error_emitted = type->is_error();
+ break;
+ }
+
+ case ast_ls_assign:
+ case ast_rs_assign: {
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
+ type = shift_result_type(op[0]->type, op[1]->type, this->oper, state,
+ &loc);
+ ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
+ type, op[0], op[1]);
+ result = do_assignment(instructions, state, op[0]->clone(ctx, NULL),
+ temp_rhs, false,
+ this->subexpressions[0]->get_location());
+ error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
+ break;
+ }
+
+ case ast_and_assign:
+ case ast_xor_assign:
+ case ast_or_assign: {
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ op[1] = this->subexpressions[1]->hir(instructions, state);
+ type = bit_logic_result_type(op[0]->type, op[1]->type, this->oper,
+ state, &loc);
+ ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
+ type, op[0], op[1]);
+ result = do_assignment(instructions, state, op[0]->clone(ctx, NULL),
+ temp_rhs, false,
+ this->subexpressions[0]->get_location());
+ error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
+ break;
+ }
+
+ case ast_conditional: {
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+
+ /* From page 59 (page 65 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "The ternary selection operator (?:). It operates on three
+ * expressions (exp1 ? exp2 : exp3). This operator evaluates the
+ * first expression, which must result in a scalar Boolean."
+ */
+ if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) {
+ YYLTYPE loc = this->subexpressions[0]->get_location();
+
+ _mesa_glsl_error(& loc, state, "?: condition must be scalar boolean");
+ error_emitted = true;
+ }
+
+ /* The :? operator is implemented by generating an anonymous temporary
+ * followed by an if-statement. The last instruction in each branch of
+ * the if-statement assigns a value to the anonymous temporary. This
+ * temporary is the r-value of the expression.
+ */
+ exec_list then_instructions;
+ exec_list else_instructions;
+
+ op[1] = this->subexpressions[1]->hir(&then_instructions, state);
+ op[2] = this->subexpressions[2]->hir(&else_instructions, state);
+
+ /* From page 59 (page 65 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "The second and third expressions can be any type, as
+ * long their types match, or there is a conversion in
+ * Section 4.1.10 "Implicit Conversions" that can be applied
+ * to one of the expressions to make their types match. This
+ * resulting matching type is the type of the entire
+ * expression."
+ */
+ if ((!apply_implicit_conversion(op[1]->type, op[2], state)
+ && !apply_implicit_conversion(op[2]->type, op[1], state))
+ || (op[1]->type != op[2]->type)) {
+ YYLTYPE loc = this->subexpressions[1]->get_location();
+
+ _mesa_glsl_error(& loc, state, "Second and third operands of ?: "
+ "operator must have matching types.");
+ error_emitted = true;
+ type = glsl_type::error_type;
+ } else {
+ type = op[1]->type;
+ }
+
+ /* From page 33 (page 39 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "The second and third expressions must be the same type, but can
+ * be of any type other than an array."
+ */
+ if ((state->language_version <= 110) && type->is_array()) {
+ _mesa_glsl_error(& loc, state, "Second and third operands of ?: "
+ "operator must not be arrays.");
+ error_emitted = true;
+ }
+
+ ir_constant *cond_val = op[0]->constant_expression_value();
+ ir_constant *then_val = op[1]->constant_expression_value();
+ ir_constant *else_val = op[2]->constant_expression_value();
+
+ if (then_instructions.is_empty()
+ && else_instructions.is_empty()
+ && (cond_val != NULL) && (then_val != NULL) && (else_val != NULL)) {
+ result = (cond_val->value.b[0]) ? then_val : else_val;
+ } else {
+ ir_variable *const tmp =
+ new(ctx) ir_variable(type, "conditional_tmp", ir_var_temporary);
+ instructions->push_tail(tmp);
+
+ ir_if *const stmt = new(ctx) ir_if(op[0]);
+ instructions->push_tail(stmt);
+
+ then_instructions.move_nodes_to(& stmt->then_instructions);
+ ir_dereference *const then_deref =
+ new(ctx) ir_dereference_variable(tmp);
+ ir_assignment *const then_assign =
+ new(ctx) ir_assignment(then_deref, op[1], NULL);
+ stmt->then_instructions.push_tail(then_assign);
+
+ else_instructions.move_nodes_to(& stmt->else_instructions);
+ ir_dereference *const else_deref =
+ new(ctx) ir_dereference_variable(tmp);
+ ir_assignment *const else_assign =
+ new(ctx) ir_assignment(else_deref, op[2], NULL);
+ stmt->else_instructions.push_tail(else_assign);
+
+ result = new(ctx) ir_dereference_variable(tmp);
+ }
+ break;
+ }
+
+ case ast_pre_inc:
+ case ast_pre_dec: {
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ if (op[0]->type->base_type == GLSL_TYPE_FLOAT)
+ op[1] = new(ctx) ir_constant(1.0f);
+ else
+ op[1] = new(ctx) ir_constant(1);
+
+ type = arithmetic_result_type(op[0], op[1], false, state, & loc);
+
+ ir_rvalue *temp_rhs;
+ temp_rhs = new(ctx) ir_expression(operations[this->oper], type,
+ op[0], op[1]);
+
+ result = do_assignment(instructions, state,
+ op[0]->clone(ctx, NULL), temp_rhs, false,
+ this->subexpressions[0]->get_location());
+ type = result->type;
+ error_emitted = op[0]->type->is_error();
+ break;
+ }
+
+ case ast_post_inc:
+ case ast_post_dec: {
+ op[0] = this->subexpressions[0]->hir(instructions, state);
+ if (op[0]->type->base_type == GLSL_TYPE_FLOAT)
+ op[1] = new(ctx) ir_constant(1.0f);
+ else
+ op[1] = new(ctx) ir_constant(1);
+
+ error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
+
+ type = arithmetic_result_type(op[0], op[1], false, state, & loc);
+
+ ir_rvalue *temp_rhs;
+ temp_rhs = new(ctx) ir_expression(operations[this->oper], type,
+ op[0], op[1]);
+
+ /* Get a temporary of a copy of the lvalue before it's modified.
+ * This may get thrown away later.
+ */
+ result = get_lvalue_copy(instructions, op[0]->clone(ctx, NULL));
+
+ (void)do_assignment(instructions, state,
+ op[0]->clone(ctx, NULL), temp_rhs, false,
+ this->subexpressions[0]->get_location());
+
+ type = result->type;
+ error_emitted = op[0]->type->is_error();
+ break;
+ }
+
+ case ast_field_selection:
+ result = _mesa_ast_field_selection_to_hir(this, instructions, state);
+ type = result->type;
+ break;
+
+ case ast_array_index: {
+ YYLTYPE index_loc = subexpressions[1]->get_location();
+
+ op[0] = subexpressions[0]->hir(instructions, state);
+ op[1] = subexpressions[1]->hir(instructions, state);
+
+ error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
+
+ ir_rvalue *const array = op[0];
+
+ result = new(ctx) ir_dereference_array(op[0], op[1]);
+
+ /* Do not use op[0] after this point. Use array.
+ */
+ op[0] = NULL;
+
+
+ if (error_emitted)
+ break;
+
+ if (!array->type->is_array()
+ && !array->type->is_matrix()
+ && !array->type->is_vector()) {
+ _mesa_glsl_error(& index_loc, state,
+ "cannot dereference non-array / non-matrix / "
+ "non-vector");
+ error_emitted = true;
+ }
+
+ if (!op[1]->type->is_integer()) {
+ _mesa_glsl_error(& index_loc, state,
+ "array index must be integer type");
+ error_emitted = true;
+ } else if (!op[1]->type->is_scalar()) {
+ _mesa_glsl_error(& index_loc, state,
+ "array index must be scalar");
+ error_emitted = true;
+ }
+
+ /* If the array index is a constant expression and the array has a
+ * declared size, ensure that the access is in-bounds. If the array
+ * index is not a constant expression, ensure that the array has a
+ * declared size.
+ */
+ ir_constant *const const_index = op[1]->constant_expression_value();
+ if (const_index != NULL) {
+ const int idx = const_index->value.i[0];
+ const char *type_name;
+ unsigned bound = 0;
+
+ if (array->type->is_matrix()) {
+ type_name = "matrix";
+ } else if (array->type->is_vector()) {
+ type_name = "vector";
+ } else {
+ type_name = "array";
+ }
+
+ /* From page 24 (page 30 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "It is illegal to declare an array with a size, and then
+ * later (in the same shader) index the same array with an
+ * integral constant expression greater than or equal to the
+ * declared size. It is also illegal to index an array with a
+ * negative constant expression."
+ */
+ if (array->type->is_matrix()) {
+ if (array->type->row_type()->vector_elements <= idx) {
+ bound = array->type->row_type()->vector_elements;
+ }
+ } else if (array->type->is_vector()) {
+ if (array->type->vector_elements <= idx) {
+ bound = array->type->vector_elements;
+ }
+ } else {
+ if ((array->type->array_size() > 0)
+ && (array->type->array_size() <= idx)) {
+ bound = array->type->array_size();
+ }
+ }
+
+ if (bound > 0) {
+ _mesa_glsl_error(& loc, state, "%s index must be < %u",
+ type_name, bound);
+ error_emitted = true;
+ } else if (idx < 0) {
+ _mesa_glsl_error(& loc, state, "%s index must be >= 0",
+ type_name);
+ error_emitted = true;
+ }
+
+ if (array->type->is_array()) {
+ /* If the array is a variable dereference, it dereferences the
+ * whole array, by definition. Use this to get the variable.
+ *
+ * FINISHME: Should some methods for getting / setting / testing
+ * FINISHME: array access limits be added to ir_dereference?
+ */
+ ir_variable *const v = array->whole_variable_referenced();
+ if ((v != NULL) && (unsigned(idx) > v->max_array_access))
+ v->max_array_access = idx;
+ }
+ } else if (array->type->array_size() == 0) {
+ _mesa_glsl_error(&loc, state, "unsized array index must be constant");
+ } else {
+ if (array->type->is_array()) {
+ /* whole_variable_referenced can return NULL if the array is a
+ * member of a structure. In this case it is safe to not update
+ * the max_array_access field because it is never used for fields
+ * of structures.
+ */
+ ir_variable *v = array->whole_variable_referenced();
+ if (v != NULL)
+ v->max_array_access = array->type->array_size();
+ }
+ }
+
+ /* From page 23 (29 of the PDF) of the GLSL 1.30 spec:
+ *
+ * "Samplers aggregated into arrays within a shader (using square
+ * brackets [ ]) can only be indexed with integral constant
+ * expressions [...]."
+ *
+ * This restriction was added in GLSL 1.30. Shaders using earlier version
+ * of the language should not be rejected by the compiler front-end for
+ * using this construct. This allows useful things such as using a loop
+ * counter as the index to an array of samplers. If the loop in unrolled,
+ * the code should compile correctly. Instead, emit a warning.
+ */
+ if (array->type->is_array() &&
+ array->type->element_type()->is_sampler() &&
+ const_index == NULL) {
+
+ if (state->language_version == 100) {
+ _mesa_glsl_warning(&loc, state,
+ "sampler arrays indexed with non-constant "
+ "expressions is optional in GLSL ES 1.00");
+ } else if (state->language_version < 130) {
+ _mesa_glsl_warning(&loc, state,
+ "sampler arrays indexed with non-constant "
+ "expressions is forbidden in GLSL 1.30 and "
+ "later");
+ } else {
+ _mesa_glsl_error(&loc, state,
+ "sampler arrays indexed with non-constant "
+ "expressions is forbidden in GLSL 1.30 and "
+ "later");
+ error_emitted = true;
+ }
+ }
+
+ if (error_emitted)
+ result->type = glsl_type::error_type;
+
+ type = result->type;
+ break;
+ }
+
+ case ast_function_call:
+ /* Should *NEVER* get here. ast_function_call should always be handled
+ * by ast_function_expression::hir.
+ */
+ assert(0);
+ break;
+
+ case ast_identifier: {
+ /* ast_identifier can appear several places in a full abstract syntax
+ * tree. This particular use must be at location specified in the grammar
+ * as 'variable_identifier'.
+ */
+ ir_variable *var =
+ state->symbols->get_variable(this->primary_expression.identifier);
+
+ result = new(ctx) ir_dereference_variable(var);
+
+ if (var != NULL) {
+ var->used = true;
+ type = result->type;
+ } else {
+ _mesa_glsl_error(& loc, state, "`%s' undeclared",
+ this->primary_expression.identifier);
+
+ error_emitted = true;
+ }
+ break;
+ }
+
+ case ast_int_constant:
+ type = glsl_type::int_type;
+ result = new(ctx) ir_constant(this->primary_expression.int_constant);
+ break;
+
+ case ast_uint_constant:
+ type = glsl_type::uint_type;
+ result = new(ctx) ir_constant(this->primary_expression.uint_constant);
+ break;
+
+ case ast_float_constant:
+ type = glsl_type::float_type;
+ result = new(ctx) ir_constant(this->primary_expression.float_constant);
+ break;
+
+ case ast_bool_constant:
+ type = glsl_type::bool_type;
+ result = new(ctx) ir_constant(bool(this->primary_expression.bool_constant));
+ break;
+
+ case ast_sequence: {
+ /* It should not be possible to generate a sequence in the AST without
+ * any expressions in it.
+ */
+ assert(!this->expressions.is_empty());
+
+ /* The r-value of a sequence is the last expression in the sequence. If
+ * the other expressions in the sequence do not have side-effects (and
+ * therefore add instructions to the instruction list), they get dropped
+ * on the floor.
+ */
+ foreach_list_typed (ast_node, ast, link, &this->expressions)
+ result = ast->hir(instructions, state);
+
+ type = result->type;
+
+ /* Any errors should have already been emitted in the loop above.
+ */
+ error_emitted = true;
+ break;
+ }
+ }
+
+ if (type->is_error() && !error_emitted)
+ _mesa_glsl_error(& loc, state, "type mismatch");
+
+ return result;
+}
+
+
+ir_rvalue *
+ast_expression_statement::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ /* It is possible to have expression statements that don't have an
+ * expression. This is the solitary semicolon:
+ *
+ * for (i = 0; i < 5; i++)
+ * ;
+ *
+ * In this case the expression will be NULL. Test for NULL and don't do
+ * anything in that case.
+ */
+ if (expression != NULL)
+ expression->hir(instructions, state);
+
+ /* Statements do not have r-values.
+ */
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_compound_statement::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ if (new_scope)
+ state->symbols->push_scope();
+
+ foreach_list_typed (ast_node, ast, link, &this->statements)
+ ast->hir(instructions, state);
+
+ if (new_scope)
+ state->symbols->pop_scope();
+
+ /* Compound statements do not have r-values.
+ */
+ return NULL;
+}
+
+
+static const glsl_type *
+process_array_type(YYLTYPE *loc, const glsl_type *base, ast_node *array_size,
+ struct _mesa_glsl_parse_state *state)
+{
+ unsigned length = 0;
+
+ /* FINISHME: Reject delcarations of multidimensional arrays. */
+
+ if (array_size != NULL) {
+ exec_list dummy_instructions;
+ ir_rvalue *const ir = array_size->hir(& dummy_instructions, state);
+ YYLTYPE loc = array_size->get_location();
+
+ /* FINISHME: Verify that the grammar forbids side-effects in array
+ * FINISHME: sizes. i.e., 'vec4 [x = 12] data'
+ */
+ assert(dummy_instructions.is_empty());
+
+ if (ir != NULL) {
+ if (!ir->type->is_integer()) {
+ _mesa_glsl_error(& loc, state, "array size must be integer type");
+ } else if (!ir->type->is_scalar()) {
+ _mesa_glsl_error(& loc, state, "array size must be scalar type");
+ } else {
+ ir_constant *const size = ir->constant_expression_value();
+
+ if (size == NULL) {
+ _mesa_glsl_error(& loc, state, "array size must be a "
+ "constant valued expression");
+ } else if (size->value.i[0] <= 0) {
+ _mesa_glsl_error(& loc, state, "array size must be > 0");
+ } else {
+ assert(size->type == ir->type);
+ length = size->value.u[0];
+ }
+ }
+ }
+ } else if (state->es_shader) {
+ /* Section 10.17 of the GLSL ES 1.00 specification states that unsized
+ * array declarations have been removed from the language.
+ */
+ _mesa_glsl_error(loc, state, "unsized array declarations are not "
+ "allowed in GLSL ES 1.00.");
+ }
+
+ return glsl_type::get_array_instance(base, length);
+}
+
+
+const glsl_type *
+ast_type_specifier::glsl_type(const char **name,
+ struct _mesa_glsl_parse_state *state) const
+{
+ const struct glsl_type *type;
+
+ type = state->symbols->get_type(this->type_name);
+ *name = this->type_name;
+
+ if (this->is_array) {
+ YYLTYPE loc = this->get_location();
+ type = process_array_type(&loc, type, this->array_size, state);
+ }
+
+ return type;
+}
+
+
+static void
+apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
+ ir_variable *var,
+ struct _mesa_glsl_parse_state *state,
+ YYLTYPE *loc)
+{
+ if (qual->flags.q.invariant) {
+ if (var->used) {
+ _mesa_glsl_error(loc, state,
+ "variable `%s' may not be redeclared "
+ "`invariant' after being used",
+ var->name);
+ } else {
+ var->invariant = 1;
+ }
+ }
+
+ if (qual->flags.q.constant || qual->flags.q.attribute
+ || qual->flags.q.uniform
+ || (qual->flags.q.varying && (state->target == fragment_shader)))
+ var->read_only = 1;
+
+ if (qual->flags.q.centroid)
+ var->centroid = 1;
+
+ if (qual->flags.q.attribute && state->target != vertex_shader) {
+ var->type = glsl_type::error_type;
+ _mesa_glsl_error(loc, state,
+ "`attribute' variables may not be declared in the "
+ "%s shader",
+ _mesa_glsl_shader_target_name(state->target));
+ }
+
+ /* From page 25 (page 31 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "The varying qualifier can be used only with the data types
+ * float, vec2, vec3, vec4, mat2, mat3, and mat4, or arrays of
+ * these."
+ */
+ if (qual->flags.q.varying) {
+ const glsl_type *non_array_type;
+
+ if (var->type && var->type->is_array())
+ non_array_type = var->type->fields.array;
+ else
+ non_array_type = var->type;
+
+ if (non_array_type && non_array_type->base_type != GLSL_TYPE_FLOAT) {
+ var->type = glsl_type::error_type;
+ _mesa_glsl_error(loc, state,
+ "varying variables must be of base type float");
+ }
+ }
+
+ /* If there is no qualifier that changes the mode of the variable, leave
+ * the setting alone.
+ */
+ if (qual->flags.q.in && qual->flags.q.out)
+ var->mode = ir_var_inout;
+ else if (qual->flags.q.attribute || qual->flags.q.in
+ || (qual->flags.q.varying && (state->target == fragment_shader)))
+ var->mode = ir_var_in;
+ else if (qual->flags.q.out
+ || (qual->flags.q.varying && (state->target == vertex_shader)))
+ var->mode = ir_var_out;
+ else if (qual->flags.q.uniform)
+ var->mode = ir_var_uniform;
+
+ if (state->all_invariant && (state->current_function == NULL)) {
+ switch (state->target) {
+ case vertex_shader:
+ if (var->mode == ir_var_out)
+ var->invariant = true;
+ break;
+ case geometry_shader:
+ if ((var->mode == ir_var_in) || (var->mode == ir_var_out))
+ var->invariant = true;
+ break;
+ case fragment_shader:
+ if (var->mode == ir_var_in)
+ var->invariant = true;
+ break;
+ }
+ }
+
+ if (qual->flags.q.flat)
+ var->interpolation = ir_var_flat;
+ else if (qual->flags.q.noperspective)
+ var->interpolation = ir_var_noperspective;
+ else
+ var->interpolation = ir_var_smooth;
+
+ var->pixel_center_integer = qual->flags.q.pixel_center_integer;
+ var->origin_upper_left = qual->flags.q.origin_upper_left;
+ if ((qual->flags.q.origin_upper_left || qual->flags.q.pixel_center_integer)
+ && (strcmp(var->name, "gl_FragCoord") != 0)) {
+ const char *const qual_string = (qual->flags.q.origin_upper_left)
+ ? "origin_upper_left" : "pixel_center_integer";
+
+ _mesa_glsl_error(loc, state,
+ "layout qualifier `%s' can only be applied to "
+ "fragment shader input `gl_FragCoord'",
+ qual_string);
+ }
+
+ if (qual->flags.q.explicit_location) {
+ const bool global_scope = (state->current_function == NULL);
+ bool fail = false;
+ const char *string = "";
+
+ /* In the vertex shader only shader inputs can be given explicit
+ * locations.
+ *
+ * In the fragment shader only shader outputs can be given explicit
+ * locations.
+ */
+ switch (state->target) {
+ case vertex_shader:
+ if (!global_scope || (var->mode != ir_var_in)) {
+ fail = true;
+ string = "input";
+ }
+ break;
+
+ case geometry_shader:
+ _mesa_glsl_error(loc, state,
+ "geometry shader variables cannot be given "
+ "explicit locations\n");
+ break;
+
+ case fragment_shader:
+ if (!global_scope || (var->mode != ir_var_in)) {
+ fail = true;
+ string = "output";
+ }
+ break;
+ };
+
+ if (fail) {
+ _mesa_glsl_error(loc, state,
+ "only %s shader %s variables can be given an "
+ "explicit location\n",
+ _mesa_glsl_shader_target_name(state->target),
+ string);
+ } else {
+ var->explicit_location = true;
+
+ /* This bit of silliness is needed because invalid explicit locations
+ * are supposed to be flagged during linking. Small negative values
+ * biased by VERT_ATTRIB_GENERIC0 or FRAG_RESULT_DATA0 could alias
+ * built-in values (e.g., -16+VERT_ATTRIB_GENERIC0 = VERT_ATTRIB_POS).
+ * The linker needs to be able to differentiate these cases. This
+ * ensures that negative values stay negative.
+ */
+ if (qual->location >= 0) {
+ var->location = (state->target == vertex_shader)
+ ? (qual->location + VERT_ATTRIB_GENERIC0)
+ : (qual->location + FRAG_RESULT_DATA0);
+ } else {
+ var->location = qual->location;
+ }
+ }
+ }
+
+ /* Does the declaration use the 'layout' keyword?
+ */
+ const bool uses_layout = qual->flags.q.pixel_center_integer
+ || qual->flags.q.origin_upper_left
+ || qual->flags.q.explicit_location;
+
+ /* Does the declaration use the deprecated 'attribute' or 'varying'
+ * keywords?
+ */
+ const bool uses_deprecated_qualifier = qual->flags.q.attribute
+ || qual->flags.q.varying;
+
+ /* Is the 'layout' keyword used with parameters that allow relaxed checking.
+ * Many implementations of GL_ARB_fragment_coord_conventions_enable and some
+ * implementations (only Mesa?) GL_ARB_explicit_attrib_location_enable
+ * allowed the layout qualifier to be used with 'varying' and 'attribute'.
+ * These extensions and all following extensions that add the 'layout'
+ * keyword have been modified to require the use of 'in' or 'out'.
+ *
+ * The following extension do not allow the deprecated keywords:
+ *
+ * GL_AMD_conservative_depth
+ * GL_ARB_gpu_shader5
+ * GL_ARB_separate_shader_objects
+ * GL_ARB_tesselation_shader
+ * GL_ARB_transform_feedback3
+ * GL_ARB_uniform_buffer_object
+ *
+ * It is unknown whether GL_EXT_shader_image_load_store or GL_NV_gpu_shader5
+ * allow layout with the deprecated keywords.
+ */
+ const bool relaxed_layout_qualifier_checking =
+ state->ARB_fragment_coord_conventions_enable;
+
+ if (uses_layout && uses_deprecated_qualifier) {
+ if (relaxed_layout_qualifier_checking) {
+ _mesa_glsl_warning(loc, state,
+ "`layout' qualifier may not be used with "
+ "`attribute' or `varying'");
+ } else {
+ _mesa_glsl_error(loc, state,
+ "`layout' qualifier may not be used with "
+ "`attribute' or `varying'");
+ }
+ }
+
+ /* Layout qualifiers for gl_FragDepth, which are enabled by extension
+ * AMD_conservative_depth.
+ */
+ int depth_layout_count = qual->flags.q.depth_any
+ + qual->flags.q.depth_greater
+ + qual->flags.q.depth_less
+ + qual->flags.q.depth_unchanged;
+ if (depth_layout_count > 0
+ && !state->AMD_conservative_depth_enable) {
+ _mesa_glsl_error(loc, state,
+ "extension GL_AMD_conservative_depth must be enabled "
+ "to use depth layout qualifiers");
+ } else if (depth_layout_count > 0
+ && strcmp(var->name, "gl_FragDepth") != 0) {
+ _mesa_glsl_error(loc, state,
+ "depth layout qualifiers can be applied only to "
+ "gl_FragDepth");
+ } else if (depth_layout_count > 1
+ && strcmp(var->name, "gl_FragDepth") == 0) {
+ _mesa_glsl_error(loc, state,
+ "at most one depth layout qualifier can be applied to "
+ "gl_FragDepth");
+ }
+ if (qual->flags.q.depth_any)
+ var->depth_layout = ir_depth_layout_any;
+ else if (qual->flags.q.depth_greater)
+ var->depth_layout = ir_depth_layout_greater;
+ else if (qual->flags.q.depth_less)
+ var->depth_layout = ir_depth_layout_less;
+ else if (qual->flags.q.depth_unchanged)
+ var->depth_layout = ir_depth_layout_unchanged;
+ else
+ var->depth_layout = ir_depth_layout_none;
+
+ if (var->type->is_array() && state->language_version != 110) {
+ var->array_lvalue = true;
+ }
+}
+
+/**
+ * Get the variable that is being redeclared by this declaration
+ *
+ * Semantic checks to verify the validity of the redeclaration are also
+ * performed. If semantic checks fail, compilation error will be emitted via
+ * \c _mesa_glsl_error, but a non-\c NULL pointer will still be returned.
+ *
+ * \returns
+ * A pointer to an existing variable in the current scope if the declaration
+ * is a redeclaration, \c NULL otherwise.
+ */
+ir_variable *
+get_variable_being_redeclared(ir_variable *var, ast_declaration *decl,
+ struct _mesa_glsl_parse_state *state)
+{
+ /* Check if this declaration is actually a re-declaration, either to
+ * resize an array or add qualifiers to an existing variable.
+ *
+ * This is allowed for variables in the current scope, or when at
+ * global scope (for built-ins in the implicit outer scope).
+ */
+ ir_variable *earlier = state->symbols->get_variable(decl->identifier);
+ if (earlier == NULL ||
+ (state->current_function != NULL &&
+ !state->symbols->name_declared_this_scope(decl->identifier))) {
+ return NULL;
+ }
+
+
+ YYLTYPE loc = decl->get_location();
+
+ /* From page 24 (page 30 of the PDF) of the GLSL 1.50 spec,
+ *
+ * "It is legal to declare an array without a size and then
+ * later re-declare the same name as an array of the same
+ * type and specify a size."
+ */
+ if ((earlier->type->array_size() == 0)
+ && var->type->is_array()
+ && (var->type->element_type() == earlier->type->element_type())) {
+ /* FINISHME: This doesn't match the qualifiers on the two
+ * FINISHME: declarations. It's not 100% clear whether this is
+ * FINISHME: required or not.
+ */
+
+ /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "The size [of gl_TexCoord] can be at most
+ * gl_MaxTextureCoords."
+ */
+ const unsigned size = unsigned(var->type->array_size());
+ if ((strcmp("gl_TexCoord", var->name) == 0)
+ && (size > state->Const.MaxTextureCoords)) {
+ _mesa_glsl_error(& loc, state, "`gl_TexCoord' array size cannot "
+ "be larger than gl_MaxTextureCoords (%u)\n",
+ state->Const.MaxTextureCoords);
+ } else if ((size > 0) && (size <= earlier->max_array_access)) {
+ _mesa_glsl_error(& loc, state, "array size must be > %u due to "
+ "previous access",
+ earlier->max_array_access);
+ }
+
+ earlier->type = var->type;
+ delete var;
+ var = NULL;
+ } else if (state->ARB_fragment_coord_conventions_enable
+ && strcmp(var->name, "gl_FragCoord") == 0
+ && earlier->type == var->type
+ && earlier->mode == var->mode) {
+ /* Allow redeclaration of gl_FragCoord for ARB_fcc layout
+ * qualifiers.
+ */
+ earlier->origin_upper_left = var->origin_upper_left;
+ earlier->pixel_center_integer = var->pixel_center_integer;
+
+ /* According to section 4.3.7 of the GLSL 1.30 spec,
+ * the following built-in varaibles can be redeclared with an
+ * interpolation qualifier:
+ * * gl_FrontColor
+ * * gl_BackColor
+ * * gl_FrontSecondaryColor
+ * * gl_BackSecondaryColor
+ * * gl_Color
+ * * gl_SecondaryColor
+ */
+ } else if (state->language_version >= 130
+ && (strcmp(var->name, "gl_FrontColor") == 0
+ || strcmp(var->name, "gl_BackColor") == 0
+ || strcmp(var->name, "gl_FrontSecondaryColor") == 0
+ || strcmp(var->name, "gl_BackSecondaryColor") == 0
+ || strcmp(var->name, "gl_Color") == 0
+ || strcmp(var->name, "gl_SecondaryColor") == 0)
+ && earlier->type == var->type
+ && earlier->mode == var->mode) {
+ earlier->interpolation = var->interpolation;
+
+ /* Layout qualifiers for gl_FragDepth. */
+ } else if (state->AMD_conservative_depth_enable
+ && strcmp(var->name, "gl_FragDepth") == 0
+ && earlier->type == var->type
+ && earlier->mode == var->mode) {
+
+ /** From the AMD_conservative_depth spec:
+ * Within any shader, the first redeclarations of gl_FragDepth
+ * must appear before any use of gl_FragDepth.
+ */
+ if (earlier->used) {
+ _mesa_glsl_error(&loc, state,
+ "the first redeclaration of gl_FragDepth "
+ "must appear before any use of gl_FragDepth");
+ }
+
+ /* Prevent inconsistent redeclaration of depth layout qualifier. */
+ if (earlier->depth_layout != ir_depth_layout_none
+ && earlier->depth_layout != var->depth_layout) {
+ _mesa_glsl_error(&loc, state,
+ "gl_FragDepth: depth layout is declared here "
+ "as '%s, but it was previously declared as "
+ "'%s'",
+ depth_layout_string(var->depth_layout),
+ depth_layout_string(earlier->depth_layout));
+ }
+
+ earlier->depth_layout = var->depth_layout;
+
+ } else {
+ _mesa_glsl_error(&loc, state, "`%s' redeclared", decl->identifier);
+ }
+
+ return earlier;
+}
+
+/**
+ * Generate the IR for an initializer in a variable declaration
+ */
+ir_rvalue *
+process_initializer(ir_variable *var, ast_declaration *decl,
+ ast_fully_specified_type *type,
+ exec_list *initializer_instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ ir_rvalue *result = NULL;
+
+ YYLTYPE initializer_loc = decl->initializer->get_location();
+
+ /* From page 24 (page 30 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "All uniform variables are read-only and are initialized either
+ * directly by an application via API commands, or indirectly by
+ * OpenGL."
+ */
+ if ((state->language_version <= 110)
+ && (var->mode == ir_var_uniform)) {
+ _mesa_glsl_error(& initializer_loc, state,
+ "cannot initialize uniforms in GLSL 1.10");
+ }
+
+ if (var->type->is_sampler()) {
+ _mesa_glsl_error(& initializer_loc, state,
+ "cannot initialize samplers");
+ }
+
+ if ((var->mode == ir_var_in) && (state->current_function == NULL)) {
+ _mesa_glsl_error(& initializer_loc, state,
+ "cannot initialize %s shader input / %s",
+ _mesa_glsl_shader_target_name(state->target),
+ (state->target == vertex_shader)
+ ? "attribute" : "varying");
+ }
+
+ ir_dereference *const lhs = new(state) ir_dereference_variable(var);
+ ir_rvalue *rhs = decl->initializer->hir(initializer_instructions,
+ state);
+
+ /* Calculate the constant value if this is a const or uniform
+ * declaration.
+ */
+ if (type->qualifier.flags.q.constant
+ || type->qualifier.flags.q.uniform) {
+ ir_rvalue *new_rhs = validate_assignment(state, var->type, rhs, true);
+ if (new_rhs != NULL) {
+ rhs = new_rhs;
+
+ ir_constant *constant_value = rhs->constant_expression_value();
+ if (!constant_value) {
+ _mesa_glsl_error(& initializer_loc, state,
+ "initializer of %s variable `%s' must be a "
+ "constant expression",
+ (type->qualifier.flags.q.constant)
+ ? "const" : "uniform",
+ decl->identifier);
+ if (var->type->is_numeric()) {
+ /* Reduce cascading errors. */
+ var->constant_value = ir_constant::zero(state, var->type);
+ }
+ } else {
+ rhs = constant_value;
+ var->constant_value = constant_value;
+ }
+ } else {
+ _mesa_glsl_error(&initializer_loc, state,
+ "initializer of type %s cannot be assigned to "
+ "variable of type %s",
+ rhs->type->name, var->type->name);
+ if (var->type->is_numeric()) {
+ /* Reduce cascading errors. */
+ var->constant_value = ir_constant::zero(state, var->type);
+ }
+ }
+ }
+
+ if (rhs && !rhs->type->is_error()) {
+ bool temp = var->read_only;
+ if (type->qualifier.flags.q.constant)
+ var->read_only = false;
+
+ /* Never emit code to initialize a uniform.
+ */
+ const glsl_type *initializer_type;
+ if (!type->qualifier.flags.q.uniform) {
+ result = do_assignment(initializer_instructions, state,
+ lhs, rhs, true,
+ type->get_location());
+ initializer_type = result->type;
+ } else
+ initializer_type = rhs->type;
+
+ /* If the declared variable is an unsized array, it must inherrit
+ * its full type from the initializer. A declaration such as
+ *
+ * uniform float a[] = float[](1.0, 2.0, 3.0, 3.0);
+ *
+ * becomes
+ *
+ * uniform float a[4] = float[](1.0, 2.0, 3.0, 3.0);
+ *
+ * The assignment generated in the if-statement (below) will also
+ * automatically handle this case for non-uniforms.
+ *
+ * If the declared variable is not an array, the types must
+ * already match exactly. As a result, the type assignment
+ * here can be done unconditionally. For non-uniforms the call
+ * to do_assignment can change the type of the initializer (via
+ * the implicit conversion rules). For uniforms the initializer
+ * must be a constant expression, and the type of that expression
+ * was validated above.
+ */
+ var->type = initializer_type;
+
+ var->read_only = temp;
+ }
+
+ return result;
+}
+
+ir_rvalue *
+ast_declarator_list::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+ const struct glsl_type *decl_type;
+ const char *type_name = NULL;
+ ir_rvalue *result = NULL;
+ YYLTYPE loc = this->get_location();
+
+ /* From page 46 (page 52 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "To ensure that a particular output variable is invariant, it is
+ * necessary to use the invariant qualifier. It can either be used to
+ * qualify a previously declared variable as being invariant
+ *
+ * invariant gl_Position; // make existing gl_Position be invariant"
+ *
+ * In these cases the parser will set the 'invariant' flag in the declarator
+ * list, and the type will be NULL.
+ */
+ if (this->invariant) {
+ assert(this->type == NULL);
+
+ if (state->current_function != NULL) {
+ _mesa_glsl_error(& loc, state,
+ "All uses of `invariant' keyword must be at global "
+ "scope\n");
+ }
+
+ foreach_list_typed (ast_declaration, decl, link, &this->declarations) {
+ assert(!decl->is_array);
+ assert(decl->array_size == NULL);
+ assert(decl->initializer == NULL);
+
+ ir_variable *const earlier =
+ state->symbols->get_variable(decl->identifier);
+ if (earlier == NULL) {
+ _mesa_glsl_error(& loc, state,
+ "Undeclared variable `%s' cannot be marked "
+ "invariant\n", decl->identifier);
+ } else if ((state->target == vertex_shader)
+ && (earlier->mode != ir_var_out)) {
+ _mesa_glsl_error(& loc, state,
+ "`%s' cannot be marked invariant, vertex shader "
+ "outputs only\n", decl->identifier);
+ } else if ((state->target == fragment_shader)
+ && (earlier->mode != ir_var_in)) {
+ _mesa_glsl_error(& loc, state,
+ "`%s' cannot be marked invariant, fragment shader "
+ "inputs only\n", decl->identifier);
+ } else if (earlier->used) {
+ _mesa_glsl_error(& loc, state,
+ "variable `%s' may not be redeclared "
+ "`invariant' after being used",
+ earlier->name);
+ } else {
+ earlier->invariant = true;
+ }
+ }
+
+ /* Invariant redeclarations do not have r-values.
+ */
+ return NULL;
+ }
+
+ assert(this->type != NULL);
+ assert(!this->invariant);
+
+ /* The type specifier may contain a structure definition. Process that
+ * before any of the variable declarations.
+ */
+ (void) this->type->specifier->hir(instructions, state);
+
+ decl_type = this->type->specifier->glsl_type(& type_name, state);
+ if (this->declarations.is_empty()) {
+ /* The only valid case where the declaration list can be empty is when
+ * the declaration is setting the default precision of a built-in type
+ * (e.g., 'precision highp vec4;').
+ */
+
+ if (decl_type != NULL) {
+ } else {
+ _mesa_glsl_error(& loc, state, "incomplete declaration");
+ }
+ }
+
+ foreach_list_typed (ast_declaration, decl, link, &this->declarations) {
+ const struct glsl_type *var_type;
+ ir_variable *var;
+
+ /* FINISHME: Emit a warning if a variable declaration shadows a
+ * FINISHME: declaration at a higher scope.
+ */
+
+ if ((decl_type == NULL) || decl_type->is_void()) {
+ if (type_name != NULL) {
+ _mesa_glsl_error(& loc, state,
+ "invalid type `%s' in declaration of `%s'",
+ type_name, decl->identifier);
+ } else {
+ _mesa_glsl_error(& loc, state,
+ "invalid type in declaration of `%s'",
+ decl->identifier);
+ }
+ continue;
+ }
+
+ if (decl->is_array) {
+ var_type = process_array_type(&loc, decl_type, decl->array_size,
+ state);
+ } else {
+ var_type = decl_type;
+ }
+
+ var = new(ctx) ir_variable(var_type, decl->identifier, ir_var_auto);
+
+ /* From page 22 (page 28 of the PDF) of the GLSL 1.10 specification;
+ *
+ * "Global variables can only use the qualifiers const,
+ * attribute, uni form, or varying. Only one may be
+ * specified.
+ *
+ * Local variables can only use the qualifier const."
+ *
+ * This is relaxed in GLSL 1.30. It is also relaxed by any extension
+ * that adds the 'layout' keyword.
+ */
+ if ((state->language_version < 130)
+ && !state->ARB_explicit_attrib_location_enable
+ && !state->ARB_fragment_coord_conventions_enable) {
+ if (this->type->qualifier.flags.q.out) {
+ _mesa_glsl_error(& loc, state,
+ "`out' qualifier in declaration of `%s' "
+ "only valid for function parameters in %s.",
+ decl->identifier, state->version_string);
+ }
+ if (this->type->qualifier.flags.q.in) {
+ _mesa_glsl_error(& loc, state,
+ "`in' qualifier in declaration of `%s' "
+ "only valid for function parameters in %s.",
+ decl->identifier, state->version_string);
+ }
+ /* FINISHME: Test for other invalid qualifiers. */
+ }
+
+ apply_type_qualifier_to_variable(& this->type->qualifier, var, state,
+ & loc);
+
+ if (this->type->qualifier.flags.q.invariant) {
+ if ((state->target == vertex_shader) && !(var->mode == ir_var_out ||
+ var->mode == ir_var_inout)) {
+ /* FINISHME: Note that this doesn't work for invariant on
+ * a function signature outval
+ */
+ _mesa_glsl_error(& loc, state,
+ "`%s' cannot be marked invariant, vertex shader "
+ "outputs only\n", var->name);
+ } else if ((state->target == fragment_shader) &&
+ !(var->mode == ir_var_in || var->mode == ir_var_inout)) {
+ /* FINISHME: Note that this doesn't work for invariant on
+ * a function signature inval
+ */
+ _mesa_glsl_error(& loc, state,
+ "`%s' cannot be marked invariant, fragment shader "
+ "inputs only\n", var->name);
+ }
+ }
+
+ if (state->current_function != NULL) {
+ const char *mode = NULL;
+ const char *extra = "";
+
+ /* There is no need to check for 'inout' here because the parser will
+ * only allow that in function parameter lists.
+ */
+ if (this->type->qualifier.flags.q.attribute) {
+ mode = "attribute";
+ } else if (this->type->qualifier.flags.q.uniform) {
+ mode = "uniform";
+ } else if (this->type->qualifier.flags.q.varying) {
+ mode = "varying";
+ } else if (this->type->qualifier.flags.q.in) {
+ mode = "in";
+ extra = " or in function parameter list";
+ } else if (this->type->qualifier.flags.q.out) {
+ mode = "out";
+ extra = " or in function parameter list";
+ }
+
+ if (mode) {
+ _mesa_glsl_error(& loc, state,
+ "%s variable `%s' must be declared at "
+ "global scope%s",
+ mode, var->name, extra);
+ }
+ } else if (var->mode == ir_var_in) {
+ var->read_only = true;
+
+ if (state->target == vertex_shader) {
+ bool error_emitted = false;
+
+ /* From page 31 (page 37 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "Vertex shader inputs can only be float, floating-point
+ * vectors, matrices, signed and unsigned integers and integer
+ * vectors. Vertex shader inputs can also form arrays of these
+ * types, but not structures."
+ *
+ * From page 31 (page 27 of the PDF) of the GLSL 1.30 spec:
+ *
+ * "Vertex shader inputs can only be float, floating-point
+ * vectors, matrices, signed and unsigned integers and integer
+ * vectors. They cannot be arrays or structures."
+ *
+ * From page 23 (page 29 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "The attribute qualifier can be used only with float,
+ * floating-point vectors, and matrices. Attribute variables
+ * cannot be declared as arrays or structures."
+ */
+ const glsl_type *check_type = var->type->is_array()
+ ? var->type->fields.array : var->type;
+
+ switch (check_type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ break;
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ if (state->language_version > 120)
+ break;
+ /* FALLTHROUGH */
+ default:
+ _mesa_glsl_error(& loc, state,
+ "vertex shader input / attribute cannot have "
+ "type %s`%s'",
+ var->type->is_array() ? "array of " : "",
+ check_type->name);
+ error_emitted = true;
+ }
+
+ if (!error_emitted && (state->language_version <= 130)
+ && var->type->is_array()) {
+ _mesa_glsl_error(& loc, state,
+ "vertex shader input / attribute cannot have "
+ "array type");
+ error_emitted = true;
+ }
+ }
+ }
+
+ /* Integer vertex outputs must be qualified with 'flat'.
+ *
+ * From section 4.3.6 of the GLSL 1.30 spec:
+ * "If a vertex output is a signed or unsigned integer or integer
+ * vector, then it must be qualified with the interpolation qualifier
+ * flat."
+ */
+ if (state->language_version >= 130
+ && state->target == vertex_shader
+ && state->current_function == NULL
+ && var->type->is_integer()
+ && var->mode == ir_var_out
+ && var->interpolation != ir_var_flat) {
+
+ _mesa_glsl_error(&loc, state, "If a vertex output is an integer, "
+ "then it must be qualified with 'flat'");
+ }
+
+
+ /* Interpolation qualifiers cannot be applied to 'centroid' and
+ * 'centroid varying'.
+ *
+ * From page 29 (page 35 of the PDF) of the GLSL 1.30 spec:
+ * "interpolation qualifiers may only precede the qualifiers in,
+ * centroid in, out, or centroid out in a declaration. They do not apply
+ * to the deprecated storage qualifiers varying or centroid varying."
+ */
+ if (state->language_version >= 130
+ && this->type->qualifier.has_interpolation()
+ && this->type->qualifier.flags.q.varying) {
+
+ const char *i = this->type->qualifier.interpolation_string();
+ assert(i != NULL);
+ const char *s;
+ if (this->type->qualifier.flags.q.centroid)
+ s = "centroid varying";
+ else
+ s = "varying";
+
+ _mesa_glsl_error(&loc, state,
+ "qualifier '%s' cannot be applied to the "
+ "deprecated storage qualifier '%s'", i, s);
+ }
+
+
+ /* Interpolation qualifiers can only apply to vertex shader outputs and
+ * fragment shader inputs.
+ *
+ * From page 29 (page 35 of the PDF) of the GLSL 1.30 spec:
+ * "Outputs from a vertex shader (out) and inputs to a fragment
+ * shader (in) can be further qualified with one or more of these
+ * interpolation qualifiers"
+ */
+ if (state->language_version >= 130
+ && this->type->qualifier.has_interpolation()) {
+
+ const char *i = this->type->qualifier.interpolation_string();
+ assert(i != NULL);
+
+ switch (state->target) {
+ case vertex_shader:
+ if (this->type->qualifier.flags.q.in) {
+ _mesa_glsl_error(&loc, state,
+ "qualifier '%s' cannot be applied to vertex "
+ "shader inputs", i);
+ }
+ break;
+ case fragment_shader:
+ if (this->type->qualifier.flags.q.out) {
+ _mesa_glsl_error(&loc, state,
+ "qualifier '%s' cannot be applied to fragment "
+ "shader outputs", i);
+ }
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+
+ /* From section 4.3.4 of the GLSL 1.30 spec:
+ * "It is an error to use centroid in in a vertex shader."
+ */
+ if (state->language_version >= 130
+ && this->type->qualifier.flags.q.centroid
+ && this->type->qualifier.flags.q.in
+ && state->target == vertex_shader) {
+
+ _mesa_glsl_error(&loc, state,
+ "'centroid in' cannot be used in a vertex shader");
+ }
+
+
+ /* Precision qualifiers exists only in GLSL versions 1.00 and >= 1.30.
+ */
+ if (this->type->specifier->precision != ast_precision_none
+ && state->language_version != 100
+ && state->language_version < 130) {
+
+ _mesa_glsl_error(&loc, state,
+ "precision qualifiers are supported only in GLSL ES "
+ "1.00, and GLSL 1.30 and later");
+ }
+
+
+ /* Precision qualifiers only apply to floating point and integer types.
+ *
+ * From section 4.5.2 of the GLSL 1.30 spec:
+ * "Any floating point or any integer declaration can have the type
+ * preceded by one of these precision qualifiers [...] Literal
+ * constants do not have precision qualifiers. Neither do Boolean
+ * variables.
+ */
+ if (this->type->specifier->precision != ast_precision_none
+ && !var->type->is_float()
+ && !var->type->is_integer()
+ && !(var->type->is_array()
+ && (var->type->fields.array->is_float()
+ || var->type->fields.array->is_integer()))) {
+
+ _mesa_glsl_error(&loc, state,
+ "precision qualifiers apply only to floating point "
+ "and integer types");
+ }
+
+ /* Process the initializer and add its instructions to a temporary
+ * list. This list will be added to the instruction stream (below) after
+ * the declaration is added. This is done because in some cases (such as
+ * redeclarations) the declaration may not actually be added to the
+ * instruction stream.
+ */
+ exec_list initializer_instructions;
+ ir_variable *earlier = get_variable_being_redeclared(var, decl, state);
+
+ if (decl->initializer != NULL) {
+ result = process_initializer((earlier == NULL) ? var : earlier,
+ decl, this->type,
+ &initializer_instructions, state);
+ }
+
+ /* From page 23 (page 29 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "It is an error to write to a const variable outside of
+ * its declaration, so they must be initialized when
+ * declared."
+ */
+ if (this->type->qualifier.flags.q.constant && decl->initializer == NULL) {
+ _mesa_glsl_error(& loc, state,
+ "const declaration of `%s' must be initialized",
+ decl->identifier);
+ }
+
+ /* If the declaration is not a redeclaration, there are a few additional
+ * semantic checks that must be applied. In addition, variable that was
+ * created for the declaration should be added to the IR stream.
+ */
+ if (earlier == NULL) {
+ /* From page 15 (page 21 of the PDF) of the GLSL 1.10 spec,
+ *
+ * "Identifiers starting with "gl_" are reserved for use by
+ * OpenGL, and may not be declared in a shader as either a
+ * variable or a function."
+ */
+ if (strncmp(decl->identifier, "gl_", 3) == 0)
+ _mesa_glsl_error(& loc, state,
+ "identifier `%s' uses reserved `gl_' prefix",
+ decl->identifier);
+
+ /* Add the variable to the symbol table. Note that the initializer's
+ * IR was already processed earlier (though it hasn't been emitted
+ * yet), without the variable in scope.
+ *
+ * This differs from most C-like languages, but it follows the GLSL
+ * specification. From page 28 (page 34 of the PDF) of the GLSL 1.50
+ * spec:
+ *
+ * "Within a declaration, the scope of a name starts immediately
+ * after the initializer if present or immediately after the name
+ * being declared if not."
+ */
+ if (!state->symbols->add_variable(var)) {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(&loc, state, "name `%s' already taken in the "
+ "current scope", decl->identifier);
+ continue;
+ }
+
+ /* Push the variable declaration to the top. It means that all the
+ * variable declarations will appear in a funny last-to-first order,
+ * but otherwise we run into trouble if a function is prototyped, a
+ * global var is decled, then the function is defined with usage of
+ * the global var. See glslparsertest's CorrectModule.frag.
+ */
+ instructions->push_head(var);
+ }
+
+ instructions->append_list(&initializer_instructions);
+ }
+
+
+ /* Generally, variable declarations do not have r-values. However,
+ * one is used for the declaration in
+ *
+ * while (bool b = some_condition()) {
+ * ...
+ * }
+ *
+ * so we return the rvalue from the last seen declaration here.
+ */
+ return result;
+}
+
+
+ir_rvalue *
+ast_parameter_declarator::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+ const struct glsl_type *type;
+ const char *name = NULL;
+ YYLTYPE loc = this->get_location();
+
+ type = this->type->specifier->glsl_type(& name, state);
+
+ if (type == NULL) {
+ if (name != NULL) {
+ _mesa_glsl_error(& loc, state,
+ "invalid type `%s' in declaration of `%s'",
+ name, this->identifier);
+ } else {
+ _mesa_glsl_error(& loc, state,
+ "invalid type in declaration of `%s'",
+ this->identifier);
+ }
+
+ type = glsl_type::error_type;
+ }
+
+ /* From page 62 (page 68 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "Functions that accept no input arguments need not use void in the
+ * argument list because prototypes (or definitions) are required and
+ * therefore there is no ambiguity when an empty argument list "( )" is
+ * declared. The idiom "(void)" as a parameter list is provided for
+ * convenience."
+ *
+ * Placing this check here prevents a void parameter being set up
+ * for a function, which avoids tripping up checks for main taking
+ * parameters and lookups of an unnamed symbol.
+ */
+ if (type->is_void()) {
+ if (this->identifier != NULL)
+ _mesa_glsl_error(& loc, state,
+ "named parameter cannot have type `void'");
+
+ is_void = true;
+ return NULL;
+ }
+
+ if (formal_parameter && (this->identifier == NULL)) {
+ _mesa_glsl_error(& loc, state, "formal parameter lacks a name");
+ return NULL;
+ }
+
+ /* This only handles "vec4 foo[..]". The earlier specifier->glsl_type(...)
+ * call already handled the "vec4[..] foo" case.
+ */
+ if (this->is_array) {
+ type = process_array_type(&loc, type, this->array_size, state);
+ }
+
+ if (type->array_size() == 0) {
+ _mesa_glsl_error(&loc, state, "arrays passed as parameters must have "
+ "a declared size.");
+ type = glsl_type::error_type;
+ }
+
+ is_void = false;
+ ir_variable *var = new(ctx) ir_variable(type, this->identifier, ir_var_in);
+
+ /* Apply any specified qualifiers to the parameter declaration. Note that
+ * for function parameters the default mode is 'in'.
+ */
+ apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc);
+
+ instructions->push_tail(var);
+
+ /* Parameter declarations do not have r-values.
+ */
+ return NULL;
+}
+
+
+void
+ast_parameter_declarator::parameters_to_hir(exec_list *ast_parameters,
+ bool formal,
+ exec_list *ir_parameters,
+ _mesa_glsl_parse_state *state)
+{
+ ast_parameter_declarator *void_param = NULL;
+ unsigned count = 0;
+
+ foreach_list_typed (ast_parameter_declarator, param, link, ast_parameters) {
+ param->formal_parameter = formal;
+ param->hir(ir_parameters, state);
+
+ if (param->is_void)
+ void_param = param;
+
+ count++;
+ }
+
+ if ((void_param != NULL) && (count > 1)) {
+ YYLTYPE loc = void_param->get_location();
+
+ _mesa_glsl_error(& loc, state,
+ "`void' parameter must be only parameter");
+ }
+}
+
+
+void
+emit_function(_mesa_glsl_parse_state *state, exec_list *instructions,
+ ir_function *f)
+{
+ /* Emit the new function header */
+ if (state->current_function == NULL) {
+ instructions->push_tail(f);
+ } else {
+ /* IR invariants disallow function declarations or definitions nested
+ * within other function definitions. Insert the new ir_function
+ * block in the instruction sequence before the ir_function block
+ * containing the current ir_function_signature.
+ */
+ ir_function *const curr =
+ const_cast<ir_function *>(state->current_function->function());
+
+ curr->insert_before(f);
+ }
+}
+
+
+ir_rvalue *
+ast_function::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+ ir_function *f = NULL;
+ ir_function_signature *sig = NULL;
+ exec_list hir_parameters;
+
+ const char *const name = identifier;
+
+ /* From page 21 (page 27 of the PDF) of the GLSL 1.20 spec,
+ *
+ * "Function declarations (prototypes) cannot occur inside of functions;
+ * they must be at global scope, or for the built-in functions, outside
+ * the global scope."
+ *
+ * From page 27 (page 33 of the PDF) of the GLSL ES 1.00.16 spec,
+ *
+ * "User defined functions may only be defined within the global scope."
+ *
+ * Note that this language does not appear in GLSL 1.10.
+ */
+ if ((state->current_function != NULL) && (state->language_version != 110)) {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(&loc, state,
+ "declaration of function `%s' not allowed within "
+ "function body", name);
+ }
+
+ /* From page 15 (page 21 of the PDF) of the GLSL 1.10 spec,
+ *
+ * "Identifiers starting with "gl_" are reserved for use by
+ * OpenGL, and may not be declared in a shader as either a
+ * variable or a function."
+ */
+ if (strncmp(name, "gl_", 3) == 0) {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(&loc, state,
+ "identifier `%s' uses reserved `gl_' prefix", name);
+ }
+
+ /* Convert the list of function parameters to HIR now so that they can be
+ * used below to compare this function's signature with previously seen
+ * signatures for functions with the same name.
+ */
+ ast_parameter_declarator::parameters_to_hir(& this->parameters,
+ is_definition,
+ & hir_parameters, state);
+
+ const char *return_type_name;
+ const glsl_type *return_type =
+ this->return_type->specifier->glsl_type(& return_type_name, state);
+
+ if (!return_type) {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(&loc, state,
+ "function `%s' has undeclared return type `%s'",
+ name, return_type_name);
+ return_type = glsl_type::error_type;
+ }
+
+ /* From page 56 (page 62 of the PDF) of the GLSL 1.30 spec:
+ * "No qualifier is allowed on the return type of a function."
+ */
+ if (this->return_type->has_qualifiers()) {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(& loc, state,
+ "function `%s' return type has qualifiers", name);
+ }
+
+ /* Verify that this function's signature either doesn't match a previously
+ * seen signature for a function with the same name, or, if a match is found,
+ * that the previously seen signature does not have an associated definition.
+ */
+ f = state->symbols->get_function(name);
+ if (f != NULL && (state->es_shader || f->has_user_signature())) {
+ sig = f->exact_matching_signature(&hir_parameters);
+ if (sig != NULL) {
+ const char *badvar = sig->qualifiers_match(&hir_parameters);
+ if (badvar != NULL) {
+ YYLTYPE loc = this->get_location();
+
+ _mesa_glsl_error(&loc, state, "function `%s' parameter `%s' "
+ "qualifiers don't match prototype", name, badvar);
+ }
+
+ if (sig->return_type != return_type) {
+ YYLTYPE loc = this->get_location();
+
+ _mesa_glsl_error(&loc, state, "function `%s' return type doesn't "
+ "match prototype", name);
+ }
+
+ if (is_definition && sig->is_defined) {
+ YYLTYPE loc = this->get_location();
+
+ _mesa_glsl_error(& loc, state, "function `%s' redefined", name);
+ }
+ }
+ } else {
+ f = new(ctx) ir_function(name);
+ if (!state->symbols->add_function(f)) {
+ /* This function name shadows a non-function use of the same name. */
+ YYLTYPE loc = this->get_location();
+
+ _mesa_glsl_error(&loc, state, "function name `%s' conflicts with "
+ "non-function", name);
+ return NULL;
+ }
+
+ emit_function(state, instructions, f);
+ }
+
+ /* Verify the return type of main() */
+ if (strcmp(name, "main") == 0) {
+ if (! return_type->is_void()) {
+ YYLTYPE loc = this->get_location();
+
+ _mesa_glsl_error(& loc, state, "main() must return void");
+ }
+
+ if (!hir_parameters.is_empty()) {
+ YYLTYPE loc = this->get_location();
+
+ _mesa_glsl_error(& loc, state, "main() must not take any parameters");
+ }
+ }
+
+ /* Finish storing the information about this new function in its signature.
+ */
+ if (sig == NULL) {
+ sig = new(ctx) ir_function_signature(return_type);
+ f->add_signature(sig);
+ }
+
+ sig->replace_parameters(&hir_parameters);
+ signature = sig;
+
+ /* Function declarations (prototypes) do not have r-values.
+ */
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_function_definition::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ prototype->is_definition = true;
+ prototype->hir(instructions, state);
+
+ ir_function_signature *signature = prototype->signature;
+ if (signature == NULL)
+ return NULL;
+
+ assert(state->current_function == NULL);
+ state->current_function = signature;
+ state->found_return = false;
+
+ /* Duplicate parameters declared in the prototype as concrete variables.
+ * Add these to the symbol table.
+ */
+ state->symbols->push_scope();
+ foreach_iter(exec_list_iterator, iter, signature->parameters) {
+ ir_variable *const var = ((ir_instruction *) iter.get())->as_variable();
+
+ assert(var != NULL);
+
+ /* The only way a parameter would "exist" is if two parameters have
+ * the same name.
+ */
+ if (state->symbols->name_declared_this_scope(var->name)) {
+ YYLTYPE loc = this->get_location();
+
+ _mesa_glsl_error(& loc, state, "parameter `%s' redeclared", var->name);
+ } else {
+ state->symbols->add_variable(var);
+ }
+ }
+
+ /* Convert the body of the function to HIR. */
+ this->body->hir(&signature->body, state);
+ signature->is_defined = true;
+
+ state->symbols->pop_scope();
+
+ assert(state->current_function == signature);
+ state->current_function = NULL;
+
+ if (!signature->return_type->is_void() && !state->found_return) {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(& loc, state, "function `%s' has non-void return type "
+ "%s, but no return statement",
+ signature->function_name(),
+ signature->return_type->name);
+ }
+
+ /* Function definitions do not have r-values.
+ */
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_jump_statement::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ switch (mode) {
+ case ast_return: {
+ ir_return *inst;
+ assert(state->current_function);
+
+ if (opt_return_value) {
+ ir_rvalue *const ret = opt_return_value->hir(instructions, state);
+
+ /* The value of the return type can be NULL if the shader says
+ * 'return foo();' and foo() is a function that returns void.
+ *
+ * NOTE: The GLSL spec doesn't say that this is an error. The type
+ * of the return value is void. If the return type of the function is
+ * also void, then this should compile without error. Seriously.
+ */
+ const glsl_type *const ret_type =
+ (ret == NULL) ? glsl_type::void_type : ret->type;
+
+ /* Implicit conversions are not allowed for return values. */
+ if (state->current_function->return_type != ret_type) {
+ YYLTYPE loc = this->get_location();
+
+ _mesa_glsl_error(& loc, state,
+ "`return' with wrong type %s, in function `%s' "
+ "returning %s",
+ ret_type->name,
+ state->current_function->function_name(),
+ state->current_function->return_type->name);
+ }
+
+ inst = new(ctx) ir_return(ret);
+ } else {
+ if (state->current_function->return_type->base_type !=
+ GLSL_TYPE_VOID) {
+ YYLTYPE loc = this->get_location();
+
+ _mesa_glsl_error(& loc, state,
+ "`return' with no value, in function %s returning "
+ "non-void",
+ state->current_function->function_name());
+ }
+ inst = new(ctx) ir_return;
+ }
+
+ state->found_return = true;
+ instructions->push_tail(inst);
+ break;
+ }
+
+ case ast_discard:
+ if (state->target != fragment_shader) {
+ YYLTYPE loc = this->get_location();
+
+ _mesa_glsl_error(& loc, state,
+ "`discard' may only appear in a fragment shader");
+ }
+ instructions->push_tail(new(ctx) ir_discard);
+ break;
+
+ case ast_break:
+ case ast_continue:
+ /* FINISHME: Handle switch-statements. They cannot contain 'continue',
+ * FINISHME: and they use a different IR instruction for 'break'.
+ */
+ /* FINISHME: Correctly handle the nesting. If a switch-statement is
+ * FINISHME: inside a loop, a 'continue' is valid and will bind to the
+ * FINISHME: loop.
+ */
+ if (state->loop_or_switch_nesting == NULL) {
+ YYLTYPE loc = this->get_location();
+
+ _mesa_glsl_error(& loc, state,
+ "`%s' may only appear in a loop",
+ (mode == ast_break) ? "break" : "continue");
+ } else {
+ ir_loop *const loop = state->loop_or_switch_nesting->as_loop();
+
+ /* Inline the for loop expression again, since we don't know
+ * where near the end of the loop body the normal copy of it
+ * is going to be placed.
+ */
+ if (mode == ast_continue &&
+ state->loop_or_switch_nesting_ast->rest_expression) {
+ state->loop_or_switch_nesting_ast->rest_expression->hir(instructions,
+ state);
+ }
+
+ if (loop != NULL) {
+ ir_loop_jump *const jump =
+ new(ctx) ir_loop_jump((mode == ast_break)
+ ? ir_loop_jump::jump_break
+ : ir_loop_jump::jump_continue);
+ instructions->push_tail(jump);
+ }
+ }
+
+ break;
+ }
+
+ /* Jump instructions do not have r-values.
+ */
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_selection_statement::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ ir_rvalue *const condition = this->condition->hir(instructions, state);
+
+ /* From page 66 (page 72 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "Any expression whose type evaluates to a Boolean can be used as the
+ * conditional expression bool-expression. Vector types are not accepted
+ * as the expression to if."
+ *
+ * The checks are separated so that higher quality diagnostics can be
+ * generated for cases where both rules are violated.
+ */
+ if (!condition->type->is_boolean() || !condition->type->is_scalar()) {
+ YYLTYPE loc = this->condition->get_location();
+
+ _mesa_glsl_error(& loc, state, "if-statement condition must be scalar "
+ "boolean");
+ }
+
+ ir_if *const stmt = new(ctx) ir_if(condition);
+
+ if (then_statement != NULL) {
+ state->symbols->push_scope();
+ then_statement->hir(& stmt->then_instructions, state);
+ state->symbols->pop_scope();
+ }
+
+ if (else_statement != NULL) {
+ state->symbols->push_scope();
+ else_statement->hir(& stmt->else_instructions, state);
+ state->symbols->pop_scope();
+ }
+
+ instructions->push_tail(stmt);
+
+ /* if-statements do not have r-values.
+ */
+ return NULL;
+}
+
+
+void
+ast_iteration_statement::condition_to_hir(ir_loop *stmt,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ if (condition != NULL) {
+ ir_rvalue *const cond =
+ condition->hir(& stmt->body_instructions, state);
+
+ if ((cond == NULL)
+ || !cond->type->is_boolean() || !cond->type->is_scalar()) {
+ YYLTYPE loc = condition->get_location();
+
+ _mesa_glsl_error(& loc, state,
+ "loop condition must be scalar boolean");
+ } else {
+ /* As the first code in the loop body, generate a block that looks
+ * like 'if (!condition) break;' as the loop termination condition.
+ */
+ ir_rvalue *const not_cond =
+ new(ctx) ir_expression(ir_unop_logic_not, glsl_type::bool_type, cond,
+ NULL);
+
+ ir_if *const if_stmt = new(ctx) ir_if(not_cond);
+
+ ir_jump *const break_stmt =
+ new(ctx) ir_loop_jump(ir_loop_jump::jump_break);
+
+ if_stmt->then_instructions.push_tail(break_stmt);
+ stmt->body_instructions.push_tail(if_stmt);
+ }
+ }
+}
+
+
+ir_rvalue *
+ast_iteration_statement::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ /* For-loops and while-loops start a new scope, but do-while loops do not.
+ */
+ if (mode != ast_do_while)
+ state->symbols->push_scope();
+
+ if (init_statement != NULL)
+ init_statement->hir(instructions, state);
+
+ ir_loop *const stmt = new(ctx) ir_loop();
+ instructions->push_tail(stmt);
+
+ /* Track the current loop and / or switch-statement nesting.
+ */
+ ir_instruction *const nesting = state->loop_or_switch_nesting;
+ ast_iteration_statement *nesting_ast = state->loop_or_switch_nesting_ast;
+
+ state->loop_or_switch_nesting = stmt;
+ state->loop_or_switch_nesting_ast = this;
+
+ if (mode != ast_do_while)
+ condition_to_hir(stmt, state);
+
+ if (body != NULL)
+ body->hir(& stmt->body_instructions, state);
+
+ if (rest_expression != NULL)
+ rest_expression->hir(& stmt->body_instructions, state);
+
+ if (mode == ast_do_while)
+ condition_to_hir(stmt, state);
+
+ if (mode != ast_do_while)
+ state->symbols->pop_scope();
+
+ /* Restore previous nesting before returning.
+ */
+ state->loop_or_switch_nesting = nesting;
+ state->loop_or_switch_nesting_ast = nesting_ast;
+
+ /* Loops do not have r-values.
+ */
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_type_specifier::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ if (!this->is_precision_statement && this->structure == NULL)
+ return NULL;
+
+ YYLTYPE loc = this->get_location();
+
+ if (this->precision != ast_precision_none
+ && state->language_version != 100
+ && state->language_version < 130) {
+ _mesa_glsl_error(&loc, state,
+ "precision qualifiers exist only in "
+ "GLSL ES 1.00, and GLSL 1.30 and later");
+ return NULL;
+ }
+ if (this->precision != ast_precision_none
+ && this->structure != NULL) {
+ _mesa_glsl_error(&loc, state,
+ "precision qualifiers do not apply to structures");
+ return NULL;
+ }
+
+ /* If this is a precision statement, check that the type to which it is
+ * applied is either float or int.
+ *
+ * From section 4.5.3 of the GLSL 1.30 spec:
+ * "The precision statement
+ * precision precision-qualifier type;
+ * can be used to establish a default precision qualifier. The type
+ * field can be either int or float [...]. Any other types or
+ * qualifiers will result in an error.
+ */
+ if (this->is_precision_statement) {
+ assert(this->precision != ast_precision_none);
+ assert(this->structure == NULL); /* The check for structures was
+ * performed above. */
+ if (this->is_array) {
+ _mesa_glsl_error(&loc, state,
+ "default precision statements do not apply to "
+ "arrays");
+ return NULL;
+ }
+ if (this->type_specifier != ast_float
+ && this->type_specifier != ast_int) {
+ _mesa_glsl_error(&loc, state,
+ "default precision statements apply only to types "
+ "float and int");
+ return NULL;
+ }
+
+ /* FINISHME: Translate precision statements into IR. */
+ return NULL;
+ }
+
+ if (this->structure != NULL)
+ return this->structure->hir(instructions, state);
+
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_struct_specifier::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ unsigned decl_count = 0;
+
+ /* Make an initial pass over the list of structure fields to determine how
+ * many there are. Each element in this list is an ast_declarator_list.
+ * This means that we actually need to count the number of elements in the
+ * 'declarations' list in each of the elements.
+ */
+ foreach_list_typed (ast_declarator_list, decl_list, link,
+ &this->declarations) {
+ foreach_list_const (decl_ptr, & decl_list->declarations) {
+ decl_count++;
+ }
+ }
+
+ /* Allocate storage for the structure fields and process the field
+ * declarations. As the declarations are processed, try to also convert
+ * the types to HIR. This ensures that structure definitions embedded in
+ * other structure definitions are processed.
+ */
+ glsl_struct_field *const fields = ralloc_array(state, glsl_struct_field,
+ decl_count);
+
+ unsigned i = 0;
+ foreach_list_typed (ast_declarator_list, decl_list, link,
+ &this->declarations) {
+ const char *type_name;
+
+ decl_list->type->specifier->hir(instructions, state);
+
+ /* Section 10.9 of the GLSL ES 1.00 specification states that
+ * embedded structure definitions have been removed from the language.
+ */
+ if (state->es_shader && decl_list->type->specifier->structure != NULL) {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(&loc, state, "Embedded structure definitions are "
+ "not allowed in GLSL ES 1.00.");
+ }
+
+ const glsl_type *decl_type =
+ decl_list->type->specifier->glsl_type(& type_name, state);
+
+ foreach_list_typed (ast_declaration, decl, link,
+ &decl_list->declarations) {
+ const struct glsl_type *field_type = decl_type;
+ if (decl->is_array) {
+ YYLTYPE loc = decl->get_location();
+ field_type = process_array_type(&loc, decl_type, decl->array_size,
+ state);
+ }
+ fields[i].type = (field_type != NULL)
+ ? field_type : glsl_type::error_type;
+ fields[i].name = decl->identifier;
+ i++;
+ }
+ }
+
+ assert(i == decl_count);
+
+ const glsl_type *t =
+ glsl_type::get_record_instance(fields, decl_count, this->name);
+
+ YYLTYPE loc = this->get_location();
+ if (!state->symbols->add_type(name, t)) {
+ _mesa_glsl_error(& loc, state, "struct `%s' previously defined", name);
+ } else {
+ 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;
+ state->num_user_structures++;
+ }
+ }
+
+ /* Structure type definitions do not have r-values.
+ */
+ return NULL;
+}
diff --git a/mesalib/src/glsl/glsl_symbol_table.cpp b/mesalib/src/glsl/glsl_symbol_table.cpp
index 2f291d4f9..bcb65d301 100644
--- a/mesalib/src/glsl/glsl_symbol_table.cpp
+++ b/mesalib/src/glsl/glsl_symbol_table.cpp
@@ -137,6 +137,7 @@ void glsl_symbol_table::add_global_function(ir_function *f)
symbol_table_entry *entry = new(mem_ctx) symbol_table_entry(f);
int added = _mesa_symbol_table_add_global_symbol(table, -1, f->name, entry);
assert(added == 0);
+ (void)added;
}
ir_variable *glsl_symbol_table::get_variable(const char *name)
diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp
index ceb989110..a3623b31e 100644
--- a/mesalib/src/glsl/ir.cpp
+++ b/mesalib/src/glsl/ir.cpp
@@ -1,1572 +1,1572 @@
-/*
- * Copyright © 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 (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.
- */
-#include <string.h>
-#include "main/core.h" /* for MAX2 */
-#include "ir.h"
-#include "ir_visitor.h"
-#include "glsl_types.h"
-
-ir_rvalue::ir_rvalue()
-{
- this->type = glsl_type::error_type;
-}
-
-bool ir_rvalue::is_zero() const
-{
- return false;
-}
-
-bool ir_rvalue::is_one() const
-{
- return false;
-}
-
-bool ir_rvalue::is_negative_one() const
-{
- return false;
-}
-
-/**
- * Modify the swizzle make to move one component to another
- *
- * \param m IR swizzle to be modified
- * \param from Component in the RHS that is to be swizzled
- * \param to Desired swizzle location of \c from
- */
-static void
-update_rhs_swizzle(ir_swizzle_mask &m, unsigned from, unsigned to)
-{
- switch (to) {
- case 0: m.x = from; break;
- case 1: m.y = from; break;
- case 2: m.z = from; break;
- case 3: m.w = from; break;
- default: assert(!"Should not get here.");
- }
-
- m.num_components = MAX2(m.num_components, (to + 1));
-}
-
-void
-ir_assignment::set_lhs(ir_rvalue *lhs)
-{
- void *mem_ctx = this;
- bool swizzled = false;
-
- while (lhs != NULL) {
- ir_swizzle *swiz = lhs->as_swizzle();
-
- if (swiz == NULL)
- break;
-
- unsigned write_mask = 0;
- ir_swizzle_mask rhs_swiz = { 0, 0, 0, 0, 0, 0 };
-
- for (unsigned i = 0; i < swiz->mask.num_components; i++) {
- unsigned c = 0;
-
- switch (i) {
- case 0: c = swiz->mask.x; break;
- case 1: c = swiz->mask.y; break;
- case 2: c = swiz->mask.z; break;
- case 3: c = swiz->mask.w; break;
- default: assert(!"Should not get here.");
- }
-
- write_mask |= (((this->write_mask >> i) & 1) << c);
- update_rhs_swizzle(rhs_swiz, i, c);
- }
-
- this->write_mask = write_mask;
- lhs = swiz->val;
-
- this->rhs = new(mem_ctx) ir_swizzle(this->rhs, rhs_swiz);
- swizzled = true;
- }
-
- if (swizzled) {
- /* Now, RHS channels line up with the LHS writemask. Collapse it
- * to just the channels that will be written.
- */
- ir_swizzle_mask rhs_swiz = { 0, 0, 0, 0, 0, 0 };
- int rhs_chan = 0;
- for (int i = 0; i < 4; i++) {
- if (write_mask & (1 << i))
- update_rhs_swizzle(rhs_swiz, i, rhs_chan++);
- }
- this->rhs = new(mem_ctx) ir_swizzle(this->rhs, rhs_swiz);
- }
-
- assert((lhs == NULL) || lhs->as_dereference());
-
- this->lhs = (ir_dereference *) lhs;
-}
-
-ir_variable *
-ir_assignment::whole_variable_written()
-{
- ir_variable *v = this->lhs->whole_variable_referenced();
-
- if (v == NULL)
- return NULL;
-
- if (v->type->is_scalar())
- return v;
-
- if (v->type->is_vector()) {
- const unsigned mask = (1U << v->type->vector_elements) - 1;
-
- if (mask != this->write_mask)
- return NULL;
- }
-
- /* Either all the vector components are assigned or the variable is some
- * composite type (and the whole thing is assigned.
- */
- return v;
-}
-
-ir_assignment::ir_assignment(ir_dereference *lhs, ir_rvalue *rhs,
- ir_rvalue *condition, unsigned write_mask)
-{
- this->ir_type = ir_type_assignment;
- this->condition = condition;
- this->rhs = rhs;
- this->lhs = lhs;
- this->write_mask = write_mask;
-
- if (lhs->type->is_scalar() || lhs->type->is_vector()) {
- int lhs_components = 0;
- for (int i = 0; i < 4; i++) {
- if (write_mask & (1 << i))
- lhs_components++;
- }
-
- assert(lhs_components == this->rhs->type->vector_elements);
- }
-}
-
-ir_assignment::ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs,
- ir_rvalue *condition)
-{
- this->ir_type = ir_type_assignment;
- this->condition = condition;
- this->rhs = rhs;
-
- /* If the RHS is a vector type, assume that all components of the vector
- * type are being written to the LHS. The write mask comes from the RHS
- * because we can have a case where the LHS is a vec4 and the RHS is a
- * vec3. In that case, the assignment is:
- *
- * (assign (...) (xyz) (var_ref lhs) (var_ref rhs))
- */
- if (rhs->type->is_vector())
- this->write_mask = (1U << rhs->type->vector_elements) - 1;
- else if (rhs->type->is_scalar())
- this->write_mask = 1;
- else
- this->write_mask = 0;
-
- this->set_lhs(lhs);
-}
-
-
-ir_expression::ir_expression(int op, const struct glsl_type *type,
- ir_rvalue *op0)
-{
- assert(get_num_operands(ir_expression_operation(op)) == 1);
- this->ir_type = ir_type_expression;
- this->type = type;
- this->operation = ir_expression_operation(op);
- this->operands[0] = op0;
- this->operands[1] = NULL;
- this->operands[2] = NULL;
- this->operands[3] = NULL;
-}
-
-ir_expression::ir_expression(int op, const struct glsl_type *type,
- ir_rvalue *op0, ir_rvalue *op1)
-{
- assert(((op1 == NULL) && (get_num_operands(ir_expression_operation(op)) == 1))
- || (get_num_operands(ir_expression_operation(op)) == 2));
- this->ir_type = ir_type_expression;
- this->type = type;
- this->operation = ir_expression_operation(op);
- this->operands[0] = op0;
- this->operands[1] = op1;
- this->operands[2] = NULL;
- this->operands[3] = NULL;
-}
-
-ir_expression::ir_expression(int op, const struct glsl_type *type,
- ir_rvalue *op0, ir_rvalue *op1,
- ir_rvalue *op2, ir_rvalue *op3)
-{
- this->ir_type = ir_type_expression;
- this->type = type;
- this->operation = ir_expression_operation(op);
- this->operands[0] = op0;
- this->operands[1] = op1;
- this->operands[2] = op2;
- this->operands[3] = op3;
-}
-
-ir_expression::ir_expression(int op, ir_rvalue *op0)
-{
- this->ir_type = ir_type_expression;
-
- this->operation = ir_expression_operation(op);
- this->operands[0] = op0;
- this->operands[1] = NULL;
- this->operands[2] = NULL;
- this->operands[3] = NULL;
-
- assert(op <= ir_last_unop);
-
- switch (this->operation) {
- case ir_unop_bit_not:
- case ir_unop_logic_not:
- case ir_unop_neg:
- case ir_unop_abs:
- case ir_unop_sign:
- case ir_unop_rcp:
- case ir_unop_rsq:
- case ir_unop_sqrt:
- case ir_unop_exp:
- case ir_unop_log:
- case ir_unop_exp2:
- case ir_unop_log2:
- case ir_unop_trunc:
- case ir_unop_ceil:
- case ir_unop_floor:
- case ir_unop_fract:
- case ir_unop_round_even:
- case ir_unop_sin:
- case ir_unop_cos:
- case ir_unop_sin_reduced:
- case ir_unop_cos_reduced:
- case ir_unop_dFdx:
- case ir_unop_dFdy:
- this->type = op0->type;
- break;
-
- case ir_unop_f2i:
- case ir_unop_b2i:
- this->type = glsl_type::get_instance(GLSL_TYPE_INT,
- op0->type->vector_elements, 1);
- break;
-
- case ir_unop_b2f:
- case ir_unop_i2f:
- case ir_unop_u2f:
- this->type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
- op0->type->vector_elements, 1);
- break;
-
- case ir_unop_f2b:
- case ir_unop_i2b:
- this->type = glsl_type::get_instance(GLSL_TYPE_BOOL,
- op0->type->vector_elements, 1);
- break;
-
- case ir_unop_noise:
- this->type = glsl_type::float_type;
- break;
-
- case ir_unop_any:
- this->type = glsl_type::bool_type;
- break;
-
- default:
- assert(!"not reached: missing automatic type setup for ir_expression");
- this->type = op0->type;
- break;
- }
-}
-
-ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1)
-{
- this->ir_type = ir_type_expression;
-
- this->operation = ir_expression_operation(op);
- this->operands[0] = op0;
- this->operands[1] = op1;
- this->operands[2] = NULL;
- this->operands[3] = NULL;
-
- assert(op > ir_last_unop);
-
- switch (this->operation) {
- case ir_binop_all_equal:
- case ir_binop_any_nequal:
- this->type = glsl_type::bool_type;
- break;
-
- case ir_binop_add:
- case ir_binop_sub:
- case ir_binop_min:
- case ir_binop_max:
- case ir_binop_pow:
- case ir_binop_mul:
- case ir_binop_div:
- case ir_binop_mod:
- if (op0->type->is_scalar()) {
- this->type = op1->type;
- } else if (op1->type->is_scalar()) {
- this->type = op0->type;
- } else {
- /* FINISHME: matrix types */
- assert(!op0->type->is_matrix() && !op1->type->is_matrix());
- assert(op0->type == op1->type);
- this->type = op0->type;
- }
- break;
-
- case ir_binop_logic_and:
- case ir_binop_logic_xor:
- case ir_binop_logic_or:
- case ir_binop_bit_and:
- case ir_binop_bit_xor:
- case ir_binop_bit_or:
- if (op0->type->is_scalar()) {
- this->type = op1->type;
- } else if (op1->type->is_scalar()) {
- this->type = op0->type;
- }
- break;
-
- case ir_binop_equal:
- case ir_binop_nequal:
- case ir_binop_lequal:
- case ir_binop_gequal:
- case ir_binop_less:
- case ir_binop_greater:
- assert(op0->type == op1->type);
- this->type = glsl_type::get_instance(GLSL_TYPE_BOOL,
- op0->type->vector_elements, 1);
- break;
-
- case ir_binop_dot:
- this->type = glsl_type::float_type;
- break;
-
- case ir_binop_lshift:
- case ir_binop_rshift:
- this->type = op0->type;
- break;
-
- default:
- assert(!"not reached: missing automatic type setup for ir_expression");
- this->type = glsl_type::float_type;
- }
-}
-
-unsigned int
-ir_expression::get_num_operands(ir_expression_operation op)
-{
- assert(op <= ir_last_opcode);
-
- if (op <= ir_last_unop)
- return 1;
-
- if (op <= ir_last_binop)
- return 2;
-
- if (op == ir_quadop_vector)
- return 4;
-
- assert(false);
- return 0;
-}
-
-static const char *const operator_strs[] = {
- "~",
- "!",
- "neg",
- "abs",
- "sign",
- "rcp",
- "rsq",
- "sqrt",
- "exp",
- "log",
- "exp2",
- "log2",
- "f2i",
- "i2f",
- "f2b",
- "b2f",
- "i2b",
- "b2i",
- "u2f",
- "any",
- "trunc",
- "ceil",
- "floor",
- "fract",
- "round_even",
- "sin",
- "cos",
- "sin_reduced",
- "cos_reduced",
- "dFdx",
- "dFdy",
- "noise",
- "+",
- "-",
- "*",
- "/",
- "%",
- "<",
- ">",
- "<=",
- ">=",
- "==",
- "!=",
- "all_equal",
- "any_nequal",
- "<<",
- ">>",
- "&",
- "^",
- "|",
- "&&",
- "^^",
- "||",
- "dot",
- "min",
- "max",
- "pow",
- "vector",
-};
-
-const char *ir_expression::operator_string(ir_expression_operation op)
-{
- assert((unsigned int) op < Elements(operator_strs));
- assert(Elements(operator_strs) == (ir_quadop_vector + 1));
- return operator_strs[op];
-}
-
-const char *ir_expression::operator_string()
-{
- return operator_string(this->operation);
-}
-
-const char*
-depth_layout_string(ir_depth_layout layout)
-{
- switch(layout) {
- case ir_depth_layout_none: return "";
- case ir_depth_layout_any: return "depth_any";
- case ir_depth_layout_greater: return "depth_greater";
- case ir_depth_layout_less: return "depth_less";
- case ir_depth_layout_unchanged: return "depth_unchanged";
-
- default:
- assert(0);
- return "";
- }
-}
-
-ir_expression_operation
-ir_expression::get_operator(const char *str)
-{
- const int operator_count = sizeof(operator_strs) / sizeof(operator_strs[0]);
- for (int op = 0; op < operator_count; op++) {
- if (strcmp(str, operator_strs[op]) == 0)
- return (ir_expression_operation) op;
- }
- return (ir_expression_operation) -1;
-}
-
-ir_constant::ir_constant()
-{
- this->ir_type = ir_type_constant;
-}
-
-ir_constant::ir_constant(const struct glsl_type *type,
- const ir_constant_data *data)
-{
- assert((type->base_type >= GLSL_TYPE_UINT)
- && (type->base_type <= GLSL_TYPE_BOOL));
-
- this->ir_type = ir_type_constant;
- this->type = type;
- memcpy(& this->value, data, sizeof(this->value));
-}
-
-ir_constant::ir_constant(float f)
-{
- this->ir_type = ir_type_constant;
- this->type = glsl_type::float_type;
- this->value.f[0] = f;
- for (int i = 1; i < 16; i++) {
- this->value.f[i] = 0;
- }
-}
-
-ir_constant::ir_constant(unsigned int u)
-{
- this->ir_type = ir_type_constant;
- this->type = glsl_type::uint_type;
- this->value.u[0] = u;
- for (int i = 1; i < 16; i++) {
- this->value.u[i] = 0;
- }
-}
-
-ir_constant::ir_constant(int i)
-{
- this->ir_type = ir_type_constant;
- this->type = glsl_type::int_type;
- this->value.i[0] = i;
- for (int i = 1; i < 16; i++) {
- this->value.i[i] = 0;
- }
-}
-
-ir_constant::ir_constant(bool b)
-{
- this->ir_type = ir_type_constant;
- this->type = glsl_type::bool_type;
- this->value.b[0] = b;
- for (int i = 1; i < 16; i++) {
- this->value.b[i] = false;
- }
-}
-
-ir_constant::ir_constant(const ir_constant *c, unsigned i)
-{
- this->ir_type = ir_type_constant;
- this->type = c->type->get_base_type();
-
- switch (this->type->base_type) {
- case GLSL_TYPE_UINT: this->value.u[0] = c->value.u[i]; break;
- case GLSL_TYPE_INT: this->value.i[0] = c->value.i[i]; break;
- case GLSL_TYPE_FLOAT: this->value.f[0] = c->value.f[i]; break;
- case GLSL_TYPE_BOOL: this->value.b[0] = c->value.b[i]; break;
- default: assert(!"Should not get here."); break;
- }
-}
-
-ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list)
-{
- this->ir_type = ir_type_constant;
- this->type = type;
-
- assert(type->is_scalar() || type->is_vector() || type->is_matrix()
- || type->is_record() || type->is_array());
-
- if (type->is_array()) {
- this->array_elements = ralloc_array(this, ir_constant *, type->length);
- unsigned i = 0;
- foreach_list(node, value_list) {
- ir_constant *value = (ir_constant *) node;
- assert(value->as_constant() != NULL);
-
- this->array_elements[i++] = value;
- }
- return;
- }
-
- /* If the constant is a record, the types of each of the entries in
- * value_list must be a 1-for-1 match with the structure components. Each
- * entry must also be a constant. Just move the nodes from the value_list
- * to the list in the ir_constant.
- */
- /* FINISHME: Should there be some type checking and / or assertions here? */
- /* FINISHME: Should the new constant take ownership of the nodes from
- * FINISHME: value_list, or should it make copies?
- */
- if (type->is_record()) {
- value_list->move_nodes_to(& this->components);
- return;
- }
-
- for (unsigned i = 0; i < 16; i++) {
- this->value.u[i] = 0;
- }
-
- ir_constant *value = (ir_constant *) (value_list->head);
-
- /* Constructors with exactly one scalar argument are special for vectors
- * and matrices. For vectors, the scalar value is replicated to fill all
- * the components. For matrices, the scalar fills the components of the
- * diagonal while the rest is filled with 0.
- */
- if (value->type->is_scalar() && value->next->is_tail_sentinel()) {
- if (type->is_matrix()) {
- /* Matrix - fill diagonal (rest is already set to 0) */
- assert(type->base_type == GLSL_TYPE_FLOAT);
- for (unsigned i = 0; i < type->matrix_columns; i++)
- this->value.f[i * type->vector_elements + i] = value->value.f[0];
- } else {
- /* Vector or scalar - fill all components */
- switch (type->base_type) {
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT:
- for (unsigned i = 0; i < type->components(); i++)
- this->value.u[i] = value->value.u[0];
- break;
- case GLSL_TYPE_FLOAT:
- for (unsigned i = 0; i < type->components(); i++)
- this->value.f[i] = value->value.f[0];
- break;
- case GLSL_TYPE_BOOL:
- for (unsigned i = 0; i < type->components(); i++)
- this->value.b[i] = value->value.b[0];
- break;
- default:
- assert(!"Should not get here.");
- break;
- }
- }
- return;
- }
-
- if (type->is_matrix() && value->type->is_matrix()) {
- assert(value->next->is_tail_sentinel());
-
- /* From section 5.4.2 of the GLSL 1.20 spec:
- * "If a matrix is constructed from a matrix, then each component
- * (column i, row j) in the result that has a corresponding component
- * (column i, row j) in the argument will be initialized from there."
- */
- unsigned cols = MIN2(type->matrix_columns, value->type->matrix_columns);
- unsigned rows = MIN2(type->vector_elements, value->type->vector_elements);
- for (unsigned i = 0; i < cols; i++) {
- for (unsigned j = 0; j < rows; j++) {
- const unsigned src = i * value->type->vector_elements + j;
- const unsigned dst = i * type->vector_elements + j;
- this->value.f[dst] = value->value.f[src];
- }
- }
-
- /* "All other components will be initialized to the identity matrix." */
- for (unsigned i = cols; i < type->matrix_columns; i++)
- this->value.f[i * type->vector_elements + i] = 1.0;
-
- return;
- }
-
- /* Use each component from each entry in the value_list to initialize one
- * component of the constant being constructed.
- */
- for (unsigned i = 0; i < type->components(); /* empty */) {
- assert(value->as_constant() != NULL);
- assert(!value->is_tail_sentinel());
-
- for (unsigned j = 0; j < value->type->components(); j++) {
- switch (type->base_type) {
- case GLSL_TYPE_UINT:
- this->value.u[i] = value->get_uint_component(j);
- break;
- case GLSL_TYPE_INT:
- this->value.i[i] = value->get_int_component(j);
- break;
- case GLSL_TYPE_FLOAT:
- this->value.f[i] = value->get_float_component(j);
- break;
- case GLSL_TYPE_BOOL:
- this->value.b[i] = value->get_bool_component(j);
- break;
- default:
- /* FINISHME: What to do? Exceptions are not the answer.
- */
- break;
- }
-
- i++;
- if (i >= type->components())
- break;
- }
-
- value = (ir_constant *) value->next;
- }
-}
-
-ir_constant *
-ir_constant::zero(void *mem_ctx, const glsl_type *type)
-{
- assert(type->is_numeric() || type->is_boolean());
-
- ir_constant *c = new(mem_ctx) ir_constant;
- c->type = type;
- memset(&c->value, 0, sizeof(c->value));
-
- return c;
-}
-
-bool
-ir_constant::get_bool_component(unsigned i) const
-{
- switch (this->type->base_type) {
- case GLSL_TYPE_UINT: return this->value.u[i] != 0;
- case GLSL_TYPE_INT: return this->value.i[i] != 0;
- case GLSL_TYPE_FLOAT: return ((int)this->value.f[i]) != 0;
- case GLSL_TYPE_BOOL: return this->value.b[i];
- default: assert(!"Should not get here."); break;
- }
-
- /* Must return something to make the compiler happy. This is clearly an
- * error case.
- */
- return false;
-}
-
-float
-ir_constant::get_float_component(unsigned i) const
-{
- switch (this->type->base_type) {
- case GLSL_TYPE_UINT: return (float) this->value.u[i];
- case GLSL_TYPE_INT: return (float) this->value.i[i];
- case GLSL_TYPE_FLOAT: return this->value.f[i];
- case GLSL_TYPE_BOOL: return this->value.b[i] ? 1.0 : 0.0;
- default: assert(!"Should not get here."); break;
- }
-
- /* Must return something to make the compiler happy. This is clearly an
- * error case.
- */
- return 0.0;
-}
-
-int
-ir_constant::get_int_component(unsigned i) const
-{
- switch (this->type->base_type) {
- case GLSL_TYPE_UINT: return this->value.u[i];
- case GLSL_TYPE_INT: return this->value.i[i];
- case GLSL_TYPE_FLOAT: return (int) this->value.f[i];
- case GLSL_TYPE_BOOL: return this->value.b[i] ? 1 : 0;
- default: assert(!"Should not get here."); break;
- }
-
- /* Must return something to make the compiler happy. This is clearly an
- * error case.
- */
- return 0;
-}
-
-unsigned
-ir_constant::get_uint_component(unsigned i) const
-{
- switch (this->type->base_type) {
- case GLSL_TYPE_UINT: return this->value.u[i];
- case GLSL_TYPE_INT: return this->value.i[i];
- case GLSL_TYPE_FLOAT: return (unsigned) this->value.f[i];
- case GLSL_TYPE_BOOL: return this->value.b[i] ? 1 : 0;
- default: assert(!"Should not get here."); break;
- }
-
- /* Must return something to make the compiler happy. This is clearly an
- * error case.
- */
- return 0;
-}
-
-ir_constant *
-ir_constant::get_array_element(unsigned i) const
-{
- assert(this->type->is_array());
-
- /* From page 35 (page 41 of the PDF) of the GLSL 1.20 spec:
- *
- * "Behavior is undefined if a shader subscripts an array with an index
- * less than 0 or greater than or equal to the size the array was
- * declared with."
- *
- * Most out-of-bounds accesses are removed before things could get this far.
- * There are cases where non-constant array index values can get constant
- * folded.
- */
- if (int(i) < 0)
- i = 0;
- else if (i >= this->type->length)
- i = this->type->length - 1;
-
- return array_elements[i];
-}
-
-ir_constant *
-ir_constant::get_record_field(const char *name)
-{
- int idx = this->type->field_index(name);
-
- if (idx < 0)
- return NULL;
-
- if (this->components.is_empty())
- return NULL;
-
- exec_node *node = this->components.head;
- for (int i = 0; i < idx; i++) {
- node = node->next;
-
- /* If the end of the list is encountered before the element matching the
- * requested field is found, return NULL.
- */
- if (node->is_tail_sentinel())
- return NULL;
- }
-
- return (ir_constant *) node;
-}
-
-
-bool
-ir_constant::has_value(const ir_constant *c) const
-{
- if (this->type != c->type)
- return false;
-
- if (this->type->is_array()) {
- for (unsigned i = 0; i < this->type->length; i++) {
- if (!this->array_elements[i]->has_value(c->array_elements[i]))
- return false;
- }
- return true;
- }
-
- if (this->type->base_type == GLSL_TYPE_STRUCT) {
- const exec_node *a_node = this->components.head;
- const exec_node *b_node = c->components.head;
-
- while (!a_node->is_tail_sentinel()) {
- assert(!b_node->is_tail_sentinel());
-
- const ir_constant *const a_field = (ir_constant *) a_node;
- const ir_constant *const b_field = (ir_constant *) b_node;
-
- if (!a_field->has_value(b_field))
- return false;
-
- a_node = a_node->next;
- b_node = b_node->next;
- }
-
- return true;
- }
-
- for (unsigned i = 0; i < this->type->components(); i++) {
- switch (this->type->base_type) {
- case GLSL_TYPE_UINT:
- if (this->value.u[i] != c->value.u[i])
- return false;
- break;
- case GLSL_TYPE_INT:
- if (this->value.i[i] != c->value.i[i])
- return false;
- break;
- case GLSL_TYPE_FLOAT:
- if (this->value.f[i] != c->value.f[i])
- return false;
- break;
- case GLSL_TYPE_BOOL:
- if (this->value.b[i] != c->value.b[i])
- return false;
- break;
- default:
- assert(!"Should not get here.");
- return false;
- }
- }
-
- return true;
-}
-
-bool
-ir_constant::is_zero() const
-{
- if (!this->type->is_scalar() && !this->type->is_vector())
- return false;
-
- for (unsigned c = 0; c < this->type->vector_elements; c++) {
- switch (this->type->base_type) {
- case GLSL_TYPE_FLOAT:
- if (this->value.f[c] != 0.0)
- return false;
- break;
- case GLSL_TYPE_INT:
- if (this->value.i[c] != 0)
- return false;
- break;
- case GLSL_TYPE_UINT:
- if (this->value.u[c] != 0)
- return false;
- break;
- case GLSL_TYPE_BOOL:
- if (this->value.b[c] != false)
- return false;
- break;
- default:
- /* The only other base types are structures, arrays, and samplers.
- * Samplers cannot be constants, and the others should have been
- * filtered out above.
- */
- assert(!"Should not get here.");
- return false;
- }
- }
-
- return true;
-}
-
-bool
-ir_constant::is_one() const
-{
- if (!this->type->is_scalar() && !this->type->is_vector())
- return false;
-
- for (unsigned c = 0; c < this->type->vector_elements; c++) {
- switch (this->type->base_type) {
- case GLSL_TYPE_FLOAT:
- if (this->value.f[c] != 1.0)
- return false;
- break;
- case GLSL_TYPE_INT:
- if (this->value.i[c] != 1)
- return false;
- break;
- case GLSL_TYPE_UINT:
- if (this->value.u[c] != 1)
- return false;
- break;
- case GLSL_TYPE_BOOL:
- if (this->value.b[c] != true)
- return false;
- break;
- default:
- /* The only other base types are structures, arrays, and samplers.
- * Samplers cannot be constants, and the others should have been
- * filtered out above.
- */
- assert(!"Should not get here.");
- return false;
- }
- }
-
- return true;
-}
-
-bool
-ir_constant::is_negative_one() const
-{
- if (!this->type->is_scalar() && !this->type->is_vector())
- return false;
-
- if (this->type->is_boolean())
- return false;
-
- for (unsigned c = 0; c < this->type->vector_elements; c++) {
- switch (this->type->base_type) {
- case GLSL_TYPE_FLOAT:
- if (this->value.f[c] != -1.0)
- return false;
- break;
- case GLSL_TYPE_INT:
- if (this->value.i[c] != -1)
- return false;
- break;
- case GLSL_TYPE_UINT:
- if (int(this->value.u[c]) != -1)
- return false;
- break;
- default:
- /* The only other base types are structures, arrays, samplers, and
- * booleans. Samplers cannot be constants, and the others should
- * have been filtered out above.
- */
- assert(!"Should not get here.");
- return false;
- }
- }
-
- return true;
-}
-
-ir_loop::ir_loop()
-{
- this->ir_type = ir_type_loop;
- this->cmp = ir_unop_neg;
- this->from = NULL;
- this->to = NULL;
- this->increment = NULL;
- this->counter = NULL;
-}
-
-
-ir_dereference_variable::ir_dereference_variable(ir_variable *var)
-{
- this->ir_type = ir_type_dereference_variable;
- this->var = var;
- this->type = (var != NULL) ? var->type : glsl_type::error_type;
-}
-
-
-ir_dereference_array::ir_dereference_array(ir_rvalue *value,
- ir_rvalue *array_index)
-{
- this->ir_type = ir_type_dereference_array;
- this->array_index = array_index;
- this->set_array(value);
-}
-
-
-ir_dereference_array::ir_dereference_array(ir_variable *var,
- ir_rvalue *array_index)
-{
- void *ctx = ralloc_parent(var);
-
- this->ir_type = ir_type_dereference_array;
- this->array_index = array_index;
- this->set_array(new(ctx) ir_dereference_variable(var));
-}
-
-
-void
-ir_dereference_array::set_array(ir_rvalue *value)
-{
- this->array = value;
- this->type = glsl_type::error_type;
-
- if (this->array != NULL) {
- const glsl_type *const vt = this->array->type;
-
- if (vt->is_array()) {
- type = vt->element_type();
- } else if (vt->is_matrix()) {
- type = vt->column_type();
- } else if (vt->is_vector()) {
- type = vt->get_base_type();
- }
- }
-}
-
-
-ir_dereference_record::ir_dereference_record(ir_rvalue *value,
- const char *field)
-{
- this->ir_type = ir_type_dereference_record;
- this->record = value;
- this->field = ralloc_strdup(this, field);
- this->type = (this->record != NULL)
- ? this->record->type->field_type(field) : glsl_type::error_type;
-}
-
-
-ir_dereference_record::ir_dereference_record(ir_variable *var,
- const char *field)
-{
- void *ctx = ralloc_parent(var);
-
- this->ir_type = ir_type_dereference_record;
- this->record = new(ctx) ir_dereference_variable(var);
- this->field = ralloc_strdup(this, field);
- this->type = (this->record != NULL)
- ? this->record->type->field_type(field) : glsl_type::error_type;
-}
-
-bool type_contains_sampler(const glsl_type *type)
-{
- if (type->is_array()) {
- return type_contains_sampler(type->fields.array);
- } else if (type->is_record()) {
- for (unsigned int i = 0; i < type->length; i++) {
- if (type_contains_sampler(type->fields.structure[i].type))
- return true;
- }
- return false;
- } else {
- return type->is_sampler();
- }
-}
-
-bool
-ir_dereference::is_lvalue()
-{
- ir_variable *var = this->variable_referenced();
-
- /* Every l-value derference chain eventually ends in a variable.
- */
- if ((var == NULL) || var->read_only)
- return false;
-
- if (this->type->is_array() && !var->array_lvalue)
- return false;
-
- /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
- *
- * "Samplers cannot be treated as l-values; hence cannot be used
- * as out or inout function parameters, nor can they be
- * assigned into."
- */
- if (type_contains_sampler(this->type))
- return false;
-
- return true;
-}
-
-
-const char *tex_opcode_strs[] = { "tex", "txb", "txl", "txd", "txf" };
-
-const char *ir_texture::opcode_string()
-{
- assert((unsigned int) op <=
- sizeof(tex_opcode_strs) / sizeof(tex_opcode_strs[0]));
- return tex_opcode_strs[op];
-}
-
-ir_texture_opcode
-ir_texture::get_opcode(const char *str)
-{
- const int count = sizeof(tex_opcode_strs) / sizeof(tex_opcode_strs[0]);
- for (int op = 0; op < count; op++) {
- if (strcmp(str, tex_opcode_strs[op]) == 0)
- return (ir_texture_opcode) op;
- }
- return (ir_texture_opcode) -1;
-}
-
-
-void
-ir_texture::set_sampler(ir_dereference *sampler, const glsl_type *type)
-{
- assert(sampler != NULL);
- assert(type != NULL);
- this->sampler = sampler;
- this->type = type;
-
- assert(sampler->type->sampler_type == type->base_type);
- if (sampler->type->sampler_shadow)
- assert(type->vector_elements == 4 || type->vector_elements == 1);
- else
- assert(type->vector_elements == 4);
-}
-
-
-void
-ir_swizzle::init_mask(const unsigned *comp, unsigned count)
-{
- assert((count >= 1) && (count <= 4));
-
- memset(&this->mask, 0, sizeof(this->mask));
- this->mask.num_components = count;
-
- unsigned dup_mask = 0;
- switch (count) {
- case 4:
- assert(comp[3] <= 3);
- dup_mask |= (1U << comp[3])
- & ((1U << comp[0]) | (1U << comp[1]) | (1U << comp[2]));
- this->mask.w = comp[3];
-
- case 3:
- assert(comp[2] <= 3);
- dup_mask |= (1U << comp[2])
- & ((1U << comp[0]) | (1U << comp[1]));
- this->mask.z = comp[2];
-
- case 2:
- assert(comp[1] <= 3);
- dup_mask |= (1U << comp[1])
- & ((1U << comp[0]));
- this->mask.y = comp[1];
-
- case 1:
- assert(comp[0] <= 3);
- this->mask.x = comp[0];
- }
-
- this->mask.has_duplicates = dup_mask != 0;
-
- /* Based on the number of elements in the swizzle and the base type
- * (i.e., float, int, unsigned, or bool) of the vector being swizzled,
- * generate the type of the resulting value.
- */
- type = glsl_type::get_instance(val->type->base_type, mask.num_components, 1);
-}
-
-ir_swizzle::ir_swizzle(ir_rvalue *val, unsigned x, unsigned y, unsigned z,
- unsigned w, unsigned count)
- : val(val)
-{
- const unsigned components[4] = { x, y, z, w };
- this->ir_type = ir_type_swizzle;
- this->init_mask(components, count);
-}
-
-ir_swizzle::ir_swizzle(ir_rvalue *val, const unsigned *comp,
- unsigned count)
- : val(val)
-{
- this->ir_type = ir_type_swizzle;
- this->init_mask(comp, count);
-}
-
-ir_swizzle::ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask)
-{
- this->ir_type = ir_type_swizzle;
- this->val = val;
- this->mask = mask;
- this->type = glsl_type::get_instance(val->type->base_type,
- mask.num_components, 1);
-}
-
-#define X 1
-#define R 5
-#define S 9
-#define I 13
-
-ir_swizzle *
-ir_swizzle::create(ir_rvalue *val, const char *str, unsigned vector_length)
-{
- void *ctx = ralloc_parent(val);
-
- /* For each possible swizzle character, this table encodes the value in
- * \c idx_map that represents the 0th element of the vector. For invalid
- * swizzle characters (e.g., 'k'), a special value is used that will allow
- * detection of errors.
- */
- static const unsigned char base_idx[26] = {
- /* a b c d e f g h i j k l m */
- R, R, I, I, I, I, R, I, I, I, I, I, I,
- /* n o p q r s t u v w x y z */
- I, I, S, S, R, S, S, I, I, X, X, X, X
- };
-
- /* Each valid swizzle character has an entry in the previous table. This
- * table encodes the base index encoded in the previous table plus the actual
- * index of the swizzle character. When processing swizzles, the first
- * character in the string is indexed in the previous table. Each character
- * in the string is indexed in this table, and the value found there has the
- * value form the first table subtracted. The result must be on the range
- * [0,3].
- *
- * For example, the string "wzyx" will get X from the first table. Each of
- * the charcaters will get X+3, X+2, X+1, and X+0 from this table. After
- * subtraction, the swizzle values are { 3, 2, 1, 0 }.
- *
- * The string "wzrg" will get X from the first table. Each of the characters
- * will get X+3, X+2, R+0, and R+1 from this table. After subtraction, the
- * swizzle values are { 3, 2, 4, 5 }. Since 4 and 5 are outside the range
- * [0,3], the error is detected.
- */
- static const unsigned char idx_map[26] = {
- /* a b c d e f g h i j k l m */
- R+3, R+2, 0, 0, 0, 0, R+1, 0, 0, 0, 0, 0, 0,
- /* n o p q r s t u v w x y z */
- 0, 0, S+2, S+3, R+0, S+0, S+1, 0, 0, X+3, X+0, X+1, X+2
- };
-
- int swiz_idx[4] = { 0, 0, 0, 0 };
- unsigned i;
-
-
- /* Validate the first character in the swizzle string and look up the base
- * index value as described above.
- */
- if ((str[0] < 'a') || (str[0] > 'z'))
- return NULL;
-
- const unsigned base = base_idx[str[0] - 'a'];
-
-
- for (i = 0; (i < 4) && (str[i] != '\0'); i++) {
- /* Validate the next character, and, as described above, convert it to a
- * swizzle index.
- */
- if ((str[i] < 'a') || (str[i] > 'z'))
- return NULL;
-
- swiz_idx[i] = idx_map[str[i] - 'a'] - base;
- if ((swiz_idx[i] < 0) || (swiz_idx[i] >= (int) vector_length))
- return NULL;
- }
-
- if (str[i] != '\0')
- return NULL;
-
- return new(ctx) ir_swizzle(val, swiz_idx[0], swiz_idx[1], swiz_idx[2],
- swiz_idx[3], i);
-}
-
-#undef X
-#undef R
-#undef S
-#undef I
-
-ir_variable *
-ir_swizzle::variable_referenced()
-{
- return this->val->variable_referenced();
-}
-
-
-ir_variable::ir_variable(const struct glsl_type *type, const char *name,
- ir_variable_mode mode)
- : max_array_access(0), read_only(false), centroid(false), invariant(false),
- mode(mode), interpolation(ir_var_smooth), array_lvalue(false)
-{
- this->ir_type = ir_type_variable;
- this->type = type;
- this->name = ralloc_strdup(this, name);
- this->explicit_location = false;
- this->location = -1;
- this->warn_extension = NULL;
- this->constant_value = NULL;
- this->origin_upper_left = false;
- this->pixel_center_integer = false;
- this->depth_layout = ir_depth_layout_none;
- this->used = false;
-
- if (type && type->base_type == GLSL_TYPE_SAMPLER)
- this->read_only = true;
-}
-
-
-const char *
-ir_variable::interpolation_string() const
-{
- switch (this->interpolation) {
- case ir_var_smooth: return "smooth";
- case ir_var_flat: return "flat";
- case ir_var_noperspective: return "noperspective";
- }
-
- assert(!"Should not get here.");
- return "";
-}
-
-
-unsigned
-ir_variable::component_slots() const
-{
- /* FINISHME: Sparsely accessed arrays require fewer slots. */
- return this->type->component_slots();
-}
-
-
-ir_function_signature::ir_function_signature(const glsl_type *return_type)
- : return_type(return_type), is_defined(false), _function(NULL)
-{
- this->ir_type = ir_type_function_signature;
- this->is_builtin = false;
-}
-
-
-static bool
-modes_match(unsigned a, unsigned b)
-{
- if (a == b)
- return true;
-
- /* Accept "in" vs. "const in" */
- if ((a == ir_var_const_in && b == ir_var_in) ||
- (b == ir_var_const_in && a == ir_var_in))
- return true;
-
- return false;
-}
-
-
-const char *
-ir_function_signature::qualifiers_match(exec_list *params)
-{
- exec_list_iterator iter_a = parameters.iterator();
- exec_list_iterator iter_b = params->iterator();
-
- /* check that the qualifiers match. */
- while (iter_a.has_next()) {
- ir_variable *a = (ir_variable *)iter_a.get();
- ir_variable *b = (ir_variable *)iter_b.get();
-
- if (a->read_only != b->read_only ||
- !modes_match(a->mode, b->mode) ||
- a->interpolation != b->interpolation ||
- a->centroid != b->centroid) {
-
- /* parameter a's qualifiers don't match */
- return a->name;
- }
-
- iter_a.next();
- iter_b.next();
- }
- return NULL;
-}
-
-
-void
-ir_function_signature::replace_parameters(exec_list *new_params)
-{
- /* Destroy all of the previous parameter information. If the previous
- * parameter information comes from the function prototype, it may either
- * specify incorrect parameter names or not have names at all.
- */
- foreach_iter(exec_list_iterator, iter, parameters) {
- assert(((ir_instruction *) iter.get())->as_variable() != NULL);
-
- iter.remove();
- }
-
- new_params->move_nodes_to(&parameters);
-}
-
-
-ir_function::ir_function(const char *name)
-{
- this->ir_type = ir_type_function;
- this->name = ralloc_strdup(this, name);
-}
-
-
-bool
-ir_function::has_user_signature()
-{
- foreach_list(n, &this->signatures) {
- ir_function_signature *const sig = (ir_function_signature *) n;
- if (!sig->is_builtin)
- return true;
- }
- return false;
-}
-
-
-ir_call *
-ir_call::get_error_instruction(void *ctx)
-{
- ir_call *call = new(ctx) ir_call;
-
- call->type = glsl_type::error_type;
- return call;
-}
-
-void
-ir_call::set_callee(ir_function_signature *sig)
-{
- assert((this->type == NULL) || (this->type == sig->return_type));
-
- this->callee = sig;
-}
-
-void
-visit_exec_list(exec_list *list, ir_visitor *visitor)
-{
- foreach_iter(exec_list_iterator, iter, *list) {
- ((ir_instruction *)iter.get())->accept(visitor);
- }
-}
-
-
-static void
-steal_memory(ir_instruction *ir, void *new_ctx)
-{
- ir_variable *var = ir->as_variable();
- ir_constant *constant = ir->as_constant();
- if (var != NULL && var->constant_value != NULL)
- steal_memory(var->constant_value, ir);
-
- /* The components of aggregate constants are not visited by the normal
- * visitor, so steal their values by hand.
- */
- if (constant != NULL) {
- if (constant->type->is_record()) {
- foreach_iter(exec_list_iterator, iter, constant->components) {
- ir_constant *field = (ir_constant *)iter.get();
- steal_memory(field, ir);
- }
- } else if (constant->type->is_array()) {
- for (unsigned int i = 0; i < constant->type->length; i++) {
- steal_memory(constant->array_elements[i], ir);
- }
- }
- }
-
- ralloc_steal(new_ctx, ir);
-}
-
-
-void
-reparent_ir(exec_list *list, void *mem_ctx)
-{
- foreach_list(node, list) {
- visit_tree((ir_instruction *) node, steal_memory, mem_ctx);
- }
-}
-
-
-static ir_rvalue *
-try_min_one(ir_rvalue *ir)
-{
- ir_expression *expr = ir->as_expression();
-
- if (!expr || expr->operation != ir_binop_min)
- return NULL;
-
- if (expr->operands[0]->is_one())
- return expr->operands[1];
-
- if (expr->operands[1]->is_one())
- return expr->operands[0];
-
- return NULL;
-}
-
-static ir_rvalue *
-try_max_zero(ir_rvalue *ir)
-{
- ir_expression *expr = ir->as_expression();
-
- if (!expr || expr->operation != ir_binop_max)
- return NULL;
-
- if (expr->operands[0]->is_zero())
- return expr->operands[1];
-
- if (expr->operands[1]->is_zero())
- return expr->operands[0];
-
- return NULL;
-}
-
-ir_rvalue *
-ir_rvalue::as_rvalue_to_saturate()
-{
- ir_expression *expr = this->as_expression();
-
- if (!expr)
- return NULL;
-
- ir_rvalue *max_zero = try_max_zero(expr);
- if (max_zero) {
- return try_min_one(max_zero);
- } else {
- ir_rvalue *min_one = try_min_one(expr);
- if (min_one) {
- return try_max_zero(min_one);
- }
- }
-
- return NULL;
-}
+/*
+ * Copyright © 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 (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.
+ */
+#include <string.h>
+#include "main/core.h" /* for MAX2 */
+#include "ir.h"
+#include "ir_visitor.h"
+#include "glsl_types.h"
+
+ir_rvalue::ir_rvalue()
+{
+ this->type = glsl_type::error_type;
+}
+
+bool ir_rvalue::is_zero() const
+{
+ return false;
+}
+
+bool ir_rvalue::is_one() const
+{
+ return false;
+}
+
+bool ir_rvalue::is_negative_one() const
+{
+ return false;
+}
+
+/**
+ * Modify the swizzle make to move one component to another
+ *
+ * \param m IR swizzle to be modified
+ * \param from Component in the RHS that is to be swizzled
+ * \param to Desired swizzle location of \c from
+ */
+static void
+update_rhs_swizzle(ir_swizzle_mask &m, unsigned from, unsigned to)
+{
+ switch (to) {
+ case 0: m.x = from; break;
+ case 1: m.y = from; break;
+ case 2: m.z = from; break;
+ case 3: m.w = from; break;
+ default: assert(!"Should not get here.");
+ }
+
+ m.num_components = MAX2(m.num_components, (to + 1));
+}
+
+void
+ir_assignment::set_lhs(ir_rvalue *lhs)
+{
+ void *mem_ctx = this;
+ bool swizzled = false;
+
+ while (lhs != NULL) {
+ ir_swizzle *swiz = lhs->as_swizzle();
+
+ if (swiz == NULL)
+ break;
+
+ unsigned write_mask = 0;
+ ir_swizzle_mask rhs_swiz = { 0, 0, 0, 0, 0, 0 };
+
+ for (unsigned i = 0; i < swiz->mask.num_components; i++) {
+ unsigned c = 0;
+
+ switch (i) {
+ case 0: c = swiz->mask.x; break;
+ case 1: c = swiz->mask.y; break;
+ case 2: c = swiz->mask.z; break;
+ case 3: c = swiz->mask.w; break;
+ default: assert(!"Should not get here.");
+ }
+
+ write_mask |= (((this->write_mask >> i) & 1) << c);
+ update_rhs_swizzle(rhs_swiz, i, c);
+ }
+
+ this->write_mask = write_mask;
+ lhs = swiz->val;
+
+ this->rhs = new(mem_ctx) ir_swizzle(this->rhs, rhs_swiz);
+ swizzled = true;
+ }
+
+ if (swizzled) {
+ /* Now, RHS channels line up with the LHS writemask. Collapse it
+ * to just the channels that will be written.
+ */
+ ir_swizzle_mask rhs_swiz = { 0, 0, 0, 0, 0, 0 };
+ int rhs_chan = 0;
+ for (int i = 0; i < 4; i++) {
+ if (write_mask & (1 << i))
+ update_rhs_swizzle(rhs_swiz, i, rhs_chan++);
+ }
+ this->rhs = new(mem_ctx) ir_swizzle(this->rhs, rhs_swiz);
+ }
+
+ assert((lhs == NULL) || lhs->as_dereference());
+
+ this->lhs = (ir_dereference *) lhs;
+}
+
+ir_variable *
+ir_assignment::whole_variable_written()
+{
+ ir_variable *v = this->lhs->whole_variable_referenced();
+
+ if (v == NULL)
+ return NULL;
+
+ if (v->type->is_scalar())
+ return v;
+
+ if (v->type->is_vector()) {
+ const unsigned mask = (1U << v->type->vector_elements) - 1;
+
+ if (mask != this->write_mask)
+ return NULL;
+ }
+
+ /* Either all the vector components are assigned or the variable is some
+ * composite type (and the whole thing is assigned.
+ */
+ return v;
+}
+
+ir_assignment::ir_assignment(ir_dereference *lhs, ir_rvalue *rhs,
+ ir_rvalue *condition, unsigned write_mask)
+{
+ this->ir_type = ir_type_assignment;
+ this->condition = condition;
+ this->rhs = rhs;
+ this->lhs = lhs;
+ this->write_mask = write_mask;
+
+ if (lhs->type->is_scalar() || lhs->type->is_vector()) {
+ int lhs_components = 0;
+ for (int i = 0; i < 4; i++) {
+ if (write_mask & (1 << i))
+ lhs_components++;
+ }
+
+ assert(lhs_components == this->rhs->type->vector_elements);
+ }
+}
+
+ir_assignment::ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs,
+ ir_rvalue *condition)
+{
+ this->ir_type = ir_type_assignment;
+ this->condition = condition;
+ this->rhs = rhs;
+
+ /* If the RHS is a vector type, assume that all components of the vector
+ * type are being written to the LHS. The write mask comes from the RHS
+ * because we can have a case where the LHS is a vec4 and the RHS is a
+ * vec3. In that case, the assignment is:
+ *
+ * (assign (...) (xyz) (var_ref lhs) (var_ref rhs))
+ */
+ if (rhs->type->is_vector())
+ this->write_mask = (1U << rhs->type->vector_elements) - 1;
+ else if (rhs->type->is_scalar())
+ this->write_mask = 1;
+ else
+ this->write_mask = 0;
+
+ this->set_lhs(lhs);
+}
+
+
+ir_expression::ir_expression(int op, const struct glsl_type *type,
+ ir_rvalue *op0)
+{
+ assert(get_num_operands(ir_expression_operation(op)) == 1);
+ this->ir_type = ir_type_expression;
+ this->type = type;
+ this->operation = ir_expression_operation(op);
+ this->operands[0] = op0;
+ this->operands[1] = NULL;
+ this->operands[2] = NULL;
+ this->operands[3] = NULL;
+}
+
+ir_expression::ir_expression(int op, const struct glsl_type *type,
+ ir_rvalue *op0, ir_rvalue *op1)
+{
+ assert(((op1 == NULL) && (get_num_operands(ir_expression_operation(op)) == 1))
+ || (get_num_operands(ir_expression_operation(op)) == 2));
+ this->ir_type = ir_type_expression;
+ this->type = type;
+ this->operation = ir_expression_operation(op);
+ this->operands[0] = op0;
+ this->operands[1] = op1;
+ this->operands[2] = NULL;
+ this->operands[3] = NULL;
+}
+
+ir_expression::ir_expression(int op, const struct glsl_type *type,
+ ir_rvalue *op0, ir_rvalue *op1,
+ ir_rvalue *op2, ir_rvalue *op3)
+{
+ this->ir_type = ir_type_expression;
+ this->type = type;
+ this->operation = ir_expression_operation(op);
+ this->operands[0] = op0;
+ this->operands[1] = op1;
+ this->operands[2] = op2;
+ this->operands[3] = op3;
+}
+
+ir_expression::ir_expression(int op, ir_rvalue *op0)
+{
+ this->ir_type = ir_type_expression;
+
+ this->operation = ir_expression_operation(op);
+ this->operands[0] = op0;
+ this->operands[1] = NULL;
+ this->operands[2] = NULL;
+ this->operands[3] = NULL;
+
+ assert(op <= ir_last_unop);
+
+ switch (this->operation) {
+ case ir_unop_bit_not:
+ case ir_unop_logic_not:
+ case ir_unop_neg:
+ case ir_unop_abs:
+ case ir_unop_sign:
+ case ir_unop_rcp:
+ case ir_unop_rsq:
+ case ir_unop_sqrt:
+ case ir_unop_exp:
+ case ir_unop_log:
+ case ir_unop_exp2:
+ case ir_unop_log2:
+ case ir_unop_trunc:
+ case ir_unop_ceil:
+ case ir_unop_floor:
+ case ir_unop_fract:
+ case ir_unop_round_even:
+ case ir_unop_sin:
+ case ir_unop_cos:
+ case ir_unop_sin_reduced:
+ case ir_unop_cos_reduced:
+ case ir_unop_dFdx:
+ case ir_unop_dFdy:
+ this->type = op0->type;
+ break;
+
+ case ir_unop_f2i:
+ case ir_unop_b2i:
+ this->type = glsl_type::get_instance(GLSL_TYPE_INT,
+ op0->type->vector_elements, 1);
+ break;
+
+ case ir_unop_b2f:
+ case ir_unop_i2f:
+ case ir_unop_u2f:
+ this->type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
+ op0->type->vector_elements, 1);
+ break;
+
+ case ir_unop_f2b:
+ case ir_unop_i2b:
+ this->type = glsl_type::get_instance(GLSL_TYPE_BOOL,
+ op0->type->vector_elements, 1);
+ break;
+
+ case ir_unop_noise:
+ this->type = glsl_type::float_type;
+ break;
+
+ case ir_unop_any:
+ this->type = glsl_type::bool_type;
+ break;
+
+ default:
+ assert(!"not reached: missing automatic type setup for ir_expression");
+ this->type = op0->type;
+ break;
+ }
+}
+
+ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1)
+{
+ this->ir_type = ir_type_expression;
+
+ this->operation = ir_expression_operation(op);
+ this->operands[0] = op0;
+ this->operands[1] = op1;
+ this->operands[2] = NULL;
+ this->operands[3] = NULL;
+
+ assert(op > ir_last_unop);
+
+ switch (this->operation) {
+ case ir_binop_all_equal:
+ case ir_binop_any_nequal:
+ this->type = glsl_type::bool_type;
+ break;
+
+ case ir_binop_add:
+ case ir_binop_sub:
+ case ir_binop_min:
+ case ir_binop_max:
+ case ir_binop_pow:
+ case ir_binop_mul:
+ case ir_binop_div:
+ case ir_binop_mod:
+ if (op0->type->is_scalar()) {
+ this->type = op1->type;
+ } else if (op1->type->is_scalar()) {
+ this->type = op0->type;
+ } else {
+ /* FINISHME: matrix types */
+ assert(!op0->type->is_matrix() && !op1->type->is_matrix());
+ assert(op0->type == op1->type);
+ this->type = op0->type;
+ }
+ break;
+
+ case ir_binop_logic_and:
+ case ir_binop_logic_xor:
+ case ir_binop_logic_or:
+ case ir_binop_bit_and:
+ case ir_binop_bit_xor:
+ case ir_binop_bit_or:
+ if (op0->type->is_scalar()) {
+ this->type = op1->type;
+ } else if (op1->type->is_scalar()) {
+ this->type = op0->type;
+ }
+ break;
+
+ case ir_binop_equal:
+ case ir_binop_nequal:
+ case ir_binop_lequal:
+ case ir_binop_gequal:
+ case ir_binop_less:
+ case ir_binop_greater:
+ assert(op0->type == op1->type);
+ this->type = glsl_type::get_instance(GLSL_TYPE_BOOL,
+ op0->type->vector_elements, 1);
+ break;
+
+ case ir_binop_dot:
+ this->type = glsl_type::float_type;
+ break;
+
+ case ir_binop_lshift:
+ case ir_binop_rshift:
+ this->type = op0->type;
+ break;
+
+ default:
+ assert(!"not reached: missing automatic type setup for ir_expression");
+ this->type = glsl_type::float_type;
+ }
+}
+
+unsigned int
+ir_expression::get_num_operands(ir_expression_operation op)
+{
+ assert(op <= ir_last_opcode);
+
+ if (op <= ir_last_unop)
+ return 1;
+
+ if (op <= ir_last_binop)
+ return 2;
+
+ if (op == ir_quadop_vector)
+ return 4;
+
+ assert(false);
+ return 0;
+}
+
+static const char *const operator_strs[] = {
+ "~",
+ "!",
+ "neg",
+ "abs",
+ "sign",
+ "rcp",
+ "rsq",
+ "sqrt",
+ "exp",
+ "log",
+ "exp2",
+ "log2",
+ "f2i",
+ "i2f",
+ "f2b",
+ "b2f",
+ "i2b",
+ "b2i",
+ "u2f",
+ "any",
+ "trunc",
+ "ceil",
+ "floor",
+ "fract",
+ "round_even",
+ "sin",
+ "cos",
+ "sin_reduced",
+ "cos_reduced",
+ "dFdx",
+ "dFdy",
+ "noise",
+ "+",
+ "-",
+ "*",
+ "/",
+ "%",
+ "<",
+ ">",
+ "<=",
+ ">=",
+ "==",
+ "!=",
+ "all_equal",
+ "any_nequal",
+ "<<",
+ ">>",
+ "&",
+ "^",
+ "|",
+ "&&",
+ "^^",
+ "||",
+ "dot",
+ "min",
+ "max",
+ "pow",
+ "vector",
+};
+
+const char *ir_expression::operator_string(ir_expression_operation op)
+{
+ assert((unsigned int) op < Elements(operator_strs));
+ assert(Elements(operator_strs) == (ir_quadop_vector + 1));
+ return operator_strs[op];
+}
+
+const char *ir_expression::operator_string()
+{
+ return operator_string(this->operation);
+}
+
+const char*
+depth_layout_string(ir_depth_layout layout)
+{
+ switch(layout) {
+ case ir_depth_layout_none: return "";
+ case ir_depth_layout_any: return "depth_any";
+ case ir_depth_layout_greater: return "depth_greater";
+ case ir_depth_layout_less: return "depth_less";
+ case ir_depth_layout_unchanged: return "depth_unchanged";
+
+ default:
+ assert(0);
+ return "";
+ }
+}
+
+ir_expression_operation
+ir_expression::get_operator(const char *str)
+{
+ const int operator_count = sizeof(operator_strs) / sizeof(operator_strs[0]);
+ for (int op = 0; op < operator_count; op++) {
+ if (strcmp(str, operator_strs[op]) == 0)
+ return (ir_expression_operation) op;
+ }
+ return (ir_expression_operation) -1;
+}
+
+ir_constant::ir_constant()
+{
+ this->ir_type = ir_type_constant;
+}
+
+ir_constant::ir_constant(const struct glsl_type *type,
+ const ir_constant_data *data)
+{
+ assert((type->base_type >= GLSL_TYPE_UINT)
+ && (type->base_type <= GLSL_TYPE_BOOL));
+
+ this->ir_type = ir_type_constant;
+ this->type = type;
+ memcpy(& this->value, data, sizeof(this->value));
+}
+
+ir_constant::ir_constant(float f)
+{
+ this->ir_type = ir_type_constant;
+ this->type = glsl_type::float_type;
+ this->value.f[0] = f;
+ for (int i = 1; i < 16; i++) {
+ this->value.f[i] = 0;
+ }
+}
+
+ir_constant::ir_constant(unsigned int u)
+{
+ this->ir_type = ir_type_constant;
+ this->type = glsl_type::uint_type;
+ this->value.u[0] = u;
+ for (int i = 1; i < 16; i++) {
+ this->value.u[i] = 0;
+ }
+}
+
+ir_constant::ir_constant(int i)
+{
+ this->ir_type = ir_type_constant;
+ this->type = glsl_type::int_type;
+ this->value.i[0] = i;
+ for (int i = 1; i < 16; i++) {
+ this->value.i[i] = 0;
+ }
+}
+
+ir_constant::ir_constant(bool b)
+{
+ this->ir_type = ir_type_constant;
+ this->type = glsl_type::bool_type;
+ this->value.b[0] = b;
+ for (int i = 1; i < 16; i++) {
+ this->value.b[i] = false;
+ }
+}
+
+ir_constant::ir_constant(const ir_constant *c, unsigned i)
+{
+ this->ir_type = ir_type_constant;
+ this->type = c->type->get_base_type();
+
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT: this->value.u[0] = c->value.u[i]; break;
+ case GLSL_TYPE_INT: this->value.i[0] = c->value.i[i]; break;
+ case GLSL_TYPE_FLOAT: this->value.f[0] = c->value.f[i]; break;
+ case GLSL_TYPE_BOOL: this->value.b[0] = c->value.b[i]; break;
+ default: assert(!"Should not get here."); break;
+ }
+}
+
+ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list)
+{
+ this->ir_type = ir_type_constant;
+ this->type = type;
+
+ assert(type->is_scalar() || type->is_vector() || type->is_matrix()
+ || type->is_record() || type->is_array());
+
+ if (type->is_array()) {
+ this->array_elements = ralloc_array(this, ir_constant *, type->length);
+ unsigned i = 0;
+ foreach_list(node, value_list) {
+ ir_constant *value = (ir_constant *) node;
+ assert(value->as_constant() != NULL);
+
+ this->array_elements[i++] = value;
+ }
+ return;
+ }
+
+ /* If the constant is a record, the types of each of the entries in
+ * value_list must be a 1-for-1 match with the structure components. Each
+ * entry must also be a constant. Just move the nodes from the value_list
+ * to the list in the ir_constant.
+ */
+ /* FINISHME: Should there be some type checking and / or assertions here? */
+ /* FINISHME: Should the new constant take ownership of the nodes from
+ * FINISHME: value_list, or should it make copies?
+ */
+ if (type->is_record()) {
+ value_list->move_nodes_to(& this->components);
+ return;
+ }
+
+ for (unsigned i = 0; i < 16; i++) {
+ this->value.u[i] = 0;
+ }
+
+ ir_constant *value = (ir_constant *) (value_list->head);
+
+ /* Constructors with exactly one scalar argument are special for vectors
+ * and matrices. For vectors, the scalar value is replicated to fill all
+ * the components. For matrices, the scalar fills the components of the
+ * diagonal while the rest is filled with 0.
+ */
+ if (value->type->is_scalar() && value->next->is_tail_sentinel()) {
+ if (type->is_matrix()) {
+ /* Matrix - fill diagonal (rest is already set to 0) */
+ assert(type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned i = 0; i < type->matrix_columns; i++)
+ this->value.f[i * type->vector_elements + i] = value->value.f[0];
+ } else {
+ /* Vector or scalar - fill all components */
+ switch (type->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ for (unsigned i = 0; i < type->components(); i++)
+ this->value.u[i] = value->value.u[0];
+ break;
+ case GLSL_TYPE_FLOAT:
+ for (unsigned i = 0; i < type->components(); i++)
+ this->value.f[i] = value->value.f[0];
+ break;
+ case GLSL_TYPE_BOOL:
+ for (unsigned i = 0; i < type->components(); i++)
+ this->value.b[i] = value->value.b[0];
+ break;
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ }
+ return;
+ }
+
+ if (type->is_matrix() && value->type->is_matrix()) {
+ assert(value->next->is_tail_sentinel());
+
+ /* From section 5.4.2 of the GLSL 1.20 spec:
+ * "If a matrix is constructed from a matrix, then each component
+ * (column i, row j) in the result that has a corresponding component
+ * (column i, row j) in the argument will be initialized from there."
+ */
+ unsigned cols = MIN2(type->matrix_columns, value->type->matrix_columns);
+ unsigned rows = MIN2(type->vector_elements, value->type->vector_elements);
+ for (unsigned i = 0; i < cols; i++) {
+ for (unsigned j = 0; j < rows; j++) {
+ const unsigned src = i * value->type->vector_elements + j;
+ const unsigned dst = i * type->vector_elements + j;
+ this->value.f[dst] = value->value.f[src];
+ }
+ }
+
+ /* "All other components will be initialized to the identity matrix." */
+ for (unsigned i = cols; i < type->matrix_columns; i++)
+ this->value.f[i * type->vector_elements + i] = 1.0;
+
+ return;
+ }
+
+ /* Use each component from each entry in the value_list to initialize one
+ * component of the constant being constructed.
+ */
+ for (unsigned i = 0; i < type->components(); /* empty */) {
+ assert(value->as_constant() != NULL);
+ assert(!value->is_tail_sentinel());
+
+ for (unsigned j = 0; j < value->type->components(); j++) {
+ switch (type->base_type) {
+ case GLSL_TYPE_UINT:
+ this->value.u[i] = value->get_uint_component(j);
+ break;
+ case GLSL_TYPE_INT:
+ this->value.i[i] = value->get_int_component(j);
+ break;
+ case GLSL_TYPE_FLOAT:
+ this->value.f[i] = value->get_float_component(j);
+ break;
+ case GLSL_TYPE_BOOL:
+ this->value.b[i] = value->get_bool_component(j);
+ break;
+ default:
+ /* FINISHME: What to do? Exceptions are not the answer.
+ */
+ break;
+ }
+
+ i++;
+ if (i >= type->components())
+ break;
+ }
+
+ value = (ir_constant *) value->next;
+ }
+}
+
+ir_constant *
+ir_constant::zero(void *mem_ctx, const glsl_type *type)
+{
+ assert(type->is_numeric() || type->is_boolean());
+
+ ir_constant *c = new(mem_ctx) ir_constant;
+ c->type = type;
+ memset(&c->value, 0, sizeof(c->value));
+
+ return c;
+}
+
+bool
+ir_constant::get_bool_component(unsigned i) const
+{
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT: return this->value.u[i] != 0;
+ case GLSL_TYPE_INT: return this->value.i[i] != 0;
+ case GLSL_TYPE_FLOAT: return ((int)this->value.f[i]) != 0;
+ case GLSL_TYPE_BOOL: return this->value.b[i];
+ default: assert(!"Should not get here."); break;
+ }
+
+ /* Must return something to make the compiler happy. This is clearly an
+ * error case.
+ */
+ return false;
+}
+
+float
+ir_constant::get_float_component(unsigned i) const
+{
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT: return (float) this->value.u[i];
+ case GLSL_TYPE_INT: return (float) this->value.i[i];
+ case GLSL_TYPE_FLOAT: return this->value.f[i];
+ case GLSL_TYPE_BOOL: return this->value.b[i] ? 1.0 : 0.0;
+ default: assert(!"Should not get here."); break;
+ }
+
+ /* Must return something to make the compiler happy. This is clearly an
+ * error case.
+ */
+ return 0.0;
+}
+
+int
+ir_constant::get_int_component(unsigned i) const
+{
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT: return this->value.u[i];
+ case GLSL_TYPE_INT: return this->value.i[i];
+ case GLSL_TYPE_FLOAT: return (int) this->value.f[i];
+ case GLSL_TYPE_BOOL: return this->value.b[i] ? 1 : 0;
+ default: assert(!"Should not get here."); break;
+ }
+
+ /* Must return something to make the compiler happy. This is clearly an
+ * error case.
+ */
+ return 0;
+}
+
+unsigned
+ir_constant::get_uint_component(unsigned i) const
+{
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT: return this->value.u[i];
+ case GLSL_TYPE_INT: return this->value.i[i];
+ case GLSL_TYPE_FLOAT: return (unsigned) this->value.f[i];
+ case GLSL_TYPE_BOOL: return this->value.b[i] ? 1 : 0;
+ default: assert(!"Should not get here."); break;
+ }
+
+ /* Must return something to make the compiler happy. This is clearly an
+ * error case.
+ */
+ return 0;
+}
+
+ir_constant *
+ir_constant::get_array_element(unsigned i) const
+{
+ assert(this->type->is_array());
+
+ /* From page 35 (page 41 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "Behavior is undefined if a shader subscripts an array with an index
+ * less than 0 or greater than or equal to the size the array was
+ * declared with."
+ *
+ * Most out-of-bounds accesses are removed before things could get this far.
+ * There are cases where non-constant array index values can get constant
+ * folded.
+ */
+ if (int(i) < 0)
+ i = 0;
+ else if (i >= this->type->length)
+ i = this->type->length - 1;
+
+ return array_elements[i];
+}
+
+ir_constant *
+ir_constant::get_record_field(const char *name)
+{
+ int idx = this->type->field_index(name);
+
+ if (idx < 0)
+ return NULL;
+
+ if (this->components.is_empty())
+ return NULL;
+
+ exec_node *node = this->components.head;
+ for (int i = 0; i < idx; i++) {
+ node = node->next;
+
+ /* If the end of the list is encountered before the element matching the
+ * requested field is found, return NULL.
+ */
+ if (node->is_tail_sentinel())
+ return NULL;
+ }
+
+ return (ir_constant *) node;
+}
+
+
+bool
+ir_constant::has_value(const ir_constant *c) const
+{
+ if (this->type != c->type)
+ return false;
+
+ if (this->type->is_array()) {
+ for (unsigned i = 0; i < this->type->length; i++) {
+ if (!this->array_elements[i]->has_value(c->array_elements[i]))
+ return false;
+ }
+ return true;
+ }
+
+ if (this->type->base_type == GLSL_TYPE_STRUCT) {
+ const exec_node *a_node = this->components.head;
+ const exec_node *b_node = c->components.head;
+
+ while (!a_node->is_tail_sentinel()) {
+ assert(!b_node->is_tail_sentinel());
+
+ const ir_constant *const a_field = (ir_constant *) a_node;
+ const ir_constant *const b_field = (ir_constant *) b_node;
+
+ if (!a_field->has_value(b_field))
+ return false;
+
+ a_node = a_node->next;
+ b_node = b_node->next;
+ }
+
+ return true;
+ }
+
+ for (unsigned i = 0; i < this->type->components(); i++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT:
+ if (this->value.u[i] != c->value.u[i])
+ return false;
+ break;
+ case GLSL_TYPE_INT:
+ if (this->value.i[i] != c->value.i[i])
+ return false;
+ break;
+ case GLSL_TYPE_FLOAT:
+ if (this->value.f[i] != c->value.f[i])
+ return false;
+ break;
+ case GLSL_TYPE_BOOL:
+ if (this->value.b[i] != c->value.b[i])
+ return false;
+ break;
+ default:
+ assert(!"Should not get here.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+ir_constant::is_zero() const
+{
+ if (!this->type->is_scalar() && !this->type->is_vector())
+ return false;
+
+ for (unsigned c = 0; c < this->type->vector_elements; c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ if (this->value.f[c] != 0.0)
+ return false;
+ break;
+ case GLSL_TYPE_INT:
+ if (this->value.i[c] != 0)
+ return false;
+ break;
+ case GLSL_TYPE_UINT:
+ if (this->value.u[c] != 0)
+ return false;
+ break;
+ case GLSL_TYPE_BOOL:
+ if (this->value.b[c] != false)
+ return false;
+ break;
+ default:
+ /* The only other base types are structures, arrays, and samplers.
+ * Samplers cannot be constants, and the others should have been
+ * filtered out above.
+ */
+ assert(!"Should not get here.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+ir_constant::is_one() const
+{
+ if (!this->type->is_scalar() && !this->type->is_vector())
+ return false;
+
+ for (unsigned c = 0; c < this->type->vector_elements; c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ if (this->value.f[c] != 1.0)
+ return false;
+ break;
+ case GLSL_TYPE_INT:
+ if (this->value.i[c] != 1)
+ return false;
+ break;
+ case GLSL_TYPE_UINT:
+ if (this->value.u[c] != 1)
+ return false;
+ break;
+ case GLSL_TYPE_BOOL:
+ if (this->value.b[c] != true)
+ return false;
+ break;
+ default:
+ /* The only other base types are structures, arrays, and samplers.
+ * Samplers cannot be constants, and the others should have been
+ * filtered out above.
+ */
+ assert(!"Should not get here.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+ir_constant::is_negative_one() const
+{
+ if (!this->type->is_scalar() && !this->type->is_vector())
+ return false;
+
+ if (this->type->is_boolean())
+ return false;
+
+ for (unsigned c = 0; c < this->type->vector_elements; c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ if (this->value.f[c] != -1.0)
+ return false;
+ break;
+ case GLSL_TYPE_INT:
+ if (this->value.i[c] != -1)
+ return false;
+ break;
+ case GLSL_TYPE_UINT:
+ if (int(this->value.u[c]) != -1)
+ return false;
+ break;
+ default:
+ /* The only other base types are structures, arrays, samplers, and
+ * booleans. Samplers cannot be constants, and the others should
+ * have been filtered out above.
+ */
+ assert(!"Should not get here.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+ir_loop::ir_loop()
+{
+ this->ir_type = ir_type_loop;
+ this->cmp = ir_unop_neg;
+ this->from = NULL;
+ this->to = NULL;
+ this->increment = NULL;
+ this->counter = NULL;
+}
+
+
+ir_dereference_variable::ir_dereference_variable(ir_variable *var)
+{
+ this->ir_type = ir_type_dereference_variable;
+ this->var = var;
+ this->type = (var != NULL) ? var->type : glsl_type::error_type;
+}
+
+
+ir_dereference_array::ir_dereference_array(ir_rvalue *value,
+ ir_rvalue *array_index)
+{
+ this->ir_type = ir_type_dereference_array;
+ this->array_index = array_index;
+ this->set_array(value);
+}
+
+
+ir_dereference_array::ir_dereference_array(ir_variable *var,
+ ir_rvalue *array_index)
+{
+ void *ctx = ralloc_parent(var);
+
+ this->ir_type = ir_type_dereference_array;
+ this->array_index = array_index;
+ this->set_array(new(ctx) ir_dereference_variable(var));
+}
+
+
+void
+ir_dereference_array::set_array(ir_rvalue *value)
+{
+ this->array = value;
+ this->type = glsl_type::error_type;
+
+ if (this->array != NULL) {
+ const glsl_type *const vt = this->array->type;
+
+ if (vt->is_array()) {
+ type = vt->element_type();
+ } else if (vt->is_matrix()) {
+ type = vt->column_type();
+ } else if (vt->is_vector()) {
+ type = vt->get_base_type();
+ }
+ }
+}
+
+
+ir_dereference_record::ir_dereference_record(ir_rvalue *value,
+ const char *field)
+{
+ this->ir_type = ir_type_dereference_record;
+ this->record = value;
+ this->field = ralloc_strdup(this, field);
+ this->type = (this->record != NULL)
+ ? this->record->type->field_type(field) : glsl_type::error_type;
+}
+
+
+ir_dereference_record::ir_dereference_record(ir_variable *var,
+ const char *field)
+{
+ void *ctx = ralloc_parent(var);
+
+ this->ir_type = ir_type_dereference_record;
+ this->record = new(ctx) ir_dereference_variable(var);
+ this->field = ralloc_strdup(this, field);
+ this->type = (this->record != NULL)
+ ? this->record->type->field_type(field) : glsl_type::error_type;
+}
+
+bool type_contains_sampler(const glsl_type *type)
+{
+ if (type->is_array()) {
+ return type_contains_sampler(type->fields.array);
+ } else if (type->is_record()) {
+ for (unsigned int i = 0; i < type->length; i++) {
+ if (type_contains_sampler(type->fields.structure[i].type))
+ return true;
+ }
+ return false;
+ } else {
+ return type->is_sampler();
+ }
+}
+
+bool
+ir_dereference::is_lvalue()
+{
+ ir_variable *var = this->variable_referenced();
+
+ /* Every l-value derference chain eventually ends in a variable.
+ */
+ if ((var == NULL) || var->read_only)
+ return false;
+
+ if (this->type->is_array() && !var->array_lvalue)
+ return false;
+
+ /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "Samplers cannot be treated as l-values; hence cannot be used
+ * as out or inout function parameters, nor can they be
+ * assigned into."
+ */
+ if (type_contains_sampler(this->type))
+ return false;
+
+ return true;
+}
+
+
+const char *tex_opcode_strs[] = { "tex", "txb", "txl", "txd", "txf" };
+
+const char *ir_texture::opcode_string()
+{
+ assert((unsigned int) op <=
+ sizeof(tex_opcode_strs) / sizeof(tex_opcode_strs[0]));
+ return tex_opcode_strs[op];
+}
+
+ir_texture_opcode
+ir_texture::get_opcode(const char *str)
+{
+ const int count = sizeof(tex_opcode_strs) / sizeof(tex_opcode_strs[0]);
+ for (int op = 0; op < count; op++) {
+ if (strcmp(str, tex_opcode_strs[op]) == 0)
+ return (ir_texture_opcode) op;
+ }
+ return (ir_texture_opcode) -1;
+}
+
+
+void
+ir_texture::set_sampler(ir_dereference *sampler, const glsl_type *type)
+{
+ assert(sampler != NULL);
+ assert(type != NULL);
+ this->sampler = sampler;
+ this->type = type;
+
+ assert(sampler->type->sampler_type == (int) type->base_type);
+ if (sampler->type->sampler_shadow)
+ assert(type->vector_elements == 4 || type->vector_elements == 1);
+ else
+ assert(type->vector_elements == 4);
+}
+
+
+void
+ir_swizzle::init_mask(const unsigned *comp, unsigned count)
+{
+ assert((count >= 1) && (count <= 4));
+
+ memset(&this->mask, 0, sizeof(this->mask));
+ this->mask.num_components = count;
+
+ unsigned dup_mask = 0;
+ switch (count) {
+ case 4:
+ assert(comp[3] <= 3);
+ dup_mask |= (1U << comp[3])
+ & ((1U << comp[0]) | (1U << comp[1]) | (1U << comp[2]));
+ this->mask.w = comp[3];
+
+ case 3:
+ assert(comp[2] <= 3);
+ dup_mask |= (1U << comp[2])
+ & ((1U << comp[0]) | (1U << comp[1]));
+ this->mask.z = comp[2];
+
+ case 2:
+ assert(comp[1] <= 3);
+ dup_mask |= (1U << comp[1])
+ & ((1U << comp[0]));
+ this->mask.y = comp[1];
+
+ case 1:
+ assert(comp[0] <= 3);
+ this->mask.x = comp[0];
+ }
+
+ this->mask.has_duplicates = dup_mask != 0;
+
+ /* Based on the number of elements in the swizzle and the base type
+ * (i.e., float, int, unsigned, or bool) of the vector being swizzled,
+ * generate the type of the resulting value.
+ */
+ type = glsl_type::get_instance(val->type->base_type, mask.num_components, 1);
+}
+
+ir_swizzle::ir_swizzle(ir_rvalue *val, unsigned x, unsigned y, unsigned z,
+ unsigned w, unsigned count)
+ : val(val)
+{
+ const unsigned components[4] = { x, y, z, w };
+ this->ir_type = ir_type_swizzle;
+ this->init_mask(components, count);
+}
+
+ir_swizzle::ir_swizzle(ir_rvalue *val, const unsigned *comp,
+ unsigned count)
+ : val(val)
+{
+ this->ir_type = ir_type_swizzle;
+ this->init_mask(comp, count);
+}
+
+ir_swizzle::ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask)
+{
+ this->ir_type = ir_type_swizzle;
+ this->val = val;
+ this->mask = mask;
+ this->type = glsl_type::get_instance(val->type->base_type,
+ mask.num_components, 1);
+}
+
+#define X 1
+#define R 5
+#define S 9
+#define I 13
+
+ir_swizzle *
+ir_swizzle::create(ir_rvalue *val, const char *str, unsigned vector_length)
+{
+ void *ctx = ralloc_parent(val);
+
+ /* For each possible swizzle character, this table encodes the value in
+ * \c idx_map that represents the 0th element of the vector. For invalid
+ * swizzle characters (e.g., 'k'), a special value is used that will allow
+ * detection of errors.
+ */
+ static const unsigned char base_idx[26] = {
+ /* a b c d e f g h i j k l m */
+ R, R, I, I, I, I, R, I, I, I, I, I, I,
+ /* n o p q r s t u v w x y z */
+ I, I, S, S, R, S, S, I, I, X, X, X, X
+ };
+
+ /* Each valid swizzle character has an entry in the previous table. This
+ * table encodes the base index encoded in the previous table plus the actual
+ * index of the swizzle character. When processing swizzles, the first
+ * character in the string is indexed in the previous table. Each character
+ * in the string is indexed in this table, and the value found there has the
+ * value form the first table subtracted. The result must be on the range
+ * [0,3].
+ *
+ * For example, the string "wzyx" will get X from the first table. Each of
+ * the charcaters will get X+3, X+2, X+1, and X+0 from this table. After
+ * subtraction, the swizzle values are { 3, 2, 1, 0 }.
+ *
+ * The string "wzrg" will get X from the first table. Each of the characters
+ * will get X+3, X+2, R+0, and R+1 from this table. After subtraction, the
+ * swizzle values are { 3, 2, 4, 5 }. Since 4 and 5 are outside the range
+ * [0,3], the error is detected.
+ */
+ static const unsigned char idx_map[26] = {
+ /* a b c d e f g h i j k l m */
+ R+3, R+2, 0, 0, 0, 0, R+1, 0, 0, 0, 0, 0, 0,
+ /* n o p q r s t u v w x y z */
+ 0, 0, S+2, S+3, R+0, S+0, S+1, 0, 0, X+3, X+0, X+1, X+2
+ };
+
+ int swiz_idx[4] = { 0, 0, 0, 0 };
+ unsigned i;
+
+
+ /* Validate the first character in the swizzle string and look up the base
+ * index value as described above.
+ */
+ if ((str[0] < 'a') || (str[0] > 'z'))
+ return NULL;
+
+ const unsigned base = base_idx[str[0] - 'a'];
+
+
+ for (i = 0; (i < 4) && (str[i] != '\0'); i++) {
+ /* Validate the next character, and, as described above, convert it to a
+ * swizzle index.
+ */
+ if ((str[i] < 'a') || (str[i] > 'z'))
+ return NULL;
+
+ swiz_idx[i] = idx_map[str[i] - 'a'] - base;
+ if ((swiz_idx[i] < 0) || (swiz_idx[i] >= (int) vector_length))
+ return NULL;
+ }
+
+ if (str[i] != '\0')
+ return NULL;
+
+ return new(ctx) ir_swizzle(val, swiz_idx[0], swiz_idx[1], swiz_idx[2],
+ swiz_idx[3], i);
+}
+
+#undef X
+#undef R
+#undef S
+#undef I
+
+ir_variable *
+ir_swizzle::variable_referenced()
+{
+ return this->val->variable_referenced();
+}
+
+
+ir_variable::ir_variable(const struct glsl_type *type, const char *name,
+ ir_variable_mode mode)
+ : max_array_access(0), read_only(false), centroid(false), invariant(false),
+ mode(mode), interpolation(ir_var_smooth), array_lvalue(false)
+{
+ this->ir_type = ir_type_variable;
+ this->type = type;
+ this->name = ralloc_strdup(this, name);
+ this->explicit_location = false;
+ this->location = -1;
+ this->warn_extension = NULL;
+ this->constant_value = NULL;
+ this->origin_upper_left = false;
+ this->pixel_center_integer = false;
+ this->depth_layout = ir_depth_layout_none;
+ this->used = false;
+
+ if (type && type->base_type == GLSL_TYPE_SAMPLER)
+ this->read_only = true;
+}
+
+
+const char *
+ir_variable::interpolation_string() const
+{
+ switch (this->interpolation) {
+ case ir_var_smooth: return "smooth";
+ case ir_var_flat: return "flat";
+ case ir_var_noperspective: return "noperspective";
+ }
+
+ assert(!"Should not get here.");
+ return "";
+}
+
+
+unsigned
+ir_variable::component_slots() const
+{
+ /* FINISHME: Sparsely accessed arrays require fewer slots. */
+ return this->type->component_slots();
+}
+
+
+ir_function_signature::ir_function_signature(const glsl_type *return_type)
+ : return_type(return_type), is_defined(false), _function(NULL)
+{
+ this->ir_type = ir_type_function_signature;
+ this->is_builtin = false;
+}
+
+
+static bool
+modes_match(unsigned a, unsigned b)
+{
+ if (a == b)
+ return true;
+
+ /* Accept "in" vs. "const in" */
+ if ((a == ir_var_const_in && b == ir_var_in) ||
+ (b == ir_var_const_in && a == ir_var_in))
+ return true;
+
+ return false;
+}
+
+
+const char *
+ir_function_signature::qualifiers_match(exec_list *params)
+{
+ exec_list_iterator iter_a = parameters.iterator();
+ exec_list_iterator iter_b = params->iterator();
+
+ /* check that the qualifiers match. */
+ while (iter_a.has_next()) {
+ ir_variable *a = (ir_variable *)iter_a.get();
+ ir_variable *b = (ir_variable *)iter_b.get();
+
+ if (a->read_only != b->read_only ||
+ !modes_match(a->mode, b->mode) ||
+ a->interpolation != b->interpolation ||
+ a->centroid != b->centroid) {
+
+ /* parameter a's qualifiers don't match */
+ return a->name;
+ }
+
+ iter_a.next();
+ iter_b.next();
+ }
+ return NULL;
+}
+
+
+void
+ir_function_signature::replace_parameters(exec_list *new_params)
+{
+ /* Destroy all of the previous parameter information. If the previous
+ * parameter information comes from the function prototype, it may either
+ * specify incorrect parameter names or not have names at all.
+ */
+ foreach_iter(exec_list_iterator, iter, parameters) {
+ assert(((ir_instruction *) iter.get())->as_variable() != NULL);
+
+ iter.remove();
+ }
+
+ new_params->move_nodes_to(&parameters);
+}
+
+
+ir_function::ir_function(const char *name)
+{
+ this->ir_type = ir_type_function;
+ this->name = ralloc_strdup(this, name);
+}
+
+
+bool
+ir_function::has_user_signature()
+{
+ foreach_list(n, &this->signatures) {
+ ir_function_signature *const sig = (ir_function_signature *) n;
+ if (!sig->is_builtin)
+ return true;
+ }
+ return false;
+}
+
+
+ir_call *
+ir_call::get_error_instruction(void *ctx)
+{
+ ir_call *call = new(ctx) ir_call;
+
+ call->type = glsl_type::error_type;
+ return call;
+}
+
+void
+ir_call::set_callee(ir_function_signature *sig)
+{
+ assert((this->type == NULL) || (this->type == sig->return_type));
+
+ this->callee = sig;
+}
+
+void
+visit_exec_list(exec_list *list, ir_visitor *visitor)
+{
+ foreach_iter(exec_list_iterator, iter, *list) {
+ ((ir_instruction *)iter.get())->accept(visitor);
+ }
+}
+
+
+static void
+steal_memory(ir_instruction *ir, void *new_ctx)
+{
+ ir_variable *var = ir->as_variable();
+ ir_constant *constant = ir->as_constant();
+ if (var != NULL && var->constant_value != NULL)
+ steal_memory(var->constant_value, ir);
+
+ /* The components of aggregate constants are not visited by the normal
+ * visitor, so steal their values by hand.
+ */
+ if (constant != NULL) {
+ if (constant->type->is_record()) {
+ foreach_iter(exec_list_iterator, iter, constant->components) {
+ ir_constant *field = (ir_constant *)iter.get();
+ steal_memory(field, ir);
+ }
+ } else if (constant->type->is_array()) {
+ for (unsigned int i = 0; i < constant->type->length; i++) {
+ steal_memory(constant->array_elements[i], ir);
+ }
+ }
+ }
+
+ ralloc_steal(new_ctx, ir);
+}
+
+
+void
+reparent_ir(exec_list *list, void *mem_ctx)
+{
+ foreach_list(node, list) {
+ visit_tree((ir_instruction *) node, steal_memory, mem_ctx);
+ }
+}
+
+
+static ir_rvalue *
+try_min_one(ir_rvalue *ir)
+{
+ ir_expression *expr = ir->as_expression();
+
+ if (!expr || expr->operation != ir_binop_min)
+ return NULL;
+
+ if (expr->operands[0]->is_one())
+ return expr->operands[1];
+
+ if (expr->operands[1]->is_one())
+ return expr->operands[0];
+
+ return NULL;
+}
+
+static ir_rvalue *
+try_max_zero(ir_rvalue *ir)
+{
+ ir_expression *expr = ir->as_expression();
+
+ if (!expr || expr->operation != ir_binop_max)
+ return NULL;
+
+ if (expr->operands[0]->is_zero())
+ return expr->operands[1];
+
+ if (expr->operands[1]->is_zero())
+ return expr->operands[0];
+
+ return NULL;
+}
+
+ir_rvalue *
+ir_rvalue::as_rvalue_to_saturate()
+{
+ ir_expression *expr = this->as_expression();
+
+ if (!expr)
+ return NULL;
+
+ ir_rvalue *max_zero = try_max_zero(expr);
+ if (max_zero) {
+ return try_min_one(max_zero);
+ } else {
+ ir_rvalue *min_one = try_min_one(expr);
+ if (min_one) {
+ return try_max_zero(min_one);
+ }
+ }
+
+ return NULL;
+}
diff --git a/mesalib/src/mesa/Makefile b/mesalib/src/mesa/Makefile
index 10d73f000..03962e9c1 100644
--- a/mesalib/src/mesa/Makefile
+++ b/mesalib/src/mesa/Makefile
@@ -43,7 +43,7 @@ endef
define mesa-cxx-c
@mkdir -p $(dir $@)
- $(CXX) -c -o $@ $< $($(1)_CPPFLAGS) $($(1)_CFLAGS) $($(1)_CXXFLAGS)
+ $(CXX) -c -o $@ $< $($(1)_CPPFLAGS) $($(1)_CXXFLAGS)
endef
$(MESA_OBJ_DIR)/%.o: %.c
diff --git a/mesalib/src/mesa/main/extensions.c b/mesalib/src/mesa/main/extensions.c
index ea8262086..4b6e91c4f 100644
--- a/mesalib/src/mesa/main/extensions.c
+++ b/mesalib/src/mesa/main/extensions.c
@@ -1,918 +1,980 @@
-/*
- * 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
- * \brief Extension handling
- */
-
-
-#include "glheader.h"
-#include "imports.h"
-#include "context.h"
-#include "extensions.h"
-#include "mfeatures.h"
-#include "mtypes.h"
-
-enum {
- DISABLE = 0,
- GL = 1 << API_OPENGL,
- ES1 = 1 << API_OPENGLES,
- ES2 = 1 << API_OPENGLES2,
-};
-
-/**
- * \brief An element of the \c extension_table.
- */
-struct extension {
- /** Name of extension, such as "GL_ARB_depth_clamp". */
- const char *name;
-
- /** Offset (in bytes) of the corresponding member in struct gl_extensions. */
- size_t offset;
-
- /** Set of API's in which the extension exists, as a bitset. */
- uint8_t api_set;
-};
-
-
-/**
- * Given a member \c x of struct gl_extensions, return offset of
- * \c x in bytes.
- */
-#define o(x) offsetof(struct gl_extensions, x)
-
-
-/**
- * \brief Table of supported OpenGL extensions for all API's.
- *
- * Note: The GL_MESAX_* extensions are placeholders for future ARB extensions.
- */
-static const struct extension extension_table[] = {
- /* ARB Extensions */
- { "GL_ARB_ES2_compatibility", o(ARB_ES2_compatibility), GL },
- { "GL_ARB_blend_func_extended", o(ARB_blend_func_extended), GL },
- { "GL_ARB_copy_buffer", o(ARB_copy_buffer), GL },
- { "GL_ARB_depth_buffer_float", o(ARB_depth_buffer_float), GL },
- { "GL_ARB_depth_clamp", o(ARB_depth_clamp), GL },
- { "GL_ARB_depth_texture", o(ARB_depth_texture), GL },
- { "GL_ARB_draw_buffers", o(ARB_draw_buffers), GL },
- { "GL_ARB_draw_buffers_blend", o(ARB_draw_buffers_blend), GL },
- { "GL_ARB_draw_elements_base_vertex", o(ARB_draw_elements_base_vertex), GL },
- { "GL_ARB_draw_instanced", o(ARB_draw_instanced), GL },
- { "GL_ARB_explicit_attrib_location", o(ARB_explicit_attrib_location), GL },
- { "GL_ARB_fragment_coord_conventions", o(ARB_fragment_coord_conventions), GL },
- { "GL_ARB_fragment_program", o(ARB_fragment_program), GL },
- { "GL_ARB_fragment_program_shadow", o(ARB_fragment_program_shadow), GL },
- { "GL_ARB_fragment_shader", o(ARB_fragment_shader), GL },
- { "GL_ARB_framebuffer_object", o(ARB_framebuffer_object), GL },
- { "GL_ARB_framebuffer_sRGB", o(EXT_framebuffer_sRGB), GL },
- { "GL_ARB_half_float_pixel", o(ARB_half_float_pixel), GL },
- { "GL_ARB_half_float_vertex", o(ARB_half_float_vertex), GL },
- { "GL_ARB_instanced_arrays", o(ARB_instanced_arrays), GL },
- { "GL_ARB_map_buffer_range", o(ARB_map_buffer_range), GL },
- { "GL_ARB_multisample", o(ARB_multisample), GL },
- { "GL_ARB_multitexture", o(ARB_multitexture), GL },
- { "GL_ARB_occlusion_query2", o(ARB_occlusion_query2), GL },
- { "GL_ARB_occlusion_query", o(ARB_occlusion_query), GL },
- { "GL_ARB_pixel_buffer_object", o(EXT_pixel_buffer_object), GL },
- { "GL_ARB_point_parameters", o(EXT_point_parameters), GL },
- { "GL_ARB_point_sprite", o(ARB_point_sprite), GL },
- { "GL_ARB_provoking_vertex", o(EXT_provoking_vertex), GL },
- { "GL_ARB_sampler_objects", o(ARB_sampler_objects), GL },
- { "GL_ARB_seamless_cube_map", o(ARB_seamless_cube_map), GL },
- { "GL_ARB_shader_objects", o(ARB_shader_objects), GL },
- { "GL_ARB_shader_stencil_export", o(ARB_shader_stencil_export), GL },
- { "GL_ARB_shading_language_100", o(ARB_shading_language_100), GL },
- { "GL_ARB_shadow_ambient", o(ARB_shadow_ambient), GL },
- { "GL_ARB_shadow", o(ARB_shadow), GL },
- { "GL_ARB_sync", o(ARB_sync), GL },
- { "GL_ARB_texture_border_clamp", o(ARB_texture_border_clamp), GL },
- { "GL_ARB_texture_buffer_object", o(ARB_texture_buffer_object), GL },
- { "GL_ARB_texture_compression", o(ARB_texture_compression), GL },
- { "GL_ARB_texture_compression_rgtc", o(ARB_texture_compression_rgtc), GL },
- { "GL_ARB_texture_cube_map", o(ARB_texture_cube_map), GL },
- { "GL_ARB_texture_env_add", o(EXT_texture_env_add), GL },
- { "GL_ARB_texture_env_combine", o(ARB_texture_env_combine), GL },
- { "GL_ARB_texture_env_crossbar", o(ARB_texture_env_crossbar), GL },
- { "GL_ARB_texture_env_dot3", o(ARB_texture_env_dot3), GL },
- { "GL_ARB_texture_mirrored_repeat", o(ARB_texture_mirrored_repeat), GL },
- { "GL_ARB_texture_multisample", o(ARB_texture_multisample), GL },
- { "GL_ARB_texture_non_power_of_two", o(ARB_texture_non_power_of_two), GL },
- { "GL_ARB_texture_rectangle", o(NV_texture_rectangle), GL },
- { "GL_ARB_texture_rgb10_a2ui", o(ARB_texture_rgb10_a2ui), GL },
- { "GL_ARB_texture_rg", o(ARB_texture_rg), GL },
- { "GL_ARB_texture_swizzle", o(EXT_texture_swizzle), GL },
- { "GL_ARB_transform_feedback2", o(ARB_transform_feedback2), GL },
- { "GL_ARB_transpose_matrix", o(ARB_transpose_matrix), GL },
- { "GL_ARB_uniform_buffer_object", o(ARB_uniform_buffer_object), GL },
- { "GL_ARB_vertex_array_bgra", o(EXT_vertex_array_bgra), GL },
- { "GL_ARB_vertex_array_object", o(ARB_vertex_array_object), GL },
- { "GL_ARB_vertex_buffer_object", o(ARB_vertex_buffer_object), GL },
- { "GL_ARB_vertex_program", o(ARB_vertex_program), GL },
- { "GL_ARB_vertex_shader", o(ARB_vertex_shader), GL },
- { "GL_ARB_vertex_type_2_10_10_10_rev", o(ARB_vertex_type_2_10_10_10_rev), GL },
- { "GL_ARB_window_pos", o(ARB_window_pos), GL },
-
- /* EXT extensions */
- { "GL_EXT_abgr", o(EXT_abgr), GL },
- { "GL_EXT_bgra", o(EXT_bgra), GL },
- { "GL_EXT_blend_color", o(EXT_blend_color), GL },
- { "GL_EXT_blend_equation_separate", o(EXT_blend_equation_separate), GL },
- { "GL_EXT_blend_func_separate", o(EXT_blend_func_separate), GL },
- { "GL_EXT_blend_logic_op", o(EXT_blend_logic_op), GL },
- { "GL_EXT_blend_minmax", o(EXT_blend_minmax), GL | ES1 | ES2 },
- { "GL_EXT_blend_subtract", o(EXT_blend_subtract), GL },
- { "GL_EXT_clip_volume_hint", o(EXT_clip_volume_hint), GL },
- { "GL_EXT_compiled_vertex_array", o(EXT_compiled_vertex_array), GL },
- { "GL_EXT_copy_texture", o(EXT_copy_texture), GL },
- { "GL_EXT_depth_bounds_test", o(EXT_depth_bounds_test), GL },
- { "GL_EXT_draw_buffers2", o(EXT_draw_buffers2), GL },
- { "GL_EXT_draw_instanced", o(ARB_draw_instanced), GL },
- { "GL_EXT_draw_range_elements", o(EXT_draw_range_elements), GL },
- { "GL_EXT_fog_coord", o(EXT_fog_coord), GL },
- { "GL_EXT_framebuffer_blit", o(EXT_framebuffer_blit), GL },
- { "GL_EXT_framebuffer_multisample", o(EXT_framebuffer_multisample), GL },
- { "GL_EXT_framebuffer_object", o(EXT_framebuffer_object), GL },
- { "GL_EXT_framebuffer_sRGB", o(EXT_framebuffer_sRGB), GL },
- { "GL_EXT_gpu_program_parameters", o(EXT_gpu_program_parameters), GL },
- { "GL_EXT_gpu_shader4", o(EXT_gpu_shader4), GL },
- { "GL_EXT_multi_draw_arrays", o(EXT_multi_draw_arrays), GL | ES1 | ES2 },
- { "GL_EXT_packed_depth_stencil", o(EXT_packed_depth_stencil), GL },
- { "GL_EXT_packed_float", o(EXT_packed_float), GL },
- { "GL_EXT_packed_pixels", o(EXT_packed_pixels), GL },
- { "GL_EXT_paletted_texture", o(EXT_paletted_texture), GL },
- { "GL_EXT_pixel_buffer_object", o(EXT_pixel_buffer_object), GL },
- { "GL_EXT_point_parameters", o(EXT_point_parameters), GL },
- { "GL_EXT_polygon_offset", o(EXT_polygon_offset), GL },
- { "GL_EXT_provoking_vertex", o(EXT_provoking_vertex), GL },
- { "GL_EXT_rescale_normal", o(EXT_rescale_normal), GL },
- { "GL_EXT_secondary_color", o(EXT_secondary_color), GL },
- { "GL_EXT_separate_shader_objects", o(EXT_separate_shader_objects), GL },
- { "GL_EXT_separate_specular_color", o(EXT_separate_specular_color), GL },
- { "GL_EXT_shadow_funcs", o(EXT_shadow_funcs), GL },
- { "GL_EXT_shared_texture_palette", o(EXT_shared_texture_palette), GL },
- { "GL_EXT_stencil_two_side", o(EXT_stencil_two_side), GL },
- { "GL_EXT_stencil_wrap", o(EXT_stencil_wrap), GL },
- { "GL_EXT_subtexture", o(EXT_subtexture), GL },
- { "GL_EXT_texture3D", o(EXT_texture3D), GL },
- { "GL_EXT_texture_array", o(EXT_texture_array), GL },
- { "GL_EXT_texture_compression_dxt1", o(EXT_texture_compression_s3tc), GL | ES1 | ES2 },
- { "GL_EXT_texture_compression_latc", o(EXT_texture_compression_latc), GL },
- { "GL_EXT_texture_compression_rgtc", o(ARB_texture_compression_rgtc), GL },
- { "GL_EXT_texture_compression_s3tc", o(EXT_texture_compression_s3tc), GL },
- { "GL_EXT_texture_cube_map", o(ARB_texture_cube_map), GL },
- { "GL_EXT_texture_edge_clamp", o(SGIS_texture_edge_clamp), GL },
- { "GL_EXT_texture_env_add", o(EXT_texture_env_add), GL },
- { "GL_EXT_texture_env_combine", o(EXT_texture_env_combine), GL },
- { "GL_EXT_texture_env_dot3", o(EXT_texture_env_dot3), GL },
- { "GL_EXT_texture_filter_anisotropic", o(EXT_texture_filter_anisotropic), GL | ES1 | ES2 },
- { "GL_EXT_texture_format_BGRA8888", o(EXT_texture_format_BGRA8888), ES1 | ES2 },
- { "GL_EXT_texture_integer", o(EXT_texture_integer), GL },
- { "GL_EXT_texture_lod_bias", o(EXT_texture_lod_bias), GL | ES1 },
- { "GL_EXT_texture_mirror_clamp", o(EXT_texture_mirror_clamp), GL },
- { "GL_EXT_texture_object", o(EXT_texture_object), GL },
- { "GL_EXT_texture", o(EXT_texture), GL },
- { "GL_EXT_texture_rectangle", o(NV_texture_rectangle), GL },
- { "GL_EXT_texture_shared_exponent", o(EXT_texture_shared_exponent), GL },
- { "GL_EXT_texture_sRGB", o(EXT_texture_sRGB), GL },
- { "GL_EXT_texture_sRGB_decode", o(EXT_texture_sRGB_decode), GL },
- { "GL_EXT_texture_swizzle", o(EXT_texture_swizzle), GL },
- { "GL_EXT_texture_type_2_10_10_10_REV", o(dummy_true), ES2 },
- { "GL_EXT_timer_query", o(EXT_timer_query), GL },
- { "GL_EXT_transform_feedback", o(EXT_transform_feedback), GL },
- { "GL_EXT_vertex_array_bgra", o(EXT_vertex_array_bgra), GL },
- { "GL_EXT_vertex_array", o(EXT_vertex_array), GL },
- { "GL_EXT_vertex_array_set", o(EXT_vertex_array_set), GL },
-
- /* OES extensions */
- { "GL_OES_blend_equation_separate", o(EXT_blend_equation_separate), ES1 },
- { "GL_OES_blend_func_separate", o(EXT_blend_func_separate), ES1 },
- { "GL_OES_blend_subtract", o(EXT_blend_subtract), ES1 },
- { "GL_OES_byte_coordinates", o(dummy_true), ES1 },
- { "GL_OES_compressed_paletted_texture", o(dummy_false), DISABLE },
- { "GL_OES_depth24", o(EXT_framebuffer_object), ES1 | ES2 },
- { "GL_OES_depth32", o(dummy_false), DISABLE },
- { "GL_OES_depth_texture", o(ARB_depth_texture), ES2 },
-#if FEATURE_OES_draw_texture
- { "GL_OES_draw_texture", o(OES_draw_texture), ES1 | ES2 },
-#endif
-#if FEATURE_OES_EGL_image
- /* FIXME: Mesa expects GL_OES_EGL_image to be available in OpenGL contexts. */
- { "GL_OES_EGL_image", o(OES_EGL_image), GL | ES1 | ES2 },
-#endif
- { "GL_OES_element_index_uint", o(EXT_vertex_array), ES1 | ES2 },
- { "GL_OES_fbo_render_mipmap", o(EXT_framebuffer_object), ES1 | ES2 },
- { "GL_OES_fixed_point", o(dummy_true), ES1 },
- { "GL_OES_framebuffer_object", o(EXT_framebuffer_object), ES1 },
- { "GL_OES_mapbuffer", o(ARB_vertex_buffer_object), ES1 | ES2 },
- { "GL_OES_matrix_get", o(dummy_true), ES1 },
- { "GL_OES_packed_depth_stencil", o(EXT_packed_depth_stencil), ES1 | ES2 },
- { "GL_OES_point_size_array", o(dummy_true), ES1 },
- { "GL_OES_point_sprite", o(ARB_point_sprite), ES1 },
- { "GL_OES_query_matrix", o(dummy_true), ES1 },
- { "GL_OES_read_format", o(OES_read_format), GL | ES1 },
- { "GL_OES_rgb8_rgba8", o(EXT_framebuffer_object), ES1 | ES2 },
- { "GL_OES_single_precision", o(dummy_true), ES1 },
- { "GL_OES_standard_derivatives", o(OES_standard_derivatives), ES2 },
- { "GL_OES_stencil1", o(dummy_false), DISABLE },
- { "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", 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 },
- { "GL_OES_texture_npot", o(ARB_texture_non_power_of_two), ES2 },
-
- /* Vendor extensions */
- { "GL_3DFX_texture_compression_FXT1", o(TDFX_texture_compression_FXT1), GL },
- { "GL_AMD_conservative_depth", o(AMD_conservative_depth), GL },
- { "GL_APPLE_client_storage", o(APPLE_client_storage), GL },
- { "GL_APPLE_object_purgeable", o(APPLE_object_purgeable), GL },
- { "GL_APPLE_packed_pixels", o(APPLE_packed_pixels), GL },
- { "GL_APPLE_vertex_array_object", o(APPLE_vertex_array_object), GL },
- { "GL_ATI_blend_equation_separate", o(EXT_blend_equation_separate), GL },
- { "GL_ATI_envmap_bumpmap", o(ATI_envmap_bumpmap), GL },
- { "GL_ATI_fragment_shader", o(ATI_fragment_shader), GL },
- { "GL_ATI_separate_stencil", o(ATI_separate_stencil), GL },
- { "GL_ATI_texture_compression_3dc", o(ATI_texture_compression_3dc), GL },
- { "GL_ATI_texture_env_combine3", o(ATI_texture_env_combine3), GL },
- { "GL_ATI_texture_mirror_once", o(ATI_texture_mirror_once), GL },
- { "GL_IBM_multimode_draw_arrays", o(IBM_multimode_draw_arrays), GL },
- { "GL_IBM_rasterpos_clip", o(IBM_rasterpos_clip), GL },
- { "GL_IBM_texture_mirrored_repeat", o(ARB_texture_mirrored_repeat), GL },
- { "GL_INGR_blend_func_separate", o(EXT_blend_func_separate), GL },
- { "GL_MESA_pack_invert", o(MESA_pack_invert), GL },
- { "GL_MESA_resize_buffers", o(MESA_resize_buffers), GL },
- { "GL_MESA_texture_array", o(MESA_texture_array), GL },
- { "GL_MESA_texture_signed_rgba", o(MESA_texture_signed_rgba), GL },
- { "GL_MESA_window_pos", o(ARB_window_pos), GL },
- { "GL_MESAX_texture_float", o(ARB_texture_float), GL },
- { "GL_MESA_ycbcr_texture", o(MESA_ycbcr_texture), GL },
- { "GL_NV_blend_square", o(NV_blend_square), GL },
- { "GL_NV_conditional_render", o(NV_conditional_render), GL },
- { "GL_NV_depth_clamp", o(ARB_depth_clamp), GL },
- { "GL_NV_fragment_program", o(NV_fragment_program), GL },
- { "GL_NV_fragment_program_option", o(NV_fragment_program_option), GL },
- { "GL_NV_light_max_exponent", o(NV_light_max_exponent), GL },
- { "GL_NV_packed_depth_stencil", o(EXT_packed_depth_stencil), GL },
- { "GL_NV_point_sprite", o(NV_point_sprite), GL },
- { "GL_NV_primitive_restart", o(NV_primitive_restart), GL },
- { "GL_NV_texgen_reflection", o(NV_texgen_reflection), GL },
- { "GL_NV_texture_barrier", o(NV_texture_barrier), GL },
- { "GL_NV_texture_env_combine4", o(NV_texture_env_combine4), GL },
- { "GL_NV_texture_rectangle", o(NV_texture_rectangle), GL },
- { "GL_NV_vertex_program1_1", o(NV_vertex_program1_1), GL },
- { "GL_NV_vertex_program", o(NV_vertex_program), GL },
- { "GL_S3_s3tc", o(S3_s3tc), GL },
- { "GL_SGIS_generate_mipmap", o(SGIS_generate_mipmap), GL },
- { "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_SUN_multi_draw_arrays", o(EXT_multi_draw_arrays), GL },
-
- { 0, 0, 0 },
-};
-
-
-/**
- * Given an extension name, lookup up the corresponding member of struct
- * gl_extensions and return that member's offset (in bytes). If the name is
- * not found in the \c extension_table, return 0.
- *
- * \param name Name of extension.
- * \return Offset of member in struct gl_extensions.
- */
-static size_t
-name_to_offset(const char* name)
-{
- const struct extension *i;
-
- if (name == 0)
- return 0;
-
- for (i = extension_table; i->name != 0; ++i) {
- if (strcmp(name, i->name) == 0)
- return i->offset;
- }
-
- return 0;
-}
-
-
-/**
- * \brief Extensions enabled by default.
- *
- * These extensions are enabled by _mesa_init_extensions().
- *
- * XXX: Should these defaults also apply to GLES?
- */
-static const size_t default_extensions[] = {
- o(ARB_copy_buffer),
- o(ARB_draw_buffers),
- o(ARB_multisample),
- o(ARB_texture_compression),
- o(ARB_transpose_matrix),
- o(ARB_vertex_buffer_object),
- o(ARB_window_pos),
-
- o(EXT_abgr),
- o(EXT_bgra),
- o(EXT_compiled_vertex_array),
- o(EXT_copy_texture),
- o(EXT_draw_range_elements),
- o(EXT_multi_draw_arrays),
- o(EXT_packed_pixels),
- o(EXT_polygon_offset),
- o(EXT_rescale_normal),
- o(EXT_separate_specular_color),
- o(EXT_subtexture),
- o(EXT_texture),
- o(EXT_texture3D),
- o(EXT_texture_object),
- o(EXT_vertex_array),
-
- o(OES_read_format),
- o(OES_standard_derivatives),
-
- /* Vendor Extensions */
- o(APPLE_packed_pixels),
- o(IBM_multimode_draw_arrays),
- o(IBM_rasterpos_clip),
- o(NV_light_max_exponent),
- o(NV_texgen_reflection),
- o(SGIS_generate_mipmap),
- o(SGIS_texture_edge_clamp),
- o(SGIS_texture_lod),
-
- 0,
-};
-
-
-/**
- * Enable all extensions suitable for a software-only renderer.
- * This is a convenience function used by the XMesa, OSMesa, GGI drivers, etc.
- */
-void
-_mesa_enable_sw_extensions(struct gl_context *ctx)
-{
- /*ctx->Extensions.ARB_copy_buffer = GL_TRUE;*/
- ctx->Extensions.ARB_depth_clamp = GL_TRUE;
- ctx->Extensions.ARB_depth_texture = GL_TRUE;
- /*ctx->Extensions.ARB_draw_buffers = GL_TRUE;*/
- ctx->Extensions.ARB_draw_elements_base_vertex = GL_TRUE;
- ctx->Extensions.ARB_draw_instanced = GL_TRUE;
- ctx->Extensions.ARB_explicit_attrib_location = GL_TRUE;
- ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE;
-#if FEATURE_ARB_fragment_program
- ctx->Extensions.ARB_fragment_program = GL_TRUE;
- ctx->Extensions.ARB_fragment_program_shadow = GL_TRUE;
-#endif
-#if FEATURE_ARB_fragment_shader
- ctx->Extensions.ARB_fragment_shader = GL_TRUE;
-#endif
-#if FEATURE_ARB_framebuffer_object
- ctx->Extensions.ARB_framebuffer_object = GL_TRUE;
-#endif
-#if FEATURE_ARB_geometry_shader4 && 0
- /* XXX re-enable when GLSL compiler again supports geometry shaders */
- ctx->Extensions.ARB_geometry_shader4 = GL_TRUE;
-#endif
- ctx->Extensions.ARB_half_float_pixel = GL_TRUE;
- ctx->Extensions.ARB_half_float_vertex = GL_TRUE;
- ctx->Extensions.ARB_map_buffer_range = GL_TRUE;
- ctx->Extensions.ARB_multitexture = GL_TRUE;
-#if FEATURE_queryobj
- ctx->Extensions.ARB_occlusion_query = GL_TRUE;
- ctx->Extensions.ARB_occlusion_query2 = GL_TRUE;
-#endif
- ctx->Extensions.ARB_point_sprite = GL_TRUE;
-#if FEATURE_ARB_shader_objects
- ctx->Extensions.ARB_shader_objects = GL_TRUE;
- ctx->Extensions.EXT_separate_shader_objects = GL_TRUE;
-#endif
-#if FEATURE_ARB_shading_language_100
- ctx->Extensions.ARB_shading_language_100 = GL_TRUE;
-#endif
- ctx->Extensions.ARB_shadow = GL_TRUE;
- ctx->Extensions.ARB_shadow_ambient = GL_TRUE;
- ctx->Extensions.ARB_texture_border_clamp = GL_TRUE;
- ctx->Extensions.ARB_texture_cube_map = GL_TRUE;
- ctx->Extensions.ARB_texture_env_combine = GL_TRUE;
- ctx->Extensions.ARB_texture_env_crossbar = GL_TRUE;
- ctx->Extensions.ARB_texture_env_dot3 = GL_TRUE;
- /*ctx->Extensions.ARB_texture_float = GL_TRUE;*/
- ctx->Extensions.ARB_texture_mirrored_repeat = GL_TRUE;
- ctx->Extensions.ARB_texture_non_power_of_two = GL_TRUE;
- ctx->Extensions.ARB_texture_rg = GL_TRUE;
- ctx->Extensions.ARB_texture_compression_rgtc = GL_TRUE;
- ctx->Extensions.ARB_vertex_array_object = GL_TRUE;
-#if FEATURE_ARB_vertex_program
- ctx->Extensions.ARB_vertex_program = GL_TRUE;
-#endif
-#if FEATURE_ARB_vertex_shader
- ctx->Extensions.ARB_vertex_shader = GL_TRUE;
-#endif
-#if FEATURE_ARB_vertex_buffer_object
- /*ctx->Extensions.ARB_vertex_buffer_object = GL_TRUE;*/
-#endif
-#if FEATURE_ARB_sync
- ctx->Extensions.ARB_sync = GL_TRUE;
-#endif
- ctx->Extensions.APPLE_vertex_array_object = GL_TRUE;
-#if FEATURE_APPLE_object_purgeable
- ctx->Extensions.APPLE_object_purgeable = GL_TRUE;
-#endif
- ctx->Extensions.ATI_envmap_bumpmap = GL_TRUE;
-#if FEATURE_ATI_fragment_shader
- ctx->Extensions.ATI_fragment_shader = GL_TRUE;
-#endif
- ctx->Extensions.ATI_texture_compression_3dc = GL_TRUE;
- ctx->Extensions.ATI_texture_env_combine3 = GL_TRUE;
- ctx->Extensions.ATI_texture_mirror_once = GL_TRUE;
- ctx->Extensions.ATI_separate_stencil = GL_TRUE;
- ctx->Extensions.EXT_blend_color = GL_TRUE;
- ctx->Extensions.EXT_blend_equation_separate = GL_TRUE;
- ctx->Extensions.EXT_blend_func_separate = GL_TRUE;
- ctx->Extensions.EXT_blend_logic_op = GL_TRUE;
- ctx->Extensions.EXT_blend_minmax = GL_TRUE;
- ctx->Extensions.EXT_blend_subtract = GL_TRUE;
- ctx->Extensions.EXT_depth_bounds_test = GL_TRUE;
- ctx->Extensions.EXT_draw_buffers2 = GL_TRUE;
- ctx->Extensions.EXT_fog_coord = GL_TRUE;
-#if FEATURE_EXT_framebuffer_object
- ctx->Extensions.EXT_framebuffer_object = GL_TRUE;
-#endif
-#if FEATURE_EXT_framebuffer_blit
- ctx->Extensions.EXT_framebuffer_blit = GL_TRUE;
-#endif
-#if FEATURE_ARB_framebuffer_object
- ctx->Extensions.EXT_framebuffer_multisample = GL_TRUE;
-#endif
- /*ctx->Extensions.EXT_multi_draw_arrays = GL_TRUE;*/
- ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE;
- ctx->Extensions.EXT_paletted_texture = GL_TRUE;
-#if FEATURE_EXT_pixel_buffer_object
- ctx->Extensions.EXT_pixel_buffer_object = GL_TRUE;
-#endif
- ctx->Extensions.EXT_point_parameters = GL_TRUE;
- ctx->Extensions.EXT_provoking_vertex = GL_TRUE;
- ctx->Extensions.EXT_shadow_funcs = GL_TRUE;
- ctx->Extensions.EXT_secondary_color = GL_TRUE;
- ctx->Extensions.EXT_shared_texture_palette = GL_TRUE;
- ctx->Extensions.EXT_stencil_wrap = GL_TRUE;
- ctx->Extensions.EXT_stencil_two_side = GL_TRUE;
- ctx->Extensions.EXT_texture_array = GL_TRUE;
- ctx->Extensions.EXT_texture_compression_latc = GL_TRUE;
- ctx->Extensions.EXT_texture_env_add = GL_TRUE;
- ctx->Extensions.EXT_texture_env_combine = GL_TRUE;
- ctx->Extensions.EXT_texture_env_dot3 = GL_TRUE;
- ctx->Extensions.EXT_texture_mirror_clamp = GL_TRUE;
- ctx->Extensions.EXT_texture_lod_bias = GL_TRUE;
-#if FEATURE_EXT_texture_sRGB
- ctx->Extensions.EXT_texture_sRGB = GL_TRUE;
- ctx->Extensions.EXT_texture_sRGB_decode = GL_TRUE;
-#endif
- ctx->Extensions.EXT_texture_swizzle = GL_TRUE;
-#if FEATURE_EXT_transform_feedback
- /*ctx->Extensions.EXT_transform_feedback = GL_TRUE;*/
-#endif
- ctx->Extensions.EXT_vertex_array_bgra = GL_TRUE;
- /*ctx->Extensions.IBM_multimode_draw_arrays = GL_TRUE;*/
- ctx->Extensions.MESA_pack_invert = GL_TRUE;
- ctx->Extensions.MESA_resize_buffers = GL_TRUE;
- ctx->Extensions.MESA_texture_array = GL_TRUE;
- ctx->Extensions.MESA_ycbcr_texture = GL_TRUE;
- ctx->Extensions.NV_blend_square = GL_TRUE;
- ctx->Extensions.NV_conditional_render = GL_TRUE;
- /*ctx->Extensions.NV_light_max_exponent = GL_TRUE;*/
- ctx->Extensions.NV_point_sprite = GL_TRUE;
- ctx->Extensions.NV_texture_env_combine4 = GL_TRUE;
- ctx->Extensions.NV_texture_rectangle = GL_TRUE;
- /*ctx->Extensions.NV_texgen_reflection = GL_TRUE;*/
-#if FEATURE_NV_vertex_program
- ctx->Extensions.NV_vertex_program = GL_TRUE;
- ctx->Extensions.NV_vertex_program1_1 = GL_TRUE;
-#endif
-#if FEATURE_NV_fragment_program
- ctx->Extensions.NV_fragment_program = GL_TRUE;
-#endif
-#if FEATURE_NV_fragment_program && FEATURE_ARB_fragment_program
- ctx->Extensions.NV_fragment_program_option = GL_TRUE;
-#endif
- /*ctx->Extensions.SGIS_generate_mipmap = GL_TRUE;*/
- ctx->Extensions.SGIS_texture_edge_clamp = GL_TRUE;
-#if FEATURE_ARB_vertex_program || FEATURE_ARB_fragment_program
- ctx->Extensions.EXT_gpu_program_parameters = GL_TRUE;
-#endif
-#if FEATURE_texture_fxt1
- _mesa_enable_extension(ctx, "GL_3DFX_texture_compression_FXT1");
-#endif
-#if FEATURE_texture_s3tc
- if (ctx->Mesa_DXTn) {
- _mesa_enable_extension(ctx, "GL_EXT_texture_compression_s3tc");
- _mesa_enable_extension(ctx, "GL_S3_s3tc");
- }
-#endif
-}
-
-
-/**
- * Enable common EXT extensions in the ARB_imaging subset.
- */
-void
-_mesa_enable_imaging_extensions(struct gl_context *ctx)
-{
- ctx->Extensions.EXT_blend_color = GL_TRUE;
- ctx->Extensions.EXT_blend_logic_op = GL_TRUE;
- ctx->Extensions.EXT_blend_minmax = GL_TRUE;
- ctx->Extensions.EXT_blend_subtract = GL_TRUE;
-}
-
-
-
-/**
- * Enable all OpenGL 1.3 features and extensions.
- * A convenience function to be called by drivers.
- */
-void
-_mesa_enable_1_3_extensions(struct gl_context *ctx)
-{
- /*ctx->Extensions.ARB_multisample = GL_TRUE;*/
- ctx->Extensions.ARB_multitexture = GL_TRUE;
- ctx->Extensions.ARB_texture_border_clamp = GL_TRUE;
- /*ctx->Extensions.ARB_texture_compression = GL_TRUE;*/
- ctx->Extensions.ARB_texture_cube_map = GL_TRUE;
- ctx->Extensions.ARB_texture_env_combine = GL_TRUE;
- ctx->Extensions.ARB_texture_env_dot3 = GL_TRUE;
- ctx->Extensions.EXT_texture_env_add = GL_TRUE;
- /*ctx->Extensions.ARB_transpose_matrix = GL_TRUE;*/
-}
-
-
-
-/**
- * Enable all OpenGL 1.4 features and extensions.
- * A convenience function to be called by drivers.
- */
-void
-_mesa_enable_1_4_extensions(struct gl_context *ctx)
-{
- ctx->Extensions.ARB_depth_texture = GL_TRUE;
- ctx->Extensions.ARB_shadow = GL_TRUE;
- ctx->Extensions.ARB_texture_env_crossbar = GL_TRUE;
- ctx->Extensions.ARB_texture_mirrored_repeat = GL_TRUE;
- ctx->Extensions.ARB_window_pos = GL_TRUE;
- ctx->Extensions.EXT_blend_color = GL_TRUE;
- ctx->Extensions.EXT_blend_func_separate = GL_TRUE;
- ctx->Extensions.EXT_blend_minmax = GL_TRUE;
- ctx->Extensions.EXT_blend_subtract = GL_TRUE;
- ctx->Extensions.EXT_fog_coord = GL_TRUE;
- /*ctx->Extensions.EXT_multi_draw_arrays = GL_TRUE;*/
- ctx->Extensions.EXT_point_parameters = GL_TRUE;
- ctx->Extensions.EXT_secondary_color = GL_TRUE;
- ctx->Extensions.EXT_stencil_wrap = GL_TRUE;
- ctx->Extensions.EXT_texture_lod_bias = GL_TRUE;
- /*ctx->Extensions.SGIS_generate_mipmap = GL_TRUE;*/
-}
-
-
-/**
- * Enable all OpenGL 1.5 features and extensions.
- * A convenience function to be called by drivers.
- */
-void
-_mesa_enable_1_5_extensions(struct gl_context *ctx)
-{
- ctx->Extensions.ARB_occlusion_query = GL_TRUE;
- /*ctx->Extensions.ARB_vertex_buffer_object = GL_TRUE;*/
- ctx->Extensions.EXT_shadow_funcs = GL_TRUE;
-}
-
-
-/**
- * Enable all OpenGL 2.0 features and extensions.
- * A convenience function to be called by drivers.
- */
-void
-_mesa_enable_2_0_extensions(struct gl_context *ctx)
-{
- /*ctx->Extensions.ARB_draw_buffers = GL_TRUE;*/
-#if FEATURE_ARB_fragment_shader
- ctx->Extensions.ARB_fragment_shader = GL_TRUE;
-#endif
- ctx->Extensions.ARB_point_sprite = GL_TRUE;
- ctx->Extensions.EXT_blend_equation_separate = GL_TRUE;
- ctx->Extensions.ARB_texture_non_power_of_two = GL_TRUE;
-#if FEATURE_ARB_shader_objects
- ctx->Extensions.ARB_shader_objects = GL_TRUE;
-#endif
-#if FEATURE_ARB_shading_language_100
- ctx->Extensions.ARB_shading_language_100 = GL_TRUE;
-#endif
- ctx->Extensions.EXT_stencil_two_side = GL_TRUE;
-#if FEATURE_ARB_vertex_shader
- ctx->Extensions.ARB_vertex_shader = GL_TRUE;
-#endif
-}
-
-
-/**
- * Enable all OpenGL 2.1 features and extensions.
- * A convenience function to be called by drivers.
- */
-void
-_mesa_enable_2_1_extensions(struct gl_context *ctx)
-{
-#if FEATURE_EXT_pixel_buffer_object
- ctx->Extensions.EXT_pixel_buffer_object = GL_TRUE;
-#endif
-#if FEATURE_EXT_texture_sRGB
- ctx->Extensions.EXT_texture_sRGB = GL_TRUE;
-#endif
-}
-
-
-/**
- * Either enable or disable the named extension.
- * \return GL_TRUE for success, GL_FALSE if invalid extension name
- */
-static GLboolean
-set_extension( struct gl_context *ctx, const char *name, GLboolean state )
-{
- size_t offset;
-
- if (ctx->Extensions.String) {
- /* The string was already queried - can't change it now! */
- _mesa_problem(ctx, "Trying to enable/disable extension after glGetString(GL_EXTENSIONS): %s", name);
- return GL_FALSE;
- }
-
- offset = name_to_offset(name);
- if (offset == 0) {
- _mesa_problem(ctx, "Trying to enable/disable unknown extension %s",
- name);
- return GL_FALSE;
- } else if (offset == o(dummy_true) && state == GL_FALSE) {
- _mesa_problem(ctx, "Trying to disable a permanently enabled extension: "
- "%s", name);
- return GL_FALSE;
- } else {
- GLboolean *base = (GLboolean *) &ctx->Extensions;
- base[offset] = state;
- return GL_TRUE;
- }
-}
-
-
-/**
- * Enable the named extension.
- * Typically called by drivers.
- */
-void
-_mesa_enable_extension( struct gl_context *ctx, const char *name )
-{
- if (!set_extension(ctx, name, GL_TRUE))
- _mesa_problem(ctx, "Trying to enable unknown extension: %s", name);
-}
-
-
-/**
- * Disable the named extension.
- * XXX is this really needed???
- */
-void
-_mesa_disable_extension( struct gl_context *ctx, const char *name )
-{
- if (!set_extension(ctx, name, GL_FALSE))
- _mesa_problem(ctx, "Trying to disable unknown extension: %s", name);
-}
-
-
-/**
- * Test if the named extension is enabled in this context.
- */
-GLboolean
-_mesa_extension_is_enabled( struct gl_context *ctx, const char *name )
-{
- size_t offset;
- GLboolean *base;
-
- if (name == 0)
- return GL_FALSE;
-
- offset = name_to_offset(name);
- if (offset == 0)
- return GL_FALSE;
- base = (GLboolean *) &ctx->Extensions;
- return base[offset];
-}
-
-
-/**
- * \brief Apply the \c MESA_EXTENSION_OVERRIDE environment variable.
- *
- * \c MESA_EXTENSION_OVERRIDE is a space-separated list of extensions to
- * enable or disable. The list is processed thus:
- * - Enable recognized extension names that are prefixed with '+'.
- * - Disable recognized extension names that are prefixed with '-'.
- * - Enable recognized extension names that are not prefixed.
- * - Collect unrecognized extension names in a new string.
- *
- * \return Space-separated list of unrecognized extension names (which must
- * be freed). Does not return \c NULL.
- */
-static char *
-get_extension_override( struct gl_context *ctx )
-{
- const char *env_const= _mesa_getenv("MESA_EXTENSION_OVERRIDE");
- char *env;
- char *ext;
- char *extra_exts;
- int len;
-
- if (env_const == NULL) {
- /* Return the empty string rather than NULL. This simplifies the logic
- * of client functions. */
- return calloc(1, sizeof(char));
- }
-
- /* extra_exts: List of unrecognized extensions. */
- extra_exts = calloc(strlen(env_const), sizeof(char));
-
- /* Copy env_const because strtok() is destructive. */
- env = strdup(env_const);
- for (ext = strtok(env, " "); ext != NULL; ext = strtok(NULL, " ")) {
- int enable;
- int recognized;
- switch (ext[0]) {
- case '+':
- enable = 1;
- ++ext;
- break;
- case '-':
- enable = 0;
- ++ext;
- break;
- default:
- enable = 1;
- break;
- }
- recognized = set_extension(ctx, ext, enable);
- if (!recognized) {
- strcat(extra_exts, ext);
- strcat(extra_exts, " ");
- }
- }
-
- /* Remove trailing space. */
- len = strlen(extra_exts);
- if (extra_exts[len - 1] == ' ')
- extra_exts[len - 1] = '\0';
-
- return extra_exts;
-}
-
-
-/**
- * \brief Initialize extension tables and enable default extensions.
- *
- * This should be called during context initialization.
- * Note: Sets gl_extensions.dummy_true to true.
- */
-void
-_mesa_init_extensions( struct gl_context *ctx )
-{
- GLboolean *base = (GLboolean *) &ctx->Extensions;
- GLboolean *sentinel = base + o(extension_sentinel);
- GLboolean *i;
- const size_t *j;
-
- /* First, turn all extensions off. */
- for (i = base; i != sentinel; ++i)
- *i = GL_FALSE;
-
- /* Then, selectively turn default extensions on. */
- ctx->Extensions.dummy_true = GL_TRUE;
- for (j = default_extensions; *j != 0; ++j)
- base[*j] = GL_TRUE;
-}
-
-
-/**
- * Construct the GL_EXTENSIONS string. Called the first time that
- * glGetString(GL_EXTENSIONS) is called.
- */
-GLubyte*
-_mesa_make_extension_string(struct gl_context *ctx)
-{
- /* The extension string. */
- char *exts = 0;
- /* Length of extension string. */
- size_t length = 0;
- /* String of extra extensions. */
- char *extra_extensions = get_extension_override(ctx);
- GLboolean *base = (GLboolean *) &ctx->Extensions;
- const struct extension *i;
-
- /* Compute length of the extension string. */
- for (i = extension_table; i->name != 0; ++i) {
- if (base[i->offset] && (i->api_set & (1 << ctx->API))) {
- length += strlen(i->name) + 1; /* +1 for space */
- }
- }
- if (extra_extensions != NULL)
- length += 1 + strlen(extra_extensions); /* +1 for space */
-
- exts = (char *) calloc(length + 1, sizeof(char));
- if (exts == NULL) {
- free(extra_extensions);
- return NULL;
- }
-
- /* Build the extension string.*/
- for (i = extension_table; i->name != 0; ++i) {
- if (base[i->offset] && (i->api_set & (1 << ctx->API))) {
- strcat(exts, i->name);
- strcat(exts, " ");
- }
- }
- if (extra_extensions != 0) {
- strcat(exts, extra_extensions);
- free(extra_extensions);
- }
-
- return (GLubyte *) exts;
-}
-
-/**
- * Return number of enabled extensions.
- */
-GLuint
-_mesa_get_extension_count(struct gl_context *ctx)
-{
- GLboolean *base;
- const struct extension *i;
-
- /* only count once */
- if (ctx->Extensions.Count != 0)
- return ctx->Extensions.Count;
-
- base = (GLboolean *) &ctx->Extensions;
- for (i = extension_table; i->name != 0; ++i) {
- if (base[i->offset]) {
- ctx->Extensions.Count++;
- }
- }
- return ctx->Extensions.Count;
-}
-
-/**
- * Return name of i-th enabled extension
- */
-const GLubyte *
-_mesa_get_enabled_extension(struct gl_context *ctx, GLuint index)
-{
- const GLboolean *base;
- size_t n;
- const struct extension *i;
-
- if (index < 0)
- return NULL;
-
- base = (GLboolean*) &ctx->Extensions;
- n = 0;
- for (i = extension_table; i->name != 0; ++i) {
- if (n == index && base[i->offset]) {
- return (GLubyte*) i->name;
- } else if (base[i->offset]) {
- ++n;
- }
- }
-
- return NULL;
-}
+/*
+ * 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
+ * \brief Extension handling
+ */
+
+
+#include "glheader.h"
+#include "imports.h"
+#include "context.h"
+#include "extensions.h"
+#include "mfeatures.h"
+#include "mtypes.h"
+
+enum {
+ DISABLE = 0,
+ GL = 1 << API_OPENGL,
+ ES1 = 1 << API_OPENGLES,
+ ES2 = 1 << API_OPENGLES2,
+};
+
+/**
+ * \brief An element of the \c extension_table.
+ */
+struct extension {
+ /** Name of extension, such as "GL_ARB_depth_clamp". */
+ const char *name;
+
+ /** Offset (in bytes) of the corresponding member in struct gl_extensions. */
+ size_t offset;
+
+ /** Set of API's in which the extension exists, as a bitset. */
+ uint8_t api_set;
+
+ /** Year the extension was proposed or approved. Used to sort the
+ * extension string chronologically. */
+ uint16_t year;
+};
+
+
+/**
+ * Given a member \c x of struct gl_extensions, return offset of
+ * \c x in bytes.
+ */
+#define o(x) offsetof(struct gl_extensions, x)
+
+
+/**
+ * \brief Table of supported OpenGL extensions for all API's.
+ *
+ * Note: The GL_MESAX_* extensions are placeholders for future ARB extensions.
+ */
+static const struct extension extension_table[] = {
+ /* ARB Extensions */
+ { "GL_ARB_ES2_compatibility", o(ARB_ES2_compatibility), GL, 2009 },
+ { "GL_ARB_blend_func_extended", o(ARB_blend_func_extended), GL, 2009 },
+ { "GL_ARB_copy_buffer", o(ARB_copy_buffer), GL, 2008 },
+ { "GL_ARB_depth_buffer_float", o(ARB_depth_buffer_float), GL, 2008 },
+ { "GL_ARB_depth_clamp", o(ARB_depth_clamp), GL, 2003 },
+ { "GL_ARB_depth_texture", o(ARB_depth_texture), GL, 2001 },
+ { "GL_ARB_draw_buffers", o(ARB_draw_buffers), GL, 2002 },
+ { "GL_ARB_draw_buffers_blend", o(ARB_draw_buffers_blend), GL, 2009 },
+ { "GL_ARB_draw_elements_base_vertex", o(ARB_draw_elements_base_vertex), GL, 2009 },
+ { "GL_ARB_draw_instanced", o(ARB_draw_instanced), GL, 2008 },
+ { "GL_ARB_explicit_attrib_location", o(ARB_explicit_attrib_location), GL, 2009 },
+ { "GL_ARB_fragment_coord_conventions", o(ARB_fragment_coord_conventions), GL, 2009 },
+ { "GL_ARB_fragment_program", o(ARB_fragment_program), GL, 2002 },
+ { "GL_ARB_fragment_program_shadow", o(ARB_fragment_program_shadow), GL, 2003 },
+ { "GL_ARB_fragment_shader", o(ARB_fragment_shader), GL, 2002 },
+ { "GL_ARB_framebuffer_object", o(ARB_framebuffer_object), GL, 2005 },
+ { "GL_ARB_framebuffer_sRGB", o(EXT_framebuffer_sRGB), GL, 1998 },
+ { "GL_ARB_half_float_pixel", o(ARB_half_float_pixel), GL, 2003 },
+ { "GL_ARB_half_float_vertex", o(ARB_half_float_vertex), GL, 2008 },
+ { "GL_ARB_instanced_arrays", o(ARB_instanced_arrays), GL, 2008 },
+ { "GL_ARB_map_buffer_range", o(ARB_map_buffer_range), GL, 2008 },
+ { "GL_ARB_multisample", o(ARB_multisample), GL, 1994 },
+ { "GL_ARB_multitexture", o(ARB_multitexture), GL, 1998 },
+ { "GL_ARB_occlusion_query2", o(ARB_occlusion_query2), GL, 2003 },
+ { "GL_ARB_occlusion_query", o(ARB_occlusion_query), GL, 2001 },
+ { "GL_ARB_pixel_buffer_object", o(EXT_pixel_buffer_object), GL, 2004 },
+ { "GL_ARB_point_parameters", o(EXT_point_parameters), GL, 1997 },
+ { "GL_ARB_point_sprite", o(ARB_point_sprite), GL, 2003 },
+ { "GL_ARB_provoking_vertex", o(EXT_provoking_vertex), GL, 2009 },
+ { "GL_ARB_sampler_objects", o(ARB_sampler_objects), GL, 2009 },
+ { "GL_ARB_seamless_cube_map", o(ARB_seamless_cube_map), GL, 2009 },
+ { "GL_ARB_shader_objects", o(ARB_shader_objects), GL, 2002 },
+ { "GL_ARB_shader_stencil_export", o(ARB_shader_stencil_export), GL, 2009 },
+ { "GL_ARB_shading_language_100", o(ARB_shading_language_100), GL, 2003 },
+ { "GL_ARB_shadow_ambient", o(ARB_shadow_ambient), GL, 2001 },
+ { "GL_ARB_shadow", o(ARB_shadow), GL, 2001 },
+ { "GL_ARB_sync", o(ARB_sync), GL, 2003 },
+ { "GL_ARB_texture_border_clamp", o(ARB_texture_border_clamp), GL, 2000 },
+ { "GL_ARB_texture_buffer_object", o(ARB_texture_buffer_object), GL, 2008 },
+ { "GL_ARB_texture_compression", o(ARB_texture_compression), GL, 2000 },
+ { "GL_ARB_texture_compression_rgtc", o(ARB_texture_compression_rgtc), GL, 2004 },
+ { "GL_ARB_texture_cube_map", o(ARB_texture_cube_map), GL, 1999 },
+ { "GL_ARB_texture_env_add", o(EXT_texture_env_add), GL, 1999 },
+ { "GL_ARB_texture_env_combine", o(ARB_texture_env_combine), GL, 2001 },
+ { "GL_ARB_texture_env_crossbar", o(ARB_texture_env_crossbar), GL, 2001 },
+ { "GL_ARB_texture_env_dot3", o(ARB_texture_env_dot3), GL, 2001 },
+ { "GL_ARB_texture_mirrored_repeat", o(ARB_texture_mirrored_repeat), GL, 2001 },
+ { "GL_ARB_texture_multisample", o(ARB_texture_multisample), GL, 2009 },
+ { "GL_ARB_texture_non_power_of_two", o(ARB_texture_non_power_of_two), GL, 2003 },
+ { "GL_ARB_texture_rectangle", o(NV_texture_rectangle), GL, 2004 },
+ { "GL_ARB_texture_rgb10_a2ui", o(ARB_texture_rgb10_a2ui), GL, 2009 },
+ { "GL_ARB_texture_rg", o(ARB_texture_rg), GL, 2008 },
+ { "GL_ARB_texture_swizzle", o(EXT_texture_swizzle), GL, 2008 },
+ { "GL_ARB_transform_feedback2", o(ARB_transform_feedback2), GL, 2010 },
+ { "GL_ARB_transpose_matrix", o(ARB_transpose_matrix), GL, 1999 },
+ { "GL_ARB_uniform_buffer_object", o(ARB_uniform_buffer_object), GL, 2002 },
+ { "GL_ARB_vertex_array_bgra", o(EXT_vertex_array_bgra), GL, 2008 },
+ { "GL_ARB_vertex_array_object", o(ARB_vertex_array_object), GL, 2006 },
+ { "GL_ARB_vertex_buffer_object", o(ARB_vertex_buffer_object), GL, 2003 },
+ { "GL_ARB_vertex_program", o(ARB_vertex_program), GL, 2002 },
+ { "GL_ARB_vertex_shader", o(ARB_vertex_shader), GL, 2002 },
+ { "GL_ARB_vertex_type_2_10_10_10_rev", o(ARB_vertex_type_2_10_10_10_rev), GL, 2009 },
+ { "GL_ARB_window_pos", o(ARB_window_pos), GL, 2001 },
+
+ /* EXT extensions */
+ { "GL_EXT_abgr", o(EXT_abgr), GL, 1995 },
+ { "GL_EXT_bgra", o(EXT_bgra), GL, 1995 },
+ { "GL_EXT_blend_color", o(EXT_blend_color), GL, 1995 },
+ { "GL_EXT_blend_equation_separate", o(EXT_blend_equation_separate), GL, 2003 },
+ { "GL_EXT_blend_func_separate", o(EXT_blend_func_separate), GL, 1999 },
+ { "GL_EXT_blend_logic_op", o(EXT_blend_logic_op), GL, 1995 },
+ { "GL_EXT_blend_minmax", o(EXT_blend_minmax), GL | ES1 | ES2, 1995 },
+ { "GL_EXT_blend_subtract", o(EXT_blend_subtract), GL, 1995 },
+ { "GL_EXT_clip_volume_hint", o(EXT_clip_volume_hint), GL, 1996 },
+ { "GL_EXT_compiled_vertex_array", o(EXT_compiled_vertex_array), GL, 1996 },
+ { "GL_EXT_copy_texture", o(EXT_copy_texture), GL, 1995 },
+ { "GL_EXT_depth_bounds_test", o(EXT_depth_bounds_test), GL, 2002 },
+ { "GL_EXT_draw_buffers2", o(EXT_draw_buffers2), GL, 2006 },
+ { "GL_EXT_draw_instanced", o(ARB_draw_instanced), GL, 2006 },
+ { "GL_EXT_draw_range_elements", o(EXT_draw_range_elements), GL, 1997 },
+ { "GL_EXT_fog_coord", o(EXT_fog_coord), GL, 1999 },
+ { "GL_EXT_framebuffer_blit", o(EXT_framebuffer_blit), GL, 2005 },
+ { "GL_EXT_framebuffer_multisample", o(EXT_framebuffer_multisample), GL, 2005 },
+ { "GL_EXT_framebuffer_object", o(EXT_framebuffer_object), GL, 2000 },
+ { "GL_EXT_framebuffer_sRGB", o(EXT_framebuffer_sRGB), GL, 1998 },
+ { "GL_EXT_gpu_program_parameters", o(EXT_gpu_program_parameters), GL, 2006 },
+ { "GL_EXT_gpu_shader4", o(EXT_gpu_shader4), GL, 2006 },
+ { "GL_EXT_multi_draw_arrays", o(EXT_multi_draw_arrays), GL | ES1 | ES2, 1999 },
+ { "GL_EXT_packed_depth_stencil", o(EXT_packed_depth_stencil), GL, 2005 },
+ { "GL_EXT_packed_float", o(EXT_packed_float), GL, 2004 },
+ { "GL_EXT_packed_pixels", o(EXT_packed_pixels), GL, 1997 },
+ { "GL_EXT_paletted_texture", o(EXT_paletted_texture), GL, 1995 },
+ { "GL_EXT_pixel_buffer_object", o(EXT_pixel_buffer_object), GL, 2004 },
+ { "GL_EXT_point_parameters", o(EXT_point_parameters), GL, 1997 },
+ { "GL_EXT_polygon_offset", o(EXT_polygon_offset), GL, 1995 },
+ { "GL_EXT_provoking_vertex", o(EXT_provoking_vertex), GL, 2009 },
+ { "GL_EXT_rescale_normal", o(EXT_rescale_normal), GL, 1997 },
+ { "GL_EXT_secondary_color", o(EXT_secondary_color), GL, 1999 },
+ { "GL_EXT_separate_shader_objects", o(EXT_separate_shader_objects), GL, 2008 },
+ { "GL_EXT_separate_specular_color", o(EXT_separate_specular_color), GL, 1997 },
+ { "GL_EXT_shadow_funcs", o(EXT_shadow_funcs), GL, 2002 },
+ { "GL_EXT_shared_texture_palette", o(EXT_shared_texture_palette), GL, 2000 },
+ { "GL_EXT_stencil_two_side", o(EXT_stencil_two_side), GL, 2001 },
+ { "GL_EXT_stencil_wrap", o(EXT_stencil_wrap), GL, 2002 },
+ { "GL_EXT_subtexture", o(EXT_subtexture), GL, 1995 },
+ { "GL_EXT_texture3D", o(EXT_texture3D), GL, 1996 },
+ { "GL_EXT_texture_array", o(EXT_texture_array), GL, 2006 },
+ { "GL_EXT_texture_compression_dxt1", o(EXT_texture_compression_s3tc), GL | ES1 | ES2, 2004 },
+ { "GL_EXT_texture_compression_latc", o(EXT_texture_compression_latc), GL, 2006 },
+ { "GL_EXT_texture_compression_rgtc", o(ARB_texture_compression_rgtc), GL, 2004 },
+ { "GL_EXT_texture_compression_s3tc", o(EXT_texture_compression_s3tc), GL, 2000 },
+ { "GL_EXT_texture_cube_map", o(ARB_texture_cube_map), GL, 2001 },
+ { "GL_EXT_texture_edge_clamp", o(SGIS_texture_edge_clamp), GL, 1997 },
+ { "GL_EXT_texture_env_add", o(EXT_texture_env_add), GL, 1999 },
+ { "GL_EXT_texture_env_combine", o(EXT_texture_env_combine), GL, 2006 },
+ { "GL_EXT_texture_env_dot3", o(EXT_texture_env_dot3), GL, 2000 },
+ { "GL_EXT_texture_filter_anisotropic", o(EXT_texture_filter_anisotropic), GL | ES1 | ES2, 1999 },
+ { "GL_EXT_texture_format_BGRA8888", o(EXT_texture_format_BGRA8888), ES1 | ES2, 2009 },
+ { "GL_EXT_texture_integer", o(EXT_texture_integer), GL, 2006 },
+ { "GL_EXT_texture_lod_bias", o(EXT_texture_lod_bias), GL | ES1, 1999 },
+ { "GL_EXT_texture_mirror_clamp", o(EXT_texture_mirror_clamp), GL, 2004 },
+ { "GL_EXT_texture_object", o(EXT_texture_object), GL, 1995 },
+ { "GL_EXT_texture", o(EXT_texture), GL, 1996 },
+ { "GL_EXT_texture_rectangle", o(NV_texture_rectangle), GL, 2004 },
+ { "GL_EXT_texture_shared_exponent", o(EXT_texture_shared_exponent), GL, 2004 },
+ { "GL_EXT_texture_sRGB", o(EXT_texture_sRGB), GL, 2004 },
+ { "GL_EXT_texture_sRGB_decode", o(EXT_texture_sRGB_decode), GL, 2006 },
+ { "GL_EXT_texture_swizzle", o(EXT_texture_swizzle), GL, 2008 },
+ { "GL_EXT_texture_type_2_10_10_10_REV", o(dummy_true), ES2, 2008 },
+ { "GL_EXT_timer_query", o(EXT_timer_query), GL, 2006 },
+ { "GL_EXT_transform_feedback", o(EXT_transform_feedback), GL, 2011 },
+ { "GL_EXT_vertex_array_bgra", o(EXT_vertex_array_bgra), GL, 2008 },
+ { "GL_EXT_vertex_array", o(EXT_vertex_array), GL, 1995 },
+ { "GL_EXT_vertex_array_set", o(EXT_vertex_array_set), GL, 1997 },
+
+ /* OES extensions */
+ { "GL_OES_blend_equation_separate", o(EXT_blend_equation_separate), ES1, 2009 },
+ { "GL_OES_blend_func_separate", o(EXT_blend_func_separate), ES1, 2009 },
+ { "GL_OES_blend_subtract", o(EXT_blend_subtract), ES1, 2009 },
+ { "GL_OES_byte_coordinates", o(dummy_true), ES1, 2002 },
+ { "GL_OES_compressed_paletted_texture", o(dummy_false), DISABLE, 2003 },
+ { "GL_OES_depth24", o(EXT_framebuffer_object), ES1 | ES2, 2005 },
+ { "GL_OES_depth32", o(dummy_false), DISABLE, 2005 },
+ { "GL_OES_depth_texture", o(ARB_depth_texture), ES2, 2006 },
+#if FEATURE_OES_draw_texture
+ { "GL_OES_draw_texture", o(OES_draw_texture), ES1 | ES2, 2004 },
+#endif
+#if FEATURE_OES_EGL_image
+ /* FIXME: Mesa expects GL_OES_EGL_image to be available in OpenGL contexts. */
+ { "GL_OES_EGL_image", o(OES_EGL_image), GL | ES1 | ES2, 2006 },
+#endif
+ { "GL_OES_element_index_uint", o(EXT_vertex_array), ES1 | ES2, 2005 },
+ { "GL_OES_fbo_render_mipmap", o(EXT_framebuffer_object), ES1 | ES2, 2005 },
+ { "GL_OES_fixed_point", o(dummy_true), ES1, 2002 },
+ { "GL_OES_framebuffer_object", o(EXT_framebuffer_object), ES1, 2005 },
+ { "GL_OES_mapbuffer", o(ARB_vertex_buffer_object), ES1 | ES2, 2005 },
+ { "GL_OES_matrix_get", o(dummy_true), ES1, 2004 },
+ { "GL_OES_packed_depth_stencil", o(EXT_packed_depth_stencil), ES1 | ES2, 2007 },
+ { "GL_OES_point_size_array", o(dummy_true), ES1, 2004 },
+ { "GL_OES_point_sprite", o(ARB_point_sprite), ES1, 2004 },
+ { "GL_OES_query_matrix", o(dummy_true), ES1, 2003 },
+ { "GL_OES_read_format", o(OES_read_format), GL | ES1, 2003 },
+ { "GL_OES_rgb8_rgba8", o(EXT_framebuffer_object), ES1 | ES2, 2005 },
+ { "GL_OES_single_precision", o(dummy_true), ES1, 2003 },
+ { "GL_OES_standard_derivatives", o(OES_standard_derivatives), ES2, 2005 },
+ { "GL_OES_stencil1", o(dummy_false), DISABLE, 2005 },
+ { "GL_OES_stencil4", o(dummy_false), DISABLE, 2005 },
+ { "GL_OES_stencil8", o(EXT_framebuffer_object), ES1 | ES2, 2005 },
+ { "GL_OES_stencil_wrap", o(EXT_stencil_wrap), ES1, 2002 },
+ { "GL_OES_texture_3D", o(EXT_texture3D), ES2, 2005 },
+ { "GL_OES_texture_cube_map", o(ARB_texture_cube_map), ES1, 2007 },
+ { "GL_OES_texture_env_crossbar", o(ARB_texture_env_crossbar), ES1, 2005 },
+ { "GL_OES_texture_mirrored_repeat", o(ARB_texture_mirrored_repeat), ES1, 2005 },
+ { "GL_OES_texture_npot", o(ARB_texture_non_power_of_two), ES2, 2005 },
+
+ /* Vendor extensions */
+ { "GL_3DFX_texture_compression_FXT1", o(TDFX_texture_compression_FXT1), GL, 1999 },
+ { "GL_AMD_conservative_depth", o(AMD_conservative_depth), GL, 2009 },
+ { "GL_APPLE_client_storage", o(APPLE_client_storage), GL, 2002 },
+ { "GL_APPLE_object_purgeable", o(APPLE_object_purgeable), GL, 2006 },
+ { "GL_APPLE_packed_pixels", o(APPLE_packed_pixels), GL, 2002 },
+ { "GL_APPLE_vertex_array_object", o(APPLE_vertex_array_object), GL, 2002 },
+ { "GL_ATI_blend_equation_separate", o(EXT_blend_equation_separate), GL, 2003 },
+ { "GL_ATI_envmap_bumpmap", o(ATI_envmap_bumpmap), GL, 2001 },
+ { "GL_ATI_fragment_shader", o(ATI_fragment_shader), GL, 2001 },
+ { "GL_ATI_separate_stencil", o(ATI_separate_stencil), GL, 2006 },
+ { "GL_ATI_texture_compression_3dc", o(ATI_texture_compression_3dc), GL, 2004 },
+ { "GL_ATI_texture_env_combine3", o(ATI_texture_env_combine3), GL, 2002 },
+ { "GL_ATI_texture_mirror_once", o(ATI_texture_mirror_once), GL, 2006 },
+ { "GL_IBM_multimode_draw_arrays", o(IBM_multimode_draw_arrays), GL, 1998 },
+ { "GL_IBM_rasterpos_clip", o(IBM_rasterpos_clip), GL, 1996 },
+ { "GL_IBM_texture_mirrored_repeat", o(ARB_texture_mirrored_repeat), GL, 1998 },
+ { "GL_INGR_blend_func_separate", o(EXT_blend_func_separate), GL, 1999 },
+ { "GL_MESA_pack_invert", o(MESA_pack_invert), GL, 2002 },
+ { "GL_MESA_resize_buffers", o(MESA_resize_buffers), GL, 1999 },
+ { "GL_MESA_texture_array", o(MESA_texture_array), GL, 2007 },
+ { "GL_MESA_texture_signed_rgba", o(MESA_texture_signed_rgba), GL, 2009 },
+ { "GL_MESA_window_pos", o(ARB_window_pos), GL, 2000 },
+ { "GL_MESAX_texture_float", o(ARB_texture_float), GL, 2009 },
+ { "GL_MESA_ycbcr_texture", o(MESA_ycbcr_texture), GL, 2002 },
+ { "GL_NV_blend_square", o(NV_blend_square), GL, 1999 },
+ { "GL_NV_conditional_render", o(NV_conditional_render), GL, 2008 },
+ { "GL_NV_depth_clamp", o(ARB_depth_clamp), GL, 2001 },
+ { "GL_NV_fragment_program", o(NV_fragment_program), GL, 2001 },
+ { "GL_NV_fragment_program_option", o(NV_fragment_program_option), GL, 2005 },
+ { "GL_NV_light_max_exponent", o(NV_light_max_exponent), GL, 1999 },
+ { "GL_NV_packed_depth_stencil", o(EXT_packed_depth_stencil), GL, 2000 },
+ { "GL_NV_point_sprite", o(NV_point_sprite), GL, 2001 },
+ { "GL_NV_primitive_restart", o(NV_primitive_restart), GL, 2002 },
+ { "GL_NV_texgen_reflection", o(NV_texgen_reflection), GL, 1999 },
+ { "GL_NV_texture_barrier", o(NV_texture_barrier), GL, 2009 },
+ { "GL_NV_texture_env_combine4", o(NV_texture_env_combine4), GL, 1999 },
+ { "GL_NV_texture_rectangle", o(NV_texture_rectangle), GL, 2000 },
+ { "GL_NV_vertex_program1_1", o(NV_vertex_program1_1), GL, 2001 },
+ { "GL_NV_vertex_program", o(NV_vertex_program), GL, 2000 },
+ { "GL_S3_s3tc", o(S3_s3tc), GL, 1999 },
+ { "GL_SGIS_generate_mipmap", o(SGIS_generate_mipmap), GL, 1997 },
+ { "GL_SGIS_texture_border_clamp", o(ARB_texture_border_clamp), GL, 1997 },
+ { "GL_SGIS_texture_edge_clamp", o(SGIS_texture_edge_clamp), GL, 1997 },
+ { "GL_SGIS_texture_lod", o(SGIS_texture_lod), GL, 1997 },
+ { "GL_SUN_multi_draw_arrays", o(EXT_multi_draw_arrays), GL, 1999 },
+
+ { 0, 0, 0, 0 },
+};
+
+
+/**
+ * Given an extension name, lookup up the corresponding member of struct
+ * gl_extensions and return that member's offset (in bytes). If the name is
+ * not found in the \c extension_table, return 0.
+ *
+ * \param name Name of extension.
+ * \return Offset of member in struct gl_extensions.
+ */
+static size_t
+name_to_offset(const char* name)
+{
+ const struct extension *i;
+
+ if (name == 0)
+ return 0;
+
+ for (i = extension_table; i->name != 0; ++i) {
+ if (strcmp(name, i->name) == 0)
+ return i->offset;
+ }
+
+ return 0;
+}
+
+
+/**
+ * \brief Extensions enabled by default.
+ *
+ * These extensions are enabled by _mesa_init_extensions().
+ *
+ * XXX: Should these defaults also apply to GLES?
+ */
+static const size_t default_extensions[] = {
+ o(ARB_copy_buffer),
+ o(ARB_draw_buffers),
+ o(ARB_multisample),
+ o(ARB_texture_compression),
+ o(ARB_transpose_matrix),
+ o(ARB_vertex_buffer_object),
+ o(ARB_window_pos),
+
+ o(EXT_abgr),
+ o(EXT_bgra),
+ o(EXT_compiled_vertex_array),
+ o(EXT_copy_texture),
+ o(EXT_draw_range_elements),
+ o(EXT_multi_draw_arrays),
+ o(EXT_packed_pixels),
+ o(EXT_polygon_offset),
+ o(EXT_rescale_normal),
+ o(EXT_separate_specular_color),
+ o(EXT_subtexture),
+ o(EXT_texture),
+ o(EXT_texture3D),
+ o(EXT_texture_object),
+ o(EXT_vertex_array),
+
+ o(OES_read_format),
+ o(OES_standard_derivatives),
+
+ /* Vendor Extensions */
+ o(APPLE_packed_pixels),
+ o(IBM_multimode_draw_arrays),
+ o(IBM_rasterpos_clip),
+ o(NV_light_max_exponent),
+ o(NV_texgen_reflection),
+ o(SGIS_generate_mipmap),
+ o(SGIS_texture_edge_clamp),
+ o(SGIS_texture_lod),
+
+ 0,
+};
+
+
+/**
+ * Enable all extensions suitable for a software-only renderer.
+ * This is a convenience function used by the XMesa, OSMesa, GGI drivers, etc.
+ */
+void
+_mesa_enable_sw_extensions(struct gl_context *ctx)
+{
+ /*ctx->Extensions.ARB_copy_buffer = GL_TRUE;*/
+ ctx->Extensions.ARB_depth_clamp = GL_TRUE;
+ ctx->Extensions.ARB_depth_texture = GL_TRUE;
+ /*ctx->Extensions.ARB_draw_buffers = GL_TRUE;*/
+ ctx->Extensions.ARB_draw_elements_base_vertex = GL_TRUE;
+ ctx->Extensions.ARB_draw_instanced = GL_TRUE;
+ ctx->Extensions.ARB_explicit_attrib_location = GL_TRUE;
+ ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE;
+#if FEATURE_ARB_fragment_program
+ ctx->Extensions.ARB_fragment_program = GL_TRUE;
+ ctx->Extensions.ARB_fragment_program_shadow = GL_TRUE;
+#endif
+#if FEATURE_ARB_fragment_shader
+ ctx->Extensions.ARB_fragment_shader = GL_TRUE;
+#endif
+#if FEATURE_ARB_framebuffer_object
+ ctx->Extensions.ARB_framebuffer_object = GL_TRUE;
+#endif
+#if FEATURE_ARB_geometry_shader4 && 0
+ /* XXX re-enable when GLSL compiler again supports geometry shaders */
+ ctx->Extensions.ARB_geometry_shader4 = GL_TRUE;
+#endif
+ ctx->Extensions.ARB_half_float_pixel = GL_TRUE;
+ ctx->Extensions.ARB_half_float_vertex = GL_TRUE;
+ ctx->Extensions.ARB_map_buffer_range = GL_TRUE;
+ ctx->Extensions.ARB_multitexture = GL_TRUE;
+#if FEATURE_queryobj
+ ctx->Extensions.ARB_occlusion_query = GL_TRUE;
+ ctx->Extensions.ARB_occlusion_query2 = GL_TRUE;
+#endif
+ ctx->Extensions.ARB_point_sprite = GL_TRUE;
+#if FEATURE_ARB_shader_objects
+ ctx->Extensions.ARB_shader_objects = GL_TRUE;
+ ctx->Extensions.EXT_separate_shader_objects = GL_TRUE;
+#endif
+#if FEATURE_ARB_shading_language_100
+ ctx->Extensions.ARB_shading_language_100 = GL_TRUE;
+#endif
+ ctx->Extensions.ARB_shadow = GL_TRUE;
+ ctx->Extensions.ARB_shadow_ambient = GL_TRUE;
+ ctx->Extensions.ARB_texture_border_clamp = GL_TRUE;
+ ctx->Extensions.ARB_texture_cube_map = GL_TRUE;
+ ctx->Extensions.ARB_texture_env_combine = GL_TRUE;
+ ctx->Extensions.ARB_texture_env_crossbar = GL_TRUE;
+ ctx->Extensions.ARB_texture_env_dot3 = GL_TRUE;
+ /*ctx->Extensions.ARB_texture_float = GL_TRUE;*/
+ ctx->Extensions.ARB_texture_mirrored_repeat = GL_TRUE;
+ ctx->Extensions.ARB_texture_non_power_of_two = GL_TRUE;
+ ctx->Extensions.ARB_texture_rg = GL_TRUE;
+ ctx->Extensions.ARB_texture_compression_rgtc = GL_TRUE;
+ ctx->Extensions.ARB_vertex_array_object = GL_TRUE;
+#if FEATURE_ARB_vertex_program
+ ctx->Extensions.ARB_vertex_program = GL_TRUE;
+#endif
+#if FEATURE_ARB_vertex_shader
+ ctx->Extensions.ARB_vertex_shader = GL_TRUE;
+#endif
+#if FEATURE_ARB_vertex_buffer_object
+ /*ctx->Extensions.ARB_vertex_buffer_object = GL_TRUE;*/
+#endif
+#if FEATURE_ARB_sync
+ ctx->Extensions.ARB_sync = GL_TRUE;
+#endif
+ ctx->Extensions.APPLE_vertex_array_object = GL_TRUE;
+#if FEATURE_APPLE_object_purgeable
+ ctx->Extensions.APPLE_object_purgeable = GL_TRUE;
+#endif
+ ctx->Extensions.ATI_envmap_bumpmap = GL_TRUE;
+#if FEATURE_ATI_fragment_shader
+ ctx->Extensions.ATI_fragment_shader = GL_TRUE;
+#endif
+ ctx->Extensions.ATI_texture_compression_3dc = GL_TRUE;
+ ctx->Extensions.ATI_texture_env_combine3 = GL_TRUE;
+ ctx->Extensions.ATI_texture_mirror_once = GL_TRUE;
+ ctx->Extensions.ATI_separate_stencil = GL_TRUE;
+ ctx->Extensions.EXT_blend_color = GL_TRUE;
+ ctx->Extensions.EXT_blend_equation_separate = GL_TRUE;
+ ctx->Extensions.EXT_blend_func_separate = GL_TRUE;
+ ctx->Extensions.EXT_blend_logic_op = GL_TRUE;
+ ctx->Extensions.EXT_blend_minmax = GL_TRUE;
+ ctx->Extensions.EXT_blend_subtract = GL_TRUE;
+ ctx->Extensions.EXT_depth_bounds_test = GL_TRUE;
+ ctx->Extensions.EXT_draw_buffers2 = GL_TRUE;
+ ctx->Extensions.EXT_fog_coord = GL_TRUE;
+#if FEATURE_EXT_framebuffer_object
+ ctx->Extensions.EXT_framebuffer_object = GL_TRUE;
+#endif
+#if FEATURE_EXT_framebuffer_blit
+ ctx->Extensions.EXT_framebuffer_blit = GL_TRUE;
+#endif
+#if FEATURE_ARB_framebuffer_object
+ ctx->Extensions.EXT_framebuffer_multisample = GL_TRUE;
+#endif
+ /*ctx->Extensions.EXT_multi_draw_arrays = GL_TRUE;*/
+ ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE;
+ ctx->Extensions.EXT_paletted_texture = GL_TRUE;
+#if FEATURE_EXT_pixel_buffer_object
+ ctx->Extensions.EXT_pixel_buffer_object = GL_TRUE;
+#endif
+ ctx->Extensions.EXT_point_parameters = GL_TRUE;
+ ctx->Extensions.EXT_provoking_vertex = GL_TRUE;
+ ctx->Extensions.EXT_shadow_funcs = GL_TRUE;
+ ctx->Extensions.EXT_secondary_color = GL_TRUE;
+ ctx->Extensions.EXT_shared_texture_palette = GL_TRUE;
+ ctx->Extensions.EXT_stencil_wrap = GL_TRUE;
+ ctx->Extensions.EXT_stencil_two_side = GL_TRUE;
+ ctx->Extensions.EXT_texture_array = GL_TRUE;
+ ctx->Extensions.EXT_texture_compression_latc = GL_TRUE;
+ ctx->Extensions.EXT_texture_env_add = GL_TRUE;
+ ctx->Extensions.EXT_texture_env_combine = GL_TRUE;
+ ctx->Extensions.EXT_texture_env_dot3 = GL_TRUE;
+ ctx->Extensions.EXT_texture_mirror_clamp = GL_TRUE;
+ ctx->Extensions.EXT_texture_lod_bias = GL_TRUE;
+#if FEATURE_EXT_texture_sRGB
+ ctx->Extensions.EXT_texture_sRGB = GL_TRUE;
+ ctx->Extensions.EXT_texture_sRGB_decode = GL_TRUE;
+#endif
+ ctx->Extensions.EXT_texture_swizzle = GL_TRUE;
+#if FEATURE_EXT_transform_feedback
+ /*ctx->Extensions.EXT_transform_feedback = GL_TRUE;*/
+#endif
+ ctx->Extensions.EXT_vertex_array_bgra = GL_TRUE;
+ /*ctx->Extensions.IBM_multimode_draw_arrays = GL_TRUE;*/
+ ctx->Extensions.MESA_pack_invert = GL_TRUE;
+ ctx->Extensions.MESA_resize_buffers = GL_TRUE;
+ ctx->Extensions.MESA_texture_array = GL_TRUE;
+ ctx->Extensions.MESA_ycbcr_texture = GL_TRUE;
+ ctx->Extensions.NV_blend_square = GL_TRUE;
+ ctx->Extensions.NV_conditional_render = GL_TRUE;
+ /*ctx->Extensions.NV_light_max_exponent = GL_TRUE;*/
+ ctx->Extensions.NV_point_sprite = GL_TRUE;
+ ctx->Extensions.NV_texture_env_combine4 = GL_TRUE;
+ ctx->Extensions.NV_texture_rectangle = GL_TRUE;
+ /*ctx->Extensions.NV_texgen_reflection = GL_TRUE;*/
+#if FEATURE_NV_vertex_program
+ ctx->Extensions.NV_vertex_program = GL_TRUE;
+ ctx->Extensions.NV_vertex_program1_1 = GL_TRUE;
+#endif
+#if FEATURE_NV_fragment_program
+ ctx->Extensions.NV_fragment_program = GL_TRUE;
+#endif
+#if FEATURE_NV_fragment_program && FEATURE_ARB_fragment_program
+ ctx->Extensions.NV_fragment_program_option = GL_TRUE;
+#endif
+ /*ctx->Extensions.SGIS_generate_mipmap = GL_TRUE;*/
+ ctx->Extensions.SGIS_texture_edge_clamp = GL_TRUE;
+#if FEATURE_ARB_vertex_program || FEATURE_ARB_fragment_program
+ ctx->Extensions.EXT_gpu_program_parameters = GL_TRUE;
+#endif
+#if FEATURE_texture_fxt1
+ _mesa_enable_extension(ctx, "GL_3DFX_texture_compression_FXT1");
+#endif
+#if FEATURE_texture_s3tc
+ if (ctx->Mesa_DXTn) {
+ _mesa_enable_extension(ctx, "GL_EXT_texture_compression_s3tc");
+ _mesa_enable_extension(ctx, "GL_S3_s3tc");
+ }
+#endif
+}
+
+
+/**
+ * Enable common EXT extensions in the ARB_imaging subset.
+ */
+void
+_mesa_enable_imaging_extensions(struct gl_context *ctx)
+{
+ ctx->Extensions.EXT_blend_color = GL_TRUE;
+ ctx->Extensions.EXT_blend_logic_op = GL_TRUE;
+ ctx->Extensions.EXT_blend_minmax = GL_TRUE;
+ ctx->Extensions.EXT_blend_subtract = GL_TRUE;
+}
+
+
+
+/**
+ * Enable all OpenGL 1.3 features and extensions.
+ * A convenience function to be called by drivers.
+ */
+void
+_mesa_enable_1_3_extensions(struct gl_context *ctx)
+{
+ /*ctx->Extensions.ARB_multisample = GL_TRUE;*/
+ ctx->Extensions.ARB_multitexture = GL_TRUE;
+ ctx->Extensions.ARB_texture_border_clamp = GL_TRUE;
+ /*ctx->Extensions.ARB_texture_compression = GL_TRUE;*/
+ ctx->Extensions.ARB_texture_cube_map = GL_TRUE;
+ ctx->Extensions.ARB_texture_env_combine = GL_TRUE;
+ ctx->Extensions.ARB_texture_env_dot3 = GL_TRUE;
+ ctx->Extensions.EXT_texture_env_add = GL_TRUE;
+ /*ctx->Extensions.ARB_transpose_matrix = GL_TRUE;*/
+}
+
+
+
+/**
+ * Enable all OpenGL 1.4 features and extensions.
+ * A convenience function to be called by drivers.
+ */
+void
+_mesa_enable_1_4_extensions(struct gl_context *ctx)
+{
+ ctx->Extensions.ARB_depth_texture = GL_TRUE;
+ ctx->Extensions.ARB_shadow = GL_TRUE;
+ ctx->Extensions.ARB_texture_env_crossbar = GL_TRUE;
+ ctx->Extensions.ARB_texture_mirrored_repeat = GL_TRUE;
+ ctx->Extensions.ARB_window_pos = GL_TRUE;
+ ctx->Extensions.EXT_blend_color = GL_TRUE;
+ ctx->Extensions.EXT_blend_func_separate = GL_TRUE;
+ ctx->Extensions.EXT_blend_minmax = GL_TRUE;
+ ctx->Extensions.EXT_blend_subtract = GL_TRUE;
+ ctx->Extensions.EXT_fog_coord = GL_TRUE;
+ /*ctx->Extensions.EXT_multi_draw_arrays = GL_TRUE;*/
+ ctx->Extensions.EXT_point_parameters = GL_TRUE;
+ ctx->Extensions.EXT_secondary_color = GL_TRUE;
+ ctx->Extensions.EXT_stencil_wrap = GL_TRUE;
+ ctx->Extensions.EXT_texture_lod_bias = GL_TRUE;
+ /*ctx->Extensions.SGIS_generate_mipmap = GL_TRUE;*/
+}
+
+
+/**
+ * Enable all OpenGL 1.5 features and extensions.
+ * A convenience function to be called by drivers.
+ */
+void
+_mesa_enable_1_5_extensions(struct gl_context *ctx)
+{
+ ctx->Extensions.ARB_occlusion_query = GL_TRUE;
+ /*ctx->Extensions.ARB_vertex_buffer_object = GL_TRUE;*/
+ ctx->Extensions.EXT_shadow_funcs = GL_TRUE;
+}
+
+
+/**
+ * Enable all OpenGL 2.0 features and extensions.
+ * A convenience function to be called by drivers.
+ */
+void
+_mesa_enable_2_0_extensions(struct gl_context *ctx)
+{
+ /*ctx->Extensions.ARB_draw_buffers = GL_TRUE;*/
+#if FEATURE_ARB_fragment_shader
+ ctx->Extensions.ARB_fragment_shader = GL_TRUE;
+#endif
+ ctx->Extensions.ARB_point_sprite = GL_TRUE;
+ ctx->Extensions.EXT_blend_equation_separate = GL_TRUE;
+ ctx->Extensions.ARB_texture_non_power_of_two = GL_TRUE;
+#if FEATURE_ARB_shader_objects
+ ctx->Extensions.ARB_shader_objects = GL_TRUE;
+#endif
+#if FEATURE_ARB_shading_language_100
+ ctx->Extensions.ARB_shading_language_100 = GL_TRUE;
+#endif
+ ctx->Extensions.EXT_stencil_two_side = GL_TRUE;
+#if FEATURE_ARB_vertex_shader
+ ctx->Extensions.ARB_vertex_shader = GL_TRUE;
+#endif
+}
+
+
+/**
+ * Enable all OpenGL 2.1 features and extensions.
+ * A convenience function to be called by drivers.
+ */
+void
+_mesa_enable_2_1_extensions(struct gl_context *ctx)
+{
+#if FEATURE_EXT_pixel_buffer_object
+ ctx->Extensions.EXT_pixel_buffer_object = GL_TRUE;
+#endif
+#if FEATURE_EXT_texture_sRGB
+ ctx->Extensions.EXT_texture_sRGB = GL_TRUE;
+#endif
+}
+
+
+/**
+ * Either enable or disable the named extension.
+ * \return GL_TRUE for success, GL_FALSE if invalid extension name
+ */
+static GLboolean
+set_extension( struct gl_context *ctx, const char *name, GLboolean state )
+{
+ size_t offset;
+
+ if (ctx->Extensions.String) {
+ /* The string was already queried - can't change it now! */
+ _mesa_problem(ctx, "Trying to enable/disable extension after glGetString(GL_EXTENSIONS): %s", name);
+ return GL_FALSE;
+ }
+
+ offset = name_to_offset(name);
+ if (offset == 0) {
+ _mesa_problem(ctx, "Trying to enable/disable unknown extension %s",
+ name);
+ return GL_FALSE;
+ } else if (offset == o(dummy_true) && state == GL_FALSE) {
+ _mesa_problem(ctx, "Trying to disable a permanently enabled extension: "
+ "%s", name);
+ return GL_FALSE;
+ } else {
+ GLboolean *base = (GLboolean *) &ctx->Extensions;
+ base[offset] = state;
+ return GL_TRUE;
+ }
+}
+
+
+/**
+ * Enable the named extension.
+ * Typically called by drivers.
+ */
+void
+_mesa_enable_extension( struct gl_context *ctx, const char *name )
+{
+ if (!set_extension(ctx, name, GL_TRUE))
+ _mesa_problem(ctx, "Trying to enable unknown extension: %s", name);
+}
+
+
+/**
+ * Disable the named extension.
+ * XXX is this really needed???
+ */
+void
+_mesa_disable_extension( struct gl_context *ctx, const char *name )
+{
+ if (!set_extension(ctx, name, GL_FALSE))
+ _mesa_problem(ctx, "Trying to disable unknown extension: %s", name);
+}
+
+
+/**
+ * Test if the named extension is enabled in this context.
+ */
+GLboolean
+_mesa_extension_is_enabled( struct gl_context *ctx, const char *name )
+{
+ size_t offset;
+ GLboolean *base;
+
+ if (name == 0)
+ return GL_FALSE;
+
+ offset = name_to_offset(name);
+ if (offset == 0)
+ return GL_FALSE;
+ base = (GLboolean *) &ctx->Extensions;
+ return base[offset];
+}
+
+
+/**
+ * \brief Apply the \c MESA_EXTENSION_OVERRIDE environment variable.
+ *
+ * \c MESA_EXTENSION_OVERRIDE is a space-separated list of extensions to
+ * enable or disable. The list is processed thus:
+ * - Enable recognized extension names that are prefixed with '+'.
+ * - Disable recognized extension names that are prefixed with '-'.
+ * - Enable recognized extension names that are not prefixed.
+ * - Collect unrecognized extension names in a new string.
+ *
+ * \return Space-separated list of unrecognized extension names (which must
+ * be freed). Does not return \c NULL.
+ */
+static char *
+get_extension_override( struct gl_context *ctx )
+{
+ const char *env_const= _mesa_getenv("MESA_EXTENSION_OVERRIDE");
+ char *env;
+ char *ext;
+ char *extra_exts;
+ int len;
+
+ if (env_const == NULL) {
+ /* Return the empty string rather than NULL. This simplifies the logic
+ * of client functions. */
+ return calloc(1, sizeof(char));
+ }
+
+ /* extra_exts: List of unrecognized extensions. */
+ extra_exts = calloc(strlen(env_const), sizeof(char));
+
+ /* Copy env_const because strtok() is destructive. */
+ env = strdup(env_const);
+ for (ext = strtok(env, " "); ext != NULL; ext = strtok(NULL, " ")) {
+ int enable;
+ int recognized;
+ switch (ext[0]) {
+ case '+':
+ enable = 1;
+ ++ext;
+ break;
+ case '-':
+ enable = 0;
+ ++ext;
+ break;
+ default:
+ enable = 1;
+ break;
+ }
+ recognized = set_extension(ctx, ext, enable);
+ if (!recognized) {
+ strcat(extra_exts, ext);
+ strcat(extra_exts, " ");
+ }
+ }
+
+ /* Remove trailing space. */
+ len = strlen(extra_exts);
+ if (extra_exts[len - 1] == ' ')
+ extra_exts[len - 1] = '\0';
+
+ return extra_exts;
+}
+
+
+/**
+ * \brief Initialize extension tables and enable default extensions.
+ *
+ * This should be called during context initialization.
+ * Note: Sets gl_extensions.dummy_true to true.
+ */
+void
+_mesa_init_extensions( struct gl_context *ctx )
+{
+ GLboolean *base = (GLboolean *) &ctx->Extensions;
+ GLboolean *sentinel = base + o(extension_sentinel);
+ GLboolean *i;
+ const size_t *j;
+
+ /* First, turn all extensions off. */
+ for (i = base; i != sentinel; ++i)
+ *i = GL_FALSE;
+
+ /* Then, selectively turn default extensions on. */
+ ctx->Extensions.dummy_true = GL_TRUE;
+ for (j = default_extensions; *j != 0; ++j)
+ base[*j] = GL_TRUE;
+}
+
+
+typedef unsigned short extension_index;
+
+
+/**
+ * Compare two entries of the extensions table. Sorts first by year,
+ * then by name.
+ *
+ * Arguments are indices into extension_table.
+ */
+static int
+extension_compare(const void *p1, const void *p2)
+{
+ extension_index i1 = * (const extension_index *) p1;
+ extension_index i2 = * (const extension_index *) p2;
+ const struct extension *e1 = &extension_table[i1];
+ const struct extension *e2 = &extension_table[i2];
+ int res;
+
+ res = (int)e1->year - (int)e2->year;
+
+ if (res == 0) {
+ res = strcmp(e1->name, e2->name);
+ }
+
+ return res;
+}
+
+
+/**
+ * Construct the GL_EXTENSIONS string. Called the first time that
+ * glGetString(GL_EXTENSIONS) is called.
+ */
+GLubyte*
+_mesa_make_extension_string(struct gl_context *ctx)
+{
+ /* The extension string. */
+ char *exts = 0;
+ /* Length of extension string. */
+ size_t length = 0;
+ /* Number of extensions */
+ unsigned count;
+ /* Indices of the extensions sorted by year */
+ extension_index *extension_indices;
+ /* String of extra extensions. */
+ char *extra_extensions = get_extension_override(ctx);
+ GLboolean *base = (GLboolean *) &ctx->Extensions;
+ const struct extension *i;
+ unsigned j;
+
+
+ /* Compute length of the extension string. */
+ count = 0;
+ for (i = extension_table; i->name != 0; ++i) {
+ if (base[i->offset] && (i->api_set & (1 << ctx->API))) {
+ length += strlen(i->name) + 1; /* +1 for space */
+ ++count;
+ }
+ }
+ if (extra_extensions != NULL)
+ length += 1 + strlen(extra_extensions); /* +1 for space */
+
+ exts = (char *) calloc(length + 1, sizeof(char));
+ if (exts == NULL) {
+ free(extra_extensions);
+ return NULL;
+ }
+
+ extension_indices = malloc(count * sizeof extension_indices);
+ if (extension_indices == NULL) {
+ free(exts);
+ free(extra_extensions);
+ return NULL;
+ }
+
+ /* Sort extensions in chronological order because certain old applications (e.g.,
+ * Quake3 demo) store the extension list in a static size buffer so chronologically
+ * order ensure that the extensions that such applications expect will fit into
+ * that buffer.
+ */
+ j = 0;
+ for (i = extension_table; i->name != 0; ++i) {
+ if (base[i->offset] && (i->api_set & (1 << ctx->API))) {
+ extension_indices[j++] = i - extension_table;
+ }
+ }
+ assert(j == count);
+ qsort(extension_indices, count, sizeof *extension_indices, extension_compare);
+
+ /* Build the extension string.*/
+ for (j = 0; j < count; ++j) {
+ i = &extension_table[extension_indices[j]];
+ assert(base[i->offset] && (i->api_set & (1 << ctx->API)));
+ strcat(exts, i->name);
+ strcat(exts, " ");
+ }
+ free(extension_indices);
+ if (extra_extensions != 0) {
+ strcat(exts, extra_extensions);
+ free(extra_extensions);
+ }
+
+ return (GLubyte *) exts;
+}
+
+/**
+ * Return number of enabled extensions.
+ */
+GLuint
+_mesa_get_extension_count(struct gl_context *ctx)
+{
+ GLboolean *base;
+ const struct extension *i;
+
+ /* only count once */
+ if (ctx->Extensions.Count != 0)
+ return ctx->Extensions.Count;
+
+ base = (GLboolean *) &ctx->Extensions;
+ for (i = extension_table; i->name != 0; ++i) {
+ if (base[i->offset]) {
+ ctx->Extensions.Count++;
+ }
+ }
+ return ctx->Extensions.Count;
+}
+
+/**
+ * Return name of i-th enabled extension
+ */
+const GLubyte *
+_mesa_get_enabled_extension(struct gl_context *ctx, GLuint index)
+{
+ const GLboolean *base;
+ size_t n;
+ const struct extension *i;
+
+ if (index < 0)
+ return NULL;
+
+ base = (GLboolean*) &ctx->Extensions;
+ n = 0;
+ for (i = extension_table; i->name != 0; ++i) {
+ if (n == index && base[i->offset]) {
+ return (GLubyte*) i->name;
+ } else if (base[i->offset]) {
+ ++n;
+ }
+ }
+
+ return NULL;
+}
diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h
index 51589aaa8..831774fa4 100644
--- a/mesalib/src/mesa/main/mtypes.h
+++ b/mesalib/src/mesa/main/mtypes.h
@@ -1,3362 +1,3362 @@
-/*
- * 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<<MAT_ATTRIB_FRONT_AMBIENT)
-#define MAT_BIT_BACK_AMBIENT (1<<MAT_ATTRIB_BACK_AMBIENT)
-#define MAT_BIT_FRONT_DIFFUSE (1<<MAT_ATTRIB_FRONT_DIFFUSE)
-#define MAT_BIT_BACK_DIFFUSE (1<<MAT_ATTRIB_BACK_DIFFUSE)
-#define MAT_BIT_FRONT_SPECULAR (1<<MAT_ATTRIB_FRONT_SPECULAR)
-#define MAT_BIT_BACK_SPECULAR (1<<MAT_ATTRIB_BACK_SPECULAR)
-#define MAT_BIT_FRONT_EMISSION (1<<MAT_ATTRIB_FRONT_EMISSION)
-#define MAT_BIT_BACK_EMISSION (1<<MAT_ATTRIB_BACK_EMISSION)
-#define MAT_BIT_FRONT_SHININESS (1<<MAT_ATTRIB_FRONT_SHININESS)
-#define MAT_BIT_BACK_SHININESS (1<<MAT_ATTRIB_BACK_SHININESS)
-#define MAT_BIT_FRONT_INDEXES (1<<MAT_ATTRIB_FRONT_INDEXES)
-#define MAT_BIT_BACK_INDEXES (1<<MAT_ATTRIB_BACK_INDEXES)
-
-
-#define FRONT_MATERIAL_BITS (MAT_BIT_FRONT_EMISSION | \
- MAT_BIT_FRONT_AMBIENT | \
- MAT_BIT_FRONT_DIFFUSE | \
- MAT_BIT_FRONT_SPECULAR | \
- MAT_BIT_FRONT_SHININESS | \
- MAT_BIT_FRONT_INDEXES)
-
-#define BACK_MATERIAL_BITS (MAT_BIT_BACK_EMISSION | \
- MAT_BIT_BACK_AMBIENT | \
- MAT_BIT_BACK_DIFFUSE | \
- MAT_BIT_BACK_SPECULAR | \
- MAT_BIT_BACK_SHININESS | \
- MAT_BIT_BACK_INDEXES)
-
-#define ALL_MATERIAL_BITS (FRONT_MATERIAL_BITS | BACK_MATERIAL_BITS)
-/*@}*/
-
-
-#define EXP_TABLE_SIZE 512 /**< Specular exponent lookup table sizes */
-#define SHINE_TABLE_SIZE 256 /**< Material shininess lookup table sizes */
-
-/**
- * Material shininess lookup table.
- */
-struct gl_shine_tab
-{
- struct gl_shine_tab *next, *prev;
- GLfloat tab[SHINE_TABLE_SIZE+1];
- GLfloat shininess;
- GLuint refcount;
-};
-
-
-/**
- * Light source state.
- */
-struct gl_light
-{
- struct gl_light *next; /**< double linked list with sentinel */
- struct gl_light *prev;
-
- GLfloat Ambient[4]; /**< ambient color */
- GLfloat Diffuse[4]; /**< diffuse color */
- GLfloat Specular[4]; /**< specular color */
- GLfloat EyePosition[4]; /**< position in eye coordinates */
- GLfloat SpotDirection[4]; /**< spotlight direction in eye coordinates */
- GLfloat SpotExponent;
- GLfloat SpotCutoff; /**< in degrees */
- GLfloat _CosCutoffNeg; /**< = cos(SpotCutoff) */
- GLfloat _CosCutoff; /**< = MAX(0, cos(SpotCutoff)) */
- GLfloat ConstantAttenuation;
- GLfloat LinearAttenuation;
- GLfloat QuadraticAttenuation;
- GLboolean Enabled; /**< On/off flag */
-
- /**
- * \name Derived fields
- */
- /*@{*/
- GLbitfield _Flags; /**< State */
-
- GLfloat _Position[4]; /**< position in eye/obj coordinates */
- GLfloat _VP_inf_norm[3]; /**< Norm direction to infinite light */
- GLfloat _h_inf_norm[3]; /**< Norm( _VP_inf_norm + <0,0,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 */
-
- GLboolean AttachedAnytime; /**< TRUE if it was attached to a framebuffer */
-
- /* 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, geometry 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 MaxAddressOffset; /**< [-MaxAddressOffset, MaxAddressOffset-1] */
- 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; /**< Usually == MaxParameters * 4 */
- /* 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 MaxGeometryTextureImageUnits;
- 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 */
-
- /** Number of varying vectors between vertex and fragment shaders */
- GLuint MaxVarying;
- GLuint MaxVertexVaryingComponents; /**< Between vert and geom shader */
- GLuint MaxGeometryVaryingComponents; /**< Between geom and frag shader */
-
- /** GL_ARB_geometry_shader4 */
- GLuint MaxGeometryOutputVertices;
- GLuint MaxGeometryTotalOutputComponents;
-
- 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_latc;
- 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_compression_3dc;
- 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_texture_barrier;
- 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 */
+/*
+ * 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) ((GLbitfield64)1 << (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<<MAT_ATTRIB_FRONT_AMBIENT)
+#define MAT_BIT_BACK_AMBIENT (1<<MAT_ATTRIB_BACK_AMBIENT)
+#define MAT_BIT_FRONT_DIFFUSE (1<<MAT_ATTRIB_FRONT_DIFFUSE)
+#define MAT_BIT_BACK_DIFFUSE (1<<MAT_ATTRIB_BACK_DIFFUSE)
+#define MAT_BIT_FRONT_SPECULAR (1<<MAT_ATTRIB_FRONT_SPECULAR)
+#define MAT_BIT_BACK_SPECULAR (1<<MAT_ATTRIB_BACK_SPECULAR)
+#define MAT_BIT_FRONT_EMISSION (1<<MAT_ATTRIB_FRONT_EMISSION)
+#define MAT_BIT_BACK_EMISSION (1<<MAT_ATTRIB_BACK_EMISSION)
+#define MAT_BIT_FRONT_SHININESS (1<<MAT_ATTRIB_FRONT_SHININESS)
+#define MAT_BIT_BACK_SHININESS (1<<MAT_ATTRIB_BACK_SHININESS)
+#define MAT_BIT_FRONT_INDEXES (1<<MAT_ATTRIB_FRONT_INDEXES)
+#define MAT_BIT_BACK_INDEXES (1<<MAT_ATTRIB_BACK_INDEXES)
+
+
+#define FRONT_MATERIAL_BITS (MAT_BIT_FRONT_EMISSION | \
+ MAT_BIT_FRONT_AMBIENT | \
+ MAT_BIT_FRONT_DIFFUSE | \
+ MAT_BIT_FRONT_SPECULAR | \
+ MAT_BIT_FRONT_SHININESS | \
+ MAT_BIT_FRONT_INDEXES)
+
+#define BACK_MATERIAL_BITS (MAT_BIT_BACK_EMISSION | \
+ MAT_BIT_BACK_AMBIENT | \
+ MAT_BIT_BACK_DIFFUSE | \
+ MAT_BIT_BACK_SPECULAR | \
+ MAT_BIT_BACK_SHININESS | \
+ MAT_BIT_BACK_INDEXES)
+
+#define ALL_MATERIAL_BITS (FRONT_MATERIAL_BITS | BACK_MATERIAL_BITS)
+/*@}*/
+
+
+#define EXP_TABLE_SIZE 512 /**< Specular exponent lookup table sizes */
+#define SHINE_TABLE_SIZE 256 /**< Material shininess lookup table sizes */
+
+/**
+ * Material shininess lookup table.
+ */
+struct gl_shine_tab
+{
+ struct gl_shine_tab *next, *prev;
+ GLfloat tab[SHINE_TABLE_SIZE+1];
+ GLfloat shininess;
+ GLuint refcount;
+};
+
+
+/**
+ * Light source state.
+ */
+struct gl_light
+{
+ struct gl_light *next; /**< double linked list with sentinel */
+ struct gl_light *prev;
+
+ GLfloat Ambient[4]; /**< ambient color */
+ GLfloat Diffuse[4]; /**< diffuse color */
+ GLfloat Specular[4]; /**< specular color */
+ GLfloat EyePosition[4]; /**< position in eye coordinates */
+ GLfloat SpotDirection[4]; /**< spotlight direction in eye coordinates */
+ GLfloat SpotExponent;
+ GLfloat SpotCutoff; /**< in degrees */
+ GLfloat _CosCutoffNeg; /**< = cos(SpotCutoff) */
+ GLfloat _CosCutoff; /**< = MAX(0, cos(SpotCutoff)) */
+ GLfloat ConstantAttenuation;
+ GLfloat LinearAttenuation;
+ GLfloat QuadraticAttenuation;
+ GLboolean Enabled; /**< On/off flag */
+
+ /**
+ * \name Derived fields
+ */
+ /*@{*/
+ GLbitfield _Flags; /**< State */
+
+ GLfloat _Position[4]; /**< position in eye/obj coordinates */
+ GLfloat _VP_inf_norm[3]; /**< Norm direction to infinite light */
+ GLfloat _h_inf_norm[3]; /**< Norm( _VP_inf_norm + <0,0,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 */
+
+ GLboolean AttachedAnytime; /**< TRUE if it was attached to a framebuffer */
+
+ /* 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, geometry 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 MaxAddressOffset; /**< [-MaxAddressOffset, MaxAddressOffset-1] */
+ 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; /**< Usually == MaxParameters * 4 */
+ /* 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 MaxGeometryTextureImageUnits;
+ 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 */
+
+ /** Number of varying vectors between vertex and fragment shaders */
+ GLuint MaxVarying;
+ GLuint MaxVertexVaryingComponents; /**< Between vert and geom shader */
+ GLuint MaxGeometryVaryingComponents; /**< Between geom and frag shader */
+
+ /** GL_ARB_geometry_shader4 */
+ GLuint MaxGeometryOutputVertices;
+ GLuint MaxGeometryTotalOutputComponents;
+
+ 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_latc;
+ 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_compression_3dc;
+ 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_texture_barrier;
+ 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/texobj.c b/mesalib/src/mesa/main/texobj.c
index c1fc05c44..c1e3e4dec 100644
--- a/mesalib/src/mesa/main/texobj.c
+++ b/mesalib/src/mesa/main/texobj.c
@@ -1,1265 +1,1267 @@
-/**
- * \file texobj.c
- * Texture object management.
- */
-
-/*
- * 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 "mfeatures.h"
-#include "colortab.h"
-#include "context.h"
-#include "enums.h"
-#include "fbobject.h"
-#include "formats.h"
-#include "hash.h"
-#include "imports.h"
-#include "macros.h"
-#include "teximage.h"
-#include "texobj.h"
-#include "mtypes.h"
-#include "program/prog_instruction.h"
-
-
-
-/**********************************************************************/
-/** \name Internal functions */
-/*@{*/
-
-
-/**
- * Return the gl_texture_object for a given ID.
- */
-struct gl_texture_object *
-_mesa_lookup_texture(struct gl_context *ctx, GLuint id)
-{
- return (struct gl_texture_object *)
- _mesa_HashLookup(ctx->Shared->TexObjects, id);
-}
-
-
-
-/**
- * Allocate and initialize a new texture object. But don't put it into the
- * texture object hash table.
- *
- * Called via ctx->Driver.NewTextureObject, unless overridden by a device
- * driver.
- *
- * \param shared the shared GL state structure to contain the texture object
- * \param name integer name for the texture object
- * \param target either GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D,
- * GL_TEXTURE_CUBE_MAP_ARB or GL_TEXTURE_RECTANGLE_NV. zero is ok for the sake
- * of GenTextures()
- *
- * \return pointer to new texture object.
- */
-struct gl_texture_object *
-_mesa_new_texture_object( struct gl_context *ctx, GLuint name, GLenum target )
-{
- struct gl_texture_object *obj;
- (void) ctx;
- obj = MALLOC_STRUCT(gl_texture_object);
- _mesa_initialize_texture_object(obj, name, target);
- return obj;
-}
-
-
-/**
- * Initialize a new texture object to default values.
- * \param obj the texture object
- * \param name the texture name
- * \param target the texture target
- */
-void
-_mesa_initialize_texture_object( struct gl_texture_object *obj,
- GLuint name, GLenum target )
-{
- ASSERT(target == 0 ||
- target == GL_TEXTURE_1D ||
- target == GL_TEXTURE_2D ||
- target == GL_TEXTURE_3D ||
- target == GL_TEXTURE_CUBE_MAP_ARB ||
- target == GL_TEXTURE_RECTANGLE_NV ||
- target == GL_TEXTURE_1D_ARRAY_EXT ||
- target == GL_TEXTURE_2D_ARRAY_EXT);
-
- memset(obj, 0, sizeof(*obj));
- /* init the non-zero fields */
- _glthread_INIT_MUTEX(obj->Mutex);
- obj->RefCount = 1;
- obj->Name = name;
- obj->Target = target;
- obj->Priority = 1.0F;
- if (target == GL_TEXTURE_RECTANGLE_NV) {
- obj->WrapS = GL_CLAMP_TO_EDGE;
- obj->WrapT = GL_CLAMP_TO_EDGE;
- obj->WrapR = GL_CLAMP_TO_EDGE;
- obj->MinFilter = GL_LINEAR;
- }
- else {
- obj->WrapS = GL_REPEAT;
- obj->WrapT = GL_REPEAT;
- obj->WrapR = GL_REPEAT;
- obj->MinFilter = GL_NEAREST_MIPMAP_LINEAR;
- }
- obj->MagFilter = GL_LINEAR;
- obj->MinLod = -1000.0;
- obj->MaxLod = 1000.0;
- obj->LodBias = 0.0;
- obj->BaseLevel = 0;
- obj->MaxLevel = 1000;
- obj->MaxAnisotropy = 1.0;
- obj->CompareMode = GL_NONE; /* ARB_shadow */
- obj->CompareFunc = GL_LEQUAL; /* ARB_shadow */
- obj->CompareFailValue = 0.0F; /* ARB_shadow_ambient */
- obj->DepthMode = GL_LUMINANCE; /* ARB_depth_texture */
- obj->Swizzle[0] = GL_RED;
- obj->Swizzle[1] = GL_GREEN;
- obj->Swizzle[2] = GL_BLUE;
- obj->Swizzle[3] = GL_ALPHA;
- obj->_Swizzle = SWIZZLE_NOOP;
- obj->sRGBDecode = GL_DECODE_EXT;
-}
-
-
-/**
- * Some texture initialization can't be finished until we know which
- * target it's getting bound to (GL_TEXTURE_1D/2D/etc).
- */
-static void
-finish_texture_init(struct gl_context *ctx, GLenum target,
- struct gl_texture_object *obj)
-{
- assert(obj->Target == 0);
-
- if (target == GL_TEXTURE_RECTANGLE_NV) {
- /* have to init wrap and filter state here - kind of klunky */
- obj->WrapS = GL_CLAMP_TO_EDGE;
- obj->WrapT = GL_CLAMP_TO_EDGE;
- obj->WrapR = GL_CLAMP_TO_EDGE;
- obj->MinFilter = GL_LINEAR;
- if (ctx->Driver.TexParameter) {
- static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE};
- static const GLfloat fparam_filter[1] = {(GLfloat) GL_LINEAR};
- ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_S, fparam_wrap);
- ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_T, fparam_wrap);
- ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_R, fparam_wrap);
- ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_MIN_FILTER, fparam_filter);
- }
- }
-}
-
-
-/**
- * Deallocate a texture object struct. It should have already been
- * removed from the texture object pool.
- * Called via ctx->Driver.DeleteTexture() if not overriden by a driver.
- *
- * \param shared the shared GL state to which the object belongs.
- * \param texObj the texture object to delete.
- */
-void
-_mesa_delete_texture_object(struct gl_context *ctx,
- struct gl_texture_object *texObj)
-{
- GLuint i, face;
-
- /* Set Target to an invalid value. With some assertions elsewhere
- * we can try to detect possible use of deleted textures.
- */
- texObj->Target = 0x99;
-
- _mesa_free_colortable_data(&texObj->Palette);
-
- /* free the texture images */
- for (face = 0; face < 6; face++) {
- for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
- if (texObj->Image[face][i]) {
- _mesa_delete_texture_image( ctx, texObj->Image[face][i] );
- }
- }
- }
-
- /* destroy the mutex -- it may have allocated memory (eg on bsd) */
- _glthread_DESTROY_MUTEX(texObj->Mutex);
-
- /* free this object */
- free(texObj);
-}
-
-
-
-/**
- * Copy texture object state from one texture object to another.
- * Use for glPush/PopAttrib.
- *
- * \param dest destination texture object.
- * \param src source texture object.
- */
-void
-_mesa_copy_texture_object( struct gl_texture_object *dest,
- const struct gl_texture_object *src )
-{
- dest->Target = src->Target;
- dest->Name = src->Name;
- dest->Priority = src->Priority;
- dest->BorderColor.f[0] = src->BorderColor.f[0];
- dest->BorderColor.f[1] = src->BorderColor.f[1];
- dest->BorderColor.f[2] = src->BorderColor.f[2];
- dest->BorderColor.f[3] = src->BorderColor.f[3];
- dest->WrapS = src->WrapS;
- dest->WrapT = src->WrapT;
- dest->WrapR = src->WrapR;
- dest->MinFilter = src->MinFilter;
- dest->MagFilter = src->MagFilter;
- dest->MinLod = src->MinLod;
- dest->MaxLod = src->MaxLod;
- dest->LodBias = src->LodBias;
- dest->BaseLevel = src->BaseLevel;
- dest->MaxLevel = src->MaxLevel;
- dest->MaxAnisotropy = src->MaxAnisotropy;
- dest->CompareMode = src->CompareMode;
- dest->CompareFunc = src->CompareFunc;
- dest->CompareFailValue = src->CompareFailValue;
- dest->DepthMode = src->DepthMode;
- dest->_MaxLevel = src->_MaxLevel;
- dest->_MaxLambda = src->_MaxLambda;
- dest->GenerateMipmap = src->GenerateMipmap;
- dest->Palette = src->Palette;
- dest->_Complete = src->_Complete;
- COPY_4V(dest->Swizzle, src->Swizzle);
- dest->_Swizzle = src->_Swizzle;
-}
-
-
-/**
- * Free all texture images of the given texture object.
- *
- * \param ctx GL context.
- * \param t texture object.
- *
- * \sa _mesa_clear_texture_image().
- */
-void
-_mesa_clear_texture_object(struct gl_context *ctx,
- struct gl_texture_object *texObj)
-{
- GLuint i, j;
-
- if (texObj->Target == 0)
- return;
-
- for (i = 0; i < MAX_FACES; i++) {
- for (j = 0; j < MAX_TEXTURE_LEVELS; j++) {
- struct gl_texture_image *texImage = texObj->Image[i][j];
- if (texImage)
- _mesa_clear_texture_image(ctx, texImage);
- }
- }
-}
-
-
-/**
- * Check if the given texture object is valid by examining its Target field.
- * For debugging only.
- */
-static GLboolean
-valid_texture_object(const struct gl_texture_object *tex)
-{
- switch (tex->Target) {
- case 0:
- case GL_TEXTURE_1D:
- case GL_TEXTURE_2D:
- case GL_TEXTURE_3D:
- case GL_TEXTURE_CUBE_MAP_ARB:
- case GL_TEXTURE_RECTANGLE_NV:
- case GL_TEXTURE_1D_ARRAY_EXT:
- case GL_TEXTURE_2D_ARRAY_EXT:
- return GL_TRUE;
- case 0x99:
- _mesa_problem(NULL, "invalid reference to a deleted texture object");
- return GL_FALSE;
- default:
- _mesa_problem(NULL, "invalid texture object Target 0x%x, Id = %u",
- tex->Target, tex->Name);
- return GL_FALSE;
- }
-}
-
-
-/**
- * Reference (or unreference) a texture object.
- * If '*ptr', decrement *ptr's refcount (and delete if it becomes zero).
- * If 'tex' is non-null, increment its refcount.
- */
-void
-_mesa_reference_texobj(struct gl_texture_object **ptr,
- struct gl_texture_object *tex)
-{
- assert(ptr);
- if (*ptr == tex) {
- /* no change */
- return;
- }
-
- if (*ptr) {
- /* Unreference the old texture */
- GLboolean deleteFlag = GL_FALSE;
- struct gl_texture_object *oldTex = *ptr;
-
- ASSERT(valid_texture_object(oldTex));
- (void) valid_texture_object; /* silence warning in release builds */
-
- _glthread_LOCK_MUTEX(oldTex->Mutex);
- ASSERT(oldTex->RefCount > 0);
- oldTex->RefCount--;
-
- deleteFlag = (oldTex->RefCount == 0);
- _glthread_UNLOCK_MUTEX(oldTex->Mutex);
-
- if (deleteFlag) {
- GET_CURRENT_CONTEXT(ctx);
- if (ctx)
- ctx->Driver.DeleteTexture(ctx, oldTex);
- else
- _mesa_problem(NULL, "Unable to delete texture, no context");
- }
-
- *ptr = NULL;
- }
- assert(!*ptr);
-
- if (tex) {
- /* reference new texture */
- ASSERT(valid_texture_object(tex));
- _glthread_LOCK_MUTEX(tex->Mutex);
- if (tex->RefCount == 0) {
- /* this texture's being deleted (look just above) */
- /* Not sure this can every really happen. Warn if it does. */
- _mesa_problem(NULL, "referencing deleted texture object");
- *ptr = NULL;
- }
- else {
- tex->RefCount++;
- *ptr = tex;
- }
- _glthread_UNLOCK_MUTEX(tex->Mutex);
- }
-}
-
-
-
-/**
- * Mark a texture object as incomplete.
- * \param t texture object
- * \param fmt... string describing why it's incomplete (for debugging).
- */
-static void
-incomplete(struct gl_texture_object *t, const char *fmt, ...)
-{
-#if 0
- va_list args;
- char s[100];
-
- va_start(args, fmt);
- vsnprintf(s, sizeof(s), fmt, args);
- va_end(args);
-
- printf("Texture Obj %d incomplete because: %s\n", t->Name, s);
-#endif
- t->_Complete = GL_FALSE;
-}
-
-
-/**
- * Examine a texture object to determine if it is complete.
- *
- * The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE
- * accordingly.
- *
- * \param ctx GL context.
- * \param t texture object.
- *
- * According to the texture target, verifies that each of the mipmaps is
- * present and has the expected size.
- */
-void
-_mesa_test_texobj_completeness( const struct gl_context *ctx,
- struct gl_texture_object *t )
-{
- const GLint baseLevel = t->BaseLevel;
- GLint maxLog2 = 0, maxLevels = 0;
-
- t->_Complete = GL_TRUE; /* be optimistic */
-
- /* Detect cases where the application set the base level to an invalid
- * value.
- */
- if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) {
- incomplete(t, "base level = %d is invalid", baseLevel);
- return;
- }
-
- /* Always need the base level image */
- if (!t->Image[0][baseLevel]) {
- incomplete(t, "Image[baseLevel=%d] == NULL", baseLevel);
- return;
- }
-
- /* Check width/height/depth for zero */
- if (t->Image[0][baseLevel]->Width == 0 ||
- t->Image[0][baseLevel]->Height == 0 ||
- t->Image[0][baseLevel]->Depth == 0) {
- incomplete(t, "texture width = 0");
- return;
- }
-
- /* Compute _MaxLevel */
- if ((t->Target == GL_TEXTURE_1D) ||
- (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) {
- maxLog2 = t->Image[0][baseLevel]->WidthLog2;
- maxLevels = ctx->Const.MaxTextureLevels;
- }
- else if ((t->Target == GL_TEXTURE_2D) ||
- (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
- maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2,
- t->Image[0][baseLevel]->HeightLog2);
- maxLevels = ctx->Const.MaxTextureLevels;
- }
- else if (t->Target == GL_TEXTURE_3D) {
- GLint max = MAX2(t->Image[0][baseLevel]->WidthLog2,
- t->Image[0][baseLevel]->HeightLog2);
- maxLog2 = MAX2(max, (GLint)(t->Image[0][baseLevel]->DepthLog2));
- maxLevels = ctx->Const.Max3DTextureLevels;
- }
- else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
- maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2,
- t->Image[0][baseLevel]->HeightLog2);
- maxLevels = ctx->Const.MaxCubeTextureLevels;
- }
- else if (t->Target == GL_TEXTURE_RECTANGLE_NV) {
- maxLog2 = 0; /* not applicable */
- maxLevels = 1; /* no mipmapping */
- }
- else {
- _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness");
- return;
- }
-
- ASSERT(maxLevels > 0);
-
- if (t->MaxLevel < t->BaseLevel) {
- incomplete(t, "MAX_LEVEL (%d) < BASE_LEVEL (%d)",
- t->MaxLevel, t->BaseLevel);
- return;
- }
-
- t->_MaxLevel = baseLevel + maxLog2;
- t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel);
- t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1);
-
- /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */
- t->_MaxLambda = (GLfloat) (t->_MaxLevel - t->BaseLevel);
-
- if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
- /* make sure that all six cube map level 0 images are the same size */
- const GLuint w = t->Image[0][baseLevel]->Width2;
- const GLuint h = t->Image[0][baseLevel]->Height2;
- GLuint face;
- for (face = 1; face < 6; face++) {
- if (t->Image[face][baseLevel] == NULL ||
- t->Image[face][baseLevel]->Width2 != w ||
- t->Image[face][baseLevel]->Height2 != h) {
- incomplete(t, "Cube face missing or mismatched size");
- return;
- }
- }
- }
-
- /* extra checking for mipmaps */
- if (t->MinFilter != GL_NEAREST && t->MinFilter != GL_LINEAR) {
- /*
- * Mipmapping: determine if we have a complete set of mipmaps
- */
- GLint i;
- GLint minLevel = baseLevel;
- GLint maxLevel = t->_MaxLevel;
-
- if (minLevel > maxLevel) {
- incomplete(t, "minLevel > maxLevel");
- return;
- }
-
- /* Test dimension-independent attributes */
- for (i = minLevel; i <= maxLevel; i++) {
- if (t->Image[0][i]) {
- if (t->Image[0][i]->TexFormat != t->Image[0][baseLevel]->TexFormat) {
- incomplete(t, "Format[i] != Format[baseLevel]");
- return;
- }
- if (t->Image[0][i]->Border != t->Image[0][baseLevel]->Border) {
- incomplete(t, "Border[i] != Border[baseLevel]");
- return;
- }
- }
- }
-
- /* Test things which depend on number of texture image dimensions */
- if ((t->Target == GL_TEXTURE_1D) ||
- (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) {
- /* Test 1-D mipmaps */
- GLuint width = t->Image[0][baseLevel]->Width2;
- for (i = baseLevel + 1; i < maxLevels; i++) {
- if (width > 1) {
- width /= 2;
- }
- if (i >= minLevel && i <= maxLevel) {
- if (!t->Image[0][i]) {
- incomplete(t, "1D Image[0][i] == NULL");
- return;
- }
- if (t->Image[0][i]->Width2 != width ) {
- incomplete(t, "1D Image[0][i] bad width");
- return;
- }
- }
- if (width == 1) {
- return; /* found smallest needed mipmap, all done! */
- }
- }
- }
- else if ((t->Target == GL_TEXTURE_2D) ||
- (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
- /* Test 2-D mipmaps */
- GLuint width = t->Image[0][baseLevel]->Width2;
- GLuint height = t->Image[0][baseLevel]->Height2;
- for (i = baseLevel + 1; i < maxLevels; i++) {
- if (width > 1) {
- width /= 2;
- }
- if (height > 1) {
- height /= 2;
- }
- if (i >= minLevel && i <= maxLevel) {
- if (!t->Image[0][i]) {
- incomplete(t, "2D Image[0][i] == NULL");
- return;
- }
- if (t->Image[0][i]->Width2 != width) {
- incomplete(t, "2D Image[0][i] bad width");
- return;
- }
- if (t->Image[0][i]->Height2 != height) {
- incomplete(t, "2D Image[0][i] bad height");
- return;
- }
- if (width==1 && height==1) {
- return; /* found smallest needed mipmap, all done! */
- }
- }
- }
- }
- else if (t->Target == GL_TEXTURE_3D) {
- /* Test 3-D mipmaps */
- GLuint width = t->Image[0][baseLevel]->Width2;
- GLuint height = t->Image[0][baseLevel]->Height2;
- GLuint depth = t->Image[0][baseLevel]->Depth2;
- for (i = baseLevel + 1; i < maxLevels; i++) {
- if (width > 1) {
- width /= 2;
- }
- if (height > 1) {
- height /= 2;
- }
- if (depth > 1) {
- depth /= 2;
- }
- if (i >= minLevel && i <= maxLevel) {
- if (!t->Image[0][i]) {
- incomplete(t, "3D Image[0][i] == NULL");
- return;
- }
- if (t->Image[0][i]->_BaseFormat == GL_DEPTH_COMPONENT) {
- incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
- return;
- }
- if (t->Image[0][i]->Width2 != width) {
- incomplete(t, "3D Image[0][i] bad width");
- return;
- }
- if (t->Image[0][i]->Height2 != height) {
- incomplete(t, "3D Image[0][i] bad height");
- return;
- }
- if (t->Image[0][i]->Depth2 != depth) {
- incomplete(t, "3D Image[0][i] bad depth");
- return;
- }
- }
- if (width == 1 && height == 1 && depth == 1) {
- return; /* found smallest needed mipmap, all done! */
- }
- }
- }
- else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
- /* make sure 6 cube faces are consistant */
- GLuint width = t->Image[0][baseLevel]->Width2;
- GLuint height = t->Image[0][baseLevel]->Height2;
- for (i = baseLevel + 1; i < maxLevels; i++) {
- if (width > 1) {
- width /= 2;
- }
- if (height > 1) {
- height /= 2;
- }
- if (i >= minLevel && i <= maxLevel) {
- GLuint face;
- for (face = 0; face < 6; face++) {
- /* check that we have images defined */
- if (!t->Image[face][i]) {
- incomplete(t, "CubeMap Image[n][i] == NULL");
- return;
- }
- /* Don't support GL_DEPTH_COMPONENT for cube maps */
- if (t->Image[face][i]->_BaseFormat == GL_DEPTH_COMPONENT) {
- incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
- return;
- }
- /* check that all six images have same size */
- if (t->Image[face][i]->Width2 != width ||
- t->Image[face][i]->Height2 != height) {
- incomplete(t, "CubeMap Image[n][i] bad size");
- return;
- }
- }
- }
- if (width == 1 && height == 1) {
- return; /* found smallest needed mipmap, all done! */
- }
- }
- }
- else if (t->Target == GL_TEXTURE_RECTANGLE_NV) {
- /* XXX special checking? */
- }
- else {
- /* Target = ??? */
- _mesa_problem(ctx, "Bug in gl_test_texture_object_completeness\n");
- }
- }
-}
-
-
-/**
- * Check if the given cube map texture is "cube complete" as defined in
- * the OpenGL specification.
- */
-GLboolean
-_mesa_cube_complete(const struct gl_texture_object *texObj)
-{
- const GLint baseLevel = texObj->BaseLevel;
- const struct gl_texture_image *img0, *img;
- GLuint face;
-
- if (texObj->Target != GL_TEXTURE_CUBE_MAP)
- return GL_FALSE;
-
- if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS))
- return GL_FALSE;
-
- /* check first face */
- img0 = texObj->Image[0][baseLevel];
- if (!img0 ||
- img0->Width < 1 ||
- img0->Width != img0->Height)
- return GL_FALSE;
-
- /* check remaining faces vs. first face */
- for (face = 1; face < 6; face++) {
- img = texObj->Image[face][baseLevel];
- if (!img ||
- img->Width != img0->Width ||
- img->Height != img0->Height ||
- img->TexFormat != img0->TexFormat)
- return GL_FALSE;
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Mark a texture object dirty. It forces the object to be incomplete
- * and optionally forces the context to re-validate its state.
- *
- * \param ctx GL context.
- * \param texObj texture object.
- * \param invalidate_state also invalidate context state.
- */
-void
-_mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj,
- GLboolean invalidate_state)
-{
- texObj->_Complete = GL_FALSE;
- if (invalidate_state)
- ctx->NewState |= _NEW_TEXTURE;
-}
-
-
-/**
- * Return pointer to a default/fallback texture.
- * The texture is a 2D 8x8 RGBA texture with all texels = (0,0,0,1).
- * That's the value a sampler should get when sampling from an
- * incomplete texture.
- */
-struct gl_texture_object *
-_mesa_get_fallback_texture(struct gl_context *ctx)
-{
- if (!ctx->Shared->FallbackTex) {
- /* create fallback texture now */
- static GLubyte texels[8 * 8][4];
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
- gl_format texFormat;
- GLuint i;
-
- for (i = 0; i < 8 * 8; i++) {
- texels[i][0] =
- texels[i][1] =
- texels[i][2] = 0x0;
- texels[i][3] = 0xff;
- }
-
- /* create texture object */
- texObj = ctx->Driver.NewTextureObject(ctx, 0, GL_TEXTURE_2D);
- assert(texObj->RefCount == 1);
- texObj->MinFilter = GL_NEAREST;
- texObj->MagFilter = GL_NEAREST;
-
- /* create level[0] texture image */
- texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, 0);
-
- texFormat = ctx->Driver.ChooseTextureFormat(ctx, GL_RGBA, GL_RGBA,
- GL_UNSIGNED_BYTE);
-
- /* init the image fields */
- _mesa_init_teximage_fields(ctx, GL_TEXTURE_2D, texImage,
- 8, 8, 1, 0, GL_RGBA, texFormat);
-
- ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
-
- /* set image data */
- ctx->Driver.TexImage2D(ctx, GL_TEXTURE_2D, 0, GL_RGBA,
- 8, 8, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, texels,
- &ctx->DefaultPacking, texObj, texImage);
-
- _mesa_test_texobj_completeness(ctx, texObj);
- assert(texObj->_Complete);
-
- ctx->Shared->FallbackTex = texObj;
- }
- return ctx->Shared->FallbackTex;
-}
-
-
-/*@}*/
-
-
-/***********************************************************************/
-/** \name API functions */
-/*@{*/
-
-
-/**
- * Generate texture names.
- *
- * \param n number of texture names to be generated.
- * \param textures an array in which will hold the generated texture names.
- *
- * \sa glGenTextures().
- *
- * Calls _mesa_HashFindFreeKeyBlock() to find a block of free texture
- * IDs which are stored in \p textures. Corresponding empty texture
- * objects are also generated.
- */
-void GLAPIENTRY
-_mesa_GenTextures( GLsizei n, GLuint *textures )
-{
- GET_CURRENT_CONTEXT(ctx);
- GLuint first;
- GLint i;
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (n < 0) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" );
- return;
- }
-
- if (!textures)
- return;
-
- /*
- * This must be atomic (generation and allocation of texture IDs)
- */
- _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
-
- first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n);
-
- /* Allocate new, empty texture objects */
- for (i = 0; i < n; i++) {
- struct gl_texture_object *texObj;
- GLuint name = first + i;
- GLenum target = 0;
- texObj = (*ctx->Driver.NewTextureObject)( ctx, name, target);
- if (!texObj) {
- _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures");
- return;
- }
-
- /* insert into hash table */
- _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj);
-
- textures[i] = name;
- }
-
- _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
-}
-
-
-/**
- * Check if the given texture object is bound to the current draw or
- * read framebuffer. If so, Unbind it.
- */
-static void
-unbind_texobj_from_fbo(struct gl_context *ctx,
- struct gl_texture_object *texObj)
-{
- const GLuint n = (ctx->DrawBuffer == ctx->ReadBuffer) ? 1 : 2;
- GLuint i;
-
- for (i = 0; i < n; i++) {
- struct gl_framebuffer *fb = (i == 0) ? ctx->DrawBuffer : ctx->ReadBuffer;
- if (fb->Name) {
- GLuint j;
- for (j = 0; j < BUFFER_COUNT; j++) {
- if (fb->Attachment[j].Type == GL_TEXTURE &&
- fb->Attachment[j].Texture == texObj) {
- _mesa_remove_attachment(ctx, fb->Attachment + j);
- }
- }
- }
- }
-}
-
-
-/**
- * Check if the given texture object is bound to any texture image units and
- * unbind it if so (revert to default textures).
- */
-static void
-unbind_texobj_from_texunits(struct gl_context *ctx,
- struct gl_texture_object *texObj)
-{
- GLuint u, tex;
-
- for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) {
- struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
- for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) {
- if (texObj == unit->CurrentTex[tex]) {
- _mesa_reference_texobj(&unit->CurrentTex[tex],
- ctx->Shared->DefaultTex[tex]);
- ASSERT(unit->CurrentTex[tex]);
- break;
- }
- }
- }
-}
-
-
-/**
- * Delete named textures.
- *
- * \param n number of textures to be deleted.
- * \param textures array of texture IDs to be deleted.
- *
- * \sa glDeleteTextures().
- *
- * If we're about to delete a texture that's currently bound to any
- * texture unit, unbind the texture first. Decrement the reference
- * count on the texture object and delete it if it's zero.
- * Recall that texture objects can be shared among several rendering
- * contexts.
- */
-void GLAPIENTRY
-_mesa_DeleteTextures( GLsizei n, const GLuint *textures)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLint i;
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */
-
- if (!textures)
- return;
-
- for (i = 0; i < n; i++) {
- if (textures[i] > 0) {
- struct gl_texture_object *delObj
- = _mesa_lookup_texture(ctx, textures[i]);
-
- if (delObj) {
- _mesa_lock_texture(ctx, delObj);
-
- /* Check if texture is bound to any framebuffer objects.
- * If so, unbind.
- * See section 4.4.2.3 of GL_EXT_framebuffer_object.
- */
- unbind_texobj_from_fbo(ctx, delObj);
-
- /* Check if this texture is currently bound to any texture units.
- * If so, unbind it.
- */
- unbind_texobj_from_texunits(ctx, delObj);
-
- _mesa_unlock_texture(ctx, delObj);
-
- ctx->NewState |= _NEW_TEXTURE;
-
- /* The texture _name_ is now free for re-use.
- * Remove it from the hash table now.
- */
- _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
- _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
- _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
-
- /* Unreference the texobj. If refcount hits zero, the texture
- * will be deleted.
- */
- _mesa_reference_texobj(&delObj, NULL);
- }
- }
- }
-}
-
-
-/**
- * Convert a GL texture target enum such as GL_TEXTURE_2D or GL_TEXTURE_3D
- * into the corresponding Mesa texture target index.
- * Note that proxy targets are not valid here.
- * \return TEXTURE_x_INDEX or -1 if target is invalid
- */
-static GLint
-target_enum_to_index(GLenum target)
-{
- switch (target) {
- case GL_TEXTURE_1D:
- return TEXTURE_1D_INDEX;
- case GL_TEXTURE_2D:
- return TEXTURE_2D_INDEX;
- case GL_TEXTURE_3D:
- return TEXTURE_3D_INDEX;
- case GL_TEXTURE_CUBE_MAP_ARB:
- return TEXTURE_CUBE_INDEX;
- case GL_TEXTURE_RECTANGLE_NV:
- return TEXTURE_RECT_INDEX;
- case GL_TEXTURE_1D_ARRAY_EXT:
- return TEXTURE_1D_ARRAY_INDEX;
- case GL_TEXTURE_2D_ARRAY_EXT:
- return TEXTURE_2D_ARRAY_INDEX;
- default:
- return -1;
- }
-}
-
-
-/**
- * Bind a named texture to a texturing target.
- *
- * \param target texture target.
- * \param texName texture name.
- *
- * \sa glBindTexture().
- *
- * Determines the old texture object bound and returns immediately if rebinding
- * the same texture. Get the current texture which is either a default texture
- * if name is null, a named texture from the hash, or a new texture if the
- * given texture name is new. Increments its reference count, binds it, and
- * calls dd_function_table::BindTexture. Decrements the old texture reference
- * count and deletes it if it reaches zero.
- */
-void GLAPIENTRY
-_mesa_BindTexture( GLenum target, GLuint texName )
-{
- GET_CURRENT_CONTEXT(ctx);
- const GLuint unit = ctx->Texture.CurrentUnit;
- struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
- struct gl_texture_object *newTexObj = NULL, *defaultTexObj = NULL;
- GLint targetIndex;
- GLboolean early_out = GL_FALSE;
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
- _mesa_debug(ctx, "glBindTexture %s %d\n",
- _mesa_lookup_enum_by_nr(target), (GLint) texName);
-
- targetIndex = target_enum_to_index(target);
- if (targetIndex < 0) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)");
- return;
- }
- assert(targetIndex < NUM_TEXTURE_TARGETS);
- defaultTexObj = ctx->Shared->DefaultTex[targetIndex];
-
- /*
- * Get pointer to new texture object (newTexObj)
- */
- if (texName == 0) {
- newTexObj = defaultTexObj;
- }
- else {
- /* non-default texture object */
- newTexObj = _mesa_lookup_texture(ctx, texName);
- if (newTexObj) {
- /* error checking */
- if (newTexObj->Target != 0 && newTexObj->Target != target) {
- /* the named texture object's target doesn't match the given target */
- _mesa_error( ctx, GL_INVALID_OPERATION,
- "glBindTexture(target mismatch)" );
- return;
- }
- if (newTexObj->Target == 0) {
- finish_texture_init(ctx, target, newTexObj);
- }
- }
- else {
- /* if this is a new texture id, allocate a texture object now */
- newTexObj = (*ctx->Driver.NewTextureObject)(ctx, texName, target);
- if (!newTexObj) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture");
- return;
- }
-
- /* and insert it into hash table */
- _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
- _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj);
- _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
- }
- newTexObj->Target = target;
- }
-
- assert(valid_texture_object(newTexObj));
-
- _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
- if ((ctx->Shared->RefCount == 1)
- && (newTexObj == texUnit->CurrentTex[targetIndex])) {
- early_out = GL_TRUE;
- }
- _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
-
- if (early_out) {
- return;
- }
-
- /* flush before changing binding */
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-
- /* Do the actual binding. The refcount on the previously bound
- * texture object will be decremented. It'll be deleted if the
- * count hits zero.
- */
- _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj);
- ASSERT(texUnit->CurrentTex[targetIndex]);
-
- /* Pass BindTexture call to device driver */
- if (ctx->Driver.BindTexture)
- (*ctx->Driver.BindTexture)( ctx, target, newTexObj );
-}
-
-
-/**
- * Set texture priorities.
- *
- * \param n number of textures.
- * \param texName texture names.
- * \param priorities corresponding texture priorities.
- *
- * \sa glPrioritizeTextures().
- *
- * Looks up each texture in the hash, clamps the corresponding priority between
- * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture.
- */
-void GLAPIENTRY
-_mesa_PrioritizeTextures( GLsizei n, const GLuint *texName,
- const GLclampf *priorities )
-{
- GET_CURRENT_CONTEXT(ctx);
- GLint i;
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (n < 0) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" );
- return;
- }
-
- if (!priorities)
- return;
-
- for (i = 0; i < n; i++) {
- if (texName[i] > 0) {
- struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]);
- if (t) {
- t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
- }
- }
- }
-
- ctx->NewState |= _NEW_TEXTURE;
-}
-
-
-
-/**
- * See if textures are loaded in texture memory.
- *
- * \param n number of textures to query.
- * \param texName array with the texture names.
- * \param residences array which will hold the residence status.
- *
- * \return GL_TRUE if all textures are resident and \p residences is left unchanged,
- *
- * \sa glAreTexturesResident().
- *
- * Looks up each texture in the hash and calls
- * dd_function_table::IsTextureResident.
- */
-GLboolean GLAPIENTRY
-_mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
- GLboolean *residences)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLboolean allResident = GL_TRUE;
- GLint i, j;
- ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
-
- if (n < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)");
- return GL_FALSE;
- }
-
- if (!texName || !residences)
- return GL_FALSE;
-
- for (i = 0; i < n; i++) {
- struct gl_texture_object *t;
- if (texName[i] == 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
- return GL_FALSE;
- }
- t = _mesa_lookup_texture(ctx, texName[i]);
- if (!t) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
- return GL_FALSE;
- }
- if (!ctx->Driver.IsTextureResident ||
- ctx->Driver.IsTextureResident(ctx, t)) {
- /* The texture is resident */
- if (!allResident)
- residences[i] = GL_TRUE;
- }
- else {
- /* The texture is not resident */
- if (allResident) {
- allResident = GL_FALSE;
- for (j = 0; j < i; j++)
- residences[j] = GL_TRUE;
- }
- residences[i] = GL_FALSE;
- }
- }
-
- return allResident;
-}
-
-
-/**
- * See if a name corresponds to a texture.
- *
- * \param texture texture name.
- *
- * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE
- * otherwise.
- *
- * \sa glIsTexture().
- *
- * Calls _mesa_HashLookup().
- */
-GLboolean GLAPIENTRY
-_mesa_IsTexture( GLuint texture )
-{
- struct gl_texture_object *t;
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
-
- if (!texture)
- return GL_FALSE;
-
- t = _mesa_lookup_texture(ctx, texture);
-
- /* IsTexture is true only after object has been bound once. */
- return t && t->Target;
-}
-
-
-/**
- * Simplest implementation of texture locking: grab the shared tex
- * mutex. Examine the shared context state timestamp and if there has
- * been a change, set the appropriate bits in ctx->NewState.
- *
- * This is used to deal with synchronizing things when a texture object
- * is used/modified by different contexts (or threads) which are sharing
- * the texture.
- *
- * See also _mesa_lock/unlock_texture() in teximage.h
- */
-void
-_mesa_lock_context_textures( struct gl_context *ctx )
-{
- _glthread_LOCK_MUTEX(ctx->Shared->TexMutex);
-
- if (ctx->Shared->TextureStateStamp != ctx->TextureStateTimestamp) {
- ctx->NewState |= _NEW_TEXTURE;
- ctx->TextureStateTimestamp = ctx->Shared->TextureStateStamp;
- }
-}
-
-
-void
-_mesa_unlock_context_textures( struct gl_context *ctx )
-{
- assert(ctx->Shared->TextureStateStamp == ctx->TextureStateTimestamp);
- _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex);
-}
-
-/*@}*/
+/**
+ * \file texobj.c
+ * Texture object management.
+ */
+
+/*
+ * 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 "mfeatures.h"
+#include "colortab.h"
+#include "context.h"
+#include "enums.h"
+#include "fbobject.h"
+#include "formats.h"
+#include "hash.h"
+#include "imports.h"
+#include "macros.h"
+#include "teximage.h"
+#include "texobj.h"
+#include "texstate.h"
+#include "mtypes.h"
+#include "program/prog_instruction.h"
+
+
+
+/**********************************************************************/
+/** \name Internal functions */
+/*@{*/
+
+
+/**
+ * Return the gl_texture_object for a given ID.
+ */
+struct gl_texture_object *
+_mesa_lookup_texture(struct gl_context *ctx, GLuint id)
+{
+ return (struct gl_texture_object *)
+ _mesa_HashLookup(ctx->Shared->TexObjects, id);
+}
+
+
+
+/**
+ * Allocate and initialize a new texture object. But don't put it into the
+ * texture object hash table.
+ *
+ * Called via ctx->Driver.NewTextureObject, unless overridden by a device
+ * driver.
+ *
+ * \param shared the shared GL state structure to contain the texture object
+ * \param name integer name for the texture object
+ * \param target either GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D,
+ * GL_TEXTURE_CUBE_MAP_ARB or GL_TEXTURE_RECTANGLE_NV. zero is ok for the sake
+ * of GenTextures()
+ *
+ * \return pointer to new texture object.
+ */
+struct gl_texture_object *
+_mesa_new_texture_object( struct gl_context *ctx, GLuint name, GLenum target )
+{
+ struct gl_texture_object *obj;
+ (void) ctx;
+ obj = MALLOC_STRUCT(gl_texture_object);
+ _mesa_initialize_texture_object(obj, name, target);
+ return obj;
+}
+
+
+/**
+ * Initialize a new texture object to default values.
+ * \param obj the texture object
+ * \param name the texture name
+ * \param target the texture target
+ */
+void
+_mesa_initialize_texture_object( struct gl_texture_object *obj,
+ GLuint name, GLenum target )
+{
+ ASSERT(target == 0 ||
+ target == GL_TEXTURE_1D ||
+ target == GL_TEXTURE_2D ||
+ target == GL_TEXTURE_3D ||
+ target == GL_TEXTURE_CUBE_MAP_ARB ||
+ target == GL_TEXTURE_RECTANGLE_NV ||
+ target == GL_TEXTURE_1D_ARRAY_EXT ||
+ target == GL_TEXTURE_2D_ARRAY_EXT);
+
+ memset(obj, 0, sizeof(*obj));
+ /* init the non-zero fields */
+ _glthread_INIT_MUTEX(obj->Mutex);
+ obj->RefCount = 1;
+ obj->Name = name;
+ obj->Target = target;
+ obj->Priority = 1.0F;
+ if (target == GL_TEXTURE_RECTANGLE_NV) {
+ obj->WrapS = GL_CLAMP_TO_EDGE;
+ obj->WrapT = GL_CLAMP_TO_EDGE;
+ obj->WrapR = GL_CLAMP_TO_EDGE;
+ obj->MinFilter = GL_LINEAR;
+ }
+ else {
+ obj->WrapS = GL_REPEAT;
+ obj->WrapT = GL_REPEAT;
+ obj->WrapR = GL_REPEAT;
+ obj->MinFilter = GL_NEAREST_MIPMAP_LINEAR;
+ }
+ obj->MagFilter = GL_LINEAR;
+ obj->MinLod = -1000.0;
+ obj->MaxLod = 1000.0;
+ obj->LodBias = 0.0;
+ obj->BaseLevel = 0;
+ obj->MaxLevel = 1000;
+ obj->MaxAnisotropy = 1.0;
+ obj->CompareMode = GL_NONE; /* ARB_shadow */
+ obj->CompareFunc = GL_LEQUAL; /* ARB_shadow */
+ obj->CompareFailValue = 0.0F; /* ARB_shadow_ambient */
+ obj->DepthMode = GL_LUMINANCE; /* ARB_depth_texture */
+ obj->Swizzle[0] = GL_RED;
+ obj->Swizzle[1] = GL_GREEN;
+ obj->Swizzle[2] = GL_BLUE;
+ obj->Swizzle[3] = GL_ALPHA;
+ obj->_Swizzle = SWIZZLE_NOOP;
+ obj->sRGBDecode = GL_DECODE_EXT;
+}
+
+
+/**
+ * Some texture initialization can't be finished until we know which
+ * target it's getting bound to (GL_TEXTURE_1D/2D/etc).
+ */
+static void
+finish_texture_init(struct gl_context *ctx, GLenum target,
+ struct gl_texture_object *obj)
+{
+ assert(obj->Target == 0);
+
+ if (target == GL_TEXTURE_RECTANGLE_NV) {
+ /* have to init wrap and filter state here - kind of klunky */
+ obj->WrapS = GL_CLAMP_TO_EDGE;
+ obj->WrapT = GL_CLAMP_TO_EDGE;
+ obj->WrapR = GL_CLAMP_TO_EDGE;
+ obj->MinFilter = GL_LINEAR;
+ if (ctx->Driver.TexParameter) {
+ static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE};
+ static const GLfloat fparam_filter[1] = {(GLfloat) GL_LINEAR};
+ ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_S, fparam_wrap);
+ ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_T, fparam_wrap);
+ ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_R, fparam_wrap);
+ ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_MIN_FILTER, fparam_filter);
+ }
+ }
+}
+
+
+/**
+ * Deallocate a texture object struct. It should have already been
+ * removed from the texture object pool.
+ * Called via ctx->Driver.DeleteTexture() if not overriden by a driver.
+ *
+ * \param shared the shared GL state to which the object belongs.
+ * \param texObj the texture object to delete.
+ */
+void
+_mesa_delete_texture_object(struct gl_context *ctx,
+ struct gl_texture_object *texObj)
+{
+ GLuint i, face;
+
+ /* Set Target to an invalid value. With some assertions elsewhere
+ * we can try to detect possible use of deleted textures.
+ */
+ texObj->Target = 0x99;
+
+ _mesa_free_colortable_data(&texObj->Palette);
+
+ /* free the texture images */
+ for (face = 0; face < 6; face++) {
+ for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
+ if (texObj->Image[face][i]) {
+ _mesa_delete_texture_image( ctx, texObj->Image[face][i] );
+ }
+ }
+ }
+
+ /* destroy the mutex -- it may have allocated memory (eg on bsd) */
+ _glthread_DESTROY_MUTEX(texObj->Mutex);
+
+ /* free this object */
+ free(texObj);
+}
+
+
+
+/**
+ * Copy texture object state from one texture object to another.
+ * Use for glPush/PopAttrib.
+ *
+ * \param dest destination texture object.
+ * \param src source texture object.
+ */
+void
+_mesa_copy_texture_object( struct gl_texture_object *dest,
+ const struct gl_texture_object *src )
+{
+ dest->Target = src->Target;
+ dest->Name = src->Name;
+ dest->Priority = src->Priority;
+ dest->BorderColor.f[0] = src->BorderColor.f[0];
+ dest->BorderColor.f[1] = src->BorderColor.f[1];
+ dest->BorderColor.f[2] = src->BorderColor.f[2];
+ dest->BorderColor.f[3] = src->BorderColor.f[3];
+ dest->WrapS = src->WrapS;
+ dest->WrapT = src->WrapT;
+ dest->WrapR = src->WrapR;
+ dest->MinFilter = src->MinFilter;
+ dest->MagFilter = src->MagFilter;
+ dest->MinLod = src->MinLod;
+ dest->MaxLod = src->MaxLod;
+ dest->LodBias = src->LodBias;
+ dest->BaseLevel = src->BaseLevel;
+ dest->MaxLevel = src->MaxLevel;
+ dest->MaxAnisotropy = src->MaxAnisotropy;
+ dest->CompareMode = src->CompareMode;
+ dest->CompareFunc = src->CompareFunc;
+ dest->CompareFailValue = src->CompareFailValue;
+ dest->DepthMode = src->DepthMode;
+ dest->_MaxLevel = src->_MaxLevel;
+ dest->_MaxLambda = src->_MaxLambda;
+ dest->GenerateMipmap = src->GenerateMipmap;
+ dest->Palette = src->Palette;
+ dest->_Complete = src->_Complete;
+ COPY_4V(dest->Swizzle, src->Swizzle);
+ dest->_Swizzle = src->_Swizzle;
+}
+
+
+/**
+ * Free all texture images of the given texture object.
+ *
+ * \param ctx GL context.
+ * \param t texture object.
+ *
+ * \sa _mesa_clear_texture_image().
+ */
+void
+_mesa_clear_texture_object(struct gl_context *ctx,
+ struct gl_texture_object *texObj)
+{
+ GLuint i, j;
+
+ if (texObj->Target == 0)
+ return;
+
+ for (i = 0; i < MAX_FACES; i++) {
+ for (j = 0; j < MAX_TEXTURE_LEVELS; j++) {
+ struct gl_texture_image *texImage = texObj->Image[i][j];
+ if (texImage)
+ _mesa_clear_texture_image(ctx, texImage);
+ }
+ }
+}
+
+
+/**
+ * Check if the given texture object is valid by examining its Target field.
+ * For debugging only.
+ */
+static GLboolean
+valid_texture_object(const struct gl_texture_object *tex)
+{
+ switch (tex->Target) {
+ case 0:
+ case GL_TEXTURE_1D:
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_3D:
+ case GL_TEXTURE_CUBE_MAP_ARB:
+ case GL_TEXTURE_RECTANGLE_NV:
+ case GL_TEXTURE_1D_ARRAY_EXT:
+ case GL_TEXTURE_2D_ARRAY_EXT:
+ return GL_TRUE;
+ case 0x99:
+ _mesa_problem(NULL, "invalid reference to a deleted texture object");
+ return GL_FALSE;
+ default:
+ _mesa_problem(NULL, "invalid texture object Target 0x%x, Id = %u",
+ tex->Target, tex->Name);
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Reference (or unreference) a texture object.
+ * If '*ptr', decrement *ptr's refcount (and delete if it becomes zero).
+ * If 'tex' is non-null, increment its refcount.
+ */
+void
+_mesa_reference_texobj(struct gl_texture_object **ptr,
+ struct gl_texture_object *tex)
+{
+ assert(ptr);
+ if (*ptr == tex) {
+ /* no change */
+ return;
+ }
+
+ if (*ptr) {
+ /* Unreference the old texture */
+ GLboolean deleteFlag = GL_FALSE;
+ struct gl_texture_object *oldTex = *ptr;
+
+ ASSERT(valid_texture_object(oldTex));
+ (void) valid_texture_object; /* silence warning in release builds */
+
+ _glthread_LOCK_MUTEX(oldTex->Mutex);
+ ASSERT(oldTex->RefCount > 0);
+ oldTex->RefCount--;
+
+ deleteFlag = (oldTex->RefCount == 0);
+ _glthread_UNLOCK_MUTEX(oldTex->Mutex);
+
+ if (deleteFlag) {
+ GET_CURRENT_CONTEXT(ctx);
+ if (ctx)
+ ctx->Driver.DeleteTexture(ctx, oldTex);
+ else
+ _mesa_problem(NULL, "Unable to delete texture, no context");
+ }
+
+ *ptr = NULL;
+ }
+ assert(!*ptr);
+
+ if (tex) {
+ /* reference new texture */
+ ASSERT(valid_texture_object(tex));
+ _glthread_LOCK_MUTEX(tex->Mutex);
+ if (tex->RefCount == 0) {
+ /* this texture's being deleted (look just above) */
+ /* Not sure this can every really happen. Warn if it does. */
+ _mesa_problem(NULL, "referencing deleted texture object");
+ *ptr = NULL;
+ }
+ else {
+ tex->RefCount++;
+ *ptr = tex;
+ }
+ _glthread_UNLOCK_MUTEX(tex->Mutex);
+ }
+}
+
+
+
+/**
+ * Mark a texture object as incomplete.
+ * \param t texture object
+ * \param fmt... string describing why it's incomplete (for debugging).
+ */
+static void
+incomplete(struct gl_texture_object *t, const char *fmt, ...)
+{
+#if 0
+ va_list args;
+ char s[100];
+
+ va_start(args, fmt);
+ vsnprintf(s, sizeof(s), fmt, args);
+ va_end(args);
+
+ printf("Texture Obj %d incomplete because: %s\n", t->Name, s);
+#endif
+ t->_Complete = GL_FALSE;
+}
+
+
+/**
+ * Examine a texture object to determine if it is complete.
+ *
+ * The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE
+ * accordingly.
+ *
+ * \param ctx GL context.
+ * \param t texture object.
+ *
+ * According to the texture target, verifies that each of the mipmaps is
+ * present and has the expected size.
+ */
+void
+_mesa_test_texobj_completeness( const struct gl_context *ctx,
+ struct gl_texture_object *t )
+{
+ const GLint baseLevel = t->BaseLevel;
+ GLint maxLog2 = 0, maxLevels = 0;
+
+ t->_Complete = GL_TRUE; /* be optimistic */
+
+ /* Detect cases where the application set the base level to an invalid
+ * value.
+ */
+ if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) {
+ incomplete(t, "base level = %d is invalid", baseLevel);
+ return;
+ }
+
+ /* Always need the base level image */
+ if (!t->Image[0][baseLevel]) {
+ incomplete(t, "Image[baseLevel=%d] == NULL", baseLevel);
+ return;
+ }
+
+ /* Check width/height/depth for zero */
+ if (t->Image[0][baseLevel]->Width == 0 ||
+ t->Image[0][baseLevel]->Height == 0 ||
+ t->Image[0][baseLevel]->Depth == 0) {
+ incomplete(t, "texture width = 0");
+ return;
+ }
+
+ /* Compute _MaxLevel */
+ if ((t->Target == GL_TEXTURE_1D) ||
+ (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) {
+ maxLog2 = t->Image[0][baseLevel]->WidthLog2;
+ maxLevels = ctx->Const.MaxTextureLevels;
+ }
+ else if ((t->Target == GL_TEXTURE_2D) ||
+ (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
+ maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2,
+ t->Image[0][baseLevel]->HeightLog2);
+ maxLevels = ctx->Const.MaxTextureLevels;
+ }
+ else if (t->Target == GL_TEXTURE_3D) {
+ GLint max = MAX2(t->Image[0][baseLevel]->WidthLog2,
+ t->Image[0][baseLevel]->HeightLog2);
+ maxLog2 = MAX2(max, (GLint)(t->Image[0][baseLevel]->DepthLog2));
+ maxLevels = ctx->Const.Max3DTextureLevels;
+ }
+ else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
+ maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2,
+ t->Image[0][baseLevel]->HeightLog2);
+ maxLevels = ctx->Const.MaxCubeTextureLevels;
+ }
+ else if (t->Target == GL_TEXTURE_RECTANGLE_NV) {
+ maxLog2 = 0; /* not applicable */
+ maxLevels = 1; /* no mipmapping */
+ }
+ else {
+ _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness");
+ return;
+ }
+
+ ASSERT(maxLevels > 0);
+
+ if (t->MaxLevel < t->BaseLevel) {
+ incomplete(t, "MAX_LEVEL (%d) < BASE_LEVEL (%d)",
+ t->MaxLevel, t->BaseLevel);
+ return;
+ }
+
+ t->_MaxLevel = baseLevel + maxLog2;
+ t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel);
+ t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1);
+
+ /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */
+ t->_MaxLambda = (GLfloat) (t->_MaxLevel - t->BaseLevel);
+
+ if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
+ /* make sure that all six cube map level 0 images are the same size */
+ const GLuint w = t->Image[0][baseLevel]->Width2;
+ const GLuint h = t->Image[0][baseLevel]->Height2;
+ GLuint face;
+ for (face = 1; face < 6; face++) {
+ if (t->Image[face][baseLevel] == NULL ||
+ t->Image[face][baseLevel]->Width2 != w ||
+ t->Image[face][baseLevel]->Height2 != h) {
+ incomplete(t, "Cube face missing or mismatched size");
+ return;
+ }
+ }
+ }
+
+ /* extra checking for mipmaps */
+ if (t->MinFilter != GL_NEAREST && t->MinFilter != GL_LINEAR) {
+ /*
+ * Mipmapping: determine if we have a complete set of mipmaps
+ */
+ GLint i;
+ GLint minLevel = baseLevel;
+ GLint maxLevel = t->_MaxLevel;
+
+ if (minLevel > maxLevel) {
+ incomplete(t, "minLevel > maxLevel");
+ return;
+ }
+
+ /* Test dimension-independent attributes */
+ for (i = minLevel; i <= maxLevel; i++) {
+ if (t->Image[0][i]) {
+ if (t->Image[0][i]->TexFormat != t->Image[0][baseLevel]->TexFormat) {
+ incomplete(t, "Format[i] != Format[baseLevel]");
+ return;
+ }
+ if (t->Image[0][i]->Border != t->Image[0][baseLevel]->Border) {
+ incomplete(t, "Border[i] != Border[baseLevel]");
+ return;
+ }
+ }
+ }
+
+ /* Test things which depend on number of texture image dimensions */
+ if ((t->Target == GL_TEXTURE_1D) ||
+ (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) {
+ /* Test 1-D mipmaps */
+ GLuint width = t->Image[0][baseLevel]->Width2;
+ for (i = baseLevel + 1; i < maxLevels; i++) {
+ if (width > 1) {
+ width /= 2;
+ }
+ if (i >= minLevel && i <= maxLevel) {
+ if (!t->Image[0][i]) {
+ incomplete(t, "1D Image[0][i] == NULL");
+ return;
+ }
+ if (t->Image[0][i]->Width2 != width ) {
+ incomplete(t, "1D Image[0][i] bad width");
+ return;
+ }
+ }
+ if (width == 1) {
+ return; /* found smallest needed mipmap, all done! */
+ }
+ }
+ }
+ else if ((t->Target == GL_TEXTURE_2D) ||
+ (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
+ /* Test 2-D mipmaps */
+ GLuint width = t->Image[0][baseLevel]->Width2;
+ GLuint height = t->Image[0][baseLevel]->Height2;
+ for (i = baseLevel + 1; i < maxLevels; i++) {
+ if (width > 1) {
+ width /= 2;
+ }
+ if (height > 1) {
+ height /= 2;
+ }
+ if (i >= minLevel && i <= maxLevel) {
+ if (!t->Image[0][i]) {
+ incomplete(t, "2D Image[0][i] == NULL");
+ return;
+ }
+ if (t->Image[0][i]->Width2 != width) {
+ incomplete(t, "2D Image[0][i] bad width");
+ return;
+ }
+ if (t->Image[0][i]->Height2 != height) {
+ incomplete(t, "2D Image[0][i] bad height");
+ return;
+ }
+ if (width==1 && height==1) {
+ return; /* found smallest needed mipmap, all done! */
+ }
+ }
+ }
+ }
+ else if (t->Target == GL_TEXTURE_3D) {
+ /* Test 3-D mipmaps */
+ GLuint width = t->Image[0][baseLevel]->Width2;
+ GLuint height = t->Image[0][baseLevel]->Height2;
+ GLuint depth = t->Image[0][baseLevel]->Depth2;
+ for (i = baseLevel + 1; i < maxLevels; i++) {
+ if (width > 1) {
+ width /= 2;
+ }
+ if (height > 1) {
+ height /= 2;
+ }
+ if (depth > 1) {
+ depth /= 2;
+ }
+ if (i >= minLevel && i <= maxLevel) {
+ if (!t->Image[0][i]) {
+ incomplete(t, "3D Image[0][i] == NULL");
+ return;
+ }
+ if (t->Image[0][i]->_BaseFormat == GL_DEPTH_COMPONENT) {
+ incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
+ return;
+ }
+ if (t->Image[0][i]->Width2 != width) {
+ incomplete(t, "3D Image[0][i] bad width");
+ return;
+ }
+ if (t->Image[0][i]->Height2 != height) {
+ incomplete(t, "3D Image[0][i] bad height");
+ return;
+ }
+ if (t->Image[0][i]->Depth2 != depth) {
+ incomplete(t, "3D Image[0][i] bad depth");
+ return;
+ }
+ }
+ if (width == 1 && height == 1 && depth == 1) {
+ return; /* found smallest needed mipmap, all done! */
+ }
+ }
+ }
+ else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
+ /* make sure 6 cube faces are consistant */
+ GLuint width = t->Image[0][baseLevel]->Width2;
+ GLuint height = t->Image[0][baseLevel]->Height2;
+ for (i = baseLevel + 1; i < maxLevels; i++) {
+ if (width > 1) {
+ width /= 2;
+ }
+ if (height > 1) {
+ height /= 2;
+ }
+ if (i >= minLevel && i <= maxLevel) {
+ GLuint face;
+ for (face = 0; face < 6; face++) {
+ /* check that we have images defined */
+ if (!t->Image[face][i]) {
+ incomplete(t, "CubeMap Image[n][i] == NULL");
+ return;
+ }
+ /* Don't support GL_DEPTH_COMPONENT for cube maps */
+ if (t->Image[face][i]->_BaseFormat == GL_DEPTH_COMPONENT) {
+ incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
+ return;
+ }
+ /* check that all six images have same size */
+ if (t->Image[face][i]->Width2 != width ||
+ t->Image[face][i]->Height2 != height) {
+ incomplete(t, "CubeMap Image[n][i] bad size");
+ return;
+ }
+ }
+ }
+ if (width == 1 && height == 1) {
+ return; /* found smallest needed mipmap, all done! */
+ }
+ }
+ }
+ else if (t->Target == GL_TEXTURE_RECTANGLE_NV) {
+ /* XXX special checking? */
+ }
+ else {
+ /* Target = ??? */
+ _mesa_problem(ctx, "Bug in gl_test_texture_object_completeness\n");
+ }
+ }
+}
+
+
+/**
+ * Check if the given cube map texture is "cube complete" as defined in
+ * the OpenGL specification.
+ */
+GLboolean
+_mesa_cube_complete(const struct gl_texture_object *texObj)
+{
+ const GLint baseLevel = texObj->BaseLevel;
+ const struct gl_texture_image *img0, *img;
+ GLuint face;
+
+ if (texObj->Target != GL_TEXTURE_CUBE_MAP)
+ return GL_FALSE;
+
+ if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS))
+ return GL_FALSE;
+
+ /* check first face */
+ img0 = texObj->Image[0][baseLevel];
+ if (!img0 ||
+ img0->Width < 1 ||
+ img0->Width != img0->Height)
+ return GL_FALSE;
+
+ /* check remaining faces vs. first face */
+ for (face = 1; face < 6; face++) {
+ img = texObj->Image[face][baseLevel];
+ if (!img ||
+ img->Width != img0->Width ||
+ img->Height != img0->Height ||
+ img->TexFormat != img0->TexFormat)
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Mark a texture object dirty. It forces the object to be incomplete
+ * and optionally forces the context to re-validate its state.
+ *
+ * \param ctx GL context.
+ * \param texObj texture object.
+ * \param invalidate_state also invalidate context state.
+ */
+void
+_mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj,
+ GLboolean invalidate_state)
+{
+ texObj->_Complete = GL_FALSE;
+ if (invalidate_state)
+ ctx->NewState |= _NEW_TEXTURE;
+}
+
+
+/**
+ * Return pointer to a default/fallback texture.
+ * The texture is a 2D 8x8 RGBA texture with all texels = (0,0,0,1).
+ * That's the value a sampler should get when sampling from an
+ * incomplete texture.
+ */
+struct gl_texture_object *
+_mesa_get_fallback_texture(struct gl_context *ctx)
+{
+ if (!ctx->Shared->FallbackTex) {
+ /* create fallback texture now */
+ static GLubyte texels[8 * 8][4];
+ struct gl_texture_object *texObj;
+ struct gl_texture_image *texImage;
+ gl_format texFormat;
+ GLuint i;
+
+ for (i = 0; i < 8 * 8; i++) {
+ texels[i][0] =
+ texels[i][1] =
+ texels[i][2] = 0x0;
+ texels[i][3] = 0xff;
+ }
+
+ /* create texture object */
+ texObj = ctx->Driver.NewTextureObject(ctx, 0, GL_TEXTURE_2D);
+ assert(texObj->RefCount == 1);
+ texObj->MinFilter = GL_NEAREST;
+ texObj->MagFilter = GL_NEAREST;
+
+ /* create level[0] texture image */
+ texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, 0);
+
+ texFormat = ctx->Driver.ChooseTextureFormat(ctx, GL_RGBA, GL_RGBA,
+ GL_UNSIGNED_BYTE);
+
+ /* init the image fields */
+ _mesa_init_teximage_fields(ctx, GL_TEXTURE_2D, texImage,
+ 8, 8, 1, 0, GL_RGBA, texFormat);
+
+ ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
+ /* set image data */
+ ctx->Driver.TexImage2D(ctx, GL_TEXTURE_2D, 0, GL_RGBA,
+ 8, 8, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, texels,
+ &ctx->DefaultPacking, texObj, texImage);
+
+ _mesa_test_texobj_completeness(ctx, texObj);
+ assert(texObj->_Complete);
+
+ ctx->Shared->FallbackTex = texObj;
+ }
+ return ctx->Shared->FallbackTex;
+}
+
+
+/*@}*/
+
+
+/***********************************************************************/
+/** \name API functions */
+/*@{*/
+
+
+/**
+ * Generate texture names.
+ *
+ * \param n number of texture names to be generated.
+ * \param textures an array in which will hold the generated texture names.
+ *
+ * \sa glGenTextures().
+ *
+ * Calls _mesa_HashFindFreeKeyBlock() to find a block of free texture
+ * IDs which are stored in \p textures. Corresponding empty texture
+ * objects are also generated.
+ */
+void GLAPIENTRY
+_mesa_GenTextures( GLsizei n, GLuint *textures )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLuint first;
+ GLint i;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (n < 0) {
+ _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" );
+ return;
+ }
+
+ if (!textures)
+ return;
+
+ /*
+ * This must be atomic (generation and allocation of texture IDs)
+ */
+ _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+
+ first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n);
+
+ /* Allocate new, empty texture objects */
+ for (i = 0; i < n; i++) {
+ struct gl_texture_object *texObj;
+ GLuint name = first + i;
+ GLenum target = 0;
+ texObj = (*ctx->Driver.NewTextureObject)( ctx, name, target);
+ if (!texObj) {
+ _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures");
+ return;
+ }
+
+ /* insert into hash table */
+ _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj);
+
+ textures[i] = name;
+ }
+
+ _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+}
+
+
+/**
+ * Check if the given texture object is bound to the current draw or
+ * read framebuffer. If so, Unbind it.
+ */
+static void
+unbind_texobj_from_fbo(struct gl_context *ctx,
+ struct gl_texture_object *texObj)
+{
+ const GLuint n = (ctx->DrawBuffer == ctx->ReadBuffer) ? 1 : 2;
+ GLuint i;
+
+ for (i = 0; i < n; i++) {
+ struct gl_framebuffer *fb = (i == 0) ? ctx->DrawBuffer : ctx->ReadBuffer;
+ if (fb->Name) {
+ GLuint j;
+ for (j = 0; j < BUFFER_COUNT; j++) {
+ if (fb->Attachment[j].Type == GL_TEXTURE &&
+ fb->Attachment[j].Texture == texObj) {
+ _mesa_remove_attachment(ctx, fb->Attachment + j);
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * Check if the given texture object is bound to any texture image units and
+ * unbind it if so (revert to default textures).
+ */
+static void
+unbind_texobj_from_texunits(struct gl_context *ctx,
+ struct gl_texture_object *texObj)
+{
+ GLuint u, tex;
+
+ for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) {
+ struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
+ for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) {
+ if (texObj == unit->CurrentTex[tex]) {
+ _mesa_reference_texobj(&unit->CurrentTex[tex],
+ ctx->Shared->DefaultTex[tex]);
+ ASSERT(unit->CurrentTex[tex]);
+ break;
+ }
+ }
+ }
+}
+
+
+/**
+ * Delete named textures.
+ *
+ * \param n number of textures to be deleted.
+ * \param textures array of texture IDs to be deleted.
+ *
+ * \sa glDeleteTextures().
+ *
+ * If we're about to delete a texture that's currently bound to any
+ * texture unit, unbind the texture first. Decrement the reference
+ * count on the texture object and delete it if it's zero.
+ * Recall that texture objects can be shared among several rendering
+ * contexts.
+ */
+void GLAPIENTRY
+_mesa_DeleteTextures( GLsizei n, const GLuint *textures)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i;
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */
+
+ if (!textures)
+ return;
+
+ for (i = 0; i < n; i++) {
+ if (textures[i] > 0) {
+ struct gl_texture_object *delObj
+ = _mesa_lookup_texture(ctx, textures[i]);
+
+ if (delObj) {
+ _mesa_lock_texture(ctx, delObj);
+
+ /* Check if texture is bound to any framebuffer objects.
+ * If so, unbind.
+ * See section 4.4.2.3 of GL_EXT_framebuffer_object.
+ */
+ unbind_texobj_from_fbo(ctx, delObj);
+
+ /* Check if this texture is currently bound to any texture units.
+ * If so, unbind it.
+ */
+ unbind_texobj_from_texunits(ctx, delObj);
+
+ _mesa_unlock_texture(ctx, delObj);
+
+ ctx->NewState |= _NEW_TEXTURE;
+
+ /* The texture _name_ is now free for re-use.
+ * Remove it from the hash table now.
+ */
+ _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+ _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
+ _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+
+ /* Unreference the texobj. If refcount hits zero, the texture
+ * will be deleted.
+ */
+ _mesa_reference_texobj(&delObj, NULL);
+ }
+ }
+ }
+}
+
+
+/**
+ * Convert a GL texture target enum such as GL_TEXTURE_2D or GL_TEXTURE_3D
+ * into the corresponding Mesa texture target index.
+ * Note that proxy targets are not valid here.
+ * \return TEXTURE_x_INDEX or -1 if target is invalid
+ */
+static GLint
+target_enum_to_index(GLenum target)
+{
+ switch (target) {
+ case GL_TEXTURE_1D:
+ return TEXTURE_1D_INDEX;
+ case GL_TEXTURE_2D:
+ return TEXTURE_2D_INDEX;
+ case GL_TEXTURE_3D:
+ return TEXTURE_3D_INDEX;
+ case GL_TEXTURE_CUBE_MAP_ARB:
+ return TEXTURE_CUBE_INDEX;
+ case GL_TEXTURE_RECTANGLE_NV:
+ return TEXTURE_RECT_INDEX;
+ case GL_TEXTURE_1D_ARRAY_EXT:
+ return TEXTURE_1D_ARRAY_INDEX;
+ case GL_TEXTURE_2D_ARRAY_EXT:
+ return TEXTURE_2D_ARRAY_INDEX;
+ default:
+ return -1;
+ }
+}
+
+
+/**
+ * Bind a named texture to a texturing target.
+ *
+ * \param target texture target.
+ * \param texName texture name.
+ *
+ * \sa glBindTexture().
+ *
+ * Determines the old texture object bound and returns immediately if rebinding
+ * the same texture. Get the current texture which is either a default texture
+ * if name is null, a named texture from the hash, or a new texture if the
+ * given texture name is new. Increments its reference count, binds it, and
+ * calls dd_function_table::BindTexture. Decrements the old texture reference
+ * count and deletes it if it reaches zero.
+ */
+void GLAPIENTRY
+_mesa_BindTexture( GLenum target, GLuint texName )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
+ struct gl_texture_object *newTexObj = NULL;
+ GLint targetIndex;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+ _mesa_debug(ctx, "glBindTexture %s %d\n",
+ _mesa_lookup_enum_by_nr(target), (GLint) texName);
+
+ targetIndex = target_enum_to_index(target);
+ if (targetIndex < 0) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)");
+ return;
+ }
+ assert(targetIndex < NUM_TEXTURE_TARGETS);
+
+ /*
+ * Get pointer to new texture object (newTexObj)
+ */
+ if (texName == 0) {
+ /* Use a default texture object */
+ newTexObj = ctx->Shared->DefaultTex[targetIndex];
+ }
+ else {
+ /* non-default texture object */
+ newTexObj = _mesa_lookup_texture(ctx, texName);
+ if (newTexObj) {
+ /* error checking */
+ if (newTexObj->Target != 0 && newTexObj->Target != target) {
+ /* the named texture object's target doesn't match the given target */
+ _mesa_error( ctx, GL_INVALID_OPERATION,
+ "glBindTexture(target mismatch)" );
+ return;
+ }
+ if (newTexObj->Target == 0) {
+ finish_texture_init(ctx, target, newTexObj);
+ }
+ }
+ else {
+ /* if this is a new texture id, allocate a texture object now */
+ newTexObj = (*ctx->Driver.NewTextureObject)(ctx, texName, target);
+ if (!newTexObj) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture");
+ return;
+ }
+
+ /* and insert it into hash table */
+ _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+ _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj);
+ _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+ }
+ newTexObj->Target = target;
+ }
+
+ assert(valid_texture_object(newTexObj));
+
+ /* Check if this texture is only used by this context and is already bound.
+ * If so, just return.
+ */
+ {
+ GLboolean early_out;
+ _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+ early_out = ((ctx->Shared->RefCount == 1)
+ && (newTexObj == texUnit->CurrentTex[targetIndex]));
+ _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+ if (early_out) {
+ return;
+ }
+ }
+
+ /* flush before changing binding */
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+
+ /* Do the actual binding. The refcount on the previously bound
+ * texture object will be decremented. It'll be deleted if the
+ * count hits zero.
+ */
+ _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj);
+ ASSERT(texUnit->CurrentTex[targetIndex]);
+
+ /* Pass BindTexture call to device driver */
+ if (ctx->Driver.BindTexture)
+ (*ctx->Driver.BindTexture)( ctx, target, newTexObj );
+}
+
+
+/**
+ * Set texture priorities.
+ *
+ * \param n number of textures.
+ * \param texName texture names.
+ * \param priorities corresponding texture priorities.
+ *
+ * \sa glPrioritizeTextures().
+ *
+ * Looks up each texture in the hash, clamps the corresponding priority between
+ * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture.
+ */
+void GLAPIENTRY
+_mesa_PrioritizeTextures( GLsizei n, const GLuint *texName,
+ const GLclampf *priorities )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i;
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+ if (n < 0) {
+ _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" );
+ return;
+ }
+
+ if (!priorities)
+ return;
+
+ for (i = 0; i < n; i++) {
+ if (texName[i] > 0) {
+ struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]);
+ if (t) {
+ t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
+ }
+ }
+ }
+
+ ctx->NewState |= _NEW_TEXTURE;
+}
+
+
+
+/**
+ * See if textures are loaded in texture memory.
+ *
+ * \param n number of textures to query.
+ * \param texName array with the texture names.
+ * \param residences array which will hold the residence status.
+ *
+ * \return GL_TRUE if all textures are resident and \p residences is left unchanged,
+ *
+ * \sa glAreTexturesResident().
+ *
+ * Looks up each texture in the hash and calls
+ * dd_function_table::IsTextureResident.
+ */
+GLboolean GLAPIENTRY
+_mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
+ GLboolean *residences)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLboolean allResident = GL_TRUE;
+ GLint i, j;
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
+
+ if (n < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)");
+ return GL_FALSE;
+ }
+
+ if (!texName || !residences)
+ return GL_FALSE;
+
+ for (i = 0; i < n; i++) {
+ struct gl_texture_object *t;
+ if (texName[i] == 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
+ return GL_FALSE;
+ }
+ t = _mesa_lookup_texture(ctx, texName[i]);
+ if (!t) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
+ return GL_FALSE;
+ }
+ if (!ctx->Driver.IsTextureResident ||
+ ctx->Driver.IsTextureResident(ctx, t)) {
+ /* The texture is resident */
+ if (!allResident)
+ residences[i] = GL_TRUE;
+ }
+ else {
+ /* The texture is not resident */
+ if (allResident) {
+ allResident = GL_FALSE;
+ for (j = 0; j < i; j++)
+ residences[j] = GL_TRUE;
+ }
+ residences[i] = GL_FALSE;
+ }
+ }
+
+ return allResident;
+}
+
+
+/**
+ * See if a name corresponds to a texture.
+ *
+ * \param texture texture name.
+ *
+ * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE
+ * otherwise.
+ *
+ * \sa glIsTexture().
+ *
+ * Calls _mesa_HashLookup().
+ */
+GLboolean GLAPIENTRY
+_mesa_IsTexture( GLuint texture )
+{
+ struct gl_texture_object *t;
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
+
+ if (!texture)
+ return GL_FALSE;
+
+ t = _mesa_lookup_texture(ctx, texture);
+
+ /* IsTexture is true only after object has been bound once. */
+ return t && t->Target;
+}
+
+
+/**
+ * Simplest implementation of texture locking: grab the shared tex
+ * mutex. Examine the shared context state timestamp and if there has
+ * been a change, set the appropriate bits in ctx->NewState.
+ *
+ * This is used to deal with synchronizing things when a texture object
+ * is used/modified by different contexts (or threads) which are sharing
+ * the texture.
+ *
+ * See also _mesa_lock/unlock_texture() in teximage.h
+ */
+void
+_mesa_lock_context_textures( struct gl_context *ctx )
+{
+ _glthread_LOCK_MUTEX(ctx->Shared->TexMutex);
+
+ if (ctx->Shared->TextureStateStamp != ctx->TextureStateTimestamp) {
+ ctx->NewState |= _NEW_TEXTURE;
+ ctx->TextureStateTimestamp = ctx->Shared->TextureStateStamp;
+ }
+}
+
+
+void
+_mesa_unlock_context_textures( struct gl_context *ctx )
+{
+ assert(ctx->Shared->TextureStateStamp == ctx->TextureStateTimestamp);
+ _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex);
+}
+
+/*@}*/
diff --git a/mesalib/src/mesa/program/program.c b/mesalib/src/mesa/program/program.c
index 6c97787e8..79034ab26 100644
--- a/mesalib/src/mesa/program/program.c
+++ b/mesalib/src/mesa/program/program.c
@@ -1,1077 +1,1077 @@
-/*
- * Mesa 3-D graphics library
- * Version: 6.5.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.
- */
-
-/**
- * \file program.c
- * Vertex and fragment program support functions.
- * \author Brian Paul
- */
-
-
-#include "main/glheader.h"
-#include "main/context.h"
-#include "main/hash.h"
-#include "main/mfeatures.h"
-#include "program.h"
-#include "prog_cache.h"
-#include "prog_parameter.h"
-#include "prog_instruction.h"
-
-
-/**
- * A pointer to this dummy program is put into the hash table when
- * glGenPrograms is called.
- */
-struct gl_program _mesa_DummyProgram;
-
-
-/**
- * Init context's vertex/fragment program state
- */
-void
-_mesa_init_program(struct gl_context *ctx)
-{
- GLuint i;
-
- /*
- * If this assertion fails, we need to increase the field
- * size for register indexes (see INST_INDEX_BITS).
- */
- ASSERT(ctx->Const.VertexProgram.MaxUniformComponents / 4
- <= (1 << INST_INDEX_BITS));
- ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents / 4
- <= (1 << INST_INDEX_BITS));
-
- ASSERT(ctx->Const.VertexProgram.MaxTemps <= (1 << INST_INDEX_BITS));
- ASSERT(ctx->Const.VertexProgram.MaxLocalParams <= (1 << INST_INDEX_BITS));
- ASSERT(ctx->Const.FragmentProgram.MaxTemps <= (1 << INST_INDEX_BITS));
- ASSERT(ctx->Const.FragmentProgram.MaxLocalParams <= (1 << INST_INDEX_BITS));
-
- ASSERT(ctx->Const.VertexProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS);
- ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS);
-
- ASSERT(ctx->Const.VertexProgram.MaxAddressOffset <= (1 << INST_INDEX_BITS));
- ASSERT(ctx->Const.FragmentProgram.MaxAddressOffset <= (1 << INST_INDEX_BITS));
-
- /* If this fails, increase prog_instruction::TexSrcUnit size */
- ASSERT(MAX_TEXTURE_UNITS < (1 << 5));
-
- /* If this fails, increase prog_instruction::TexSrcTarget size */
- ASSERT(NUM_TEXTURE_TARGETS < (1 << 3));
-
- ctx->Program.ErrorPos = -1;
- ctx->Program.ErrorString = _mesa_strdup("");
-
-#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
- ctx->VertexProgram.Enabled = GL_FALSE;
-#if FEATURE_es2_glsl
- ctx->VertexProgram.PointSizeEnabled =
- (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE;
-#else
- ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
-#endif
- ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
- ctx->Shared->DefaultVertexProgram);
- assert(ctx->VertexProgram.Current);
- for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
- ctx->VertexProgram.TrackMatrix[i] = GL_NONE;
- ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV;
- }
- ctx->VertexProgram.Cache = _mesa_new_program_cache();
-#endif
-
-#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
- ctx->FragmentProgram.Enabled = GL_FALSE;
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
- ctx->Shared->DefaultFragmentProgram);
- assert(ctx->FragmentProgram.Current);
- ctx->FragmentProgram.Cache = _mesa_new_program_cache();
-#endif
-
-#if FEATURE_ARB_geometry_shader4
- ctx->GeometryProgram.Enabled = GL_FALSE;
- /* right now by default we don't have a geometry program */
- _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current,
- NULL);
- ctx->GeometryProgram.Cache = _mesa_new_program_cache();
-#endif
-
- /* XXX probably move this stuff */
-#if FEATURE_ATI_fragment_shader
- ctx->ATIFragmentShader.Enabled = GL_FALSE;
- ctx->ATIFragmentShader.Current = ctx->Shared->DefaultFragmentShader;
- assert(ctx->ATIFragmentShader.Current);
- ctx->ATIFragmentShader.Current->RefCount++;
-#endif
-}
-
-
-/**
- * Free a context's vertex/fragment program state
- */
-void
-_mesa_free_program_data(struct gl_context *ctx)
-{
-#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL);
- _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache);
-#endif
-#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
- _mesa_delete_program_cache(ctx, ctx->FragmentProgram.Cache);
-#endif
-#if FEATURE_ARB_geometry_shader4
- _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL);
- _mesa_delete_program_cache(ctx, ctx->GeometryProgram.Cache);
-#endif
- /* XXX probably move this stuff */
-#if FEATURE_ATI_fragment_shader
- if (ctx->ATIFragmentShader.Current) {
- ctx->ATIFragmentShader.Current->RefCount--;
- if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
- free(ctx->ATIFragmentShader.Current);
- }
- }
-#endif
- free((void *) ctx->Program.ErrorString);
-}
-
-
-/**
- * Update the default program 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_program(struct gl_context *ctx)
-{
-#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
- (struct gl_vertex_program *)
- ctx->Shared->DefaultVertexProgram);
- assert(ctx->VertexProgram.Current);
-#endif
-
-#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
- (struct gl_fragment_program *)
- ctx->Shared->DefaultFragmentProgram);
- assert(ctx->FragmentProgram.Current);
-#endif
-
-#if FEATURE_ARB_geometry_shader4
- _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current,
- (struct gl_geometry_program *)
- ctx->Shared->DefaultGeometryProgram);
-#endif
-
- /* XXX probably move this stuff */
-#if FEATURE_ATI_fragment_shader
- if (ctx->ATIFragmentShader.Current) {
- ctx->ATIFragmentShader.Current->RefCount--;
- if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
- free(ctx->ATIFragmentShader.Current);
- }
- }
- ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
- assert(ctx->ATIFragmentShader.Current);
- ctx->ATIFragmentShader.Current->RefCount++;
-#endif
-}
-
-
-/**
- * Set the vertex/fragment program error state (position and error string).
- * This is generally called from within the parsers.
- */
-void
-_mesa_set_program_error(struct gl_context *ctx, GLint pos, const char *string)
-{
- ctx->Program.ErrorPos = pos;
- free((void *) ctx->Program.ErrorString);
- if (!string)
- string = "";
- ctx->Program.ErrorString = _mesa_strdup(string);
-}
-
-
-/**
- * Find the line number and column for 'pos' within 'string'.
- * Return a copy of the line which contains 'pos'. Free the line with
- * free().
- * \param string the program string
- * \param pos the position within the string
- * \param line returns the line number corresponding to 'pos'.
- * \param col returns the column number corresponding to 'pos'.
- * \return copy of the line containing 'pos'.
- */
-const GLubyte *
-_mesa_find_line_column(const GLubyte *string, const GLubyte *pos,
- GLint *line, GLint *col)
-{
- const GLubyte *lineStart = string;
- const GLubyte *p = string;
- GLubyte *s;
- int len;
-
- *line = 1;
-
- while (p != pos) {
- if (*p == (GLubyte) '\n') {
- (*line)++;
- lineStart = p + 1;
- }
- p++;
- }
-
- *col = (pos - lineStart) + 1;
-
- /* return copy of this line */
- while (*p != 0 && *p != '\n')
- p++;
- len = p - lineStart;
- s = (GLubyte *) malloc(len + 1);
- memcpy(s, lineStart, len);
- s[len] = 0;
-
- return s;
-}
-
-
-/**
- * Initialize a new vertex/fragment program object.
- */
-static struct gl_program *
-_mesa_init_program_struct( struct gl_context *ctx, struct gl_program *prog,
- GLenum target, GLuint id)
-{
- (void) ctx;
- if (prog) {
- GLuint i;
- memset(prog, 0, sizeof(*prog));
- prog->Id = id;
- prog->Target = target;
- prog->Resident = GL_TRUE;
- prog->RefCount = 1;
- prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB;
-
- /* default mapping from samplers to texture units */
- for (i = 0; i < MAX_SAMPLERS; i++)
- prog->SamplerUnits[i] = i;
- }
-
- return prog;
-}
-
-
-/**
- * Initialize a new fragment program object.
- */
-struct gl_program *
-_mesa_init_fragment_program( struct gl_context *ctx, struct gl_fragment_program *prog,
- GLenum target, GLuint id)
-{
- if (prog)
- return _mesa_init_program_struct( ctx, &prog->Base, target, id );
- else
- return NULL;
-}
-
-
-/**
- * Initialize a new vertex program object.
- */
-struct gl_program *
-_mesa_init_vertex_program( struct gl_context *ctx, struct gl_vertex_program *prog,
- GLenum target, GLuint id)
-{
- if (prog)
- return _mesa_init_program_struct( ctx, &prog->Base, target, id );
- else
- return NULL;
-}
-
-
-/**
- * Initialize a new geometry program object.
- */
-struct gl_program *
-_mesa_init_geometry_program( struct gl_context *ctx, struct gl_geometry_program *prog,
- GLenum target, GLuint id)
-{
- if (prog)
- return _mesa_init_program_struct( ctx, &prog->Base, target, id );
- else
- return NULL;
-}
-
-
-/**
- * Allocate and initialize a new fragment/vertex program object but
- * don't put it into the program hash table. Called via
- * ctx->Driver.NewProgram. May be overridden (ie. replaced) by a
- * device driver function to implement OO deriviation with additional
- * types not understood by this function.
- *
- * \param ctx context
- * \param id program id/number
- * \param target program target/type
- * \return pointer to new program object
- */
-struct gl_program *
-_mesa_new_program(struct gl_context *ctx, GLenum target, GLuint id)
-{
- struct gl_program *prog;
- switch (target) {
- case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
- case GL_VERTEX_STATE_PROGRAM_NV:
- prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program),
- target, id );
- break;
- case GL_FRAGMENT_PROGRAM_NV:
- case GL_FRAGMENT_PROGRAM_ARB:
- prog =_mesa_init_fragment_program(ctx,
- CALLOC_STRUCT(gl_fragment_program),
- target, id );
- break;
- case MESA_GEOMETRY_PROGRAM:
- prog = _mesa_init_geometry_program(ctx,
- CALLOC_STRUCT(gl_geometry_program),
- target, id);
- break;
- default:
- _mesa_problem(ctx, "bad target in _mesa_new_program");
- prog = NULL;
- }
- return prog;
-}
-
-
-/**
- * Delete a program and remove it from the hash table, ignoring the
- * reference count.
- * Called via ctx->Driver.DeleteProgram. May be wrapped (OO deriviation)
- * by a device driver function.
- */
-void
-_mesa_delete_program(struct gl_context *ctx, struct gl_program *prog)
-{
- (void) ctx;
- ASSERT(prog);
- ASSERT(prog->RefCount==0);
-
- if (prog == &_mesa_DummyProgram)
- return;
-
- if (prog->String)
- free(prog->String);
-
- _mesa_free_instructions(prog->Instructions, prog->NumInstructions);
-
- if (prog->Parameters) {
- _mesa_free_parameter_list(prog->Parameters);
- }
- if (prog->Varying) {
- _mesa_free_parameter_list(prog->Varying);
- }
- if (prog->Attributes) {
- _mesa_free_parameter_list(prog->Attributes);
- }
-
- free(prog);
-}
-
-
-/**
- * Return the gl_program object for a given ID.
- * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of
- * casts elsewhere.
- */
-struct gl_program *
-_mesa_lookup_program(struct gl_context *ctx, GLuint id)
-{
- if (id)
- return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id);
- else
- return NULL;
-}
-
-
-/**
- * Reference counting for vertex/fragment programs
- */
-void
-_mesa_reference_program(struct gl_context *ctx,
- struct gl_program **ptr,
- struct gl_program *prog)
-{
- assert(ptr);
- if (*ptr && prog) {
- /* sanity check */
- if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB)
- ASSERT(prog->Target == GL_VERTEX_PROGRAM_ARB);
- else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB)
- ASSERT(prog->Target == GL_FRAGMENT_PROGRAM_ARB ||
- prog->Target == GL_FRAGMENT_PROGRAM_NV);
- else if ((*ptr)->Target == MESA_GEOMETRY_PROGRAM)
- ASSERT(prog->Target == MESA_GEOMETRY_PROGRAM);
- }
- if (*ptr == prog) {
- return; /* no change */
- }
- if (*ptr) {
- GLboolean deleteFlag;
-
- /*_glthread_LOCK_MUTEX((*ptr)->Mutex);*/
-#if 0
- printf("Program %p ID=%u Target=%s Refcount-- to %d\n",
- *ptr, (*ptr)->Id,
- ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB ? "VP" :
- ((*ptr)->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")),
- (*ptr)->RefCount - 1);
-#endif
- ASSERT((*ptr)->RefCount > 0);
- (*ptr)->RefCount--;
-
- deleteFlag = ((*ptr)->RefCount == 0);
- /*_glthread_UNLOCK_MUTEX((*ptr)->Mutex);*/
-
- if (deleteFlag) {
- ASSERT(ctx);
- ctx->Driver.DeleteProgram(ctx, *ptr);
- }
-
- *ptr = NULL;
- }
-
- assert(!*ptr);
- if (prog) {
- /*_glthread_LOCK_MUTEX(prog->Mutex);*/
- prog->RefCount++;
-#if 0
- printf("Program %p ID=%u Target=%s Refcount++ to %d\n",
- prog, prog->Id,
- (prog->Target == GL_VERTEX_PROGRAM_ARB ? "VP" :
- (prog->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")),
- prog->RefCount);
-#endif
- /*_glthread_UNLOCK_MUTEX(prog->Mutex);*/
- }
-
- *ptr = prog;
-}
-
-
-/**
- * Return a copy of a program.
- * XXX Problem here if the program object is actually OO-derivation
- * made by a device driver.
- */
-struct gl_program *
-_mesa_clone_program(struct gl_context *ctx, const struct gl_program *prog)
-{
- struct gl_program *clone;
-
- clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id);
- if (!clone)
- return NULL;
-
- assert(clone->Target == prog->Target);
- assert(clone->RefCount == 1);
-
- clone->String = (GLubyte *) _mesa_strdup((char *) prog->String);
- clone->Format = prog->Format;
- clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions);
- if (!clone->Instructions) {
- _mesa_reference_program(ctx, &clone, NULL);
- return NULL;
- }
- _mesa_copy_instructions(clone->Instructions, prog->Instructions,
- prog->NumInstructions);
- clone->InputsRead = prog->InputsRead;
- clone->OutputsWritten = prog->OutputsWritten;
- clone->SamplersUsed = prog->SamplersUsed;
- clone->ShadowSamplers = prog->ShadowSamplers;
- memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed));
-
- if (prog->Parameters)
- clone->Parameters = _mesa_clone_parameter_list(prog->Parameters);
- memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
- if (prog->Varying)
- clone->Varying = _mesa_clone_parameter_list(prog->Varying);
- if (prog->Attributes)
- clone->Attributes = _mesa_clone_parameter_list(prog->Attributes);
- memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
- clone->IndirectRegisterFiles = prog->IndirectRegisterFiles;
- clone->NumInstructions = prog->NumInstructions;
- clone->NumTemporaries = prog->NumTemporaries;
- clone->NumParameters = prog->NumParameters;
- clone->NumAttributes = prog->NumAttributes;
- clone->NumAddressRegs = prog->NumAddressRegs;
- clone->NumNativeInstructions = prog->NumNativeInstructions;
- clone->NumNativeTemporaries = prog->NumNativeTemporaries;
- clone->NumNativeParameters = prog->NumNativeParameters;
- clone->NumNativeAttributes = prog->NumNativeAttributes;
- clone->NumNativeAddressRegs = prog->NumNativeAddressRegs;
- clone->NumAluInstructions = prog->NumAluInstructions;
- clone->NumTexInstructions = prog->NumTexInstructions;
- clone->NumTexIndirections = prog->NumTexIndirections;
- clone->NumNativeAluInstructions = prog->NumNativeAluInstructions;
- clone->NumNativeTexInstructions = prog->NumNativeTexInstructions;
- clone->NumNativeTexIndirections = prog->NumNativeTexIndirections;
-
- switch (prog->Target) {
- case GL_VERTEX_PROGRAM_ARB:
- {
- const struct gl_vertex_program *vp
- = (const struct gl_vertex_program *) prog;
- struct gl_vertex_program *vpc = (struct gl_vertex_program *) clone;
- vpc->IsPositionInvariant = vp->IsPositionInvariant;
- vpc->IsNVProgram = vp->IsNVProgram;
- }
- break;
- case GL_FRAGMENT_PROGRAM_ARB:
- {
- const struct gl_fragment_program *fp
- = (const struct gl_fragment_program *) prog;
- struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone;
- fpc->FogOption = fp->FogOption;
- fpc->UsesKill = fp->UsesKill;
- fpc->OriginUpperLeft = fp->OriginUpperLeft;
- fpc->PixelCenterInteger = fp->PixelCenterInteger;
- }
- break;
- case MESA_GEOMETRY_PROGRAM:
- {
- const struct gl_geometry_program *gp
- = (const struct gl_geometry_program *) prog;
- struct gl_geometry_program *gpc = (struct gl_geometry_program *) clone;
- gpc->VerticesOut = gp->VerticesOut;
- gpc->InputType = gp->InputType;
- gpc->OutputType = gp->OutputType;
- }
- break;
- default:
- _mesa_problem(NULL, "Unexpected target in _mesa_clone_program");
- }
-
- return clone;
-}
-
-
-/**
- * Insert 'count' NOP instructions at 'start' in the given program.
- * Adjust branch targets accordingly.
- */
-GLboolean
-_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count)
-{
- const GLuint origLen = prog->NumInstructions;
- const GLuint newLen = origLen + count;
- struct prog_instruction *newInst;
- GLuint i;
-
- /* adjust branches */
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = prog->Instructions + i;
- if (inst->BranchTarget > 0) {
- if ((GLuint)inst->BranchTarget >= start) {
- inst->BranchTarget += count;
- }
- }
- }
-
- /* Alloc storage for new instructions */
- newInst = _mesa_alloc_instructions(newLen);
- if (!newInst) {
- return GL_FALSE;
- }
-
- /* Copy 'start' instructions into new instruction buffer */
- _mesa_copy_instructions(newInst, prog->Instructions, start);
-
- /* init the new instructions */
- _mesa_init_instructions(newInst + start, count);
-
- /* Copy the remaining/tail instructions to new inst buffer */
- _mesa_copy_instructions(newInst + start + count,
- prog->Instructions + start,
- origLen - start);
-
- /* free old instructions */
- _mesa_free_instructions(prog->Instructions, origLen);
-
- /* install new instructions */
- prog->Instructions = newInst;
- prog->NumInstructions = newLen;
-
- return GL_TRUE;
-}
-
-/**
- * Delete 'count' instructions at 'start' in the given program.
- * Adjust branch targets accordingly.
- */
-GLboolean
-_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count)
-{
- const GLuint origLen = prog->NumInstructions;
- const GLuint newLen = origLen - count;
- struct prog_instruction *newInst;
- GLuint i;
-
- /* adjust branches */
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = prog->Instructions + i;
- if (inst->BranchTarget > 0) {
- if (inst->BranchTarget > (GLint) start) {
- inst->BranchTarget -= count;
- }
- }
- }
-
- /* Alloc storage for new instructions */
- newInst = _mesa_alloc_instructions(newLen);
- if (!newInst) {
- return GL_FALSE;
- }
-
- /* Copy 'start' instructions into new instruction buffer */
- _mesa_copy_instructions(newInst, prog->Instructions, start);
-
- /* Copy the remaining/tail instructions to new inst buffer */
- _mesa_copy_instructions(newInst + start,
- prog->Instructions + start + count,
- newLen - start);
-
- /* free old instructions */
- _mesa_free_instructions(prog->Instructions, origLen);
-
- /* install new instructions */
- prog->Instructions = newInst;
- prog->NumInstructions = newLen;
-
- return GL_TRUE;
-}
-
-
-/**
- * Search instructions for registers that match (oldFile, oldIndex),
- * replacing them with (newFile, newIndex).
- */
-static void
-replace_registers(struct prog_instruction *inst, GLuint numInst,
- GLuint oldFile, GLuint oldIndex,
- GLuint newFile, GLuint newIndex)
-{
- GLuint i, j;
- for (i = 0; i < numInst; i++) {
- /* src regs */
- for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) {
- if (inst[i].SrcReg[j].File == oldFile &&
- inst[i].SrcReg[j].Index == oldIndex) {
- inst[i].SrcReg[j].File = newFile;
- inst[i].SrcReg[j].Index = newIndex;
- }
- }
- /* dst reg */
- if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) {
- inst[i].DstReg.File = newFile;
- inst[i].DstReg.Index = newIndex;
- }
- }
-}
-
-
-/**
- * Search instructions for references to program parameters. When found,
- * increment the parameter index by 'offset'.
- * Used when combining programs.
- */
-static void
-adjust_param_indexes(struct prog_instruction *inst, GLuint numInst,
- GLuint offset)
-{
- GLuint i, j;
- for (i = 0; i < numInst; i++) {
- for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) {
- GLuint f = inst[i].SrcReg[j].File;
- if (f == PROGRAM_CONSTANT ||
- f == PROGRAM_UNIFORM ||
- f == PROGRAM_STATE_VAR) {
- inst[i].SrcReg[j].Index += offset;
- }
- }
- }
-}
-
-
-/**
- * Combine two programs into one. Fix instructions so the outputs of
- * the first program go to the inputs of the second program.
- */
-struct gl_program *
-_mesa_combine_programs(struct gl_context *ctx,
- const struct gl_program *progA,
- const struct gl_program *progB)
-{
- struct prog_instruction *newInst;
- struct gl_program *newProg;
- const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */
- const GLuint lenB = progB->NumInstructions;
- const GLuint numParamsA = _mesa_num_parameters(progA->Parameters);
- const GLuint newLength = lenA + lenB;
- GLboolean usedTemps[MAX_PROGRAM_TEMPS];
- GLuint firstTemp = 0;
- GLbitfield inputsB;
- GLuint i;
-
- ASSERT(progA->Target == progB->Target);
-
- newInst = _mesa_alloc_instructions(newLength);
- if (!newInst)
- return GL_FALSE;
-
- _mesa_copy_instructions(newInst, progA->Instructions, lenA);
- _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB);
-
- /* adjust branch / instruction addresses for B's instructions */
- for (i = 0; i < lenB; i++) {
- newInst[lenA + i].BranchTarget += lenA;
- }
-
- newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0);
- newProg->Instructions = newInst;
- newProg->NumInstructions = newLength;
-
- /* find used temp regs (we may need new temps below) */
- _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY,
- usedTemps, MAX_PROGRAM_TEMPS);
-
- if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) {
- struct gl_fragment_program *fprogA, *fprogB, *newFprog;
- GLbitfield progB_inputsRead = progB->InputsRead;
- GLint progB_colorFile, progB_colorIndex;
-
- fprogA = (struct gl_fragment_program *) progA;
- fprogB = (struct gl_fragment_program *) progB;
- newFprog = (struct gl_fragment_program *) newProg;
-
- newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill;
-
- /* We'll do a search and replace for instances
- * of progB_colorFile/progB_colorIndex below...
- */
- progB_colorFile = PROGRAM_INPUT;
- progB_colorIndex = FRAG_ATTRIB_COL0;
-
- /*
- * The fragment program may get color from a state var rather than
- * a fragment input (vertex output) if it's constant.
- * See the texenvprogram.c code.
- * So, search the program's parameter list now to see if the program
- * gets color from a state var instead of a conventional fragment
- * input register.
- */
- for (i = 0; i < progB->Parameters->NumParameters; i++) {
- struct gl_program_parameter *p = &progB->Parameters->Parameters[i];
- if (p->Type == PROGRAM_STATE_VAR &&
- p->StateIndexes[0] == STATE_INTERNAL &&
- p->StateIndexes[1] == STATE_CURRENT_ATTRIB &&
- (int) p->StateIndexes[2] == (int) VERT_ATTRIB_COLOR0) {
- progB_inputsRead |= FRAG_BIT_COL0;
- progB_colorFile = PROGRAM_STATE_VAR;
- progB_colorIndex = i;
- break;
- }
- }
-
- /* Connect color outputs of fprogA to color inputs of fprogB, via a
- * new temporary register.
- */
- if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) &&
- (progB_inputsRead & FRAG_BIT_COL0)) {
- GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS,
- firstTemp);
- if (tempReg < 0) {
- _mesa_problem(ctx, "No free temp regs found in "
- "_mesa_combine_programs(), using 31");
- tempReg = 31;
- }
- firstTemp = tempReg + 1;
-
- /* replace writes to result.color[0] with tempReg */
- replace_registers(newInst, lenA,
- PROGRAM_OUTPUT, FRAG_RESULT_COLOR,
- PROGRAM_TEMPORARY, tempReg);
- /* replace reads from the input color with tempReg */
- replace_registers(newInst + lenA, lenB,
- progB_colorFile, progB_colorIndex, /* search for */
- PROGRAM_TEMPORARY, tempReg /* replace with */ );
- }
-
- /* compute combined program's InputsRead */
- inputsB = progB_inputsRead;
- if (progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) {
- inputsB &= ~(1 << FRAG_ATTRIB_COL0);
- }
- newProg->InputsRead = progA->InputsRead | inputsB;
- newProg->OutputsWritten = progB->OutputsWritten;
- newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed;
- }
- else {
- /* vertex program */
- assert(0); /* XXX todo */
- }
-
- /*
- * Merge parameters (uniforms, constants, etc)
- */
- newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters,
- progB->Parameters);
-
- adjust_param_indexes(newInst + lenA, lenB, numParamsA);
-
-
- return newProg;
-}
-
-
-/**
- * Populate the 'used' array with flags indicating which registers (TEMPs,
- * INPUTs, OUTPUTs, etc, are used by the given program.
- * \param file type of register to scan for
- * \param used returns true/false flags for in use / free
- * \param usedSize size of the 'used' array
- */
-void
-_mesa_find_used_registers(const struct gl_program *prog,
- gl_register_file file,
- GLboolean used[], GLuint usedSize)
-{
- GLuint i, j;
-
- memset(used, 0, usedSize);
-
- for (i = 0; i < prog->NumInstructions; i++) {
- const struct prog_instruction *inst = prog->Instructions + i;
- const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
-
- if (inst->DstReg.File == file) {
- ASSERT(inst->DstReg.Index < usedSize);
- if(inst->DstReg.Index < usedSize)
- used[inst->DstReg.Index] = GL_TRUE;
- }
-
- for (j = 0; j < n; j++) {
- if (inst->SrcReg[j].File == file) {
- ASSERT(inst->SrcReg[j].Index < usedSize);
- if(inst->SrcReg[j].Index < usedSize)
- used[inst->SrcReg[j].Index] = GL_TRUE;
- }
- }
- }
-}
-
-
-/**
- * Scan the given 'used' register flag array for the first entry
- * that's >= firstReg.
- * \param used vector of flags indicating registers in use (as returned
- * by _mesa_find_used_registers())
- * \param usedSize size of the 'used' array
- * \param firstReg first register to start searching at
- * \return index of unused register, or -1 if none.
- */
-GLint
-_mesa_find_free_register(const GLboolean used[],
- GLuint usedSize, GLuint firstReg)
-{
- GLuint i;
-
- assert(firstReg < usedSize);
-
- for (i = firstReg; i < usedSize; i++)
- if (!used[i])
- return i;
-
- return -1;
-}
-
-
-
-/**
- * Check if the given register index is valid (doesn't exceed implementation-
- * dependent limits).
- * \return GL_TRUE if OK, GL_FALSE if bad index
- */
-GLboolean
-_mesa_valid_register_index(const struct gl_context *ctx,
- gl_shader_type shaderType,
- gl_register_file file, GLint index)
-{
- const struct gl_program_constants *c;
-
- switch (shaderType) {
- case MESA_SHADER_VERTEX:
- c = &ctx->Const.VertexProgram;
- break;
- case MESA_SHADER_FRAGMENT:
- c = &ctx->Const.FragmentProgram;
- break;
- case MESA_SHADER_GEOMETRY:
- c = &ctx->Const.GeometryProgram;
- break;
- default:
- _mesa_problem(ctx,
- "unexpected shader type in _mesa_valid_register_index()");
- return GL_FALSE;
- }
-
- switch (file) {
- case PROGRAM_UNDEFINED:
- return GL_TRUE; /* XXX or maybe false? */
-
- case PROGRAM_TEMPORARY:
- return index >= 0 && index < c->MaxTemps;
-
- case PROGRAM_ENV_PARAM:
- return index >= 0 && index < c->MaxEnvParams;
-
- case PROGRAM_LOCAL_PARAM:
- return index >= 0 && index < c->MaxLocalParams;
-
- case PROGRAM_NAMED_PARAM:
- return index >= 0 && index < c->MaxParameters;
-
- case PROGRAM_UNIFORM:
- case PROGRAM_STATE_VAR:
- /* aka constant buffer */
- return index >= 0 && index < c->MaxUniformComponents / 4;
-
- case PROGRAM_CONSTANT:
- /* constant buffer w/ possible relative negative addressing */
- return (index > (int) c->MaxUniformComponents / -4 &&
- index < c->MaxUniformComponents / 4);
-
- case PROGRAM_INPUT:
- if (index < 0)
- return GL_FALSE;
-
- switch (shaderType) {
- case MESA_SHADER_VERTEX:
- return index < VERT_ATTRIB_GENERIC0 + c->MaxAttribs;
- case MESA_SHADER_FRAGMENT:
- return index < FRAG_ATTRIB_VAR0 + ctx->Const.MaxVarying;
- case MESA_SHADER_GEOMETRY:
- return index < GEOM_ATTRIB_VAR0 + ctx->Const.MaxVarying;
- default:
- return GL_FALSE;
- }
-
- case PROGRAM_OUTPUT:
- if (index < 0)
- return GL_FALSE;
-
- switch (shaderType) {
- case MESA_SHADER_VERTEX:
- return index < VERT_RESULT_VAR0 + ctx->Const.MaxVarying;
- case MESA_SHADER_FRAGMENT:
- return index < FRAG_RESULT_DATA0 + ctx->Const.MaxDrawBuffers;
- case MESA_SHADER_GEOMETRY:
- return index < GEOM_RESULT_VAR0 + ctx->Const.MaxVarying;
- default:
- return GL_FALSE;
- }
-
- case PROGRAM_ADDRESS:
- return index >= 0 && index < c->MaxAddressRegs;
-
- default:
- _mesa_problem(ctx,
- "unexpected register file in _mesa_valid_register_index()");
- return GL_FALSE;
- }
-}
-
-
-
-/**
- * "Post-process" a GPU program. This is intended to be used for debugging.
- * Example actions include no-op'ing instructions or changing instruction
- * behaviour.
- */
-void
-_mesa_postprocess_program(struct gl_context *ctx, struct gl_program *prog)
-{
- static const GLfloat white[4] = { 0.5, 0.5, 0.5, 0.5 };
- GLuint i;
- GLuint whiteSwizzle;
- GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters,
- white, 4, &whiteSwizzle);
-
- (void) whiteIndex;
-
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = prog->Instructions + i;
- const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
-
- (void) n;
-
- if (_mesa_is_tex_instruction(inst->Opcode)) {
-#if 0
- /* replace TEX/TXP/TXB with MOV */
- inst->Opcode = OPCODE_MOV;
- inst->DstReg.WriteMask = WRITEMASK_XYZW;
- inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
- inst->SrcReg[0].Negate = NEGATE_NONE;
-#endif
-
-#if 0
- /* disable shadow texture mode */
- inst->TexShadow = 0;
-#endif
- }
-
- if (inst->Opcode == OPCODE_TXP) {
-#if 0
- inst->Opcode = OPCODE_MOV;
- inst->DstReg.WriteMask = WRITEMASK_XYZW;
- inst->SrcReg[0].File = PROGRAM_CONSTANT;
- inst->SrcReg[0].Index = whiteIndex;
- inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
- inst->SrcReg[0].Negate = NEGATE_NONE;
-#endif
-#if 0
- inst->TexShadow = 0;
-#endif
-#if 0
- inst->Opcode = OPCODE_TEX;
- inst->TexShadow = 0;
-#endif
- }
-
- }
-}
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.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.
+ */
+
+/**
+ * \file program.c
+ * Vertex and fragment program support functions.
+ * \author Brian Paul
+ */
+
+
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/hash.h"
+#include "main/mfeatures.h"
+#include "program.h"
+#include "prog_cache.h"
+#include "prog_parameter.h"
+#include "prog_instruction.h"
+
+
+/**
+ * A pointer to this dummy program is put into the hash table when
+ * glGenPrograms is called.
+ */
+struct gl_program _mesa_DummyProgram;
+
+
+/**
+ * Init context's vertex/fragment program state
+ */
+void
+_mesa_init_program(struct gl_context *ctx)
+{
+ GLuint i;
+
+ /*
+ * If this assertion fails, we need to increase the field
+ * size for register indexes (see INST_INDEX_BITS).
+ */
+ ASSERT(ctx->Const.VertexProgram.MaxUniformComponents / 4
+ <= (1 << INST_INDEX_BITS));
+ ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents / 4
+ <= (1 << INST_INDEX_BITS));
+
+ ASSERT(ctx->Const.VertexProgram.MaxTemps <= (1 << INST_INDEX_BITS));
+ ASSERT(ctx->Const.VertexProgram.MaxLocalParams <= (1 << INST_INDEX_BITS));
+ ASSERT(ctx->Const.FragmentProgram.MaxTemps <= (1 << INST_INDEX_BITS));
+ ASSERT(ctx->Const.FragmentProgram.MaxLocalParams <= (1 << INST_INDEX_BITS));
+
+ ASSERT(ctx->Const.VertexProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS);
+ ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS);
+
+ ASSERT(ctx->Const.VertexProgram.MaxAddressOffset <= (1 << INST_INDEX_BITS));
+ ASSERT(ctx->Const.FragmentProgram.MaxAddressOffset <= (1 << INST_INDEX_BITS));
+
+ /* If this fails, increase prog_instruction::TexSrcUnit size */
+ ASSERT(MAX_TEXTURE_UNITS < (1 << 5));
+
+ /* If this fails, increase prog_instruction::TexSrcTarget size */
+ ASSERT(NUM_TEXTURE_TARGETS < (1 << 3));
+
+ ctx->Program.ErrorPos = -1;
+ ctx->Program.ErrorString = _mesa_strdup("");
+
+#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
+ ctx->VertexProgram.Enabled = GL_FALSE;
+#if FEATURE_es2_glsl
+ ctx->VertexProgram.PointSizeEnabled =
+ (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE;
+#else
+ ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
+#endif
+ ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
+ ctx->Shared->DefaultVertexProgram);
+ assert(ctx->VertexProgram.Current);
+ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
+ ctx->VertexProgram.TrackMatrix[i] = GL_NONE;
+ ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV;
+ }
+ ctx->VertexProgram.Cache = _mesa_new_program_cache();
+#endif
+
+#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
+ ctx->FragmentProgram.Enabled = GL_FALSE;
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
+ ctx->Shared->DefaultFragmentProgram);
+ assert(ctx->FragmentProgram.Current);
+ ctx->FragmentProgram.Cache = _mesa_new_program_cache();
+#endif
+
+#if FEATURE_ARB_geometry_shader4
+ ctx->GeometryProgram.Enabled = GL_FALSE;
+ /* right now by default we don't have a geometry program */
+ _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current,
+ NULL);
+ ctx->GeometryProgram.Cache = _mesa_new_program_cache();
+#endif
+
+ /* XXX probably move this stuff */
+#if FEATURE_ATI_fragment_shader
+ ctx->ATIFragmentShader.Enabled = GL_FALSE;
+ ctx->ATIFragmentShader.Current = ctx->Shared->DefaultFragmentShader;
+ assert(ctx->ATIFragmentShader.Current);
+ ctx->ATIFragmentShader.Current->RefCount++;
+#endif
+}
+
+
+/**
+ * Free a context's vertex/fragment program state
+ */
+void
+_mesa_free_program_data(struct gl_context *ctx)
+{
+#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL);
+ _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache);
+#endif
+#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
+ _mesa_delete_program_cache(ctx, ctx->FragmentProgram.Cache);
+#endif
+#if FEATURE_ARB_geometry_shader4
+ _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL);
+ _mesa_delete_program_cache(ctx, ctx->GeometryProgram.Cache);
+#endif
+ /* XXX probably move this stuff */
+#if FEATURE_ATI_fragment_shader
+ if (ctx->ATIFragmentShader.Current) {
+ ctx->ATIFragmentShader.Current->RefCount--;
+ if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
+ free(ctx->ATIFragmentShader.Current);
+ }
+ }
+#endif
+ free((void *) ctx->Program.ErrorString);
+}
+
+
+/**
+ * Update the default program 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_program(struct gl_context *ctx)
+{
+#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
+ (struct gl_vertex_program *)
+ ctx->Shared->DefaultVertexProgram);
+ assert(ctx->VertexProgram.Current);
+#endif
+
+#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
+ (struct gl_fragment_program *)
+ ctx->Shared->DefaultFragmentProgram);
+ assert(ctx->FragmentProgram.Current);
+#endif
+
+#if FEATURE_ARB_geometry_shader4
+ _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current,
+ (struct gl_geometry_program *)
+ ctx->Shared->DefaultGeometryProgram);
+#endif
+
+ /* XXX probably move this stuff */
+#if FEATURE_ATI_fragment_shader
+ if (ctx->ATIFragmentShader.Current) {
+ ctx->ATIFragmentShader.Current->RefCount--;
+ if (ctx->ATIFragmentShader.Current->RefCount <= 0) {
+ free(ctx->ATIFragmentShader.Current);
+ }
+ }
+ ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader;
+ assert(ctx->ATIFragmentShader.Current);
+ ctx->ATIFragmentShader.Current->RefCount++;
+#endif
+}
+
+
+/**
+ * Set the vertex/fragment program error state (position and error string).
+ * This is generally called from within the parsers.
+ */
+void
+_mesa_set_program_error(struct gl_context *ctx, GLint pos, const char *string)
+{
+ ctx->Program.ErrorPos = pos;
+ free((void *) ctx->Program.ErrorString);
+ if (!string)
+ string = "";
+ ctx->Program.ErrorString = _mesa_strdup(string);
+}
+
+
+/**
+ * Find the line number and column for 'pos' within 'string'.
+ * Return a copy of the line which contains 'pos'. Free the line with
+ * free().
+ * \param string the program string
+ * \param pos the position within the string
+ * \param line returns the line number corresponding to 'pos'.
+ * \param col returns the column number corresponding to 'pos'.
+ * \return copy of the line containing 'pos'.
+ */
+const GLubyte *
+_mesa_find_line_column(const GLubyte *string, const GLubyte *pos,
+ GLint *line, GLint *col)
+{
+ const GLubyte *lineStart = string;
+ const GLubyte *p = string;
+ GLubyte *s;
+ int len;
+
+ *line = 1;
+
+ while (p != pos) {
+ if (*p == (GLubyte) '\n') {
+ (*line)++;
+ lineStart = p + 1;
+ }
+ p++;
+ }
+
+ *col = (pos - lineStart) + 1;
+
+ /* return copy of this line */
+ while (*p != 0 && *p != '\n')
+ p++;
+ len = p - lineStart;
+ s = (GLubyte *) malloc(len + 1);
+ memcpy(s, lineStart, len);
+ s[len] = 0;
+
+ return s;
+}
+
+
+/**
+ * Initialize a new vertex/fragment program object.
+ */
+static struct gl_program *
+_mesa_init_program_struct( struct gl_context *ctx, struct gl_program *prog,
+ GLenum target, GLuint id)
+{
+ (void) ctx;
+ if (prog) {
+ GLuint i;
+ memset(prog, 0, sizeof(*prog));
+ prog->Id = id;
+ prog->Target = target;
+ prog->Resident = GL_TRUE;
+ prog->RefCount = 1;
+ prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB;
+
+ /* default mapping from samplers to texture units */
+ for (i = 0; i < MAX_SAMPLERS; i++)
+ prog->SamplerUnits[i] = i;
+ }
+
+ return prog;
+}
+
+
+/**
+ * Initialize a new fragment program object.
+ */
+struct gl_program *
+_mesa_init_fragment_program( struct gl_context *ctx, struct gl_fragment_program *prog,
+ GLenum target, GLuint id)
+{
+ if (prog)
+ return _mesa_init_program_struct( ctx, &prog->Base, target, id );
+ else
+ return NULL;
+}
+
+
+/**
+ * Initialize a new vertex program object.
+ */
+struct gl_program *
+_mesa_init_vertex_program( struct gl_context *ctx, struct gl_vertex_program *prog,
+ GLenum target, GLuint id)
+{
+ if (prog)
+ return _mesa_init_program_struct( ctx, &prog->Base, target, id );
+ else
+ return NULL;
+}
+
+
+/**
+ * Initialize a new geometry program object.
+ */
+struct gl_program *
+_mesa_init_geometry_program( struct gl_context *ctx, struct gl_geometry_program *prog,
+ GLenum target, GLuint id)
+{
+ if (prog)
+ return _mesa_init_program_struct( ctx, &prog->Base, target, id );
+ else
+ return NULL;
+}
+
+
+/**
+ * Allocate and initialize a new fragment/vertex program object but
+ * don't put it into the program hash table. Called via
+ * ctx->Driver.NewProgram. May be overridden (ie. replaced) by a
+ * device driver function to implement OO deriviation with additional
+ * types not understood by this function.
+ *
+ * \param ctx context
+ * \param id program id/number
+ * \param target program target/type
+ * \return pointer to new program object
+ */
+struct gl_program *
+_mesa_new_program(struct gl_context *ctx, GLenum target, GLuint id)
+{
+ struct gl_program *prog;
+ switch (target) {
+ case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
+ case GL_VERTEX_STATE_PROGRAM_NV:
+ prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program),
+ target, id );
+ break;
+ case GL_FRAGMENT_PROGRAM_NV:
+ case GL_FRAGMENT_PROGRAM_ARB:
+ prog =_mesa_init_fragment_program(ctx,
+ CALLOC_STRUCT(gl_fragment_program),
+ target, id );
+ break;
+ case MESA_GEOMETRY_PROGRAM:
+ prog = _mesa_init_geometry_program(ctx,
+ CALLOC_STRUCT(gl_geometry_program),
+ target, id);
+ break;
+ default:
+ _mesa_problem(ctx, "bad target in _mesa_new_program");
+ prog = NULL;
+ }
+ return prog;
+}
+
+
+/**
+ * Delete a program and remove it from the hash table, ignoring the
+ * reference count.
+ * Called via ctx->Driver.DeleteProgram. May be wrapped (OO deriviation)
+ * by a device driver function.
+ */
+void
+_mesa_delete_program(struct gl_context *ctx, struct gl_program *prog)
+{
+ (void) ctx;
+ ASSERT(prog);
+ ASSERT(prog->RefCount==0);
+
+ if (prog == &_mesa_DummyProgram)
+ return;
+
+ if (prog->String)
+ free(prog->String);
+
+ _mesa_free_instructions(prog->Instructions, prog->NumInstructions);
+
+ if (prog->Parameters) {
+ _mesa_free_parameter_list(prog->Parameters);
+ }
+ if (prog->Varying) {
+ _mesa_free_parameter_list(prog->Varying);
+ }
+ if (prog->Attributes) {
+ _mesa_free_parameter_list(prog->Attributes);
+ }
+
+ free(prog);
+}
+
+
+/**
+ * Return the gl_program object for a given ID.
+ * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of
+ * casts elsewhere.
+ */
+struct gl_program *
+_mesa_lookup_program(struct gl_context *ctx, GLuint id)
+{
+ if (id)
+ return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id);
+ else
+ return NULL;
+}
+
+
+/**
+ * Reference counting for vertex/fragment programs
+ */
+void
+_mesa_reference_program(struct gl_context *ctx,
+ struct gl_program **ptr,
+ struct gl_program *prog)
+{
+ assert(ptr);
+ if (*ptr && prog) {
+ /* sanity check */
+ if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB)
+ ASSERT(prog->Target == GL_VERTEX_PROGRAM_ARB);
+ else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB)
+ ASSERT(prog->Target == GL_FRAGMENT_PROGRAM_ARB ||
+ prog->Target == GL_FRAGMENT_PROGRAM_NV);
+ else if ((*ptr)->Target == MESA_GEOMETRY_PROGRAM)
+ ASSERT(prog->Target == MESA_GEOMETRY_PROGRAM);
+ }
+ if (*ptr == prog) {
+ return; /* no change */
+ }
+ if (*ptr) {
+ GLboolean deleteFlag;
+
+ /*_glthread_LOCK_MUTEX((*ptr)->Mutex);*/
+#if 0
+ printf("Program %p ID=%u Target=%s Refcount-- to %d\n",
+ *ptr, (*ptr)->Id,
+ ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB ? "VP" :
+ ((*ptr)->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")),
+ (*ptr)->RefCount - 1);
+#endif
+ ASSERT((*ptr)->RefCount > 0);
+ (*ptr)->RefCount--;
+
+ deleteFlag = ((*ptr)->RefCount == 0);
+ /*_glthread_UNLOCK_MUTEX((*ptr)->Mutex);*/
+
+ if (deleteFlag) {
+ ASSERT(ctx);
+ ctx->Driver.DeleteProgram(ctx, *ptr);
+ }
+
+ *ptr = NULL;
+ }
+
+ assert(!*ptr);
+ if (prog) {
+ /*_glthread_LOCK_MUTEX(prog->Mutex);*/
+ prog->RefCount++;
+#if 0
+ printf("Program %p ID=%u Target=%s Refcount++ to %d\n",
+ prog, prog->Id,
+ (prog->Target == GL_VERTEX_PROGRAM_ARB ? "VP" :
+ (prog->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")),
+ prog->RefCount);
+#endif
+ /*_glthread_UNLOCK_MUTEX(prog->Mutex);*/
+ }
+
+ *ptr = prog;
+}
+
+
+/**
+ * Return a copy of a program.
+ * XXX Problem here if the program object is actually OO-derivation
+ * made by a device driver.
+ */
+struct gl_program *
+_mesa_clone_program(struct gl_context *ctx, const struct gl_program *prog)
+{
+ struct gl_program *clone;
+
+ clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id);
+ if (!clone)
+ return NULL;
+
+ assert(clone->Target == prog->Target);
+ assert(clone->RefCount == 1);
+
+ clone->String = (GLubyte *) _mesa_strdup((char *) prog->String);
+ clone->Format = prog->Format;
+ clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions);
+ if (!clone->Instructions) {
+ _mesa_reference_program(ctx, &clone, NULL);
+ return NULL;
+ }
+ _mesa_copy_instructions(clone->Instructions, prog->Instructions,
+ prog->NumInstructions);
+ clone->InputsRead = prog->InputsRead;
+ clone->OutputsWritten = prog->OutputsWritten;
+ clone->SamplersUsed = prog->SamplersUsed;
+ clone->ShadowSamplers = prog->ShadowSamplers;
+ memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed));
+
+ if (prog->Parameters)
+ clone->Parameters = _mesa_clone_parameter_list(prog->Parameters);
+ memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
+ if (prog->Varying)
+ clone->Varying = _mesa_clone_parameter_list(prog->Varying);
+ if (prog->Attributes)
+ clone->Attributes = _mesa_clone_parameter_list(prog->Attributes);
+ memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams));
+ clone->IndirectRegisterFiles = prog->IndirectRegisterFiles;
+ clone->NumInstructions = prog->NumInstructions;
+ clone->NumTemporaries = prog->NumTemporaries;
+ clone->NumParameters = prog->NumParameters;
+ clone->NumAttributes = prog->NumAttributes;
+ clone->NumAddressRegs = prog->NumAddressRegs;
+ clone->NumNativeInstructions = prog->NumNativeInstructions;
+ clone->NumNativeTemporaries = prog->NumNativeTemporaries;
+ clone->NumNativeParameters = prog->NumNativeParameters;
+ clone->NumNativeAttributes = prog->NumNativeAttributes;
+ clone->NumNativeAddressRegs = prog->NumNativeAddressRegs;
+ clone->NumAluInstructions = prog->NumAluInstructions;
+ clone->NumTexInstructions = prog->NumTexInstructions;
+ clone->NumTexIndirections = prog->NumTexIndirections;
+ clone->NumNativeAluInstructions = prog->NumNativeAluInstructions;
+ clone->NumNativeTexInstructions = prog->NumNativeTexInstructions;
+ clone->NumNativeTexIndirections = prog->NumNativeTexIndirections;
+
+ switch (prog->Target) {
+ case GL_VERTEX_PROGRAM_ARB:
+ {
+ const struct gl_vertex_program *vp
+ = (const struct gl_vertex_program *) prog;
+ struct gl_vertex_program *vpc = (struct gl_vertex_program *) clone;
+ vpc->IsPositionInvariant = vp->IsPositionInvariant;
+ vpc->IsNVProgram = vp->IsNVProgram;
+ }
+ break;
+ case GL_FRAGMENT_PROGRAM_ARB:
+ {
+ const struct gl_fragment_program *fp
+ = (const struct gl_fragment_program *) prog;
+ struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone;
+ fpc->FogOption = fp->FogOption;
+ fpc->UsesKill = fp->UsesKill;
+ fpc->OriginUpperLeft = fp->OriginUpperLeft;
+ fpc->PixelCenterInteger = fp->PixelCenterInteger;
+ }
+ break;
+ case MESA_GEOMETRY_PROGRAM:
+ {
+ const struct gl_geometry_program *gp
+ = (const struct gl_geometry_program *) prog;
+ struct gl_geometry_program *gpc = (struct gl_geometry_program *) clone;
+ gpc->VerticesOut = gp->VerticesOut;
+ gpc->InputType = gp->InputType;
+ gpc->OutputType = gp->OutputType;
+ }
+ break;
+ default:
+ _mesa_problem(NULL, "Unexpected target in _mesa_clone_program");
+ }
+
+ return clone;
+}
+
+
+/**
+ * Insert 'count' NOP instructions at 'start' in the given program.
+ * Adjust branch targets accordingly.
+ */
+GLboolean
+_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count)
+{
+ const GLuint origLen = prog->NumInstructions;
+ const GLuint newLen = origLen + count;
+ struct prog_instruction *newInst;
+ GLuint i;
+
+ /* adjust branches */
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ if (inst->BranchTarget > 0) {
+ if ((GLuint)inst->BranchTarget >= start) {
+ inst->BranchTarget += count;
+ }
+ }
+ }
+
+ /* Alloc storage for new instructions */
+ newInst = _mesa_alloc_instructions(newLen);
+ if (!newInst) {
+ return GL_FALSE;
+ }
+
+ /* Copy 'start' instructions into new instruction buffer */
+ _mesa_copy_instructions(newInst, prog->Instructions, start);
+
+ /* init the new instructions */
+ _mesa_init_instructions(newInst + start, count);
+
+ /* Copy the remaining/tail instructions to new inst buffer */
+ _mesa_copy_instructions(newInst + start + count,
+ prog->Instructions + start,
+ origLen - start);
+
+ /* free old instructions */
+ _mesa_free_instructions(prog->Instructions, origLen);
+
+ /* install new instructions */
+ prog->Instructions = newInst;
+ prog->NumInstructions = newLen;
+
+ return GL_TRUE;
+}
+
+/**
+ * Delete 'count' instructions at 'start' in the given program.
+ * Adjust branch targets accordingly.
+ */
+GLboolean
+_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count)
+{
+ const GLuint origLen = prog->NumInstructions;
+ const GLuint newLen = origLen - count;
+ struct prog_instruction *newInst;
+ GLuint i;
+
+ /* adjust branches */
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ if (inst->BranchTarget > 0) {
+ if (inst->BranchTarget > (GLint) start) {
+ inst->BranchTarget -= count;
+ }
+ }
+ }
+
+ /* Alloc storage for new instructions */
+ newInst = _mesa_alloc_instructions(newLen);
+ if (!newInst) {
+ return GL_FALSE;
+ }
+
+ /* Copy 'start' instructions into new instruction buffer */
+ _mesa_copy_instructions(newInst, prog->Instructions, start);
+
+ /* Copy the remaining/tail instructions to new inst buffer */
+ _mesa_copy_instructions(newInst + start,
+ prog->Instructions + start + count,
+ newLen - start);
+
+ /* free old instructions */
+ _mesa_free_instructions(prog->Instructions, origLen);
+
+ /* install new instructions */
+ prog->Instructions = newInst;
+ prog->NumInstructions = newLen;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Search instructions for registers that match (oldFile, oldIndex),
+ * replacing them with (newFile, newIndex).
+ */
+static void
+replace_registers(struct prog_instruction *inst, GLuint numInst,
+ GLuint oldFile, GLuint oldIndex,
+ GLuint newFile, GLuint newIndex)
+{
+ GLuint i, j;
+ for (i = 0; i < numInst; i++) {
+ /* src regs */
+ for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) {
+ if (inst[i].SrcReg[j].File == oldFile &&
+ inst[i].SrcReg[j].Index == oldIndex) {
+ inst[i].SrcReg[j].File = newFile;
+ inst[i].SrcReg[j].Index = newIndex;
+ }
+ }
+ /* dst reg */
+ if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) {
+ inst[i].DstReg.File = newFile;
+ inst[i].DstReg.Index = newIndex;
+ }
+ }
+}
+
+
+/**
+ * Search instructions for references to program parameters. When found,
+ * increment the parameter index by 'offset'.
+ * Used when combining programs.
+ */
+static void
+adjust_param_indexes(struct prog_instruction *inst, GLuint numInst,
+ GLuint offset)
+{
+ GLuint i, j;
+ for (i = 0; i < numInst; i++) {
+ for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) {
+ GLuint f = inst[i].SrcReg[j].File;
+ if (f == PROGRAM_CONSTANT ||
+ f == PROGRAM_UNIFORM ||
+ f == PROGRAM_STATE_VAR) {
+ inst[i].SrcReg[j].Index += offset;
+ }
+ }
+ }
+}
+
+
+/**
+ * Combine two programs into one. Fix instructions so the outputs of
+ * the first program go to the inputs of the second program.
+ */
+struct gl_program *
+_mesa_combine_programs(struct gl_context *ctx,
+ const struct gl_program *progA,
+ const struct gl_program *progB)
+{
+ struct prog_instruction *newInst;
+ struct gl_program *newProg;
+ const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */
+ const GLuint lenB = progB->NumInstructions;
+ const GLuint numParamsA = _mesa_num_parameters(progA->Parameters);
+ const GLuint newLength = lenA + lenB;
+ GLboolean usedTemps[MAX_PROGRAM_TEMPS];
+ GLuint firstTemp = 0;
+ GLbitfield inputsB;
+ GLuint i;
+
+ ASSERT(progA->Target == progB->Target);
+
+ newInst = _mesa_alloc_instructions(newLength);
+ if (!newInst)
+ return GL_FALSE;
+
+ _mesa_copy_instructions(newInst, progA->Instructions, lenA);
+ _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB);
+
+ /* adjust branch / instruction addresses for B's instructions */
+ for (i = 0; i < lenB; i++) {
+ newInst[lenA + i].BranchTarget += lenA;
+ }
+
+ newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0);
+ newProg->Instructions = newInst;
+ newProg->NumInstructions = newLength;
+
+ /* find used temp regs (we may need new temps below) */
+ _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY,
+ usedTemps, MAX_PROGRAM_TEMPS);
+
+ if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) {
+ struct gl_fragment_program *fprogA, *fprogB, *newFprog;
+ GLbitfield progB_inputsRead = progB->InputsRead;
+ GLint progB_colorFile, progB_colorIndex;
+
+ fprogA = (struct gl_fragment_program *) progA;
+ fprogB = (struct gl_fragment_program *) progB;
+ newFprog = (struct gl_fragment_program *) newProg;
+
+ newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill;
+
+ /* We'll do a search and replace for instances
+ * of progB_colorFile/progB_colorIndex below...
+ */
+ progB_colorFile = PROGRAM_INPUT;
+ progB_colorIndex = FRAG_ATTRIB_COL0;
+
+ /*
+ * The fragment program may get color from a state var rather than
+ * a fragment input (vertex output) if it's constant.
+ * See the texenvprogram.c code.
+ * So, search the program's parameter list now to see if the program
+ * gets color from a state var instead of a conventional fragment
+ * input register.
+ */
+ for (i = 0; i < progB->Parameters->NumParameters; i++) {
+ struct gl_program_parameter *p = &progB->Parameters->Parameters[i];
+ if (p->Type == PROGRAM_STATE_VAR &&
+ p->StateIndexes[0] == STATE_INTERNAL &&
+ p->StateIndexes[1] == STATE_CURRENT_ATTRIB &&
+ (int) p->StateIndexes[2] == (int) VERT_ATTRIB_COLOR0) {
+ progB_inputsRead |= FRAG_BIT_COL0;
+ progB_colorFile = PROGRAM_STATE_VAR;
+ progB_colorIndex = i;
+ break;
+ }
+ }
+
+ /* Connect color outputs of fprogA to color inputs of fprogB, via a
+ * new temporary register.
+ */
+ if ((progA->OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) &&
+ (progB_inputsRead & FRAG_BIT_COL0)) {
+ GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS,
+ firstTemp);
+ if (tempReg < 0) {
+ _mesa_problem(ctx, "No free temp regs found in "
+ "_mesa_combine_programs(), using 31");
+ tempReg = 31;
+ }
+ firstTemp = tempReg + 1;
+
+ /* replace writes to result.color[0] with tempReg */
+ replace_registers(newInst, lenA,
+ PROGRAM_OUTPUT, FRAG_RESULT_COLOR,
+ PROGRAM_TEMPORARY, tempReg);
+ /* replace reads from the input color with tempReg */
+ replace_registers(newInst + lenA, lenB,
+ progB_colorFile, progB_colorIndex, /* search for */
+ PROGRAM_TEMPORARY, tempReg /* replace with */ );
+ }
+
+ /* compute combined program's InputsRead */
+ inputsB = progB_inputsRead;
+ if (progA->OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) {
+ inputsB &= ~(1 << FRAG_ATTRIB_COL0);
+ }
+ newProg->InputsRead = progA->InputsRead | inputsB;
+ newProg->OutputsWritten = progB->OutputsWritten;
+ newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed;
+ }
+ else {
+ /* vertex program */
+ assert(0); /* XXX todo */
+ }
+
+ /*
+ * Merge parameters (uniforms, constants, etc)
+ */
+ newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters,
+ progB->Parameters);
+
+ adjust_param_indexes(newInst + lenA, lenB, numParamsA);
+
+
+ return newProg;
+}
+
+
+/**
+ * Populate the 'used' array with flags indicating which registers (TEMPs,
+ * INPUTs, OUTPUTs, etc, are used by the given program.
+ * \param file type of register to scan for
+ * \param used returns true/false flags for in use / free
+ * \param usedSize size of the 'used' array
+ */
+void
+_mesa_find_used_registers(const struct gl_program *prog,
+ gl_register_file file,
+ GLboolean used[], GLuint usedSize)
+{
+ GLuint i, j;
+
+ memset(used, 0, usedSize);
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ const struct prog_instruction *inst = prog->Instructions + i;
+ const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
+
+ if (inst->DstReg.File == file) {
+ ASSERT(inst->DstReg.Index < usedSize);
+ if(inst->DstReg.Index < usedSize)
+ used[inst->DstReg.Index] = GL_TRUE;
+ }
+
+ for (j = 0; j < n; j++) {
+ if (inst->SrcReg[j].File == file) {
+ ASSERT(inst->SrcReg[j].Index < usedSize);
+ if(inst->SrcReg[j].Index < usedSize)
+ used[inst->SrcReg[j].Index] = GL_TRUE;
+ }
+ }
+ }
+}
+
+
+/**
+ * Scan the given 'used' register flag array for the first entry
+ * that's >= firstReg.
+ * \param used vector of flags indicating registers in use (as returned
+ * by _mesa_find_used_registers())
+ * \param usedSize size of the 'used' array
+ * \param firstReg first register to start searching at
+ * \return index of unused register, or -1 if none.
+ */
+GLint
+_mesa_find_free_register(const GLboolean used[],
+ GLuint usedSize, GLuint firstReg)
+{
+ GLuint i;
+
+ assert(firstReg < usedSize);
+
+ for (i = firstReg; i < usedSize; i++)
+ if (!used[i])
+ return i;
+
+ return -1;
+}
+
+
+
+/**
+ * Check if the given register index is valid (doesn't exceed implementation-
+ * dependent limits).
+ * \return GL_TRUE if OK, GL_FALSE if bad index
+ */
+GLboolean
+_mesa_valid_register_index(const struct gl_context *ctx,
+ gl_shader_type shaderType,
+ gl_register_file file, GLint index)
+{
+ const struct gl_program_constants *c;
+
+ switch (shaderType) {
+ case MESA_SHADER_VERTEX:
+ c = &ctx->Const.VertexProgram;
+ break;
+ case MESA_SHADER_FRAGMENT:
+ c = &ctx->Const.FragmentProgram;
+ break;
+ case MESA_SHADER_GEOMETRY:
+ c = &ctx->Const.GeometryProgram;
+ break;
+ default:
+ _mesa_problem(ctx,
+ "unexpected shader type in _mesa_valid_register_index()");
+ return GL_FALSE;
+ }
+
+ switch (file) {
+ case PROGRAM_UNDEFINED:
+ return GL_TRUE; /* XXX or maybe false? */
+
+ case PROGRAM_TEMPORARY:
+ return index >= 0 && index < c->MaxTemps;
+
+ case PROGRAM_ENV_PARAM:
+ return index >= 0 && index < c->MaxEnvParams;
+
+ case PROGRAM_LOCAL_PARAM:
+ return index >= 0 && index < c->MaxLocalParams;
+
+ case PROGRAM_NAMED_PARAM:
+ return index >= 0 && index < c->MaxParameters;
+
+ case PROGRAM_UNIFORM:
+ case PROGRAM_STATE_VAR:
+ /* aka constant buffer */
+ return index >= 0 && index < c->MaxUniformComponents / 4;
+
+ case PROGRAM_CONSTANT:
+ /* constant buffer w/ possible relative negative addressing */
+ return (index > (int) c->MaxUniformComponents / -4 &&
+ index < c->MaxUniformComponents / 4);
+
+ case PROGRAM_INPUT:
+ if (index < 0)
+ return GL_FALSE;
+
+ switch (shaderType) {
+ case MESA_SHADER_VERTEX:
+ return index < VERT_ATTRIB_GENERIC0 + c->MaxAttribs;
+ case MESA_SHADER_FRAGMENT:
+ return index < FRAG_ATTRIB_VAR0 + ctx->Const.MaxVarying;
+ case MESA_SHADER_GEOMETRY:
+ return index < GEOM_ATTRIB_VAR0 + ctx->Const.MaxVarying;
+ default:
+ return GL_FALSE;
+ }
+
+ case PROGRAM_OUTPUT:
+ if (index < 0)
+ return GL_FALSE;
+
+ switch (shaderType) {
+ case MESA_SHADER_VERTEX:
+ return index < VERT_RESULT_VAR0 + ctx->Const.MaxVarying;
+ case MESA_SHADER_FRAGMENT:
+ return index < FRAG_RESULT_DATA0 + ctx->Const.MaxDrawBuffers;
+ case MESA_SHADER_GEOMETRY:
+ return index < GEOM_RESULT_VAR0 + ctx->Const.MaxVarying;
+ default:
+ return GL_FALSE;
+ }
+
+ case PROGRAM_ADDRESS:
+ return index >= 0 && index < c->MaxAddressRegs;
+
+ default:
+ _mesa_problem(ctx,
+ "unexpected register file in _mesa_valid_register_index()");
+ return GL_FALSE;
+ }
+}
+
+
+
+/**
+ * "Post-process" a GPU program. This is intended to be used for debugging.
+ * Example actions include no-op'ing instructions or changing instruction
+ * behaviour.
+ */
+void
+_mesa_postprocess_program(struct gl_context *ctx, struct gl_program *prog)
+{
+ static const GLfloat white[4] = { 0.5, 0.5, 0.5, 0.5 };
+ GLuint i;
+ GLuint whiteSwizzle;
+ GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters,
+ white, 4, &whiteSwizzle);
+
+ (void) whiteIndex;
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
+
+ (void) n;
+
+ if (_mesa_is_tex_instruction(inst->Opcode)) {
+#if 0
+ /* replace TEX/TXP/TXB with MOV */
+ inst->Opcode = OPCODE_MOV;
+ inst->DstReg.WriteMask = WRITEMASK_XYZW;
+ inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
+ inst->SrcReg[0].Negate = NEGATE_NONE;
+#endif
+
+#if 0
+ /* disable shadow texture mode */
+ inst->TexShadow = 0;
+#endif
+ }
+
+ if (inst->Opcode == OPCODE_TXP) {
+#if 0
+ inst->Opcode = OPCODE_MOV;
+ inst->DstReg.WriteMask = WRITEMASK_XYZW;
+ inst->SrcReg[0].File = PROGRAM_CONSTANT;
+ inst->SrcReg[0].Index = whiteIndex;
+ inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
+ inst->SrcReg[0].Negate = NEGATE_NONE;
+#endif
+#if 0
+ inst->TexShadow = 0;
+#endif
+#if 0
+ inst->Opcode = OPCODE_TEX;
+ inst->TexShadow = 0;
+#endif
+ }
+
+ }
+}
diff --git a/mesalib/src/mesa/state_tracker/st_atom_pixeltransfer.c b/mesalib/src/mesa/state_tracker/st_atom_pixeltransfer.c
index 98be6ab75..9557adc2d 100644
--- a/mesalib/src/mesa/state_tracker/st_atom_pixeltransfer.c
+++ b/mesalib/src/mesa/state_tracker/st_atom_pixeltransfer.c
@@ -1,354 +1,354 @@
-/**************************************************************************
- *
- * 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.
- *
- **************************************************************************/
-
-/*
- * Generate fragment programs to implement pixel transfer ops, such as
- * scale/bias, colortable, convolution...
- *
- * Authors:
- * Brian Paul
- */
-
-#include "main/imports.h"
-#include "main/image.h"
-#include "main/macros.h"
-#include "program/program.h"
-#include "program/prog_cache.h"
-#include "program/prog_instruction.h"
-#include "program/prog_parameter.h"
-#include "program/prog_print.h"
-
-#include "st_context.h"
-#include "st_format.h"
-#include "st_texture.h"
-
-#include "pipe/p_screen.h"
-#include "pipe/p_context.h"
-#include "util/u_inlines.h"
-#include "util/u_pack_color.h"
-
-
-struct state_key
-{
- GLuint scaleAndBias:1;
- GLuint pixelMaps:1;
-
-#if 0
- GLfloat Maps[3][256][4];
- int NumMaps;
- GLint NumStages;
- pipeline_stage Stages[STAGE_MAX];
- GLboolean StagesUsed[STAGE_MAX];
- GLfloat Scale1[4], Bias1[4];
- GLfloat Scale2[4], Bias2[4];
-#endif
-};
-
-static void
-make_state_key(struct gl_context *ctx, struct state_key *key)
-{
- memset(key, 0, sizeof(*key));
-
- if (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->scaleAndBias = 1;
- }
-
- key->pixelMaps = ctx->Pixel.MapColorFlag;
-}
-
-
-static struct pipe_resource *
-create_color_map_texture(struct gl_context *ctx)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct pipe_resource *pt;
- enum pipe_format format;
- const uint texSize = 256; /* simple, and usually perfect */
-
- /* find an RGBA texture format */
- format = st_choose_format(pipe->screen, GL_RGBA,
- PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW);
-
- /* create texture for color map/table */
- pt = st_texture_create(st, PIPE_TEXTURE_2D, format, 0,
- texSize, texSize, 1, 1, PIPE_BIND_SAMPLER_VIEW);
- return pt;
-}
-
-
-/**
- * Update the pixelmap texture with the contents of the R/G/B/A pixel maps.
- */
-static void
-load_color_map_texture(struct gl_context *ctx, struct pipe_resource *pt)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct pipe_transfer *transfer;
- const GLuint rSize = ctx->PixelMaps.RtoR.Size;
- const GLuint gSize = ctx->PixelMaps.GtoG.Size;
- const GLuint bSize = ctx->PixelMaps.BtoB.Size;
- const GLuint aSize = ctx->PixelMaps.AtoA.Size;
- const uint texSize = pt->width0;
- uint *dest;
- uint i, j;
-
- transfer = pipe_get_transfer(st_context(ctx)->pipe,
- pt, 0, 0, PIPE_TRANSFER_WRITE,
- 0, 0, texSize, texSize);
- dest = (uint *) pipe_transfer_map(pipe, transfer);
-
- /* Pack four 1D maps into a 2D texture:
- * R map is placed horizontally, indexed by S, in channel 0
- * G map is placed vertically, indexed by T, in channel 1
- * B map is placed horizontally, indexed by S, in channel 2
- * A map is placed vertically, indexed by T, in channel 3
- */
- for (i = 0; i < texSize; i++) {
- for (j = 0; j < texSize; j++) {
- union util_color uc;
- int k = (i * texSize + j);
- ubyte r = ctx->PixelMaps.RtoR.Map8[j * rSize / texSize];
- ubyte g = ctx->PixelMaps.GtoG.Map8[i * gSize / texSize];
- ubyte b = ctx->PixelMaps.BtoB.Map8[j * bSize / texSize];
- ubyte a = ctx->PixelMaps.AtoA.Map8[i * aSize / texSize];
- util_pack_color_ub(r, g, b, a, pt->format, &uc);
- *(dest + k) = uc.ui;
- }
- }
-
- pipe_transfer_unmap(pipe, transfer);
- pipe->transfer_destroy(pipe, transfer);
-}
-
-
-
-#define MAX_INST 100
-
-/**
- * Returns a fragment program which implements the current pixel transfer ops.
- */
-static struct gl_fragment_program *
-get_pixel_transfer_program(struct gl_context *ctx, const struct state_key *key)
-{
- struct st_context *st = st_context(ctx);
- struct prog_instruction inst[MAX_INST];
- struct gl_program_parameter_list *params;
- struct gl_fragment_program *fp;
- GLuint ic = 0;
- const GLuint colorTemp = 0;
-
- fp = (struct gl_fragment_program *)
- ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
- if (!fp)
- return NULL;
-
- params = _mesa_new_parameter_list();
-
- /*
- * Get initial pixel color from the texture.
- * TEX colorTemp, fragment.texcoord[0], texture[0], 2D;
- */
- _mesa_init_instructions(inst + ic, 1);
- inst[ic].Opcode = OPCODE_TEX;
- inst[ic].DstReg.File = PROGRAM_TEMPORARY;
- inst[ic].DstReg.Index = colorTemp;
- inst[ic].SrcReg[0].File = PROGRAM_INPUT;
- inst[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
- inst[ic].TexSrcUnit = 0;
- inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
- ic++;
- fp->Base.InputsRead = (1 << FRAG_ATTRIB_TEX0);
- fp->Base.OutputsWritten = (1 << FRAG_RESULT_COLOR);
- fp->Base.SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */
-
- if (key->scaleAndBias) {
- static const gl_state_index scale_state[STATE_LENGTH] =
- { STATE_INTERNAL, STATE_PT_SCALE, 0, 0, 0 };
- static const gl_state_index bias_state[STATE_LENGTH] =
- { STATE_INTERNAL, STATE_PT_BIAS, 0, 0, 0 };
- GLfloat scale[4], bias[4];
- GLint scale_p, bias_p;
-
- scale[0] = ctx->Pixel.RedScale;
- scale[1] = ctx->Pixel.GreenScale;
- scale[2] = ctx->Pixel.BlueScale;
- scale[3] = ctx->Pixel.AlphaScale;
- bias[0] = ctx->Pixel.RedBias;
- bias[1] = ctx->Pixel.GreenBias;
- bias[2] = ctx->Pixel.BlueBias;
- bias[3] = ctx->Pixel.AlphaBias;
-
- scale_p = _mesa_add_state_reference(params, scale_state);
- bias_p = _mesa_add_state_reference(params, bias_state);
-
- /* MAD colorTemp, colorTemp, scale, bias; */
- _mesa_init_instructions(inst + ic, 1);
- inst[ic].Opcode = OPCODE_MAD;
- inst[ic].DstReg.File = PROGRAM_TEMPORARY;
- inst[ic].DstReg.Index = colorTemp;
- inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
- inst[ic].SrcReg[0].Index = colorTemp;
- inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR;
- inst[ic].SrcReg[1].Index = scale_p;
- inst[ic].SrcReg[2].File = PROGRAM_STATE_VAR;
- inst[ic].SrcReg[2].Index = bias_p;
- ic++;
- }
-
- if (key->pixelMaps) {
- const GLuint temp = 1;
-
- /* create the colormap/texture now if not already done */
- if (!st->pixel_xfer.pixelmap_texture) {
- st->pixel_xfer.pixelmap_texture = create_color_map_texture(ctx);
- st->pixel_xfer.pixelmap_sampler_view =
- st_create_texture_sampler_view(st->pipe,
- st->pixel_xfer.pixelmap_texture);
- }
-
- /* with a little effort, we can do four pixel map look-ups with
- * two TEX instructions:
- */
-
- /* TEX temp.rg, colorTemp.rgba, texture[1], 2D; */
- _mesa_init_instructions(inst + ic, 1);
- inst[ic].Opcode = OPCODE_TEX;
- inst[ic].DstReg.File = PROGRAM_TEMPORARY;
- inst[ic].DstReg.Index = temp;
- inst[ic].DstReg.WriteMask = WRITEMASK_XY; /* write R,G */
- inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
- inst[ic].SrcReg[0].Index = colorTemp;
- inst[ic].TexSrcUnit = 1;
- inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
- ic++;
-
- /* TEX temp.ba, colorTemp.baba, texture[1], 2D; */
- _mesa_init_instructions(inst + ic, 1);
- inst[ic].Opcode = OPCODE_TEX;
- inst[ic].DstReg.File = PROGRAM_TEMPORARY;
- inst[ic].DstReg.Index = temp;
- inst[ic].DstReg.WriteMask = WRITEMASK_ZW; /* write B,A */
- inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
- inst[ic].SrcReg[0].Index = colorTemp;
- inst[ic].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W,
- SWIZZLE_Z, SWIZZLE_W);
- inst[ic].TexSrcUnit = 1;
- inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
- ic++;
-
- /* MOV colorTemp, temp; */
- _mesa_init_instructions(inst + ic, 1);
- inst[ic].Opcode = OPCODE_MOV;
- inst[ic].DstReg.File = PROGRAM_TEMPORARY;
- inst[ic].DstReg.Index = colorTemp;
- inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
- inst[ic].SrcReg[0].Index = temp;
- ic++;
-
- fp->Base.SamplersUsed |= (1 << 1); /* sampler 1 is used */
- }
-
- /* Modify last instruction's dst reg to write to result.color */
- {
- struct prog_instruction *last = &inst[ic - 1];
- last->DstReg.File = PROGRAM_OUTPUT;
- last->DstReg.Index = FRAG_RESULT_COLOR;
- }
-
- /* END; */
- _mesa_init_instructions(inst + ic, 1);
- inst[ic].Opcode = OPCODE_END;
- ic++;
-
- assert(ic <= MAX_INST);
-
-
- fp->Base.Instructions = _mesa_alloc_instructions(ic);
- if (!fp->Base.Instructions) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY,
- "generating pixel transfer program");
- return NULL;
- }
-
- _mesa_copy_instructions(fp->Base.Instructions, inst, ic);
- fp->Base.NumInstructions = ic;
- fp->Base.Parameters = params;
-
-#if 0
- printf("========= pixel transfer prog\n");
- _mesa_print_program(&fp->Base);
- _mesa_print_parameter_list(fp->Base.Parameters);
-#endif
-
- return fp;
-}
-
-
-
-/**
- * Update st->pixel_xfer.program in response to new pixel-transfer state.
- */
-static void
-update_pixel_transfer(struct st_context *st)
-{
- struct gl_context *ctx = st->ctx;
- struct state_key key;
- struct gl_fragment_program *fp;
-
- make_state_key(st->ctx, &key);
-
- fp = (struct gl_fragment_program *)
- _mesa_search_program_cache(st->pixel_xfer.cache, &key, sizeof(key));
- if (!fp) {
- fp = get_pixel_transfer_program(st->ctx, &key);
- _mesa_program_cache_insert(st->ctx, st->pixel_xfer.cache,
- &key, sizeof(key), &fp->Base);
- }
-
- if (ctx->Pixel.MapColorFlag) {
- load_color_map_texture(ctx, st->pixel_xfer.pixelmap_texture);
- }
- st->pixel_xfer.pixelmap_enabled = ctx->Pixel.MapColorFlag;
-
- st->pixel_xfer.program = (struct st_fragment_program *) fp;
-}
-
-
-
-const struct st_tracked_state st_update_pixel_transfer = {
- "st_update_pixel_transfer", /* name */
- { /* dirty */
- _NEW_PIXEL, /* mesa */
- 0, /* st */
- },
- update_pixel_transfer /* update */
-};
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Generate fragment programs to implement pixel transfer ops, such as
+ * scale/bias, colortable, convolution...
+ *
+ * Authors:
+ * Brian Paul
+ */
+
+#include "main/imports.h"
+#include "main/image.h"
+#include "main/macros.h"
+#include "program/program.h"
+#include "program/prog_cache.h"
+#include "program/prog_instruction.h"
+#include "program/prog_parameter.h"
+#include "program/prog_print.h"
+
+#include "st_context.h"
+#include "st_format.h"
+#include "st_texture.h"
+
+#include "pipe/p_screen.h"
+#include "pipe/p_context.h"
+#include "util/u_inlines.h"
+#include "util/u_pack_color.h"
+
+
+struct state_key
+{
+ GLuint scaleAndBias:1;
+ GLuint pixelMaps:1;
+
+#if 0
+ GLfloat Maps[3][256][4];
+ int NumMaps;
+ GLint NumStages;
+ pipeline_stage Stages[STAGE_MAX];
+ GLboolean StagesUsed[STAGE_MAX];
+ GLfloat Scale1[4], Bias1[4];
+ GLfloat Scale2[4], Bias2[4];
+#endif
+};
+
+static void
+make_state_key(struct gl_context *ctx, struct state_key *key)
+{
+ memset(key, 0, sizeof(*key));
+
+ if (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->scaleAndBias = 1;
+ }
+
+ key->pixelMaps = ctx->Pixel.MapColorFlag;
+}
+
+
+static struct pipe_resource *
+create_color_map_texture(struct gl_context *ctx)
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_context *pipe = st->pipe;
+ struct pipe_resource *pt;
+ enum pipe_format format;
+ const uint texSize = 256; /* simple, and usually perfect */
+
+ /* find an RGBA texture format */
+ format = st_choose_format(pipe->screen, GL_RGBA,
+ PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW);
+
+ /* create texture for color map/table */
+ pt = st_texture_create(st, PIPE_TEXTURE_2D, format, 0,
+ texSize, texSize, 1, 1, PIPE_BIND_SAMPLER_VIEW);
+ return pt;
+}
+
+
+/**
+ * Update the pixelmap texture with the contents of the R/G/B/A pixel maps.
+ */
+static void
+load_color_map_texture(struct gl_context *ctx, struct pipe_resource *pt)
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_context *pipe = st->pipe;
+ struct pipe_transfer *transfer;
+ const GLuint rSize = ctx->PixelMaps.RtoR.Size;
+ const GLuint gSize = ctx->PixelMaps.GtoG.Size;
+ const GLuint bSize = ctx->PixelMaps.BtoB.Size;
+ const GLuint aSize = ctx->PixelMaps.AtoA.Size;
+ const uint texSize = pt->width0;
+ uint *dest;
+ uint i, j;
+
+ transfer = pipe_get_transfer(st_context(ctx)->pipe,
+ pt, 0, 0, PIPE_TRANSFER_WRITE,
+ 0, 0, texSize, texSize);
+ dest = (uint *) pipe_transfer_map(pipe, transfer);
+
+ /* Pack four 1D maps into a 2D texture:
+ * R map is placed horizontally, indexed by S, in channel 0
+ * G map is placed vertically, indexed by T, in channel 1
+ * B map is placed horizontally, indexed by S, in channel 2
+ * A map is placed vertically, indexed by T, in channel 3
+ */
+ for (i = 0; i < texSize; i++) {
+ for (j = 0; j < texSize; j++) {
+ union util_color uc;
+ int k = (i * texSize + j);
+ ubyte r = ctx->PixelMaps.RtoR.Map8[j * rSize / texSize];
+ ubyte g = ctx->PixelMaps.GtoG.Map8[i * gSize / texSize];
+ ubyte b = ctx->PixelMaps.BtoB.Map8[j * bSize / texSize];
+ ubyte a = ctx->PixelMaps.AtoA.Map8[i * aSize / texSize];
+ util_pack_color_ub(r, g, b, a, pt->format, &uc);
+ *(dest + k) = uc.ui;
+ }
+ }
+
+ pipe_transfer_unmap(pipe, transfer);
+ pipe->transfer_destroy(pipe, transfer);
+}
+
+
+
+#define MAX_INST 100
+
+/**
+ * Returns a fragment program which implements the current pixel transfer ops.
+ */
+static struct gl_fragment_program *
+get_pixel_transfer_program(struct gl_context *ctx, const struct state_key *key)
+{
+ struct st_context *st = st_context(ctx);
+ struct prog_instruction inst[MAX_INST];
+ struct gl_program_parameter_list *params;
+ struct gl_fragment_program *fp;
+ GLuint ic = 0;
+ const GLuint colorTemp = 0;
+
+ fp = (struct gl_fragment_program *)
+ ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
+ if (!fp)
+ return NULL;
+
+ params = _mesa_new_parameter_list();
+
+ /*
+ * Get initial pixel color from the texture.
+ * TEX colorTemp, fragment.texcoord[0], texture[0], 2D;
+ */
+ _mesa_init_instructions(inst + ic, 1);
+ inst[ic].Opcode = OPCODE_TEX;
+ inst[ic].DstReg.File = PROGRAM_TEMPORARY;
+ inst[ic].DstReg.Index = colorTemp;
+ inst[ic].SrcReg[0].File = PROGRAM_INPUT;
+ inst[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
+ inst[ic].TexSrcUnit = 0;
+ inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
+ ic++;
+ fp->Base.InputsRead = (1 << FRAG_ATTRIB_TEX0);
+ fp->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR);
+ fp->Base.SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */
+
+ if (key->scaleAndBias) {
+ static const gl_state_index scale_state[STATE_LENGTH] =
+ { STATE_INTERNAL, STATE_PT_SCALE, 0, 0, 0 };
+ static const gl_state_index bias_state[STATE_LENGTH] =
+ { STATE_INTERNAL, STATE_PT_BIAS, 0, 0, 0 };
+ GLfloat scale[4], bias[4];
+ GLint scale_p, bias_p;
+
+ scale[0] = ctx->Pixel.RedScale;
+ scale[1] = ctx->Pixel.GreenScale;
+ scale[2] = ctx->Pixel.BlueScale;
+ scale[3] = ctx->Pixel.AlphaScale;
+ bias[0] = ctx->Pixel.RedBias;
+ bias[1] = ctx->Pixel.GreenBias;
+ bias[2] = ctx->Pixel.BlueBias;
+ bias[3] = ctx->Pixel.AlphaBias;
+
+ scale_p = _mesa_add_state_reference(params, scale_state);
+ bias_p = _mesa_add_state_reference(params, bias_state);
+
+ /* MAD colorTemp, colorTemp, scale, bias; */
+ _mesa_init_instructions(inst + ic, 1);
+ inst[ic].Opcode = OPCODE_MAD;
+ inst[ic].DstReg.File = PROGRAM_TEMPORARY;
+ inst[ic].DstReg.Index = colorTemp;
+ inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
+ inst[ic].SrcReg[0].Index = colorTemp;
+ inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR;
+ inst[ic].SrcReg[1].Index = scale_p;
+ inst[ic].SrcReg[2].File = PROGRAM_STATE_VAR;
+ inst[ic].SrcReg[2].Index = bias_p;
+ ic++;
+ }
+
+ if (key->pixelMaps) {
+ const GLuint temp = 1;
+
+ /* create the colormap/texture now if not already done */
+ if (!st->pixel_xfer.pixelmap_texture) {
+ st->pixel_xfer.pixelmap_texture = create_color_map_texture(ctx);
+ st->pixel_xfer.pixelmap_sampler_view =
+ st_create_texture_sampler_view(st->pipe,
+ st->pixel_xfer.pixelmap_texture);
+ }
+
+ /* with a little effort, we can do four pixel map look-ups with
+ * two TEX instructions:
+ */
+
+ /* TEX temp.rg, colorTemp.rgba, texture[1], 2D; */
+ _mesa_init_instructions(inst + ic, 1);
+ inst[ic].Opcode = OPCODE_TEX;
+ inst[ic].DstReg.File = PROGRAM_TEMPORARY;
+ inst[ic].DstReg.Index = temp;
+ inst[ic].DstReg.WriteMask = WRITEMASK_XY; /* write R,G */
+ inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
+ inst[ic].SrcReg[0].Index = colorTemp;
+ inst[ic].TexSrcUnit = 1;
+ inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
+ ic++;
+
+ /* TEX temp.ba, colorTemp.baba, texture[1], 2D; */
+ _mesa_init_instructions(inst + ic, 1);
+ inst[ic].Opcode = OPCODE_TEX;
+ inst[ic].DstReg.File = PROGRAM_TEMPORARY;
+ inst[ic].DstReg.Index = temp;
+ inst[ic].DstReg.WriteMask = WRITEMASK_ZW; /* write B,A */
+ inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
+ inst[ic].SrcReg[0].Index = colorTemp;
+ inst[ic].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W,
+ SWIZZLE_Z, SWIZZLE_W);
+ inst[ic].TexSrcUnit = 1;
+ inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
+ ic++;
+
+ /* MOV colorTemp, temp; */
+ _mesa_init_instructions(inst + ic, 1);
+ inst[ic].Opcode = OPCODE_MOV;
+ inst[ic].DstReg.File = PROGRAM_TEMPORARY;
+ inst[ic].DstReg.Index = colorTemp;
+ inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
+ inst[ic].SrcReg[0].Index = temp;
+ ic++;
+
+ fp->Base.SamplersUsed |= (1 << 1); /* sampler 1 is used */
+ }
+
+ /* Modify last instruction's dst reg to write to result.color */
+ {
+ struct prog_instruction *last = &inst[ic - 1];
+ last->DstReg.File = PROGRAM_OUTPUT;
+ last->DstReg.Index = FRAG_RESULT_COLOR;
+ }
+
+ /* END; */
+ _mesa_init_instructions(inst + ic, 1);
+ inst[ic].Opcode = OPCODE_END;
+ ic++;
+
+ assert(ic <= MAX_INST);
+
+
+ fp->Base.Instructions = _mesa_alloc_instructions(ic);
+ if (!fp->Base.Instructions) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY,
+ "generating pixel transfer program");
+ return NULL;
+ }
+
+ _mesa_copy_instructions(fp->Base.Instructions, inst, ic);
+ fp->Base.NumInstructions = ic;
+ fp->Base.Parameters = params;
+
+#if 0
+ printf("========= pixel transfer prog\n");
+ _mesa_print_program(&fp->Base);
+ _mesa_print_parameter_list(fp->Base.Parameters);
+#endif
+
+ return fp;
+}
+
+
+
+/**
+ * Update st->pixel_xfer.program in response to new pixel-transfer state.
+ */
+static void
+update_pixel_transfer(struct st_context *st)
+{
+ struct gl_context *ctx = st->ctx;
+ struct state_key key;
+ struct gl_fragment_program *fp;
+
+ make_state_key(st->ctx, &key);
+
+ fp = (struct gl_fragment_program *)
+ _mesa_search_program_cache(st->pixel_xfer.cache, &key, sizeof(key));
+ if (!fp) {
+ fp = get_pixel_transfer_program(st->ctx, &key);
+ _mesa_program_cache_insert(st->ctx, st->pixel_xfer.cache,
+ &key, sizeof(key), &fp->Base);
+ }
+
+ if (ctx->Pixel.MapColorFlag) {
+ load_color_map_texture(ctx, st->pixel_xfer.pixelmap_texture);
+ }
+ st->pixel_xfer.pixelmap_enabled = ctx->Pixel.MapColorFlag;
+
+ st->pixel_xfer.program = (struct st_fragment_program *) fp;
+}
+
+
+
+const struct st_tracked_state st_update_pixel_transfer = {
+ "st_update_pixel_transfer", /* name */
+ { /* dirty */
+ _NEW_PIXEL, /* mesa */
+ 0, /* st */
+ },
+ update_pixel_transfer /* update */
+};
diff --git a/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c b/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c
index 5c95eddd0..eccc20757 100644
--- a/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c
+++ b/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c
@@ -1,1488 +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/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)) {
- 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 |= BITFIELD64_BIT(FRAG_RESULT_DEPTH);
+ if (write_stencil)
+ p->OutputsWritten |= BITFIELD64_BIT(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)) {
+ 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_program.c b/mesalib/src/mesa/state_tracker/st_program.c
index fc1dfb3ef..0b1ad63af 100644
--- a/mesalib/src/mesa/state_tracker/st_program.c
+++ b/mesalib/src/mesa/state_tracker/st_program.c
@@ -798,7 +798,7 @@ st_translate_geometry_program(struct st_context *st,
* mapping and the semantic information for each output.
*/
for (attr = 0; attr < GEOM_RESULT_MAX; attr++) {
- if (stgp->Base.Base.OutputsWritten & (1 << attr)) {
+ if (stgp->Base.Base.OutputsWritten & BITFIELD64_BIT(attr)) {
GLuint slot;
slot = gs_num_outputs;