aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src')
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp6919
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.cpp1652
-rw-r--r--mesalib/src/mesa/drivers/dri/common/dri_util.c20
-rw-r--r--mesalib/src/mesa/drivers/dri/common/dri_util.h6
-rw-r--r--mesalib/src/mesa/drivers/dri/swrast/swrast.c1622
-rw-r--r--mesalib/src/mesa/drivers/windows/gdi/wmesa.c3
-rw-r--r--mesalib/src/mesa/drivers/windows/gldirect/dglcontext.c2
-rw-r--r--mesalib/src/mesa/main/blend.c16
-rw-r--r--mesalib/src/mesa/main/bufferobj.c13
-rw-r--r--mesalib/src/mesa/main/context.c3799
-rw-r--r--mesalib/src/mesa/main/context.h25
-rw-r--r--mesalib/src/mesa/main/depth.c6
-rw-r--r--mesalib/src/mesa/main/hint.c5
-rw-r--r--mesalib/src/mesa/main/lines.c6
-rw-r--r--mesalib/src/mesa/main/mtypes.h6757
-rw-r--r--mesalib/src/mesa/main/queryobj.c38
-rw-r--r--mesalib/src/mesa/main/shaderapi.c3873
-rw-r--r--mesalib/src/mesa/main/stencil.c24
-rw-r--r--mesalib/src/mesa/program/ir_to_mesa.cpp6501
-rw-r--r--mesalib/src/mesa/state_tracker/st_context.c2
-rw-r--r--mesalib/src/mesa/state_tracker/st_draw_feedback.c1
-rw-r--r--mesalib/src/mesa/state_tracker/st_program.c15
22 files changed, 15713 insertions, 15592 deletions
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp
index 75f28cd2c..27c4301a0 100644
--- a/mesalib/src/glsl/ast_to_hir.cpp
+++ b/mesalib/src/glsl/ast_to_hir.cpp
@@ -1,3456 +1,3463 @@
-/*
- * 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)
-{
- /* 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;
- }
-}
-
-
-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;
- if (decl->initializer != 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(ctx) 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 (this->type->qualifier.flags.q.constant
- || this->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",
- (this->type->qualifier.flags.q.constant)
- ? "const" : "uniform",
- decl->identifier);
- if (var->type->is_numeric()) {
- /* Reduce cascading errors. */
- var->constant_value = ir_constant::zero(ctx, 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(ctx, var->type);
- }
- }
- }
-
- if (rhs && !rhs->type->is_error()) {
- bool temp = var->read_only;
- if (this->type->qualifier.flags.q.constant)
- var->read_only = false;
-
- /* Never emit code to initialize a uniform.
- */
- const glsl_type *initializer_type;
- if (!this->type->qualifier.flags.q.uniform) {
- result = do_assignment(&initializer_instructions, state,
- lhs, rhs,
- this->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;
- }
- }
-
- /* 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);
- }
-
- /* 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))) {
-
- /* 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)) {
- YYLTYPE loc = this->get_location();
-
- _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)) {
- YYLTYPE loc = this->get_location();
-
- _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 {
- YYLTYPE loc = this->get_location();
- _mesa_glsl_error(&loc, state, "`%s' redeclared", decl->identifier);
- }
-
- continue;
- }
-
- /* By now, we know it's a new variable declaration (we didn't hit the
- * above "continue").
- *
- * 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 = (const glsl_type **)
- realloc(state->user_structures,
- sizeof(state->user_structures[0]) *
- (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)
+{
+ /* 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;
+ }
+}
+
+
+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;
+ if (decl->initializer != 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(ctx) 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 (this->type->qualifier.flags.q.constant
+ || this->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",
+ (this->type->qualifier.flags.q.constant)
+ ? "const" : "uniform",
+ decl->identifier);
+ if (var->type->is_numeric()) {
+ /* Reduce cascading errors. */
+ var->constant_value = ir_constant::zero(ctx, 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(ctx, var->type);
+ }
+ }
+ }
+
+ if (rhs && !rhs->type->is_error()) {
+ bool temp = var->read_only;
+ if (this->type->qualifier.flags.q.constant)
+ var->read_only = false;
+
+ /* Never emit code to initialize a uniform.
+ */
+ const glsl_type *initializer_type;
+ if (!this->type->qualifier.flags.q.uniform) {
+ result = do_assignment(&initializer_instructions, state,
+ lhs, rhs,
+ this->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;
+ }
+ }
+
+ /* 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);
+ }
+
+ /* 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))) {
+
+ /* 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)) {
+ YYLTYPE loc = this->get_location();
+
+ _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)) {
+ YYLTYPE loc = this->get_location();
+
+ _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 {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(&loc, state, "`%s' redeclared", decl->identifier);
+ }
+
+ continue;
+ }
+
+ /* By now, we know it's a new variable declaration (we didn't hit the
+ * above "continue").
+ *
+ * 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 = (const glsl_type **)
+ realloc(state->user_structures,
+ sizeof(state->user_structures[0]) *
+ (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_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp
index c2bb59b9c..81065640e 100644
--- a/mesalib/src/glsl/glsl_parser_extras.cpp
+++ b/mesalib/src/glsl/glsl_parser_extras.cpp
@@ -1,826 +1,826 @@
-/*
- * Copyright © 2008, 2009 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <assert.h>
-
-extern "C" {
-#include "main/core.h" /* for struct gl_context */
-}
-
-#include "ralloc.h"
-#include "ast.h"
-#include "glsl_parser_extras.h"
-#include "glsl_parser.h"
-#include "ir_optimization.h"
-#include "loop_analysis.h"
-
-_mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *ctx,
- GLenum target, void *mem_ctx)
-{
- switch (target) {
- case GL_VERTEX_SHADER: this->target = vertex_shader; break;
- case GL_FRAGMENT_SHADER: this->target = fragment_shader; break;
- case GL_GEOMETRY_SHADER: this->target = geometry_shader; break;
- }
-
- this->scanner = NULL;
- this->translation_unit.make_empty();
- this->symbols = new(mem_ctx) glsl_symbol_table;
- this->info_log = ralloc_strdup(mem_ctx, "");
- this->error = false;
- this->loop_or_switch_nesting = NULL;
-
- /* Set default language version and extensions */
- this->language_version = 110;
- this->es_shader = false;
- this->ARB_texture_rectangle_enable = true;
-
- /* OpenGL ES 2.0 has different defaults from desktop GL. */
- if (ctx->API == API_OPENGLES2) {
- this->language_version = 100;
- this->es_shader = true;
- this->ARB_texture_rectangle_enable = false;
- }
-
- this->extensions = &ctx->Extensions;
-
- this->Const.MaxLights = ctx->Const.MaxLights;
- this->Const.MaxClipPlanes = ctx->Const.MaxClipPlanes;
- this->Const.MaxTextureUnits = ctx->Const.MaxTextureUnits;
- this->Const.MaxTextureCoords = ctx->Const.MaxTextureCoordUnits;
- this->Const.MaxVertexAttribs = ctx->Const.VertexProgram.MaxAttribs;
- this->Const.MaxVertexUniformComponents = ctx->Const.VertexProgram.MaxUniformComponents;
- this->Const.MaxVaryingFloats = ctx->Const.MaxVarying * 4;
- this->Const.MaxVertexTextureImageUnits = ctx->Const.MaxVertexTextureImageUnits;
- this->Const.MaxCombinedTextureImageUnits = ctx->Const.MaxCombinedTextureImageUnits;
- this->Const.MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits;
- this->Const.MaxFragmentUniformComponents = ctx->Const.FragmentProgram.MaxUniformComponents;
-
- this->Const.MaxDrawBuffers = ctx->Const.MaxDrawBuffers;
-
- /* Note: Once the OpenGL 3.0 'forward compatible' context or the OpenGL 3.2
- * Core context is supported, this logic will need change. Older versions of
- * GLSL are no longer supported outside the compatibility contexts of 3.x.
- */
- this->Const.GLSL_100ES = (ctx->API == API_OPENGLES2)
- || ctx->Extensions.ARB_ES2_compatibility;
- this->Const.GLSL_110 = (ctx->API == API_OPENGL);
- this->Const.GLSL_120 = (ctx->API == API_OPENGL)
- && (ctx->Const.GLSLVersion >= 120);
- this->Const.GLSL_130 = (ctx->API == API_OPENGL)
- && (ctx->Const.GLSLVersion >= 130);
-
- const unsigned lowest_version =
- (ctx->API == API_OPENGLES2) || ctx->Extensions.ARB_ES2_compatibility
- ? 100 : 110;
- const unsigned highest_version =
- (ctx->API == API_OPENGL) ? ctx->Const.GLSLVersion : 100;
- char *supported = ralloc_strdup(this, "");
-
- for (unsigned ver = lowest_version; ver <= highest_version; ver += 10) {
- const char *const prefix = (ver == lowest_version)
- ? ""
- : ((ver == highest_version) ? ", and " : ", ");
-
- ralloc_asprintf_append(& supported, "%s%d.%02d%s",
- prefix,
- ver / 100, ver % 100,
- (ver == 100) ? " ES" : "");
- }
-
- this->supported_version_string = supported;
-}
-
-const char *
-_mesa_glsl_shader_target_name(enum _mesa_glsl_parser_targets target)
-{
- switch (target) {
- case vertex_shader: return "vertex";
- case fragment_shader: return "fragment";
- case geometry_shader: return "geometry";
- }
-
- assert(!"Should not get here.");
- return "unknown";
-}
-
-
-void
-_mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state,
- const char *fmt, ...)
-{
- va_list ap;
-
- state->error = true;
-
- assert(state->info_log != NULL);
- ralloc_asprintf_append(&state->info_log, "%u:%u(%u): error: ",
- locp->source,
- locp->first_line,
- locp->first_column);
- va_start(ap, fmt);
- ralloc_vasprintf_append(&state->info_log, fmt, ap);
- va_end(ap);
- ralloc_strcat(&state->info_log, "\n");
-}
-
-
-void
-_mesa_glsl_warning(const YYLTYPE *locp, _mesa_glsl_parse_state *state,
- const char *fmt, ...)
-{
- va_list ap;
-
- assert(state->info_log != NULL);
- ralloc_asprintf_append(&state->info_log, "%u:%u(%u): warning: ",
- locp->source,
- locp->first_line,
- locp->first_column);
- va_start(ap, fmt);
- ralloc_vasprintf_append(&state->info_log, fmt, ap);
- va_end(ap);
- ralloc_strcat(&state->info_log, "\n");
-}
-
-
-bool
-_mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp,
- const char *behavior, YYLTYPE *behavior_locp,
- _mesa_glsl_parse_state *state)
-{
- enum {
- extension_disable,
- extension_enable,
- extension_require,
- extension_warn
- } ext_mode;
-
- if (strcmp(behavior, "warn") == 0) {
- ext_mode = extension_warn;
- } else if (strcmp(behavior, "require") == 0) {
- ext_mode = extension_require;
- } else if (strcmp(behavior, "enable") == 0) {
- ext_mode = extension_enable;
- } else if (strcmp(behavior, "disable") == 0) {
- ext_mode = extension_disable;
- } else {
- _mesa_glsl_error(behavior_locp, state,
- "Unknown extension behavior `%s'",
- behavior);
- return false;
- }
-
- bool unsupported = false;
-
- if (strcmp(name, "all") == 0) {
- if ((ext_mode == extension_enable) || (ext_mode == extension_require)) {
- _mesa_glsl_error(name_locp, state, "Cannot %s all extensions",
- (ext_mode == extension_enable)
- ? "enable" : "require");
- return false;
- }
- } else if (strcmp(name, "GL_ARB_draw_buffers") == 0) {
- /* This extension is only supported in fragment shaders.
- */
- if (state->target != fragment_shader) {
- unsupported = true;
- } else {
- state->ARB_draw_buffers_enable = (ext_mode != extension_disable);
- state->ARB_draw_buffers_warn = (ext_mode == extension_warn);
- }
- } else if (strcmp(name, "GL_ARB_draw_instanced") == 0) {
- /* This extension is only supported in vertex shaders.
- */
- if (state->target != vertex_shader) {
- unsupported = true;
- } else {
- state->ARB_draw_instanced_enable = (ext_mode != extension_disable);
- state->ARB_draw_instanced_warn = (ext_mode == extension_warn);
- }
- } else if (strcmp(name, "GL_ARB_explicit_attrib_location") == 0) {
- state->ARB_explicit_attrib_location_enable =
- (ext_mode != extension_disable);
- state->ARB_explicit_attrib_location_warn =
- (ext_mode == extension_warn);
-
- unsupported = !state->extensions->ARB_explicit_attrib_location;
- } else if (strcmp(name, "GL_ARB_fragment_coord_conventions") == 0) {
- state->ARB_fragment_coord_conventions_enable =
- (ext_mode != extension_disable);
- state->ARB_fragment_coord_conventions_warn =
- (ext_mode == extension_warn);
-
- unsupported = !state->extensions->ARB_fragment_coord_conventions;
- } else if (strcmp(name, "GL_ARB_texture_rectangle") == 0) {
- state->ARB_texture_rectangle_enable = (ext_mode != extension_disable);
- state->ARB_texture_rectangle_warn = (ext_mode == extension_warn);
- } else if (strcmp(name, "GL_EXT_texture_array") == 0) {
- state->EXT_texture_array_enable = (ext_mode != extension_disable);
- state->EXT_texture_array_warn = (ext_mode == extension_warn);
-
- unsupported = !state->extensions->EXT_texture_array;
- } else if (strcmp(name, "GL_ARB_shader_stencil_export") == 0) {
- if (state->target != fragment_shader) {
- unsupported = true;
- } else {
- state->ARB_shader_stencil_export_enable = (ext_mode != extension_disable);
- state->ARB_shader_stencil_export_warn = (ext_mode == extension_warn);
- unsupported = !state->extensions->ARB_shader_stencil_export;
- }
- } else if (strcmp(name, "GL_AMD_conservative_depth") == 0) {
- /* The AMD_conservative spec does not forbid requiring the extension in
- * the vertex shader.
- */
- state->AMD_conservative_depth_enable = (ext_mode != extension_disable);
- state->AMD_conservative_depth_warn = (ext_mode == extension_warn);
- unsupported = !state->extensions->AMD_conservative_depth;
- } else {
- unsupported = true;
- }
-
- if (unsupported) {
- static const char *const fmt = "extension `%s' unsupported in %s shader";
-
- if (ext_mode == extension_require) {
- _mesa_glsl_error(name_locp, state, fmt,
- name, _mesa_glsl_shader_target_name(state->target));
- return false;
- } else {
- _mesa_glsl_warning(name_locp, state, fmt,
- name, _mesa_glsl_shader_target_name(state->target));
- }
- }
-
- return true;
-}
-
-void
-_mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q)
-{
- if (q->flags.q.constant)
- printf("const ");
-
- if (q->flags.q.invariant)
- printf("invariant ");
-
- if (q->flags.q.attribute)
- printf("attribute ");
-
- if (q->flags.q.varying)
- printf("varying ");
-
- if (q->flags.q.in && q->flags.q.out)
- printf("inout ");
- else {
- if (q->flags.q.in)
- printf("in ");
-
- if (q->flags.q.out)
- printf("out ");
- }
-
- if (q->flags.q.centroid)
- printf("centroid ");
- if (q->flags.q.uniform)
- printf("uniform ");
- if (q->flags.q.smooth)
- printf("smooth ");
- if (q->flags.q.flat)
- printf("flat ");
- if (q->flags.q.noperspective)
- printf("noperspective ");
-}
-
-
-void
-ast_node::print(void) const
-{
- printf("unhandled node ");
-}
-
-
-ast_node::ast_node(void)
-{
- this->location.source = 0;
- this->location.line = 0;
- this->location.column = 0;
-}
-
-
-static void
-ast_opt_array_size_print(bool is_array, const ast_expression *array_size)
-{
- if (is_array) {
- printf("[ ");
-
- if (array_size)
- array_size->print();
-
- printf("] ");
- }
-}
-
-
-void
-ast_compound_statement::print(void) const
-{
- printf("{\n");
-
- foreach_list_const(n, &this->statements) {
- ast_node *ast = exec_node_data(ast_node, n, link);
- ast->print();
- }
-
- printf("}\n");
-}
-
-
-ast_compound_statement::ast_compound_statement(int new_scope,
- ast_node *statements)
-{
- this->new_scope = new_scope;
-
- if (statements != NULL) {
- this->statements.push_degenerate_list_at_head(&statements->link);
- }
-}
-
-
-void
-ast_expression::print(void) const
-{
- switch (oper) {
- case ast_assign:
- case ast_mul_assign:
- case ast_div_assign:
- case ast_mod_assign:
- case ast_add_assign:
- case ast_sub_assign:
- case ast_ls_assign:
- case ast_rs_assign:
- case ast_and_assign:
- case ast_xor_assign:
- case ast_or_assign:
- subexpressions[0]->print();
- printf("%s ", operator_string(oper));
- subexpressions[1]->print();
- break;
-
- case ast_field_selection:
- subexpressions[0]->print();
- printf(". %s ", primary_expression.identifier);
- break;
-
- case ast_plus:
- case ast_neg:
- case ast_bit_not:
- case ast_logic_not:
- case ast_pre_inc:
- case ast_pre_dec:
- printf("%s ", operator_string(oper));
- subexpressions[0]->print();
- break;
-
- case ast_post_inc:
- case ast_post_dec:
- subexpressions[0]->print();
- printf("%s ", operator_string(oper));
- break;
-
- case ast_conditional:
- subexpressions[0]->print();
- printf("? ");
- subexpressions[1]->print();
- printf(": ");
- subexpressions[1]->print();
- break;
-
- case ast_array_index:
- subexpressions[0]->print();
- printf("[ ");
- subexpressions[1]->print();
- printf("] ");
- break;
-
- case ast_function_call: {
- subexpressions[0]->print();
- printf("( ");
-
- foreach_list_const (n, &this->expressions) {
- if (n != this->expressions.get_head())
- printf(", ");
-
- ast_node *ast = exec_node_data(ast_node, n, link);
- ast->print();
- }
-
- printf(") ");
- break;
- }
-
- case ast_identifier:
- printf("%s ", primary_expression.identifier);
- break;
-
- case ast_int_constant:
- printf("%d ", primary_expression.int_constant);
- break;
-
- case ast_uint_constant:
- printf("%u ", primary_expression.uint_constant);
- break;
-
- case ast_float_constant:
- printf("%f ", primary_expression.float_constant);
- break;
-
- case ast_bool_constant:
- printf("%s ",
- primary_expression.bool_constant
- ? "true" : "false");
- break;
-
- case ast_sequence: {
- printf("( ");
- foreach_list_const(n, & this->expressions) {
- if (n != this->expressions.get_head())
- printf(", ");
-
- ast_node *ast = exec_node_data(ast_node, n, link);
- ast->print();
- }
- printf(") ");
- break;
- }
-
- default:
- assert(0);
- break;
- }
-}
-
-ast_expression::ast_expression(int oper,
- ast_expression *ex0,
- ast_expression *ex1,
- ast_expression *ex2)
-{
- this->oper = ast_operators(oper);
- this->subexpressions[0] = ex0;
- this->subexpressions[1] = ex1;
- this->subexpressions[2] = ex2;
-}
-
-
-void
-ast_expression_statement::print(void) const
-{
- if (expression)
- expression->print();
-
- printf("; ");
-}
-
-
-ast_expression_statement::ast_expression_statement(ast_expression *ex) :
- expression(ex)
-{
- /* empty */
-}
-
-
-void
-ast_function::print(void) const
-{
- return_type->print();
- printf(" %s (", identifier);
-
- foreach_list_const(n, & this->parameters) {
- ast_node *ast = exec_node_data(ast_node, n, link);
- ast->print();
- }
-
- printf(")");
-}
-
-
-ast_function::ast_function(void)
- : is_definition(false), signature(NULL)
-{
- /* empty */
-}
-
-
-void
-ast_fully_specified_type::print(void) const
-{
- _mesa_ast_type_qualifier_print(& qualifier);
- specifier->print();
-}
-
-
-void
-ast_parameter_declarator::print(void) const
-{
- type->print();
- if (identifier)
- printf("%s ", identifier);
- ast_opt_array_size_print(is_array, array_size);
-}
-
-
-void
-ast_function_definition::print(void) const
-{
- prototype->print();
- body->print();
-}
-
-
-void
-ast_declaration::print(void) const
-{
- printf("%s ", identifier);
- ast_opt_array_size_print(is_array, array_size);
-
- if (initializer) {
- printf("= ");
- initializer->print();
- }
-}
-
-
-ast_declaration::ast_declaration(char *identifier, int is_array,
- ast_expression *array_size,
- ast_expression *initializer)
-{
- this->identifier = identifier;
- this->is_array = is_array;
- this->array_size = array_size;
- this->initializer = initializer;
-}
-
-
-void
-ast_declarator_list::print(void) const
-{
- assert(type || invariant);
-
- if (type)
- type->print();
- else
- printf("invariant ");
-
- foreach_list_const (ptr, & this->declarations) {
- if (ptr != this->declarations.get_head())
- printf(", ");
-
- ast_node *ast = exec_node_data(ast_node, ptr, link);
- ast->print();
- }
-
- printf("; ");
-}
-
-
-ast_declarator_list::ast_declarator_list(ast_fully_specified_type *type)
-{
- this->type = type;
- this->invariant = false;
-}
-
-void
-ast_jump_statement::print(void) const
-{
- switch (mode) {
- case ast_continue:
- printf("continue; ");
- break;
- case ast_break:
- printf("break; ");
- break;
- case ast_return:
- printf("return ");
- if (opt_return_value)
- opt_return_value->print();
-
- printf("; ");
- break;
- case ast_discard:
- printf("discard; ");
- break;
- }
-}
-
-
-ast_jump_statement::ast_jump_statement(int mode, ast_expression *return_value)
-{
- this->mode = ast_jump_modes(mode);
-
- if (mode == ast_return)
- opt_return_value = return_value;
-}
-
-
-void
-ast_selection_statement::print(void) const
-{
- printf("if ( ");
- condition->print();
- printf(") ");
-
- then_statement->print();
-
- if (else_statement) {
- printf("else ");
- else_statement->print();
- }
-
-}
-
-
-ast_selection_statement::ast_selection_statement(ast_expression *condition,
- ast_node *then_statement,
- ast_node *else_statement)
-{
- this->condition = condition;
- this->then_statement = then_statement;
- this->else_statement = else_statement;
-}
-
-
-void
-ast_iteration_statement::print(void) const
-{
- switch (mode) {
- case ast_for:
- printf("for( ");
- if (init_statement)
- init_statement->print();
- printf("; ");
-
- if (condition)
- condition->print();
- printf("; ");
-
- if (rest_expression)
- rest_expression->print();
- printf(") ");
-
- body->print();
- break;
-
- case ast_while:
- printf("while ( ");
- if (condition)
- condition->print();
- printf(") ");
- body->print();
- break;
-
- case ast_do_while:
- printf("do ");
- body->print();
- printf("while ( ");
- if (condition)
- condition->print();
- printf("); ");
- break;
- }
-}
-
-
-ast_iteration_statement::ast_iteration_statement(int mode,
- ast_node *init,
- ast_node *condition,
- ast_expression *rest_expression,
- ast_node *body)
-{
- this->mode = ast_iteration_modes(mode);
- this->init_statement = init;
- this->condition = condition;
- this->rest_expression = rest_expression;
- this->body = body;
-}
-
-
-void
-ast_struct_specifier::print(void) const
-{
- printf("struct %s { ", name);
- foreach_list_const(n, &this->declarations) {
- ast_node *ast = exec_node_data(ast_node, n, link);
- ast->print();
- }
- printf("} ");
-}
-
-
-ast_struct_specifier::ast_struct_specifier(char *identifier,
- ast_node *declarator_list)
-{
- if (identifier == NULL) {
- static unsigned anon_count = 1;
- identifier = ralloc_asprintf(this, "#anon_struct_%04x", anon_count);
- anon_count++;
- }
- name = identifier;
- this->declarations.push_degenerate_list_at_head(&declarator_list->link);
-}
-
-bool
-do_common_optimization(exec_list *ir, bool linked, unsigned max_unroll_iterations)
-{
- GLboolean progress = GL_FALSE;
-
- progress = lower_instructions(ir, SUB_TO_ADD_NEG) || progress;
-
- if (linked) {
- progress = do_function_inlining(ir) || progress;
- progress = do_dead_functions(ir) || progress;
- }
- progress = do_structure_splitting(ir) || progress;
- progress = do_if_simplification(ir) || progress;
- progress = do_discard_simplification(ir) || progress;
- progress = do_copy_propagation(ir) || progress;
- progress = do_copy_propagation_elements(ir) || progress;
- if (linked)
- progress = do_dead_code(ir) || progress;
- else
- progress = do_dead_code_unlinked(ir) || progress;
- progress = do_dead_code_local(ir) || progress;
- progress = do_tree_grafting(ir) || progress;
- progress = do_constant_propagation(ir) || progress;
- if (linked)
- progress = do_constant_variable(ir) || progress;
- else
- progress = do_constant_variable_unlinked(ir) || progress;
- progress = do_constant_folding(ir) || progress;
- progress = do_algebraic(ir) || progress;
- progress = do_lower_jumps(ir) || progress;
- progress = do_vec_index_to_swizzle(ir) || progress;
- progress = do_swizzle_swizzle(ir) || progress;
- progress = do_noop_swizzle(ir) || progress;
-
- progress = optimize_redundant_jumps(ir) || progress;
-
- loop_state *ls = analyze_loop_variables(ir);
- if (ls->loop_found) {
- progress = set_loop_controls(ir, ls) || progress;
- progress = unroll_loops(ir, ls, max_unroll_iterations) || progress;
- }
- delete ls;
-
- return progress;
-}
-
-extern "C" {
-
-/**
- * To be called at GL teardown time, this frees compiler datastructures.
- *
- * After calling this, any previously compiled shaders and shader
- * programs would be invalid. So this should happen at approximately
- * program exit.
- */
-void
-_mesa_destroy_shader_compiler(void)
-{
- _mesa_destroy_shader_compiler_caches();
-
- _mesa_glsl_release_types();
-}
-
-/**
- * Releases compiler caches to trade off performance for memory.
- *
- * Intended to be used with glReleaseShaderCompiler().
- */
-void
-_mesa_destroy_shader_compiler_caches(void)
-{
- _mesa_glsl_release_functions();
-}
-
-}
+/*
+ * Copyright © 2008, 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+
+extern "C" {
+#include "main/core.h" /* for struct gl_context */
+}
+
+#include "ralloc.h"
+#include "ast.h"
+#include "glsl_parser_extras.h"
+#include "glsl_parser.h"
+#include "ir_optimization.h"
+#include "loop_analysis.h"
+
+_mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *ctx,
+ GLenum target, void *mem_ctx)
+{
+ switch (target) {
+ case GL_VERTEX_SHADER: this->target = vertex_shader; break;
+ case GL_FRAGMENT_SHADER: this->target = fragment_shader; break;
+ case GL_GEOMETRY_SHADER: this->target = geometry_shader; break;
+ }
+
+ this->scanner = NULL;
+ this->translation_unit.make_empty();
+ this->symbols = new(mem_ctx) glsl_symbol_table;
+ this->info_log = ralloc_strdup(mem_ctx, "");
+ this->error = false;
+ this->loop_or_switch_nesting = NULL;
+
+ /* Set default language version and extensions */
+ this->language_version = 110;
+ this->es_shader = false;
+ this->ARB_texture_rectangle_enable = true;
+
+ /* OpenGL ES 2.0 has different defaults from desktop GL. */
+ if (ctx->API == API_OPENGLES2) {
+ this->language_version = 100;
+ this->es_shader = true;
+ this->ARB_texture_rectangle_enable = false;
+ }
+
+ this->extensions = &ctx->Extensions;
+
+ this->Const.MaxLights = ctx->Const.MaxLights;
+ this->Const.MaxClipPlanes = ctx->Const.MaxClipPlanes;
+ this->Const.MaxTextureUnits = ctx->Const.MaxTextureUnits;
+ this->Const.MaxTextureCoords = ctx->Const.MaxTextureCoordUnits;
+ this->Const.MaxVertexAttribs = ctx->Const.VertexProgram.MaxAttribs;
+ this->Const.MaxVertexUniformComponents = ctx->Const.VertexProgram.MaxUniformComponents;
+ this->Const.MaxVaryingFloats = ctx->Const.MaxVarying * 4;
+ this->Const.MaxVertexTextureImageUnits = ctx->Const.MaxVertexTextureImageUnits;
+ this->Const.MaxCombinedTextureImageUnits = ctx->Const.MaxCombinedTextureImageUnits;
+ this->Const.MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits;
+ this->Const.MaxFragmentUniformComponents = ctx->Const.FragmentProgram.MaxUniformComponents;
+
+ this->Const.MaxDrawBuffers = ctx->Const.MaxDrawBuffers;
+
+ /* Note: Once the OpenGL 3.0 'forward compatible' context or the OpenGL 3.2
+ * Core context is supported, this logic will need change. Older versions of
+ * GLSL are no longer supported outside the compatibility contexts of 3.x.
+ */
+ this->Const.GLSL_100ES = (ctx->API == API_OPENGLES2)
+ || ctx->Extensions.ARB_ES2_compatibility;
+ this->Const.GLSL_110 = (ctx->API == API_OPENGL);
+ this->Const.GLSL_120 = (ctx->API == API_OPENGL)
+ && (ctx->Const.GLSLVersion >= 120);
+ this->Const.GLSL_130 = (ctx->API == API_OPENGL)
+ && (ctx->Const.GLSLVersion >= 130);
+
+ const unsigned lowest_version =
+ (ctx->API == API_OPENGLES2) || ctx->Extensions.ARB_ES2_compatibility
+ ? 100 : 110;
+ const unsigned highest_version =
+ (ctx->API == API_OPENGL) ? ctx->Const.GLSLVersion : 100;
+ char *supported = ralloc_strdup(this, "");
+
+ for (unsigned ver = lowest_version; ver <= highest_version; ver += 10) {
+ const char *const prefix = (ver == lowest_version)
+ ? ""
+ : ((ver == highest_version) ? ", and " : ", ");
+
+ ralloc_asprintf_append(& supported, "%s%d.%02d%s",
+ prefix,
+ ver / 100, ver % 100,
+ (ver == 100) ? " ES" : "");
+ }
+
+ this->supported_version_string = supported;
+}
+
+const char *
+_mesa_glsl_shader_target_name(enum _mesa_glsl_parser_targets target)
+{
+ switch (target) {
+ case vertex_shader: return "vertex";
+ case fragment_shader: return "fragment";
+ case geometry_shader: return "geometry";
+ }
+
+ assert(!"Should not get here.");
+ return "unknown";
+}
+
+
+void
+_mesa_glsl_error(YYLTYPE *locp, _mesa_glsl_parse_state *state,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ state->error = true;
+
+ assert(state->info_log != NULL);
+ ralloc_asprintf_append(&state->info_log, "%u:%u(%u): error: ",
+ locp->source,
+ locp->first_line,
+ locp->first_column);
+ va_start(ap, fmt);
+ ralloc_vasprintf_append(&state->info_log, fmt, ap);
+ va_end(ap);
+ ralloc_strcat(&state->info_log, "\n");
+}
+
+
+void
+_mesa_glsl_warning(const YYLTYPE *locp, _mesa_glsl_parse_state *state,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ assert(state->info_log != NULL);
+ ralloc_asprintf_append(&state->info_log, "%u:%u(%u): warning: ",
+ locp->source,
+ locp->first_line,
+ locp->first_column);
+ va_start(ap, fmt);
+ ralloc_vasprintf_append(&state->info_log, fmt, ap);
+ va_end(ap);
+ ralloc_strcat(&state->info_log, "\n");
+}
+
+
+bool
+_mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp,
+ const char *behavior, YYLTYPE *behavior_locp,
+ _mesa_glsl_parse_state *state)
+{
+ enum {
+ extension_disable,
+ extension_enable,
+ extension_require,
+ extension_warn
+ } ext_mode;
+
+ if (strcmp(behavior, "warn") == 0) {
+ ext_mode = extension_warn;
+ } else if (strcmp(behavior, "require") == 0) {
+ ext_mode = extension_require;
+ } else if (strcmp(behavior, "enable") == 0) {
+ ext_mode = extension_enable;
+ } else if (strcmp(behavior, "disable") == 0) {
+ ext_mode = extension_disable;
+ } else {
+ _mesa_glsl_error(behavior_locp, state,
+ "Unknown extension behavior `%s'",
+ behavior);
+ return false;
+ }
+
+ bool unsupported = false;
+
+ if (strcmp(name, "all") == 0) {
+ if ((ext_mode == extension_enable) || (ext_mode == extension_require)) {
+ _mesa_glsl_error(name_locp, state, "Cannot %s all extensions",
+ (ext_mode == extension_enable)
+ ? "enable" : "require");
+ return false;
+ }
+ } else if (strcmp(name, "GL_ARB_draw_buffers") == 0) {
+ /* This extension is only supported in fragment shaders.
+ */
+ if (state->target != fragment_shader) {
+ unsupported = true;
+ } else {
+ state->ARB_draw_buffers_enable = (ext_mode != extension_disable);
+ state->ARB_draw_buffers_warn = (ext_mode == extension_warn);
+ }
+ } else if (strcmp(name, "GL_ARB_draw_instanced") == 0) {
+ /* This extension is only supported in vertex shaders.
+ */
+ if (state->target != vertex_shader) {
+ unsupported = true;
+ } else {
+ state->ARB_draw_instanced_enable = (ext_mode != extension_disable);
+ state->ARB_draw_instanced_warn = (ext_mode == extension_warn);
+ }
+ } else if (strcmp(name, "GL_ARB_explicit_attrib_location") == 0) {
+ state->ARB_explicit_attrib_location_enable =
+ (ext_mode != extension_disable);
+ state->ARB_explicit_attrib_location_warn =
+ (ext_mode == extension_warn);
+
+ unsupported = !state->extensions->ARB_explicit_attrib_location;
+ } else if (strcmp(name, "GL_ARB_fragment_coord_conventions") == 0) {
+ state->ARB_fragment_coord_conventions_enable =
+ (ext_mode != extension_disable);
+ state->ARB_fragment_coord_conventions_warn =
+ (ext_mode == extension_warn);
+
+ unsupported = !state->extensions->ARB_fragment_coord_conventions;
+ } else if (strcmp(name, "GL_ARB_texture_rectangle") == 0) {
+ state->ARB_texture_rectangle_enable = (ext_mode != extension_disable);
+ state->ARB_texture_rectangle_warn = (ext_mode == extension_warn);
+ } else if (strcmp(name, "GL_EXT_texture_array") == 0) {
+ state->EXT_texture_array_enable = (ext_mode != extension_disable);
+ state->EXT_texture_array_warn = (ext_mode == extension_warn);
+
+ unsupported = !state->extensions->EXT_texture_array;
+ } else if (strcmp(name, "GL_ARB_shader_stencil_export") == 0) {
+ if (state->target != fragment_shader) {
+ unsupported = true;
+ } else {
+ state->ARB_shader_stencil_export_enable = (ext_mode != extension_disable);
+ state->ARB_shader_stencil_export_warn = (ext_mode == extension_warn);
+ unsupported = !state->extensions->ARB_shader_stencil_export;
+ }
+ } else if (strcmp(name, "GL_AMD_conservative_depth") == 0) {
+ /* The AMD_conservative spec does not forbid requiring the extension in
+ * the vertex shader.
+ */
+ state->AMD_conservative_depth_enable = (ext_mode != extension_disable);
+ state->AMD_conservative_depth_warn = (ext_mode == extension_warn);
+ unsupported = !state->extensions->AMD_conservative_depth;
+ } else {
+ unsupported = true;
+ }
+
+ if (unsupported) {
+ static const char *const fmt = "extension `%s' unsupported in %s shader";
+
+ if (ext_mode == extension_require) {
+ _mesa_glsl_error(name_locp, state, fmt,
+ name, _mesa_glsl_shader_target_name(state->target));
+ return false;
+ } else {
+ _mesa_glsl_warning(name_locp, state, fmt,
+ name, _mesa_glsl_shader_target_name(state->target));
+ }
+ }
+
+ return true;
+}
+
+void
+_mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q)
+{
+ if (q->flags.q.constant)
+ printf("const ");
+
+ if (q->flags.q.invariant)
+ printf("invariant ");
+
+ if (q->flags.q.attribute)
+ printf("attribute ");
+
+ if (q->flags.q.varying)
+ printf("varying ");
+
+ if (q->flags.q.in && q->flags.q.out)
+ printf("inout ");
+ else {
+ if (q->flags.q.in)
+ printf("in ");
+
+ if (q->flags.q.out)
+ printf("out ");
+ }
+
+ if (q->flags.q.centroid)
+ printf("centroid ");
+ if (q->flags.q.uniform)
+ printf("uniform ");
+ if (q->flags.q.smooth)
+ printf("smooth ");
+ if (q->flags.q.flat)
+ printf("flat ");
+ if (q->flags.q.noperspective)
+ printf("noperspective ");
+}
+
+
+void
+ast_node::print(void) const
+{
+ printf("unhandled node ");
+}
+
+
+ast_node::ast_node(void)
+{
+ this->location.source = 0;
+ this->location.line = 0;
+ this->location.column = 0;
+}
+
+
+static void
+ast_opt_array_size_print(bool is_array, const ast_expression *array_size)
+{
+ if (is_array) {
+ printf("[ ");
+
+ if (array_size)
+ array_size->print();
+
+ printf("] ");
+ }
+}
+
+
+void
+ast_compound_statement::print(void) const
+{
+ printf("{\n");
+
+ foreach_list_const(n, &this->statements) {
+ ast_node *ast = exec_node_data(ast_node, n, link);
+ ast->print();
+ }
+
+ printf("}\n");
+}
+
+
+ast_compound_statement::ast_compound_statement(int new_scope,
+ ast_node *statements)
+{
+ this->new_scope = new_scope;
+
+ if (statements != NULL) {
+ this->statements.push_degenerate_list_at_head(&statements->link);
+ }
+}
+
+
+void
+ast_expression::print(void) const
+{
+ switch (oper) {
+ case ast_assign:
+ case ast_mul_assign:
+ case ast_div_assign:
+ case ast_mod_assign:
+ case ast_add_assign:
+ case ast_sub_assign:
+ case ast_ls_assign:
+ case ast_rs_assign:
+ case ast_and_assign:
+ case ast_xor_assign:
+ case ast_or_assign:
+ subexpressions[0]->print();
+ printf("%s ", operator_string(oper));
+ subexpressions[1]->print();
+ break;
+
+ case ast_field_selection:
+ subexpressions[0]->print();
+ printf(". %s ", primary_expression.identifier);
+ break;
+
+ case ast_plus:
+ case ast_neg:
+ case ast_bit_not:
+ case ast_logic_not:
+ case ast_pre_inc:
+ case ast_pre_dec:
+ printf("%s ", operator_string(oper));
+ subexpressions[0]->print();
+ break;
+
+ case ast_post_inc:
+ case ast_post_dec:
+ subexpressions[0]->print();
+ printf("%s ", operator_string(oper));
+ break;
+
+ case ast_conditional:
+ subexpressions[0]->print();
+ printf("? ");
+ subexpressions[1]->print();
+ printf(": ");
+ subexpressions[1]->print();
+ break;
+
+ case ast_array_index:
+ subexpressions[0]->print();
+ printf("[ ");
+ subexpressions[1]->print();
+ printf("] ");
+ break;
+
+ case ast_function_call: {
+ subexpressions[0]->print();
+ printf("( ");
+
+ foreach_list_const (n, &this->expressions) {
+ if (n != this->expressions.get_head())
+ printf(", ");
+
+ ast_node *ast = exec_node_data(ast_node, n, link);
+ ast->print();
+ }
+
+ printf(") ");
+ break;
+ }
+
+ case ast_identifier:
+ printf("%s ", primary_expression.identifier);
+ break;
+
+ case ast_int_constant:
+ printf("%d ", primary_expression.int_constant);
+ break;
+
+ case ast_uint_constant:
+ printf("%u ", primary_expression.uint_constant);
+ break;
+
+ case ast_float_constant:
+ printf("%f ", primary_expression.float_constant);
+ break;
+
+ case ast_bool_constant:
+ printf("%s ",
+ primary_expression.bool_constant
+ ? "true" : "false");
+ break;
+
+ case ast_sequence: {
+ printf("( ");
+ foreach_list_const(n, & this->expressions) {
+ if (n != this->expressions.get_head())
+ printf(", ");
+
+ ast_node *ast = exec_node_data(ast_node, n, link);
+ ast->print();
+ }
+ printf(") ");
+ break;
+ }
+
+ default:
+ assert(0);
+ break;
+ }
+}
+
+ast_expression::ast_expression(int oper,
+ ast_expression *ex0,
+ ast_expression *ex1,
+ ast_expression *ex2)
+{
+ this->oper = ast_operators(oper);
+ this->subexpressions[0] = ex0;
+ this->subexpressions[1] = ex1;
+ this->subexpressions[2] = ex2;
+}
+
+
+void
+ast_expression_statement::print(void) const
+{
+ if (expression)
+ expression->print();
+
+ printf("; ");
+}
+
+
+ast_expression_statement::ast_expression_statement(ast_expression *ex) :
+ expression(ex)
+{
+ /* empty */
+}
+
+
+void
+ast_function::print(void) const
+{
+ return_type->print();
+ printf(" %s (", identifier);
+
+ foreach_list_const(n, & this->parameters) {
+ ast_node *ast = exec_node_data(ast_node, n, link);
+ ast->print();
+ }
+
+ printf(")");
+}
+
+
+ast_function::ast_function(void)
+ : is_definition(false), signature(NULL)
+{
+ /* empty */
+}
+
+
+void
+ast_fully_specified_type::print(void) const
+{
+ _mesa_ast_type_qualifier_print(& qualifier);
+ specifier->print();
+}
+
+
+void
+ast_parameter_declarator::print(void) const
+{
+ type->print();
+ if (identifier)
+ printf("%s ", identifier);
+ ast_opt_array_size_print(is_array, array_size);
+}
+
+
+void
+ast_function_definition::print(void) const
+{
+ prototype->print();
+ body->print();
+}
+
+
+void
+ast_declaration::print(void) const
+{
+ printf("%s ", identifier);
+ ast_opt_array_size_print(is_array, array_size);
+
+ if (initializer) {
+ printf("= ");
+ initializer->print();
+ }
+}
+
+
+ast_declaration::ast_declaration(char *identifier, int is_array,
+ ast_expression *array_size,
+ ast_expression *initializer)
+{
+ this->identifier = identifier;
+ this->is_array = is_array;
+ this->array_size = array_size;
+ this->initializer = initializer;
+}
+
+
+void
+ast_declarator_list::print(void) const
+{
+ assert(type || invariant);
+
+ if (type)
+ type->print();
+ else
+ printf("invariant ");
+
+ foreach_list_const (ptr, & this->declarations) {
+ if (ptr != this->declarations.get_head())
+ printf(", ");
+
+ ast_node *ast = exec_node_data(ast_node, ptr, link);
+ ast->print();
+ }
+
+ printf("; ");
+}
+
+
+ast_declarator_list::ast_declarator_list(ast_fully_specified_type *type)
+{
+ this->type = type;
+ this->invariant = false;
+}
+
+void
+ast_jump_statement::print(void) const
+{
+ switch (mode) {
+ case ast_continue:
+ printf("continue; ");
+ break;
+ case ast_break:
+ printf("break; ");
+ break;
+ case ast_return:
+ printf("return ");
+ if (opt_return_value)
+ opt_return_value->print();
+
+ printf("; ");
+ break;
+ case ast_discard:
+ printf("discard; ");
+ break;
+ }
+}
+
+
+ast_jump_statement::ast_jump_statement(int mode, ast_expression *return_value)
+{
+ this->mode = ast_jump_modes(mode);
+
+ if (mode == ast_return)
+ opt_return_value = return_value;
+}
+
+
+void
+ast_selection_statement::print(void) const
+{
+ printf("if ( ");
+ condition->print();
+ printf(") ");
+
+ then_statement->print();
+
+ if (else_statement) {
+ printf("else ");
+ else_statement->print();
+ }
+
+}
+
+
+ast_selection_statement::ast_selection_statement(ast_expression *condition,
+ ast_node *then_statement,
+ ast_node *else_statement)
+{
+ this->condition = condition;
+ this->then_statement = then_statement;
+ this->else_statement = else_statement;
+}
+
+
+void
+ast_iteration_statement::print(void) const
+{
+ switch (mode) {
+ case ast_for:
+ printf("for( ");
+ if (init_statement)
+ init_statement->print();
+ printf("; ");
+
+ if (condition)
+ condition->print();
+ printf("; ");
+
+ if (rest_expression)
+ rest_expression->print();
+ printf(") ");
+
+ body->print();
+ break;
+
+ case ast_while:
+ printf("while ( ");
+ if (condition)
+ condition->print();
+ printf(") ");
+ body->print();
+ break;
+
+ case ast_do_while:
+ printf("do ");
+ body->print();
+ printf("while ( ");
+ if (condition)
+ condition->print();
+ printf("); ");
+ break;
+ }
+}
+
+
+ast_iteration_statement::ast_iteration_statement(int mode,
+ ast_node *init,
+ ast_node *condition,
+ ast_expression *rest_expression,
+ ast_node *body)
+{
+ this->mode = ast_iteration_modes(mode);
+ this->init_statement = init;
+ this->condition = condition;
+ this->rest_expression = rest_expression;
+ this->body = body;
+}
+
+
+void
+ast_struct_specifier::print(void) const
+{
+ printf("struct %s { ", name);
+ foreach_list_const(n, &this->declarations) {
+ ast_node *ast = exec_node_data(ast_node, n, link);
+ ast->print();
+ }
+ printf("} ");
+}
+
+
+ast_struct_specifier::ast_struct_specifier(char *identifier,
+ ast_node *declarator_list)
+{
+ if (identifier == NULL) {
+ static unsigned anon_count = 1;
+ identifier = ralloc_asprintf(this, "#anon_struct_%04x", anon_count);
+ anon_count++;
+ }
+ name = identifier;
+ this->declarations.push_degenerate_list_at_head(&declarator_list->link);
+}
+
+bool
+do_common_optimization(exec_list *ir, bool linked, unsigned max_unroll_iterations)
+{
+ GLboolean progress = GL_FALSE;
+
+ progress = lower_instructions(ir, SUB_TO_ADD_NEG) || progress;
+
+ if (linked) {
+ progress = do_function_inlining(ir) || progress;
+ progress = do_dead_functions(ir) || progress;
+ }
+ progress = do_structure_splitting(ir) || progress;
+ progress = do_if_simplification(ir) || progress;
+ progress = do_discard_simplification(ir) || progress;
+ progress = do_copy_propagation(ir) || progress;
+ /*progress = do_copy_propagation_elements(ir) || progress;*/
+ if (linked)
+ progress = do_dead_code(ir) || progress;
+ else
+ progress = do_dead_code_unlinked(ir) || progress;
+ progress = do_dead_code_local(ir) || progress;
+ progress = do_tree_grafting(ir) || progress;
+ progress = do_constant_propagation(ir) || progress;
+ if (linked)
+ progress = do_constant_variable(ir) || progress;
+ else
+ progress = do_constant_variable_unlinked(ir) || progress;
+ progress = do_constant_folding(ir) || progress;
+ progress = do_algebraic(ir) || progress;
+ progress = do_lower_jumps(ir) || progress;
+ progress = do_vec_index_to_swizzle(ir) || progress;
+ progress = do_swizzle_swizzle(ir) || progress;
+ progress = do_noop_swizzle(ir) || progress;
+
+ progress = optimize_redundant_jumps(ir) || progress;
+
+ loop_state *ls = analyze_loop_variables(ir);
+ if (ls->loop_found) {
+ progress = set_loop_controls(ir, ls) || progress;
+ progress = unroll_loops(ir, ls, max_unroll_iterations) || progress;
+ }
+ delete ls;
+
+ return progress;
+}
+
+extern "C" {
+
+/**
+ * To be called at GL teardown time, this frees compiler datastructures.
+ *
+ * After calling this, any previously compiled shaders and shader
+ * programs would be invalid. So this should happen at approximately
+ * program exit.
+ */
+void
+_mesa_destroy_shader_compiler(void)
+{
+ _mesa_destroy_shader_compiler_caches();
+
+ _mesa_glsl_release_types();
+}
+
+/**
+ * Releases compiler caches to trade off performance for memory.
+ *
+ * Intended to be used with glReleaseShaderCompiler().
+ */
+void
+_mesa_destroy_shader_compiler_caches(void)
+{
+ _mesa_glsl_release_functions();
+}
+
+}
diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.c b/mesalib/src/mesa/drivers/dri/common/dri_util.c
index 8b3b55e5e..6d3dd0a2c 100644
--- a/mesalib/src/mesa/drivers/dri/common/dri_util.c
+++ b/mesalib/src/mesa/drivers/dri/common/dri_util.c
@@ -481,6 +481,22 @@ dri2CreateNewDrawable(__DRIscreen *screen,
return pdraw;
}
+static __DRIbuffer *
+dri2AllocateBuffer(__DRIscreen *screen,
+ unsigned int attachment, unsigned int format,
+ int width, int height)
+{
+ return (*screen->DriverAPI.AllocateBuffer)(screen, attachment, format,
+ width, height);
+}
+
+static void
+dri2ReleaseBuffer(__DRIscreen *screen, __DRIbuffer *buffer)
+{
+ (*screen->DriverAPI.ReleaseBuffer)(screen, buffer);
+}
+
+
static int
dri2ConfigQueryb(__DRIscreen *screen, const char *var, GLboolean *val)
{
@@ -930,7 +946,9 @@ const __DRIdri2Extension driDRI2Extension = {
dri2CreateNewDrawable,
dri2CreateNewContext,
dri2GetAPIMask,
- dri2CreateNewContextForAPI
+ dri2CreateNewContextForAPI,
+ dri2AllocateBuffer,
+ dri2ReleaseBuffer
};
const __DRI2configQueryExtension dri2ConfigQueryExtension = {
diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.h b/mesalib/src/mesa/drivers/dri/common/dri_util.h
index b6f04993e..8d2a38524 100644
--- a/mesalib/src/mesa/drivers/dri/common/dri_util.h
+++ b/mesalib/src/mesa/drivers/dri/common/dri_util.h
@@ -223,6 +223,12 @@ struct __DriverAPIRec {
/* DRI2 Entry point */
const __DRIconfig **(*InitScreen2) (__DRIscreen * priv);
+
+ __DRIbuffer *(*AllocateBuffer) (__DRIscreen *screenPrivate,
+ unsigned int attachment,
+ unsigned int format,
+ int width, int height);
+ void (*ReleaseBuffer) (__DRIscreen *screenPrivate, __DRIbuffer *buffer);
};
extern const struct __DriverAPIRec driDriverAPI;
diff --git a/mesalib/src/mesa/drivers/dri/swrast/swrast.c b/mesalib/src/mesa/drivers/dri/swrast/swrast.c
index 508b85e6d..e6d1ab741 100644
--- a/mesalib/src/mesa/drivers/dri/swrast/swrast.c
+++ b/mesalib/src/mesa/drivers/dri/swrast/swrast.c
@@ -1,811 +1,811 @@
-/*
- * Copyright 2008, 2010 George Sapountzis <gsapountzis@gmail.com>
- *
- * 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.
- */
-
-/*
- * DRI software rasterizer
- *
- * This is the mesa swrast module packaged into a DRI driver structure.
- *
- * The front-buffer is allocated by the loader. The loader provides read/write
- * callbacks for access to the front-buffer. The driver uses a scratch row for
- * front-buffer rendering to avoid repeated calls to the loader.
- *
- * The back-buffer is allocated by the driver and is private.
- */
-
-#ifdef _MSC_VER
-#define WIN32_LEAN_AND_MEAN 1
-#include <windows.h>
-#endif
-
-#include "main/context.h"
-#include "main/extensions.h"
-#include "main/formats.h"
-#include "main/framebuffer.h"
-#include "main/imports.h"
-#include "main/renderbuffer.h"
-#include "swrast/swrast.h"
-#include "swrast_setup/swrast_setup.h"
-#include "tnl/tnl.h"
-#include "tnl/t_context.h"
-#include "tnl/t_pipeline.h"
-#include "vbo/vbo.h"
-#include "drivers/common/driverfuncs.h"
-#include "drivers/common/meta.h"
-#include "utils.h"
-
-#include "main/teximage.h"
-#include "main/texformat.h"
-#include "main/texstate.h"
-
-#include "swrast_priv.h"
-
-
-/**
- * Screen and config-related functions
- */
-
-static void swrastSetTexBuffer2(__DRIcontext *pDRICtx, GLint target,
- GLint texture_format, __DRIdrawable *dPriv)
-{
- struct dri_context *dri_ctx;
- int x, y, w, h;
- __DRIscreen *sPriv = dPriv->driScreenPriv;
- struct gl_texture_unit *texUnit;
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
- uint32_t internalFormat;
- gl_format texFormat;
-
- dri_ctx = pDRICtx->driverPrivate;
-
- internalFormat = (texture_format == __DRI_TEXTURE_FORMAT_RGB ? 3 : 4);
-
- texUnit = _mesa_get_current_tex_unit(&dri_ctx->Base);
- texObj = _mesa_select_tex_object(&dri_ctx->Base, texUnit, target);
- texImage = _mesa_get_tex_image(&dri_ctx->Base, texObj, target, 0);
-
- _mesa_lock_texture(&dri_ctx->Base, texObj);
-
- sPriv->swrast_loader->getDrawableInfo(dPriv, &x, &y, &w, &h, dPriv->loaderPrivate);
-
- if (texture_format == __DRI_TEXTURE_FORMAT_RGB)
- texFormat = MESA_FORMAT_XRGB8888;
- else
- texFormat = MESA_FORMAT_ARGB8888;
-
- _mesa_init_teximage_fields(&dri_ctx->Base, target, texImage,
- w, h, 1, 0, internalFormat, texFormat);
-
- sPriv->swrast_loader->getImage(dPriv, x, y, w, h, (char *)texImage->Data,
- dPriv->loaderPrivate);
-
- _mesa_unlock_texture(&dri_ctx->Base, texObj);
-}
-
-static void swrastSetTexBuffer(__DRIcontext *pDRICtx, GLint target,
- __DRIdrawable *dPriv)
-{
- swrastSetTexBuffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
-}
-
-static const __DRItexBufferExtension swrastTexBufferExtension = {
- { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
- swrastSetTexBuffer,
- swrastSetTexBuffer2,
-};
-
-static const __DRIextension *dri_screen_extensions[] = {
- &swrastTexBufferExtension.base,
- NULL
-};
-
-static __DRIconfig **
-swrastFillInModes(__DRIscreen *psp,
- unsigned pixel_bits, unsigned depth_bits,
- unsigned stencil_bits, GLboolean have_back_buffer)
-{
- __DRIconfig **configs;
- unsigned depth_buffer_factor;
- unsigned back_buffer_factor;
- GLenum fb_format;
- GLenum fb_type;
-
- /* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't
- * support pageflipping at all.
- */
- static const GLenum back_buffer_modes[] = {
- GLX_NONE, GLX_SWAP_UNDEFINED_OML
- };
-
- uint8_t depth_bits_array[4];
- uint8_t stencil_bits_array[4];
- uint8_t msaa_samples_array[1];
-
- depth_bits_array[0] = 0;
- depth_bits_array[1] = 0;
- depth_bits_array[2] = depth_bits;
- depth_bits_array[3] = depth_bits;
-
- /* Just like with the accumulation buffer, always provide some modes
- * with a stencil buffer.
- */
- stencil_bits_array[0] = 0;
- stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
- stencil_bits_array[2] = 0;
- stencil_bits_array[3] = (stencil_bits == 0) ? 8 : stencil_bits;
-
- msaa_samples_array[0] = 0;
-
- depth_buffer_factor = 4;
- back_buffer_factor = 2;
-
- switch (pixel_bits) {
- case 8:
- fb_format = GL_RGB;
- fb_type = GL_UNSIGNED_BYTE_2_3_3_REV;
- break;
- case 16:
- fb_format = GL_RGB;
- fb_type = GL_UNSIGNED_SHORT_5_6_5;
- break;
- case 24:
- fb_format = GL_BGR;
- fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
- break;
- case 32:
- fb_format = GL_BGRA;
- fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
- break;
- default:
- fprintf(stderr, "[%s:%u] bad depth %d\n", __FUNCTION__, __LINE__,
- pixel_bits);
- return NULL;
- }
-
- configs = driCreateConfigs(fb_format, fb_type,
- depth_bits_array, stencil_bits_array,
- depth_buffer_factor, back_buffer_modes,
- back_buffer_factor, msaa_samples_array, 1,
- GL_TRUE);
- if (configs == NULL) {
- fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __FUNCTION__,
- __LINE__);
- return NULL;
- }
-
- return configs;
-}
-
-static const __DRIconfig **
-dri_init_screen(__DRIscreen * psp)
-{
- __DRIconfig **configs8, **configs16, **configs24, **configs32;
-
- TRACE;
-
- psp->extensions = dri_screen_extensions;
-
- configs8 = swrastFillInModes(psp, 8, 8, 0, 1);
- configs16 = swrastFillInModes(psp, 16, 16, 0, 1);
- configs24 = swrastFillInModes(psp, 24, 24, 8, 1);
- configs32 = swrastFillInModes(psp, 32, 24, 8, 1);
-
- configs16 = driConcatConfigs(configs8, configs16);
- configs24 = driConcatConfigs(configs16, configs24);
- configs32 = driConcatConfigs(configs24, configs32);
-
- return (const __DRIconfig **)configs32;
-}
-
-static void
-dri_destroy_screen(__DRIscreen * sPriv)
-{
- TRACE;
-}
-
-
-/**
- * Framebuffer and renderbuffer-related functions.
- */
-
-static GLuint
-choose_pixel_format(const struct gl_config *v)
-{
- int depth = v->rgbBits;
-
- if (depth == 32
- && v->redMask == 0xff0000
- && v->greenMask == 0x00ff00
- && v->blueMask == 0x0000ff)
- return PF_A8R8G8B8;
- else if (depth == 24
- && v->redMask == 0xff0000
- && v->greenMask == 0x00ff00
- && v->blueMask == 0x0000ff)
- return PF_X8R8G8B8;
- else if (depth == 16
- && v->redMask == 0xf800
- && v->greenMask == 0x07e0
- && v->blueMask == 0x001f)
- return PF_R5G6B5;
- else if (depth == 8
- && v->redMask == 0x07
- && v->greenMask == 0x38
- && v->blueMask == 0xc0)
- return PF_R3G3B2;
-
- _mesa_problem( NULL, "unexpected format in %s", __FUNCTION__ );
- return 0;
-}
-
-static void
-swrast_delete_renderbuffer(struct gl_renderbuffer *rb)
-{
- TRACE;
-
- free(rb->Data);
- free(rb);
-}
-
-/* see bytes_per_line in libGL */
-static INLINE int
-bytes_per_line(unsigned pitch_bits, unsigned mul)
-{
- unsigned mask = mul - 1;
-
- return ((pitch_bits + mask) & ~mask) / 8;
-}
-
-static GLboolean
-swrast_alloc_front_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
- GLenum internalFormat, GLuint width, GLuint height)
-{
- struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb);
-
- TRACE;
-
- rb->Data = NULL;
- rb->Width = width;
- rb->Height = height;
-
- xrb->pitch = bytes_per_line(width * xrb->bpp, 32);
-
- return GL_TRUE;
-}
-
-static GLboolean
-swrast_alloc_back_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
- GLenum internalFormat, GLuint width, GLuint height)
-{
- struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb);
-
- TRACE;
-
- free(rb->Data);
-
- swrast_alloc_front_storage(ctx, rb, internalFormat, width, height);
-
- rb->Data = malloc(height * xrb->pitch);
-
- return GL_TRUE;
-}
-
-static struct swrast_renderbuffer *
-swrast_new_renderbuffer(const struct gl_config *visual, GLboolean front)
-{
- struct swrast_renderbuffer *xrb = calloc(1, sizeof *xrb);
- GLuint pixel_format;
-
- TRACE;
-
- if (!xrb)
- return NULL;
-
- _mesa_init_renderbuffer(&xrb->Base, 0);
-
- pixel_format = choose_pixel_format(visual);
-
- xrb->Base.Delete = swrast_delete_renderbuffer;
- if (front) {
- xrb->Base.AllocStorage = swrast_alloc_front_storage;
- swrast_set_span_funcs_front(xrb, pixel_format);
- }
- else {
- xrb->Base.AllocStorage = swrast_alloc_back_storage;
- swrast_set_span_funcs_back(xrb, pixel_format);
- }
-
- switch (pixel_format) {
- case PF_A8R8G8B8:
- xrb->Base.Format = MESA_FORMAT_ARGB8888;
- xrb->Base.InternalFormat = GL_RGBA;
- xrb->Base._BaseFormat = GL_RGBA;
- xrb->Base.DataType = GL_UNSIGNED_BYTE;
- xrb->bpp = 32;
- break;
- case PF_X8R8G8B8:
- xrb->Base.Format = MESA_FORMAT_ARGB8888; /* XXX */
- xrb->Base.InternalFormat = GL_RGB;
- xrb->Base._BaseFormat = GL_RGB;
- xrb->Base.DataType = GL_UNSIGNED_BYTE;
- xrb->bpp = 32;
- break;
- case PF_R5G6B5:
- xrb->Base.Format = MESA_FORMAT_RGB565;
- xrb->Base.InternalFormat = GL_RGB;
- xrb->Base._BaseFormat = GL_RGB;
- xrb->Base.DataType = GL_UNSIGNED_BYTE;
- xrb->bpp = 16;
- break;
- case PF_R3G3B2:
- xrb->Base.Format = MESA_FORMAT_RGB332;
- xrb->Base.InternalFormat = GL_RGB;
- xrb->Base._BaseFormat = GL_RGB;
- xrb->Base.DataType = GL_UNSIGNED_BYTE;
- xrb->bpp = 8;
- break;
- default:
- return NULL;
- }
-
- return xrb;
-}
-
-static GLboolean
-dri_create_buffer(__DRIscreen * sPriv,
- __DRIdrawable * dPriv,
- const struct gl_config * visual, GLboolean isPixmap)
-{
- struct dri_drawable *drawable = NULL;
- struct gl_framebuffer *fb;
- struct swrast_renderbuffer *frontrb, *backrb;
-
- TRACE;
-
- drawable = CALLOC_STRUCT(dri_drawable);
- if (drawable == NULL)
- goto drawable_fail;
-
- dPriv->driverPrivate = drawable;
- drawable->dPriv = dPriv;
-
- drawable->row = malloc(MAX_WIDTH * 4);
- if (drawable->row == NULL)
- goto drawable_fail;
-
- fb = &drawable->Base;
-
- /* basic framebuffer setup */
- _mesa_initialize_window_framebuffer(fb, visual);
-
- /* add front renderbuffer */
- frontrb = swrast_new_renderbuffer(visual, GL_TRUE);
- _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontrb->Base);
-
- /* add back renderbuffer */
- if (visual->doubleBufferMode) {
- backrb = swrast_new_renderbuffer(visual, GL_FALSE);
- _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backrb->Base);
- }
-
- /* add software renderbuffers */
- _mesa_add_soft_renderbuffers(fb,
- GL_FALSE, /* color */
- visual->haveDepthBuffer,
- visual->haveStencilBuffer,
- visual->haveAccumBuffer,
- GL_FALSE, /* alpha */
- GL_FALSE /* aux bufs */);
-
- return GL_TRUE;
-
-drawable_fail:
-
- if (drawable)
- free(drawable->row);
-
- FREE(drawable);
-
- return GL_FALSE;
-}
-
-static void
-dri_destroy_buffer(__DRIdrawable * dPriv)
-{
- TRACE;
-
- if (dPriv) {
- struct dri_drawable *drawable = dri_drawable(dPriv);
- struct gl_framebuffer *fb;
-
- free(drawable->row);
-
- fb = &drawable->Base;
-
- fb->DeletePending = GL_TRUE;
- _mesa_reference_framebuffer(&fb, NULL);
- }
-}
-
-static void
-dri_swap_buffers(__DRIdrawable * dPriv)
-{
- __DRIscreen *sPriv = dPriv->driScreenPriv;
-
- GET_CURRENT_CONTEXT(ctx);
-
- struct dri_drawable *drawable = dri_drawable(dPriv);
- struct gl_framebuffer *fb;
- struct swrast_renderbuffer *frontrb, *backrb;
-
- TRACE;
-
- fb = &drawable->Base;
-
- frontrb =
- swrast_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
- backrb =
- swrast_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
-
- /* check for signle-buffered */
- if (backrb == NULL)
- return;
-
- /* check if swapping currently bound buffer */
- if (ctx && ctx->DrawBuffer == fb) {
- /* flush pending rendering */
- _mesa_notifySwapBuffers(ctx);
- }
-
- sPriv->swrast_loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
- 0, 0,
- frontrb->Base.Width,
- frontrb->Base.Height,
- backrb->Base.Data,
- dPriv->loaderPrivate);
-}
-
-
-/**
- * General device driver functions.
- */
-
-static void
-get_window_size( struct gl_framebuffer *fb, GLsizei *w, GLsizei *h )
-{
- __DRIdrawable *dPriv = swrast_drawable(fb)->dPriv;
- __DRIscreen *sPriv = dPriv->driScreenPriv;
- int x, y;
-
- sPriv->swrast_loader->getDrawableInfo(dPriv,
- &x, &y, w, h,
- dPriv->loaderPrivate);
-}
-
-static void
-swrast_check_and_update_window_size( struct gl_context *ctx, struct gl_framebuffer *fb )
-{
- GLsizei width, height;
-
- get_window_size(fb, &width, &height);
- if (fb->Width != width || fb->Height != height) {
- _mesa_resize_framebuffer(ctx, fb, width, height);
- }
-}
-
-static const GLubyte *
-get_string(struct gl_context *ctx, GLenum pname)
-{
- (void) ctx;
- switch (pname) {
- case GL_VENDOR:
- return (const GLubyte *) "Mesa Project";
- case GL_RENDERER:
- return (const GLubyte *) "Software Rasterizer";
- default:
- return NULL;
- }
-}
-
-static void
-update_state( struct gl_context *ctx, GLuint new_state )
-{
- /* not much to do here - pass it on */
- _swrast_InvalidateState( ctx, new_state );
- _swsetup_InvalidateState( ctx, new_state );
- _vbo_InvalidateState( ctx, new_state );
- _tnl_InvalidateState( ctx, new_state );
-}
-
-static void
-viewport(struct gl_context *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
-{
- struct gl_framebuffer *draw = ctx->WinSysDrawBuffer;
- struct gl_framebuffer *read = ctx->WinSysReadBuffer;
-
- swrast_check_and_update_window_size(ctx, draw);
- swrast_check_and_update_window_size(ctx, read);
-}
-
-static gl_format swrastChooseTextureFormat(struct gl_context * ctx,
- GLint internalFormat,
- GLenum format,
- GLenum type)
-{
- if (internalFormat == GL_RGB)
- return MESA_FORMAT_XRGB8888;
- return _mesa_choose_tex_format(ctx, internalFormat, format, type);
-}
-
-static void
-swrast_init_driver_functions(struct dd_function_table *driver)
-{
- driver->GetString = get_string;
- driver->UpdateState = update_state;
- driver->GetBufferSize = NULL;
- driver->Viewport = viewport;
- driver->ChooseTextureFormat = swrastChooseTextureFormat;
-}
-
-static const char *es2_extensions[] = {
- /* Used by mesa internally (cf all_mesa_extensions in ../common/utils.c) */
- "GL_ARB_draw_buffers",
- "GL_ARB_multisample",
- "GL_ARB_texture_compression",
- "GL_ARB_transpose_matrix",
- "GL_ARB_vertex_buffer_object",
- "GL_ARB_window_pos",
- "GL_EXT_blend_func_separate",
- "GL_EXT_compiled_vertex_array",
- "GL_EXT_framebuffer_blit",
- "GL_EXT_multi_draw_arrays",
- "GL_EXT_polygon_offset",
- "GL_EXT_texture_object",
- "GL_EXT_vertex_array",
- "GL_IBM_multimode_draw_arrays",
- "GL_MESA_window_pos",
- "GL_NV_vertex_program",
-
- /* Required by GLES2 */
- "GL_ARB_fragment_program",
- "GL_ARB_fragment_shader",
- "GL_ARB_multitexture",
- "GL_ARB_shader_objects",
- "GL_ARB_texture_cube_map",
- "GL_ARB_texture_mirrored_repeat",
- "GL_ARB_texture_non_power_of_two",
- "GL_ARB_vertex_shader",
- "GL_EXT_blend_color",
- "GL_EXT_blend_equation_separate",
- "GL_EXT_blend_minmax",
- "GL_EXT_blend_subtract",
- "GL_EXT_stencil_wrap",
-
- /* Optional GLES2 */
- "GL_ARB_framebuffer_object",
- "GL_EXT_texture_filter_anisotropic",
- "GL_ARB_depth_texture",
- "GL_EXT_packed_depth_stencil",
- "GL_EXT_framebuffer_object",
- NULL,
-};
-
-static void
-InitExtensionsES2(struct gl_context *ctx)
-{
- int i;
-
- /* Can't use driInitExtensions() since it uses extensions from
- * main/remap_helper.h when called the first time. */
-
- for (i = 0; es2_extensions[i]; i++)
- _mesa_enable_extension(ctx, es2_extensions[i]);
-}
-
-/**
- * Context-related functions.
- */
-
-static GLboolean
-dri_create_context(gl_api api,
- const struct gl_config * visual,
- __DRIcontext * cPriv, void *sharedContextPrivate)
-{
- struct dri_context *ctx = NULL;
- struct dri_context *share = (struct dri_context *)sharedContextPrivate;
- struct gl_context *mesaCtx = NULL;
- struct gl_context *sharedCtx = NULL;
- struct dd_function_table functions;
-
- TRACE;
-
- ctx = CALLOC_STRUCT(dri_context);
- if (ctx == NULL)
- goto context_fail;
-
- cPriv->driverPrivate = ctx;
- ctx->cPriv = cPriv;
-
- /* build table of device driver functions */
- _mesa_init_driver_functions(&functions);
- swrast_init_driver_functions(&functions);
-
- if (share) {
- sharedCtx = &share->Base;
- }
-
- mesaCtx = &ctx->Base;
-
- /* basic context setup */
- if (!_mesa_initialize_context_for_api(mesaCtx, api, visual, sharedCtx, &functions, (void *) cPriv)) {
- goto context_fail;
- }
-
- /* do bounds checking to prevent segfaults and server crashes! */
- mesaCtx->Const.CheckArrayBounds = GL_TRUE;
-
- /* create module contexts */
- _swrast_CreateContext( mesaCtx );
- _vbo_CreateContext( mesaCtx );
- _tnl_CreateContext( mesaCtx );
- _swsetup_CreateContext( mesaCtx );
- _swsetup_Wakeup( mesaCtx );
-
- /* use default TCL pipeline */
- {
- TNLcontext *tnl = TNL_CONTEXT(mesaCtx);
- tnl->Driver.RunPipeline = _tnl_run_pipeline;
- }
-
- _mesa_meta_init(mesaCtx);
- _mesa_enable_sw_extensions(mesaCtx);
-
- switch (api) {
- case API_OPENGL:
- _mesa_enable_1_3_extensions(mesaCtx);
- _mesa_enable_1_4_extensions(mesaCtx);
- _mesa_enable_1_5_extensions(mesaCtx);
- _mesa_enable_2_0_extensions(mesaCtx);
- _mesa_enable_2_1_extensions(mesaCtx);
-
- driInitExtensions( mesaCtx, NULL, GL_FALSE );
- break;
- case API_OPENGLES:
- _mesa_enable_1_3_extensions(mesaCtx);
- _mesa_enable_1_4_extensions(mesaCtx);
- _mesa_enable_1_5_extensions(mesaCtx);
-
- break;
- case API_OPENGLES2:
- InitExtensionsES2( mesaCtx);
- break;
- }
-
- return GL_TRUE;
-
-context_fail:
-
- FREE(ctx);
-
- return GL_FALSE;
-}
-
-static void
-dri_destroy_context(__DRIcontext * cPriv)
-{
- TRACE;
-
- if (cPriv) {
- struct dri_context *ctx = dri_context(cPriv);
- struct gl_context *mesaCtx;
-
- mesaCtx = &ctx->Base;
-
- _mesa_meta_free(mesaCtx);
- _swsetup_DestroyContext( mesaCtx );
- _swrast_DestroyContext( mesaCtx );
- _tnl_DestroyContext( mesaCtx );
- _vbo_DestroyContext( mesaCtx );
- _mesa_destroy_context( mesaCtx );
- }
-}
-
-static GLboolean
-dri_make_current(__DRIcontext * cPriv,
- __DRIdrawable * driDrawPriv,
- __DRIdrawable * driReadPriv)
-{
- struct gl_context *mesaCtx;
- struct gl_framebuffer *mesaDraw;
- struct gl_framebuffer *mesaRead;
- TRACE;
-
- if (cPriv) {
- struct dri_context *ctx = dri_context(cPriv);
- struct dri_drawable *draw;
- struct dri_drawable *read;
-
- if (!driDrawPriv || !driReadPriv)
- return GL_FALSE;
-
- draw = dri_drawable(driDrawPriv);
- read = dri_drawable(driReadPriv);
- mesaCtx = &ctx->Base;
- mesaDraw = &draw->Base;
- mesaRead = &read->Base;
-
- /* check for same context and buffer */
- if (mesaCtx == _mesa_get_current_context()
- && mesaCtx->DrawBuffer == mesaDraw
- && mesaCtx->ReadBuffer == mesaRead) {
- return GL_TRUE;
- }
-
- _glapi_check_multithread();
-
- swrast_check_and_update_window_size(mesaCtx, mesaDraw);
- if (mesaRead != mesaDraw)
- swrast_check_and_update_window_size(mesaCtx, mesaRead);
-
- _mesa_make_current( mesaCtx,
- mesaDraw,
- mesaRead );
- }
- else {
- /* unbind */
- _mesa_make_current( NULL, NULL, NULL );
- }
-
- return GL_TRUE;
-}
-
-static GLboolean
-dri_unbind_context(__DRIcontext * cPriv)
-{
- TRACE;
- (void) cPriv;
-
- /* Unset current context and dispath table */
- _mesa_make_current(NULL, NULL, NULL);
-
- return GL_TRUE;
-}
-
-
-const struct __DriverAPIRec driDriverAPI = {
- /*.InitScreen = */dri_init_screen,
- /*.DestroyScreen = */dri_destroy_screen,
- /*.CreateContext = */dri_create_context,
- /*.DestroyContext = */dri_destroy_context,
- /*.CreateBuffer = */dri_create_buffer,
- /*.DestroyBuffer = */dri_destroy_buffer,
- /*.SwapBuffers = */dri_swap_buffers,
- /*.MakeCurrent = */dri_make_current,
- /*.UnbindContext = */dri_unbind_context,
-};
-
-/* This is the table of extensions that the loader will dlsym() for. */
-PUBLIC const __DRIextension *__driDriverExtensions[] = {
- &driCoreExtension.base,
- &driSWRastExtension.base,
- NULL
-};
+/*
+ * Copyright 2008, 2010 George Sapountzis <gsapountzis@gmail.com>
+ *
+ * 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.
+ */
+
+/*
+ * DRI software rasterizer
+ *
+ * This is the mesa swrast module packaged into a DRI driver structure.
+ *
+ * The front-buffer is allocated by the loader. The loader provides read/write
+ * callbacks for access to the front-buffer. The driver uses a scratch row for
+ * front-buffer rendering to avoid repeated calls to the loader.
+ *
+ * The back-buffer is allocated by the driver and is private.
+ */
+
+#ifdef _MSC_VER
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#endif
+
+#include "main/context.h"
+#include "main/extensions.h"
+#include "main/formats.h"
+#include "main/framebuffer.h"
+#include "main/imports.h"
+#include "main/renderbuffer.h"
+#include "swrast/swrast.h"
+#include "swrast_setup/swrast_setup.h"
+#include "tnl/tnl.h"
+#include "tnl/t_context.h"
+#include "tnl/t_pipeline.h"
+#include "vbo/vbo.h"
+#include "drivers/common/driverfuncs.h"
+#include "drivers/common/meta.h"
+#include "utils.h"
+
+#include "main/teximage.h"
+#include "main/texformat.h"
+#include "main/texstate.h"
+
+#include "swrast_priv.h"
+
+
+/**
+ * Screen and config-related functions
+ */
+
+static void swrastSetTexBuffer2(__DRIcontext *pDRICtx, GLint target,
+ GLint texture_format, __DRIdrawable *dPriv)
+{
+ struct dri_context *dri_ctx;
+ int x, y, w, h;
+ __DRIscreen *sPriv = dPriv->driScreenPriv;
+ struct gl_texture_unit *texUnit;
+ struct gl_texture_object *texObj;
+ struct gl_texture_image *texImage;
+ uint32_t internalFormat;
+ gl_format texFormat;
+
+ dri_ctx = pDRICtx->driverPrivate;
+
+ internalFormat = (texture_format == __DRI_TEXTURE_FORMAT_RGB ? 3 : 4);
+
+ texUnit = _mesa_get_current_tex_unit(&dri_ctx->Base);
+ texObj = _mesa_select_tex_object(&dri_ctx->Base, texUnit, target);
+ texImage = _mesa_get_tex_image(&dri_ctx->Base, texObj, target, 0);
+
+ _mesa_lock_texture(&dri_ctx->Base, texObj);
+
+ sPriv->swrast_loader->getDrawableInfo(dPriv, &x, &y, &w, &h, dPriv->loaderPrivate);
+
+ if (texture_format == __DRI_TEXTURE_FORMAT_RGB)
+ texFormat = MESA_FORMAT_XRGB8888;
+ else
+ texFormat = MESA_FORMAT_ARGB8888;
+
+ _mesa_init_teximage_fields(&dri_ctx->Base, target, texImage,
+ w, h, 1, 0, internalFormat, texFormat);
+
+ sPriv->swrast_loader->getImage(dPriv, x, y, w, h, (char *)texImage->Data,
+ dPriv->loaderPrivate);
+
+ _mesa_unlock_texture(&dri_ctx->Base, texObj);
+}
+
+static void swrastSetTexBuffer(__DRIcontext *pDRICtx, GLint target,
+ __DRIdrawable *dPriv)
+{
+ swrastSetTexBuffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
+}
+
+static const __DRItexBufferExtension swrastTexBufferExtension = {
+ { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
+ swrastSetTexBuffer,
+ swrastSetTexBuffer2,
+};
+
+static const __DRIextension *dri_screen_extensions[] = {
+ &swrastTexBufferExtension.base,
+ NULL
+};
+
+static __DRIconfig **
+swrastFillInModes(__DRIscreen *psp,
+ unsigned pixel_bits, unsigned depth_bits,
+ unsigned stencil_bits, GLboolean have_back_buffer)
+{
+ __DRIconfig **configs;
+ unsigned depth_buffer_factor;
+ unsigned back_buffer_factor;
+ GLenum fb_format;
+ GLenum fb_type;
+
+ /* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't
+ * support pageflipping at all.
+ */
+ static const GLenum back_buffer_modes[] = {
+ GLX_NONE, GLX_SWAP_UNDEFINED_OML
+ };
+
+ uint8_t depth_bits_array[4];
+ uint8_t stencil_bits_array[4];
+ uint8_t msaa_samples_array[1];
+
+ depth_bits_array[0] = 0;
+ depth_bits_array[1] = 0;
+ depth_bits_array[2] = depth_bits;
+ depth_bits_array[3] = depth_bits;
+
+ /* Just like with the accumulation buffer, always provide some modes
+ * with a stencil buffer.
+ */
+ stencil_bits_array[0] = 0;
+ stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
+ stencil_bits_array[2] = 0;
+ stencil_bits_array[3] = (stencil_bits == 0) ? 8 : stencil_bits;
+
+ msaa_samples_array[0] = 0;
+
+ depth_buffer_factor = 4;
+ back_buffer_factor = 2;
+
+ switch (pixel_bits) {
+ case 8:
+ fb_format = GL_RGB;
+ fb_type = GL_UNSIGNED_BYTE_2_3_3_REV;
+ break;
+ case 16:
+ fb_format = GL_RGB;
+ fb_type = GL_UNSIGNED_SHORT_5_6_5;
+ break;
+ case 24:
+ fb_format = GL_BGR;
+ fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ break;
+ case 32:
+ fb_format = GL_BGRA;
+ fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ break;
+ default:
+ fprintf(stderr, "[%s:%u] bad depth %d\n", __FUNCTION__, __LINE__,
+ pixel_bits);
+ return NULL;
+ }
+
+ configs = driCreateConfigs(fb_format, fb_type,
+ depth_bits_array, stencil_bits_array,
+ depth_buffer_factor, back_buffer_modes,
+ back_buffer_factor, msaa_samples_array, 1,
+ GL_TRUE);
+ if (configs == NULL) {
+ fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __FUNCTION__,
+ __LINE__);
+ return NULL;
+ }
+
+ return configs;
+}
+
+static const __DRIconfig **
+dri_init_screen(__DRIscreen * psp)
+{
+ __DRIconfig **configs8, **configs16, **configs24, **configs32;
+
+ TRACE;
+
+ psp->extensions = dri_screen_extensions;
+
+ configs8 = swrastFillInModes(psp, 8, 8, 0, 1);
+ configs16 = swrastFillInModes(psp, 16, 16, 0, 1);
+ configs24 = swrastFillInModes(psp, 24, 24, 8, 1);
+ configs32 = swrastFillInModes(psp, 32, 24, 8, 1);
+
+ configs16 = driConcatConfigs(configs8, configs16);
+ configs24 = driConcatConfigs(configs16, configs24);
+ configs32 = driConcatConfigs(configs24, configs32);
+
+ return (const __DRIconfig **)configs32;
+}
+
+static void
+dri_destroy_screen(__DRIscreen * sPriv)
+{
+ TRACE;
+}
+
+
+/**
+ * Framebuffer and renderbuffer-related functions.
+ */
+
+static GLuint
+choose_pixel_format(const struct gl_config *v)
+{
+ int depth = v->rgbBits;
+
+ if (depth == 32
+ && v->redMask == 0xff0000
+ && v->greenMask == 0x00ff00
+ && v->blueMask == 0x0000ff)
+ return PF_A8R8G8B8;
+ else if (depth == 24
+ && v->redMask == 0xff0000
+ && v->greenMask == 0x00ff00
+ && v->blueMask == 0x0000ff)
+ return PF_X8R8G8B8;
+ else if (depth == 16
+ && v->redMask == 0xf800
+ && v->greenMask == 0x07e0
+ && v->blueMask == 0x001f)
+ return PF_R5G6B5;
+ else if (depth == 8
+ && v->redMask == 0x07
+ && v->greenMask == 0x38
+ && v->blueMask == 0xc0)
+ return PF_R3G3B2;
+
+ _mesa_problem( NULL, "unexpected format in %s", __FUNCTION__ );
+ return 0;
+}
+
+static void
+swrast_delete_renderbuffer(struct gl_renderbuffer *rb)
+{
+ TRACE;
+
+ free(rb->Data);
+ free(rb);
+}
+
+/* see bytes_per_line in libGL */
+static INLINE int
+bytes_per_line(unsigned pitch_bits, unsigned mul)
+{
+ unsigned mask = mul - 1;
+
+ return ((pitch_bits + mask) & ~mask) / 8;
+}
+
+static GLboolean
+swrast_alloc_front_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLenum internalFormat, GLuint width, GLuint height)
+{
+ struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb);
+
+ TRACE;
+
+ rb->Data = NULL;
+ rb->Width = width;
+ rb->Height = height;
+
+ xrb->pitch = bytes_per_line(width * xrb->bpp, 32);
+
+ return GL_TRUE;
+}
+
+static GLboolean
+swrast_alloc_back_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLenum internalFormat, GLuint width, GLuint height)
+{
+ struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb);
+
+ TRACE;
+
+ free(rb->Data);
+
+ swrast_alloc_front_storage(ctx, rb, internalFormat, width, height);
+
+ rb->Data = malloc(height * xrb->pitch);
+
+ return GL_TRUE;
+}
+
+static struct swrast_renderbuffer *
+swrast_new_renderbuffer(const struct gl_config *visual, GLboolean front)
+{
+ struct swrast_renderbuffer *xrb = calloc(1, sizeof *xrb);
+ GLuint pixel_format;
+
+ TRACE;
+
+ if (!xrb)
+ return NULL;
+
+ _mesa_init_renderbuffer(&xrb->Base, 0);
+
+ pixel_format = choose_pixel_format(visual);
+
+ xrb->Base.Delete = swrast_delete_renderbuffer;
+ if (front) {
+ xrb->Base.AllocStorage = swrast_alloc_front_storage;
+ swrast_set_span_funcs_front(xrb, pixel_format);
+ }
+ else {
+ xrb->Base.AllocStorage = swrast_alloc_back_storage;
+ swrast_set_span_funcs_back(xrb, pixel_format);
+ }
+
+ switch (pixel_format) {
+ case PF_A8R8G8B8:
+ xrb->Base.Format = MESA_FORMAT_ARGB8888;
+ xrb->Base.InternalFormat = GL_RGBA;
+ xrb->Base._BaseFormat = GL_RGBA;
+ xrb->Base.DataType = GL_UNSIGNED_BYTE;
+ xrb->bpp = 32;
+ break;
+ case PF_X8R8G8B8:
+ xrb->Base.Format = MESA_FORMAT_ARGB8888; /* XXX */
+ xrb->Base.InternalFormat = GL_RGB;
+ xrb->Base._BaseFormat = GL_RGB;
+ xrb->Base.DataType = GL_UNSIGNED_BYTE;
+ xrb->bpp = 32;
+ break;
+ case PF_R5G6B5:
+ xrb->Base.Format = MESA_FORMAT_RGB565;
+ xrb->Base.InternalFormat = GL_RGB;
+ xrb->Base._BaseFormat = GL_RGB;
+ xrb->Base.DataType = GL_UNSIGNED_BYTE;
+ xrb->bpp = 16;
+ break;
+ case PF_R3G3B2:
+ xrb->Base.Format = MESA_FORMAT_RGB332;
+ xrb->Base.InternalFormat = GL_RGB;
+ xrb->Base._BaseFormat = GL_RGB;
+ xrb->Base.DataType = GL_UNSIGNED_BYTE;
+ xrb->bpp = 8;
+ break;
+ default:
+ return NULL;
+ }
+
+ return xrb;
+}
+
+static GLboolean
+dri_create_buffer(__DRIscreen * sPriv,
+ __DRIdrawable * dPriv,
+ const struct gl_config * visual, GLboolean isPixmap)
+{
+ struct dri_drawable *drawable = NULL;
+ struct gl_framebuffer *fb;
+ struct swrast_renderbuffer *frontrb, *backrb;
+
+ TRACE;
+
+ drawable = CALLOC_STRUCT(dri_drawable);
+ if (drawable == NULL)
+ goto drawable_fail;
+
+ dPriv->driverPrivate = drawable;
+ drawable->dPriv = dPriv;
+
+ drawable->row = malloc(MAX_WIDTH * 4);
+ if (drawable->row == NULL)
+ goto drawable_fail;
+
+ fb = &drawable->Base;
+
+ /* basic framebuffer setup */
+ _mesa_initialize_window_framebuffer(fb, visual);
+
+ /* add front renderbuffer */
+ frontrb = swrast_new_renderbuffer(visual, GL_TRUE);
+ _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontrb->Base);
+
+ /* add back renderbuffer */
+ if (visual->doubleBufferMode) {
+ backrb = swrast_new_renderbuffer(visual, GL_FALSE);
+ _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backrb->Base);
+ }
+
+ /* add software renderbuffers */
+ _mesa_add_soft_renderbuffers(fb,
+ GL_FALSE, /* color */
+ visual->haveDepthBuffer,
+ visual->haveStencilBuffer,
+ visual->haveAccumBuffer,
+ GL_FALSE, /* alpha */
+ GL_FALSE /* aux bufs */);
+
+ return GL_TRUE;
+
+drawable_fail:
+
+ if (drawable)
+ free(drawable->row);
+
+ FREE(drawable);
+
+ return GL_FALSE;
+}
+
+static void
+dri_destroy_buffer(__DRIdrawable * dPriv)
+{
+ TRACE;
+
+ if (dPriv) {
+ struct dri_drawable *drawable = dri_drawable(dPriv);
+ struct gl_framebuffer *fb;
+
+ free(drawable->row);
+
+ fb = &drawable->Base;
+
+ fb->DeletePending = GL_TRUE;
+ _mesa_reference_framebuffer(&fb, NULL);
+ }
+}
+
+static void
+dri_swap_buffers(__DRIdrawable * dPriv)
+{
+ __DRIscreen *sPriv = dPriv->driScreenPriv;
+
+ GET_CURRENT_CONTEXT(ctx);
+
+ struct dri_drawable *drawable = dri_drawable(dPriv);
+ struct gl_framebuffer *fb;
+ struct swrast_renderbuffer *frontrb, *backrb;
+
+ TRACE;
+
+ fb = &drawable->Base;
+
+ frontrb =
+ swrast_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
+ backrb =
+ swrast_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
+
+ /* check for signle-buffered */
+ if (backrb == NULL)
+ return;
+
+ /* check if swapping currently bound buffer */
+ if (ctx && ctx->DrawBuffer == fb) {
+ /* flush pending rendering */
+ _mesa_notifySwapBuffers(ctx);
+ }
+
+ sPriv->swrast_loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
+ 0, 0,
+ frontrb->Base.Width,
+ frontrb->Base.Height,
+ backrb->Base.Data,
+ dPriv->loaderPrivate);
+}
+
+
+/**
+ * General device driver functions.
+ */
+
+static void
+get_window_size( struct gl_framebuffer *fb, GLsizei *w, GLsizei *h )
+{
+ __DRIdrawable *dPriv = swrast_drawable(fb)->dPriv;
+ __DRIscreen *sPriv = dPriv->driScreenPriv;
+ int x, y;
+
+ sPriv->swrast_loader->getDrawableInfo(dPriv,
+ &x, &y, w, h,
+ dPriv->loaderPrivate);
+}
+
+static void
+swrast_check_and_update_window_size( struct gl_context *ctx, struct gl_framebuffer *fb )
+{
+ GLsizei width, height;
+
+ get_window_size(fb, &width, &height);
+ if (fb->Width != width || fb->Height != height) {
+ _mesa_resize_framebuffer(ctx, fb, width, height);
+ }
+}
+
+static const GLubyte *
+get_string(struct gl_context *ctx, GLenum pname)
+{
+ (void) ctx;
+ switch (pname) {
+ case GL_VENDOR:
+ return (const GLubyte *) "Mesa Project";
+ case GL_RENDERER:
+ return (const GLubyte *) "Software Rasterizer";
+ default:
+ return NULL;
+ }
+}
+
+static void
+update_state( struct gl_context *ctx, GLuint new_state )
+{
+ /* not much to do here - pass it on */
+ _swrast_InvalidateState( ctx, new_state );
+ _swsetup_InvalidateState( ctx, new_state );
+ _vbo_InvalidateState( ctx, new_state );
+ _tnl_InvalidateState( ctx, new_state );
+}
+
+static void
+viewport(struct gl_context *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
+{
+ struct gl_framebuffer *draw = ctx->WinSysDrawBuffer;
+ struct gl_framebuffer *read = ctx->WinSysReadBuffer;
+
+ swrast_check_and_update_window_size(ctx, draw);
+ swrast_check_and_update_window_size(ctx, read);
+}
+
+static gl_format swrastChooseTextureFormat(struct gl_context * ctx,
+ GLint internalFormat,
+ GLenum format,
+ GLenum type)
+{
+ if (internalFormat == GL_RGB)
+ return MESA_FORMAT_XRGB8888;
+ return _mesa_choose_tex_format(ctx, internalFormat, format, type);
+}
+
+static void
+swrast_init_driver_functions(struct dd_function_table *driver)
+{
+ driver->GetString = get_string;
+ driver->UpdateState = update_state;
+ driver->GetBufferSize = NULL;
+ driver->Viewport = viewport;
+ driver->ChooseTextureFormat = swrastChooseTextureFormat;
+}
+
+static const char *es2_extensions[] = {
+ /* Used by mesa internally (cf all_mesa_extensions in ../common/utils.c) */
+ "GL_ARB_draw_buffers",
+ "GL_ARB_multisample",
+ "GL_ARB_texture_compression",
+ "GL_ARB_transpose_matrix",
+ "GL_ARB_vertex_buffer_object",
+ "GL_ARB_window_pos",
+ "GL_EXT_blend_func_separate",
+ "GL_EXT_compiled_vertex_array",
+ "GL_EXT_framebuffer_blit",
+ "GL_EXT_multi_draw_arrays",
+ "GL_EXT_polygon_offset",
+ "GL_EXT_texture_object",
+ "GL_EXT_vertex_array",
+ "GL_IBM_multimode_draw_arrays",
+ "GL_MESA_window_pos",
+ "GL_NV_vertex_program",
+
+ /* Required by GLES2 */
+ "GL_ARB_fragment_program",
+ "GL_ARB_fragment_shader",
+ "GL_ARB_multitexture",
+ "GL_ARB_shader_objects",
+ "GL_ARB_texture_cube_map",
+ "GL_ARB_texture_mirrored_repeat",
+ "GL_ARB_texture_non_power_of_two",
+ "GL_ARB_vertex_shader",
+ "GL_EXT_blend_color",
+ "GL_EXT_blend_equation_separate",
+ "GL_EXT_blend_minmax",
+ "GL_EXT_blend_subtract",
+ "GL_EXT_stencil_wrap",
+
+ /* Optional GLES2 */
+ "GL_ARB_framebuffer_object",
+ "GL_EXT_texture_filter_anisotropic",
+ "GL_ARB_depth_texture",
+ "GL_EXT_packed_depth_stencil",
+ "GL_EXT_framebuffer_object",
+ NULL,
+};
+
+static void
+InitExtensionsES2(struct gl_context *ctx)
+{
+ int i;
+
+ /* Can't use driInitExtensions() since it uses extensions from
+ * main/remap_helper.h when called the first time. */
+
+ for (i = 0; es2_extensions[i]; i++)
+ _mesa_enable_extension(ctx, es2_extensions[i]);
+}
+
+/**
+ * Context-related functions.
+ */
+
+static GLboolean
+dri_create_context(gl_api api,
+ const struct gl_config * visual,
+ __DRIcontext * cPriv, void *sharedContextPrivate)
+{
+ struct dri_context *ctx = NULL;
+ struct dri_context *share = (struct dri_context *)sharedContextPrivate;
+ struct gl_context *mesaCtx = NULL;
+ struct gl_context *sharedCtx = NULL;
+ struct dd_function_table functions;
+
+ TRACE;
+
+ ctx = CALLOC_STRUCT(dri_context);
+ if (ctx == NULL)
+ goto context_fail;
+
+ cPriv->driverPrivate = ctx;
+ ctx->cPriv = cPriv;
+
+ /* build table of device driver functions */
+ _mesa_init_driver_functions(&functions);
+ swrast_init_driver_functions(&functions);
+
+ if (share) {
+ sharedCtx = &share->Base;
+ }
+
+ mesaCtx = &ctx->Base;
+
+ /* basic context setup */
+ if (!_mesa_initialize_context(mesaCtx, api, visual, sharedCtx, &functions, (void *) cPriv)) {
+ goto context_fail;
+ }
+
+ /* do bounds checking to prevent segfaults and server crashes! */
+ mesaCtx->Const.CheckArrayBounds = GL_TRUE;
+
+ /* create module contexts */
+ _swrast_CreateContext( mesaCtx );
+ _vbo_CreateContext( mesaCtx );
+ _tnl_CreateContext( mesaCtx );
+ _swsetup_CreateContext( mesaCtx );
+ _swsetup_Wakeup( mesaCtx );
+
+ /* use default TCL pipeline */
+ {
+ TNLcontext *tnl = TNL_CONTEXT(mesaCtx);
+ tnl->Driver.RunPipeline = _tnl_run_pipeline;
+ }
+
+ _mesa_meta_init(mesaCtx);
+ _mesa_enable_sw_extensions(mesaCtx);
+
+ switch (api) {
+ case API_OPENGL:
+ _mesa_enable_1_3_extensions(mesaCtx);
+ _mesa_enable_1_4_extensions(mesaCtx);
+ _mesa_enable_1_5_extensions(mesaCtx);
+ _mesa_enable_2_0_extensions(mesaCtx);
+ _mesa_enable_2_1_extensions(mesaCtx);
+
+ driInitExtensions( mesaCtx, NULL, GL_FALSE );
+ break;
+ case API_OPENGLES:
+ _mesa_enable_1_3_extensions(mesaCtx);
+ _mesa_enable_1_4_extensions(mesaCtx);
+ _mesa_enable_1_5_extensions(mesaCtx);
+
+ break;
+ case API_OPENGLES2:
+ InitExtensionsES2( mesaCtx);
+ break;
+ }
+
+ return GL_TRUE;
+
+context_fail:
+
+ FREE(ctx);
+
+ return GL_FALSE;
+}
+
+static void
+dri_destroy_context(__DRIcontext * cPriv)
+{
+ TRACE;
+
+ if (cPriv) {
+ struct dri_context *ctx = dri_context(cPriv);
+ struct gl_context *mesaCtx;
+
+ mesaCtx = &ctx->Base;
+
+ _mesa_meta_free(mesaCtx);
+ _swsetup_DestroyContext( mesaCtx );
+ _swrast_DestroyContext( mesaCtx );
+ _tnl_DestroyContext( mesaCtx );
+ _vbo_DestroyContext( mesaCtx );
+ _mesa_destroy_context( mesaCtx );
+ }
+}
+
+static GLboolean
+dri_make_current(__DRIcontext * cPriv,
+ __DRIdrawable * driDrawPriv,
+ __DRIdrawable * driReadPriv)
+{
+ struct gl_context *mesaCtx;
+ struct gl_framebuffer *mesaDraw;
+ struct gl_framebuffer *mesaRead;
+ TRACE;
+
+ if (cPriv) {
+ struct dri_context *ctx = dri_context(cPriv);
+ struct dri_drawable *draw;
+ struct dri_drawable *read;
+
+ if (!driDrawPriv || !driReadPriv)
+ return GL_FALSE;
+
+ draw = dri_drawable(driDrawPriv);
+ read = dri_drawable(driReadPriv);
+ mesaCtx = &ctx->Base;
+ mesaDraw = &draw->Base;
+ mesaRead = &read->Base;
+
+ /* check for same context and buffer */
+ if (mesaCtx == _mesa_get_current_context()
+ && mesaCtx->DrawBuffer == mesaDraw
+ && mesaCtx->ReadBuffer == mesaRead) {
+ return GL_TRUE;
+ }
+
+ _glapi_check_multithread();
+
+ swrast_check_and_update_window_size(mesaCtx, mesaDraw);
+ if (mesaRead != mesaDraw)
+ swrast_check_and_update_window_size(mesaCtx, mesaRead);
+
+ _mesa_make_current( mesaCtx,
+ mesaDraw,
+ mesaRead );
+ }
+ else {
+ /* unbind */
+ _mesa_make_current( NULL, NULL, NULL );
+ }
+
+ return GL_TRUE;
+}
+
+static GLboolean
+dri_unbind_context(__DRIcontext * cPriv)
+{
+ TRACE;
+ (void) cPriv;
+
+ /* Unset current context and dispath table */
+ _mesa_make_current(NULL, NULL, NULL);
+
+ return GL_TRUE;
+}
+
+
+const struct __DriverAPIRec driDriverAPI = {
+ /*.InitScreen = */dri_init_screen,
+ /*.DestroyScreen = */dri_destroy_screen,
+ /*.CreateContext = */dri_create_context,
+ /*.DestroyContext = */dri_destroy_context,
+ /*.CreateBuffer = */dri_create_buffer,
+ /*.DestroyBuffer = */dri_destroy_buffer,
+ /*.SwapBuffers = */dri_swap_buffers,
+ /*.MakeCurrent = */dri_make_current,
+ /*.UnbindContext = */dri_unbind_context,
+};
+
+/* This is the table of extensions that the loader will dlsym() for. */
+PUBLIC const __DRIextension *__driDriverExtensions[] = {
+ &driCoreExtension.base,
+ &driSWRastExtension.base,
+ NULL
+};
diff --git a/mesalib/src/mesa/drivers/windows/gdi/wmesa.c b/mesalib/src/mesa/drivers/windows/gdi/wmesa.c
index a30326c0c..1a13e9f5c 100644
--- a/mesalib/src/mesa/drivers/windows/gdi/wmesa.c
+++ b/mesalib/src/mesa/drivers/windows/gdi/wmesa.c
@@ -1479,7 +1479,8 @@ WMesaContext WMesaCreateContext(HDC hDC,
/* initialize the Mesa context data */
ctx = &c->gl_ctx;
- _mesa_initialize_context(ctx, visual, NULL, &functions, (void *)c);
+ _mesa_initialize_context(ctx, API_OPENGL, visual,
+ NULL, &functions, (void *)c);
/* visual no longer needed - it was copied by _mesa_initialize_context() */
_mesa_destroy_visual(visual);
diff --git a/mesalib/src/mesa/drivers/windows/gldirect/dglcontext.c b/mesalib/src/mesa/drivers/windows/gldirect/dglcontext.c
index fabce4c0b..bc4839cfe 100644
--- a/mesalib/src/mesa/drivers/windows/gldirect/dglcontext.c
+++ b/mesalib/src/mesa/drivers/windows/gldirect/dglcontext.c
@@ -1414,7 +1414,7 @@ SkipPrimaryCreate:
}
#ifdef _USE_GLD3_WGL
- lpCtx->glCtx = _mesa_create_context(lpCtx->glVis, NULL, (void *)lpCtx, GL_TRUE);
+ lpCtx->glCtx = _mesa_create_context(API_OPENGL, lpCtx->glVis, NULL, (void *)lpCtx, GL_TRUE);
#else
// Create the Mesa context
lpCtx->glCtx = (*mesaFuncs.gl_create_context)(
diff --git a/mesalib/src/mesa/main/blend.c b/mesalib/src/mesa/main/blend.c
index 30466cca3..22031fd2a 100644
--- a/mesalib/src/mesa/main/blend.c
+++ b/mesalib/src/mesa/main/blend.c
@@ -317,7 +317,7 @@ _mesa_BlendEquation( GLenum mode )
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx, "glBlendEquation %s\n",
+ _mesa_debug(ctx, "glBlendEquation(%s)\n",
_mesa_lookup_enum_by_nr(mode));
if (!legal_blend_equation(ctx, mode, GL_FALSE)) {
@@ -398,7 +398,7 @@ _mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA )
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx, "glBlendEquationSeparateEXT %s %s\n",
+ _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n",
_mesa_lookup_enum_by_nr(modeRGB),
_mesa_lookup_enum_by_nr(modeA));
@@ -454,7 +454,7 @@ _mesa_BlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeA)
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx, "glBlendEquationSeparatei %u, %s %s\n", buf,
+ _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf,
_mesa_lookup_enum_by_nr(modeRGB),
_mesa_lookup_enum_by_nr(modeA));
@@ -545,6 +545,10 @@ _mesa_AlphaFunc( GLenum func, GLclampf ref )
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glAlphaFunc(%s, %f)\n",
+ _mesa_lookup_enum_by_nr(func), ref);
+
switch (func) {
case GL_NEVER:
case GL_LESS:
@@ -590,6 +594,9 @@ _mesa_LogicOp( GLenum opcode )
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glLogicOp(%s)\n", _mesa_lookup_enum_by_nr(opcode));
+
switch (opcode) {
case GL_CLEAR:
case GL_SET:
@@ -664,7 +671,8 @@ _mesa_ColorMask( GLboolean red, GLboolean green,
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx, "glColorMask %d %d %d %d\n", red, green, blue, alpha);
+ _mesa_debug(ctx, "glColorMask(%d, %d, %d, %d)\n",
+ red, green, blue, alpha);
/* Shouldn't have any information about channel depth in core mesa
* -- should probably store these as the native booleans:
diff --git a/mesalib/src/mesa/main/bufferobj.c b/mesalib/src/mesa/main/bufferobj.c
index e971ee558..2de4602b8 100644
--- a/mesalib/src/mesa/main/bufferobj.c
+++ b/mesalib/src/mesa/main/bufferobj.c
@@ -970,6 +970,10 @@ _mesa_BindBufferARB(GLenum target, GLuint buffer)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glBindBuffer(%s, %u)\n",
+ _mesa_lookup_enum_by_nr(target), buffer);
+
bind_buffer_object(ctx, target, buffer);
}
@@ -1064,6 +1068,9 @@ _mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
GLint i;
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glGenBuffers(%d)\n", n);
+
if (n < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB");
return;
@@ -1121,6 +1128,12 @@ _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
struct gl_buffer_object *bufObj;
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glBufferData(%s, %ld, %p, %s)\n",
+ _mesa_lookup_enum_by_nr(target),
+ (long int) size, data,
+ _mesa_lookup_enum_by_nr(usage));
+
if (size < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)");
return;
diff --git a/mesalib/src/mesa/main/context.c b/mesalib/src/mesa/main/context.c
index e017939a4..cfb6b348b 100644
--- a/mesalib/src/mesa/main/context.c
+++ b/mesalib/src/mesa/main/context.c
@@ -1,1917 +1,1882 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.3
- *
- * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
- * Copyright (C) 2008 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 context.c
- * Mesa context/visual/framebuffer management functions.
- * \author Brian Paul
- */
-
-/**
- * \mainpage Mesa Main Module
- *
- * \section MainIntroduction Introduction
- *
- * The Mesa Main module consists of all the files in the main/ directory.
- * Among the features of this module are:
- * <UL>
- * <LI> Structures to represent most GL state </LI>
- * <LI> State set/get functions </LI>
- * <LI> Display lists </LI>
- * <LI> Texture unit, object and image handling </LI>
- * <LI> Matrix and attribute stacks </LI>
- * </UL>
- *
- * Other modules are responsible for API dispatch, vertex transformation,
- * point/line/triangle setup, rasterization, vertex array caching,
- * vertex/fragment programs/shaders, etc.
- *
- *
- * \section AboutDoxygen About Doxygen
- *
- * If you're viewing this information as Doxygen-generated HTML you'll
- * see the documentation index at the top of this page.
- *
- * The first line lists the Mesa source code modules.
- * The second line lists the indexes available for viewing the documentation
- * for each module.
- *
- * Selecting the <b>Main page</b> link will display a summary of the module
- * (this page).
- *
- * Selecting <b>Data Structures</b> will list all C structures.
- *
- * Selecting the <b>File List</b> link will list all the source files in
- * the module.
- * Selecting a filename will show a list of all functions defined in that file.
- *
- * Selecting the <b>Data Fields</b> link will display a list of all
- * documented structure members.
- *
- * Selecting the <b>Globals</b> link will display a list
- * of all functions, structures, global variables and macros in the module.
- *
- */
-
-
-#include "glheader.h"
-#include "mfeatures.h"
-#include "imports.h"
-#include "accum.h"
-#include "api_exec.h"
-#include "arrayobj.h"
-#include "attrib.h"
-#include "blend.h"
-#include "buffers.h"
-#include "bufferobj.h"
-#include "context.h"
-#include "cpuinfo.h"
-#include "debug.h"
-#include "depth.h"
-#include "dlist.h"
-#include "eval.h"
-#include "extensions.h"
-#include "fbobject.h"
-#include "feedback.h"
-#include "fog.h"
-#include "formats.h"
-#include "framebuffer.h"
-#include "hint.h"
-#include "hash.h"
-#include "light.h"
-#include "lines.h"
-#include "macros.h"
-#include "matrix.h"
-#include "multisample.h"
-#include "pixel.h"
-#include "pixelstore.h"
-#include "points.h"
-#include "polygon.h"
-#include "queryobj.h"
-#include "syncobj.h"
-#include "rastpos.h"
-#include "remap.h"
-#include "scissor.h"
-#include "shared.h"
-#include "shaderobj.h"
-#include "simple_list.h"
-#include "state.h"
-#include "stencil.h"
-#include "texcompress_s3tc.h"
-#include "texstate.h"
-#include "transformfeedback.h"
-#include "mtypes.h"
-#include "varray.h"
-#include "version.h"
-#include "viewport.h"
-#include "vtxfmt.h"
-#include "program/program.h"
-#include "program/prog_print.h"
-#if _HAVE_FULL_GL
-#include "math/m_matrix.h"
-#endif
-#include "main/dispatch.h" /* for _gloffset_COUNT */
-
-#ifdef USE_SPARC_ASM
-#include "sparc/sparc.h"
-#endif
-
-#include "glsl_parser_extras.h"
-#include <stdbool.h>
-
-
-#ifndef MESA_VERBOSE
-int MESA_VERBOSE = 0;
-#endif
-
-#ifndef MESA_DEBUG_FLAGS
-int MESA_DEBUG_FLAGS = 0;
-#endif
-
-
-/* ubyte -> float conversion */
-GLfloat _mesa_ubyte_to_float_color_tab[256];
-
-
-
-/**
- * Swap buffers notification callback.
- *
- * \param ctx GL context.
- *
- * Called by window system just before swapping buffers.
- * We have to finish any pending rendering.
- */
-void
-_mesa_notifySwapBuffers(struct gl_context *ctx)
-{
- if (MESA_VERBOSE & VERBOSE_SWAPBUFFERS)
- _mesa_debug(ctx, "SwapBuffers\n");
- FLUSH_CURRENT( ctx, 0 );
- if (ctx->Driver.Flush) {
- ctx->Driver.Flush(ctx);
- }
-}
-
-
-/**********************************************************************/
-/** \name GL Visual allocation/destruction */
-/**********************************************************************/
-/*@{*/
-
-/**
- * Allocates a struct gl_config structure and initializes it via
- * _mesa_initialize_visual().
- *
- * \param dbFlag double buffering
- * \param stereoFlag stereo buffer
- * \param depthBits requested bits per depth buffer value. Any value in [0, 32]
- * is acceptable but the actual depth type will be GLushort or GLuint as
- * needed.
- * \param stencilBits requested minimum bits per stencil buffer value
- * \param accumRedBits, accumGreenBits, accumBlueBits, accumAlphaBits number of bits per color component in accum buffer.
- * \param indexBits number of bits per pixel if \p rgbFlag is GL_FALSE
- * \param redBits number of bits per color component in frame buffer for RGB(A)
- * mode. We always use 8 in core Mesa though.
- * \param greenBits same as above.
- * \param blueBits same as above.
- * \param alphaBits same as above.
- * \param numSamples not really used.
- *
- * \return pointer to new struct gl_config or NULL if requested parameters can't be
- * met.
- *
- * \note Need to add params for level and numAuxBuffers (at least)
- */
-struct gl_config *
-_mesa_create_visual( GLboolean dbFlag,
- GLboolean stereoFlag,
- GLint redBits,
- GLint greenBits,
- GLint blueBits,
- GLint alphaBits,
- GLint depthBits,
- GLint stencilBits,
- GLint accumRedBits,
- GLint accumGreenBits,
- GLint accumBlueBits,
- GLint accumAlphaBits,
- GLint numSamples )
-{
- struct gl_config *vis = CALLOC_STRUCT(gl_config);
- if (vis) {
- if (!_mesa_initialize_visual(vis, dbFlag, stereoFlag,
- redBits, greenBits, blueBits, alphaBits,
- depthBits, stencilBits,
- accumRedBits, accumGreenBits,
- accumBlueBits, accumAlphaBits,
- numSamples)) {
- free(vis);
- return NULL;
- }
- }
- return vis;
-}
-
-
-/**
- * Makes some sanity checks and fills in the fields of the struct
- * gl_config object with the given parameters. If the caller needs to
- * set additional fields, he should just probably init the whole
- * gl_config object himself.
- *
- * \return GL_TRUE on success, or GL_FALSE on failure.
- *
- * \sa _mesa_create_visual() above for the parameter description.
- */
-GLboolean
-_mesa_initialize_visual( struct gl_config *vis,
- GLboolean dbFlag,
- GLboolean stereoFlag,
- GLint redBits,
- GLint greenBits,
- GLint blueBits,
- GLint alphaBits,
- GLint depthBits,
- GLint stencilBits,
- GLint accumRedBits,
- GLint accumGreenBits,
- GLint accumBlueBits,
- GLint accumAlphaBits,
- GLint numSamples )
-{
- assert(vis);
-
- if (depthBits < 0 || depthBits > 32) {
- return GL_FALSE;
- }
- if (stencilBits < 0 || stencilBits > STENCIL_BITS) {
- return GL_FALSE;
- }
- assert(accumRedBits >= 0);
- assert(accumGreenBits >= 0);
- assert(accumBlueBits >= 0);
- assert(accumAlphaBits >= 0);
-
- vis->rgbMode = GL_TRUE;
- vis->doubleBufferMode = dbFlag;
- vis->stereoMode = stereoFlag;
-
- vis->redBits = redBits;
- vis->greenBits = greenBits;
- vis->blueBits = blueBits;
- vis->alphaBits = alphaBits;
- vis->rgbBits = redBits + greenBits + blueBits;
-
- vis->indexBits = 0;
- vis->depthBits = depthBits;
- vis->stencilBits = stencilBits;
-
- vis->accumRedBits = accumRedBits;
- vis->accumGreenBits = accumGreenBits;
- vis->accumBlueBits = accumBlueBits;
- vis->accumAlphaBits = accumAlphaBits;
-
- vis->haveAccumBuffer = accumRedBits > 0;
- vis->haveDepthBuffer = depthBits > 0;
- vis->haveStencilBuffer = stencilBits > 0;
-
- vis->numAuxBuffers = 0;
- vis->level = 0;
- vis->sampleBuffers = numSamples > 0 ? 1 : 0;
- vis->samples = numSamples;
-
- return GL_TRUE;
-}
-
-
-/**
- * Destroy a visual and free its memory.
- *
- * \param vis visual.
- *
- * Frees the visual structure.
- */
-void
-_mesa_destroy_visual( struct gl_config *vis )
-{
- free(vis);
-}
-
-/*@}*/
-
-
-/**********************************************************************/
-/** \name Context allocation, initialization, destroying
- *
- * The purpose of the most initialization functions here is to provide the
- * default state values according to the OpenGL specification.
- */
-/**********************************************************************/
-/*@{*/
-
-
-/**
- * This is lame. gdb only seems to recognize enum types that are
- * actually used somewhere. We want to be able to print/use enum
- * values such as TEXTURE_2D_INDEX in gdb. But we don't actually use
- * the gl_texture_index type anywhere. Thus, this lame function.
- */
-static void
-dummy_enum_func(void)
-{
- gl_buffer_index bi = BUFFER_FRONT_LEFT;
- gl_face_index fi = FACE_POS_X;
- gl_frag_attrib fa = FRAG_ATTRIB_WPOS;
- gl_frag_result fr = FRAG_RESULT_DEPTH;
- gl_texture_index ti = TEXTURE_2D_ARRAY_INDEX;
- gl_vert_attrib va = VERT_ATTRIB_POS;
- gl_vert_result vr = VERT_RESULT_HPOS;
- gl_geom_attrib ga = GEOM_ATTRIB_POSITION;
- gl_geom_result gr = GEOM_RESULT_POS;
-
- (void) bi;
- (void) fi;
- (void) fa;
- (void) fr;
- (void) ti;
- (void) va;
- (void) vr;
- (void) ga;
- (void) gr;
-}
-
-
-/**
- * One-time initialization mutex lock.
- *
- * \sa Used by one_time_init().
- */
-_glthread_DECLARE_STATIC_MUTEX(OneTimeLock);
-
-
-
-/**
- * Calls all the various one-time-init functions in Mesa.
- *
- * While holding a global mutex lock, calls several initialization functions,
- * and sets the glapi callbacks if the \c MESA_DEBUG environment variable is
- * defined.
- *
- * \sa _math_init().
- */
-static void
-one_time_init( struct gl_context *ctx )
-{
- static GLbitfield api_init_mask = 0x0;
-
- _glthread_LOCK_MUTEX(OneTimeLock);
-
- /* truly one-time init */
- if (!api_init_mask) {
- GLuint i;
-
- /* do some implementation tests */
- assert( sizeof(GLbyte) == 1 );
- assert( sizeof(GLubyte) == 1 );
- assert( sizeof(GLshort) == 2 );
- assert( sizeof(GLushort) == 2 );
- assert( sizeof(GLint) == 4 );
- assert( sizeof(GLuint) == 4 );
-
- _mesa_get_cpu_features();
-
- _mesa_init_sqrt_table();
-
- /* context dependence is never a one-time thing... */
- _mesa_init_get_hash(ctx);
-
- for (i = 0; i < 256; i++) {
- _mesa_ubyte_to_float_color_tab[i] = (float) i / 255.0F;
- }
-
-#if defined(DEBUG) && defined(__DATE__) && defined(__TIME__)
- if (MESA_VERBOSE != 0) {
- _mesa_debug(ctx, "Mesa %s DEBUG build %s %s\n",
- MESA_VERSION_STRING, __DATE__, __TIME__);
- }
-#endif
-
-#ifdef DEBUG
- _mesa_test_formats();
-#endif
- }
-
- /* per-API one-time init */
- if (!(api_init_mask & (1 << ctx->API))) {
- /*
- * This is fine as ES does not use the remap table, but it may not be
- * future-proof. We cannot always initialize the remap table because
- * when an app is linked to libGLES*, there are not enough dynamic
- * entries.
- */
- if (ctx->API == API_OPENGL)
- _mesa_init_remap_table();
- }
-
- api_init_mask |= 1 << ctx->API;
-
- _glthread_UNLOCK_MUTEX(OneTimeLock);
-
- /* Hopefully atexit() is widely available. If not, we may need some
- * #ifdef tests here.
- */
- atexit(_mesa_destroy_shader_compiler);
-
- dummy_enum_func();
-}
-
-
-/**
- * Initialize fields of gl_current_attrib (aka ctx->Current.*)
- */
-static void
-_mesa_init_current(struct gl_context *ctx)
-{
- GLuint i;
-
- /* Init all to (0,0,0,1) */
- for (i = 0; i < Elements(ctx->Current.Attrib); i++) {
- ASSIGN_4V( ctx->Current.Attrib[i], 0.0, 0.0, 0.0, 1.0 );
- }
-
- /* redo special cases: */
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_WEIGHT], 1.0, 0.0, 0.0, 0.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_NORMAL], 0.0, 0.0, 1.0, 1.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR0], 1.0, 1.0, 1.0, 1.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR1], 0.0, 0.0, 0.0, 1.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR_INDEX], 1.0, 0.0, 0.0, 1.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG], 1.0, 0.0, 0.0, 1.0 );
-}
-
-
-/**
- * Init vertex/fragment/geometry program limits.
- * Important: drivers should override these with actual limits.
- */
-static void
-init_program_limits(GLenum type, struct gl_program_constants *prog)
-{
- prog->MaxInstructions = MAX_PROGRAM_INSTRUCTIONS;
- prog->MaxAluInstructions = MAX_PROGRAM_INSTRUCTIONS;
- prog->MaxTexInstructions = MAX_PROGRAM_INSTRUCTIONS;
- prog->MaxTexIndirections = MAX_PROGRAM_INSTRUCTIONS;
- prog->MaxTemps = MAX_PROGRAM_TEMPS;
- prog->MaxEnvParams = MAX_PROGRAM_ENV_PARAMS;
- prog->MaxLocalParams = MAX_PROGRAM_LOCAL_PARAMS;
- prog->MaxUniformComponents = 4 * MAX_UNIFORMS;
-
- switch (type) {
- case GL_VERTEX_PROGRAM_ARB:
- prog->MaxParameters = MAX_VERTEX_PROGRAM_PARAMS;
- prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS;
- prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS;
- break;
- case GL_FRAGMENT_PROGRAM_ARB:
- prog->MaxParameters = MAX_NV_FRAGMENT_PROGRAM_PARAMS;
- prog->MaxAttribs = MAX_NV_FRAGMENT_PROGRAM_INPUTS;
- prog->MaxAddressRegs = MAX_FRAGMENT_PROGRAM_ADDRESS_REGS;
- break;
- case MESA_GEOMETRY_PROGRAM:
- prog->MaxParameters = MAX_NV_VERTEX_PROGRAM_PARAMS;
- prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS;
- prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS;
-
- prog->MaxGeometryTextureImageUnits = MAX_GEOMETRY_TEXTURE_IMAGE_UNITS;
- prog->MaxGeometryVaryingComponents = MAX_GEOMETRY_VARYING_COMPONENTS;
- prog->MaxVertexVaryingComponents = MAX_VERTEX_VARYING_COMPONENTS;
- prog->MaxGeometryUniformComponents = MAX_GEOMETRY_UNIFORM_COMPONENTS;
- prog->MaxGeometryOutputVertices = MAX_GEOMETRY_OUTPUT_VERTICES;
- prog->MaxGeometryTotalOutputComponents = MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS;
- break;
- default:
- assert(0 && "Bad program type in init_program_limits()");
- }
-
- /* Set the native limits to zero. This implies that there is no native
- * support for shaders. Let the drivers fill in the actual values.
- */
- prog->MaxNativeInstructions = 0;
- prog->MaxNativeAluInstructions = 0;
- prog->MaxNativeTexInstructions = 0;
- prog->MaxNativeTexIndirections = 0;
- prog->MaxNativeAttribs = 0;
- prog->MaxNativeTemps = 0;
- prog->MaxNativeAddressRegs = 0;
- prog->MaxNativeParameters = 0;
-
- /* Set GLSL datatype range/precision info assuming IEEE float values.
- * Drivers should override these defaults as needed.
- */
- prog->MediumFloat.RangeMin = 127;
- prog->MediumFloat.RangeMax = 127;
- prog->MediumFloat.Precision = 23;
- prog->LowFloat = prog->HighFloat = prog->MediumFloat;
-
- /* Assume ints are stored as floats for now, since this is the least-common
- * denominator. The OpenGL ES spec implies (page 132) that the precision
- * of integer types should be 0. Practically speaking, IEEE
- * single-precision floating point values can only store integers in the
- * range [-0x01000000, 0x01000000] without loss of precision.
- */
- prog->MediumInt.RangeMin = 24;
- prog->MediumInt.RangeMax = 24;
- prog->MediumInt.Precision = 0;
- prog->LowInt = prog->HighInt = prog->MediumInt;
-}
-
-
-/**
- * Initialize fields of gl_constants (aka ctx->Const.*).
- * Use defaults from config.h. The device drivers will often override
- * some of these values (such as number of texture units).
- */
-static void
-_mesa_init_constants(struct gl_context *ctx)
-{
- assert(ctx);
-
- /* Constants, may be overriden (usually only reduced) by device drivers */
- ctx->Const.MaxTextureMbytes = MAX_TEXTURE_MBYTES;
- ctx->Const.MaxTextureLevels = MAX_TEXTURE_LEVELS;
- ctx->Const.Max3DTextureLevels = MAX_3D_TEXTURE_LEVELS;
- ctx->Const.MaxCubeTextureLevels = MAX_CUBE_TEXTURE_LEVELS;
- ctx->Const.MaxTextureRectSize = MAX_TEXTURE_RECT_SIZE;
- ctx->Const.MaxArrayTextureLayers = MAX_ARRAY_TEXTURE_LAYERS;
- ctx->Const.MaxTextureCoordUnits = MAX_TEXTURE_COORD_UNITS;
- ctx->Const.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
- ctx->Const.MaxTextureUnits = MIN2(ctx->Const.MaxTextureCoordUnits,
- ctx->Const.MaxTextureImageUnits);
- ctx->Const.MaxTextureMaxAnisotropy = MAX_TEXTURE_MAX_ANISOTROPY;
- ctx->Const.MaxTextureLodBias = MAX_TEXTURE_LOD_BIAS;
- ctx->Const.MaxArrayLockSize = MAX_ARRAY_LOCK_SIZE;
- ctx->Const.SubPixelBits = SUB_PIXEL_BITS;
- ctx->Const.MinPointSize = MIN_POINT_SIZE;
- ctx->Const.MaxPointSize = MAX_POINT_SIZE;
- ctx->Const.MinPointSizeAA = MIN_POINT_SIZE;
- ctx->Const.MaxPointSizeAA = MAX_POINT_SIZE;
- ctx->Const.PointSizeGranularity = (GLfloat) POINT_SIZE_GRANULARITY;
- ctx->Const.MinLineWidth = MIN_LINE_WIDTH;
- ctx->Const.MaxLineWidth = MAX_LINE_WIDTH;
- ctx->Const.MinLineWidthAA = MIN_LINE_WIDTH;
- ctx->Const.MaxLineWidthAA = MAX_LINE_WIDTH;
- ctx->Const.LineWidthGranularity = (GLfloat) LINE_WIDTH_GRANULARITY;
- ctx->Const.MaxColorTableSize = MAX_COLOR_TABLE_SIZE;
- ctx->Const.MaxClipPlanes = MAX_CLIP_PLANES;
- ctx->Const.MaxLights = MAX_LIGHTS;
- ctx->Const.MaxShininess = 128.0;
- ctx->Const.MaxSpotExponent = 128.0;
- ctx->Const.MaxViewportWidth = MAX_WIDTH;
- ctx->Const.MaxViewportHeight = MAX_HEIGHT;
-#if FEATURE_ARB_vertex_program
- init_program_limits(GL_VERTEX_PROGRAM_ARB, &ctx->Const.VertexProgram);
-#endif
-#if FEATURE_ARB_fragment_program
- init_program_limits(GL_FRAGMENT_PROGRAM_ARB, &ctx->Const.FragmentProgram);
-#endif
-#if FEATURE_ARB_geometry_shader4
- init_program_limits(MESA_GEOMETRY_PROGRAM, &ctx->Const.GeometryProgram);
-#endif
- ctx->Const.MaxProgramMatrices = MAX_PROGRAM_MATRICES;
- ctx->Const.MaxProgramMatrixStackDepth = MAX_PROGRAM_MATRIX_STACK_DEPTH;
-
- /* CheckArrayBounds is overriden by drivers/x11 for X server */
- ctx->Const.CheckArrayBounds = GL_FALSE;
-
- /* GL_ARB_draw_buffers */
- ctx->Const.MaxDrawBuffers = MAX_DRAW_BUFFERS;
-
-#if FEATURE_EXT_framebuffer_object
- ctx->Const.MaxColorAttachments = MAX_COLOR_ATTACHMENTS;
- ctx->Const.MaxRenderbufferSize = MAX_WIDTH;
-#endif
-
-#if FEATURE_ARB_vertex_shader
- ctx->Const.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
- ctx->Const.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
- ctx->Const.MaxVarying = MAX_VARYING;
-#endif
-
- /* Shading language version */
- if (ctx->API == API_OPENGL) {
- ctx->Const.GLSLVersion = 120;
- }
- else if (ctx->API == API_OPENGLES2) {
- ctx->Const.GLSLVersion = 100;
- }
- else if (ctx->API == API_OPENGLES) {
- ctx->Const.GLSLVersion = 0; /* GLSL not supported */
- }
-
- /* GL_ARB_framebuffer_object */
- ctx->Const.MaxSamples = 0;
-
- /* GL_ARB_sync */
- ctx->Const.MaxServerWaitTimeout = (GLuint64) ~0;
-
- /* GL_ATI_envmap_bumpmap */
- ctx->Const.SupportedBumpUnits = SUPPORTED_ATI_BUMP_UNITS;
-
- /* GL_EXT_provoking_vertex */
- ctx->Const.QuadsFollowProvokingVertexConvention = GL_TRUE;
-
- /* GL_EXT_transform_feedback */
- ctx->Const.MaxTransformFeedbackSeparateAttribs = MAX_FEEDBACK_ATTRIBS;
- ctx->Const.MaxTransformFeedbackSeparateComponents = 4 * MAX_FEEDBACK_ATTRIBS;
- ctx->Const.MaxTransformFeedbackInterleavedComponents = 4 * MAX_FEEDBACK_ATTRIBS;
-
- /* GL 3.2: hard-coded for now: */
- ctx->Const.ProfileMask = GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
-
- /** GL_EXT_gpu_shader4 */
- ctx->Const.MinProgramTexelOffset = -8;
- ctx->Const.MaxProgramTexelOffset = 7;
-}
-
-
-/**
- * Do some sanity checks on the limits/constants for the given context.
- * Only called the first time a context is bound.
- */
-static void
-check_context_limits(struct gl_context *ctx)
-{
- /* check that we don't exceed the size of various bitfields */
- assert(VERT_RESULT_MAX <=
- (8 * sizeof(ctx->VertexProgram._Current->Base.OutputsWritten)));
- assert(FRAG_ATTRIB_MAX <=
- (8 * sizeof(ctx->FragmentProgram._Current->Base.InputsRead)));
-
- assert(MAX_COMBINED_TEXTURE_IMAGE_UNITS <= 8 * sizeof(GLbitfield));
-
- /* shader-related checks */
- assert(ctx->Const.FragmentProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS);
- assert(ctx->Const.VertexProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS);
-
- assert(MAX_NV_FRAGMENT_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS);
- assert(MAX_NV_VERTEX_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS);
- assert(MAX_NV_VERTEX_PROGRAM_INPUTS <= VERT_ATTRIB_MAX);
- assert(MAX_NV_VERTEX_PROGRAM_OUTPUTS <= VERT_RESULT_MAX);
-
- /* Texture unit checks */
- assert(ctx->Const.MaxTextureImageUnits > 0);
- assert(ctx->Const.MaxTextureImageUnits <= MAX_TEXTURE_IMAGE_UNITS);
- assert(ctx->Const.MaxTextureCoordUnits > 0);
- assert(ctx->Const.MaxTextureCoordUnits <= MAX_TEXTURE_COORD_UNITS);
- assert(ctx->Const.MaxTextureUnits > 0);
- assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_IMAGE_UNITS);
- assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_COORD_UNITS);
- assert(ctx->Const.MaxTextureUnits == MIN2(ctx->Const.MaxTextureImageUnits,
- ctx->Const.MaxTextureCoordUnits));
- assert(ctx->Const.MaxCombinedTextureImageUnits > 0);
- assert(ctx->Const.MaxCombinedTextureImageUnits <= MAX_COMBINED_TEXTURE_IMAGE_UNITS);
- assert(ctx->Const.MaxTextureCoordUnits <= MAX_COMBINED_TEXTURE_IMAGE_UNITS);
- /* number of coord units cannot be greater than number of image units */
- assert(ctx->Const.MaxTextureCoordUnits <= ctx->Const.MaxTextureImageUnits);
-
-
- /* Texture size checks */
- assert(ctx->Const.MaxTextureLevels <= MAX_TEXTURE_LEVELS);
- assert(ctx->Const.Max3DTextureLevels <= MAX_3D_TEXTURE_LEVELS);
- assert(ctx->Const.MaxCubeTextureLevels <= MAX_CUBE_TEXTURE_LEVELS);
- assert(ctx->Const.MaxTextureRectSize <= MAX_TEXTURE_RECT_SIZE);
-
- /* make sure largest texture image is <= MAX_WIDTH in size */
- assert((1 << (ctx->Const.MaxTextureLevels - 1)) <= MAX_WIDTH);
- assert((1 << (ctx->Const.MaxCubeTextureLevels - 1)) <= MAX_WIDTH);
- assert((1 << (ctx->Const.Max3DTextureLevels - 1)) <= MAX_WIDTH);
-
- /* Texture level checks */
- assert(MAX_TEXTURE_LEVELS >= MAX_3D_TEXTURE_LEVELS);
- assert(MAX_TEXTURE_LEVELS >= MAX_CUBE_TEXTURE_LEVELS);
-
- /* Max texture size should be <= max viewport size (render to texture) */
- assert((1 << (MAX_TEXTURE_LEVELS - 1)) <= MAX_WIDTH);
-
- assert(ctx->Const.MaxViewportWidth <= MAX_WIDTH);
- assert(ctx->Const.MaxViewportHeight <= MAX_WIDTH);
-
- assert(ctx->Const.MaxDrawBuffers <= MAX_DRAW_BUFFERS);
-
- /* if this fails, add more enum values to gl_buffer_index */
- assert(BUFFER_COLOR0 + MAX_DRAW_BUFFERS <= BUFFER_COUNT);
-
- /* XXX probably add more tests */
-}
-
-
-/**
- * Initialize the attribute groups in a GL context.
- *
- * \param ctx GL context.
- *
- * Initializes all the attributes, calling the respective <tt>init*</tt>
- * functions for the more complex data structures.
- */
-static GLboolean
-init_attrib_groups(struct gl_context *ctx)
-{
- assert(ctx);
-
- /* Constants */
- _mesa_init_constants( ctx );
-
- /* Extensions */
- _mesa_init_extensions( ctx );
-
- /* Attribute Groups */
- _mesa_init_accum( ctx );
- _mesa_init_attrib( ctx );
- _mesa_init_buffer_objects( ctx );
- _mesa_init_color( ctx );
- _mesa_init_current( ctx );
- _mesa_init_depth( ctx );
- _mesa_init_debug( ctx );
- _mesa_init_display_list( ctx );
- _mesa_init_eval( ctx );
- _mesa_init_fbobjects( ctx );
- _mesa_init_feedback( ctx );
- _mesa_init_fog( ctx );
- _mesa_init_hint( ctx );
- _mesa_init_line( ctx );
- _mesa_init_lighting( ctx );
- _mesa_init_matrix( ctx );
- _mesa_init_multisample( ctx );
- _mesa_init_pixel( ctx );
- _mesa_init_pixelstore( ctx );
- _mesa_init_point( ctx );
- _mesa_init_polygon( ctx );
- _mesa_init_program( ctx );
- _mesa_init_queryobj( ctx );
- _mesa_init_sync( ctx );
- _mesa_init_rastpos( ctx );
- _mesa_init_scissor( ctx );
- _mesa_init_shader_state( ctx );
- _mesa_init_stencil( ctx );
- _mesa_init_transform( ctx );
- _mesa_init_transform_feedback( ctx );
- _mesa_init_varray( ctx );
- _mesa_init_viewport( ctx );
-
- if (!_mesa_init_texture( ctx ))
- return GL_FALSE;
-
- _mesa_init_texture_s3tc( ctx );
-
- /* Miscellaneous */
- ctx->NewState = _NEW_ALL;
- ctx->ErrorValue = (GLenum) GL_NO_ERROR;
- ctx->varying_vp_inputs = ~0;
-
- return GL_TRUE;
-}
-
-
-/**
- * Update default objects in a GL context with respect to shared state.
- *
- * \param ctx GL context.
- *
- * Removes references to old default objects, (texture objects, program
- * objects, etc.) and changes to reference those from the current shared
- * state.
- */
-static GLboolean
-update_default_objects(struct gl_context *ctx)
-{
- assert(ctx);
-
- _mesa_update_default_objects_program(ctx);
- _mesa_update_default_objects_texture(ctx);
- _mesa_update_default_objects_buffer_objects(ctx);
-
- return GL_TRUE;
-}
-
-
-/**
- * This is the default function we plug into all dispatch table slots
- * This helps prevents a segfault when someone calls a GL function without
- * first checking if the extension's supported.
- */
-static int
-generic_nop(void)
-{
- _mesa_warning(NULL, "User called no-op dispatch function (an unsupported extension function?)");
- return 0;
-}
-
-
-/**
- * Allocate and initialize a new dispatch table.
- */
-struct _glapi_table *
-_mesa_alloc_dispatch_table(int size)
-{
- /* Find the larger of Mesa's dispatch table and libGL's dispatch table.
- * In practice, this'll be the same for stand-alone Mesa. But for DRI
- * Mesa we do this to accomodate different versions of libGL and various
- * DRI drivers.
- */
- GLint numEntries = MAX2(_glapi_get_dispatch_table_size(), _gloffset_COUNT);
- struct _glapi_table *table;
-
- /* should never happen, but just in case */
- numEntries = MAX2(numEntries, size);
-
- table = (struct _glapi_table *) malloc(numEntries * sizeof(_glapi_proc));
- if (table) {
- _glapi_proc *entry = (_glapi_proc *) table;
- GLint i;
- for (i = 0; i < numEntries; i++) {
- entry[i] = (_glapi_proc) generic_nop;
- }
- }
- return table;
-}
-
-
-/**
- * Initialize a struct gl_context struct (rendering context).
- *
- * This includes allocating all the other structs and arrays which hang off of
- * the context by pointers.
- * Note that the driver needs to pass in its dd_function_table here since
- * we need to at least call driverFunctions->NewTextureObject to create the
- * default texture objects.
- *
- * Called by _mesa_create_context().
- *
- * Performs the imports and exports callback tables initialization, and
- * miscellaneous one-time initializations. If no shared context is supplied one
- * is allocated, and increase its reference count. Setups the GL API dispatch
- * tables. Initialize the TNL module. Sets the maximum Z buffer depth.
- * Finally queries the \c MESA_DEBUG and \c MESA_VERBOSE environment variables
- * for debug flags.
- *
- * \param ctx the context to initialize
- * \param api the GL API type to create the context for
- * \param visual describes the visual attributes for this context
- * \param share_list points to context to share textures, display lists,
- * etc with, or NULL
- * \param driverFunctions table of device driver functions for this context
- * to use
- * \param driverContext pointer to driver-specific context data
- */
-GLboolean
-_mesa_initialize_context_for_api(struct gl_context *ctx,
- gl_api api,
- const struct gl_config *visual,
- struct gl_context *share_list,
- const struct dd_function_table *driverFunctions,
- void *driverContext)
-{
- struct gl_shared_state *shared;
- int i;
-
- /*ASSERT(driverContext);*/
- assert(driverFunctions->NewTextureObject);
- assert(driverFunctions->FreeTexImageData);
-
- ctx->API = api;
- ctx->Visual = *visual;
- ctx->DrawBuffer = NULL;
- ctx->ReadBuffer = NULL;
- ctx->WinSysDrawBuffer = NULL;
- ctx->WinSysReadBuffer = NULL;
-
- /* misc one-time initializations */
- one_time_init(ctx);
-
- /* Plug in driver functions and context pointer here.
- * This is important because when we call alloc_shared_state() below
- * we'll call ctx->Driver.NewTextureObject() to create the default
- * textures.
- */
- ctx->Driver = *driverFunctions;
- ctx->DriverCtx = driverContext;
-
- if (share_list) {
- /* share state with another context */
- shared = share_list->Shared;
- }
- else {
- /* allocate new, unshared state */
- shared = _mesa_alloc_shared_state(ctx);
- if (!shared)
- return GL_FALSE;
- }
-
- _glthread_LOCK_MUTEX(shared->Mutex);
- ctx->Shared = shared;
- shared->RefCount++;
- _glthread_UNLOCK_MUTEX(shared->Mutex);
-
- if (!init_attrib_groups( ctx )) {
- _mesa_release_shared_state(ctx, ctx->Shared);
- return GL_FALSE;
- }
-
-#if FEATURE_dispatch
- /* setup the API dispatch tables */
- switch (ctx->API) {
-#if FEATURE_GL
- case API_OPENGL:
- ctx->Exec = _mesa_create_exec_table();
- break;
-#endif
-#if FEATURE_ES1
- case API_OPENGLES:
- ctx->Exec = _mesa_create_exec_table_es1();
- break;
-#endif
-#if FEATURE_ES2
- case API_OPENGLES2:
- ctx->Exec = _mesa_create_exec_table_es2();
- break;
-#endif
- default:
- _mesa_problem(ctx, "unknown or unsupported API");
- break;
- }
-
- if (!ctx->Exec) {
- _mesa_release_shared_state(ctx, ctx->Shared);
- return GL_FALSE;
- }
-#endif
- ctx->CurrentDispatch = ctx->Exec;
-
- ctx->FragmentProgram._MaintainTexEnvProgram
- = (_mesa_getenv("MESA_TEX_PROG") != NULL);
-
- ctx->VertexProgram._MaintainTnlProgram
- = (_mesa_getenv("MESA_TNL_PROG") != NULL);
- if (ctx->VertexProgram._MaintainTnlProgram) {
- /* this is required... */
- ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
- }
-
- /* Mesa core handles all the formats that mesa core knows about.
- * Drivers will want to override this list with just the formats
- * they can handle, and confirm that appropriate fallbacks exist in
- * _mesa_choose_tex_format().
- */
- memset(&ctx->TextureFormatSupported, GL_TRUE,
- sizeof(ctx->TextureFormatSupported));
-
- switch (ctx->API) {
- case API_OPENGL:
-#if FEATURE_dlist
- ctx->Save = _mesa_create_save_table();
- if (!ctx->Save) {
- _mesa_release_shared_state(ctx, ctx->Shared);
- free(ctx->Exec);
- return GL_FALSE;
- }
-
- _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
-#endif
- break;
- case API_OPENGLES:
- /**
- * GL_OES_texture_cube_map says
- * "Initially all texture generation modes are set to REFLECTION_MAP_OES"
- */
- for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
- struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
- texUnit->GenS.Mode = GL_REFLECTION_MAP_NV;
- texUnit->GenT.Mode = GL_REFLECTION_MAP_NV;
- texUnit->GenR.Mode = GL_REFLECTION_MAP_NV;
- texUnit->GenS._ModeBit = TEXGEN_REFLECTION_MAP_NV;
- texUnit->GenT._ModeBit = TEXGEN_REFLECTION_MAP_NV;
- texUnit->GenR._ModeBit = TEXGEN_REFLECTION_MAP_NV;
- }
- break;
- case API_OPENGLES2:
- ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
- ctx->VertexProgram._MaintainTnlProgram = GL_TRUE;
- ctx->Point.PointSprite = GL_TRUE; /* always on for ES 2.x */
- break;
- }
-
- ctx->FirstTimeCurrent = GL_TRUE;
-
- return GL_TRUE;
-}
-
-
-/**
- * Initialize an OpenGL context.
- */
-GLboolean
-_mesa_initialize_context(struct gl_context *ctx,
- const struct gl_config *visual,
- struct gl_context *share_list,
- const struct dd_function_table *driverFunctions,
- void *driverContext)
-{
- return _mesa_initialize_context_for_api(ctx,
- API_OPENGL,
- visual,
- share_list,
- driverFunctions,
- driverContext);
-}
-
-
-/**
- * Allocate and initialize a struct gl_context structure.
- * Note that the driver needs to pass in its dd_function_table here since
- * we need to at least call driverFunctions->NewTextureObject to initialize
- * the rendering context.
- *
- * \param api the GL API type to create the context for
- * \param visual a struct gl_config pointer (we copy the struct contents)
- * \param share_list another context to share display lists with or NULL
- * \param driverFunctions points to the dd_function_table into which the
- * driver has plugged in all its special functions.
- * \param driverContext points to the device driver's private context state
- *
- * \return pointer to a new __struct gl_contextRec or NULL if error.
- */
-struct gl_context *
-_mesa_create_context_for_api(gl_api api,
- const struct gl_config *visual,
- struct gl_context *share_list,
- const struct dd_function_table *driverFunctions,
- void *driverContext)
-{
- struct gl_context *ctx;
-
- ASSERT(visual);
- /*ASSERT(driverContext);*/
-
- ctx = (struct gl_context *) calloc(1, sizeof(struct gl_context));
- if (!ctx)
- return NULL;
-
- if (_mesa_initialize_context_for_api(ctx, api, visual, share_list,
- driverFunctions, driverContext)) {
- return ctx;
- }
- else {
- free(ctx);
- return NULL;
- }
-}
-
-
-/**
- * Create an OpenGL context.
- */
-struct gl_context *
-_mesa_create_context(const struct gl_config *visual,
- struct gl_context *share_list,
- const struct dd_function_table *driverFunctions,
- void *driverContext)
-{
- return _mesa_create_context_for_api(API_OPENGL, visual,
- share_list,
- driverFunctions,
- driverContext);
-}
-
-
-/**
- * Free the data associated with the given context.
- *
- * But doesn't free the struct gl_context struct itself.
- *
- * \sa _mesa_initialize_context() and init_attrib_groups().
- */
-void
-_mesa_free_context_data( struct gl_context *ctx )
-{
- if (!_mesa_get_current_context()){
- /* No current context, but we may need one in order to delete
- * texture objs, etc. So temporarily bind the context now.
- */
- _mesa_make_current(ctx, NULL, NULL);
- }
-
- /* unreference WinSysDraw/Read buffers */
- _mesa_reference_framebuffer(&ctx->WinSysDrawBuffer, NULL);
- _mesa_reference_framebuffer(&ctx->WinSysReadBuffer, NULL);
- _mesa_reference_framebuffer(&ctx->DrawBuffer, NULL);
- _mesa_reference_framebuffer(&ctx->ReadBuffer, NULL);
-
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL);
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, NULL);
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram, NULL);
-
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL);
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram, NULL);
-
- _mesa_free_attrib_data(ctx);
- _mesa_free_buffer_objects(ctx);
- _mesa_free_lighting_data( ctx );
- _mesa_free_eval_data( ctx );
- _mesa_free_texture_data( ctx );
- _mesa_free_matrix_data( ctx );
- _mesa_free_viewport_data( ctx );
- _mesa_free_program_data(ctx);
- _mesa_free_shader_state(ctx);
- _mesa_free_queryobj_data(ctx);
- _mesa_free_sync_data(ctx);
- _mesa_free_varray_data(ctx);
- _mesa_free_transform_feedback(ctx);
-
- _mesa_delete_array_object(ctx, ctx->Array.DefaultArrayObj);
-
-#if FEATURE_ARB_pixel_buffer_object
- _mesa_reference_buffer_object(ctx, &ctx->Pack.BufferObj, NULL);
- _mesa_reference_buffer_object(ctx, &ctx->Unpack.BufferObj, NULL);
- _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, NULL);
-#endif
-
-#if FEATURE_ARB_vertex_buffer_object
- _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
- _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL);
-#endif
-
- /* free dispatch tables */
- free(ctx->Exec);
- free(ctx->Save);
-
- /* Shared context state (display lists, textures, etc) */
- _mesa_release_shared_state( ctx, ctx->Shared );
-
- /* needs to be after freeing shared state */
- _mesa_free_display_list_data(ctx);
-
- if (ctx->Extensions.String)
- free((void *) ctx->Extensions.String);
-
- if (ctx->VersionString)
- free(ctx->VersionString);
-
- /* unbind the context if it's currently bound */
- if (ctx == _mesa_get_current_context()) {
- _mesa_make_current(NULL, NULL, NULL);
- }
-}
-
-
-/**
- * Destroy a struct gl_context structure.
- *
- * \param ctx GL context.
- *
- * Calls _mesa_free_context_data() and frees the gl_context object itself.
- */
-void
-_mesa_destroy_context( struct gl_context *ctx )
-{
- if (ctx) {
- _mesa_free_context_data(ctx);
- free( (void *) ctx );
- }
-}
-
-
-#if _HAVE_FULL_GL
-/**
- * Copy attribute groups from one context to another.
- *
- * \param src source context
- * \param dst destination context
- * \param mask bitwise OR of GL_*_BIT flags
- *
- * According to the bits specified in \p mask, copies the corresponding
- * attributes from \p src into \p dst. For many of the attributes a simple \c
- * memcpy is not enough due to the existence of internal pointers in their data
- * structures.
- */
-void
-_mesa_copy_context( const struct gl_context *src, struct gl_context *dst, GLuint mask )
-{
- if (mask & GL_ACCUM_BUFFER_BIT) {
- /* OK to memcpy */
- dst->Accum = src->Accum;
- }
- if (mask & GL_COLOR_BUFFER_BIT) {
- /* OK to memcpy */
- dst->Color = src->Color;
- }
- if (mask & GL_CURRENT_BIT) {
- /* OK to memcpy */
- dst->Current = src->Current;
- }
- if (mask & GL_DEPTH_BUFFER_BIT) {
- /* OK to memcpy */
- dst->Depth = src->Depth;
- }
- if (mask & GL_ENABLE_BIT) {
- /* no op */
- }
- if (mask & GL_EVAL_BIT) {
- /* OK to memcpy */
- dst->Eval = src->Eval;
- }
- if (mask & GL_FOG_BIT) {
- /* OK to memcpy */
- dst->Fog = src->Fog;
- }
- if (mask & GL_HINT_BIT) {
- /* OK to memcpy */
- dst->Hint = src->Hint;
- }
- if (mask & GL_LIGHTING_BIT) {
- GLuint i;
- /* begin with memcpy */
- dst->Light = src->Light;
- /* fixup linked lists to prevent pointer insanity */
- make_empty_list( &(dst->Light.EnabledList) );
- for (i = 0; i < MAX_LIGHTS; i++) {
- if (dst->Light.Light[i].Enabled) {
- insert_at_tail(&(dst->Light.EnabledList), &(dst->Light.Light[i]));
- }
- }
- }
- if (mask & GL_LINE_BIT) {
- /* OK to memcpy */
- dst->Line = src->Line;
- }
- if (mask & GL_LIST_BIT) {
- /* OK to memcpy */
- dst->List = src->List;
- }
- if (mask & GL_PIXEL_MODE_BIT) {
- /* OK to memcpy */
- dst->Pixel = src->Pixel;
- }
- if (mask & GL_POINT_BIT) {
- /* OK to memcpy */
- dst->Point = src->Point;
- }
- if (mask & GL_POLYGON_BIT) {
- /* OK to memcpy */
- dst->Polygon = src->Polygon;
- }
- if (mask & GL_POLYGON_STIPPLE_BIT) {
- /* Use loop instead of memcpy due to problem with Portland Group's
- * C compiler. Reported by John Stone.
- */
- GLuint i;
- for (i = 0; i < 32; i++) {
- dst->PolygonStipple[i] = src->PolygonStipple[i];
- }
- }
- if (mask & GL_SCISSOR_BIT) {
- /* OK to memcpy */
- dst->Scissor = src->Scissor;
- }
- if (mask & GL_STENCIL_BUFFER_BIT) {
- /* OK to memcpy */
- dst->Stencil = src->Stencil;
- }
- if (mask & GL_TEXTURE_BIT) {
- /* Cannot memcpy because of pointers */
- _mesa_copy_texture_state(src, dst);
- }
- if (mask & GL_TRANSFORM_BIT) {
- /* OK to memcpy */
- dst->Transform = src->Transform;
- }
- if (mask & GL_VIEWPORT_BIT) {
- /* Cannot use memcpy, because of pointers in GLmatrix _WindowMap */
- dst->Viewport.X = src->Viewport.X;
- dst->Viewport.Y = src->Viewport.Y;
- dst->Viewport.Width = src->Viewport.Width;
- dst->Viewport.Height = src->Viewport.Height;
- dst->Viewport.Near = src->Viewport.Near;
- dst->Viewport.Far = src->Viewport.Far;
- _math_matrix_copy(&dst->Viewport._WindowMap, &src->Viewport._WindowMap);
- }
-
- /* XXX FIXME: Call callbacks?
- */
- dst->NewState = _NEW_ALL;
-}
-#endif
-
-
-/**
- * Check if the given context can render into the given framebuffer
- * by checking visual attributes.
- *
- * Most of these tests could go away because Mesa is now pretty flexible
- * in terms of mixing rendering contexts with framebuffers. As long
- * as RGB vs. CI mode agree, we're probably good.
- *
- * \return GL_TRUE if compatible, GL_FALSE otherwise.
- */
-static GLboolean
-check_compatible(const struct gl_context *ctx,
- const struct gl_framebuffer *buffer)
-{
- const struct gl_config *ctxvis = &ctx->Visual;
- const struct gl_config *bufvis = &buffer->Visual;
-
- if (buffer == _mesa_get_incomplete_framebuffer())
- return GL_TRUE;
-
-#if 0
- /* disabling this fixes the fgl_glxgears pbuffer demo */
- if (ctxvis->doubleBufferMode && !bufvis->doubleBufferMode)
- return GL_FALSE;
-#endif
- if (ctxvis->stereoMode && !bufvis->stereoMode)
- return GL_FALSE;
- if (ctxvis->haveAccumBuffer && !bufvis->haveAccumBuffer)
- return GL_FALSE;
- if (ctxvis->haveDepthBuffer && !bufvis->haveDepthBuffer)
- return GL_FALSE;
- if (ctxvis->haveStencilBuffer && !bufvis->haveStencilBuffer)
- return GL_FALSE;
- if (ctxvis->redMask && ctxvis->redMask != bufvis->redMask)
- return GL_FALSE;
- if (ctxvis->greenMask && ctxvis->greenMask != bufvis->greenMask)
- return GL_FALSE;
- if (ctxvis->blueMask && ctxvis->blueMask != bufvis->blueMask)
- return GL_FALSE;
-#if 0
- /* disabled (see bug 11161) */
- if (ctxvis->depthBits && ctxvis->depthBits != bufvis->depthBits)
- return GL_FALSE;
-#endif
- if (ctxvis->stencilBits && ctxvis->stencilBits != bufvis->stencilBits)
- return GL_FALSE;
-
- return GL_TRUE;
-}
-
-
-/**
- * Do one-time initialization for the given framebuffer. Specifically,
- * ask the driver for the window's current size and update the framebuffer
- * object to match.
- * Really, the device driver should totally take care of this.
- */
-static void
-initialize_framebuffer_size(struct gl_context *ctx, struct gl_framebuffer *fb)
-{
- GLuint width, height;
- if (ctx->Driver.GetBufferSize) {
- ctx->Driver.GetBufferSize(fb, &width, &height);
- if (ctx->Driver.ResizeBuffers)
- ctx->Driver.ResizeBuffers(ctx, fb, width, height);
- fb->Initialized = GL_TRUE;
- }
-}
-
-
-/**
- * Check if the viewport/scissor size has not yet been initialized.
- * Initialize the size if the given width and height are non-zero.
- */
-void
-_mesa_check_init_viewport(struct gl_context *ctx, GLuint width, GLuint height)
-{
- if (!ctx->ViewportInitialized && width > 0 && height > 0) {
- /* Note: set flag here, before calling _mesa_set_viewport(), to prevent
- * potential infinite recursion.
- */
- ctx->ViewportInitialized = GL_TRUE;
- _mesa_set_viewport(ctx, 0, 0, width, height);
- _mesa_set_scissor(ctx, 0, 0, width, height);
- }
-}
-
-
-/**
- * Bind the given context to the given drawBuffer and readBuffer and
- * make it the current context for the calling thread.
- * We'll render into the drawBuffer and read pixels from the
- * readBuffer (i.e. glRead/CopyPixels, glCopyTexImage, etc).
- *
- * We check that the context's and framebuffer's visuals are compatible
- * and return immediately if they're not.
- *
- * \param newCtx the new GL context. If NULL then there will be no current GL
- * context.
- * \param drawBuffer the drawing framebuffer
- * \param readBuffer the reading framebuffer
- */
-GLboolean
-_mesa_make_current( struct gl_context *newCtx,
- struct gl_framebuffer *drawBuffer,
- struct gl_framebuffer *readBuffer )
-{
- GET_CURRENT_CONTEXT(curCtx);
-
- if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(newCtx, "_mesa_make_current()\n");
-
- /* Check that the context's and framebuffer's visuals are compatible.
- */
- if (newCtx && drawBuffer && newCtx->WinSysDrawBuffer != drawBuffer) {
- if (!check_compatible(newCtx, drawBuffer)) {
- _mesa_warning(newCtx,
- "MakeCurrent: incompatible visuals for context and drawbuffer");
- return GL_FALSE;
- }
- }
- if (newCtx && readBuffer && newCtx->WinSysReadBuffer != readBuffer) {
- if (!check_compatible(newCtx, readBuffer)) {
- _mesa_warning(newCtx,
- "MakeCurrent: incompatible visuals for context and readbuffer");
- return GL_FALSE;
- }
- }
-
- if (curCtx &&
- (curCtx->WinSysDrawBuffer || curCtx->WinSysReadBuffer) && /* make sure this context is valid for flushing */
- curCtx != newCtx)
- _mesa_flush(curCtx);
-
- /* We used to call _glapi_check_multithread() here. Now do it in drivers */
- _glapi_set_context((void *) newCtx);
- ASSERT(_mesa_get_current_context() == newCtx);
-
- if (!newCtx) {
- _glapi_set_dispatch(NULL); /* none current */
- }
- else {
- _glapi_set_dispatch(newCtx->CurrentDispatch);
-
- if (drawBuffer && readBuffer) {
- /* TODO: check if newCtx and buffer's visual match??? */
-
- ASSERT(drawBuffer->Name == 0);
- ASSERT(readBuffer->Name == 0);
- _mesa_reference_framebuffer(&newCtx->WinSysDrawBuffer, drawBuffer);
- _mesa_reference_framebuffer(&newCtx->WinSysReadBuffer, readBuffer);
-
- /*
- * Only set the context's Draw/ReadBuffer fields if they're NULL
- * or not bound to a user-created FBO.
- */
- if (!newCtx->DrawBuffer || newCtx->DrawBuffer->Name == 0) {
- /* KW: merge conflict here, revisit.
- */
- /* fix up the fb fields - these will end up wrong otherwise
- * if the DRIdrawable changes, and everything relies on them.
- * This is a bit messy (same as needed in _mesa_BindFramebufferEXT)
- */
- unsigned int i;
- GLenum buffers[MAX_DRAW_BUFFERS];
-
- _mesa_reference_framebuffer(&newCtx->DrawBuffer, drawBuffer);
-
- for(i = 0; i < newCtx->Const.MaxDrawBuffers; i++) {
- buffers[i] = newCtx->Color.DrawBuffer[i];
- }
-
- _mesa_drawbuffers(newCtx, newCtx->Const.MaxDrawBuffers,
- buffers, NULL);
- }
- if (!newCtx->ReadBuffer || newCtx->ReadBuffer->Name == 0) {
- _mesa_reference_framebuffer(&newCtx->ReadBuffer, readBuffer);
- }
-
- /* XXX only set this flag if we're really changing the draw/read
- * framebuffer bindings.
- */
- newCtx->NewState |= _NEW_BUFFERS;
-
-#if 1
- /* We want to get rid of these lines: */
-
-#if _HAVE_FULL_GL
- if (!drawBuffer->Initialized) {
- initialize_framebuffer_size(newCtx, drawBuffer);
- }
- if (readBuffer != drawBuffer && !readBuffer->Initialized) {
- initialize_framebuffer_size(newCtx, readBuffer);
- }
-
- _mesa_resizebuffers(newCtx);
-#endif
-
-#else
- /* We want the drawBuffer and readBuffer to be initialized by
- * the driver.
- * This generally means the Width and Height match the actual
- * window size and the renderbuffers (both hardware and software
- * based) are allocated to match. The later can generally be
- * done with a call to _mesa_resize_framebuffer().
- *
- * It's theoretically possible for a buffer to have zero width
- * or height, but for now, assert check that the driver did what's
- * expected of it.
- */
- ASSERT(drawBuffer->Width > 0);
- ASSERT(drawBuffer->Height > 0);
-#endif
-
- if (drawBuffer) {
- _mesa_check_init_viewport(newCtx,
- drawBuffer->Width, drawBuffer->Height);
- }
- }
-
- if (newCtx->FirstTimeCurrent) {
- _mesa_compute_version(newCtx);
-
- newCtx->Extensions.String = _mesa_make_extension_string(newCtx);
-
- check_context_limits(newCtx);
-
- /* We can use this to help debug user's problems. Tell them to set
- * the MESA_INFO env variable before running their app. Then the
- * first time each context is made current we'll print some useful
- * information.
- */
- if (_mesa_getenv("MESA_INFO")) {
- _mesa_print_info();
- }
-
- newCtx->FirstTimeCurrent = GL_FALSE;
- }
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Make context 'ctx' share the display lists, textures and programs
- * that are associated with 'ctxToShare'.
- * Any display lists, textures or programs associated with 'ctx' will
- * be deleted if nobody else is sharing them.
- */
-GLboolean
-_mesa_share_state(struct gl_context *ctx, struct gl_context *ctxToShare)
-{
- if (ctx && ctxToShare && ctx->Shared && ctxToShare->Shared) {
- struct gl_shared_state *oldSharedState = ctx->Shared;
-
- ctx->Shared = ctxToShare->Shared;
-
- _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
- ctx->Shared->RefCount++;
- _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
-
- update_default_objects(ctx);
-
- _mesa_release_shared_state(ctx, oldSharedState);
-
- return GL_TRUE;
- }
- else {
- return GL_FALSE;
- }
-}
-
-
-
-/**
- * \return pointer to the current GL context for this thread.
- *
- * Calls _glapi_get_context(). This isn't the fastest way to get the current
- * context. If you need speed, see the #GET_CURRENT_CONTEXT macro in
- * context.h.
- */
-struct gl_context *
-_mesa_get_current_context( void )
-{
- return (struct gl_context *) _glapi_get_context();
-}
-
-
-/**
- * Get context's current API dispatch table.
- *
- * It'll either be the immediate-mode execute dispatcher or the display list
- * compile dispatcher.
- *
- * \param ctx GL context.
- *
- * \return pointer to dispatch_table.
- *
- * Simply returns __struct gl_contextRec::CurrentDispatch.
- */
-struct _glapi_table *
-_mesa_get_dispatch(struct gl_context *ctx)
-{
- return ctx->CurrentDispatch;
-}
-
-/*@}*/
-
-
-/**********************************************************************/
-/** \name Miscellaneous functions */
-/**********************************************************************/
-/*@{*/
-
-/**
- * Record an error.
- *
- * \param ctx GL context.
- * \param error error code.
- *
- * Records the given error code and call the driver's dd_function_table::Error
- * function if defined.
- *
- * \sa
- * This is called via _mesa_error().
- */
-void
-_mesa_record_error(struct gl_context *ctx, GLenum error)
-{
- if (!ctx)
- return;
-
- if (ctx->ErrorValue == GL_NO_ERROR) {
- ctx->ErrorValue = error;
- }
-
- /* Call device driver's error handler, if any. This is used on the Mac. */
- if (ctx->Driver.Error) {
- ctx->Driver.Error(ctx);
- }
-}
-
-
-/**
- * Flush commands and wait for completion.
- */
-void
-_mesa_finish(struct gl_context *ctx)
-{
- FLUSH_CURRENT( ctx, 0 );
- if (ctx->Driver.Finish) {
- ctx->Driver.Finish(ctx);
- }
-}
-
-
-/**
- * Flush commands.
- */
-void
-_mesa_flush(struct gl_context *ctx)
-{
- FLUSH_CURRENT( ctx, 0 );
- if (ctx->Driver.Flush) {
- ctx->Driver.Flush(ctx);
- }
-}
-
-
-
-/**
- * Execute glFinish().
- *
- * Calls the #ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH macro and the
- * dd_function_table::Finish driver callback, if not NULL.
- */
-void GLAPIENTRY
-_mesa_Finish(void)
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
- _mesa_finish(ctx);
-}
-
-
-/**
- * Execute glFlush().
- *
- * Calls the #ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH macro and the
- * dd_function_table::Flush driver callback, if not NULL.
- */
-void GLAPIENTRY
-_mesa_Flush(void)
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
- _mesa_flush(ctx);
-}
-
-
-/**
- * Set mvp_with_dp4 flag. If a driver has a preference for DP4 over
- * MUL/MAD, or vice versa, call this function to register that.
- * Otherwise we default to MUL/MAD.
- */
-void
-_mesa_set_mvp_with_dp4( struct gl_context *ctx,
- GLboolean flag )
-{
- ctx->mvp_with_dp4 = flag;
-}
-
-
-
-/**
- * Prior to drawing anything with glBegin, glDrawArrays, etc. this function
- * is called to see if it's valid to render. This involves checking that
- * the current shader is valid and the framebuffer is complete.
- * If an error is detected it'll be recorded here.
- * \return GL_TRUE if OK to render, GL_FALSE if not
- */
-GLboolean
-_mesa_valid_to_render(struct gl_context *ctx, const char *where)
-{
- bool vert_from_glsl_shader = false;
- bool geom_from_glsl_shader = false;
- bool frag_from_glsl_shader = false;
-
- /* This depends on having up to date derived state (shaders) */
- if (ctx->NewState)
- _mesa_update_state(ctx);
-
- if (ctx->Shader.CurrentVertexProgram) {
- vert_from_glsl_shader = true;
-
- if (!ctx->Shader.CurrentVertexProgram->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(shader not linked)", where);
- return GL_FALSE;
- }
-#if 0 /* not normally enabled */
- {
- char errMsg[100];
- if (!_mesa_validate_shader_program(ctx,
- ctx->Shader.CurrentVertexProgram,
- errMsg)) {
- _mesa_warning(ctx, "Shader program %u is invalid: %s",
- ctx->Shader.CurrentVertexProgram->Name, errMsg);
- }
- }
-#endif
- }
-
- if (ctx->Shader.CurrentGeometryProgram) {
- geom_from_glsl_shader = true;
-
- if (!ctx->Shader.CurrentGeometryProgram->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(shader not linked)", where);
- return GL_FALSE;
- }
-#if 0 /* not normally enabled */
- {
- char errMsg[100];
- if (!_mesa_validate_shader_program(ctx,
- ctx->Shader.CurrentGeometryProgram,
- errMsg)) {
- _mesa_warning(ctx, "Shader program %u is invalid: %s",
- ctx->Shader.CurrentGeometryProgram->Name, errMsg);
- }
- }
-#endif
- }
-
- if (ctx->Shader.CurrentFragmentProgram) {
- frag_from_glsl_shader = true;
-
- if (!ctx->Shader.CurrentFragmentProgram->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(shader not linked)", where);
- return GL_FALSE;
- }
-#if 0 /* not normally enabled */
- {
- char errMsg[100];
- if (!_mesa_validate_shader_program(ctx,
- ctx->Shader.CurrentFragmentProgram,
- errMsg)) {
- _mesa_warning(ctx, "Shader program %u is invalid: %s",
- ctx->Shader.CurrentFragmentProgram->Name, errMsg);
- }
- }
-#endif
- }
-
- /* Any shader stages that are not supplied by the GLSL shader and have
- * assembly shaders enabled must now be validated.
- */
- if (!vert_from_glsl_shader
- && ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(vertex program not valid)", where);
- return GL_FALSE;
- }
-
- /* FINISHME: If GL_NV_geometry_program4 is ever supported, the current
- * FINISHME: geometry program should validated here.
- */
- (void) geom_from_glsl_shader;
-
- if (!frag_from_glsl_shader) {
- if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(fragment program not valid)", where);
- return GL_FALSE;
- }
-
- /* If drawing to integer-valued color buffers, there must be an
- * active fragment shader (GL_EXT_texture_integer).
- */
- if (ctx->DrawBuffer && ctx->DrawBuffer->_IntegerColor) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(integer format but no fragment shader)", where);
- return GL_FALSE;
- }
- }
-
- if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
- "%s(incomplete framebuffer)", where);
- return GL_FALSE;
- }
-
-#ifdef DEBUG
- if (ctx->Shader.Flags & GLSL_LOG) {
- struct gl_shader_program *shProg[MESA_SHADER_TYPES];
- gl_shader_type i;
-
- shProg[MESA_SHADER_VERTEX] = ctx->Shader.CurrentVertexProgram;
- shProg[MESA_SHADER_GEOMETRY] = ctx->Shader.CurrentGeometryProgram;
- shProg[MESA_SHADER_FRAGMENT] = ctx->Shader.CurrentFragmentProgram;
-
- for (i = 0; i < MESA_SHADER_TYPES; i++) {
- struct gl_shader *sh;
-
- if (shProg[i] == NULL || shProg[i]->_Used
- || shProg[i]->_LinkedShaders[i] == NULL)
- continue;
-
- /* This is the first time this shader is being used.
- * Append shader's constants/uniforms to log file.
- *
- * The logic is a little odd here. We only want to log data for each
- * shader target that will actually be used, and we only want to log
- * it once. It's possible to have a program bound to the vertex
- * shader target that also supplied a fragment shader. If that
- * program isn't also bound to the fragment shader target we don't
- * want to log its fragment data.
- */
- sh = shProg[i]->_LinkedShaders[i];
- switch (sh->Type) {
- case GL_VERTEX_SHADER:
- _mesa_append_uniforms_to_file(sh, &shProg[i]->VertexProgram->Base);
- break;
-
- case GL_GEOMETRY_SHADER_ARB:
- _mesa_append_uniforms_to_file(sh,
- &shProg[i]->GeometryProgram->Base);
- break;
-
- case GL_FRAGMENT_SHADER:
- _mesa_append_uniforms_to_file(sh,
- &shProg[i]->FragmentProgram->Base);
- break;
- }
- }
-
- for (i = 0; i < MESA_SHADER_TYPES; i++) {
- if (shProg[i] != NULL)
- shProg[i]->_Used = GL_TRUE;
- }
- }
-#endif
-
- return GL_TRUE;
-}
-
-
-/*@}*/
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.3
+ *
+ * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
+ * Copyright (C) 2008 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 context.c
+ * Mesa context/visual/framebuffer management functions.
+ * \author Brian Paul
+ */
+
+/**
+ * \mainpage Mesa Main Module
+ *
+ * \section MainIntroduction Introduction
+ *
+ * The Mesa Main module consists of all the files in the main/ directory.
+ * Among the features of this module are:
+ * <UL>
+ * <LI> Structures to represent most GL state </LI>
+ * <LI> State set/get functions </LI>
+ * <LI> Display lists </LI>
+ * <LI> Texture unit, object and image handling </LI>
+ * <LI> Matrix and attribute stacks </LI>
+ * </UL>
+ *
+ * Other modules are responsible for API dispatch, vertex transformation,
+ * point/line/triangle setup, rasterization, vertex array caching,
+ * vertex/fragment programs/shaders, etc.
+ *
+ *
+ * \section AboutDoxygen About Doxygen
+ *
+ * If you're viewing this information as Doxygen-generated HTML you'll
+ * see the documentation index at the top of this page.
+ *
+ * The first line lists the Mesa source code modules.
+ * The second line lists the indexes available for viewing the documentation
+ * for each module.
+ *
+ * Selecting the <b>Main page</b> link will display a summary of the module
+ * (this page).
+ *
+ * Selecting <b>Data Structures</b> will list all C structures.
+ *
+ * Selecting the <b>File List</b> link will list all the source files in
+ * the module.
+ * Selecting a filename will show a list of all functions defined in that file.
+ *
+ * Selecting the <b>Data Fields</b> link will display a list of all
+ * documented structure members.
+ *
+ * Selecting the <b>Globals</b> link will display a list
+ * of all functions, structures, global variables and macros in the module.
+ *
+ */
+
+
+#include "glheader.h"
+#include "mfeatures.h"
+#include "imports.h"
+#include "accum.h"
+#include "api_exec.h"
+#include "arrayobj.h"
+#include "attrib.h"
+#include "blend.h"
+#include "buffers.h"
+#include "bufferobj.h"
+#include "context.h"
+#include "cpuinfo.h"
+#include "debug.h"
+#include "depth.h"
+#include "dlist.h"
+#include "eval.h"
+#include "extensions.h"
+#include "fbobject.h"
+#include "feedback.h"
+#include "fog.h"
+#include "formats.h"
+#include "framebuffer.h"
+#include "hint.h"
+#include "hash.h"
+#include "light.h"
+#include "lines.h"
+#include "macros.h"
+#include "matrix.h"
+#include "multisample.h"
+#include "pixel.h"
+#include "pixelstore.h"
+#include "points.h"
+#include "polygon.h"
+#include "queryobj.h"
+#include "syncobj.h"
+#include "rastpos.h"
+#include "remap.h"
+#include "scissor.h"
+#include "shared.h"
+#include "shaderobj.h"
+#include "simple_list.h"
+#include "state.h"
+#include "stencil.h"
+#include "texcompress_s3tc.h"
+#include "texstate.h"
+#include "transformfeedback.h"
+#include "mtypes.h"
+#include "varray.h"
+#include "version.h"
+#include "viewport.h"
+#include "vtxfmt.h"
+#include "program/program.h"
+#include "program/prog_print.h"
+#if _HAVE_FULL_GL
+#include "math/m_matrix.h"
+#endif
+#include "main/dispatch.h" /* for _gloffset_COUNT */
+
+#ifdef USE_SPARC_ASM
+#include "sparc/sparc.h"
+#endif
+
+#include "glsl_parser_extras.h"
+#include <stdbool.h>
+
+
+#ifndef MESA_VERBOSE
+int MESA_VERBOSE = 0;
+#endif
+
+#ifndef MESA_DEBUG_FLAGS
+int MESA_DEBUG_FLAGS = 0;
+#endif
+
+
+/* ubyte -> float conversion */
+GLfloat _mesa_ubyte_to_float_color_tab[256];
+
+
+
+/**
+ * Swap buffers notification callback.
+ *
+ * \param ctx GL context.
+ *
+ * Called by window system just before swapping buffers.
+ * We have to finish any pending rendering.
+ */
+void
+_mesa_notifySwapBuffers(struct gl_context *ctx)
+{
+ if (MESA_VERBOSE & VERBOSE_SWAPBUFFERS)
+ _mesa_debug(ctx, "SwapBuffers\n");
+ FLUSH_CURRENT( ctx, 0 );
+ if (ctx->Driver.Flush) {
+ ctx->Driver.Flush(ctx);
+ }
+}
+
+
+/**********************************************************************/
+/** \name GL Visual allocation/destruction */
+/**********************************************************************/
+/*@{*/
+
+/**
+ * Allocates a struct gl_config structure and initializes it via
+ * _mesa_initialize_visual().
+ *
+ * \param dbFlag double buffering
+ * \param stereoFlag stereo buffer
+ * \param depthBits requested bits per depth buffer value. Any value in [0, 32]
+ * is acceptable but the actual depth type will be GLushort or GLuint as
+ * needed.
+ * \param stencilBits requested minimum bits per stencil buffer value
+ * \param accumRedBits, accumGreenBits, accumBlueBits, accumAlphaBits number of bits per color component in accum buffer.
+ * \param indexBits number of bits per pixel if \p rgbFlag is GL_FALSE
+ * \param redBits number of bits per color component in frame buffer for RGB(A)
+ * mode. We always use 8 in core Mesa though.
+ * \param greenBits same as above.
+ * \param blueBits same as above.
+ * \param alphaBits same as above.
+ * \param numSamples not really used.
+ *
+ * \return pointer to new struct gl_config or NULL if requested parameters can't be
+ * met.
+ *
+ * \note Need to add params for level and numAuxBuffers (at least)
+ */
+struct gl_config *
+_mesa_create_visual( GLboolean dbFlag,
+ GLboolean stereoFlag,
+ GLint redBits,
+ GLint greenBits,
+ GLint blueBits,
+ GLint alphaBits,
+ GLint depthBits,
+ GLint stencilBits,
+ GLint accumRedBits,
+ GLint accumGreenBits,
+ GLint accumBlueBits,
+ GLint accumAlphaBits,
+ GLint numSamples )
+{
+ struct gl_config *vis = CALLOC_STRUCT(gl_config);
+ if (vis) {
+ if (!_mesa_initialize_visual(vis, dbFlag, stereoFlag,
+ redBits, greenBits, blueBits, alphaBits,
+ depthBits, stencilBits,
+ accumRedBits, accumGreenBits,
+ accumBlueBits, accumAlphaBits,
+ numSamples)) {
+ free(vis);
+ return NULL;
+ }
+ }
+ return vis;
+}
+
+
+/**
+ * Makes some sanity checks and fills in the fields of the struct
+ * gl_config object with the given parameters. If the caller needs to
+ * set additional fields, he should just probably init the whole
+ * gl_config object himself.
+ *
+ * \return GL_TRUE on success, or GL_FALSE on failure.
+ *
+ * \sa _mesa_create_visual() above for the parameter description.
+ */
+GLboolean
+_mesa_initialize_visual( struct gl_config *vis,
+ GLboolean dbFlag,
+ GLboolean stereoFlag,
+ GLint redBits,
+ GLint greenBits,
+ GLint blueBits,
+ GLint alphaBits,
+ GLint depthBits,
+ GLint stencilBits,
+ GLint accumRedBits,
+ GLint accumGreenBits,
+ GLint accumBlueBits,
+ GLint accumAlphaBits,
+ GLint numSamples )
+{
+ assert(vis);
+
+ if (depthBits < 0 || depthBits > 32) {
+ return GL_FALSE;
+ }
+ if (stencilBits < 0 || stencilBits > STENCIL_BITS) {
+ return GL_FALSE;
+ }
+ assert(accumRedBits >= 0);
+ assert(accumGreenBits >= 0);
+ assert(accumBlueBits >= 0);
+ assert(accumAlphaBits >= 0);
+
+ vis->rgbMode = GL_TRUE;
+ vis->doubleBufferMode = dbFlag;
+ vis->stereoMode = stereoFlag;
+
+ vis->redBits = redBits;
+ vis->greenBits = greenBits;
+ vis->blueBits = blueBits;
+ vis->alphaBits = alphaBits;
+ vis->rgbBits = redBits + greenBits + blueBits;
+
+ vis->indexBits = 0;
+ vis->depthBits = depthBits;
+ vis->stencilBits = stencilBits;
+
+ vis->accumRedBits = accumRedBits;
+ vis->accumGreenBits = accumGreenBits;
+ vis->accumBlueBits = accumBlueBits;
+ vis->accumAlphaBits = accumAlphaBits;
+
+ vis->haveAccumBuffer = accumRedBits > 0;
+ vis->haveDepthBuffer = depthBits > 0;
+ vis->haveStencilBuffer = stencilBits > 0;
+
+ vis->numAuxBuffers = 0;
+ vis->level = 0;
+ vis->sampleBuffers = numSamples > 0 ? 1 : 0;
+ vis->samples = numSamples;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Destroy a visual and free its memory.
+ *
+ * \param vis visual.
+ *
+ * Frees the visual structure.
+ */
+void
+_mesa_destroy_visual( struct gl_config *vis )
+{
+ free(vis);
+}
+
+/*@}*/
+
+
+/**********************************************************************/
+/** \name Context allocation, initialization, destroying
+ *
+ * The purpose of the most initialization functions here is to provide the
+ * default state values according to the OpenGL specification.
+ */
+/**********************************************************************/
+/*@{*/
+
+
+/**
+ * This is lame. gdb only seems to recognize enum types that are
+ * actually used somewhere. We want to be able to print/use enum
+ * values such as TEXTURE_2D_INDEX in gdb. But we don't actually use
+ * the gl_texture_index type anywhere. Thus, this lame function.
+ */
+static void
+dummy_enum_func(void)
+{
+ gl_buffer_index bi = BUFFER_FRONT_LEFT;
+ gl_face_index fi = FACE_POS_X;
+ gl_frag_attrib fa = FRAG_ATTRIB_WPOS;
+ gl_frag_result fr = FRAG_RESULT_DEPTH;
+ gl_texture_index ti = TEXTURE_2D_ARRAY_INDEX;
+ gl_vert_attrib va = VERT_ATTRIB_POS;
+ gl_vert_result vr = VERT_RESULT_HPOS;
+ gl_geom_attrib ga = GEOM_ATTRIB_POSITION;
+ gl_geom_result gr = GEOM_RESULT_POS;
+
+ (void) bi;
+ (void) fi;
+ (void) fa;
+ (void) fr;
+ (void) ti;
+ (void) va;
+ (void) vr;
+ (void) ga;
+ (void) gr;
+}
+
+
+/**
+ * One-time initialization mutex lock.
+ *
+ * \sa Used by one_time_init().
+ */
+_glthread_DECLARE_STATIC_MUTEX(OneTimeLock);
+
+
+
+/**
+ * Calls all the various one-time-init functions in Mesa.
+ *
+ * While holding a global mutex lock, calls several initialization functions,
+ * and sets the glapi callbacks if the \c MESA_DEBUG environment variable is
+ * defined.
+ *
+ * \sa _math_init().
+ */
+static void
+one_time_init( struct gl_context *ctx )
+{
+ static GLbitfield api_init_mask = 0x0;
+
+ _glthread_LOCK_MUTEX(OneTimeLock);
+
+ /* truly one-time init */
+ if (!api_init_mask) {
+ GLuint i;
+
+ /* do some implementation tests */
+ assert( sizeof(GLbyte) == 1 );
+ assert( sizeof(GLubyte) == 1 );
+ assert( sizeof(GLshort) == 2 );
+ assert( sizeof(GLushort) == 2 );
+ assert( sizeof(GLint) == 4 );
+ assert( sizeof(GLuint) == 4 );
+
+ _mesa_get_cpu_features();
+
+ _mesa_init_sqrt_table();
+
+ /* context dependence is never a one-time thing... */
+ _mesa_init_get_hash(ctx);
+
+ for (i = 0; i < 256; i++) {
+ _mesa_ubyte_to_float_color_tab[i] = (float) i / 255.0F;
+ }
+
+#if defined(DEBUG) && defined(__DATE__) && defined(__TIME__)
+ if (MESA_VERBOSE != 0) {
+ _mesa_debug(ctx, "Mesa %s DEBUG build %s %s\n",
+ MESA_VERSION_STRING, __DATE__, __TIME__);
+ }
+#endif
+
+#ifdef DEBUG
+ _mesa_test_formats();
+#endif
+ }
+
+ /* per-API one-time init */
+ if (!(api_init_mask & (1 << ctx->API))) {
+ /*
+ * This is fine as ES does not use the remap table, but it may not be
+ * future-proof. We cannot always initialize the remap table because
+ * when an app is linked to libGLES*, there are not enough dynamic
+ * entries.
+ */
+ if (ctx->API == API_OPENGL)
+ _mesa_init_remap_table();
+ }
+
+ api_init_mask |= 1 << ctx->API;
+
+ _glthread_UNLOCK_MUTEX(OneTimeLock);
+
+ /* Hopefully atexit() is widely available. If not, we may need some
+ * #ifdef tests here.
+ */
+ atexit(_mesa_destroy_shader_compiler);
+
+ dummy_enum_func();
+}
+
+
+/**
+ * Initialize fields of gl_current_attrib (aka ctx->Current.*)
+ */
+static void
+_mesa_init_current(struct gl_context *ctx)
+{
+ GLuint i;
+
+ /* Init all to (0,0,0,1) */
+ for (i = 0; i < Elements(ctx->Current.Attrib); i++) {
+ ASSIGN_4V( ctx->Current.Attrib[i], 0.0, 0.0, 0.0, 1.0 );
+ }
+
+ /* redo special cases: */
+ ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_WEIGHT], 1.0, 0.0, 0.0, 0.0 );
+ ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_NORMAL], 0.0, 0.0, 1.0, 1.0 );
+ ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR0], 1.0, 1.0, 1.0, 1.0 );
+ ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR1], 0.0, 0.0, 0.0, 1.0 );
+ ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR_INDEX], 1.0, 0.0, 0.0, 1.0 );
+ ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG], 1.0, 0.0, 0.0, 1.0 );
+}
+
+
+/**
+ * Init vertex/fragment/geometry program limits.
+ * Important: drivers should override these with actual limits.
+ */
+static void
+init_program_limits(GLenum type, struct gl_program_constants *prog)
+{
+ prog->MaxInstructions = MAX_PROGRAM_INSTRUCTIONS;
+ prog->MaxAluInstructions = MAX_PROGRAM_INSTRUCTIONS;
+ prog->MaxTexInstructions = MAX_PROGRAM_INSTRUCTIONS;
+ prog->MaxTexIndirections = MAX_PROGRAM_INSTRUCTIONS;
+ prog->MaxTemps = MAX_PROGRAM_TEMPS;
+ prog->MaxEnvParams = MAX_PROGRAM_ENV_PARAMS;
+ prog->MaxLocalParams = MAX_PROGRAM_LOCAL_PARAMS;
+ prog->MaxUniformComponents = 4 * MAX_UNIFORMS;
+
+ switch (type) {
+ case GL_VERTEX_PROGRAM_ARB:
+ prog->MaxParameters = MAX_VERTEX_PROGRAM_PARAMS;
+ prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS;
+ prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS;
+ break;
+ case GL_FRAGMENT_PROGRAM_ARB:
+ prog->MaxParameters = MAX_NV_FRAGMENT_PROGRAM_PARAMS;
+ prog->MaxAttribs = MAX_NV_FRAGMENT_PROGRAM_INPUTS;
+ prog->MaxAddressRegs = MAX_FRAGMENT_PROGRAM_ADDRESS_REGS;
+ break;
+ case MESA_GEOMETRY_PROGRAM:
+ prog->MaxParameters = MAX_NV_VERTEX_PROGRAM_PARAMS;
+ prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS;
+ prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS;
+
+ prog->MaxGeometryTextureImageUnits = MAX_GEOMETRY_TEXTURE_IMAGE_UNITS;
+ prog->MaxGeometryVaryingComponents = MAX_GEOMETRY_VARYING_COMPONENTS;
+ prog->MaxVertexVaryingComponents = MAX_VERTEX_VARYING_COMPONENTS;
+ prog->MaxGeometryUniformComponents = MAX_GEOMETRY_UNIFORM_COMPONENTS;
+ prog->MaxGeometryOutputVertices = MAX_GEOMETRY_OUTPUT_VERTICES;
+ prog->MaxGeometryTotalOutputComponents = MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS;
+ break;
+ default:
+ assert(0 && "Bad program type in init_program_limits()");
+ }
+
+ /* Set the native limits to zero. This implies that there is no native
+ * support for shaders. Let the drivers fill in the actual values.
+ */
+ prog->MaxNativeInstructions = 0;
+ prog->MaxNativeAluInstructions = 0;
+ prog->MaxNativeTexInstructions = 0;
+ prog->MaxNativeTexIndirections = 0;
+ prog->MaxNativeAttribs = 0;
+ prog->MaxNativeTemps = 0;
+ prog->MaxNativeAddressRegs = 0;
+ prog->MaxNativeParameters = 0;
+
+ /* Set GLSL datatype range/precision info assuming IEEE float values.
+ * Drivers should override these defaults as needed.
+ */
+ prog->MediumFloat.RangeMin = 127;
+ prog->MediumFloat.RangeMax = 127;
+ prog->MediumFloat.Precision = 23;
+ prog->LowFloat = prog->HighFloat = prog->MediumFloat;
+
+ /* Assume ints are stored as floats for now, since this is the least-common
+ * denominator. The OpenGL ES spec implies (page 132) that the precision
+ * of integer types should be 0. Practically speaking, IEEE
+ * single-precision floating point values can only store integers in the
+ * range [-0x01000000, 0x01000000] without loss of precision.
+ */
+ prog->MediumInt.RangeMin = 24;
+ prog->MediumInt.RangeMax = 24;
+ prog->MediumInt.Precision = 0;
+ prog->LowInt = prog->HighInt = prog->MediumInt;
+}
+
+
+/**
+ * Initialize fields of gl_constants (aka ctx->Const.*).
+ * Use defaults from config.h. The device drivers will often override
+ * some of these values (such as number of texture units).
+ */
+static void
+_mesa_init_constants(struct gl_context *ctx)
+{
+ assert(ctx);
+
+ /* Constants, may be overriden (usually only reduced) by device drivers */
+ ctx->Const.MaxTextureMbytes = MAX_TEXTURE_MBYTES;
+ ctx->Const.MaxTextureLevels = MAX_TEXTURE_LEVELS;
+ ctx->Const.Max3DTextureLevels = MAX_3D_TEXTURE_LEVELS;
+ ctx->Const.MaxCubeTextureLevels = MAX_CUBE_TEXTURE_LEVELS;
+ ctx->Const.MaxTextureRectSize = MAX_TEXTURE_RECT_SIZE;
+ ctx->Const.MaxArrayTextureLayers = MAX_ARRAY_TEXTURE_LAYERS;
+ ctx->Const.MaxTextureCoordUnits = MAX_TEXTURE_COORD_UNITS;
+ ctx->Const.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
+ ctx->Const.MaxTextureUnits = MIN2(ctx->Const.MaxTextureCoordUnits,
+ ctx->Const.MaxTextureImageUnits);
+ ctx->Const.MaxTextureMaxAnisotropy = MAX_TEXTURE_MAX_ANISOTROPY;
+ ctx->Const.MaxTextureLodBias = MAX_TEXTURE_LOD_BIAS;
+ ctx->Const.MaxArrayLockSize = MAX_ARRAY_LOCK_SIZE;
+ ctx->Const.SubPixelBits = SUB_PIXEL_BITS;
+ ctx->Const.MinPointSize = MIN_POINT_SIZE;
+ ctx->Const.MaxPointSize = MAX_POINT_SIZE;
+ ctx->Const.MinPointSizeAA = MIN_POINT_SIZE;
+ ctx->Const.MaxPointSizeAA = MAX_POINT_SIZE;
+ ctx->Const.PointSizeGranularity = (GLfloat) POINT_SIZE_GRANULARITY;
+ ctx->Const.MinLineWidth = MIN_LINE_WIDTH;
+ ctx->Const.MaxLineWidth = MAX_LINE_WIDTH;
+ ctx->Const.MinLineWidthAA = MIN_LINE_WIDTH;
+ ctx->Const.MaxLineWidthAA = MAX_LINE_WIDTH;
+ ctx->Const.LineWidthGranularity = (GLfloat) LINE_WIDTH_GRANULARITY;
+ ctx->Const.MaxColorTableSize = MAX_COLOR_TABLE_SIZE;
+ ctx->Const.MaxClipPlanes = MAX_CLIP_PLANES;
+ ctx->Const.MaxLights = MAX_LIGHTS;
+ ctx->Const.MaxShininess = 128.0;
+ ctx->Const.MaxSpotExponent = 128.0;
+ ctx->Const.MaxViewportWidth = MAX_WIDTH;
+ ctx->Const.MaxViewportHeight = MAX_HEIGHT;
+#if FEATURE_ARB_vertex_program
+ init_program_limits(GL_VERTEX_PROGRAM_ARB, &ctx->Const.VertexProgram);
+#endif
+#if FEATURE_ARB_fragment_program
+ init_program_limits(GL_FRAGMENT_PROGRAM_ARB, &ctx->Const.FragmentProgram);
+#endif
+#if FEATURE_ARB_geometry_shader4
+ init_program_limits(MESA_GEOMETRY_PROGRAM, &ctx->Const.GeometryProgram);
+#endif
+ ctx->Const.MaxProgramMatrices = MAX_PROGRAM_MATRICES;
+ ctx->Const.MaxProgramMatrixStackDepth = MAX_PROGRAM_MATRIX_STACK_DEPTH;
+
+ /* CheckArrayBounds is overriden by drivers/x11 for X server */
+ ctx->Const.CheckArrayBounds = GL_FALSE;
+
+ /* GL_ARB_draw_buffers */
+ ctx->Const.MaxDrawBuffers = MAX_DRAW_BUFFERS;
+
+#if FEATURE_EXT_framebuffer_object
+ ctx->Const.MaxColorAttachments = MAX_COLOR_ATTACHMENTS;
+ ctx->Const.MaxRenderbufferSize = MAX_WIDTH;
+#endif
+
+#if FEATURE_ARB_vertex_shader
+ ctx->Const.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
+ ctx->Const.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
+ ctx->Const.MaxVarying = MAX_VARYING;
+#endif
+
+ /* Shading language version */
+ if (ctx->API == API_OPENGL) {
+ ctx->Const.GLSLVersion = 120;
+ }
+ else if (ctx->API == API_OPENGLES2) {
+ ctx->Const.GLSLVersion = 100;
+ }
+ else if (ctx->API == API_OPENGLES) {
+ ctx->Const.GLSLVersion = 0; /* GLSL not supported */
+ }
+
+ /* GL_ARB_framebuffer_object */
+ ctx->Const.MaxSamples = 0;
+
+ /* GL_ARB_sync */
+ ctx->Const.MaxServerWaitTimeout = (GLuint64) ~0;
+
+ /* GL_ATI_envmap_bumpmap */
+ ctx->Const.SupportedBumpUnits = SUPPORTED_ATI_BUMP_UNITS;
+
+ /* GL_EXT_provoking_vertex */
+ ctx->Const.QuadsFollowProvokingVertexConvention = GL_TRUE;
+
+ /* GL_EXT_transform_feedback */
+ ctx->Const.MaxTransformFeedbackSeparateAttribs = MAX_FEEDBACK_ATTRIBS;
+ ctx->Const.MaxTransformFeedbackSeparateComponents = 4 * MAX_FEEDBACK_ATTRIBS;
+ ctx->Const.MaxTransformFeedbackInterleavedComponents = 4 * MAX_FEEDBACK_ATTRIBS;
+
+ /* GL 3.2: hard-coded for now: */
+ ctx->Const.ProfileMask = GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
+
+ /** GL_EXT_gpu_shader4 */
+ ctx->Const.MinProgramTexelOffset = -8;
+ ctx->Const.MaxProgramTexelOffset = 7;
+}
+
+
+/**
+ * Do some sanity checks on the limits/constants for the given context.
+ * Only called the first time a context is bound.
+ */
+static void
+check_context_limits(struct gl_context *ctx)
+{
+ /* check that we don't exceed the size of various bitfields */
+ assert(VERT_RESULT_MAX <=
+ (8 * sizeof(ctx->VertexProgram._Current->Base.OutputsWritten)));
+ assert(FRAG_ATTRIB_MAX <=
+ (8 * sizeof(ctx->FragmentProgram._Current->Base.InputsRead)));
+
+ assert(MAX_COMBINED_TEXTURE_IMAGE_UNITS <= 8 * sizeof(GLbitfield));
+
+ /* shader-related checks */
+ assert(ctx->Const.FragmentProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS);
+ assert(ctx->Const.VertexProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS);
+
+ assert(MAX_NV_FRAGMENT_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS);
+ assert(MAX_NV_VERTEX_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS);
+ assert(MAX_NV_VERTEX_PROGRAM_INPUTS <= VERT_ATTRIB_MAX);
+ assert(MAX_NV_VERTEX_PROGRAM_OUTPUTS <= VERT_RESULT_MAX);
+
+ /* Texture unit checks */
+ assert(ctx->Const.MaxTextureImageUnits > 0);
+ assert(ctx->Const.MaxTextureImageUnits <= MAX_TEXTURE_IMAGE_UNITS);
+ assert(ctx->Const.MaxTextureCoordUnits > 0);
+ assert(ctx->Const.MaxTextureCoordUnits <= MAX_TEXTURE_COORD_UNITS);
+ assert(ctx->Const.MaxTextureUnits > 0);
+ assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_IMAGE_UNITS);
+ assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_COORD_UNITS);
+ assert(ctx->Const.MaxTextureUnits == MIN2(ctx->Const.MaxTextureImageUnits,
+ ctx->Const.MaxTextureCoordUnits));
+ assert(ctx->Const.MaxCombinedTextureImageUnits > 0);
+ assert(ctx->Const.MaxCombinedTextureImageUnits <= MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+ assert(ctx->Const.MaxTextureCoordUnits <= MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+ /* number of coord units cannot be greater than number of image units */
+ assert(ctx->Const.MaxTextureCoordUnits <= ctx->Const.MaxTextureImageUnits);
+
+
+ /* Texture size checks */
+ assert(ctx->Const.MaxTextureLevels <= MAX_TEXTURE_LEVELS);
+ assert(ctx->Const.Max3DTextureLevels <= MAX_3D_TEXTURE_LEVELS);
+ assert(ctx->Const.MaxCubeTextureLevels <= MAX_CUBE_TEXTURE_LEVELS);
+ assert(ctx->Const.MaxTextureRectSize <= MAX_TEXTURE_RECT_SIZE);
+
+ /* make sure largest texture image is <= MAX_WIDTH in size */
+ assert((1 << (ctx->Const.MaxTextureLevels - 1)) <= MAX_WIDTH);
+ assert((1 << (ctx->Const.MaxCubeTextureLevels - 1)) <= MAX_WIDTH);
+ assert((1 << (ctx->Const.Max3DTextureLevels - 1)) <= MAX_WIDTH);
+
+ /* Texture level checks */
+ assert(MAX_TEXTURE_LEVELS >= MAX_3D_TEXTURE_LEVELS);
+ assert(MAX_TEXTURE_LEVELS >= MAX_CUBE_TEXTURE_LEVELS);
+
+ /* Max texture size should be <= max viewport size (render to texture) */
+ assert((1 << (MAX_TEXTURE_LEVELS - 1)) <= MAX_WIDTH);
+
+ assert(ctx->Const.MaxViewportWidth <= MAX_WIDTH);
+ assert(ctx->Const.MaxViewportHeight <= MAX_WIDTH);
+
+ assert(ctx->Const.MaxDrawBuffers <= MAX_DRAW_BUFFERS);
+
+ /* if this fails, add more enum values to gl_buffer_index */
+ assert(BUFFER_COLOR0 + MAX_DRAW_BUFFERS <= BUFFER_COUNT);
+
+ /* XXX probably add more tests */
+}
+
+
+/**
+ * Initialize the attribute groups in a GL context.
+ *
+ * \param ctx GL context.
+ *
+ * Initializes all the attributes, calling the respective <tt>init*</tt>
+ * functions for the more complex data structures.
+ */
+static GLboolean
+init_attrib_groups(struct gl_context *ctx)
+{
+ assert(ctx);
+
+ /* Constants */
+ _mesa_init_constants( ctx );
+
+ /* Extensions */
+ _mesa_init_extensions( ctx );
+
+ /* Attribute Groups */
+ _mesa_init_accum( ctx );
+ _mesa_init_attrib( ctx );
+ _mesa_init_buffer_objects( ctx );
+ _mesa_init_color( ctx );
+ _mesa_init_current( ctx );
+ _mesa_init_depth( ctx );
+ _mesa_init_debug( ctx );
+ _mesa_init_display_list( ctx );
+ _mesa_init_eval( ctx );
+ _mesa_init_fbobjects( ctx );
+ _mesa_init_feedback( ctx );
+ _mesa_init_fog( ctx );
+ _mesa_init_hint( ctx );
+ _mesa_init_line( ctx );
+ _mesa_init_lighting( ctx );
+ _mesa_init_matrix( ctx );
+ _mesa_init_multisample( ctx );
+ _mesa_init_pixel( ctx );
+ _mesa_init_pixelstore( ctx );
+ _mesa_init_point( ctx );
+ _mesa_init_polygon( ctx );
+ _mesa_init_program( ctx );
+ _mesa_init_queryobj( ctx );
+ _mesa_init_sync( ctx );
+ _mesa_init_rastpos( ctx );
+ _mesa_init_scissor( ctx );
+ _mesa_init_shader_state( ctx );
+ _mesa_init_stencil( ctx );
+ _mesa_init_transform( ctx );
+ _mesa_init_transform_feedback( ctx );
+ _mesa_init_varray( ctx );
+ _mesa_init_viewport( ctx );
+
+ if (!_mesa_init_texture( ctx ))
+ return GL_FALSE;
+
+ _mesa_init_texture_s3tc( ctx );
+
+ /* Miscellaneous */
+ ctx->NewState = _NEW_ALL;
+ ctx->ErrorValue = (GLenum) GL_NO_ERROR;
+ ctx->varying_vp_inputs = ~0;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Update default objects in a GL context with respect to shared state.
+ *
+ * \param ctx GL context.
+ *
+ * Removes references to old default objects, (texture objects, program
+ * objects, etc.) and changes to reference those from the current shared
+ * state.
+ */
+static GLboolean
+update_default_objects(struct gl_context *ctx)
+{
+ assert(ctx);
+
+ _mesa_update_default_objects_program(ctx);
+ _mesa_update_default_objects_texture(ctx);
+ _mesa_update_default_objects_buffer_objects(ctx);
+
+ return GL_TRUE;
+}
+
+
+/**
+ * This is the default function we plug into all dispatch table slots
+ * This helps prevents a segfault when someone calls a GL function without
+ * first checking if the extension's supported.
+ */
+static int
+generic_nop(void)
+{
+ _mesa_warning(NULL, "User called no-op dispatch function (an unsupported extension function?)");
+ return 0;
+}
+
+
+/**
+ * Allocate and initialize a new dispatch table.
+ */
+struct _glapi_table *
+_mesa_alloc_dispatch_table(int size)
+{
+ /* Find the larger of Mesa's dispatch table and libGL's dispatch table.
+ * In practice, this'll be the same for stand-alone Mesa. But for DRI
+ * Mesa we do this to accomodate different versions of libGL and various
+ * DRI drivers.
+ */
+ GLint numEntries = MAX2(_glapi_get_dispatch_table_size(), _gloffset_COUNT);
+ struct _glapi_table *table;
+
+ /* should never happen, but just in case */
+ numEntries = MAX2(numEntries, size);
+
+ table = (struct _glapi_table *) malloc(numEntries * sizeof(_glapi_proc));
+ if (table) {
+ _glapi_proc *entry = (_glapi_proc *) table;
+ GLint i;
+ for (i = 0; i < numEntries; i++) {
+ entry[i] = (_glapi_proc) generic_nop;
+ }
+ }
+ return table;
+}
+
+
+/**
+ * Initialize a struct gl_context struct (rendering context).
+ *
+ * This includes allocating all the other structs and arrays which hang off of
+ * the context by pointers.
+ * Note that the driver needs to pass in its dd_function_table here since
+ * we need to at least call driverFunctions->NewTextureObject to create the
+ * default texture objects.
+ *
+ * Called by _mesa_create_context().
+ *
+ * Performs the imports and exports callback tables initialization, and
+ * miscellaneous one-time initializations. If no shared context is supplied one
+ * is allocated, and increase its reference count. Setups the GL API dispatch
+ * tables. Initialize the TNL module. Sets the maximum Z buffer depth.
+ * Finally queries the \c MESA_DEBUG and \c MESA_VERBOSE environment variables
+ * for debug flags.
+ *
+ * \param ctx the context to initialize
+ * \param api the GL API type to create the context for
+ * \param visual describes the visual attributes for this context
+ * \param share_list points to context to share textures, display lists,
+ * etc with, or NULL
+ * \param driverFunctions table of device driver functions for this context
+ * to use
+ * \param driverContext pointer to driver-specific context data
+ */
+GLboolean
+_mesa_initialize_context(struct gl_context *ctx,
+ gl_api api,
+ const struct gl_config *visual,
+ struct gl_context *share_list,
+ const struct dd_function_table *driverFunctions,
+ void *driverContext)
+{
+ struct gl_shared_state *shared;
+ int i;
+
+ /*ASSERT(driverContext);*/
+ assert(driverFunctions->NewTextureObject);
+ assert(driverFunctions->FreeTexImageData);
+
+ ctx->API = api;
+ ctx->Visual = *visual;
+ ctx->DrawBuffer = NULL;
+ ctx->ReadBuffer = NULL;
+ ctx->WinSysDrawBuffer = NULL;
+ ctx->WinSysReadBuffer = NULL;
+
+ /* misc one-time initializations */
+ one_time_init(ctx);
+
+ /* Plug in driver functions and context pointer here.
+ * This is important because when we call alloc_shared_state() below
+ * we'll call ctx->Driver.NewTextureObject() to create the default
+ * textures.
+ */
+ ctx->Driver = *driverFunctions;
+ ctx->DriverCtx = driverContext;
+
+ if (share_list) {
+ /* share state with another context */
+ shared = share_list->Shared;
+ }
+ else {
+ /* allocate new, unshared state */
+ shared = _mesa_alloc_shared_state(ctx);
+ if (!shared)
+ return GL_FALSE;
+ }
+
+ _glthread_LOCK_MUTEX(shared->Mutex);
+ ctx->Shared = shared;
+ shared->RefCount++;
+ _glthread_UNLOCK_MUTEX(shared->Mutex);
+
+ if (!init_attrib_groups( ctx )) {
+ _mesa_release_shared_state(ctx, ctx->Shared);
+ return GL_FALSE;
+ }
+
+#if FEATURE_dispatch
+ /* setup the API dispatch tables */
+ switch (ctx->API) {
+#if FEATURE_GL
+ case API_OPENGL:
+ ctx->Exec = _mesa_create_exec_table();
+ break;
+#endif
+#if FEATURE_ES1
+ case API_OPENGLES:
+ ctx->Exec = _mesa_create_exec_table_es1();
+ break;
+#endif
+#if FEATURE_ES2
+ case API_OPENGLES2:
+ ctx->Exec = _mesa_create_exec_table_es2();
+ break;
+#endif
+ default:
+ _mesa_problem(ctx, "unknown or unsupported API");
+ break;
+ }
+
+ if (!ctx->Exec) {
+ _mesa_release_shared_state(ctx, ctx->Shared);
+ return GL_FALSE;
+ }
+#endif
+ ctx->CurrentDispatch = ctx->Exec;
+
+ ctx->FragmentProgram._MaintainTexEnvProgram
+ = (_mesa_getenv("MESA_TEX_PROG") != NULL);
+
+ ctx->VertexProgram._MaintainTnlProgram
+ = (_mesa_getenv("MESA_TNL_PROG") != NULL);
+ if (ctx->VertexProgram._MaintainTnlProgram) {
+ /* this is required... */
+ ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
+ }
+
+ /* Mesa core handles all the formats that mesa core knows about.
+ * Drivers will want to override this list with just the formats
+ * they can handle, and confirm that appropriate fallbacks exist in
+ * _mesa_choose_tex_format().
+ */
+ memset(&ctx->TextureFormatSupported, GL_TRUE,
+ sizeof(ctx->TextureFormatSupported));
+
+ switch (ctx->API) {
+ case API_OPENGL:
+#if FEATURE_dlist
+ ctx->Save = _mesa_create_save_table();
+ if (!ctx->Save) {
+ _mesa_release_shared_state(ctx, ctx->Shared);
+ free(ctx->Exec);
+ return GL_FALSE;
+ }
+
+ _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
+#endif
+ break;
+ case API_OPENGLES:
+ /**
+ * GL_OES_texture_cube_map says
+ * "Initially all texture generation modes are set to REFLECTION_MAP_OES"
+ */
+ for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
+ texUnit->GenS.Mode = GL_REFLECTION_MAP_NV;
+ texUnit->GenT.Mode = GL_REFLECTION_MAP_NV;
+ texUnit->GenR.Mode = GL_REFLECTION_MAP_NV;
+ texUnit->GenS._ModeBit = TEXGEN_REFLECTION_MAP_NV;
+ texUnit->GenT._ModeBit = TEXGEN_REFLECTION_MAP_NV;
+ texUnit->GenR._ModeBit = TEXGEN_REFLECTION_MAP_NV;
+ }
+ break;
+ case API_OPENGLES2:
+ ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
+ ctx->VertexProgram._MaintainTnlProgram = GL_TRUE;
+ ctx->Point.PointSprite = GL_TRUE; /* always on for ES 2.x */
+ break;
+ }
+
+ ctx->FirstTimeCurrent = GL_TRUE;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Allocate and initialize a struct gl_context structure.
+ * Note that the driver needs to pass in its dd_function_table here since
+ * we need to at least call driverFunctions->NewTextureObject to initialize
+ * the rendering context.
+ *
+ * \param api the GL API type to create the context for
+ * \param visual a struct gl_config pointer (we copy the struct contents)
+ * \param share_list another context to share display lists with or NULL
+ * \param driverFunctions points to the dd_function_table into which the
+ * driver has plugged in all its special functions.
+ * \param driverContext points to the device driver's private context state
+ *
+ * \return pointer to a new __struct gl_contextRec or NULL if error.
+ */
+struct gl_context *
+_mesa_create_context(gl_api api,
+ const struct gl_config *visual,
+ struct gl_context *share_list,
+ const struct dd_function_table *driverFunctions,
+ void *driverContext)
+{
+ struct gl_context *ctx;
+
+ ASSERT(visual);
+ /*ASSERT(driverContext);*/
+
+ ctx = (struct gl_context *) calloc(1, sizeof(struct gl_context));
+ if (!ctx)
+ return NULL;
+
+ if (_mesa_initialize_context(ctx, api, visual, share_list,
+ driverFunctions, driverContext)) {
+ return ctx;
+ }
+ else {
+ free(ctx);
+ return NULL;
+ }
+}
+
+
+/**
+ * Free the data associated with the given context.
+ *
+ * But doesn't free the struct gl_context struct itself.
+ *
+ * \sa _mesa_initialize_context() and init_attrib_groups().
+ */
+void
+_mesa_free_context_data( struct gl_context *ctx )
+{
+ if (!_mesa_get_current_context()){
+ /* No current context, but we may need one in order to delete
+ * texture objs, etc. So temporarily bind the context now.
+ */
+ _mesa_make_current(ctx, NULL, NULL);
+ }
+
+ /* unreference WinSysDraw/Read buffers */
+ _mesa_reference_framebuffer(&ctx->WinSysDrawBuffer, NULL);
+ _mesa_reference_framebuffer(&ctx->WinSysReadBuffer, NULL);
+ _mesa_reference_framebuffer(&ctx->DrawBuffer, NULL);
+ _mesa_reference_framebuffer(&ctx->ReadBuffer, NULL);
+
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL);
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, NULL);
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram, NULL);
+
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL);
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram, NULL);
+
+ _mesa_free_attrib_data(ctx);
+ _mesa_free_buffer_objects(ctx);
+ _mesa_free_lighting_data( ctx );
+ _mesa_free_eval_data( ctx );
+ _mesa_free_texture_data( ctx );
+ _mesa_free_matrix_data( ctx );
+ _mesa_free_viewport_data( ctx );
+ _mesa_free_program_data(ctx);
+ _mesa_free_shader_state(ctx);
+ _mesa_free_queryobj_data(ctx);
+ _mesa_free_sync_data(ctx);
+ _mesa_free_varray_data(ctx);
+ _mesa_free_transform_feedback(ctx);
+
+ _mesa_delete_array_object(ctx, ctx->Array.DefaultArrayObj);
+
+#if FEATURE_ARB_pixel_buffer_object
+ _mesa_reference_buffer_object(ctx, &ctx->Pack.BufferObj, NULL);
+ _mesa_reference_buffer_object(ctx, &ctx->Unpack.BufferObj, NULL);
+ _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, NULL);
+#endif
+
+#if FEATURE_ARB_vertex_buffer_object
+ _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
+ _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL);
+#endif
+
+ /* free dispatch tables */
+ free(ctx->Exec);
+ free(ctx->Save);
+
+ /* Shared context state (display lists, textures, etc) */
+ _mesa_release_shared_state( ctx, ctx->Shared );
+
+ /* needs to be after freeing shared state */
+ _mesa_free_display_list_data(ctx);
+
+ if (ctx->Extensions.String)
+ free((void *) ctx->Extensions.String);
+
+ if (ctx->VersionString)
+ free(ctx->VersionString);
+
+ /* unbind the context if it's currently bound */
+ if (ctx == _mesa_get_current_context()) {
+ _mesa_make_current(NULL, NULL, NULL);
+ }
+}
+
+
+/**
+ * Destroy a struct gl_context structure.
+ *
+ * \param ctx GL context.
+ *
+ * Calls _mesa_free_context_data() and frees the gl_context object itself.
+ */
+void
+_mesa_destroy_context( struct gl_context *ctx )
+{
+ if (ctx) {
+ _mesa_free_context_data(ctx);
+ free( (void *) ctx );
+ }
+}
+
+
+#if _HAVE_FULL_GL
+/**
+ * Copy attribute groups from one context to another.
+ *
+ * \param src source context
+ * \param dst destination context
+ * \param mask bitwise OR of GL_*_BIT flags
+ *
+ * According to the bits specified in \p mask, copies the corresponding
+ * attributes from \p src into \p dst. For many of the attributes a simple \c
+ * memcpy is not enough due to the existence of internal pointers in their data
+ * structures.
+ */
+void
+_mesa_copy_context( const struct gl_context *src, struct gl_context *dst, GLuint mask )
+{
+ if (mask & GL_ACCUM_BUFFER_BIT) {
+ /* OK to memcpy */
+ dst->Accum = src->Accum;
+ }
+ if (mask & GL_COLOR_BUFFER_BIT) {
+ /* OK to memcpy */
+ dst->Color = src->Color;
+ }
+ if (mask & GL_CURRENT_BIT) {
+ /* OK to memcpy */
+ dst->Current = src->Current;
+ }
+ if (mask & GL_DEPTH_BUFFER_BIT) {
+ /* OK to memcpy */
+ dst->Depth = src->Depth;
+ }
+ if (mask & GL_ENABLE_BIT) {
+ /* no op */
+ }
+ if (mask & GL_EVAL_BIT) {
+ /* OK to memcpy */
+ dst->Eval = src->Eval;
+ }
+ if (mask & GL_FOG_BIT) {
+ /* OK to memcpy */
+ dst->Fog = src->Fog;
+ }
+ if (mask & GL_HINT_BIT) {
+ /* OK to memcpy */
+ dst->Hint = src->Hint;
+ }
+ if (mask & GL_LIGHTING_BIT) {
+ GLuint i;
+ /* begin with memcpy */
+ dst->Light = src->Light;
+ /* fixup linked lists to prevent pointer insanity */
+ make_empty_list( &(dst->Light.EnabledList) );
+ for (i = 0; i < MAX_LIGHTS; i++) {
+ if (dst->Light.Light[i].Enabled) {
+ insert_at_tail(&(dst->Light.EnabledList), &(dst->Light.Light[i]));
+ }
+ }
+ }
+ if (mask & GL_LINE_BIT) {
+ /* OK to memcpy */
+ dst->Line = src->Line;
+ }
+ if (mask & GL_LIST_BIT) {
+ /* OK to memcpy */
+ dst->List = src->List;
+ }
+ if (mask & GL_PIXEL_MODE_BIT) {
+ /* OK to memcpy */
+ dst->Pixel = src->Pixel;
+ }
+ if (mask & GL_POINT_BIT) {
+ /* OK to memcpy */
+ dst->Point = src->Point;
+ }
+ if (mask & GL_POLYGON_BIT) {
+ /* OK to memcpy */
+ dst->Polygon = src->Polygon;
+ }
+ if (mask & GL_POLYGON_STIPPLE_BIT) {
+ /* Use loop instead of memcpy due to problem with Portland Group's
+ * C compiler. Reported by John Stone.
+ */
+ GLuint i;
+ for (i = 0; i < 32; i++) {
+ dst->PolygonStipple[i] = src->PolygonStipple[i];
+ }
+ }
+ if (mask & GL_SCISSOR_BIT) {
+ /* OK to memcpy */
+ dst->Scissor = src->Scissor;
+ }
+ if (mask & GL_STENCIL_BUFFER_BIT) {
+ /* OK to memcpy */
+ dst->Stencil = src->Stencil;
+ }
+ if (mask & GL_TEXTURE_BIT) {
+ /* Cannot memcpy because of pointers */
+ _mesa_copy_texture_state(src, dst);
+ }
+ if (mask & GL_TRANSFORM_BIT) {
+ /* OK to memcpy */
+ dst->Transform = src->Transform;
+ }
+ if (mask & GL_VIEWPORT_BIT) {
+ /* Cannot use memcpy, because of pointers in GLmatrix _WindowMap */
+ dst->Viewport.X = src->Viewport.X;
+ dst->Viewport.Y = src->Viewport.Y;
+ dst->Viewport.Width = src->Viewport.Width;
+ dst->Viewport.Height = src->Viewport.Height;
+ dst->Viewport.Near = src->Viewport.Near;
+ dst->Viewport.Far = src->Viewport.Far;
+ _math_matrix_copy(&dst->Viewport._WindowMap, &src->Viewport._WindowMap);
+ }
+
+ /* XXX FIXME: Call callbacks?
+ */
+ dst->NewState = _NEW_ALL;
+}
+#endif
+
+
+/**
+ * Check if the given context can render into the given framebuffer
+ * by checking visual attributes.
+ *
+ * Most of these tests could go away because Mesa is now pretty flexible
+ * in terms of mixing rendering contexts with framebuffers. As long
+ * as RGB vs. CI mode agree, we're probably good.
+ *
+ * \return GL_TRUE if compatible, GL_FALSE otherwise.
+ */
+static GLboolean
+check_compatible(const struct gl_context *ctx,
+ const struct gl_framebuffer *buffer)
+{
+ const struct gl_config *ctxvis = &ctx->Visual;
+ const struct gl_config *bufvis = &buffer->Visual;
+
+ if (buffer == _mesa_get_incomplete_framebuffer())
+ return GL_TRUE;
+
+#if 0
+ /* disabling this fixes the fgl_glxgears pbuffer demo */
+ if (ctxvis->doubleBufferMode && !bufvis->doubleBufferMode)
+ return GL_FALSE;
+#endif
+ if (ctxvis->stereoMode && !bufvis->stereoMode)
+ return GL_FALSE;
+ if (ctxvis->haveAccumBuffer && !bufvis->haveAccumBuffer)
+ return GL_FALSE;
+ if (ctxvis->haveDepthBuffer && !bufvis->haveDepthBuffer)
+ return GL_FALSE;
+ if (ctxvis->haveStencilBuffer && !bufvis->haveStencilBuffer)
+ return GL_FALSE;
+ if (ctxvis->redMask && ctxvis->redMask != bufvis->redMask)
+ return GL_FALSE;
+ if (ctxvis->greenMask && ctxvis->greenMask != bufvis->greenMask)
+ return GL_FALSE;
+ if (ctxvis->blueMask && ctxvis->blueMask != bufvis->blueMask)
+ return GL_FALSE;
+#if 0
+ /* disabled (see bug 11161) */
+ if (ctxvis->depthBits && ctxvis->depthBits != bufvis->depthBits)
+ return GL_FALSE;
+#endif
+ if (ctxvis->stencilBits && ctxvis->stencilBits != bufvis->stencilBits)
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Do one-time initialization for the given framebuffer. Specifically,
+ * ask the driver for the window's current size and update the framebuffer
+ * object to match.
+ * Really, the device driver should totally take care of this.
+ */
+static void
+initialize_framebuffer_size(struct gl_context *ctx, struct gl_framebuffer *fb)
+{
+ GLuint width, height;
+ if (ctx->Driver.GetBufferSize) {
+ ctx->Driver.GetBufferSize(fb, &width, &height);
+ if (ctx->Driver.ResizeBuffers)
+ ctx->Driver.ResizeBuffers(ctx, fb, width, height);
+ fb->Initialized = GL_TRUE;
+ }
+}
+
+
+/**
+ * Check if the viewport/scissor size has not yet been initialized.
+ * Initialize the size if the given width and height are non-zero.
+ */
+void
+_mesa_check_init_viewport(struct gl_context *ctx, GLuint width, GLuint height)
+{
+ if (!ctx->ViewportInitialized && width > 0 && height > 0) {
+ /* Note: set flag here, before calling _mesa_set_viewport(), to prevent
+ * potential infinite recursion.
+ */
+ ctx->ViewportInitialized = GL_TRUE;
+ _mesa_set_viewport(ctx, 0, 0, width, height);
+ _mesa_set_scissor(ctx, 0, 0, width, height);
+ }
+}
+
+
+/**
+ * Bind the given context to the given drawBuffer and readBuffer and
+ * make it the current context for the calling thread.
+ * We'll render into the drawBuffer and read pixels from the
+ * readBuffer (i.e. glRead/CopyPixels, glCopyTexImage, etc).
+ *
+ * We check that the context's and framebuffer's visuals are compatible
+ * and return immediately if they're not.
+ *
+ * \param newCtx the new GL context. If NULL then there will be no current GL
+ * context.
+ * \param drawBuffer the drawing framebuffer
+ * \param readBuffer the reading framebuffer
+ */
+GLboolean
+_mesa_make_current( struct gl_context *newCtx,
+ struct gl_framebuffer *drawBuffer,
+ struct gl_framebuffer *readBuffer )
+{
+ GET_CURRENT_CONTEXT(curCtx);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(newCtx, "_mesa_make_current()\n");
+
+ /* Check that the context's and framebuffer's visuals are compatible.
+ */
+ if (newCtx && drawBuffer && newCtx->WinSysDrawBuffer != drawBuffer) {
+ if (!check_compatible(newCtx, drawBuffer)) {
+ _mesa_warning(newCtx,
+ "MakeCurrent: incompatible visuals for context and drawbuffer");
+ return GL_FALSE;
+ }
+ }
+ if (newCtx && readBuffer && newCtx->WinSysReadBuffer != readBuffer) {
+ if (!check_compatible(newCtx, readBuffer)) {
+ _mesa_warning(newCtx,
+ "MakeCurrent: incompatible visuals for context and readbuffer");
+ return GL_FALSE;
+ }
+ }
+
+ if (curCtx &&
+ (curCtx->WinSysDrawBuffer || curCtx->WinSysReadBuffer) && /* make sure this context is valid for flushing */
+ curCtx != newCtx)
+ _mesa_flush(curCtx);
+
+ /* We used to call _glapi_check_multithread() here. Now do it in drivers */
+ _glapi_set_context((void *) newCtx);
+ ASSERT(_mesa_get_current_context() == newCtx);
+
+ if (!newCtx) {
+ _glapi_set_dispatch(NULL); /* none current */
+ }
+ else {
+ _glapi_set_dispatch(newCtx->CurrentDispatch);
+
+ if (drawBuffer && readBuffer) {
+ /* TODO: check if newCtx and buffer's visual match??? */
+
+ ASSERT(drawBuffer->Name == 0);
+ ASSERT(readBuffer->Name == 0);
+ _mesa_reference_framebuffer(&newCtx->WinSysDrawBuffer, drawBuffer);
+ _mesa_reference_framebuffer(&newCtx->WinSysReadBuffer, readBuffer);
+
+ /*
+ * Only set the context's Draw/ReadBuffer fields if they're NULL
+ * or not bound to a user-created FBO.
+ */
+ if (!newCtx->DrawBuffer || newCtx->DrawBuffer->Name == 0) {
+ /* KW: merge conflict here, revisit.
+ */
+ /* fix up the fb fields - these will end up wrong otherwise
+ * if the DRIdrawable changes, and everything relies on them.
+ * This is a bit messy (same as needed in _mesa_BindFramebufferEXT)
+ */
+ unsigned int i;
+ GLenum buffers[MAX_DRAW_BUFFERS];
+
+ _mesa_reference_framebuffer(&newCtx->DrawBuffer, drawBuffer);
+
+ for(i = 0; i < newCtx->Const.MaxDrawBuffers; i++) {
+ buffers[i] = newCtx->Color.DrawBuffer[i];
+ }
+
+ _mesa_drawbuffers(newCtx, newCtx->Const.MaxDrawBuffers,
+ buffers, NULL);
+ }
+ if (!newCtx->ReadBuffer || newCtx->ReadBuffer->Name == 0) {
+ _mesa_reference_framebuffer(&newCtx->ReadBuffer, readBuffer);
+ }
+
+ /* XXX only set this flag if we're really changing the draw/read
+ * framebuffer bindings.
+ */
+ newCtx->NewState |= _NEW_BUFFERS;
+
+#if 1
+ /* We want to get rid of these lines: */
+
+#if _HAVE_FULL_GL
+ if (!drawBuffer->Initialized) {
+ initialize_framebuffer_size(newCtx, drawBuffer);
+ }
+ if (readBuffer != drawBuffer && !readBuffer->Initialized) {
+ initialize_framebuffer_size(newCtx, readBuffer);
+ }
+
+ _mesa_resizebuffers(newCtx);
+#endif
+
+#else
+ /* We want the drawBuffer and readBuffer to be initialized by
+ * the driver.
+ * This generally means the Width and Height match the actual
+ * window size and the renderbuffers (both hardware and software
+ * based) are allocated to match. The later can generally be
+ * done with a call to _mesa_resize_framebuffer().
+ *
+ * It's theoretically possible for a buffer to have zero width
+ * or height, but for now, assert check that the driver did what's
+ * expected of it.
+ */
+ ASSERT(drawBuffer->Width > 0);
+ ASSERT(drawBuffer->Height > 0);
+#endif
+
+ if (drawBuffer) {
+ _mesa_check_init_viewport(newCtx,
+ drawBuffer->Width, drawBuffer->Height);
+ }
+ }
+
+ if (newCtx->FirstTimeCurrent) {
+ _mesa_compute_version(newCtx);
+
+ newCtx->Extensions.String = _mesa_make_extension_string(newCtx);
+
+ check_context_limits(newCtx);
+
+ /* We can use this to help debug user's problems. Tell them to set
+ * the MESA_INFO env variable before running their app. Then the
+ * first time each context is made current we'll print some useful
+ * information.
+ */
+ if (_mesa_getenv("MESA_INFO")) {
+ _mesa_print_info();
+ }
+
+ newCtx->FirstTimeCurrent = GL_FALSE;
+ }
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Make context 'ctx' share the display lists, textures and programs
+ * that are associated with 'ctxToShare'.
+ * Any display lists, textures or programs associated with 'ctx' will
+ * be deleted if nobody else is sharing them.
+ */
+GLboolean
+_mesa_share_state(struct gl_context *ctx, struct gl_context *ctxToShare)
+{
+ if (ctx && ctxToShare && ctx->Shared && ctxToShare->Shared) {
+ struct gl_shared_state *oldSharedState = ctx->Shared;
+
+ ctx->Shared = ctxToShare->Shared;
+
+ _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+ ctx->Shared->RefCount++;
+ _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+
+ update_default_objects(ctx);
+
+ _mesa_release_shared_state(ctx, oldSharedState);
+
+ return GL_TRUE;
+ }
+ else {
+ return GL_FALSE;
+ }
+}
+
+
+
+/**
+ * \return pointer to the current GL context for this thread.
+ *
+ * Calls _glapi_get_context(). This isn't the fastest way to get the current
+ * context. If you need speed, see the #GET_CURRENT_CONTEXT macro in
+ * context.h.
+ */
+struct gl_context *
+_mesa_get_current_context( void )
+{
+ return (struct gl_context *) _glapi_get_context();
+}
+
+
+/**
+ * Get context's current API dispatch table.
+ *
+ * It'll either be the immediate-mode execute dispatcher or the display list
+ * compile dispatcher.
+ *
+ * \param ctx GL context.
+ *
+ * \return pointer to dispatch_table.
+ *
+ * Simply returns __struct gl_contextRec::CurrentDispatch.
+ */
+struct _glapi_table *
+_mesa_get_dispatch(struct gl_context *ctx)
+{
+ return ctx->CurrentDispatch;
+}
+
+/*@}*/
+
+
+/**********************************************************************/
+/** \name Miscellaneous functions */
+/**********************************************************************/
+/*@{*/
+
+/**
+ * Record an error.
+ *
+ * \param ctx GL context.
+ * \param error error code.
+ *
+ * Records the given error code and call the driver's dd_function_table::Error
+ * function if defined.
+ *
+ * \sa
+ * This is called via _mesa_error().
+ */
+void
+_mesa_record_error(struct gl_context *ctx, GLenum error)
+{
+ if (!ctx)
+ return;
+
+ if (ctx->ErrorValue == GL_NO_ERROR) {
+ ctx->ErrorValue = error;
+ }
+
+ /* Call device driver's error handler, if any. This is used on the Mac. */
+ if (ctx->Driver.Error) {
+ ctx->Driver.Error(ctx);
+ }
+}
+
+
+/**
+ * Flush commands and wait for completion.
+ */
+void
+_mesa_finish(struct gl_context *ctx)
+{
+ FLUSH_CURRENT( ctx, 0 );
+ if (ctx->Driver.Finish) {
+ ctx->Driver.Finish(ctx);
+ }
+}
+
+
+/**
+ * Flush commands.
+ */
+void
+_mesa_flush(struct gl_context *ctx)
+{
+ FLUSH_CURRENT( ctx, 0 );
+ if (ctx->Driver.Flush) {
+ ctx->Driver.Flush(ctx);
+ }
+}
+
+
+
+/**
+ * Execute glFinish().
+ *
+ * Calls the #ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH macro and the
+ * dd_function_table::Finish driver callback, if not NULL.
+ */
+void GLAPIENTRY
+_mesa_Finish(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+ _mesa_finish(ctx);
+}
+
+
+/**
+ * Execute glFlush().
+ *
+ * Calls the #ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH macro and the
+ * dd_function_table::Flush driver callback, if not NULL.
+ */
+void GLAPIENTRY
+_mesa_Flush(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+ _mesa_flush(ctx);
+}
+
+
+/**
+ * Set mvp_with_dp4 flag. If a driver has a preference for DP4 over
+ * MUL/MAD, or vice versa, call this function to register that.
+ * Otherwise we default to MUL/MAD.
+ */
+void
+_mesa_set_mvp_with_dp4( struct gl_context *ctx,
+ GLboolean flag )
+{
+ ctx->mvp_with_dp4 = flag;
+}
+
+
+
+/**
+ * Prior to drawing anything with glBegin, glDrawArrays, etc. this function
+ * is called to see if it's valid to render. This involves checking that
+ * the current shader is valid and the framebuffer is complete.
+ * If an error is detected it'll be recorded here.
+ * \return GL_TRUE if OK to render, GL_FALSE if not
+ */
+GLboolean
+_mesa_valid_to_render(struct gl_context *ctx, const char *where)
+{
+ bool vert_from_glsl_shader = false;
+ bool geom_from_glsl_shader = false;
+ bool frag_from_glsl_shader = false;
+
+ /* This depends on having up to date derived state (shaders) */
+ if (ctx->NewState)
+ _mesa_update_state(ctx);
+
+ if (ctx->Shader.CurrentVertexProgram) {
+ vert_from_glsl_shader = true;
+
+ if (!ctx->Shader.CurrentVertexProgram->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(shader not linked)", where);
+ return GL_FALSE;
+ }
+#if 0 /* not normally enabled */
+ {
+ char errMsg[100];
+ if (!_mesa_validate_shader_program(ctx,
+ ctx->Shader.CurrentVertexProgram,
+ errMsg)) {
+ _mesa_warning(ctx, "Shader program %u is invalid: %s",
+ ctx->Shader.CurrentVertexProgram->Name, errMsg);
+ }
+ }
+#endif
+ }
+
+ if (ctx->Shader.CurrentGeometryProgram) {
+ geom_from_glsl_shader = true;
+
+ if (!ctx->Shader.CurrentGeometryProgram->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(shader not linked)", where);
+ return GL_FALSE;
+ }
+#if 0 /* not normally enabled */
+ {
+ char errMsg[100];
+ if (!_mesa_validate_shader_program(ctx,
+ ctx->Shader.CurrentGeometryProgram,
+ errMsg)) {
+ _mesa_warning(ctx, "Shader program %u is invalid: %s",
+ ctx->Shader.CurrentGeometryProgram->Name, errMsg);
+ }
+ }
+#endif
+ }
+
+ if (ctx->Shader.CurrentFragmentProgram) {
+ frag_from_glsl_shader = true;
+
+ if (!ctx->Shader.CurrentFragmentProgram->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(shader not linked)", where);
+ return GL_FALSE;
+ }
+#if 0 /* not normally enabled */
+ {
+ char errMsg[100];
+ if (!_mesa_validate_shader_program(ctx,
+ ctx->Shader.CurrentFragmentProgram,
+ errMsg)) {
+ _mesa_warning(ctx, "Shader program %u is invalid: %s",
+ ctx->Shader.CurrentFragmentProgram->Name, errMsg);
+ }
+ }
+#endif
+ }
+
+ /* Any shader stages that are not supplied by the GLSL shader and have
+ * assembly shaders enabled must now be validated.
+ */
+ if (!vert_from_glsl_shader
+ && ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(vertex program not valid)", where);
+ return GL_FALSE;
+ }
+
+ /* FINISHME: If GL_NV_geometry_program4 is ever supported, the current
+ * FINISHME: geometry program should validated here.
+ */
+ (void) geom_from_glsl_shader;
+
+ if (!frag_from_glsl_shader) {
+ if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(fragment program not valid)", where);
+ return GL_FALSE;
+ }
+
+ /* If drawing to integer-valued color buffers, there must be an
+ * active fragment shader (GL_EXT_texture_integer).
+ */
+ if (ctx->DrawBuffer && ctx->DrawBuffer->_IntegerColor) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(integer format but no fragment shader)", where);
+ return GL_FALSE;
+ }
+ }
+
+ if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
+ "%s(incomplete framebuffer)", where);
+ return GL_FALSE;
+ }
+
+#ifdef DEBUG
+ if (ctx->Shader.Flags & GLSL_LOG) {
+ struct gl_shader_program *shProg[MESA_SHADER_TYPES];
+ gl_shader_type i;
+
+ shProg[MESA_SHADER_VERTEX] = ctx->Shader.CurrentVertexProgram;
+ shProg[MESA_SHADER_GEOMETRY] = ctx->Shader.CurrentGeometryProgram;
+ shProg[MESA_SHADER_FRAGMENT] = ctx->Shader.CurrentFragmentProgram;
+
+ for (i = 0; i < MESA_SHADER_TYPES; i++) {
+ struct gl_shader *sh;
+
+ if (shProg[i] == NULL || shProg[i]->_Used
+ || shProg[i]->_LinkedShaders[i] == NULL)
+ continue;
+
+ /* This is the first time this shader is being used.
+ * Append shader's constants/uniforms to log file.
+ *
+ * The logic is a little odd here. We only want to log data for each
+ * shader target that will actually be used, and we only want to log
+ * it once. It's possible to have a program bound to the vertex
+ * shader target that also supplied a fragment shader. If that
+ * program isn't also bound to the fragment shader target we don't
+ * want to log its fragment data.
+ */
+ sh = shProg[i]->_LinkedShaders[i];
+ switch (sh->Type) {
+ case GL_VERTEX_SHADER:
+ _mesa_append_uniforms_to_file(sh, &shProg[i]->VertexProgram->Base);
+ break;
+
+ case GL_GEOMETRY_SHADER_ARB:
+ _mesa_append_uniforms_to_file(sh,
+ &shProg[i]->GeometryProgram->Base);
+ break;
+
+ case GL_FRAGMENT_SHADER:
+ _mesa_append_uniforms_to_file(sh,
+ &shProg[i]->FragmentProgram->Base);
+ break;
+ }
+ }
+
+ for (i = 0; i < MESA_SHADER_TYPES; i++) {
+ if (shProg[i] != NULL)
+ shProg[i]->_Used = GL_TRUE;
+ }
+ }
+#endif
+
+ return GL_TRUE;
+}
+
+
+/*@}*/
diff --git a/mesalib/src/mesa/main/context.h b/mesalib/src/mesa/main/context.h
index bcadaea4f..160e795f7 100644
--- a/mesalib/src/mesa/main/context.h
+++ b/mesalib/src/mesa/main/context.h
@@ -99,33 +99,20 @@ _mesa_destroy_visual( struct gl_config *vis );
/** \name Context-related functions */
/*@{*/
-extern struct gl_context *
-_mesa_create_context( const struct gl_config *visual,
- struct gl_context *share_list,
- const struct dd_function_table *driverFunctions,
- void *driverContext );
-
extern GLboolean
_mesa_initialize_context( struct gl_context *ctx,
+ gl_api api,
const struct gl_config *visual,
struct gl_context *share_list,
const struct dd_function_table *driverFunctions,
void *driverContext );
extern struct gl_context *
-_mesa_create_context_for_api(gl_api api,
- const struct gl_config *visual,
- struct gl_context *share_list,
- const struct dd_function_table *driverFunctions,
- void *driverContext);
-
-extern GLboolean
-_mesa_initialize_context_for_api(struct gl_context *ctx,
- gl_api api,
- const struct gl_config *visual,
- struct gl_context *share_list,
- const struct dd_function_table *driverFunctions,
- void *driverContext);
+_mesa_create_context(gl_api api,
+ const struct gl_config *visual,
+ struct gl_context *share_list,
+ const struct dd_function_table *driverFunctions,
+ void *driverContext);
extern void
_mesa_free_context_data( struct gl_context *ctx );
diff --git a/mesalib/src/mesa/main/depth.c b/mesalib/src/mesa/main/depth.c
index fe1380e71..d666ed5fe 100644
--- a/mesalib/src/mesa/main/depth.c
+++ b/mesalib/src/mesa/main/depth.c
@@ -44,6 +44,9 @@ _mesa_ClearDepth( GLclampd depth )
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glClearDepth(%f)\n", depth);
+
depth = CLAMP( depth, 0.0, 1.0 );
if (ctx->Depth.Clear == depth)
@@ -133,6 +136,9 @@ _mesa_DepthBoundsEXT( GLclampd zmin, GLclampd zmax )
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glDepthBounds(%f, %f)\n", zmin, zmax);
+
if (zmin > zmax) {
_mesa_error(ctx, GL_INVALID_VALUE, "glDepthBoundsEXT(zmin > zmax)");
return;
diff --git a/mesalib/src/mesa/main/hint.c b/mesalib/src/mesa/main/hint.c
index 96f5f4d6b..aea0d7022 100644
--- a/mesalib/src/mesa/main/hint.c
+++ b/mesalib/src/mesa/main/hint.c
@@ -40,8 +40,9 @@ _mesa_Hint( GLenum target, GLenum mode )
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx, "glHint %s %d\n",
- _mesa_lookup_enum_by_nr(target), mode);
+ _mesa_debug(ctx, "glHint %s %s\n",
+ _mesa_lookup_enum_by_nr(target),
+ _mesa_lookup_enum_by_nr(mode));
if (mode != GL_NICEST && mode != GL_FASTEST && mode != GL_DONT_CARE) {
_mesa_error(ctx, GL_INVALID_ENUM, "glHint(mode)");
diff --git a/mesalib/src/mesa/main/lines.c b/mesalib/src/mesa/main/lines.c
index 79385cd75..1df409f45 100644
--- a/mesalib/src/mesa/main/lines.c
+++ b/mesalib/src/mesa/main/lines.c
@@ -43,6 +43,9 @@ _mesa_LineWidth( GLfloat width )
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glLineWidth %f\n", width);
+
if (width<=0.0) {
_mesa_error( ctx, GL_INVALID_VALUE, "glLineWidth" );
return;
@@ -77,6 +80,9 @@ _mesa_LineStipple( GLint factor, GLushort pattern )
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glLineStipple %d %u\n", factor, pattern);
+
factor = CLAMP( factor, 1, 256 );
if (ctx->Line.StippleFactor == factor &&
diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h
index 4e7621239..7199a05fb 100644
--- a/mesalib/src/mesa/main/mtypes.h
+++ b/mesalib/src/mesa/main/mtypes.h
@@ -1,3386 +1,3371 @@
-/*
- * 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;
-
-#define BITFIELD64_ONE 1ULL
-#define BITFIELD64_ALLONES ~0ULL
-
-/** Set a single bit */
-#define BITFIELD64_BIT(b) (BITFIELD64_ONE << (b))
-
-/** Set a mask of the least significant \c b bits */
-#define BITFIELD64_MASK(b) (((b) >= 64) ? BITFIELD64_ALLONES : \
- (BITFIELD64_BIT(b) - 1))
-
-/**
- * Set all bits from l (low bit) to h (high bit), inclusive.
- *
- * \note \C BITFIELD_64_RANGE(0, 63) return 64 set bits.
- */
-#define BITFIELD64_RANGE(l, h) (BITFIELD64_MASK((h) + 1) & ~BITFIELD64_MASK(l))
-/*@}*/
-
-
-/**
- * \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;
-
- /** GL_SGI_texture_color_table */
- GLfloat TextureColorTableScale[4]; /**< RGBA */
- GLfloat TextureColorTableBias[4]; /**< RGBA */
-};
-
-
-/**
- * Point attribute group (GL_POINT_BIT).
- */
-struct gl_point_attrib
-{
- GLboolean SmoothFlag; /**< True if GL_POINT_SMOOTH is enabled */
- GLfloat Size; /**< User-specified point size */
- GLfloat Params[3]; /**< GL_EXT_point_parameters */
- GLfloat MinSize, MaxSize; /**< GL_EXT_point_parameters */
- GLfloat Threshold; /**< GL_EXT_point_parameters */
- GLboolean _Attenuated; /**< True if Params != [1, 0, 0] */
- GLboolean PointSprite; /**< GL_NV/ARB_point_sprite */
- GLboolean CoordReplace[MAX_TEXTURE_COORD_UNITS]; /**< GL_ARB_point_sprite*/
- GLenum SpriteRMode; /**< GL_NV_point_sprite (only!) */
- GLenum SpriteOrigin; /**< GL_ARB_point_sprite */
-};
-
-
-/**
- * Polygon attribute group (GL_POLYGON_BIT).
- */
-struct gl_polygon_attrib
-{
- GLenum FrontFace; /**< Either GL_CW or GL_CCW */
- GLenum FrontMode; /**< Either GL_POINT, GL_LINE or GL_FILL */
- GLenum BackMode; /**< Either GL_POINT, GL_LINE or GL_FILL */
- GLboolean _FrontBit; /**< 0=GL_CCW, 1=GL_CW */
- GLboolean CullFlag; /**< Culling on/off flag */
- GLboolean SmoothFlag; /**< True if GL_POLYGON_SMOOTH is enabled */
- GLboolean StippleFlag; /**< True if GL_POLYGON_STIPPLE is enabled */
- GLenum CullFaceMode; /**< Culling mode GL_FRONT or GL_BACK */
- GLfloat OffsetFactor; /**< Polygon offset factor, from user */
- GLfloat OffsetUnits; /**< Polygon offset units, from user */
- GLboolean OffsetPoint; /**< Offset in GL_POINT mode */
- GLboolean OffsetLine; /**< Offset in GL_LINE mode */
- GLboolean OffsetFill; /**< Offset in GL_FILL mode */
-};
-
-
-/**
- * Scissor attributes (GL_SCISSOR_BIT).
- */
-struct gl_scissor_attrib
-{
- GLboolean Enabled; /**< Scissor test enabled? */
- GLint X, Y; /**< Lower left corner of box */
- GLsizei Width, Height; /**< Size of box */
-};
-
-
-/**
- * Stencil attribute group (GL_STENCIL_BUFFER_BIT).
- *
- * Three sets of stencil data are tracked so that OpenGL 2.0,
- * GL_EXT_stencil_two_side, and GL_ATI_separate_stencil can all be supported
- * simultaneously. In each of the stencil state arrays, element 0 corresponds
- * to GL_FRONT. Element 1 corresponds to the OpenGL 2.0 /
- * GL_ATI_separate_stencil GL_BACK state. Element 2 corresponds to the
- * GL_EXT_stencil_two_side GL_BACK state.
- *
- * The derived value \c _BackFace is either 1 or 2 depending on whether or
- * not GL_STENCIL_TEST_TWO_SIDE_EXT is enabled.
- *
- * The derived value \c _TestTwoSide is set when the front-face and back-face
- * stencil state are different.
- */
-struct gl_stencil_attrib
-{
- GLboolean Enabled; /**< Enabled flag */
- GLboolean TestTwoSide; /**< GL_EXT_stencil_two_side */
- GLubyte ActiveFace; /**< GL_EXT_stencil_two_side (0 or 2) */
- GLboolean _Enabled; /**< Enabled and stencil buffer present */
- GLboolean _TestTwoSide;
- GLubyte _BackFace; /**< Current back stencil state (1 or 2) */
- GLenum Function[3]; /**< Stencil function */
- GLenum FailFunc[3]; /**< Fail function */
- GLenum ZPassFunc[3]; /**< Depth buffer pass function */
- GLenum ZFailFunc[3]; /**< Depth buffer fail function */
- GLint Ref[3]; /**< Reference value */
- GLuint ValueMask[3]; /**< Value mask */
- GLuint WriteMask[3]; /**< Write mask */
- GLuint Clear; /**< Clear value */
-};
-
-
-/**
- * An index for each type of texture object. These correspond to the GL
- * texture target enums, such as GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP, etc.
- * Note: the order is from highest priority to lowest priority.
- */
-typedef enum
-{
- TEXTURE_2D_ARRAY_INDEX,
- TEXTURE_1D_ARRAY_INDEX,
- TEXTURE_CUBE_INDEX,
- TEXTURE_3D_INDEX,
- TEXTURE_RECT_INDEX,
- TEXTURE_2D_INDEX,
- TEXTURE_1D_INDEX,
- NUM_TEXTURE_TARGETS
-} gl_texture_index;
-
-
-/**
- * Bit flags for each type of texture object
- * Used for Texture.Unit[]._ReallyEnabled flags.
- */
-/*@{*/
-#define TEXTURE_2D_ARRAY_BIT (1 << TEXTURE_2D_ARRAY_INDEX)
-#define TEXTURE_1D_ARRAY_BIT (1 << TEXTURE_1D_ARRAY_INDEX)
-#define TEXTURE_CUBE_BIT (1 << TEXTURE_CUBE_INDEX)
-#define TEXTURE_3D_BIT (1 << TEXTURE_3D_INDEX)
-#define TEXTURE_RECT_BIT (1 << TEXTURE_RECT_INDEX)
-#define TEXTURE_2D_BIT (1 << TEXTURE_2D_INDEX)
-#define TEXTURE_1D_BIT (1 << TEXTURE_1D_INDEX)
-/*@}*/
-
-
-/**
- * TexGenEnabled flags.
- */
-/*@{*/
-#define S_BIT 1
-#define T_BIT 2
-#define R_BIT 4
-#define Q_BIT 8
-#define STR_BITS (S_BIT | T_BIT | R_BIT)
-/*@}*/
-
-
-/**
- * Bit flag versions of the corresponding GL_ constants.
- */
-/*@{*/
-#define TEXGEN_SPHERE_MAP 0x1
-#define TEXGEN_OBJ_LINEAR 0x2
-#define TEXGEN_EYE_LINEAR 0x4
-#define TEXGEN_REFLECTION_MAP_NV 0x8
-#define TEXGEN_NORMAL_MAP_NV 0x10
-
-#define TEXGEN_NEED_NORMALS (TEXGEN_SPHERE_MAP | \
- TEXGEN_REFLECTION_MAP_NV | \
- TEXGEN_NORMAL_MAP_NV)
-#define TEXGEN_NEED_EYE_COORD (TEXGEN_SPHERE_MAP | \
- TEXGEN_REFLECTION_MAP_NV | \
- TEXGEN_NORMAL_MAP_NV | \
- TEXGEN_EYE_LINEAR)
-/*@}*/
-
-
-
-/** Tex-gen enabled for texture unit? */
-#define ENABLE_TEXGEN(unit) (1 << (unit))
-
-/** Non-identity texture matrix for texture unit? */
-#define ENABLE_TEXMAT(unit) (1 << (unit))
-
-
-/**
- * Texel fetch function prototype. We use texel fetch functions to
- * extract RGBA, color indexes and depth components out of 1D, 2D and 3D
- * texture images. These functions help to isolate us from the gritty
- * details of all the various texture image encodings.
- *
- * \param texImage texture image.
- * \param col texel column.
- * \param row texel row.
- * \param img texel image level/layer.
- * \param texelOut output texel (up to 4 GLchans)
- */
-typedef void (*FetchTexelFuncC)( const struct gl_texture_image *texImage,
- GLint col, GLint row, GLint img,
- GLchan *texelOut );
-
-/**
- * As above, but returns floats.
- * Used for depth component images and for upcoming signed/float
- * texture images.
- */
-typedef void (*FetchTexelFuncF)( const struct gl_texture_image *texImage,
- GLint col, GLint row, GLint img,
- GLfloat *texelOut );
-
-
-typedef void (*StoreTexelFunc)(struct gl_texture_image *texImage,
- GLint col, GLint row, GLint img,
- const void *texel);
-
-
-/**
- * Texture image state. Describes the dimensions of a texture image,
- * the texel format and pointers to Texel Fetch functions.
- */
-struct gl_texture_image
-{
- GLint InternalFormat; /**< Internal format as given by the user */
- GLenum _BaseFormat; /**< Either GL_RGB, GL_RGBA, GL_ALPHA,
- * GL_LUMINANCE, GL_LUMINANCE_ALPHA,
- * GL_INTENSITY, GL_COLOR_INDEX,
- * GL_DEPTH_COMPONENT or GL_DEPTH_STENCIL_EXT
- * only. Used for choosing TexEnv arithmetic.
- */
- GLuint TexFormat; /**< The actual format: MESA_FORMAT_x */
-
- GLuint Border; /**< 0 or 1 */
- GLuint Width; /**< = 2^WidthLog2 + 2*Border */
- GLuint Height; /**< = 2^HeightLog2 + 2*Border */
- GLuint Depth; /**< = 2^DepthLog2 + 2*Border */
- GLuint Width2; /**< = Width - 2*Border */
- GLuint Height2; /**< = Height - 2*Border */
- GLuint Depth2; /**< = Depth - 2*Border */
- GLuint WidthLog2; /**< = log2(Width2) */
- GLuint HeightLog2; /**< = log2(Height2) */
- GLuint DepthLog2; /**< = log2(Depth2) */
- GLuint MaxLog2; /**< = MAX(WidthLog2, HeightLog2) */
- GLfloat WidthScale; /**< used for mipmap LOD computation */
- GLfloat HeightScale; /**< used for mipmap LOD computation */
- GLfloat DepthScale; /**< used for mipmap LOD computation */
- GLboolean IsClientData; /**< Data owned by client? */
- GLboolean _IsPowerOfTwo; /**< Are all dimensions powers of two? */
-
- struct gl_texture_object *TexObject; /**< Pointer back to parent object */
-
- FetchTexelFuncC FetchTexelc; /**< GLchan texel fetch function pointer */
- FetchTexelFuncF FetchTexelf; /**< Float texel fetch function pointer */
-
- GLuint RowStride; /**< Padded width in units of texels */
- GLuint *ImageOffsets; /**< if 3D texture: array [Depth] of offsets to
- each 2D slice in 'Data', in texels */
- GLvoid *Data; /**< Image data, accessed via FetchTexel() */
-
- /**
- * \name For device driver:
- */
- /*@{*/
- void *DriverData; /**< Arbitrary device driver data */
- /*@}*/
-};
-
-
-/**
- * Indexes for cube map faces.
- */
-typedef enum
-{
- FACE_POS_X = 0,
- FACE_NEG_X = 1,
- FACE_POS_Y = 2,
- FACE_NEG_Y = 3,
- FACE_POS_Z = 4,
- FACE_NEG_Z = 5,
- MAX_FACES = 6
-} gl_face_index;
-
-
-/**
- * Texture object state. Contains the array of mipmap images, border color,
- * wrap modes, filter modes, shadow/texcompare state, and the per-texture
- * color palette.
- */
-struct gl_texture_object
-{
- _glthread_Mutex Mutex; /**< for thread safety */
- GLint RefCount; /**< reference count */
- GLuint Name; /**< the user-visible texture object ID */
- GLenum Target; /**< GL_TEXTURE_1D, GL_TEXTURE_2D, etc. */
- GLfloat Priority; /**< in [0,1] */
- union {
- GLfloat f[4];
- GLuint ui[4];
- GLint i[4];
- } BorderColor; /**< Interpreted according to texture format */
- GLenum WrapS; /**< S-axis texture image wrap mode */
- GLenum WrapT; /**< T-axis texture image wrap mode */
- GLenum WrapR; /**< R-axis texture image wrap mode */
- GLenum MinFilter; /**< minification filter */
- GLenum MagFilter; /**< magnification filter */
- GLfloat MinLod; /**< min lambda, OpenGL 1.2 */
- GLfloat MaxLod; /**< max lambda, OpenGL 1.2 */
- GLfloat LodBias; /**< OpenGL 1.4 */
- GLint BaseLevel; /**< min mipmap level, OpenGL 1.2 */
- GLint MaxLevel; /**< max mipmap level, OpenGL 1.2 */
- GLfloat MaxAnisotropy; /**< GL_EXT_texture_filter_anisotropic */
- GLenum CompareMode; /**< GL_ARB_shadow */
- GLenum CompareFunc; /**< GL_ARB_shadow */
- GLfloat CompareFailValue; /**< GL_ARB_shadow_ambient */
- GLenum DepthMode; /**< GL_ARB_depth_texture */
- GLint _MaxLevel; /**< actual max mipmap level (q in the spec) */
- GLfloat _MaxLambda; /**< = _MaxLevel - BaseLevel (q - b in spec) */
- GLint CropRect[4]; /**< GL_OES_draw_texture */
- GLenum Swizzle[4]; /**< GL_EXT_texture_swizzle */
- GLuint _Swizzle; /**< same as Swizzle, but SWIZZLE_* format */
- GLboolean GenerateMipmap; /**< GL_SGIS_generate_mipmap */
- GLboolean _Complete; /**< Is texture object complete? */
- GLboolean _RenderToTexture; /**< Any rendering to this texture? */
- GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */
- GLenum sRGBDecode; /**< GL_DECODE_EXT or GL_SKIP_DECODE_EXT */
-
- /** Actual texture images, indexed by [cube face] and [mipmap level] */
- struct gl_texture_image *Image[MAX_FACES][MAX_TEXTURE_LEVELS];
-
- /** GL_EXT_paletted_texture */
- struct gl_color_table Palette;
-
- /**
- * \name For device driver.
- * Note: instead of attaching driver data to this pointer, it's preferable
- * to instead use this struct as a base class for your own texture object
- * class. Driver->NewTextureObject() can be used to implement the
- * allocation.
- */
- void *DriverData; /**< Arbitrary device driver data */
-};
-
-
-/** Up to four combiner sources are possible with GL_NV_texture_env_combine4 */
-#define MAX_COMBINER_TERMS 4
-
-
-/**
- * Texture combine environment state.
- */
-struct gl_tex_env_combine_state
-{
- GLenum ModeRGB; /**< GL_REPLACE, GL_DECAL, GL_ADD, etc. */
- GLenum ModeA; /**< GL_REPLACE, GL_DECAL, GL_ADD, etc. */
- /** Source terms: GL_PRIMARY_COLOR, GL_TEXTURE, etc */
- GLenum SourceRGB[MAX_COMBINER_TERMS];
- GLenum SourceA[MAX_COMBINER_TERMS];
- /** Source operands: GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, etc */
- GLenum OperandRGB[MAX_COMBINER_TERMS];
- GLenum OperandA[MAX_COMBINER_TERMS];
- GLuint ScaleShiftRGB; /**< 0, 1 or 2 */
- GLuint ScaleShiftA; /**< 0, 1 or 2 */
- GLuint _NumArgsRGB; /**< Number of inputs used for the RGB combiner */
- GLuint _NumArgsA; /**< Number of inputs used for the A combiner */
-};
-
-
-/**
- * Texture coord generation state.
- */
-struct gl_texgen
-{
- GLenum Mode; /**< GL_EYE_LINEAR, GL_SPHERE_MAP, etc */
- GLbitfield _ModeBit; /**< TEXGEN_x bit corresponding to Mode */
- GLfloat ObjectPlane[4];
- GLfloat EyePlane[4];
-};
-
-
-/**
- * Texture unit state. Contains enable flags, texture environment/function/
- * combiners, texgen state, pointers to current texture objects and
- * post-filter color tables.
- */
-struct gl_texture_unit
-{
- GLbitfield Enabled; /**< bitmask of TEXTURE_*_BIT flags */
- GLbitfield _ReallyEnabled; /**< 0 or exactly one of TEXTURE_*_BIT flags */
-
- GLenum EnvMode; /**< GL_MODULATE, GL_DECAL, GL_BLEND, etc. */
- GLfloat EnvColor[4];
-
- struct gl_texgen GenS;
- struct gl_texgen GenT;
- struct gl_texgen GenR;
- struct gl_texgen GenQ;
- GLbitfield TexGenEnabled; /**< Bitwise-OR of [STRQ]_BIT values */
- GLbitfield _GenFlags; /**< Bitwise-OR of Gen[STRQ]._ModeBit */
-
- GLfloat LodBias; /**< for biasing mipmap levels */
- GLenum BumpTarget;
- GLfloat RotMatrix[4]; /* 2x2 matrix */
-
- /**
- * \name GL_EXT_texture_env_combine
- */
- struct gl_tex_env_combine_state Combine;
-
- /**
- * Derived state based on \c EnvMode and the \c BaseFormat of the
- * currently enabled texture.
- */
- struct gl_tex_env_combine_state _EnvMode;
-
- /**
- * Currently enabled combiner state. This will point to either
- * \c Combine or \c _EnvMode.
- */
- struct gl_tex_env_combine_state *_CurrentCombine;
-
- /** Current texture object pointers */
- struct gl_texture_object *CurrentTex[NUM_TEXTURE_TARGETS];
-
- /** Points to highest priority, complete and enabled texture object */
- struct gl_texture_object *_Current;
-
- /** GL_SGI_texture_color_table */
- /*@{*/
- struct gl_color_table ColorTable;
- struct gl_color_table ProxyColorTable;
- GLboolean ColorTableEnabled;
- /*@}*/
-};
-
-
-/**
- * Texture attribute group (GL_TEXTURE_BIT).
- */
-struct gl_texture_attrib
-{
- GLuint CurrentUnit; /**< GL_ACTIVE_TEXTURE */
- struct gl_texture_unit Unit[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
-
- struct gl_texture_object *ProxyTex[NUM_TEXTURE_TARGETS];
-
- /** GL_ARB_seamless_cubemap */
- GLboolean CubeMapSeamless;
-
- /** GL_EXT_shared_texture_palette */
- GLboolean SharedPalette;
- struct gl_color_table Palette;
-
- /** Texture units/samplers used by vertex or fragment texturing */
- GLbitfield _EnabledUnits;
-
- /** Texture coord units/sets used for fragment texturing */
- GLbitfield _EnabledCoordUnits;
-
- /** Texture coord units that have texgen enabled */
- GLbitfield _TexGenEnabled;
-
- /** Texture coord units that have non-identity matrices */
- GLbitfield _TexMatEnabled;
-
- /** Bitwise-OR of all Texture.Unit[i]._GenFlags */
- GLbitfield _GenFlags;
-};
-
-
-/**
- * Transformation attribute group (GL_TRANSFORM_BIT).
- */
-struct gl_transform_attrib
-{
- GLenum MatrixMode; /**< Matrix mode */
- GLfloat EyeUserPlane[MAX_CLIP_PLANES][4]; /**< User clip planes */
- GLfloat _ClipUserPlane[MAX_CLIP_PLANES][4]; /**< derived */
- GLbitfield ClipPlanesEnabled; /**< on/off bitmask */
- GLboolean Normalize; /**< Normalize all normals? */
- GLboolean RescaleNormals; /**< GL_EXT_rescale_normal */
- GLboolean RasterPositionUnclipped; /**< GL_IBM_rasterpos_clip */
- GLboolean DepthClamp; /**< GL_ARB_depth_clamp */
-
- GLfloat CullEyePos[4];
- GLfloat CullObjPos[4];
-};
-
-
-/**
- * Viewport attribute group (GL_VIEWPORT_BIT).
- */
-struct gl_viewport_attrib
-{
- GLint X, Y; /**< position */
- GLsizei Width, Height; /**< size */
- GLfloat Near, Far; /**< Depth buffer range */
- GLmatrix _WindowMap; /**< Mapping transformation as a matrix. */
-};
-
-
-/**
- * GL_ARB_vertex/pixel_buffer_object buffer object
- */
-struct gl_buffer_object
-{
- _glthread_Mutex Mutex;
- GLint RefCount;
- GLuint Name;
- GLenum Usage; /**< GL_STREAM_DRAW_ARB, GL_STREAM_READ_ARB, etc. */
- GLsizeiptrARB Size; /**< Size of buffer storage in bytes */
- GLubyte *Data; /**< Location of storage either in RAM or VRAM. */
- /** Fields describing a mapped buffer */
- /*@{*/
- GLbitfield AccessFlags; /**< Mask of GL_MAP_x_BIT flags */
- GLvoid *Pointer; /**< User-space address of mapping */
- GLintptr Offset; /**< Mapped offset */
- GLsizeiptr Length; /**< Mapped length */
- /*@}*/
- GLboolean Written; /**< Ever written to? (for debugging) */
- GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */
-};
-
-
-/**
- * Client pixel packing/unpacking attributes
- */
-struct gl_pixelstore_attrib
-{
- GLint Alignment;
- GLint RowLength;
- GLint SkipPixels;
- GLint SkipRows;
- GLint ImageHeight;
- GLint SkipImages;
- GLboolean SwapBytes;
- GLboolean LsbFirst;
- GLboolean ClientStorage; /**< GL_APPLE_client_storage */
- GLboolean Invert; /**< GL_MESA_pack_invert */
- struct gl_buffer_object *BufferObj; /**< GL_ARB_pixel_buffer_object */
-};
-
-
-/**
- * Client vertex array attributes
- */
-struct gl_client_array
-{
- GLint Size; /**< components per element (1,2,3,4) */
- GLenum Type; /**< datatype: GL_FLOAT, GL_INT, etc */
- GLenum Format; /**< default: GL_RGBA, but may be GL_BGRA */
- GLsizei Stride; /**< user-specified stride */
- GLsizei StrideB; /**< actual stride in bytes */
- const GLubyte *Ptr; /**< Points to array data */
- GLboolean Enabled; /**< Enabled flag is a boolean */
- GLboolean Normalized; /**< GL_ARB_vertex_program */
- GLboolean Integer; /**< Integer-valued? */
- GLuint InstanceDivisor; /**< GL_ARB_instanced_arrays */
- GLuint _ElementSize; /**< size of each element in bytes */
-
- struct gl_buffer_object *BufferObj;/**< GL_ARB_vertex_buffer_object */
- GLuint _MaxElement; /**< max element index into array buffer + 1 */
-};
-
-
-/**
- * Collection of vertex arrays. Defined by the GL_APPLE_vertex_array_object
- * extension, but a nice encapsulation in any case.
- */
-struct gl_array_object
-{
- /** Name of the array object as received from glGenVertexArrayAPPLE. */
- GLuint Name;
-
- GLint RefCount;
- _glthread_Mutex Mutex;
- GLboolean VBOonly; /**< require all arrays to live in VBOs? */
-
- /** Conventional vertex arrays */
- /*@{*/
- struct gl_client_array Vertex;
- struct gl_client_array Weight;
- struct gl_client_array Normal;
- struct gl_client_array Color;
- struct gl_client_array SecondaryColor;
- struct gl_client_array FogCoord;
- struct gl_client_array Index;
- struct gl_client_array EdgeFlag;
- struct gl_client_array TexCoord[MAX_TEXTURE_COORD_UNITS];
- struct gl_client_array PointSize;
- /*@}*/
-
- /**
- * Generic arrays for vertex programs/shaders.
- * For NV vertex programs, these attributes alias and take priority
- * over the conventional attribs above. For ARB vertex programs and
- * GLSL vertex shaders, these attributes are separate.
- */
- struct gl_client_array VertexAttrib[MAX_VERTEX_GENERIC_ATTRIBS];
-
- /** Mask of _NEW_ARRAY_* values indicating which arrays are enabled */
- GLbitfield _Enabled;
-
- /**
- * Min of all enabled arrays' _MaxElement. When arrays reside inside VBOs
- * we can determine the max legal (in bounds) glDrawElements array index.
- */
- GLuint _MaxElement;
-};
-
-
-/**
- * Vertex array state
- */
-struct gl_array_attrib
-{
- /** Currently bound array object. See _mesa_BindVertexArrayAPPLE() */
- struct gl_array_object *ArrayObj;
-
- /** The default vertex array object */
- struct gl_array_object *DefaultArrayObj;
-
- /** Array objects (GL_ARB/APPLE_vertex_array_object) */
- struct _mesa_HashTable *Objects;
-
- GLint ActiveTexture; /**< Client Active Texture */
- GLuint LockFirst; /**< GL_EXT_compiled_vertex_array */
- GLuint LockCount; /**< GL_EXT_compiled_vertex_array */
-
- /** GL 3.1 (slightly different from GL_NV_primitive_restart) */
- GLboolean PrimitiveRestart;
- GLuint RestartIndex;
-
- GLbitfield NewState; /**< mask of _NEW_ARRAY_* values */
-
- /* 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;
- GLboolean Main; /**< shader defines main() */
- GLboolean UnresolvedRefs;
- 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. */
- GLuint Format; /**< The actual format: MESA_FORMAT_x */
-
- GLubyte NumSamples;
-
- GLenum DataType; /**< Type of values passed to the Get/Put functions */
- GLvoid *Data; /**< This may not be used by some kinds of RBs */
-
- /* Used to wrap one renderbuffer around another: */
- struct gl_renderbuffer *Wrapped;
-
- /* Delete this renderbuffer */
- void (*Delete)(struct gl_renderbuffer *rb);
-
- /* Allocate new storage for this renderbuffer */
- GLboolean (*AllocStorage)(struct gl_context *ctx, struct gl_renderbuffer *rb,
- GLenum internalFormat,
- GLuint width, GLuint height);
-
- /* Lock/Unlock are called before/after calling the Get/Put functions.
- * Not sure this is the right place for these yet.
- void (*Lock)(struct gl_context *ctx, struct gl_renderbuffer *rb);
- void (*Unlock)(struct gl_context *ctx, struct gl_renderbuffer *rb);
- */
-
- /* Return a pointer to the element/pixel at (x,y).
- * Should return NULL if the buffer memory can't be directly addressed.
- */
- void *(*GetPointer)(struct gl_context *ctx, struct gl_renderbuffer *rb,
- GLint x, GLint y);
-
- /* Get/Read a row of values.
- * The values will be of format _BaseFormat and type DataType.
- */
- void (*GetRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
- GLint x, GLint y, void *values);
-
- /* Get/Read values at arbitrary locations.
- * The values will be of format _BaseFormat and type DataType.
- */
- void (*GetValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
- const GLint x[], const GLint y[], void *values);
-
- /* Put/Write a row of values.
- * The values will be of format _BaseFormat and type DataType.
- */
- void (*PutRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
- GLint x, GLint y, const void *values, const GLubyte *mask);
-
- /* Put/Write a row of RGB values. This is a special-case routine that's
- * only used for RGBA renderbuffers when the source data is GL_RGB. That's
- * a common case for glDrawPixels and some triangle routines.
- * The values will be of format GL_RGB and type DataType.
- */
- void (*PutRowRGB)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
- GLint x, GLint y, const void *values, const GLubyte *mask);
-
-
- /* Put/Write a row of identical values.
- * The values will be of format _BaseFormat and type DataType.
- */
- void (*PutMonoRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
- GLint x, GLint y, const void *value, const GLubyte *mask);
-
- /* Put/Write values at arbitrary locations.
- * The values will be of format _BaseFormat and type DataType.
- */
- void (*PutValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
- const GLint x[], const GLint y[], const void *values,
- const GLubyte *mask);
- /* Put/Write identical values at arbitrary locations.
- * The values will be of format _BaseFormat and type DataType.
- */
- void (*PutMonoValues)(struct gl_context *ctx, struct gl_renderbuffer *rb,
- GLuint count, const GLint x[], const GLint y[],
- const void *value, const GLubyte *mask);
-};
-
-
-/**
- * A renderbuffer attachment points to either a texture object (and specifies
- * a mipmap level, cube face or 3D texture slice) or points to a renderbuffer.
- */
-struct gl_renderbuffer_attachment
-{
- GLenum Type; /**< \c GL_NONE or \c GL_TEXTURE or \c GL_RENDERBUFFER_EXT */
- GLboolean Complete;
-
- /**
- * If \c Type is \c GL_RENDERBUFFER_EXT, this stores a pointer to the
- * application supplied renderbuffer object.
- */
- struct gl_renderbuffer *Renderbuffer;
-
- /**
- * If \c Type is \c GL_TEXTURE, this stores a pointer to the application
- * supplied texture object.
- */
- struct gl_texture_object *Texture;
- GLuint TextureLevel; /**< Attached mipmap level. */
- GLuint CubeMapFace; /**< 0 .. 5, for cube map textures. */
- GLuint Zoffset; /**< Slice for 3D textures, or layer for both 1D
- * and 2D array textures */
-};
-
-
-/**
- * A framebuffer is a collection of renderbuffers (color, depth, stencil, etc).
- * In C++ terms, think of this as a base class from which device drivers
- * will make derived classes.
- */
-struct gl_framebuffer
-{
- _glthread_Mutex Mutex; /**< for thread safety */
- /**
- * If zero, this is a window system framebuffer. If non-zero, this
- * is a FBO framebuffer; note that for some devices (i.e. those with
- * a natural pixel coordinate system for FBOs that differs from the
- * OpenGL/Mesa coordinate system), this means that the viewport,
- * polygon face orientation, and polygon stipple will have to be inverted.
- */
- GLuint Name;
-
- GLint RefCount;
- GLboolean DeletePending;
-
- /**
- * The framebuffer's visual. Immutable if this is a window system buffer.
- * Computed from attachments if user-made FBO.
- */
- struct gl_config Visual;
-
- GLboolean Initialized;
-
- GLuint Width, Height; /**< size of frame buffer in pixels */
-
- /** \name Drawing bounds (Intersection of buffer size and scissor box) */
- /*@{*/
- GLint _Xmin, _Xmax; /**< inclusive */
- GLint _Ymin, _Ymax; /**< exclusive */
- /*@}*/
-
- /** \name Derived Z buffer stuff */
- /*@{*/
- GLuint _DepthMax; /**< Max depth buffer value */
- GLfloat _DepthMaxF; /**< Float max depth buffer value */
- GLfloat _MRD; /**< minimum resolvable difference in Z values */
- /*@}*/
-
- /** One of the GL_FRAMEBUFFER_(IN)COMPLETE_* tokens */
- GLenum _Status;
-
- /** Integer color values */
- GLboolean _IntegerColor;
-
- /** Array of all renderbuffer attachments, indexed by BUFFER_* tokens. */
- struct gl_renderbuffer_attachment Attachment[BUFFER_COUNT];
-
- /* In unextended OpenGL these vars are part of the GL_COLOR_BUFFER
- * attribute group and GL_PIXEL attribute group, respectively.
- */
- GLenum ColorDrawBuffer[MAX_DRAW_BUFFERS];
- GLenum ColorReadBuffer;
-
- /** Computed from ColorDraw/ReadBuffer above */
- GLuint _NumColorDrawBuffers;
- GLint _ColorDrawBufferIndexes[MAX_DRAW_BUFFERS]; /**< BUFFER_x or -1 */
- GLint _ColorReadBufferIndex; /* -1 = None */
- struct gl_renderbuffer *_ColorDrawBuffers[MAX_DRAW_BUFFERS];
- struct gl_renderbuffer *_ColorReadBuffer;
-
- /** The Actual depth/stencil buffers to use. May be wrappers around the
- * depth/stencil buffers attached above. */
- struct gl_renderbuffer *_DepthBuffer;
- struct gl_renderbuffer *_StencilBuffer;
-
- /** Delete this framebuffer */
- void (*Delete)(struct gl_framebuffer *fb);
-};
-
-
-/**
- * Precision info for shader datatypes. See glGetShaderPrecisionFormat().
- */
-struct gl_precision
-{
- GLushort RangeMin; /**< min value exponent */
- GLushort RangeMax; /**< max value exponent */
- GLushort Precision; /**< number of mantissa bits */
-};
-
-
-/**
- * Limits for vertex and fragment programs/shaders.
- */
-struct gl_program_constants
-{
- /* logical limits */
- GLuint MaxInstructions;
- GLuint MaxAluInstructions;
- GLuint MaxTexInstructions;
- GLuint MaxTexIndirections;
- GLuint MaxAttribs;
- GLuint MaxTemps;
- GLuint MaxAddressRegs;
- GLuint MaxParameters;
- GLuint MaxLocalParams;
- GLuint MaxEnvParams;
- /* native/hardware limits */
- GLuint MaxNativeInstructions;
- GLuint MaxNativeAluInstructions;
- GLuint MaxNativeTexInstructions;
- GLuint MaxNativeTexIndirections;
- GLuint MaxNativeAttribs;
- GLuint MaxNativeTemps;
- GLuint MaxNativeAddressRegs;
- GLuint MaxNativeParameters;
- /* For shaders */
- GLuint MaxUniformComponents;
- /* GL_ARB_geometry_shader4 */
- GLuint MaxGeometryTextureImageUnits;
- GLuint MaxGeometryVaryingComponents;
- GLuint MaxVertexVaryingComponents;
- GLuint MaxGeometryUniformComponents;
- GLuint MaxGeometryOutputVertices;
- GLuint MaxGeometryTotalOutputComponents;
- /* ES 2.0 and GL_ARB_ES2_compatibility */
- struct gl_precision LowFloat, MediumFloat, HighFloat;
- struct gl_precision LowInt, MediumInt, HighInt;
-};
-
-
-/**
- * Constants which may be overridden by device driver during context creation
- * but are never changed after that.
- */
-struct gl_constants
-{
- GLint MaxTextureMbytes; /**< Max memory per image, in MB */
- GLint MaxTextureLevels; /**< Max mipmap levels. */
- GLint Max3DTextureLevels; /**< Max mipmap levels for 3D textures */
- GLint MaxCubeTextureLevels; /**< Max mipmap levels for cube textures */
- GLint MaxArrayTextureLayers; /**< Max layers in array textures */
- GLint MaxTextureRectSize; /**< Max rectangle texture size, in pixes */
- GLuint MaxTextureCoordUnits;
- GLuint MaxTextureImageUnits;
- GLuint MaxVertexTextureImageUnits;
- GLuint MaxCombinedTextureImageUnits;
- GLuint MaxTextureUnits; /**< = MIN(CoordUnits, ImageUnits) */
- GLfloat MaxTextureMaxAnisotropy; /**< GL_EXT_texture_filter_anisotropic */
- GLfloat MaxTextureLodBias; /**< GL_EXT_texture_lod_bias */
-
- GLuint MaxArrayLockSize;
-
- GLint SubPixelBits;
-
- GLfloat MinPointSize, MaxPointSize; /**< aliased */
- GLfloat MinPointSizeAA, MaxPointSizeAA; /**< antialiased */
- GLfloat PointSizeGranularity;
- GLfloat MinLineWidth, MaxLineWidth; /**< aliased */
- GLfloat MinLineWidthAA, MaxLineWidthAA; /**< antialiased */
- GLfloat LineWidthGranularity;
-
- GLuint MaxColorTableSize;
-
- GLuint MaxClipPlanes;
- GLuint MaxLights;
- GLfloat MaxShininess; /**< GL_NV_light_max_exponent */
- GLfloat MaxSpotExponent; /**< GL_NV_light_max_exponent */
-
- GLuint MaxViewportWidth, MaxViewportHeight;
-
- struct gl_program_constants VertexProgram; /**< GL_ARB_vertex_program */
- struct gl_program_constants FragmentProgram; /**< GL_ARB_fragment_program */
- struct gl_program_constants GeometryProgram; /**< GL_ARB_geometry_shader4 */
- GLuint MaxProgramMatrices;
- GLuint MaxProgramMatrixStackDepth;
-
- /** vertex array / buffer object bounds checking */
- GLboolean CheckArrayBounds;
-
- GLuint MaxDrawBuffers; /**< GL_ARB_draw_buffers */
-
- GLuint MaxColorAttachments; /**< GL_EXT_framebuffer_object */
- GLuint MaxRenderbufferSize; /**< GL_EXT_framebuffer_object */
- GLuint MaxSamples; /**< GL_ARB_framebuffer_object */
-
- GLuint MaxVarying; /**< Number of float[4] varying parameters */
-
- GLuint GLSLVersion; /**< GLSL version supported (ex: 120 = 1.20) */
-
- /** Which texture units support GL_ATI_envmap_bumpmap as targets */
- GLbitfield SupportedBumpUnits;
-
- /**
- * Maximum amount of time, measured in nanseconds, that the server can wait.
- */
- GLuint64 MaxServerWaitTimeout;
-
- /** GL_EXT_provoking_vertex */
- GLboolean QuadsFollowProvokingVertexConvention;
-
- /** OpenGL version 3.0 */
- GLbitfield ContextFlags; /**< Ex: GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT */
-
- /** OpenGL version 3.2 */
- GLbitfield ProfileMask; /**< Mask of CONTEXT_x_PROFILE_BIT */
-
- /** GL_EXT_transform_feedback */
- GLuint MaxTransformFeedbackSeparateAttribs;
- GLuint MaxTransformFeedbackSeparateComponents;
- GLuint MaxTransformFeedbackInterleavedComponents;
-
- /** GL_EXT_gpu_shader4 */
- GLint MinProgramTexelOffset, MaxProgramTexelOffset;
-
- /* GL_EXT_framebuffer_sRGB */
- GLboolean sRGBCapable; /* can enable sRGB blend/update on FBOs */
-};
-
-
-/**
- * Enable flag for each OpenGL extension. Different device drivers will
- * enable different extensions at runtime.
- */
-struct gl_extensions
-{
- GLboolean dummy; /* don't remove this! */
- GLboolean dummy_true; /* Set true by _mesa_init_extensions(). */
- GLboolean dummy_false; /* Set false by _mesa_init_extensions(). */
- GLboolean ARB_ES2_compatibility;
- GLboolean ARB_blend_func_extended;
- GLboolean ARB_copy_buffer;
- GLboolean ARB_depth_buffer_float;
- GLboolean ARB_depth_clamp;
- GLboolean ARB_depth_texture;
- GLboolean ARB_draw_buffers;
- GLboolean ARB_draw_buffers_blend;
- GLboolean ARB_draw_elements_base_vertex;
- GLboolean ARB_draw_instanced;
- GLboolean ARB_fragment_coord_conventions;
- GLboolean ARB_fragment_program;
- GLboolean ARB_fragment_program_shadow;
- GLboolean ARB_fragment_shader;
- GLboolean ARB_framebuffer_object;
- GLboolean ARB_explicit_attrib_location;
- GLboolean ARB_geometry_shader4;
- GLboolean ARB_half_float_pixel;
- GLboolean ARB_half_float_vertex;
- GLboolean ARB_instanced_arrays;
- GLboolean ARB_map_buffer_range;
- GLboolean ARB_multisample;
- GLboolean ARB_multitexture;
- GLboolean ARB_occlusion_query;
- GLboolean ARB_occlusion_query2;
- GLboolean ARB_point_sprite;
- GLboolean ARB_sampler_objects;
- GLboolean ARB_seamless_cube_map;
- GLboolean ARB_shader_objects;
- GLboolean ARB_shader_stencil_export;
- GLboolean ARB_shading_language_100;
- GLboolean ARB_shadow;
- GLboolean ARB_shadow_ambient;
- GLboolean ARB_sync;
- GLboolean ARB_texture_border_clamp;
- GLboolean ARB_texture_buffer_object;
- GLboolean ARB_texture_compression;
- GLboolean ARB_texture_compression_rgtc;
- GLboolean ARB_texture_cube_map;
- GLboolean ARB_texture_env_combine;
- GLboolean ARB_texture_env_crossbar;
- GLboolean ARB_texture_env_dot3;
- GLboolean ARB_texture_float;
- GLboolean ARB_texture_mirrored_repeat;
- GLboolean ARB_texture_multisample;
- GLboolean ARB_texture_non_power_of_two;
- GLboolean ARB_texture_rg;
- GLboolean ARB_texture_rgb10_a2ui;
- GLboolean ARB_timer_query;
- GLboolean ARB_transform_feedback2;
- GLboolean ARB_transpose_matrix;
- GLboolean ARB_uniform_buffer_object;
- GLboolean ARB_vertex_array_object;
- GLboolean ARB_vertex_buffer_object;
- GLboolean ARB_vertex_program;
- GLboolean ARB_vertex_shader;
- GLboolean ARB_vertex_type_2_10_10_10_rev;
- GLboolean ARB_window_pos;
- GLboolean EXT_abgr;
- GLboolean EXT_bgra;
- GLboolean EXT_blend_color;
- GLboolean EXT_blend_equation_separate;
- GLboolean EXT_blend_func_separate;
- GLboolean EXT_blend_logic_op;
- GLboolean EXT_blend_minmax;
- GLboolean EXT_blend_subtract;
- GLboolean EXT_clip_volume_hint;
- GLboolean EXT_compiled_vertex_array;
- GLboolean EXT_copy_texture;
- GLboolean EXT_depth_bounds_test;
- GLboolean EXT_draw_buffers2;
- GLboolean EXT_draw_range_elements;
- GLboolean EXT_fog_coord;
- GLboolean EXT_framebuffer_blit;
- GLboolean EXT_framebuffer_multisample;
- GLboolean EXT_framebuffer_object;
- GLboolean EXT_framebuffer_sRGB;
- GLboolean EXT_gpu_program_parameters;
- GLboolean EXT_gpu_shader4;
- GLboolean EXT_multi_draw_arrays;
- GLboolean EXT_paletted_texture;
- GLboolean EXT_packed_depth_stencil;
- GLboolean EXT_packed_float;
- GLboolean EXT_packed_pixels;
- GLboolean EXT_pixel_buffer_object;
- GLboolean EXT_point_parameters;
- GLboolean EXT_polygon_offset;
- GLboolean EXT_provoking_vertex;
- GLboolean EXT_rescale_normal;
- GLboolean EXT_shadow_funcs;
- GLboolean EXT_secondary_color;
- GLboolean EXT_separate_shader_objects;
- GLboolean EXT_separate_specular_color;
- GLboolean EXT_shared_texture_palette;
- GLboolean EXT_stencil_wrap;
- GLboolean EXT_stencil_two_side;
- GLboolean EXT_subtexture;
- GLboolean EXT_texture;
- GLboolean EXT_texture_object;
- GLboolean EXT_texture3D;
- GLboolean EXT_texture_array;
- GLboolean EXT_texture_compression_s3tc;
- GLboolean EXT_texture_env_add;
- GLboolean EXT_texture_env_combine;
- GLboolean EXT_texture_env_dot3;
- GLboolean EXT_texture_filter_anisotropic;
- GLboolean EXT_texture_integer;
- GLboolean EXT_texture_lod_bias;
- GLboolean EXT_texture_mirror_clamp;
- GLboolean EXT_texture_shared_exponent;
- GLboolean EXT_texture_sRGB;
- GLboolean EXT_texture_sRGB_decode;
- GLboolean EXT_texture_swizzle;
- GLboolean EXT_transform_feedback;
- GLboolean EXT_timer_query;
- GLboolean EXT_vertex_array;
- GLboolean EXT_vertex_array_bgra;
- GLboolean EXT_vertex_array_set;
- GLboolean OES_standard_derivatives;
- /* vendor extensions */
- GLboolean AMD_conservative_depth;
- GLboolean APPLE_client_storage;
- GLboolean APPLE_packed_pixels;
- GLboolean APPLE_vertex_array_object;
- GLboolean APPLE_object_purgeable;
- GLboolean ATI_envmap_bumpmap;
- GLboolean ATI_texture_mirror_once;
- GLboolean ATI_texture_env_combine3;
- GLboolean ATI_fragment_shader;
- GLboolean ATI_separate_stencil;
- GLboolean IBM_rasterpos_clip;
- GLboolean IBM_multimode_draw_arrays;
- GLboolean MESA_pack_invert;
- GLboolean MESA_resize_buffers;
- GLboolean MESA_ycbcr_texture;
- GLboolean MESA_texture_array;
- GLboolean MESA_texture_signed_rgba;
- GLboolean NV_blend_square;
- GLboolean NV_conditional_render;
- GLboolean NV_fragment_program;
- GLboolean NV_fragment_program_option;
- GLboolean NV_light_max_exponent;
- GLboolean NV_point_sprite;
- GLboolean NV_primitive_restart;
- GLboolean NV_texgen_reflection;
- GLboolean NV_texture_env_combine4;
- GLboolean NV_texture_rectangle;
- GLboolean NV_vertex_program;
- GLboolean NV_vertex_program1_1;
- GLboolean OES_read_format;
- GLboolean SGI_texture_color_table;
- GLboolean SGIS_generate_mipmap;
- GLboolean SGIS_texture_edge_clamp;
- GLboolean SGIS_texture_lod;
- GLboolean TDFX_texture_compression_FXT1;
- GLboolean S3_s3tc;
- GLboolean OES_EGL_image;
- GLboolean OES_draw_texture;
- GLboolean EXT_texture_format_BGRA8888;
- GLboolean extension_sentinel;
- /** The extension string */
- const GLubyte *String;
- /** Number of supported extensions */
- GLuint Count;
-};
-
-
-/**
- * A stack of matrices (projection, modelview, color, texture, etc).
- */
-struct gl_matrix_stack
-{
- GLmatrix *Top; /**< points into Stack */
- GLmatrix *Stack; /**< array [MaxDepth] of GLmatrix */
- GLuint Depth; /**< 0 <= Depth < MaxDepth */
- GLuint MaxDepth; /**< size of Stack[] array */
- GLuint DirtyFlag; /**< _NEW_MODELVIEW or _NEW_PROJECTION, for example */
-};
-
-
-/**
- * \name Bits for image transfer operations
- * \sa __struct gl_contextRec::ImageTransferState.
- */
-/*@{*/
-#define IMAGE_SCALE_BIAS_BIT 0x1
-#define IMAGE_SHIFT_OFFSET_BIT 0x2
-#define IMAGE_MAP_COLOR_BIT 0x4
-#define IMAGE_CLAMP_BIT 0x800
-
-
-/** Pixel Transfer ops */
-#define IMAGE_BITS (IMAGE_SCALE_BIAS_BIT | \
- IMAGE_SHIFT_OFFSET_BIT | \
- IMAGE_MAP_COLOR_BIT)
-
-/**
- * \name Bits to indicate what state has changed.
- */
-/*@{*/
-#define _NEW_MODELVIEW (1 << 0) /**< gl_context::ModelView */
-#define _NEW_PROJECTION (1 << 1) /**< gl_context::Projection */
-#define _NEW_TEXTURE_MATRIX (1 << 2) /**< gl_context::TextureMatrix */
-#define _NEW_COLOR (1 << 3) /**< gl_context::Color */
-#define _NEW_DEPTH (1 << 4) /**< gl_context::Depth */
-#define _NEW_EVAL (1 << 5) /**< gl_context::Eval, EvalMap */
-#define _NEW_FOG (1 << 6) /**< gl_context::Fog */
-#define _NEW_HINT (1 << 7) /**< gl_context::Hint */
-#define _NEW_LIGHT (1 << 8) /**< gl_context::Light */
-#define _NEW_LINE (1 << 9) /**< gl_context::Line */
-#define _NEW_PIXEL (1 << 10) /**< gl_context::Pixel */
-#define _NEW_POINT (1 << 11) /**< gl_context::Point */
-#define _NEW_POLYGON (1 << 12) /**< gl_context::Polygon */
-#define _NEW_POLYGONSTIPPLE (1 << 13) /**< gl_context::PolygonStipple */
-#define _NEW_SCISSOR (1 << 14) /**< gl_context::Scissor */
-#define _NEW_STENCIL (1 << 15) /**< gl_context::Stencil */
-#define _NEW_TEXTURE (1 << 16) /**< gl_context::Texture */
-#define _NEW_TRANSFORM (1 << 17) /**< gl_context::Transform */
-#define _NEW_VIEWPORT (1 << 18) /**< gl_context::Viewport */
-#define _NEW_PACKUNPACK (1 << 19) /**< gl_context::Pack, Unpack */
-#define _NEW_ARRAY (1 << 20) /**< gl_context::Array */
-#define _NEW_RENDERMODE (1 << 21) /**< gl_context::RenderMode, etc */
-#define _NEW_BUFFERS (1 << 22) /**< gl_context::Visual, DrawBuffer, */
-#define _NEW_CURRENT_ATTRIB (1 << 23) /**< gl_context::Current */
-#define _NEW_MULTISAMPLE (1 << 24) /**< gl_context::Multisample */
-#define _NEW_TRACK_MATRIX (1 << 25) /**< gl_context::VertexProgram */
-#define _NEW_PROGRAM (1 << 26) /**< New program/shader state */
-#define _NEW_PROGRAM_CONSTANTS (1 << 27)
-#define _NEW_BUFFER_OBJECT (1 << 28)
-#define _NEW_ALL ~0
-/*@}*/
-
-
-/**
- * \name Bits to track array state changes
- *
- * Also used to summarize array enabled.
- */
-/*@{*/
-#define _NEW_ARRAY_VERTEX VERT_BIT_POS
-#define _NEW_ARRAY_WEIGHT VERT_BIT_WEIGHT
-#define _NEW_ARRAY_NORMAL VERT_BIT_NORMAL
-#define _NEW_ARRAY_COLOR0 VERT_BIT_COLOR0
-#define _NEW_ARRAY_COLOR1 VERT_BIT_COLOR1
-#define _NEW_ARRAY_FOGCOORD VERT_BIT_FOG
-#define _NEW_ARRAY_INDEX VERT_BIT_COLOR_INDEX
-#define _NEW_ARRAY_EDGEFLAG VERT_BIT_EDGEFLAG
-#define _NEW_ARRAY_POINT_SIZE VERT_BIT_COLOR_INDEX /* aliased */
-#define _NEW_ARRAY_TEXCOORD_0 VERT_BIT_TEX0
-#define _NEW_ARRAY_TEXCOORD_1 VERT_BIT_TEX1
-#define _NEW_ARRAY_TEXCOORD_2 VERT_BIT_TEX2
-#define _NEW_ARRAY_TEXCOORD_3 VERT_BIT_TEX3
-#define _NEW_ARRAY_TEXCOORD_4 VERT_BIT_TEX4
-#define _NEW_ARRAY_TEXCOORD_5 VERT_BIT_TEX5
-#define _NEW_ARRAY_TEXCOORD_6 VERT_BIT_TEX6
-#define _NEW_ARRAY_TEXCOORD_7 VERT_BIT_TEX7
-#define _NEW_ARRAY_ATTRIB_0 VERT_BIT_GENERIC0 /* start at bit 16 */
-#define _NEW_ARRAY_ALL 0xffffffff
-
-
-#define _NEW_ARRAY_TEXCOORD(i) (_NEW_ARRAY_TEXCOORD_0 << (i))
-#define _NEW_ARRAY_ATTRIB(i) (_NEW_ARRAY_ATTRIB_0 << (i))
-/*@}*/
-
-
-
-/**
- * \name A bunch of flags that we think might be useful to drivers.
- *
- * Set in the __struct gl_contextRec::_TriangleCaps bitfield.
- */
-/*@{*/
-#define DD_FLATSHADE 0x1
-#define DD_SEPARATE_SPECULAR 0x2
-#define DD_TRI_CULL_FRONT_BACK 0x4 /* special case on some hw */
-#define DD_TRI_LIGHT_TWOSIDE 0x8
-#define DD_TRI_UNFILLED 0x10
-#define DD_TRI_SMOOTH 0x20
-#define DD_TRI_STIPPLE 0x40
-#define DD_TRI_OFFSET 0x80
-#define DD_LINE_SMOOTH 0x100
-#define DD_LINE_STIPPLE 0x200
-#define DD_POINT_SMOOTH 0x400
-#define DD_POINT_ATTEN 0x800
-#define DD_TRI_TWOSTENCIL 0x1000
-/*@}*/
-
-
-/**
- * \name Define the state changes under which each of these bits might change
- */
-/*@{*/
-#define _DD_NEW_FLATSHADE _NEW_LIGHT
-#define _DD_NEW_SEPARATE_SPECULAR (_NEW_LIGHT | _NEW_FOG | _NEW_PROGRAM)
-#define _DD_NEW_TRI_CULL_FRONT_BACK _NEW_POLYGON
-#define _DD_NEW_TRI_LIGHT_TWOSIDE _NEW_LIGHT
-#define _DD_NEW_TRI_UNFILLED _NEW_POLYGON
-#define _DD_NEW_TRI_SMOOTH _NEW_POLYGON
-#define _DD_NEW_TRI_STIPPLE _NEW_POLYGON
-#define _DD_NEW_TRI_OFFSET _NEW_POLYGON
-#define _DD_NEW_LINE_SMOOTH _NEW_LINE
-#define _DD_NEW_LINE_STIPPLE _NEW_LINE
-#define _DD_NEW_LINE_WIDTH _NEW_LINE
-#define _DD_NEW_POINT_SMOOTH _NEW_POINT
-#define _DD_NEW_POINT_SIZE _NEW_POINT
-#define _DD_NEW_POINT_ATTEN _NEW_POINT
-/*@}*/
-
-
-/**
- * Composite state flags
- */
-/*@{*/
-#define _MESA_NEW_NEED_EYE_COORDS (_NEW_LIGHT | \
- _NEW_TEXTURE | \
- _NEW_POINT | \
- _NEW_PROGRAM | \
- _NEW_MODELVIEW)
-
-#define _MESA_NEW_NEED_NORMALS (_NEW_LIGHT | \
- _NEW_TEXTURE)
-
-#define _MESA_NEW_TRANSFER_STATE (_NEW_PIXEL)
-/*@}*/
-
-
-
-
-/* This has to be included here. */
-#include "dd.h"
-
-
-/**
- * Display list flags.
- * Strictly this is a tnl-private concept, but it doesn't seem
- * worthwhile adding a tnl private structure just to hold this one bit
- * of information:
- */
-#define DLIST_DANGLING_REFS 0x1
-
-
-/** Opaque declaration of display list payload data type */
-union gl_dlist_node;
-
-
-/**
- * Provide a location where information about a display list can be
- * collected. Could be extended with driverPrivate structures,
- * etc. in the future.
- */
-struct gl_display_list
-{
- GLuint Name;
- GLbitfield Flags; /**< DLIST_x flags */
- /** The dlist commands are in a linked list of nodes */
- union gl_dlist_node *Head;
-};
-
-
-/**
- * State used during display list compilation and execution.
- */
-struct gl_dlist_state
-{
- GLuint CallDepth; /**< Current recursion calling depth */
-
- struct gl_display_list *CurrentList; /**< List currently being compiled */
- union gl_dlist_node *CurrentBlock; /**< Pointer to current block of nodes */
- GLuint CurrentPos; /**< Index into current block of nodes */
-
- GLvertexformat ListVtxfmt;
-
- GLubyte ActiveAttribSize[VERT_ATTRIB_MAX];
- GLfloat CurrentAttrib[VERT_ATTRIB_MAX][4];
-
- GLubyte ActiveMaterialSize[MAT_ATTRIB_MAX];
- GLfloat CurrentMaterial[MAT_ATTRIB_MAX][4];
-
- GLubyte ActiveIndex;
- GLfloat CurrentIndex;
-
- GLubyte ActiveEdgeFlag;
- GLboolean CurrentEdgeFlag;
-
- struct {
- /* State known to have been set by the currently-compiling display
- * list. Used to eliminate some redundant state changes.
- */
- GLenum ShadeModel;
- } Current;
-};
-
-
-/**
- * Enum for the OpenGL APIs we know about and may support.
- */
-typedef enum
-{
- API_OPENGL,
- API_OPENGLES,
- API_OPENGLES2
-} gl_api;
-
-
-/**
- * Mesa rendering context.
- *
- * This is the central context data structure for Mesa. Almost all
- * OpenGL state is contained in this structure.
- * Think of this as a base class from which device drivers will derive
- * sub classes.
- *
- * The struct gl_context typedef names this structure.
- */
-struct gl_context
-{
- /** State possibly shared with other contexts in the address space */
- struct gl_shared_state *Shared;
-
- /** \name API function pointer tables */
- /*@{*/
- gl_api API;
- struct _glapi_table *Save; /**< Display list save functions */
- struct _glapi_table *Exec; /**< Execute functions */
- struct _glapi_table *CurrentDispatch; /**< == Save or Exec !! */
- /*@}*/
-
- struct gl_config Visual;
- struct gl_framebuffer *DrawBuffer; /**< buffer for writing */
- struct gl_framebuffer *ReadBuffer; /**< buffer for reading */
- struct gl_framebuffer *WinSysDrawBuffer; /**< set with MakeCurrent */
- struct gl_framebuffer *WinSysReadBuffer; /**< set with MakeCurrent */
-
- /**
- * Device driver function pointer table
- */
- struct dd_function_table Driver;
-
- void *DriverCtx; /**< Points to device driver context/state */
-
- /** Core/Driver constants */
- struct gl_constants Const;
-
- /** \name The various 4x4 matrix stacks */
- /*@{*/
- struct gl_matrix_stack ModelviewMatrixStack;
- struct gl_matrix_stack ProjectionMatrixStack;
- struct gl_matrix_stack TextureMatrixStack[MAX_TEXTURE_UNITS];
- struct gl_matrix_stack ProgramMatrixStack[MAX_PROGRAM_MATRICES];
- struct gl_matrix_stack *CurrentStack; /**< Points to one of the above stacks */
- /*@}*/
-
- /** Combined modelview and projection matrix */
- GLmatrix _ModelProjectMatrix;
-
- /** \name Display lists */
- struct gl_dlist_state ListState;
-
- GLboolean ExecuteFlag; /**< Execute GL commands? */
- GLboolean CompileFlag; /**< Compile GL commands into display list? */
-
- /** Extension information */
- struct gl_extensions Extensions;
-
- /** Version info */
- GLuint VersionMajor, VersionMinor;
- char *VersionString;
-
- /** \name State attribute stack (for glPush/PopAttrib) */
- /*@{*/
- GLuint AttribStackDepth;
- struct gl_attrib_node *AttribStack[MAX_ATTRIB_STACK_DEPTH];
- /*@}*/
-
- /** \name Renderer attribute groups
- *
- * We define a struct for each attribute group to make pushing and popping
- * attributes easy. Also it's a good organization.
- */
- /*@{*/
- struct gl_accum_attrib Accum; /**< Accum buffer attributes */
- struct gl_colorbuffer_attrib Color; /**< Color buffer attributes */
- struct gl_current_attrib Current; /**< Current attributes */
- struct gl_depthbuffer_attrib Depth; /**< Depth buffer attributes */
- struct gl_eval_attrib Eval; /**< Eval attributes */
- struct gl_fog_attrib Fog; /**< Fog attributes */
- struct gl_hint_attrib Hint; /**< Hint attributes */
- struct gl_light_attrib Light; /**< Light attributes */
- struct gl_line_attrib Line; /**< Line attributes */
- struct gl_list_attrib List; /**< List attributes */
- struct gl_multisample_attrib Multisample;
- struct gl_pixel_attrib Pixel; /**< Pixel attributes */
- struct gl_point_attrib Point; /**< Point attributes */
- struct gl_polygon_attrib Polygon; /**< Polygon attributes */
- GLuint PolygonStipple[32]; /**< Polygon stipple */
- struct gl_scissor_attrib Scissor; /**< Scissor attributes */
- struct gl_stencil_attrib Stencil; /**< Stencil buffer attributes */
- struct gl_texture_attrib Texture; /**< Texture attributes */
- struct gl_transform_attrib Transform; /**< Transformation attributes */
- struct gl_viewport_attrib Viewport; /**< Viewport attributes */
- /*@}*/
-
- /** \name Client attribute stack */
- /*@{*/
- GLuint ClientAttribStackDepth;
- struct gl_attrib_node *ClientAttribStack[MAX_CLIENT_ATTRIB_STACK_DEPTH];
- /*@}*/
-
- /** \name Client attribute groups */
- /*@{*/
- struct gl_array_attrib Array; /**< Vertex arrays */
- struct gl_pixelstore_attrib Pack; /**< Pixel packing */
- struct gl_pixelstore_attrib Unpack; /**< Pixel unpacking */
- struct gl_pixelstore_attrib DefaultPacking; /**< Default params */
- /*@}*/
-
- /** \name Other assorted state (not pushed/popped on attribute stack) */
- /*@{*/
- struct gl_pixelmaps PixelMaps;
-
- struct gl_evaluators EvalMap; /**< All evaluators */
- struct gl_feedback Feedback; /**< Feedback */
- struct gl_selection Select; /**< Selection */
-
- struct gl_program_state Program; /**< general program state */
- struct gl_vertex_program_state VertexProgram;
- struct gl_fragment_program_state FragmentProgram;
- struct gl_geometry_program_state GeometryProgram;
- struct gl_ati_fragment_shader_state ATIFragmentShader;
-
- struct gl_shader_state Shader; /**< GLSL shader object state */
- struct gl_shader_compiler_options ShaderCompilerOptions[MESA_SHADER_TYPES];
-
- struct gl_query_state Query; /**< occlusion, timer queries */
-
- struct gl_transform_feedback TransformFeedback;
-
- struct gl_buffer_object *CopyReadBuffer; /**< GL_ARB_copy_buffer */
- struct gl_buffer_object *CopyWriteBuffer; /**< GL_ARB_copy_buffer */
- /*@}*/
-
- struct gl_meta_state *Meta; /**< for "meta" operations */
-
- /* GL_EXT_framebuffer_object */
- struct gl_renderbuffer *CurrentRenderbuffer;
-
- GLenum ErrorValue; /**< Last error code */
-
- /**
- * Recognize and silence repeated error debug messages in buggy apps.
- */
- const char *ErrorDebugFmtString;
- GLuint ErrorDebugCount;
-
- GLenum RenderMode; /**< either GL_RENDER, GL_SELECT, GL_FEEDBACK */
- GLbitfield NewState; /**< bitwise-or of _NEW_* flags */
-
- GLboolean ViewportInitialized; /**< has viewport size been initialized? */
-
- GLbitfield varying_vp_inputs; /**< mask of VERT_BIT_* flags */
-
- /** \name Derived state */
- /*@{*/
- /** Bitwise-or of DD_* flags. Note that this bitfield may be used before
- * state validation so they need to always be current.
- */
- GLbitfield _TriangleCaps;
- GLbitfield _ImageTransferState;/**< bitwise-or of IMAGE_*_BIT flags */
- GLfloat _EyeZDir[3];
- GLfloat _ModelViewInvScale;
- GLboolean _NeedEyeCoords;
- GLboolean _ForceEyeCoords;
-
- GLuint TextureStateTimestamp; /**< detect changes to shared state */
-
- struct gl_shine_tab *_ShineTable[2]; /**< Active shine tables */
- struct gl_shine_tab *_ShineTabList; /**< MRU list of inactive shine tables */
- /**@}*/
-
- struct gl_list_extensions *ListExt; /**< driver dlist extensions */
-
- /** \name For debugging/development only */
- /*@{*/
- GLboolean FirstTimeCurrent;
- /*@}*/
-
- /** Dither disable via MESA_NO_DITHER env var */
- GLboolean NoDither;
-
- /** software compression/decompression supported or not */
- GLboolean Mesa_DXTn;
-
- GLboolean TextureFormatSupported[MESA_FORMAT_COUNT];
-
- /**
- * Use dp4 (rather than mul/mad) instructions for position
- * transformation?
- */
- GLboolean mvp_with_dp4;
-
- /**
- * \name Hooks for module contexts.
- *
- * These will eventually live in the driver or elsewhere.
- */
- /*@{*/
- void *swrast_context;
- void *swsetup_context;
- void *swtnl_context;
- void *swtnl_im;
- struct st_context *st;
- void *aelt_context;
- /*@}*/
-};
-
-
-#ifdef DEBUG
-extern int MESA_VERBOSE;
-extern int MESA_DEBUG_FLAGS;
-# define MESA_FUNCTION __FUNCTION__
-#else
-# define MESA_VERBOSE 0
-# define MESA_DEBUG_FLAGS 0
-# define MESA_FUNCTION "a function"
-# ifndef NDEBUG
-# define NDEBUG
-# endif
-#endif
-
-
-/** The MESA_VERBOSE var is a bitmask of these flags */
-enum _verbose
-{
- VERBOSE_VARRAY = 0x0001,
- VERBOSE_TEXTURE = 0x0002,
- VERBOSE_MATERIAL = 0x0004,
- VERBOSE_PIPELINE = 0x0008,
- VERBOSE_DRIVER = 0x0010,
- VERBOSE_STATE = 0x0020,
- VERBOSE_API = 0x0040,
- VERBOSE_DISPLAY_LIST = 0x0100,
- VERBOSE_LIGHTING = 0x0200,
- VERBOSE_PRIMS = 0x0400,
- VERBOSE_VERTS = 0x0800,
- VERBOSE_DISASSEM = 0x1000,
- VERBOSE_DRAW = 0x2000,
- VERBOSE_SWAPBUFFERS = 0x4000
-};
-
-
-/** The MESA_DEBUG_FLAGS var is a bitmask of these flags */
-enum _debug
-{
- DEBUG_ALWAYS_FLUSH = 0x1
-};
-
-
-
-#endif /* MTYPES_H */
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.7
+ *
+ * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file mtypes.h
+ * Main Mesa data structures.
+ *
+ * Please try to mark derived values with a leading underscore ('_').
+ */
+
+#ifndef MTYPES_H
+#define MTYPES_H
+
+
+#include "main/glheader.h"
+#include "main/config.h"
+#include "main/mfeatures.h"
+#include "glapi/glapi.h"
+#include "math/m_matrix.h" /* GLmatrix */
+#include "main/simple_list.h" /* struct simple_node */
+#include "main/formats.h" /* MESA_FORMAT_COUNT */
+
+
+/**
+ * Color channel data type.
+ */
+#if CHAN_BITS == 8
+ typedef GLubyte GLchan;
+#define CHAN_MAX 255
+#define CHAN_MAXF 255.0F
+#define CHAN_TYPE GL_UNSIGNED_BYTE
+#elif CHAN_BITS == 16
+ typedef GLushort GLchan;
+#define CHAN_MAX 65535
+#define CHAN_MAXF 65535.0F
+#define CHAN_TYPE GL_UNSIGNED_SHORT
+#elif CHAN_BITS == 32
+ typedef GLfloat GLchan;
+#define CHAN_MAX 1.0
+#define CHAN_MAXF 1.0F
+#define CHAN_TYPE GL_FLOAT
+#else
+#error "illegal number of color channel bits"
+#endif
+
+
+/**
+ * Stencil buffer data type.
+ */
+#if STENCIL_BITS==8
+ typedef GLubyte GLstencil;
+#elif STENCIL_BITS==16
+ typedef GLushort GLstencil;
+#else
+# error "illegal number of stencil bits"
+#endif
+
+
+/**
+ * \name 64-bit extension of GLbitfield.
+ */
+/*@{*/
+typedef GLuint64 GLbitfield64;
+
+/** Set a single bit */
+#define BITFIELD64_BIT(b) (1ULL << (b))
+
+
+/**
+ * \name Some forward type declarations
+ */
+/*@{*/
+struct _mesa_HashTable;
+struct gl_attrib_node;
+struct gl_list_extensions;
+struct gl_meta_state;
+struct gl_pixelstore_attrib;
+struct gl_program_cache;
+struct gl_texture_format;
+struct gl_texture_image;
+struct gl_texture_object;
+struct gl_context;
+struct st_context;
+/*@}*/
+
+
+/** Extra draw modes beyond GL_POINTS, GL_TRIANGLE_FAN, etc */
+#define PRIM_OUTSIDE_BEGIN_END (GL_POLYGON+1)
+#define PRIM_INSIDE_UNKNOWN_PRIM (GL_POLYGON+2)
+#define PRIM_UNKNOWN (GL_POLYGON+3)
+
+
+/**
+ * Shader stages. Note that these will become 5 with tessellation.
+ * These MUST have the same values as gallium's PIPE_SHADER_*
+ */
+typedef enum
+{
+ MESA_SHADER_VERTEX = 0,
+ MESA_SHADER_FRAGMENT = 1,
+ MESA_SHADER_GEOMETRY = 2,
+ MESA_SHADER_TYPES = 3
+} gl_shader_type;
+
+
+
+/**
+ * Indexes for vertex program attributes.
+ * GL_NV_vertex_program aliases generic attributes over the conventional
+ * attributes. In GL_ARB_vertex_program shader the aliasing is optional.
+ * In GL_ARB_vertex_shader / OpenGL 2.0 the aliasing is disallowed (the
+ * generic attributes are distinct/separate).
+ */
+typedef enum
+{
+ VERT_ATTRIB_POS = 0,
+ VERT_ATTRIB_WEIGHT = 1,
+ VERT_ATTRIB_NORMAL = 2,
+ VERT_ATTRIB_COLOR0 = 3,
+ VERT_ATTRIB_COLOR1 = 4,
+ VERT_ATTRIB_FOG = 5,
+ VERT_ATTRIB_COLOR_INDEX = 6,
+ VERT_ATTRIB_POINT_SIZE = 6, /*alias*/
+ VERT_ATTRIB_EDGEFLAG = 7,
+ VERT_ATTRIB_TEX0 = 8,
+ VERT_ATTRIB_TEX1 = 9,
+ VERT_ATTRIB_TEX2 = 10,
+ VERT_ATTRIB_TEX3 = 11,
+ VERT_ATTRIB_TEX4 = 12,
+ VERT_ATTRIB_TEX5 = 13,
+ VERT_ATTRIB_TEX6 = 14,
+ VERT_ATTRIB_TEX7 = 15,
+ VERT_ATTRIB_GENERIC0 = 16,
+ VERT_ATTRIB_GENERIC1 = 17,
+ VERT_ATTRIB_GENERIC2 = 18,
+ VERT_ATTRIB_GENERIC3 = 19,
+ VERT_ATTRIB_GENERIC4 = 20,
+ VERT_ATTRIB_GENERIC5 = 21,
+ VERT_ATTRIB_GENERIC6 = 22,
+ VERT_ATTRIB_GENERIC7 = 23,
+ VERT_ATTRIB_GENERIC8 = 24,
+ VERT_ATTRIB_GENERIC9 = 25,
+ VERT_ATTRIB_GENERIC10 = 26,
+ VERT_ATTRIB_GENERIC11 = 27,
+ VERT_ATTRIB_GENERIC12 = 28,
+ VERT_ATTRIB_GENERIC13 = 29,
+ VERT_ATTRIB_GENERIC14 = 30,
+ VERT_ATTRIB_GENERIC15 = 31,
+ VERT_ATTRIB_MAX = 32
+} gl_vert_attrib;
+
+/**
+ * Bitflags for vertex attributes.
+ * These are used in bitfields in many places.
+ */
+/*@{*/
+#define VERT_BIT_POS (1 << VERT_ATTRIB_POS)
+#define VERT_BIT_WEIGHT (1 << VERT_ATTRIB_WEIGHT)
+#define VERT_BIT_NORMAL (1 << VERT_ATTRIB_NORMAL)
+#define VERT_BIT_COLOR0 (1 << VERT_ATTRIB_COLOR0)
+#define VERT_BIT_COLOR1 (1 << VERT_ATTRIB_COLOR1)
+#define VERT_BIT_FOG (1 << VERT_ATTRIB_FOG)
+#define VERT_BIT_COLOR_INDEX (1 << VERT_ATTRIB_COLOR_INDEX)
+#define VERT_BIT_EDGEFLAG (1 << VERT_ATTRIB_EDGEFLAG)
+#define VERT_BIT_TEX0 (1 << VERT_ATTRIB_TEX0)
+#define VERT_BIT_TEX1 (1 << VERT_ATTRIB_TEX1)
+#define VERT_BIT_TEX2 (1 << VERT_ATTRIB_TEX2)
+#define VERT_BIT_TEX3 (1 << VERT_ATTRIB_TEX3)
+#define VERT_BIT_TEX4 (1 << VERT_ATTRIB_TEX4)
+#define VERT_BIT_TEX5 (1 << VERT_ATTRIB_TEX5)
+#define VERT_BIT_TEX6 (1 << VERT_ATTRIB_TEX6)
+#define VERT_BIT_TEX7 (1 << VERT_ATTRIB_TEX7)
+#define VERT_BIT_GENERIC0 (1 << VERT_ATTRIB_GENERIC0)
+#define VERT_BIT_GENERIC1 (1 << VERT_ATTRIB_GENERIC1)
+#define VERT_BIT_GENERIC2 (1 << VERT_ATTRIB_GENERIC2)
+#define VERT_BIT_GENERIC3 (1 << VERT_ATTRIB_GENERIC3)
+#define VERT_BIT_GENERIC4 (1 << VERT_ATTRIB_GENERIC4)
+#define VERT_BIT_GENERIC5 (1 << VERT_ATTRIB_GENERIC5)
+#define VERT_BIT_GENERIC6 (1 << VERT_ATTRIB_GENERIC6)
+#define VERT_BIT_GENERIC7 (1 << VERT_ATTRIB_GENERIC7)
+#define VERT_BIT_GENERIC8 (1 << VERT_ATTRIB_GENERIC8)
+#define VERT_BIT_GENERIC9 (1 << VERT_ATTRIB_GENERIC9)
+#define VERT_BIT_GENERIC10 (1 << VERT_ATTRIB_GENERIC10)
+#define VERT_BIT_GENERIC11 (1 << VERT_ATTRIB_GENERIC11)
+#define VERT_BIT_GENERIC12 (1 << VERT_ATTRIB_GENERIC12)
+#define VERT_BIT_GENERIC13 (1 << VERT_ATTRIB_GENERIC13)
+#define VERT_BIT_GENERIC14 (1 << VERT_ATTRIB_GENERIC14)
+#define VERT_BIT_GENERIC15 (1 << VERT_ATTRIB_GENERIC15)
+
+#define VERT_BIT_TEX(u) (1 << (VERT_ATTRIB_TEX0 + (u)))
+#define VERT_BIT_GENERIC(g) (1 << (VERT_ATTRIB_GENERIC0 + (g)))
+/*@}*/
+
+
+/**
+ * Indexes for vertex program result attributes
+ */
+typedef enum
+{
+ VERT_RESULT_HPOS = 0,
+ VERT_RESULT_COL0 = 1,
+ VERT_RESULT_COL1 = 2,
+ VERT_RESULT_FOGC = 3,
+ VERT_RESULT_TEX0 = 4,
+ VERT_RESULT_TEX1 = 5,
+ VERT_RESULT_TEX2 = 6,
+ VERT_RESULT_TEX3 = 7,
+ VERT_RESULT_TEX4 = 8,
+ VERT_RESULT_TEX5 = 9,
+ VERT_RESULT_TEX6 = 10,
+ VERT_RESULT_TEX7 = 11,
+ VERT_RESULT_PSIZ = 12,
+ VERT_RESULT_BFC0 = 13,
+ VERT_RESULT_BFC1 = 14,
+ VERT_RESULT_EDGE = 15,
+ VERT_RESULT_VAR0 = 16, /**< shader varying */
+ VERT_RESULT_MAX = (VERT_RESULT_VAR0 + MAX_VARYING)
+} gl_vert_result;
+
+
+/*********************************************/
+
+/**
+ * Indexes for geometry program attributes.
+ */
+typedef enum
+{
+ GEOM_ATTRIB_POSITION = 0,
+ GEOM_ATTRIB_COLOR0 = 1,
+ GEOM_ATTRIB_COLOR1 = 2,
+ GEOM_ATTRIB_SECONDARY_COLOR0 = 3,
+ GEOM_ATTRIB_SECONDARY_COLOR1 = 4,
+ GEOM_ATTRIB_FOG_FRAG_COORD = 5,
+ GEOM_ATTRIB_POINT_SIZE = 6,
+ GEOM_ATTRIB_CLIP_VERTEX = 7,
+ GEOM_ATTRIB_PRIMITIVE_ID = 8,
+ GEOM_ATTRIB_TEX_COORD = 9,
+
+ GEOM_ATTRIB_VAR0 = 16,
+ GEOM_ATTRIB_MAX = (GEOM_ATTRIB_VAR0 + MAX_VARYING)
+} gl_geom_attrib;
+
+/**
+ * Bitflags for geometry attributes.
+ * These are used in bitfields in many places.
+ */
+/*@{*/
+#define GEOM_BIT_COLOR0 (1 << GEOM_ATTRIB_COLOR0)
+#define GEOM_BIT_COLOR1 (1 << GEOM_ATTRIB_COLOR1)
+#define GEOM_BIT_SCOLOR0 (1 << GEOM_ATTRIB_SECONDARY_COLOR0)
+#define GEOM_BIT_SCOLOR1 (1 << GEOM_ATTRIB_SECONDARY_COLOR1)
+#define GEOM_BIT_TEX_COORD (1 << GEOM_ATTRIB_TEX_COORD)
+#define GEOM_BIT_FOG_COORD (1 << GEOM_ATTRIB_FOG_FRAG_COORD)
+#define GEOM_BIT_POSITION (1 << GEOM_ATTRIB_POSITION)
+#define GEOM_BIT_POINT_SIDE (1 << GEOM_ATTRIB_POINT_SIZE)
+#define GEOM_BIT_CLIP_VERTEX (1 << GEOM_ATTRIB_CLIP_VERTEX)
+#define GEOM_BIT_PRIM_ID (1 << GEOM_ATTRIB_PRIMITIVE_ID)
+#define GEOM_BIT_VAR0 (1 << GEOM_ATTRIB_VAR0)
+
+#define GEOM_BIT_VAR(g) (1 << (GEOM_BIT_VAR0 + (g)))
+/*@}*/
+
+
+/**
+ * Indexes for geometry program result attributes
+ */
+typedef enum
+{
+ GEOM_RESULT_POS = 0,
+ GEOM_RESULT_COL0 = 1,
+ GEOM_RESULT_COL1 = 2,
+ GEOM_RESULT_SCOL0 = 3,
+ GEOM_RESULT_SCOL1 = 4,
+ GEOM_RESULT_FOGC = 5,
+ GEOM_RESULT_TEX0 = 6,
+ GEOM_RESULT_TEX1 = 7,
+ GEOM_RESULT_TEX2 = 8,
+ GEOM_RESULT_TEX3 = 9,
+ GEOM_RESULT_TEX4 = 10,
+ GEOM_RESULT_TEX5 = 11,
+ GEOM_RESULT_TEX6 = 12,
+ GEOM_RESULT_TEX7 = 13,
+ GEOM_RESULT_PSIZ = 14,
+ GEOM_RESULT_CLPV = 15,
+ GEOM_RESULT_PRID = 16,
+ GEOM_RESULT_LAYR = 17,
+ GEOM_RESULT_VAR0 = 18, /**< shader varying, should really be 16 */
+ /* ### we need to -2 because var0 is 18 instead 16 like in the others */
+ GEOM_RESULT_MAX = (GEOM_RESULT_VAR0 + MAX_VARYING - 2)
+} gl_geom_result;
+
+
+/**
+ * Indexes for fragment program input attributes.
+ */
+typedef enum
+{
+ FRAG_ATTRIB_WPOS = 0,
+ FRAG_ATTRIB_COL0 = 1,
+ FRAG_ATTRIB_COL1 = 2,
+ FRAG_ATTRIB_FOGC = 3,
+ FRAG_ATTRIB_TEX0 = 4,
+ FRAG_ATTRIB_TEX1 = 5,
+ FRAG_ATTRIB_TEX2 = 6,
+ FRAG_ATTRIB_TEX3 = 7,
+ FRAG_ATTRIB_TEX4 = 8,
+ FRAG_ATTRIB_TEX5 = 9,
+ FRAG_ATTRIB_TEX6 = 10,
+ FRAG_ATTRIB_TEX7 = 11,
+ FRAG_ATTRIB_FACE = 12, /**< front/back face */
+ FRAG_ATTRIB_PNTC = 13, /**< sprite/point coord */
+ FRAG_ATTRIB_VAR0 = 14, /**< shader varying */
+ FRAG_ATTRIB_MAX = (FRAG_ATTRIB_VAR0 + MAX_VARYING)
+} gl_frag_attrib;
+
+/**
+ * Bitflags for fragment program input attributes.
+ */
+/*@{*/
+#define FRAG_BIT_WPOS (1 << FRAG_ATTRIB_WPOS)
+#define FRAG_BIT_COL0 (1 << FRAG_ATTRIB_COL0)
+#define FRAG_BIT_COL1 (1 << FRAG_ATTRIB_COL1)
+#define FRAG_BIT_FOGC (1 << FRAG_ATTRIB_FOGC)
+#define FRAG_BIT_FACE (1 << FRAG_ATTRIB_FACE)
+#define FRAG_BIT_PNTC (1 << FRAG_ATTRIB_PNTC)
+#define FRAG_BIT_TEX0 (1 << FRAG_ATTRIB_TEX0)
+#define FRAG_BIT_TEX1 (1 << FRAG_ATTRIB_TEX1)
+#define FRAG_BIT_TEX2 (1 << FRAG_ATTRIB_TEX2)
+#define FRAG_BIT_TEX3 (1 << FRAG_ATTRIB_TEX3)
+#define FRAG_BIT_TEX4 (1 << FRAG_ATTRIB_TEX4)
+#define FRAG_BIT_TEX5 (1 << FRAG_ATTRIB_TEX5)
+#define FRAG_BIT_TEX6 (1 << FRAG_ATTRIB_TEX6)
+#define FRAG_BIT_TEX7 (1 << FRAG_ATTRIB_TEX7)
+#define FRAG_BIT_VAR0 (1 << FRAG_ATTRIB_VAR0)
+
+#define FRAG_BIT_TEX(U) (FRAG_BIT_TEX0 << (U))
+#define FRAG_BIT_VAR(V) (FRAG_BIT_VAR0 << (V))
+
+#define FRAG_BITS_TEX_ANY (FRAG_BIT_TEX0| \
+ FRAG_BIT_TEX1| \
+ FRAG_BIT_TEX2| \
+ FRAG_BIT_TEX3| \
+ FRAG_BIT_TEX4| \
+ FRAG_BIT_TEX5| \
+ FRAG_BIT_TEX6| \
+ FRAG_BIT_TEX7)
+/*@}*/
+
+
+/**
+ * Fragment program results
+ */
+typedef enum
+{
+ FRAG_RESULT_DEPTH = 0,
+ FRAG_RESULT_STENCIL = 1,
+ FRAG_RESULT_COLOR = 2,
+ FRAG_RESULT_DATA0 = 3,
+ FRAG_RESULT_MAX = (FRAG_RESULT_DATA0 + MAX_DRAW_BUFFERS)
+} gl_frag_result;
+
+
+/**
+ * Indexes for all renderbuffers
+ */
+typedef enum
+{
+ /* the four standard color buffers */
+ BUFFER_FRONT_LEFT,
+ BUFFER_BACK_LEFT,
+ BUFFER_FRONT_RIGHT,
+ BUFFER_BACK_RIGHT,
+ BUFFER_DEPTH,
+ BUFFER_STENCIL,
+ BUFFER_ACCUM,
+ /* optional aux buffer */
+ BUFFER_AUX0,
+ /* generic renderbuffers */
+ BUFFER_COLOR0,
+ BUFFER_COLOR1,
+ BUFFER_COLOR2,
+ BUFFER_COLOR3,
+ BUFFER_COLOR4,
+ BUFFER_COLOR5,
+ BUFFER_COLOR6,
+ BUFFER_COLOR7,
+ BUFFER_COUNT
+} gl_buffer_index;
+
+/**
+ * Bit flags for all renderbuffers
+ */
+#define BUFFER_BIT_FRONT_LEFT (1 << BUFFER_FRONT_LEFT)
+#define BUFFER_BIT_BACK_LEFT (1 << BUFFER_BACK_LEFT)
+#define BUFFER_BIT_FRONT_RIGHT (1 << BUFFER_FRONT_RIGHT)
+#define BUFFER_BIT_BACK_RIGHT (1 << BUFFER_BACK_RIGHT)
+#define BUFFER_BIT_AUX0 (1 << BUFFER_AUX0)
+#define BUFFER_BIT_AUX1 (1 << BUFFER_AUX1)
+#define BUFFER_BIT_AUX2 (1 << BUFFER_AUX2)
+#define BUFFER_BIT_AUX3 (1 << BUFFER_AUX3)
+#define BUFFER_BIT_DEPTH (1 << BUFFER_DEPTH)
+#define BUFFER_BIT_STENCIL (1 << BUFFER_STENCIL)
+#define BUFFER_BIT_ACCUM (1 << BUFFER_ACCUM)
+#define BUFFER_BIT_COLOR0 (1 << BUFFER_COLOR0)
+#define BUFFER_BIT_COLOR1 (1 << BUFFER_COLOR1)
+#define BUFFER_BIT_COLOR2 (1 << BUFFER_COLOR2)
+#define BUFFER_BIT_COLOR3 (1 << BUFFER_COLOR3)
+#define BUFFER_BIT_COLOR4 (1 << BUFFER_COLOR4)
+#define BUFFER_BIT_COLOR5 (1 << BUFFER_COLOR5)
+#define BUFFER_BIT_COLOR6 (1 << BUFFER_COLOR6)
+#define BUFFER_BIT_COLOR7 (1 << BUFFER_COLOR7)
+
+/**
+ * Mask of all the color buffer bits (but not accum).
+ */
+#define BUFFER_BITS_COLOR (BUFFER_BIT_FRONT_LEFT | \
+ BUFFER_BIT_BACK_LEFT | \
+ BUFFER_BIT_FRONT_RIGHT | \
+ BUFFER_BIT_BACK_RIGHT | \
+ BUFFER_BIT_AUX0 | \
+ BUFFER_BIT_COLOR0 | \
+ BUFFER_BIT_COLOR1 | \
+ BUFFER_BIT_COLOR2 | \
+ BUFFER_BIT_COLOR3 | \
+ BUFFER_BIT_COLOR4 | \
+ BUFFER_BIT_COLOR5 | \
+ BUFFER_BIT_COLOR6 | \
+ BUFFER_BIT_COLOR7)
+
+
+/**
+ * Framebuffer configuration (aka visual / pixelformat)
+ * Note: some of these fields should be boolean, but it appears that
+ * code in drivers/dri/common/util.c requires int-sized fields.
+ */
+struct gl_config
+{
+ GLboolean rgbMode;
+ GLboolean floatMode;
+ GLboolean colorIndexMode; /* XXX is this used anywhere? */
+ GLuint doubleBufferMode;
+ GLuint stereoMode;
+
+ GLboolean haveAccumBuffer;
+ GLboolean haveDepthBuffer;
+ GLboolean haveStencilBuffer;
+
+ GLint redBits, greenBits, blueBits, alphaBits; /* bits per comp */
+ GLuint redMask, greenMask, blueMask, alphaMask;
+ GLint rgbBits; /* total bits for rgb */
+ GLint indexBits; /* total bits for colorindex */
+
+ GLint accumRedBits, accumGreenBits, accumBlueBits, accumAlphaBits;
+ GLint depthBits;
+ GLint stencilBits;
+
+ GLint numAuxBuffers;
+
+ GLint level;
+
+ /* EXT_visual_rating / GLX 1.2 */
+ GLint visualRating;
+
+ /* EXT_visual_info / GLX 1.2 */
+ GLint transparentPixel;
+ /* colors are floats scaled to ints */
+ GLint transparentRed, transparentGreen, transparentBlue, transparentAlpha;
+ GLint transparentIndex;
+
+ /* ARB_multisample / SGIS_multisample */
+ GLint sampleBuffers;
+ GLint samples;
+
+ /* SGIX_pbuffer / GLX 1.3 */
+ GLint maxPbufferWidth;
+ GLint maxPbufferHeight;
+ GLint maxPbufferPixels;
+ GLint optimalPbufferWidth; /* Only for SGIX_pbuffer. */
+ GLint optimalPbufferHeight; /* Only for SGIX_pbuffer. */
+
+ /* OML_swap_method */
+ GLint swapMethod;
+
+ /* EXT_texture_from_pixmap */
+ GLint bindToTextureRgb;
+ GLint bindToTextureRgba;
+ GLint bindToMipmapTexture;
+ GLint bindToTextureTargets;
+ GLint yInverted;
+
+ /* EXT_framebuffer_sRGB */
+ GLint sRGBCapable;
+};
+
+
+/**
+ * Data structure for color tables
+ */
+struct gl_color_table
+{
+ GLenum InternalFormat; /**< The user-specified format */
+ GLenum _BaseFormat; /**< GL_ALPHA, GL_RGBA, GL_RGB, etc */
+ GLuint Size; /**< number of entries in table */
+ GLfloat *TableF; /**< Color table, floating point values */
+ GLubyte *TableUB; /**< Color table, ubyte values */
+ GLubyte RedSize;
+ GLubyte GreenSize;
+ GLubyte BlueSize;
+ GLubyte AlphaSize;
+ GLubyte LuminanceSize;
+ GLubyte IntensitySize;
+};
+
+
+/**
+ * \name Bit flags used for updating material values.
+ */
+/*@{*/
+#define MAT_ATTRIB_FRONT_AMBIENT 0
+#define MAT_ATTRIB_BACK_AMBIENT 1
+#define MAT_ATTRIB_FRONT_DIFFUSE 2
+#define MAT_ATTRIB_BACK_DIFFUSE 3
+#define MAT_ATTRIB_FRONT_SPECULAR 4
+#define MAT_ATTRIB_BACK_SPECULAR 5
+#define MAT_ATTRIB_FRONT_EMISSION 6
+#define MAT_ATTRIB_BACK_EMISSION 7
+#define MAT_ATTRIB_FRONT_SHININESS 8
+#define MAT_ATTRIB_BACK_SHININESS 9
+#define MAT_ATTRIB_FRONT_INDEXES 10
+#define MAT_ATTRIB_BACK_INDEXES 11
+#define MAT_ATTRIB_MAX 12
+
+#define MAT_ATTRIB_AMBIENT(f) (MAT_ATTRIB_FRONT_AMBIENT+(f))
+#define MAT_ATTRIB_DIFFUSE(f) (MAT_ATTRIB_FRONT_DIFFUSE+(f))
+#define MAT_ATTRIB_SPECULAR(f) (MAT_ATTRIB_FRONT_SPECULAR+(f))
+#define MAT_ATTRIB_EMISSION(f) (MAT_ATTRIB_FRONT_EMISSION+(f))
+#define MAT_ATTRIB_SHININESS(f)(MAT_ATTRIB_FRONT_SHININESS+(f))
+#define MAT_ATTRIB_INDEXES(f) (MAT_ATTRIB_FRONT_INDEXES+(f))
+
+#define MAT_INDEX_AMBIENT 0
+#define MAT_INDEX_DIFFUSE 1
+#define MAT_INDEX_SPECULAR 2
+
+#define MAT_BIT_FRONT_AMBIENT (1<<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;
+
+ /** GL_SGI_texture_color_table */
+ GLfloat TextureColorTableScale[4]; /**< RGBA */
+ GLfloat TextureColorTableBias[4]; /**< RGBA */
+};
+
+
+/**
+ * Point attribute group (GL_POINT_BIT).
+ */
+struct gl_point_attrib
+{
+ GLboolean SmoothFlag; /**< True if GL_POINT_SMOOTH is enabled */
+ GLfloat Size; /**< User-specified point size */
+ GLfloat Params[3]; /**< GL_EXT_point_parameters */
+ GLfloat MinSize, MaxSize; /**< GL_EXT_point_parameters */
+ GLfloat Threshold; /**< GL_EXT_point_parameters */
+ GLboolean _Attenuated; /**< True if Params != [1, 0, 0] */
+ GLboolean PointSprite; /**< GL_NV/ARB_point_sprite */
+ GLboolean CoordReplace[MAX_TEXTURE_COORD_UNITS]; /**< GL_ARB_point_sprite*/
+ GLenum SpriteRMode; /**< GL_NV_point_sprite (only!) */
+ GLenum SpriteOrigin; /**< GL_ARB_point_sprite */
+};
+
+
+/**
+ * Polygon attribute group (GL_POLYGON_BIT).
+ */
+struct gl_polygon_attrib
+{
+ GLenum FrontFace; /**< Either GL_CW or GL_CCW */
+ GLenum FrontMode; /**< Either GL_POINT, GL_LINE or GL_FILL */
+ GLenum BackMode; /**< Either GL_POINT, GL_LINE or GL_FILL */
+ GLboolean _FrontBit; /**< 0=GL_CCW, 1=GL_CW */
+ GLboolean CullFlag; /**< Culling on/off flag */
+ GLboolean SmoothFlag; /**< True if GL_POLYGON_SMOOTH is enabled */
+ GLboolean StippleFlag; /**< True if GL_POLYGON_STIPPLE is enabled */
+ GLenum CullFaceMode; /**< Culling mode GL_FRONT or GL_BACK */
+ GLfloat OffsetFactor; /**< Polygon offset factor, from user */
+ GLfloat OffsetUnits; /**< Polygon offset units, from user */
+ GLboolean OffsetPoint; /**< Offset in GL_POINT mode */
+ GLboolean OffsetLine; /**< Offset in GL_LINE mode */
+ GLboolean OffsetFill; /**< Offset in GL_FILL mode */
+};
+
+
+/**
+ * Scissor attributes (GL_SCISSOR_BIT).
+ */
+struct gl_scissor_attrib
+{
+ GLboolean Enabled; /**< Scissor test enabled? */
+ GLint X, Y; /**< Lower left corner of box */
+ GLsizei Width, Height; /**< Size of box */
+};
+
+
+/**
+ * Stencil attribute group (GL_STENCIL_BUFFER_BIT).
+ *
+ * Three sets of stencil data are tracked so that OpenGL 2.0,
+ * GL_EXT_stencil_two_side, and GL_ATI_separate_stencil can all be supported
+ * simultaneously. In each of the stencil state arrays, element 0 corresponds
+ * to GL_FRONT. Element 1 corresponds to the OpenGL 2.0 /
+ * GL_ATI_separate_stencil GL_BACK state. Element 2 corresponds to the
+ * GL_EXT_stencil_two_side GL_BACK state.
+ *
+ * The derived value \c _BackFace is either 1 or 2 depending on whether or
+ * not GL_STENCIL_TEST_TWO_SIDE_EXT is enabled.
+ *
+ * The derived value \c _TestTwoSide is set when the front-face and back-face
+ * stencil state are different.
+ */
+struct gl_stencil_attrib
+{
+ GLboolean Enabled; /**< Enabled flag */
+ GLboolean TestTwoSide; /**< GL_EXT_stencil_two_side */
+ GLubyte ActiveFace; /**< GL_EXT_stencil_two_side (0 or 2) */
+ GLboolean _Enabled; /**< Enabled and stencil buffer present */
+ GLboolean _TestTwoSide;
+ GLubyte _BackFace; /**< Current back stencil state (1 or 2) */
+ GLenum Function[3]; /**< Stencil function */
+ GLenum FailFunc[3]; /**< Fail function */
+ GLenum ZPassFunc[3]; /**< Depth buffer pass function */
+ GLenum ZFailFunc[3]; /**< Depth buffer fail function */
+ GLint Ref[3]; /**< Reference value */
+ GLuint ValueMask[3]; /**< Value mask */
+ GLuint WriteMask[3]; /**< Write mask */
+ GLuint Clear; /**< Clear value */
+};
+
+
+/**
+ * An index for each type of texture object. These correspond to the GL
+ * texture target enums, such as GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP, etc.
+ * Note: the order is from highest priority to lowest priority.
+ */
+typedef enum
+{
+ TEXTURE_2D_ARRAY_INDEX,
+ TEXTURE_1D_ARRAY_INDEX,
+ TEXTURE_CUBE_INDEX,
+ TEXTURE_3D_INDEX,
+ TEXTURE_RECT_INDEX,
+ TEXTURE_2D_INDEX,
+ TEXTURE_1D_INDEX,
+ NUM_TEXTURE_TARGETS
+} gl_texture_index;
+
+
+/**
+ * Bit flags for each type of texture object
+ * Used for Texture.Unit[]._ReallyEnabled flags.
+ */
+/*@{*/
+#define TEXTURE_2D_ARRAY_BIT (1 << TEXTURE_2D_ARRAY_INDEX)
+#define TEXTURE_1D_ARRAY_BIT (1 << TEXTURE_1D_ARRAY_INDEX)
+#define TEXTURE_CUBE_BIT (1 << TEXTURE_CUBE_INDEX)
+#define TEXTURE_3D_BIT (1 << TEXTURE_3D_INDEX)
+#define TEXTURE_RECT_BIT (1 << TEXTURE_RECT_INDEX)
+#define TEXTURE_2D_BIT (1 << TEXTURE_2D_INDEX)
+#define TEXTURE_1D_BIT (1 << TEXTURE_1D_INDEX)
+/*@}*/
+
+
+/**
+ * TexGenEnabled flags.
+ */
+/*@{*/
+#define S_BIT 1
+#define T_BIT 2
+#define R_BIT 4
+#define Q_BIT 8
+#define STR_BITS (S_BIT | T_BIT | R_BIT)
+/*@}*/
+
+
+/**
+ * Bit flag versions of the corresponding GL_ constants.
+ */
+/*@{*/
+#define TEXGEN_SPHERE_MAP 0x1
+#define TEXGEN_OBJ_LINEAR 0x2
+#define TEXGEN_EYE_LINEAR 0x4
+#define TEXGEN_REFLECTION_MAP_NV 0x8
+#define TEXGEN_NORMAL_MAP_NV 0x10
+
+#define TEXGEN_NEED_NORMALS (TEXGEN_SPHERE_MAP | \
+ TEXGEN_REFLECTION_MAP_NV | \
+ TEXGEN_NORMAL_MAP_NV)
+#define TEXGEN_NEED_EYE_COORD (TEXGEN_SPHERE_MAP | \
+ TEXGEN_REFLECTION_MAP_NV | \
+ TEXGEN_NORMAL_MAP_NV | \
+ TEXGEN_EYE_LINEAR)
+/*@}*/
+
+
+
+/** Tex-gen enabled for texture unit? */
+#define ENABLE_TEXGEN(unit) (1 << (unit))
+
+/** Non-identity texture matrix for texture unit? */
+#define ENABLE_TEXMAT(unit) (1 << (unit))
+
+
+/**
+ * Texel fetch function prototype. We use texel fetch functions to
+ * extract RGBA, color indexes and depth components out of 1D, 2D and 3D
+ * texture images. These functions help to isolate us from the gritty
+ * details of all the various texture image encodings.
+ *
+ * \param texImage texture image.
+ * \param col texel column.
+ * \param row texel row.
+ * \param img texel image level/layer.
+ * \param texelOut output texel (up to 4 GLchans)
+ */
+typedef void (*FetchTexelFuncC)( const struct gl_texture_image *texImage,
+ GLint col, GLint row, GLint img,
+ GLchan *texelOut );
+
+/**
+ * As above, but returns floats.
+ * Used for depth component images and for upcoming signed/float
+ * texture images.
+ */
+typedef void (*FetchTexelFuncF)( const struct gl_texture_image *texImage,
+ GLint col, GLint row, GLint img,
+ GLfloat *texelOut );
+
+
+typedef void (*StoreTexelFunc)(struct gl_texture_image *texImage,
+ GLint col, GLint row, GLint img,
+ const void *texel);
+
+
+/**
+ * Texture image state. Describes the dimensions of a texture image,
+ * the texel format and pointers to Texel Fetch functions.
+ */
+struct gl_texture_image
+{
+ GLint InternalFormat; /**< Internal format as given by the user */
+ GLenum _BaseFormat; /**< Either GL_RGB, GL_RGBA, GL_ALPHA,
+ * GL_LUMINANCE, GL_LUMINANCE_ALPHA,
+ * GL_INTENSITY, GL_COLOR_INDEX,
+ * GL_DEPTH_COMPONENT or GL_DEPTH_STENCIL_EXT
+ * only. Used for choosing TexEnv arithmetic.
+ */
+ GLuint TexFormat; /**< The actual format: MESA_FORMAT_x */
+
+ GLuint Border; /**< 0 or 1 */
+ GLuint Width; /**< = 2^WidthLog2 + 2*Border */
+ GLuint Height; /**< = 2^HeightLog2 + 2*Border */
+ GLuint Depth; /**< = 2^DepthLog2 + 2*Border */
+ GLuint Width2; /**< = Width - 2*Border */
+ GLuint Height2; /**< = Height - 2*Border */
+ GLuint Depth2; /**< = Depth - 2*Border */
+ GLuint WidthLog2; /**< = log2(Width2) */
+ GLuint HeightLog2; /**< = log2(Height2) */
+ GLuint DepthLog2; /**< = log2(Depth2) */
+ GLuint MaxLog2; /**< = MAX(WidthLog2, HeightLog2) */
+ GLfloat WidthScale; /**< used for mipmap LOD computation */
+ GLfloat HeightScale; /**< used for mipmap LOD computation */
+ GLfloat DepthScale; /**< used for mipmap LOD computation */
+ GLboolean IsClientData; /**< Data owned by client? */
+ GLboolean _IsPowerOfTwo; /**< Are all dimensions powers of two? */
+
+ struct gl_texture_object *TexObject; /**< Pointer back to parent object */
+
+ FetchTexelFuncC FetchTexelc; /**< GLchan texel fetch function pointer */
+ FetchTexelFuncF FetchTexelf; /**< Float texel fetch function pointer */
+
+ GLuint RowStride; /**< Padded width in units of texels */
+ GLuint *ImageOffsets; /**< if 3D texture: array [Depth] of offsets to
+ each 2D slice in 'Data', in texels */
+ GLvoid *Data; /**< Image data, accessed via FetchTexel() */
+
+ /**
+ * \name For device driver:
+ */
+ /*@{*/
+ void *DriverData; /**< Arbitrary device driver data */
+ /*@}*/
+};
+
+
+/**
+ * Indexes for cube map faces.
+ */
+typedef enum
+{
+ FACE_POS_X = 0,
+ FACE_NEG_X = 1,
+ FACE_POS_Y = 2,
+ FACE_NEG_Y = 3,
+ FACE_POS_Z = 4,
+ FACE_NEG_Z = 5,
+ MAX_FACES = 6
+} gl_face_index;
+
+
+/**
+ * Texture object state. Contains the array of mipmap images, border color,
+ * wrap modes, filter modes, shadow/texcompare state, and the per-texture
+ * color palette.
+ */
+struct gl_texture_object
+{
+ _glthread_Mutex Mutex; /**< for thread safety */
+ GLint RefCount; /**< reference count */
+ GLuint Name; /**< the user-visible texture object ID */
+ GLenum Target; /**< GL_TEXTURE_1D, GL_TEXTURE_2D, etc. */
+ GLfloat Priority; /**< in [0,1] */
+ union {
+ GLfloat f[4];
+ GLuint ui[4];
+ GLint i[4];
+ } BorderColor; /**< Interpreted according to texture format */
+ GLenum WrapS; /**< S-axis texture image wrap mode */
+ GLenum WrapT; /**< T-axis texture image wrap mode */
+ GLenum WrapR; /**< R-axis texture image wrap mode */
+ GLenum MinFilter; /**< minification filter */
+ GLenum MagFilter; /**< magnification filter */
+ GLfloat MinLod; /**< min lambda, OpenGL 1.2 */
+ GLfloat MaxLod; /**< max lambda, OpenGL 1.2 */
+ GLfloat LodBias; /**< OpenGL 1.4 */
+ GLint BaseLevel; /**< min mipmap level, OpenGL 1.2 */
+ GLint MaxLevel; /**< max mipmap level, OpenGL 1.2 */
+ GLfloat MaxAnisotropy; /**< GL_EXT_texture_filter_anisotropic */
+ GLenum CompareMode; /**< GL_ARB_shadow */
+ GLenum CompareFunc; /**< GL_ARB_shadow */
+ GLfloat CompareFailValue; /**< GL_ARB_shadow_ambient */
+ GLenum DepthMode; /**< GL_ARB_depth_texture */
+ GLint _MaxLevel; /**< actual max mipmap level (q in the spec) */
+ GLfloat _MaxLambda; /**< = _MaxLevel - BaseLevel (q - b in spec) */
+ GLint CropRect[4]; /**< GL_OES_draw_texture */
+ GLenum Swizzle[4]; /**< GL_EXT_texture_swizzle */
+ GLuint _Swizzle; /**< same as Swizzle, but SWIZZLE_* format */
+ GLboolean GenerateMipmap; /**< GL_SGIS_generate_mipmap */
+ GLboolean _Complete; /**< Is texture object complete? */
+ GLboolean _RenderToTexture; /**< Any rendering to this texture? */
+ GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */
+ GLenum sRGBDecode; /**< GL_DECODE_EXT or GL_SKIP_DECODE_EXT */
+
+ /** Actual texture images, indexed by [cube face] and [mipmap level] */
+ struct gl_texture_image *Image[MAX_FACES][MAX_TEXTURE_LEVELS];
+
+ /** GL_EXT_paletted_texture */
+ struct gl_color_table Palette;
+
+ /**
+ * \name For device driver.
+ * Note: instead of attaching driver data to this pointer, it's preferable
+ * to instead use this struct as a base class for your own texture object
+ * class. Driver->NewTextureObject() can be used to implement the
+ * allocation.
+ */
+ void *DriverData; /**< Arbitrary device driver data */
+};
+
+
+/** Up to four combiner sources are possible with GL_NV_texture_env_combine4 */
+#define MAX_COMBINER_TERMS 4
+
+
+/**
+ * Texture combine environment state.
+ */
+struct gl_tex_env_combine_state
+{
+ GLenum ModeRGB; /**< GL_REPLACE, GL_DECAL, GL_ADD, etc. */
+ GLenum ModeA; /**< GL_REPLACE, GL_DECAL, GL_ADD, etc. */
+ /** Source terms: GL_PRIMARY_COLOR, GL_TEXTURE, etc */
+ GLenum SourceRGB[MAX_COMBINER_TERMS];
+ GLenum SourceA[MAX_COMBINER_TERMS];
+ /** Source operands: GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, etc */
+ GLenum OperandRGB[MAX_COMBINER_TERMS];
+ GLenum OperandA[MAX_COMBINER_TERMS];
+ GLuint ScaleShiftRGB; /**< 0, 1 or 2 */
+ GLuint ScaleShiftA; /**< 0, 1 or 2 */
+ GLuint _NumArgsRGB; /**< Number of inputs used for the RGB combiner */
+ GLuint _NumArgsA; /**< Number of inputs used for the A combiner */
+};
+
+
+/**
+ * Texture coord generation state.
+ */
+struct gl_texgen
+{
+ GLenum Mode; /**< GL_EYE_LINEAR, GL_SPHERE_MAP, etc */
+ GLbitfield _ModeBit; /**< TEXGEN_x bit corresponding to Mode */
+ GLfloat ObjectPlane[4];
+ GLfloat EyePlane[4];
+};
+
+
+/**
+ * Texture unit state. Contains enable flags, texture environment/function/
+ * combiners, texgen state, pointers to current texture objects and
+ * post-filter color tables.
+ */
+struct gl_texture_unit
+{
+ GLbitfield Enabled; /**< bitmask of TEXTURE_*_BIT flags */
+ GLbitfield _ReallyEnabled; /**< 0 or exactly one of TEXTURE_*_BIT flags */
+
+ GLenum EnvMode; /**< GL_MODULATE, GL_DECAL, GL_BLEND, etc. */
+ GLfloat EnvColor[4];
+
+ struct gl_texgen GenS;
+ struct gl_texgen GenT;
+ struct gl_texgen GenR;
+ struct gl_texgen GenQ;
+ GLbitfield TexGenEnabled; /**< Bitwise-OR of [STRQ]_BIT values */
+ GLbitfield _GenFlags; /**< Bitwise-OR of Gen[STRQ]._ModeBit */
+
+ GLfloat LodBias; /**< for biasing mipmap levels */
+ GLenum BumpTarget;
+ GLfloat RotMatrix[4]; /* 2x2 matrix */
+
+ /**
+ * \name GL_EXT_texture_env_combine
+ */
+ struct gl_tex_env_combine_state Combine;
+
+ /**
+ * Derived state based on \c EnvMode and the \c BaseFormat of the
+ * currently enabled texture.
+ */
+ struct gl_tex_env_combine_state _EnvMode;
+
+ /**
+ * Currently enabled combiner state. This will point to either
+ * \c Combine or \c _EnvMode.
+ */
+ struct gl_tex_env_combine_state *_CurrentCombine;
+
+ /** Current texture object pointers */
+ struct gl_texture_object *CurrentTex[NUM_TEXTURE_TARGETS];
+
+ /** Points to highest priority, complete and enabled texture object */
+ struct gl_texture_object *_Current;
+
+ /** GL_SGI_texture_color_table */
+ /*@{*/
+ struct gl_color_table ColorTable;
+ struct gl_color_table ProxyColorTable;
+ GLboolean ColorTableEnabled;
+ /*@}*/
+};
+
+
+/**
+ * Texture attribute group (GL_TEXTURE_BIT).
+ */
+struct gl_texture_attrib
+{
+ GLuint CurrentUnit; /**< GL_ACTIVE_TEXTURE */
+ struct gl_texture_unit Unit[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
+
+ struct gl_texture_object *ProxyTex[NUM_TEXTURE_TARGETS];
+
+ /** GL_ARB_seamless_cubemap */
+ GLboolean CubeMapSeamless;
+
+ /** GL_EXT_shared_texture_palette */
+ GLboolean SharedPalette;
+ struct gl_color_table Palette;
+
+ /** Texture units/samplers used by vertex or fragment texturing */
+ GLbitfield _EnabledUnits;
+
+ /** Texture coord units/sets used for fragment texturing */
+ GLbitfield _EnabledCoordUnits;
+
+ /** Texture coord units that have texgen enabled */
+ GLbitfield _TexGenEnabled;
+
+ /** Texture coord units that have non-identity matrices */
+ GLbitfield _TexMatEnabled;
+
+ /** Bitwise-OR of all Texture.Unit[i]._GenFlags */
+ GLbitfield _GenFlags;
+};
+
+
+/**
+ * Transformation attribute group (GL_TRANSFORM_BIT).
+ */
+struct gl_transform_attrib
+{
+ GLenum MatrixMode; /**< Matrix mode */
+ GLfloat EyeUserPlane[MAX_CLIP_PLANES][4]; /**< User clip planes */
+ GLfloat _ClipUserPlane[MAX_CLIP_PLANES][4]; /**< derived */
+ GLbitfield ClipPlanesEnabled; /**< on/off bitmask */
+ GLboolean Normalize; /**< Normalize all normals? */
+ GLboolean RescaleNormals; /**< GL_EXT_rescale_normal */
+ GLboolean RasterPositionUnclipped; /**< GL_IBM_rasterpos_clip */
+ GLboolean DepthClamp; /**< GL_ARB_depth_clamp */
+
+ GLfloat CullEyePos[4];
+ GLfloat CullObjPos[4];
+};
+
+
+/**
+ * Viewport attribute group (GL_VIEWPORT_BIT).
+ */
+struct gl_viewport_attrib
+{
+ GLint X, Y; /**< position */
+ GLsizei Width, Height; /**< size */
+ GLfloat Near, Far; /**< Depth buffer range */
+ GLmatrix _WindowMap; /**< Mapping transformation as a matrix. */
+};
+
+
+/**
+ * GL_ARB_vertex/pixel_buffer_object buffer object
+ */
+struct gl_buffer_object
+{
+ _glthread_Mutex Mutex;
+ GLint RefCount;
+ GLuint Name;
+ GLenum Usage; /**< GL_STREAM_DRAW_ARB, GL_STREAM_READ_ARB, etc. */
+ GLsizeiptrARB Size; /**< Size of buffer storage in bytes */
+ GLubyte *Data; /**< Location of storage either in RAM or VRAM. */
+ /** Fields describing a mapped buffer */
+ /*@{*/
+ GLbitfield AccessFlags; /**< Mask of GL_MAP_x_BIT flags */
+ GLvoid *Pointer; /**< User-space address of mapping */
+ GLintptr Offset; /**< Mapped offset */
+ GLsizeiptr Length; /**< Mapped length */
+ /*@}*/
+ GLboolean Written; /**< Ever written to? (for debugging) */
+ GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */
+};
+
+
+/**
+ * Client pixel packing/unpacking attributes
+ */
+struct gl_pixelstore_attrib
+{
+ GLint Alignment;
+ GLint RowLength;
+ GLint SkipPixels;
+ GLint SkipRows;
+ GLint ImageHeight;
+ GLint SkipImages;
+ GLboolean SwapBytes;
+ GLboolean LsbFirst;
+ GLboolean ClientStorage; /**< GL_APPLE_client_storage */
+ GLboolean Invert; /**< GL_MESA_pack_invert */
+ struct gl_buffer_object *BufferObj; /**< GL_ARB_pixel_buffer_object */
+};
+
+
+/**
+ * Client vertex array attributes
+ */
+struct gl_client_array
+{
+ GLint Size; /**< components per element (1,2,3,4) */
+ GLenum Type; /**< datatype: GL_FLOAT, GL_INT, etc */
+ GLenum Format; /**< default: GL_RGBA, but may be GL_BGRA */
+ GLsizei Stride; /**< user-specified stride */
+ GLsizei StrideB; /**< actual stride in bytes */
+ const GLubyte *Ptr; /**< Points to array data */
+ GLboolean Enabled; /**< Enabled flag is a boolean */
+ GLboolean Normalized; /**< GL_ARB_vertex_program */
+ GLboolean Integer; /**< Integer-valued? */
+ GLuint InstanceDivisor; /**< GL_ARB_instanced_arrays */
+ GLuint _ElementSize; /**< size of each element in bytes */
+
+ struct gl_buffer_object *BufferObj;/**< GL_ARB_vertex_buffer_object */
+ GLuint _MaxElement; /**< max element index into array buffer + 1 */
+};
+
+
+/**
+ * Collection of vertex arrays. Defined by the GL_APPLE_vertex_array_object
+ * extension, but a nice encapsulation in any case.
+ */
+struct gl_array_object
+{
+ /** Name of the array object as received from glGenVertexArrayAPPLE. */
+ GLuint Name;
+
+ GLint RefCount;
+ _glthread_Mutex Mutex;
+ GLboolean VBOonly; /**< require all arrays to live in VBOs? */
+
+ /** Conventional vertex arrays */
+ /*@{*/
+ struct gl_client_array Vertex;
+ struct gl_client_array Weight;
+ struct gl_client_array Normal;
+ struct gl_client_array Color;
+ struct gl_client_array SecondaryColor;
+ struct gl_client_array FogCoord;
+ struct gl_client_array Index;
+ struct gl_client_array EdgeFlag;
+ struct gl_client_array TexCoord[MAX_TEXTURE_COORD_UNITS];
+ struct gl_client_array PointSize;
+ /*@}*/
+
+ /**
+ * Generic arrays for vertex programs/shaders.
+ * For NV vertex programs, these attributes alias and take priority
+ * over the conventional attribs above. For ARB vertex programs and
+ * GLSL vertex shaders, these attributes are separate.
+ */
+ struct gl_client_array VertexAttrib[MAX_VERTEX_GENERIC_ATTRIBS];
+
+ /** Mask of _NEW_ARRAY_* values indicating which arrays are enabled */
+ GLbitfield _Enabled;
+
+ /**
+ * Min of all enabled arrays' _MaxElement. When arrays reside inside VBOs
+ * we can determine the max legal (in bounds) glDrawElements array index.
+ */
+ GLuint _MaxElement;
+};
+
+
+/**
+ * Vertex array state
+ */
+struct gl_array_attrib
+{
+ /** Currently bound array object. See _mesa_BindVertexArrayAPPLE() */
+ struct gl_array_object *ArrayObj;
+
+ /** The default vertex array object */
+ struct gl_array_object *DefaultArrayObj;
+
+ /** Array objects (GL_ARB/APPLE_vertex_array_object) */
+ struct _mesa_HashTable *Objects;
+
+ GLint ActiveTexture; /**< Client Active Texture */
+ GLuint LockFirst; /**< GL_EXT_compiled_vertex_array */
+ GLuint LockCount; /**< GL_EXT_compiled_vertex_array */
+
+ /** GL 3.1 (slightly different from GL_NV_primitive_restart) */
+ GLboolean PrimitiveRestart;
+ GLuint RestartIndex;
+
+ GLbitfield NewState; /**< mask of _NEW_ARRAY_* values */
+
+ /* 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;
+ GLboolean Main; /**< shader defines main() */
+ GLboolean UnresolvedRefs;
+ 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. */
+ GLuint Format; /**< The actual format: MESA_FORMAT_x */
+
+ GLubyte NumSamples;
+
+ GLenum DataType; /**< Type of values passed to the Get/Put functions */
+ GLvoid *Data; /**< This may not be used by some kinds of RBs */
+
+ /* Used to wrap one renderbuffer around another: */
+ struct gl_renderbuffer *Wrapped;
+
+ /* Delete this renderbuffer */
+ void (*Delete)(struct gl_renderbuffer *rb);
+
+ /* Allocate new storage for this renderbuffer */
+ GLboolean (*AllocStorage)(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLenum internalFormat,
+ GLuint width, GLuint height);
+
+ /* Lock/Unlock are called before/after calling the Get/Put functions.
+ * Not sure this is the right place for these yet.
+ void (*Lock)(struct gl_context *ctx, struct gl_renderbuffer *rb);
+ void (*Unlock)(struct gl_context *ctx, struct gl_renderbuffer *rb);
+ */
+
+ /* Return a pointer to the element/pixel at (x,y).
+ * Should return NULL if the buffer memory can't be directly addressed.
+ */
+ void *(*GetPointer)(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLint x, GLint y);
+
+ /* Get/Read a row of values.
+ * The values will be of format _BaseFormat and type DataType.
+ */
+ void (*GetRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
+ GLint x, GLint y, void *values);
+
+ /* Get/Read values at arbitrary locations.
+ * The values will be of format _BaseFormat and type DataType.
+ */
+ void (*GetValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
+ const GLint x[], const GLint y[], void *values);
+
+ /* Put/Write a row of values.
+ * The values will be of format _BaseFormat and type DataType.
+ */
+ void (*PutRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
+ GLint x, GLint y, const void *values, const GLubyte *mask);
+
+ /* Put/Write a row of RGB values. This is a special-case routine that's
+ * only used for RGBA renderbuffers when the source data is GL_RGB. That's
+ * a common case for glDrawPixels and some triangle routines.
+ * The values will be of format GL_RGB and type DataType.
+ */
+ void (*PutRowRGB)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
+ GLint x, GLint y, const void *values, const GLubyte *mask);
+
+
+ /* Put/Write a row of identical values.
+ * The values will be of format _BaseFormat and type DataType.
+ */
+ void (*PutMonoRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
+ GLint x, GLint y, const void *value, const GLubyte *mask);
+
+ /* Put/Write values at arbitrary locations.
+ * The values will be of format _BaseFormat and type DataType.
+ */
+ void (*PutValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
+ const GLint x[], const GLint y[], const void *values,
+ const GLubyte *mask);
+ /* Put/Write identical values at arbitrary locations.
+ * The values will be of format _BaseFormat and type DataType.
+ */
+ void (*PutMonoValues)(struct gl_context *ctx, struct gl_renderbuffer *rb,
+ GLuint count, const GLint x[], const GLint y[],
+ const void *value, const GLubyte *mask);
+};
+
+
+/**
+ * A renderbuffer attachment points to either a texture object (and specifies
+ * a mipmap level, cube face or 3D texture slice) or points to a renderbuffer.
+ */
+struct gl_renderbuffer_attachment
+{
+ GLenum Type; /**< \c GL_NONE or \c GL_TEXTURE or \c GL_RENDERBUFFER_EXT */
+ GLboolean Complete;
+
+ /**
+ * If \c Type is \c GL_RENDERBUFFER_EXT, this stores a pointer to the
+ * application supplied renderbuffer object.
+ */
+ struct gl_renderbuffer *Renderbuffer;
+
+ /**
+ * If \c Type is \c GL_TEXTURE, this stores a pointer to the application
+ * supplied texture object.
+ */
+ struct gl_texture_object *Texture;
+ GLuint TextureLevel; /**< Attached mipmap level. */
+ GLuint CubeMapFace; /**< 0 .. 5, for cube map textures. */
+ GLuint Zoffset; /**< Slice for 3D textures, or layer for both 1D
+ * and 2D array textures */
+};
+
+
+/**
+ * A framebuffer is a collection of renderbuffers (color, depth, stencil, etc).
+ * In C++ terms, think of this as a base class from which device drivers
+ * will make derived classes.
+ */
+struct gl_framebuffer
+{
+ _glthread_Mutex Mutex; /**< for thread safety */
+ /**
+ * If zero, this is a window system framebuffer. If non-zero, this
+ * is a FBO framebuffer; note that for some devices (i.e. those with
+ * a natural pixel coordinate system for FBOs that differs from the
+ * OpenGL/Mesa coordinate system), this means that the viewport,
+ * polygon face orientation, and polygon stipple will have to be inverted.
+ */
+ GLuint Name;
+
+ GLint RefCount;
+ GLboolean DeletePending;
+
+ /**
+ * The framebuffer's visual. Immutable if this is a window system buffer.
+ * Computed from attachments if user-made FBO.
+ */
+ struct gl_config Visual;
+
+ GLboolean Initialized;
+
+ GLuint Width, Height; /**< size of frame buffer in pixels */
+
+ /** \name Drawing bounds (Intersection of buffer size and scissor box) */
+ /*@{*/
+ GLint _Xmin, _Xmax; /**< inclusive */
+ GLint _Ymin, _Ymax; /**< exclusive */
+ /*@}*/
+
+ /** \name Derived Z buffer stuff */
+ /*@{*/
+ GLuint _DepthMax; /**< Max depth buffer value */
+ GLfloat _DepthMaxF; /**< Float max depth buffer value */
+ GLfloat _MRD; /**< minimum resolvable difference in Z values */
+ /*@}*/
+
+ /** One of the GL_FRAMEBUFFER_(IN)COMPLETE_* tokens */
+ GLenum _Status;
+
+ /** Integer color values */
+ GLboolean _IntegerColor;
+
+ /** Array of all renderbuffer attachments, indexed by BUFFER_* tokens. */
+ struct gl_renderbuffer_attachment Attachment[BUFFER_COUNT];
+
+ /* In unextended OpenGL these vars are part of the GL_COLOR_BUFFER
+ * attribute group and GL_PIXEL attribute group, respectively.
+ */
+ GLenum ColorDrawBuffer[MAX_DRAW_BUFFERS];
+ GLenum ColorReadBuffer;
+
+ /** Computed from ColorDraw/ReadBuffer above */
+ GLuint _NumColorDrawBuffers;
+ GLint _ColorDrawBufferIndexes[MAX_DRAW_BUFFERS]; /**< BUFFER_x or -1 */
+ GLint _ColorReadBufferIndex; /* -1 = None */
+ struct gl_renderbuffer *_ColorDrawBuffers[MAX_DRAW_BUFFERS];
+ struct gl_renderbuffer *_ColorReadBuffer;
+
+ /** The Actual depth/stencil buffers to use. May be wrappers around the
+ * depth/stencil buffers attached above. */
+ struct gl_renderbuffer *_DepthBuffer;
+ struct gl_renderbuffer *_StencilBuffer;
+
+ /** Delete this framebuffer */
+ void (*Delete)(struct gl_framebuffer *fb);
+};
+
+
+/**
+ * Precision info for shader datatypes. See glGetShaderPrecisionFormat().
+ */
+struct gl_precision
+{
+ GLushort RangeMin; /**< min value exponent */
+ GLushort RangeMax; /**< max value exponent */
+ GLushort Precision; /**< number of mantissa bits */
+};
+
+
+/**
+ * Limits for vertex and fragment programs/shaders.
+ */
+struct gl_program_constants
+{
+ /* logical limits */
+ GLuint MaxInstructions;
+ GLuint MaxAluInstructions;
+ GLuint MaxTexInstructions;
+ GLuint MaxTexIndirections;
+ GLuint MaxAttribs;
+ GLuint MaxTemps;
+ GLuint MaxAddressRegs;
+ GLuint MaxParameters;
+ GLuint MaxLocalParams;
+ GLuint MaxEnvParams;
+ /* native/hardware limits */
+ GLuint MaxNativeInstructions;
+ GLuint MaxNativeAluInstructions;
+ GLuint MaxNativeTexInstructions;
+ GLuint MaxNativeTexIndirections;
+ GLuint MaxNativeAttribs;
+ GLuint MaxNativeTemps;
+ GLuint MaxNativeAddressRegs;
+ GLuint MaxNativeParameters;
+ /* For shaders */
+ GLuint MaxUniformComponents;
+ /* GL_ARB_geometry_shader4 */
+ GLuint MaxGeometryTextureImageUnits;
+ GLuint MaxGeometryVaryingComponents;
+ GLuint MaxVertexVaryingComponents;
+ GLuint MaxGeometryUniformComponents;
+ GLuint MaxGeometryOutputVertices;
+ GLuint MaxGeometryTotalOutputComponents;
+ /* ES 2.0 and GL_ARB_ES2_compatibility */
+ struct gl_precision LowFloat, MediumFloat, HighFloat;
+ struct gl_precision LowInt, MediumInt, HighInt;
+};
+
+
+/**
+ * Constants which may be overridden by device driver during context creation
+ * but are never changed after that.
+ */
+struct gl_constants
+{
+ GLint MaxTextureMbytes; /**< Max memory per image, in MB */
+ GLint MaxTextureLevels; /**< Max mipmap levels. */
+ GLint Max3DTextureLevels; /**< Max mipmap levels for 3D textures */
+ GLint MaxCubeTextureLevels; /**< Max mipmap levels for cube textures */
+ GLint MaxArrayTextureLayers; /**< Max layers in array textures */
+ GLint MaxTextureRectSize; /**< Max rectangle texture size, in pixes */
+ GLuint MaxTextureCoordUnits;
+ GLuint MaxTextureImageUnits;
+ GLuint MaxVertexTextureImageUnits;
+ GLuint MaxCombinedTextureImageUnits;
+ GLuint MaxTextureUnits; /**< = MIN(CoordUnits, ImageUnits) */
+ GLfloat MaxTextureMaxAnisotropy; /**< GL_EXT_texture_filter_anisotropic */
+ GLfloat MaxTextureLodBias; /**< GL_EXT_texture_lod_bias */
+
+ GLuint MaxArrayLockSize;
+
+ GLint SubPixelBits;
+
+ GLfloat MinPointSize, MaxPointSize; /**< aliased */
+ GLfloat MinPointSizeAA, MaxPointSizeAA; /**< antialiased */
+ GLfloat PointSizeGranularity;
+ GLfloat MinLineWidth, MaxLineWidth; /**< aliased */
+ GLfloat MinLineWidthAA, MaxLineWidthAA; /**< antialiased */
+ GLfloat LineWidthGranularity;
+
+ GLuint MaxColorTableSize;
+
+ GLuint MaxClipPlanes;
+ GLuint MaxLights;
+ GLfloat MaxShininess; /**< GL_NV_light_max_exponent */
+ GLfloat MaxSpotExponent; /**< GL_NV_light_max_exponent */
+
+ GLuint MaxViewportWidth, MaxViewportHeight;
+
+ struct gl_program_constants VertexProgram; /**< GL_ARB_vertex_program */
+ struct gl_program_constants FragmentProgram; /**< GL_ARB_fragment_program */
+ struct gl_program_constants GeometryProgram; /**< GL_ARB_geometry_shader4 */
+ GLuint MaxProgramMatrices;
+ GLuint MaxProgramMatrixStackDepth;
+
+ /** vertex array / buffer object bounds checking */
+ GLboolean CheckArrayBounds;
+
+ GLuint MaxDrawBuffers; /**< GL_ARB_draw_buffers */
+
+ GLuint MaxColorAttachments; /**< GL_EXT_framebuffer_object */
+ GLuint MaxRenderbufferSize; /**< GL_EXT_framebuffer_object */
+ GLuint MaxSamples; /**< GL_ARB_framebuffer_object */
+
+ GLuint MaxVarying; /**< Number of float[4] varying parameters */
+
+ GLuint GLSLVersion; /**< GLSL version supported (ex: 120 = 1.20) */
+
+ /** Which texture units support GL_ATI_envmap_bumpmap as targets */
+ GLbitfield SupportedBumpUnits;
+
+ /**
+ * Maximum amount of time, measured in nanseconds, that the server can wait.
+ */
+ GLuint64 MaxServerWaitTimeout;
+
+ /** GL_EXT_provoking_vertex */
+ GLboolean QuadsFollowProvokingVertexConvention;
+
+ /** OpenGL version 3.0 */
+ GLbitfield ContextFlags; /**< Ex: GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT */
+
+ /** OpenGL version 3.2 */
+ GLbitfield ProfileMask; /**< Mask of CONTEXT_x_PROFILE_BIT */
+
+ /** GL_EXT_transform_feedback */
+ GLuint MaxTransformFeedbackSeparateAttribs;
+ GLuint MaxTransformFeedbackSeparateComponents;
+ GLuint MaxTransformFeedbackInterleavedComponents;
+
+ /** GL_EXT_gpu_shader4 */
+ GLint MinProgramTexelOffset, MaxProgramTexelOffset;
+
+ /* GL_EXT_framebuffer_sRGB */
+ GLboolean sRGBCapable; /* can enable sRGB blend/update on FBOs */
+};
+
+
+/**
+ * Enable flag for each OpenGL extension. Different device drivers will
+ * enable different extensions at runtime.
+ */
+struct gl_extensions
+{
+ GLboolean dummy; /* don't remove this! */
+ GLboolean dummy_true; /* Set true by _mesa_init_extensions(). */
+ GLboolean dummy_false; /* Set false by _mesa_init_extensions(). */
+ GLboolean ARB_ES2_compatibility;
+ GLboolean ARB_blend_func_extended;
+ GLboolean ARB_copy_buffer;
+ GLboolean ARB_depth_buffer_float;
+ GLboolean ARB_depth_clamp;
+ GLboolean ARB_depth_texture;
+ GLboolean ARB_draw_buffers;
+ GLboolean ARB_draw_buffers_blend;
+ GLboolean ARB_draw_elements_base_vertex;
+ GLboolean ARB_draw_instanced;
+ GLboolean ARB_fragment_coord_conventions;
+ GLboolean ARB_fragment_program;
+ GLboolean ARB_fragment_program_shadow;
+ GLboolean ARB_fragment_shader;
+ GLboolean ARB_framebuffer_object;
+ GLboolean ARB_explicit_attrib_location;
+ GLboolean ARB_geometry_shader4;
+ GLboolean ARB_half_float_pixel;
+ GLboolean ARB_half_float_vertex;
+ GLboolean ARB_instanced_arrays;
+ GLboolean ARB_map_buffer_range;
+ GLboolean ARB_multisample;
+ GLboolean ARB_multitexture;
+ GLboolean ARB_occlusion_query;
+ GLboolean ARB_occlusion_query2;
+ GLboolean ARB_point_sprite;
+ GLboolean ARB_sampler_objects;
+ GLboolean ARB_seamless_cube_map;
+ GLboolean ARB_shader_objects;
+ GLboolean ARB_shader_stencil_export;
+ GLboolean ARB_shading_language_100;
+ GLboolean ARB_shadow;
+ GLboolean ARB_shadow_ambient;
+ GLboolean ARB_sync;
+ GLboolean ARB_texture_border_clamp;
+ GLboolean ARB_texture_buffer_object;
+ GLboolean ARB_texture_compression;
+ GLboolean ARB_texture_compression_rgtc;
+ GLboolean ARB_texture_cube_map;
+ GLboolean ARB_texture_env_combine;
+ GLboolean ARB_texture_env_crossbar;
+ GLboolean ARB_texture_env_dot3;
+ GLboolean ARB_texture_float;
+ GLboolean ARB_texture_mirrored_repeat;
+ GLboolean ARB_texture_multisample;
+ GLboolean ARB_texture_non_power_of_two;
+ GLboolean ARB_texture_rg;
+ GLboolean ARB_texture_rgb10_a2ui;
+ GLboolean ARB_timer_query;
+ GLboolean ARB_transform_feedback2;
+ GLboolean ARB_transpose_matrix;
+ GLboolean ARB_uniform_buffer_object;
+ GLboolean ARB_vertex_array_object;
+ GLboolean ARB_vertex_buffer_object;
+ GLboolean ARB_vertex_program;
+ GLboolean ARB_vertex_shader;
+ GLboolean ARB_vertex_type_2_10_10_10_rev;
+ GLboolean ARB_window_pos;
+ GLboolean EXT_abgr;
+ GLboolean EXT_bgra;
+ GLboolean EXT_blend_color;
+ GLboolean EXT_blend_equation_separate;
+ GLboolean EXT_blend_func_separate;
+ GLboolean EXT_blend_logic_op;
+ GLboolean EXT_blend_minmax;
+ GLboolean EXT_blend_subtract;
+ GLboolean EXT_clip_volume_hint;
+ GLboolean EXT_compiled_vertex_array;
+ GLboolean EXT_copy_texture;
+ GLboolean EXT_depth_bounds_test;
+ GLboolean EXT_draw_buffers2;
+ GLboolean EXT_draw_range_elements;
+ GLboolean EXT_fog_coord;
+ GLboolean EXT_framebuffer_blit;
+ GLboolean EXT_framebuffer_multisample;
+ GLboolean EXT_framebuffer_object;
+ GLboolean EXT_framebuffer_sRGB;
+ GLboolean EXT_gpu_program_parameters;
+ GLboolean EXT_gpu_shader4;
+ GLboolean EXT_multi_draw_arrays;
+ GLboolean EXT_paletted_texture;
+ GLboolean EXT_packed_depth_stencil;
+ GLboolean EXT_packed_float;
+ GLboolean EXT_packed_pixels;
+ GLboolean EXT_pixel_buffer_object;
+ GLboolean EXT_point_parameters;
+ GLboolean EXT_polygon_offset;
+ GLboolean EXT_provoking_vertex;
+ GLboolean EXT_rescale_normal;
+ GLboolean EXT_shadow_funcs;
+ GLboolean EXT_secondary_color;
+ GLboolean EXT_separate_shader_objects;
+ GLboolean EXT_separate_specular_color;
+ GLboolean EXT_shared_texture_palette;
+ GLboolean EXT_stencil_wrap;
+ GLboolean EXT_stencil_two_side;
+ GLboolean EXT_subtexture;
+ GLboolean EXT_texture;
+ GLboolean EXT_texture_object;
+ GLboolean EXT_texture3D;
+ GLboolean EXT_texture_array;
+ GLboolean EXT_texture_compression_s3tc;
+ GLboolean EXT_texture_env_add;
+ GLboolean EXT_texture_env_combine;
+ GLboolean EXT_texture_env_dot3;
+ GLboolean EXT_texture_filter_anisotropic;
+ GLboolean EXT_texture_integer;
+ GLboolean EXT_texture_lod_bias;
+ GLboolean EXT_texture_mirror_clamp;
+ GLboolean EXT_texture_shared_exponent;
+ GLboolean EXT_texture_sRGB;
+ GLboolean EXT_texture_sRGB_decode;
+ GLboolean EXT_texture_swizzle;
+ GLboolean EXT_transform_feedback;
+ GLboolean EXT_timer_query;
+ GLboolean EXT_vertex_array;
+ GLboolean EXT_vertex_array_bgra;
+ GLboolean EXT_vertex_array_set;
+ GLboolean OES_standard_derivatives;
+ /* vendor extensions */
+ GLboolean AMD_conservative_depth;
+ GLboolean APPLE_client_storage;
+ GLboolean APPLE_packed_pixels;
+ GLboolean APPLE_vertex_array_object;
+ GLboolean APPLE_object_purgeable;
+ GLboolean ATI_envmap_bumpmap;
+ GLboolean ATI_texture_mirror_once;
+ GLboolean ATI_texture_env_combine3;
+ GLboolean ATI_fragment_shader;
+ GLboolean ATI_separate_stencil;
+ GLboolean IBM_rasterpos_clip;
+ GLboolean IBM_multimode_draw_arrays;
+ GLboolean MESA_pack_invert;
+ GLboolean MESA_resize_buffers;
+ GLboolean MESA_ycbcr_texture;
+ GLboolean MESA_texture_array;
+ GLboolean MESA_texture_signed_rgba;
+ GLboolean NV_blend_square;
+ GLboolean NV_conditional_render;
+ GLboolean NV_fragment_program;
+ GLboolean NV_fragment_program_option;
+ GLboolean NV_light_max_exponent;
+ GLboolean NV_point_sprite;
+ GLboolean NV_primitive_restart;
+ GLboolean NV_texgen_reflection;
+ GLboolean NV_texture_env_combine4;
+ GLboolean NV_texture_rectangle;
+ GLboolean NV_vertex_program;
+ GLboolean NV_vertex_program1_1;
+ GLboolean OES_read_format;
+ GLboolean SGI_texture_color_table;
+ GLboolean SGIS_generate_mipmap;
+ GLboolean SGIS_texture_edge_clamp;
+ GLboolean SGIS_texture_lod;
+ GLboolean TDFX_texture_compression_FXT1;
+ GLboolean S3_s3tc;
+ GLboolean OES_EGL_image;
+ GLboolean OES_draw_texture;
+ GLboolean EXT_texture_format_BGRA8888;
+ GLboolean extension_sentinel;
+ /** The extension string */
+ const GLubyte *String;
+ /** Number of supported extensions */
+ GLuint Count;
+};
+
+
+/**
+ * A stack of matrices (projection, modelview, color, texture, etc).
+ */
+struct gl_matrix_stack
+{
+ GLmatrix *Top; /**< points into Stack */
+ GLmatrix *Stack; /**< array [MaxDepth] of GLmatrix */
+ GLuint Depth; /**< 0 <= Depth < MaxDepth */
+ GLuint MaxDepth; /**< size of Stack[] array */
+ GLuint DirtyFlag; /**< _NEW_MODELVIEW or _NEW_PROJECTION, for example */
+};
+
+
+/**
+ * \name Bits for image transfer operations
+ * \sa __struct gl_contextRec::ImageTransferState.
+ */
+/*@{*/
+#define IMAGE_SCALE_BIAS_BIT 0x1
+#define IMAGE_SHIFT_OFFSET_BIT 0x2
+#define IMAGE_MAP_COLOR_BIT 0x4
+#define IMAGE_CLAMP_BIT 0x800
+
+
+/** Pixel Transfer ops */
+#define IMAGE_BITS (IMAGE_SCALE_BIAS_BIT | \
+ IMAGE_SHIFT_OFFSET_BIT | \
+ IMAGE_MAP_COLOR_BIT)
+
+/**
+ * \name Bits to indicate what state has changed.
+ */
+/*@{*/
+#define _NEW_MODELVIEW (1 << 0) /**< gl_context::ModelView */
+#define _NEW_PROJECTION (1 << 1) /**< gl_context::Projection */
+#define _NEW_TEXTURE_MATRIX (1 << 2) /**< gl_context::TextureMatrix */
+#define _NEW_COLOR (1 << 3) /**< gl_context::Color */
+#define _NEW_DEPTH (1 << 4) /**< gl_context::Depth */
+#define _NEW_EVAL (1 << 5) /**< gl_context::Eval, EvalMap */
+#define _NEW_FOG (1 << 6) /**< gl_context::Fog */
+#define _NEW_HINT (1 << 7) /**< gl_context::Hint */
+#define _NEW_LIGHT (1 << 8) /**< gl_context::Light */
+#define _NEW_LINE (1 << 9) /**< gl_context::Line */
+#define _NEW_PIXEL (1 << 10) /**< gl_context::Pixel */
+#define _NEW_POINT (1 << 11) /**< gl_context::Point */
+#define _NEW_POLYGON (1 << 12) /**< gl_context::Polygon */
+#define _NEW_POLYGONSTIPPLE (1 << 13) /**< gl_context::PolygonStipple */
+#define _NEW_SCISSOR (1 << 14) /**< gl_context::Scissor */
+#define _NEW_STENCIL (1 << 15) /**< gl_context::Stencil */
+#define _NEW_TEXTURE (1 << 16) /**< gl_context::Texture */
+#define _NEW_TRANSFORM (1 << 17) /**< gl_context::Transform */
+#define _NEW_VIEWPORT (1 << 18) /**< gl_context::Viewport */
+#define _NEW_PACKUNPACK (1 << 19) /**< gl_context::Pack, Unpack */
+#define _NEW_ARRAY (1 << 20) /**< gl_context::Array */
+#define _NEW_RENDERMODE (1 << 21) /**< gl_context::RenderMode, etc */
+#define _NEW_BUFFERS (1 << 22) /**< gl_context::Visual, DrawBuffer, */
+#define _NEW_CURRENT_ATTRIB (1 << 23) /**< gl_context::Current */
+#define _NEW_MULTISAMPLE (1 << 24) /**< gl_context::Multisample */
+#define _NEW_TRACK_MATRIX (1 << 25) /**< gl_context::VertexProgram */
+#define _NEW_PROGRAM (1 << 26) /**< New program/shader state */
+#define _NEW_PROGRAM_CONSTANTS (1 << 27)
+#define _NEW_BUFFER_OBJECT (1 << 28)
+#define _NEW_ALL ~0
+/*@}*/
+
+
+/**
+ * \name Bits to track array state changes
+ *
+ * Also used to summarize array enabled.
+ */
+/*@{*/
+#define _NEW_ARRAY_VERTEX VERT_BIT_POS
+#define _NEW_ARRAY_WEIGHT VERT_BIT_WEIGHT
+#define _NEW_ARRAY_NORMAL VERT_BIT_NORMAL
+#define _NEW_ARRAY_COLOR0 VERT_BIT_COLOR0
+#define _NEW_ARRAY_COLOR1 VERT_BIT_COLOR1
+#define _NEW_ARRAY_FOGCOORD VERT_BIT_FOG
+#define _NEW_ARRAY_INDEX VERT_BIT_COLOR_INDEX
+#define _NEW_ARRAY_EDGEFLAG VERT_BIT_EDGEFLAG
+#define _NEW_ARRAY_POINT_SIZE VERT_BIT_COLOR_INDEX /* aliased */
+#define _NEW_ARRAY_TEXCOORD_0 VERT_BIT_TEX0
+#define _NEW_ARRAY_TEXCOORD_1 VERT_BIT_TEX1
+#define _NEW_ARRAY_TEXCOORD_2 VERT_BIT_TEX2
+#define _NEW_ARRAY_TEXCOORD_3 VERT_BIT_TEX3
+#define _NEW_ARRAY_TEXCOORD_4 VERT_BIT_TEX4
+#define _NEW_ARRAY_TEXCOORD_5 VERT_BIT_TEX5
+#define _NEW_ARRAY_TEXCOORD_6 VERT_BIT_TEX6
+#define _NEW_ARRAY_TEXCOORD_7 VERT_BIT_TEX7
+#define _NEW_ARRAY_ATTRIB_0 VERT_BIT_GENERIC0 /* start at bit 16 */
+#define _NEW_ARRAY_ALL 0xffffffff
+
+
+#define _NEW_ARRAY_TEXCOORD(i) (_NEW_ARRAY_TEXCOORD_0 << (i))
+#define _NEW_ARRAY_ATTRIB(i) (_NEW_ARRAY_ATTRIB_0 << (i))
+/*@}*/
+
+
+
+/**
+ * \name A bunch of flags that we think might be useful to drivers.
+ *
+ * Set in the __struct gl_contextRec::_TriangleCaps bitfield.
+ */
+/*@{*/
+#define DD_FLATSHADE 0x1
+#define DD_SEPARATE_SPECULAR 0x2
+#define DD_TRI_CULL_FRONT_BACK 0x4 /* special case on some hw */
+#define DD_TRI_LIGHT_TWOSIDE 0x8
+#define DD_TRI_UNFILLED 0x10
+#define DD_TRI_SMOOTH 0x20
+#define DD_TRI_STIPPLE 0x40
+#define DD_TRI_OFFSET 0x80
+#define DD_LINE_SMOOTH 0x100
+#define DD_LINE_STIPPLE 0x200
+#define DD_POINT_SMOOTH 0x400
+#define DD_POINT_ATTEN 0x800
+#define DD_TRI_TWOSTENCIL 0x1000
+/*@}*/
+
+
+/**
+ * \name Define the state changes under which each of these bits might change
+ */
+/*@{*/
+#define _DD_NEW_FLATSHADE _NEW_LIGHT
+#define _DD_NEW_SEPARATE_SPECULAR (_NEW_LIGHT | _NEW_FOG | _NEW_PROGRAM)
+#define _DD_NEW_TRI_CULL_FRONT_BACK _NEW_POLYGON
+#define _DD_NEW_TRI_LIGHT_TWOSIDE _NEW_LIGHT
+#define _DD_NEW_TRI_UNFILLED _NEW_POLYGON
+#define _DD_NEW_TRI_SMOOTH _NEW_POLYGON
+#define _DD_NEW_TRI_STIPPLE _NEW_POLYGON
+#define _DD_NEW_TRI_OFFSET _NEW_POLYGON
+#define _DD_NEW_LINE_SMOOTH _NEW_LINE
+#define _DD_NEW_LINE_STIPPLE _NEW_LINE
+#define _DD_NEW_LINE_WIDTH _NEW_LINE
+#define _DD_NEW_POINT_SMOOTH _NEW_POINT
+#define _DD_NEW_POINT_SIZE _NEW_POINT
+#define _DD_NEW_POINT_ATTEN _NEW_POINT
+/*@}*/
+
+
+/**
+ * Composite state flags
+ */
+/*@{*/
+#define _MESA_NEW_NEED_EYE_COORDS (_NEW_LIGHT | \
+ _NEW_TEXTURE | \
+ _NEW_POINT | \
+ _NEW_PROGRAM | \
+ _NEW_MODELVIEW)
+
+#define _MESA_NEW_NEED_NORMALS (_NEW_LIGHT | \
+ _NEW_TEXTURE)
+
+#define _MESA_NEW_TRANSFER_STATE (_NEW_PIXEL)
+/*@}*/
+
+
+
+
+/* This has to be included here. */
+#include "dd.h"
+
+
+/**
+ * Display list flags.
+ * Strictly this is a tnl-private concept, but it doesn't seem
+ * worthwhile adding a tnl private structure just to hold this one bit
+ * of information:
+ */
+#define DLIST_DANGLING_REFS 0x1
+
+
+/** Opaque declaration of display list payload data type */
+union gl_dlist_node;
+
+
+/**
+ * Provide a location where information about a display list can be
+ * collected. Could be extended with driverPrivate structures,
+ * etc. in the future.
+ */
+struct gl_display_list
+{
+ GLuint Name;
+ GLbitfield Flags; /**< DLIST_x flags */
+ /** The dlist commands are in a linked list of nodes */
+ union gl_dlist_node *Head;
+};
+
+
+/**
+ * State used during display list compilation and execution.
+ */
+struct gl_dlist_state
+{
+ GLuint CallDepth; /**< Current recursion calling depth */
+
+ struct gl_display_list *CurrentList; /**< List currently being compiled */
+ union gl_dlist_node *CurrentBlock; /**< Pointer to current block of nodes */
+ GLuint CurrentPos; /**< Index into current block of nodes */
+
+ GLvertexformat ListVtxfmt;
+
+ GLubyte ActiveAttribSize[VERT_ATTRIB_MAX];
+ GLfloat CurrentAttrib[VERT_ATTRIB_MAX][4];
+
+ GLubyte ActiveMaterialSize[MAT_ATTRIB_MAX];
+ GLfloat CurrentMaterial[MAT_ATTRIB_MAX][4];
+
+ GLubyte ActiveIndex;
+ GLfloat CurrentIndex;
+
+ GLubyte ActiveEdgeFlag;
+ GLboolean CurrentEdgeFlag;
+
+ struct {
+ /* State known to have been set by the currently-compiling display
+ * list. Used to eliminate some redundant state changes.
+ */
+ GLenum ShadeModel;
+ } Current;
+};
+
+
+/**
+ * Enum for the OpenGL APIs we know about and may support.
+ */
+typedef enum
+{
+ API_OPENGL,
+ API_OPENGLES,
+ API_OPENGLES2
+} gl_api;
+
+
+/**
+ * Mesa rendering context.
+ *
+ * This is the central context data structure for Mesa. Almost all
+ * OpenGL state is contained in this structure.
+ * Think of this as a base class from which device drivers will derive
+ * sub classes.
+ *
+ * The struct gl_context typedef names this structure.
+ */
+struct gl_context
+{
+ /** State possibly shared with other contexts in the address space */
+ struct gl_shared_state *Shared;
+
+ /** \name API function pointer tables */
+ /*@{*/
+ gl_api API;
+ struct _glapi_table *Save; /**< Display list save functions */
+ struct _glapi_table *Exec; /**< Execute functions */
+ struct _glapi_table *CurrentDispatch; /**< == Save or Exec !! */
+ /*@}*/
+
+ struct gl_config Visual;
+ struct gl_framebuffer *DrawBuffer; /**< buffer for writing */
+ struct gl_framebuffer *ReadBuffer; /**< buffer for reading */
+ struct gl_framebuffer *WinSysDrawBuffer; /**< set with MakeCurrent */
+ struct gl_framebuffer *WinSysReadBuffer; /**< set with MakeCurrent */
+
+ /**
+ * Device driver function pointer table
+ */
+ struct dd_function_table Driver;
+
+ void *DriverCtx; /**< Points to device driver context/state */
+
+ /** Core/Driver constants */
+ struct gl_constants Const;
+
+ /** \name The various 4x4 matrix stacks */
+ /*@{*/
+ struct gl_matrix_stack ModelviewMatrixStack;
+ struct gl_matrix_stack ProjectionMatrixStack;
+ struct gl_matrix_stack TextureMatrixStack[MAX_TEXTURE_UNITS];
+ struct gl_matrix_stack ProgramMatrixStack[MAX_PROGRAM_MATRICES];
+ struct gl_matrix_stack *CurrentStack; /**< Points to one of the above stacks */
+ /*@}*/
+
+ /** Combined modelview and projection matrix */
+ GLmatrix _ModelProjectMatrix;
+
+ /** \name Display lists */
+ struct gl_dlist_state ListState;
+
+ GLboolean ExecuteFlag; /**< Execute GL commands? */
+ GLboolean CompileFlag; /**< Compile GL commands into display list? */
+
+ /** Extension information */
+ struct gl_extensions Extensions;
+
+ /** Version info */
+ GLuint VersionMajor, VersionMinor;
+ char *VersionString;
+
+ /** \name State attribute stack (for glPush/PopAttrib) */
+ /*@{*/
+ GLuint AttribStackDepth;
+ struct gl_attrib_node *AttribStack[MAX_ATTRIB_STACK_DEPTH];
+ /*@}*/
+
+ /** \name Renderer attribute groups
+ *
+ * We define a struct for each attribute group to make pushing and popping
+ * attributes easy. Also it's a good organization.
+ */
+ /*@{*/
+ struct gl_accum_attrib Accum; /**< Accum buffer attributes */
+ struct gl_colorbuffer_attrib Color; /**< Color buffer attributes */
+ struct gl_current_attrib Current; /**< Current attributes */
+ struct gl_depthbuffer_attrib Depth; /**< Depth buffer attributes */
+ struct gl_eval_attrib Eval; /**< Eval attributes */
+ struct gl_fog_attrib Fog; /**< Fog attributes */
+ struct gl_hint_attrib Hint; /**< Hint attributes */
+ struct gl_light_attrib Light; /**< Light attributes */
+ struct gl_line_attrib Line; /**< Line attributes */
+ struct gl_list_attrib List; /**< List attributes */
+ struct gl_multisample_attrib Multisample;
+ struct gl_pixel_attrib Pixel; /**< Pixel attributes */
+ struct gl_point_attrib Point; /**< Point attributes */
+ struct gl_polygon_attrib Polygon; /**< Polygon attributes */
+ GLuint PolygonStipple[32]; /**< Polygon stipple */
+ struct gl_scissor_attrib Scissor; /**< Scissor attributes */
+ struct gl_stencil_attrib Stencil; /**< Stencil buffer attributes */
+ struct gl_texture_attrib Texture; /**< Texture attributes */
+ struct gl_transform_attrib Transform; /**< Transformation attributes */
+ struct gl_viewport_attrib Viewport; /**< Viewport attributes */
+ /*@}*/
+
+ /** \name Client attribute stack */
+ /*@{*/
+ GLuint ClientAttribStackDepth;
+ struct gl_attrib_node *ClientAttribStack[MAX_CLIENT_ATTRIB_STACK_DEPTH];
+ /*@}*/
+
+ /** \name Client attribute groups */
+ /*@{*/
+ struct gl_array_attrib Array; /**< Vertex arrays */
+ struct gl_pixelstore_attrib Pack; /**< Pixel packing */
+ struct gl_pixelstore_attrib Unpack; /**< Pixel unpacking */
+ struct gl_pixelstore_attrib DefaultPacking; /**< Default params */
+ /*@}*/
+
+ /** \name Other assorted state (not pushed/popped on attribute stack) */
+ /*@{*/
+ struct gl_pixelmaps PixelMaps;
+
+ struct gl_evaluators EvalMap; /**< All evaluators */
+ struct gl_feedback Feedback; /**< Feedback */
+ struct gl_selection Select; /**< Selection */
+
+ struct gl_program_state Program; /**< general program state */
+ struct gl_vertex_program_state VertexProgram;
+ struct gl_fragment_program_state FragmentProgram;
+ struct gl_geometry_program_state GeometryProgram;
+ struct gl_ati_fragment_shader_state ATIFragmentShader;
+
+ struct gl_shader_state Shader; /**< GLSL shader object state */
+ struct gl_shader_compiler_options ShaderCompilerOptions[MESA_SHADER_TYPES];
+
+ struct gl_query_state Query; /**< occlusion, timer queries */
+
+ struct gl_transform_feedback TransformFeedback;
+
+ struct gl_buffer_object *CopyReadBuffer; /**< GL_ARB_copy_buffer */
+ struct gl_buffer_object *CopyWriteBuffer; /**< GL_ARB_copy_buffer */
+ /*@}*/
+
+ struct gl_meta_state *Meta; /**< for "meta" operations */
+
+ /* GL_EXT_framebuffer_object */
+ struct gl_renderbuffer *CurrentRenderbuffer;
+
+ GLenum ErrorValue; /**< Last error code */
+
+ /**
+ * Recognize and silence repeated error debug messages in buggy apps.
+ */
+ const char *ErrorDebugFmtString;
+ GLuint ErrorDebugCount;
+
+ GLenum RenderMode; /**< either GL_RENDER, GL_SELECT, GL_FEEDBACK */
+ GLbitfield NewState; /**< bitwise-or of _NEW_* flags */
+
+ GLboolean ViewportInitialized; /**< has viewport size been initialized? */
+
+ GLbitfield varying_vp_inputs; /**< mask of VERT_BIT_* flags */
+
+ /** \name Derived state */
+ /*@{*/
+ /** Bitwise-or of DD_* flags. Note that this bitfield may be used before
+ * state validation so they need to always be current.
+ */
+ GLbitfield _TriangleCaps;
+ GLbitfield _ImageTransferState;/**< bitwise-or of IMAGE_*_BIT flags */
+ GLfloat _EyeZDir[3];
+ GLfloat _ModelViewInvScale;
+ GLboolean _NeedEyeCoords;
+ GLboolean _ForceEyeCoords;
+
+ GLuint TextureStateTimestamp; /**< detect changes to shared state */
+
+ struct gl_shine_tab *_ShineTable[2]; /**< Active shine tables */
+ struct gl_shine_tab *_ShineTabList; /**< MRU list of inactive shine tables */
+ /**@}*/
+
+ struct gl_list_extensions *ListExt; /**< driver dlist extensions */
+
+ /** \name For debugging/development only */
+ /*@{*/
+ GLboolean FirstTimeCurrent;
+ /*@}*/
+
+ /** Dither disable via MESA_NO_DITHER env var */
+ GLboolean NoDither;
+
+ /** 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/queryobj.c b/mesalib/src/mesa/main/queryobj.c
index c97179f1e..dc9f18a65 100644
--- a/mesalib/src/mesa/main/queryobj.c
+++ b/mesalib/src/mesa/main/queryobj.c
@@ -25,6 +25,7 @@
#include "glheader.h"
#include "context.h"
+#include "enums.h"
#include "hash.h"
#include "imports.h"
#include "queryobj.h"
@@ -179,6 +180,9 @@ _mesa_GenQueriesARB(GLsizei n, GLuint *ids)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glGenQueries(%d)\n", n);
+
if (n < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)");
return;
@@ -215,6 +219,9 @@ _mesa_DeleteQueriesARB(GLsizei n, const GLuint *ids)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glDeleeteQueries(%d)\n", n);
+
if (n < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
return;
@@ -246,6 +253,9 @@ _mesa_IsQueryARB(GLuint id)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glIsQuery(%u)\n", id);
+
if (id && _mesa_lookup_query_object(ctx, id))
return GL_TRUE;
else
@@ -260,6 +270,10 @@ _mesa_BeginQueryARB(GLenum target, GLuint id)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glBeginQuery(%s, %u)\n",
+ _mesa_lookup_enum_by_nr(target), id);
+
FLUSH_VERTICES(ctx, _NEW_DEPTH);
bindpt = get_query_binding_point(ctx, target);
@@ -311,6 +325,9 @@ _mesa_EndQueryARB(GLenum target)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glEndQuery(%s)\n", _mesa_lookup_enum_by_nr(target));
+
FLUSH_VERTICES(ctx, _NEW_DEPTH);
bindpt = get_query_binding_point(ctx, target);
@@ -341,6 +358,11 @@ _mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glGetQueryiv(%s, %s)\n",
+ _mesa_lookup_enum_by_nr(target),
+ _mesa_lookup_enum_by_nr(pname));
+
bindpt = get_query_binding_point(ctx, target);
if (!bindpt) {
_mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
@@ -370,6 +392,10 @@ _mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id,
+ _mesa_lookup_enum_by_nr(pname));
+
if (id)
q = _mesa_lookup_query_object(ctx, id);
@@ -417,6 +443,10 @@ _mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id,
+ _mesa_lookup_enum_by_nr(pname));
+
if (id)
q = _mesa_lookup_query_object(ctx, id);
@@ -467,6 +497,10 @@ _mesa_GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id,
+ _mesa_lookup_enum_by_nr(pname));
+
if (id)
q = _mesa_lookup_query_object(ctx, id);
@@ -504,6 +538,10 @@ _mesa_GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id,
+ _mesa_lookup_enum_by_nr(pname));
+
if (id)
q = _mesa_lookup_query_object(ctx, id);
diff --git a/mesalib/src/mesa/main/shaderapi.c b/mesalib/src/mesa/main/shaderapi.c
index f2b8aa449..252cda845 100644
--- a/mesalib/src/mesa/main/shaderapi.c
+++ b/mesalib/src/mesa/main/shaderapi.c
@@ -1,1931 +1,1942 @@
-/*
- * Mesa 3-D graphics library
- *
- * Copyright (C) 2004-2008 Brian Paul All Rights Reserved.
- * Copyright (C) 2009-2010 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 shaderapi.c
- * \author Brian Paul
- *
- * Implementation of GLSL-related API functions.
- * The glUniform* functions are in uniforms.c
- *
- *
- * XXX things to do:
- * 1. Check that the right error code is generated for all _mesa_error() calls.
- * 2. Insert FLUSH_VERTICES calls in various places
- */
-
-
-#include "main/glheader.h"
-#include "main/context.h"
-#include "main/dispatch.h"
-#include "main/enums.h"
-#include "main/hash.h"
-#include "main/mfeatures.h"
-#include "main/mtypes.h"
-#include "main/shaderapi.h"
-#include "main/shaderobj.h"
-#include "program/program.h"
-#include "program/prog_parameter.h"
-#include "program/prog_uniform.h"
-#include "ralloc.h"
-#include <stdbool.h>
-#include "../glsl/glsl_parser_extras.h"
-
-/** Define this to enable shader substitution (see below) */
-#define SHADER_SUBST 0
-
-
-/**
- * Return mask of GLSL_x flags by examining the MESA_GLSL env var.
- */
-static GLbitfield
-get_shader_flags(void)
-{
- GLbitfield flags = 0x0;
- const char *env = _mesa_getenv("MESA_GLSL");
-
- if (env) {
- if (strstr(env, "dump"))
- flags |= GLSL_DUMP;
- if (strstr(env, "log"))
- flags |= GLSL_LOG;
- if (strstr(env, "nopvert"))
- flags |= GLSL_NOP_VERT;
- if (strstr(env, "nopfrag"))
- flags |= GLSL_NOP_FRAG;
- if (strstr(env, "nopt"))
- flags |= GLSL_NO_OPT;
- else if (strstr(env, "opt"))
- flags |= GLSL_OPT;
- if (strstr(env, "uniform"))
- flags |= GLSL_UNIFORMS;
- if (strstr(env, "useprog"))
- flags |= GLSL_USE_PROG;
- }
-
- return flags;
-}
-
-
-/**
- * Initialize context's shader state.
- */
-void
-_mesa_init_shader_state(struct gl_context *ctx)
-{
- /* Device drivers may override these to control what kind of instructions
- * are generated by the GLSL compiler.
- */
- struct gl_shader_compiler_options options;
- gl_shader_type sh;
-
- memset(&options, 0, sizeof(options));
- options.MaxUnrollIterations = 32;
-
- /* Default pragma settings */
- options.DefaultPragmas.Optimize = GL_TRUE;
-
- for (sh = 0; sh < MESA_SHADER_TYPES; ++sh)
- memcpy(&ctx->ShaderCompilerOptions[sh], &options, sizeof(options));
-
- ctx->Shader.Flags = get_shader_flags();
-}
-
-
-/**
- * Free the per-context shader-related state.
- */
-void
-_mesa_free_shader_state(struct gl_context *ctx)
-{
- _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentVertexProgram, NULL);
- _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentGeometryProgram,
- NULL);
- _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentFragmentProgram,
- NULL);
- _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL);
-}
-
-
-/**
- * Return the size of the given GLSL datatype, in floats (components).
- */
-GLint
-_mesa_sizeof_glsl_type(GLenum type)
-{
- switch (type) {
- case GL_FLOAT:
- case GL_INT:
- case GL_BOOL:
- case GL_SAMPLER_1D:
- case GL_SAMPLER_2D:
- case GL_SAMPLER_3D:
- case GL_SAMPLER_CUBE:
- case GL_SAMPLER_1D_SHADOW:
- case GL_SAMPLER_2D_SHADOW:
- case GL_SAMPLER_2D_RECT_ARB:
- case GL_SAMPLER_2D_RECT_SHADOW_ARB:
- case GL_SAMPLER_1D_ARRAY_EXT:
- case GL_SAMPLER_2D_ARRAY_EXT:
- case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
- case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
- case GL_SAMPLER_CUBE_SHADOW_EXT:
- return 1;
- case GL_FLOAT_VEC2:
- case GL_INT_VEC2:
- case GL_UNSIGNED_INT_VEC2:
- case GL_BOOL_VEC2:
- return 2;
- case GL_FLOAT_VEC3:
- case GL_INT_VEC3:
- case GL_UNSIGNED_INT_VEC3:
- case GL_BOOL_VEC3:
- return 3;
- case GL_FLOAT_VEC4:
- case GL_INT_VEC4:
- case GL_UNSIGNED_INT_VEC4:
- case GL_BOOL_VEC4:
- return 4;
- case GL_FLOAT_MAT2:
- case GL_FLOAT_MAT2x3:
- case GL_FLOAT_MAT2x4:
- return 8; /* two float[4] vectors */
- case GL_FLOAT_MAT3:
- case GL_FLOAT_MAT3x2:
- case GL_FLOAT_MAT3x4:
- return 12; /* three float[4] vectors */
- case GL_FLOAT_MAT4:
- case GL_FLOAT_MAT4x2:
- case GL_FLOAT_MAT4x3:
- return 16; /* four float[4] vectors */
- default:
- _mesa_problem(NULL, "Invalid type in _mesa_sizeof_glsl_type()");
- return 1;
- }
-}
-
-
-/**
- * Copy string from <src> to <dst>, up to maxLength characters, returning
- * length of <dst> in <length>.
- * \param src the strings source
- * \param maxLength max chars to copy
- * \param length returns number of chars copied
- * \param dst the string destination
- */
-void
-_mesa_copy_string(GLchar *dst, GLsizei maxLength,
- GLsizei *length, const GLchar *src)
-{
- GLsizei len;
- for (len = 0; len < maxLength - 1 && src && src[len]; len++)
- dst[len] = src[len];
- if (maxLength > 0)
- dst[len] = 0;
- if (length)
- *length = len;
-}
-
-
-
-/**
- * Confirm that the a shader type is valid and supported by the implementation
- *
- * \param ctx Current GL context
- * \param type Shader target
- *
- */
-static bool
-validate_shader_target(const struct gl_context *ctx, GLenum type)
-{
- switch (type) {
-#if FEATURE_ARB_fragment_shader
- case GL_FRAGMENT_SHADER:
- return ctx->Extensions.ARB_fragment_shader;
-#endif
-#if FEATURE_ARB_vertex_shader
- case GL_VERTEX_SHADER:
- return ctx->Extensions.ARB_vertex_shader;
-#endif
-#if FEATURE_ARB_geometry_shader4
- case GL_GEOMETRY_SHADER_ARB:
- return ctx->Extensions.ARB_geometry_shader4;
-#endif
- default:
- return false;
- }
-}
-
-
-/**
- * Find the length of the longest transform feedback varying name
- * which was specified with glTransformFeedbackVaryings().
- */
-static GLint
-longest_feedback_varying_name(const struct gl_shader_program *shProg)
-{
- GLuint i;
- GLint max = 0;
- for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
- GLint len = strlen(shProg->TransformFeedback.VaryingNames[i]);
- if (len > max)
- max = len;
- }
- return max;
-}
-
-
-
-static GLboolean
-is_program(struct gl_context *ctx, GLuint name)
-{
- struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
- return shProg ? GL_TRUE : GL_FALSE;
-}
-
-
-static GLboolean
-is_shader(struct gl_context *ctx, GLuint name)
-{
- struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
- return shader ? GL_TRUE : GL_FALSE;
-}
-
-
-/**
- * Attach shader to a shader program.
- */
-static void
-attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
-{
- struct gl_shader_program *shProg;
- struct gl_shader *sh;
- GLuint i, n;
-
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
- if (!shProg)
- return;
-
- sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
- if (!sh) {
- return;
- }
-
- n = shProg->NumShaders;
- for (i = 0; i < n; i++) {
- if (shProg->Shaders[i] == sh) {
- /* The shader is already attched to this program. The
- * GL_ARB_shader_objects spec says:
- *
- * "The error INVALID_OPERATION is generated by AttachObjectARB
- * if <obj> is already attached to <containerObj>."
- */
- _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader");
- return;
- }
- }
-
- /* grow list */
- shProg->Shaders = (struct gl_shader **)
- _mesa_realloc(shProg->Shaders,
- n * sizeof(struct gl_shader *),
- (n + 1) * sizeof(struct gl_shader *));
- if (!shProg->Shaders) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
- return;
- }
-
- /* append */
- shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
- _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
- shProg->NumShaders++;
-}
-
-
-static GLint
-get_attrib_location(struct gl_context *ctx, GLuint program, const GLchar *name)
-{
- struct gl_shader_program *shProg
- = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
-
- if (!shProg) {
- return -1;
- }
-
- if (!shProg->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetAttribLocation(program not linked)");
- return -1;
- }
-
- if (!name)
- return -1;
-
- if (shProg->VertexProgram) {
- const struct gl_program_parameter_list *attribs =
- shProg->VertexProgram->Base.Attributes;
- if (attribs) {
- GLint i = _mesa_lookup_parameter_index(attribs, -1, name);
- if (i >= 0) {
- return attribs->Parameters[i].StateIndexes[0];
- }
- }
- }
- return -1;
-}
-
-
-static void
-bind_attrib_location(struct gl_context *ctx, GLuint program, GLuint index,
- const GLchar *name)
-{
- struct gl_shader_program *shProg;
- const GLint size = -1; /* unknown size */
- GLint i, oldIndex;
- GLenum datatype = GL_FLOAT_VEC4;
-
- shProg = _mesa_lookup_shader_program_err(ctx, program,
- "glBindAttribLocation");
- if (!shProg) {
- return;
- }
-
- if (!name)
- return;
-
- if (strncmp(name, "gl_", 3) == 0) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindAttribLocation(illegal name)");
- return;
- }
-
- if (index >= ctx->Const.VertexProgram.MaxAttribs) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
- return;
- }
-
- if (shProg->LinkStatus) {
- /* get current index/location for the attribute */
- oldIndex = get_attrib_location(ctx, program, name);
- }
- else {
- oldIndex = -1;
- }
-
- /* this will replace the current value if it's already in the list */
- i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
- if (i < 0) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
- return;
- }
-
- /*
- * Note that this attribute binding won't go into effect until
- * glLinkProgram is called again.
- */
-}
-
-
-static void
-bind_frag_data_location(struct gl_context *ctx, GLuint program,
- GLuint colorNumber, const GLchar *name)
-{
- _mesa_problem(ctx, "bind_frag_data_location() not implemented yet");
-}
-
-
-static GLuint
-create_shader(struct gl_context *ctx, GLenum type)
-{
- struct gl_shader *sh;
- GLuint name;
-
- if (!validate_shader_target(ctx, type)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
- return 0;
- }
-
- name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
- sh = ctx->Driver.NewShader(ctx, name, type);
- _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
-
- return name;
-}
-
-
-static GLuint
-create_shader_program(struct gl_context *ctx)
-{
- GLuint name;
- struct gl_shader_program *shProg;
-
- name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
-
- shProg = ctx->Driver.NewShaderProgram(ctx, name);
-
- _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
-
- assert(shProg->RefCount == 1);
-
- return name;
-}
-
-
-/**
- * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
- * DeleteProgramARB.
- */
-static void
-delete_shader_program(struct gl_context *ctx, GLuint name)
-{
- /*
- * NOTE: deleting shaders/programs works a bit differently than
- * texture objects (and buffer objects, etc). Shader/program
- * handles/IDs exist in the hash table until the object is really
- * deleted (refcount==0). With texture objects, the handle/ID is
- * removed from the hash table in glDeleteTextures() while the tex
- * object itself might linger until its refcount goes to zero.
- */
- struct gl_shader_program *shProg;
-
- shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
- if (!shProg)
- return;
-
- shProg->DeletePending = GL_TRUE;
-
- /* effectively, decr shProg's refcount */
- _mesa_reference_shader_program(ctx, &shProg, NULL);
-}
-
-
-static void
-delete_shader(struct gl_context *ctx, GLuint shader)
-{
- struct gl_shader *sh;
-
- sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
- if (!sh)
- return;
-
- sh->DeletePending = GL_TRUE;
-
- /* effectively, decr sh's refcount */
- _mesa_reference_shader(ctx, &sh, NULL);
-}
-
-
-static void
-detach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
-{
- struct gl_shader_program *shProg;
- GLuint n;
- GLuint i, j;
-
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
- if (!shProg)
- return;
-
- n = shProg->NumShaders;
-
- for (i = 0; i < n; i++) {
- if (shProg->Shaders[i]->Name == shader) {
- /* found it */
- struct gl_shader **newList;
-
- /* release */
- _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
-
- /* alloc new, smaller array */
- newList = (struct gl_shader **)
- malloc((n - 1) * sizeof(struct gl_shader *));
- if (!newList) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
- return;
- }
- for (j = 0; j < i; j++) {
- newList[j] = shProg->Shaders[j];
- }
- while (++i < n)
- newList[j++] = shProg->Shaders[i];
- free(shProg->Shaders);
-
- shProg->Shaders = newList;
- shProg->NumShaders = n - 1;
-
-#ifdef DEBUG
- /* sanity check */
- {
- for (j = 0; j < shProg->NumShaders; j++) {
- assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
- shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
- assert(shProg->Shaders[j]->RefCount > 0);
- }
- }
-#endif
-
- return;
- }
- }
-
- /* not found */
- {
- GLenum err;
- if (is_shader(ctx, shader))
- err = GL_INVALID_OPERATION;
- else if (is_program(ctx, shader))
- err = GL_INVALID_OPERATION;
- else
- err = GL_INVALID_VALUE;
- _mesa_error(ctx, err, "glDetachProgram(shader)");
- return;
- }
-}
-
-
-static void
-get_active_attrib(struct gl_context *ctx, GLuint program, GLuint index,
- GLsizei maxLength, GLsizei *length, GLint *size,
- GLenum *type, GLchar *nameOut)
-{
- const struct gl_program_parameter_list *attribs = NULL;
- struct gl_shader_program *shProg;
-
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
- if (!shProg)
- return;
-
- if (shProg->VertexProgram)
- attribs = shProg->VertexProgram->Base.Attributes;
-
- if (!attribs || index >= attribs->NumParameters) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
- return;
- }
-
- _mesa_copy_string(nameOut, maxLength, length,
- attribs->Parameters[index].Name);
-
- if (size)
- *size = attribs->Parameters[index].Size
- / _mesa_sizeof_glsl_type(attribs->Parameters[index].DataType);
-
- if (type)
- *type = attribs->Parameters[index].DataType;
-}
-
-
-/**
- * Return list of shaders attached to shader program.
- */
-static void
-get_attached_shaders(struct gl_context *ctx, GLuint program, GLsizei maxCount,
- GLsizei *count, GLuint *obj)
-{
- struct gl_shader_program *shProg =
- _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
- if (shProg) {
- GLuint i;
- for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
- obj[i] = shProg->Shaders[i]->Name;
- }
- if (count)
- *count = i;
- }
-}
-
-
-static GLint
-get_frag_data_location(struct gl_context *ctx, GLuint program,
- const GLchar *name)
-{
- _mesa_problem(ctx, "get_frag_data_location() not implemented yet");
- return -1;
-}
-
-
-
-/**
- * glGetHandleARB() - return ID/name of currently bound shader program.
- */
-static GLuint
-get_handle(struct gl_context *ctx, GLenum pname)
-{
- if (pname == GL_PROGRAM_OBJECT_ARB) {
- if (ctx->Shader.ActiveProgram)
- return ctx->Shader.ActiveProgram->Name;
- else
- return 0;
- }
- else {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
- return 0;
- }
-}
-
-
-/**
- * glGetProgramiv() - get shader program state.
- * Note that this is for GLSL shader programs, not ARB vertex/fragment
- * programs (see glGetProgramivARB).
- */
-static void
-get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *params)
-{
- const struct gl_program_parameter_list *attribs;
- struct gl_shader_program *shProg
- = _mesa_lookup_shader_program(ctx, program);
-
- if (!shProg) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
- return;
- }
-
- if (shProg->VertexProgram)
- attribs = shProg->VertexProgram->Base.Attributes;
- else
- attribs = NULL;
-
- switch (pname) {
- case GL_DELETE_STATUS:
- *params = shProg->DeletePending;
- break;
- case GL_LINK_STATUS:
- *params = shProg->LinkStatus;
- break;
- case GL_VALIDATE_STATUS:
- *params = shProg->Validated;
- break;
- case GL_INFO_LOG_LENGTH:
- *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
- break;
- case GL_ATTACHED_SHADERS:
- *params = shProg->NumShaders;
- break;
- case GL_ACTIVE_ATTRIBUTES:
- *params = attribs ? attribs->NumParameters : 0;
- break;
- case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
- *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
- break;
- case GL_ACTIVE_UNIFORMS:
- *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
- break;
- case GL_ACTIVE_UNIFORM_MAX_LENGTH:
- *params = _mesa_longest_uniform_name(shProg->Uniforms);
- if (*params > 0)
- (*params)++; /* add one for terminating zero */
- break;
- case GL_PROGRAM_BINARY_LENGTH_OES:
- *params = 0;
- break;
-#if FEATURE_EXT_transform_feedback
- case GL_TRANSFORM_FEEDBACK_VARYINGS:
- *params = shProg->TransformFeedback.NumVarying;
- break;
- case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
- *params = longest_feedback_varying_name(shProg) + 1;
- break;
- case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
- *params = shProg->TransformFeedback.BufferMode;
- break;
-#endif
-#if FEATURE_ARB_geometry_shader4
- case GL_GEOMETRY_VERTICES_OUT_ARB:
- *params = shProg->Geom.VerticesOut;
- break;
- case GL_GEOMETRY_INPUT_TYPE_ARB:
- *params = shProg->Geom.InputType;
- break;
- case GL_GEOMETRY_OUTPUT_TYPE_ARB:
- *params = shProg->Geom.OutputType;
- break;
-#endif
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
- return;
- }
-}
-
-
-/**
- * glGetShaderiv() - get GLSL shader state
- */
-static void
-get_shaderiv(struct gl_context *ctx, GLuint name, GLenum pname, GLint *params)
-{
- struct gl_shader *shader =
- _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
-
- if (!shader) {
- return;
- }
-
- switch (pname) {
- case GL_SHADER_TYPE:
- *params = shader->Type;
- break;
- case GL_DELETE_STATUS:
- *params = shader->DeletePending;
- break;
- case GL_COMPILE_STATUS:
- *params = shader->CompileStatus;
- break;
- case GL_INFO_LOG_LENGTH:
- *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
- break;
- case GL_SHADER_SOURCE_LENGTH:
- *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
- return;
- }
-}
-
-
-static void
-get_program_info_log(struct gl_context *ctx, GLuint program, GLsizei bufSize,
- GLsizei *length, GLchar *infoLog)
-{
- struct gl_shader_program *shProg
- = _mesa_lookup_shader_program(ctx, program);
- if (!shProg) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
- return;
- }
- _mesa_copy_string(infoLog, bufSize, length, shProg->InfoLog);
-}
-
-
-static void
-get_shader_info_log(struct gl_context *ctx, GLuint shader, GLsizei bufSize,
- GLsizei *length, GLchar *infoLog)
-{
- struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
- if (!sh) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
- return;
- }
- _mesa_copy_string(infoLog, bufSize, length, sh->InfoLog);
-}
-
-
-/**
- * Return shader source code.
- */
-static void
-get_shader_source(struct gl_context *ctx, GLuint shader, GLsizei maxLength,
- GLsizei *length, GLchar *sourceOut)
-{
- struct gl_shader *sh;
- sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
- if (!sh) {
- return;
- }
- _mesa_copy_string(sourceOut, maxLength, length, sh->Source);
-}
-
-
-/**
- * Set/replace shader source code.
- */
-static void
-shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source)
-{
- struct gl_shader *sh;
-
- sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
- if (!sh)
- return;
-
- /* free old shader source string and install new one */
- if (sh->Source) {
- free((void *) sh->Source);
- }
- sh->Source = source;
- sh->CompileStatus = GL_FALSE;
-#ifdef DEBUG
- sh->SourceChecksum = _mesa_str_checksum(sh->Source);
-#endif
-}
-
-
-/**
- * Compile a shader.
- */
-static void
-compile_shader(struct gl_context *ctx, GLuint shaderObj)
-{
- struct gl_shader *sh;
- struct gl_shader_compiler_options *options;
-
- sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
- if (!sh)
- return;
-
- options = &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(sh->Type)];
-
- /* set default pragma state for shader */
- sh->Pragmas = options->DefaultPragmas;
-
- /* this call will set the sh->CompileStatus field to indicate if
- * compilation was successful.
- */
- _mesa_glsl_compile_shader(ctx, sh);
-}
-
-
-/**
- * Link a program's shaders.
- */
-static void
-link_program(struct gl_context *ctx, GLuint program)
-{
- struct gl_shader_program *shProg;
- struct gl_transform_feedback_object *obj =
- ctx->TransformFeedback.CurrentObject;
-
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
- if (!shProg)
- return;
-
- if (obj->Active
- && (shProg == ctx->Shader.CurrentVertexProgram
- || shProg == ctx->Shader.CurrentGeometryProgram
- || shProg == ctx->Shader.CurrentFragmentProgram)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glLinkProgram(transform feedback active");
- return;
- }
-
- FLUSH_VERTICES(ctx, _NEW_PROGRAM);
-
- _mesa_glsl_link_shader(ctx, shProg);
-
- /* debug code */
- if (0) {
- GLuint i;
-
- printf("Link %u shaders in program %u: %s\n",
- shProg->NumShaders, shProg->Name,
- shProg->LinkStatus ? "Success" : "Failed");
-
- for (i = 0; i < shProg->NumShaders; i++) {
- printf(" shader %u, type 0x%x\n",
- shProg->Shaders[i]->Name,
- shProg->Shaders[i]->Type);
- }
- }
-}
-
-
-/**
- * Print basic shader info (for debug).
- */
-static void
-print_shader_info(const struct gl_shader_program *shProg)
-{
- GLuint i;
-
- printf("Mesa: glUseProgram(%u)\n", shProg->Name);
- for (i = 0; i < shProg->NumShaders; i++) {
- const char *s;
- switch (shProg->Shaders[i]->Type) {
- case GL_VERTEX_SHADER:
- s = "vertex";
- break;
- case GL_FRAGMENT_SHADER:
- s = "fragment";
- break;
- case GL_GEOMETRY_SHADER:
- s = "geometry";
- break;
- default:
- s = "";
- }
- printf(" %s shader %u, checksum %u\n", s,
- shProg->Shaders[i]->Name,
- shProg->Shaders[i]->SourceChecksum);
- }
- if (shProg->VertexProgram)
- printf(" vert prog %u\n", shProg->VertexProgram->Base.Id);
- if (shProg->FragmentProgram)
- printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id);
-}
-
-
-/**
- * Use the named shader program for subsequent glUniform calls
- */
-void
-_mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg,
- const char *caller)
-{
- if ((shProg != NULL) && !shProg->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(program %u not linked)", caller, shProg->Name);
- return;
- }
-
- if (ctx->Shader.ActiveProgram != shProg) {
- _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, shProg);
- }
-}
-
-/**
- */
-static bool
-use_shader_program(struct gl_context *ctx, GLenum type,
- struct gl_shader_program *shProg)
-{
- struct gl_shader_program **target;
-
- switch (type) {
-#if FEATURE_ARB_vertex_shader
- case GL_VERTEX_SHADER:
- target = &ctx->Shader.CurrentVertexProgram;
- if ((shProg == NULL)
- || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) {
- shProg = NULL;
- }
- break;
-#endif
-#if FEATURE_ARB_geometry_shader4
- case GL_GEOMETRY_SHADER_ARB:
- target = &ctx->Shader.CurrentGeometryProgram;
- if ((shProg == NULL)
- || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) {
- shProg = NULL;
- }
- break;
-#endif
-#if FEATURE_ARB_fragment_shader
- case GL_FRAGMENT_SHADER:
- target = &ctx->Shader.CurrentFragmentProgram;
- if ((shProg == NULL)
- || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) {
- shProg = NULL;
- }
- break;
-#endif
- default:
- return false;
- }
-
- if (*target != shProg) {
- FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
- _mesa_reference_shader_program(ctx, target, shProg);
- return true;
- }
-
- return false;
-}
-
-/**
- * Use the named shader program for subsequent rendering.
- */
-void
-_mesa_use_program(struct gl_context *ctx, struct gl_shader_program *shProg)
-{
- use_shader_program(ctx, GL_VERTEX_SHADER, shProg);
- use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg);
- use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg);
- _mesa_active_program(ctx, shProg, "glUseProgram");
-
- if (ctx->Driver.UseProgram)
- ctx->Driver.UseProgram(ctx, shProg);
-}
-
-
-/**
- * Validate a program's samplers.
- * Specifically, check that there aren't two samplers of different types
- * pointing to the same texture unit.
- * \return GL_TRUE if valid, GL_FALSE if invalid
- */
-static GLboolean
-validate_samplers(const struct gl_program *prog, char *errMsg)
-{
- static const char *targetName[] = {
- "TEXTURE_2D_ARRAY",
- "TEXTURE_1D_ARRAY",
- "TEXTURE_CUBE",
- "TEXTURE_3D",
- "TEXTURE_RECT",
- "TEXTURE_2D",
- "TEXTURE_1D",
- };
- GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS];
- GLbitfield samplersUsed = prog->SamplersUsed;
- GLuint i;
-
- assert(Elements(targetName) == NUM_TEXTURE_TARGETS);
-
- if (samplersUsed == 0x0)
- return GL_TRUE;
-
- for (i = 0; i < Elements(targetUsed); i++)
- targetUsed[i] = -1;
-
- /* walk over bits which are set in 'samplers' */
- while (samplersUsed) {
- GLuint unit;
- gl_texture_index target;
- GLint sampler = _mesa_ffs(samplersUsed) - 1;
- assert(sampler >= 0);
- assert(sampler < MAX_TEXTURE_IMAGE_UNITS);
- unit = prog->SamplerUnits[sampler];
- target = prog->SamplerTargets[sampler];
- if (targetUsed[unit] != -1 && targetUsed[unit] != (int) target) {
- _mesa_snprintf(errMsg, 100,
- "Texture unit %d is accessed both as %s and %s",
- unit, targetName[targetUsed[unit]], targetName[target]);
- return GL_FALSE;
- }
- targetUsed[unit] = target;
- samplersUsed ^= (1 << sampler);
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Do validation of the given shader program.
- * \param errMsg returns error message if validation fails.
- * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg)
- */
-static GLboolean
-validate_shader_program(const struct gl_shader_program *shProg,
- char *errMsg)
-{
- const struct gl_vertex_program *vp = shProg->VertexProgram;
- const struct gl_fragment_program *fp = shProg->FragmentProgram;
-
- if (!shProg->LinkStatus) {
- return GL_FALSE;
- }
-
- /* From the GL spec, a program is invalid if any of these are true:
-
- any two active samplers in the current program object are of
- different types, but refer to the same texture image unit,
-
- any active sampler in the current program object refers to a texture
- image unit where fixed-function fragment processing accesses a
- texture target that does not match the sampler type, or
-
- the sum of the number of active samplers in the program and the
- number of texture image units enabled for fixed-function fragment
- processing exceeds the combined limit on the total number of texture
- image units allowed.
- */
-
-
- /*
- * Check: any two active samplers in the current program object are of
- * different types, but refer to the same texture image unit,
- */
- if (vp && !validate_samplers(&vp->Base, errMsg)) {
- return GL_FALSE;
- }
- if (fp && !validate_samplers(&fp->Base, errMsg)) {
- return GL_FALSE;
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Called via glValidateProgram()
- */
-static void
-validate_program(struct gl_context *ctx, GLuint program)
-{
- struct gl_shader_program *shProg;
- char errMsg[100];
-
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
- if (!shProg) {
- return;
- }
-
- shProg->Validated = validate_shader_program(shProg, errMsg);
- if (!shProg->Validated) {
- /* update info log */
- if (shProg->InfoLog) {
- ralloc_free(shProg->InfoLog);
- }
- shProg->InfoLog = ralloc_strdup(shProg, errMsg);
- }
-}
-
-
-
-void GLAPIENTRY
-_mesa_AttachObjectARB(GLhandleARB program, GLhandleARB shader)
-{
- GET_CURRENT_CONTEXT(ctx);
- attach_shader(ctx, program, shader);
-}
-
-
-void GLAPIENTRY
-_mesa_AttachShader(GLuint program, GLuint shader)
-{
- GET_CURRENT_CONTEXT(ctx);
- attach_shader(ctx, program, shader);
-}
-
-
-void GLAPIENTRY
-_mesa_BindAttribLocationARB(GLhandleARB program, GLuint index,
- const GLcharARB *name)
-{
- GET_CURRENT_CONTEXT(ctx);
- bind_attrib_location(ctx, program, index, name);
-}
-
-
-/* GL_EXT_gpu_shader4, GL3 */
-void GLAPIENTRY
-_mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
- const GLchar *name)
-{
- GET_CURRENT_CONTEXT(ctx);
- bind_frag_data_location(ctx, program, colorNumber, name);
-}
-
-
-void GLAPIENTRY
-_mesa_CompileShaderARB(GLhandleARB shaderObj)
-{
- GET_CURRENT_CONTEXT(ctx);
- compile_shader(ctx, shaderObj);
-}
-
-
-GLuint GLAPIENTRY
-_mesa_CreateShader(GLenum type)
-{
- GET_CURRENT_CONTEXT(ctx);
- return create_shader(ctx, type);
-}
-
-
-GLhandleARB GLAPIENTRY
-_mesa_CreateShaderObjectARB(GLenum type)
-{
- GET_CURRENT_CONTEXT(ctx);
- return create_shader(ctx, type);
-}
-
-
-GLuint GLAPIENTRY
-_mesa_CreateProgram(void)
-{
- GET_CURRENT_CONTEXT(ctx);
- return create_shader_program(ctx);
-}
-
-
-GLhandleARB GLAPIENTRY
-_mesa_CreateProgramObjectARB(void)
-{
- GET_CURRENT_CONTEXT(ctx);
- return create_shader_program(ctx);
-}
-
-
-void GLAPIENTRY
-_mesa_DeleteObjectARB(GLhandleARB obj)
-{
- if (obj) {
- GET_CURRENT_CONTEXT(ctx);
- if (is_program(ctx, obj)) {
- delete_shader_program(ctx, obj);
- }
- else if (is_shader(ctx, obj)) {
- delete_shader(ctx, obj);
- }
- else {
- /* error? */
- }
- }
-}
-
-
-void GLAPIENTRY
-_mesa_DeleteProgram(GLuint name)
-{
- if (name) {
- GET_CURRENT_CONTEXT(ctx);
- delete_shader_program(ctx, name);
- }
-}
-
-
-void GLAPIENTRY
-_mesa_DeleteShader(GLuint name)
-{
- if (name) {
- GET_CURRENT_CONTEXT(ctx);
- delete_shader(ctx, name);
- }
-}
-
-
-void GLAPIENTRY
-_mesa_DetachObjectARB(GLhandleARB program, GLhandleARB shader)
-{
- GET_CURRENT_CONTEXT(ctx);
- detach_shader(ctx, program, shader);
-}
-
-
-void GLAPIENTRY
-_mesa_DetachShader(GLuint program, GLuint shader)
-{
- GET_CURRENT_CONTEXT(ctx);
- detach_shader(ctx, program, shader);
-}
-
-
-void GLAPIENTRY
-_mesa_GetActiveAttribARB(GLhandleARB program, GLuint index,
- GLsizei maxLength, GLsizei * length, GLint * size,
- GLenum * type, GLcharARB * name)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_active_attrib(ctx, program, index, maxLength, length, size, type, name);
-}
-
-
-void GLAPIENTRY
-_mesa_GetAttachedObjectsARB(GLhandleARB container, GLsizei maxCount,
- GLsizei * count, GLhandleARB * obj)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_attached_shaders(ctx, container, maxCount, count, obj);
-}
-
-
-void GLAPIENTRY
-_mesa_GetAttachedShaders(GLuint program, GLsizei maxCount,
- GLsizei *count, GLuint *obj)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_attached_shaders(ctx, program, maxCount, count, obj);
-}
-
-
-GLint GLAPIENTRY
-_mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name)
-{
- GET_CURRENT_CONTEXT(ctx);
- return get_attrib_location(ctx, program, name);
-}
-
-
-/* GL_EXT_gpu_shader4, GL3 */
-GLint GLAPIENTRY
-_mesa_GetFragDataLocation(GLuint program, const GLchar *name)
-{
- GET_CURRENT_CONTEXT(ctx);
- return get_frag_data_location(ctx, program, name);
-}
-
-
-
-void GLAPIENTRY
-_mesa_GetInfoLogARB(GLhandleARB object, GLsizei maxLength, GLsizei * length,
- GLcharARB * infoLog)
-{
- GET_CURRENT_CONTEXT(ctx);
- if (is_program(ctx, object)) {
- get_program_info_log(ctx, object, maxLength, length, infoLog);
- }
- else if (is_shader(ctx, object)) {
- get_shader_info_log(ctx, object, maxLength, length, infoLog);
- }
- else {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInfoLogARB");
- }
-}
-
-
-void GLAPIENTRY
-_mesa_GetObjectParameterivARB(GLhandleARB object, GLenum pname, GLint *params)
-{
- GET_CURRENT_CONTEXT(ctx);
- /* Implement in terms of GetProgramiv, GetShaderiv */
- if (is_program(ctx, object)) {
- if (pname == GL_OBJECT_TYPE_ARB) {
- *params = GL_PROGRAM_OBJECT_ARB;
- }
- else {
- get_programiv(ctx, object, pname, params);
- }
- }
- else if (is_shader(ctx, object)) {
- if (pname == GL_OBJECT_TYPE_ARB) {
- *params = GL_SHADER_OBJECT_ARB;
- }
- else {
- get_shaderiv(ctx, object, pname, params);
- }
- }
- else {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetObjectParameterivARB");
- }
-}
-
-
-void GLAPIENTRY
-_mesa_GetObjectParameterfvARB(GLhandleARB object, GLenum pname,
- GLfloat *params)
-{
- GLint iparams[1]; /* XXX is one element enough? */
- _mesa_GetObjectParameterivARB(object, pname, iparams);
- params[0] = (GLfloat) iparams[0];
-}
-
-
-void GLAPIENTRY
-_mesa_GetProgramiv(GLuint program, GLenum pname, GLint *params)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_programiv(ctx, program, pname, params);
-}
-
-
-void GLAPIENTRY
-_mesa_GetShaderiv(GLuint shader, GLenum pname, GLint *params)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_shaderiv(ctx, shader, pname, params);
-}
-
-
-void GLAPIENTRY
-_mesa_GetProgramInfoLog(GLuint program, GLsizei bufSize,
- GLsizei *length, GLchar *infoLog)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_program_info_log(ctx, program, bufSize, length, infoLog);
-}
-
-
-void GLAPIENTRY
-_mesa_GetShaderInfoLog(GLuint shader, GLsizei bufSize,
- GLsizei *length, GLchar *infoLog)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_shader_info_log(ctx, shader, bufSize, length, infoLog);
-}
-
-
-void GLAPIENTRY
-_mesa_GetShaderSourceARB(GLhandleARB shader, GLsizei maxLength,
- GLsizei *length, GLcharARB *sourceOut)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_shader_source(ctx, shader, maxLength, length, sourceOut);
-}
-
-
-GLhandleARB GLAPIENTRY
-_mesa_GetHandleARB(GLenum pname)
-{
- GET_CURRENT_CONTEXT(ctx);
- return get_handle(ctx, pname);
-}
-
-
-GLboolean GLAPIENTRY
-_mesa_IsProgram(GLuint name)
-{
- GET_CURRENT_CONTEXT(ctx);
- return is_program(ctx, name);
-}
-
-
-GLboolean GLAPIENTRY
-_mesa_IsShader(GLuint name)
-{
- GET_CURRENT_CONTEXT(ctx);
- return is_shader(ctx, name);
-}
-
-
-void GLAPIENTRY
-_mesa_LinkProgramARB(GLhandleARB programObj)
-{
- GET_CURRENT_CONTEXT(ctx);
- link_program(ctx, programObj);
-}
-
-
-
-/**
- * Read shader source code from a file.
- * Useful for debugging to override an app's shader.
- */
-static GLcharARB *
-read_shader(const char *fname)
-{
- const int max = 50*1000;
- FILE *f = fopen(fname, "r");
- GLcharARB *buffer, *shader;
- int len;
-
- if (!f) {
- return NULL;
- }
-
- buffer = (char *) malloc(max);
- len = fread(buffer, 1, max, f);
- buffer[len] = 0;
-
- fclose(f);
-
- shader = _mesa_strdup(buffer);
- free(buffer);
-
- return shader;
-}
-
-
-/**
- * Called via glShaderSource() and glShaderSourceARB() API functions.
- * Basically, concatenate the source code strings into one long string
- * and pass it to _mesa_shader_source().
- */
-void GLAPIENTRY
-_mesa_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count,
- const GLcharARB ** string, const GLint * length)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLint *offsets;
- GLsizei i, totalLength;
- GLcharARB *source;
- GLuint checksum;
-
- if (!shaderObj || string == NULL) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB");
- return;
- }
-
- /*
- * This array holds offsets of where the appropriate string ends, thus the
- * last element will be set to the total length of the source code.
- */
- offsets = (GLint *) malloc(count * sizeof(GLint));
- if (offsets == NULL) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB");
- return;
- }
-
- for (i = 0; i < count; i++) {
- if (string[i] == NULL) {
- free((GLvoid *) offsets);
- _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderSourceARB(null string)");
- return;
- }
- if (length == NULL || length[i] < 0)
- offsets[i] = strlen(string[i]);
- else
- offsets[i] = length[i];
- /* accumulate string lengths */
- if (i > 0)
- offsets[i] += offsets[i - 1];
- }
-
- /* Total length of source string is sum off all strings plus two.
- * One extra byte for terminating zero, another extra byte to silence
- * valgrind warnings in the parser/grammer code.
- */
- totalLength = offsets[count - 1] + 2;
- source = (GLcharARB *) malloc(totalLength * sizeof(GLcharARB));
- if (source == NULL) {
- free((GLvoid *) offsets);
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB");
- return;
- }
-
- for (i = 0; i < count; i++) {
- GLint start = (i > 0) ? offsets[i - 1] : 0;
- memcpy(source + start, string[i],
- (offsets[i] - start) * sizeof(GLcharARB));
- }
- source[totalLength - 1] = '\0';
- source[totalLength - 2] = '\0';
-
- if (SHADER_SUBST) {
- /* Compute the shader's source code checksum then try to open a file
- * named newshader_<CHECKSUM>. If it exists, use it in place of the
- * original shader source code. For debugging.
- */
- char filename[100];
- GLcharARB *newSource;
-
- checksum = _mesa_str_checksum(source);
-
- _mesa_snprintf(filename, sizeof(filename), "newshader_%d", checksum);
-
- newSource = read_shader(filename);
- if (newSource) {
- fprintf(stderr, "Mesa: Replacing shader %u chksum=%d with %s\n",
- shaderObj, checksum, filename);
- free(source);
- source = newSource;
- }
- }
-
- shader_source(ctx, shaderObj, source);
-
- if (SHADER_SUBST) {
- struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
- if (sh)
- sh->SourceChecksum = checksum; /* save original checksum */
- }
-
- free(offsets);
-}
-
-
-void GLAPIENTRY
-_mesa_UseProgramObjectARB(GLhandleARB program)
-{
- GET_CURRENT_CONTEXT(ctx);
- struct gl_shader_program *shProg;
- struct gl_transform_feedback_object *obj =
- ctx->TransformFeedback.CurrentObject;
-
- if (obj->Active) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUseProgram(transform feedback active)");
- return;
- }
-
- if (program) {
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
- if (!shProg) {
- return;
- }
- if (!shProg->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUseProgram(program %u not linked)", program);
- return;
- }
-
- /* debug code */
- if (ctx->Shader.Flags & GLSL_USE_PROG) {
- print_shader_info(shProg);
- }
- }
- else {
- shProg = NULL;
- }
-
- _mesa_use_program(ctx, shProg);
-}
-
-
-void GLAPIENTRY
-_mesa_ValidateProgramARB(GLhandleARB program)
-{
- GET_CURRENT_CONTEXT(ctx);
- validate_program(ctx, program);
-}
-
-#ifdef FEATURE_ES2
-
-void GLAPIENTRY
-_mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype,
- GLint* range, GLint* precision)
-{
- const struct gl_program_constants *limits;
- const struct gl_precision *p;
- GET_CURRENT_CONTEXT(ctx);
-
- switch (shadertype) {
- case GL_VERTEX_SHADER:
- limits = &ctx->Const.VertexProgram;
- break;
- case GL_FRAGMENT_SHADER:
- limits = &ctx->Const.FragmentProgram;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetShaderPrecisionFormat(shadertype)");
- return;
- }
-
- switch (precisiontype) {
- case GL_LOW_FLOAT:
- p = &limits->LowFloat;
- break;
- case GL_MEDIUM_FLOAT:
- p = &limits->MediumFloat;
- break;
- case GL_HIGH_FLOAT:
- p = &limits->HighFloat;
- break;
- case GL_LOW_INT:
- p = &limits->LowInt;
- break;
- case GL_MEDIUM_INT:
- p = &limits->MediumInt;
- break;
- case GL_HIGH_INT:
- p = &limits->HighInt;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetShaderPrecisionFormat(precisiontype)");
- return;
- }
-
- range[0] = p->RangeMin;
- range[1] = p->RangeMax;
- precision[0] = p->Precision;
-}
-
-
-void GLAPIENTRY
-_mesa_ReleaseShaderCompiler(void)
-{
- _mesa_destroy_shader_compiler_caches();
-}
-
-
-void GLAPIENTRY
-_mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat,
- const void* binary, GLint length)
-{
- GET_CURRENT_CONTEXT(ctx);
- (void) n;
- (void) shaders;
- (void) binaryformat;
- (void) binary;
- (void) length;
- _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__);
-}
-
-#endif /* FEATURE_ES2 */
-
-
-#if FEATURE_ARB_geometry_shader4
-
-void GLAPIENTRY
-_mesa_ProgramParameteriARB(GLuint program, GLenum pname,
- GLint value)
-{
- struct gl_shader_program *shProg;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- shProg = _mesa_lookup_shader_program_err(ctx, program,
- "glProgramParameteri");
- if (!shProg)
- return;
-
- switch (pname) {
- case GL_GEOMETRY_VERTICES_OUT_ARB:
- if (value < 1 ||
- (unsigned) value > ctx->Const.GeometryProgram.MaxGeometryOutputVertices) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d",
- value);
- return;
- }
- shProg->Geom.VerticesOut = value;
- break;
- case GL_GEOMETRY_INPUT_TYPE_ARB:
- switch (value) {
- case GL_POINTS:
- case GL_LINES:
- case GL_LINES_ADJACENCY_ARB:
- case GL_TRIANGLES:
- case GL_TRIANGLES_ADJACENCY_ARB:
- shProg->Geom.InputType = value;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glProgramParameteri(geometry input type = %s",
- _mesa_lookup_enum_by_nr(value));
- return;
- }
- break;
- case GL_GEOMETRY_OUTPUT_TYPE_ARB:
- switch (value) {
- case GL_POINTS:
- case GL_LINE_STRIP:
- case GL_TRIANGLE_STRIP:
- shProg->Geom.OutputType = value;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glProgramParameteri(geometry output type = %s",
- _mesa_lookup_enum_by_nr(value));
- return;
- }
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteriARB(pname=%s)",
- _mesa_lookup_enum_by_nr(pname));
- break;
- }
-}
-
-#endif
-
-void
-_mesa_use_shader_program(struct gl_context *ctx, GLenum type,
- struct gl_shader_program *shProg)
-{
- use_shader_program(ctx, type, shProg);
-
- if (ctx->Driver.UseProgram)
- ctx->Driver.UseProgram(ctx, shProg);
-}
-
-void GLAPIENTRY
-_mesa_UseShaderProgramEXT(GLenum type, GLuint program)
-{
- GET_CURRENT_CONTEXT(ctx);
- struct gl_shader_program *shProg = NULL;
-
- if (!validate_shader_target(ctx, type)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)");
- return;
- }
-
- if (ctx->TransformFeedback.CurrentObject->Active) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUseShaderProgramEXT(transform feedback is active)");
- return;
- }
-
- if (program) {
- shProg = _mesa_lookup_shader_program_err(ctx, program,
- "glUseShaderProgramEXT");
- if (shProg == NULL)
- return;
-
- if (!shProg->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUseShaderProgramEXT(program not linked)");
- return;
- }
- }
-
- _mesa_use_shader_program(ctx, type, shProg);
-}
-
-void GLAPIENTRY
-_mesa_ActiveProgramEXT(GLuint program)
-{
- GET_CURRENT_CONTEXT(ctx);
- struct gl_shader_program *shProg = (program != 0)
- ? _mesa_lookup_shader_program_err(ctx, program, "glActiveProgramEXT")
- : NULL;
-
- _mesa_active_program(ctx, shProg, "glActiveProgramEXT");
- return;
-}
-
-GLuint GLAPIENTRY
-_mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string)
-{
- GET_CURRENT_CONTEXT(ctx);
- const GLuint shader = create_shader(ctx, type);
- GLuint program = 0;
-
- if (shader) {
- shader_source(ctx, shader, _mesa_strdup(string));
- compile_shader(ctx, shader);
-
- program = create_shader_program(ctx);
- if (program) {
- struct gl_shader_program *shProg;
- struct gl_shader *sh;
- GLint compiled = GL_FALSE;
-
- shProg = _mesa_lookup_shader_program(ctx, program);
- sh = _mesa_lookup_shader(ctx, shader);
-
- get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled);
- if (compiled) {
- attach_shader(ctx, program, shader);
- link_program(ctx, program);
- detach_shader(ctx, program, shader);
-
-#if 0
- /* Possibly... */
- if (active-user-defined-varyings-in-linked-program) {
- append-error-to-info-log;
- shProg->LinkStatus = GL_FALSE;
- }
-#endif
- }
-
- ralloc_strcat(&shProg->InfoLog, sh->InfoLog);
- }
-
- delete_shader(ctx, shader);
- }
-
- return program;
-}
-
-/**
- * Plug in shader-related functions into API dispatch table.
- */
-void
-_mesa_init_shader_dispatch(struct _glapi_table *exec)
-{
-#if FEATURE_GL
- /* GL_ARB_vertex/fragment_shader */
- SET_DeleteObjectARB(exec, _mesa_DeleteObjectARB);
- SET_GetHandleARB(exec, _mesa_GetHandleARB);
- SET_DetachObjectARB(exec, _mesa_DetachObjectARB);
- SET_CreateShaderObjectARB(exec, _mesa_CreateShaderObjectARB);
- SET_ShaderSourceARB(exec, _mesa_ShaderSourceARB);
- SET_CompileShaderARB(exec, _mesa_CompileShaderARB);
- SET_CreateProgramObjectARB(exec, _mesa_CreateProgramObjectARB);
- SET_AttachObjectARB(exec, _mesa_AttachObjectARB);
- SET_LinkProgramARB(exec, _mesa_LinkProgramARB);
- SET_UseProgramObjectARB(exec, _mesa_UseProgramObjectARB);
- SET_ValidateProgramARB(exec, _mesa_ValidateProgramARB);
- SET_GetObjectParameterfvARB(exec, _mesa_GetObjectParameterfvARB);
- SET_GetObjectParameterivARB(exec, _mesa_GetObjectParameterivARB);
- SET_GetInfoLogARB(exec, _mesa_GetInfoLogARB);
- SET_GetAttachedObjectsARB(exec, _mesa_GetAttachedObjectsARB);
- SET_GetShaderSourceARB(exec, _mesa_GetShaderSourceARB);
-
- /* OpenGL 2.0 */
- SET_AttachShader(exec, _mesa_AttachShader);
- SET_CreateProgram(exec, _mesa_CreateProgram);
- SET_CreateShader(exec, _mesa_CreateShader);
- SET_DeleteProgram(exec, _mesa_DeleteProgram);
- SET_DeleteShader(exec, _mesa_DeleteShader);
- SET_DetachShader(exec, _mesa_DetachShader);
- SET_GetAttachedShaders(exec, _mesa_GetAttachedShaders);
- SET_GetProgramiv(exec, _mesa_GetProgramiv);
- SET_GetProgramInfoLog(exec, _mesa_GetProgramInfoLog);
- SET_GetShaderiv(exec, _mesa_GetShaderiv);
- SET_GetShaderInfoLog(exec, _mesa_GetShaderInfoLog);
- SET_IsProgram(exec, _mesa_IsProgram);
- SET_IsShader(exec, _mesa_IsShader);
-
-#if FEATURE_ARB_vertex_shader
- SET_BindAttribLocationARB(exec, _mesa_BindAttribLocationARB);
- SET_GetActiveAttribARB(exec, _mesa_GetActiveAttribARB);
- SET_GetAttribLocationARB(exec, _mesa_GetAttribLocationARB);
-#endif
-
-#if FEATURE_ARB_geometry_shader4
- SET_ProgramParameteriARB(exec, _mesa_ProgramParameteriARB);
-#endif
-
- SET_UseShaderProgramEXT(exec, _mesa_UseShaderProgramEXT);
- SET_ActiveProgramEXT(exec, _mesa_ActiveProgramEXT);
- SET_CreateShaderProgramEXT(exec, _mesa_CreateShaderProgramEXT);
-
- /* GL_EXT_gpu_shader4 / GL 3.0 */
- SET_BindFragDataLocationEXT(exec, _mesa_BindFragDataLocation);
- SET_GetFragDataLocationEXT(exec, _mesa_GetFragDataLocation);
-
- /* GL_ARB_ES2_compatibility */
- SET_ReleaseShaderCompiler(exec, _mesa_ReleaseShaderCompiler);
- SET_GetShaderPrecisionFormat(exec, _mesa_GetShaderPrecisionFormat);
-
-#endif /* FEATURE_GL */
-}
-
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2004-2008 Brian Paul All Rights Reserved.
+ * Copyright (C) 2009-2010 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 shaderapi.c
+ * \author Brian Paul
+ *
+ * Implementation of GLSL-related API functions.
+ * The glUniform* functions are in uniforms.c
+ *
+ *
+ * XXX things to do:
+ * 1. Check that the right error code is generated for all _mesa_error() calls.
+ * 2. Insert FLUSH_VERTICES calls in various places
+ */
+
+
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/dispatch.h"
+#include "main/enums.h"
+#include "main/hash.h"
+#include "main/mfeatures.h"
+#include "main/mtypes.h"
+#include "main/shaderapi.h"
+#include "main/shaderobj.h"
+#include "program/program.h"
+#include "program/prog_parameter.h"
+#include "program/prog_uniform.h"
+#include "ralloc.h"
+#include <stdbool.h>
+#include "../glsl/glsl_parser_extras.h"
+
+/** Define this to enable shader substitution (see below) */
+#define SHADER_SUBST 0
+
+
+/**
+ * Return mask of GLSL_x flags by examining the MESA_GLSL env var.
+ */
+static GLbitfield
+get_shader_flags(void)
+{
+ GLbitfield flags = 0x0;
+ const char *env = _mesa_getenv("MESA_GLSL");
+
+ if (env) {
+ if (strstr(env, "dump"))
+ flags |= GLSL_DUMP;
+ if (strstr(env, "log"))
+ flags |= GLSL_LOG;
+ if (strstr(env, "nopvert"))
+ flags |= GLSL_NOP_VERT;
+ if (strstr(env, "nopfrag"))
+ flags |= GLSL_NOP_FRAG;
+ if (strstr(env, "nopt"))
+ flags |= GLSL_NO_OPT;
+ else if (strstr(env, "opt"))
+ flags |= GLSL_OPT;
+ if (strstr(env, "uniform"))
+ flags |= GLSL_UNIFORMS;
+ if (strstr(env, "useprog"))
+ flags |= GLSL_USE_PROG;
+ }
+
+ return flags;
+}
+
+
+/**
+ * Initialize context's shader state.
+ */
+void
+_mesa_init_shader_state(struct gl_context *ctx)
+{
+ /* Device drivers may override these to control what kind of instructions
+ * are generated by the GLSL compiler.
+ */
+ struct gl_shader_compiler_options options;
+ gl_shader_type sh;
+
+ memset(&options, 0, sizeof(options));
+ options.MaxUnrollIterations = 32;
+
+ /* Default pragma settings */
+ options.DefaultPragmas.Optimize = GL_TRUE;
+
+ for (sh = 0; sh < MESA_SHADER_TYPES; ++sh)
+ memcpy(&ctx->ShaderCompilerOptions[sh], &options, sizeof(options));
+
+ ctx->Shader.Flags = get_shader_flags();
+}
+
+
+/**
+ * Free the per-context shader-related state.
+ */
+void
+_mesa_free_shader_state(struct gl_context *ctx)
+{
+ _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentVertexProgram, NULL);
+ _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentGeometryProgram,
+ NULL);
+ _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentFragmentProgram,
+ NULL);
+ _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL);
+}
+
+
+/**
+ * Return the size of the given GLSL datatype, in floats (components).
+ */
+GLint
+_mesa_sizeof_glsl_type(GLenum type)
+{
+ switch (type) {
+ case GL_FLOAT:
+ case GL_INT:
+ case GL_BOOL:
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_2D_RECT_ARB:
+ case GL_SAMPLER_2D_RECT_SHADOW_ARB:
+ case GL_SAMPLER_1D_ARRAY_EXT:
+ case GL_SAMPLER_2D_ARRAY_EXT:
+ case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
+ case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
+ case GL_SAMPLER_CUBE_SHADOW_EXT:
+ return 1;
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC2:
+ case GL_BOOL_VEC2:
+ return 2;
+ case GL_FLOAT_VEC3:
+ case GL_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC3:
+ case GL_BOOL_VEC3:
+ return 3;
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT_VEC4:
+ case GL_BOOL_VEC4:
+ return 4;
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT2x4:
+ return 8; /* two float[4] vectors */
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_MAT3x4:
+ return 12; /* three float[4] vectors */
+ case GL_FLOAT_MAT4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ return 16; /* four float[4] vectors */
+ default:
+ _mesa_problem(NULL, "Invalid type in _mesa_sizeof_glsl_type()");
+ return 1;
+ }
+}
+
+
+/**
+ * Copy string from <src> to <dst>, up to maxLength characters, returning
+ * length of <dst> in <length>.
+ * \param src the strings source
+ * \param maxLength max chars to copy
+ * \param length returns number of chars copied
+ * \param dst the string destination
+ */
+void
+_mesa_copy_string(GLchar *dst, GLsizei maxLength,
+ GLsizei *length, const GLchar *src)
+{
+ GLsizei len;
+ for (len = 0; len < maxLength - 1 && src && src[len]; len++)
+ dst[len] = src[len];
+ if (maxLength > 0)
+ dst[len] = 0;
+ if (length)
+ *length = len;
+}
+
+
+
+/**
+ * Confirm that the a shader type is valid and supported by the implementation
+ *
+ * \param ctx Current GL context
+ * \param type Shader target
+ *
+ */
+static bool
+validate_shader_target(const struct gl_context *ctx, GLenum type)
+{
+ switch (type) {
+#if FEATURE_ARB_fragment_shader
+ case GL_FRAGMENT_SHADER:
+ return ctx->Extensions.ARB_fragment_shader;
+#endif
+#if FEATURE_ARB_vertex_shader
+ case GL_VERTEX_SHADER:
+ return ctx->Extensions.ARB_vertex_shader;
+#endif
+#if FEATURE_ARB_geometry_shader4
+ case GL_GEOMETRY_SHADER_ARB:
+ return ctx->Extensions.ARB_geometry_shader4;
+#endif
+ default:
+ return false;
+ }
+}
+
+
+/**
+ * Find the length of the longest transform feedback varying name
+ * which was specified with glTransformFeedbackVaryings().
+ */
+static GLint
+longest_feedback_varying_name(const struct gl_shader_program *shProg)
+{
+ GLuint i;
+ GLint max = 0;
+ for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
+ GLint len = strlen(shProg->TransformFeedback.VaryingNames[i]);
+ if (len > max)
+ max = len;
+ }
+ return max;
+}
+
+
+
+static GLboolean
+is_program(struct gl_context *ctx, GLuint name)
+{
+ struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
+ return shProg ? GL_TRUE : GL_FALSE;
+}
+
+
+static GLboolean
+is_shader(struct gl_context *ctx, GLuint name)
+{
+ struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
+ return shader ? GL_TRUE : GL_FALSE;
+}
+
+
+/**
+ * Attach shader to a shader program.
+ */
+static void
+attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
+{
+ struct gl_shader_program *shProg;
+ struct gl_shader *sh;
+ GLuint i, n;
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
+ if (!shProg)
+ return;
+
+ sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
+ if (!sh) {
+ return;
+ }
+
+ n = shProg->NumShaders;
+ for (i = 0; i < n; i++) {
+ if (shProg->Shaders[i] == sh) {
+ /* The shader is already attched to this program. The
+ * GL_ARB_shader_objects spec says:
+ *
+ * "The error INVALID_OPERATION is generated by AttachObjectARB
+ * if <obj> is already attached to <containerObj>."
+ */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader");
+ return;
+ }
+ }
+
+ /* grow list */
+ shProg->Shaders = (struct gl_shader **)
+ _mesa_realloc(shProg->Shaders,
+ n * sizeof(struct gl_shader *),
+ (n + 1) * sizeof(struct gl_shader *));
+ if (!shProg->Shaders) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
+ return;
+ }
+
+ /* append */
+ shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
+ _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
+ shProg->NumShaders++;
+}
+
+
+static GLint
+get_attrib_location(struct gl_context *ctx, GLuint program, const GLchar *name)
+{
+ struct gl_shader_program *shProg
+ = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
+
+ if (!shProg) {
+ return -1;
+ }
+
+ if (!shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetAttribLocation(program not linked)");
+ return -1;
+ }
+
+ if (!name)
+ return -1;
+
+ if (shProg->VertexProgram) {
+ const struct gl_program_parameter_list *attribs =
+ shProg->VertexProgram->Base.Attributes;
+ if (attribs) {
+ GLint i = _mesa_lookup_parameter_index(attribs, -1, name);
+ if (i >= 0) {
+ return attribs->Parameters[i].StateIndexes[0];
+ }
+ }
+ }
+ return -1;
+}
+
+
+static void
+bind_attrib_location(struct gl_context *ctx, GLuint program, GLuint index,
+ const GLchar *name)
+{
+ struct gl_shader_program *shProg;
+ const GLint size = -1; /* unknown size */
+ GLint i, oldIndex;
+ GLenum datatype = GL_FLOAT_VEC4;
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program,
+ "glBindAttribLocation");
+ if (!shProg) {
+ return;
+ }
+
+ if (!name)
+ return;
+
+ if (strncmp(name, "gl_", 3) == 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindAttribLocation(illegal name)");
+ return;
+ }
+
+ if (index >= ctx->Const.VertexProgram.MaxAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
+ return;
+ }
+
+ if (shProg->LinkStatus) {
+ /* get current index/location for the attribute */
+ oldIndex = get_attrib_location(ctx, program, name);
+ }
+ else {
+ oldIndex = -1;
+ }
+
+ /* this will replace the current value if it's already in the list */
+ i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
+ if (i < 0) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
+ return;
+ }
+
+ /*
+ * Note that this attribute binding won't go into effect until
+ * glLinkProgram is called again.
+ */
+}
+
+
+static void
+bind_frag_data_location(struct gl_context *ctx, GLuint program,
+ GLuint colorNumber, const GLchar *name)
+{
+ _mesa_problem(ctx, "bind_frag_data_location() not implemented yet");
+}
+
+
+static GLuint
+create_shader(struct gl_context *ctx, GLenum type)
+{
+ struct gl_shader *sh;
+ GLuint name;
+
+ if (!validate_shader_target(ctx, type)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
+ return 0;
+ }
+
+ name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
+ sh = ctx->Driver.NewShader(ctx, name, type);
+ _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
+
+ return name;
+}
+
+
+static GLuint
+create_shader_program(struct gl_context *ctx)
+{
+ GLuint name;
+ struct gl_shader_program *shProg;
+
+ name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
+
+ shProg = ctx->Driver.NewShaderProgram(ctx, name);
+
+ _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
+
+ assert(shProg->RefCount == 1);
+
+ return name;
+}
+
+
+/**
+ * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
+ * DeleteProgramARB.
+ */
+static void
+delete_shader_program(struct gl_context *ctx, GLuint name)
+{
+ /*
+ * NOTE: deleting shaders/programs works a bit differently than
+ * texture objects (and buffer objects, etc). Shader/program
+ * handles/IDs exist in the hash table until the object is really
+ * deleted (refcount==0). With texture objects, the handle/ID is
+ * removed from the hash table in glDeleteTextures() while the tex
+ * object itself might linger until its refcount goes to zero.
+ */
+ struct gl_shader_program *shProg;
+
+ shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
+ if (!shProg)
+ return;
+
+ shProg->DeletePending = GL_TRUE;
+
+ /* effectively, decr shProg's refcount */
+ _mesa_reference_shader_program(ctx, &shProg, NULL);
+}
+
+
+static void
+delete_shader(struct gl_context *ctx, GLuint shader)
+{
+ struct gl_shader *sh;
+
+ sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
+ if (!sh)
+ return;
+
+ sh->DeletePending = GL_TRUE;
+
+ /* effectively, decr sh's refcount */
+ _mesa_reference_shader(ctx, &sh, NULL);
+}
+
+
+static void
+detach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
+{
+ struct gl_shader_program *shProg;
+ GLuint n;
+ GLuint i, j;
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
+ if (!shProg)
+ return;
+
+ n = shProg->NumShaders;
+
+ for (i = 0; i < n; i++) {
+ if (shProg->Shaders[i]->Name == shader) {
+ /* found it */
+ struct gl_shader **newList;
+
+ /* release */
+ _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
+
+ /* alloc new, smaller array */
+ newList = (struct gl_shader **)
+ malloc((n - 1) * sizeof(struct gl_shader *));
+ if (!newList) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
+ return;
+ }
+ for (j = 0; j < i; j++) {
+ newList[j] = shProg->Shaders[j];
+ }
+ while (++i < n)
+ newList[j++] = shProg->Shaders[i];
+ free(shProg->Shaders);
+
+ shProg->Shaders = newList;
+ shProg->NumShaders = n - 1;
+
+#ifdef DEBUG
+ /* sanity check */
+ {
+ for (j = 0; j < shProg->NumShaders; j++) {
+ assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
+ shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
+ assert(shProg->Shaders[j]->RefCount > 0);
+ }
+ }
+#endif
+
+ return;
+ }
+ }
+
+ /* not found */
+ {
+ GLenum err;
+ if (is_shader(ctx, shader))
+ err = GL_INVALID_OPERATION;
+ else if (is_program(ctx, shader))
+ err = GL_INVALID_OPERATION;
+ else
+ err = GL_INVALID_VALUE;
+ _mesa_error(ctx, err, "glDetachProgram(shader)");
+ return;
+ }
+}
+
+
+static void
+get_active_attrib(struct gl_context *ctx, GLuint program, GLuint index,
+ GLsizei maxLength, GLsizei *length, GLint *size,
+ GLenum *type, GLchar *nameOut)
+{
+ const struct gl_program_parameter_list *attribs = NULL;
+ struct gl_shader_program *shProg;
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
+ if (!shProg)
+ return;
+
+ if (shProg->VertexProgram)
+ attribs = shProg->VertexProgram->Base.Attributes;
+
+ if (!attribs || index >= attribs->NumParameters) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
+ return;
+ }
+
+ _mesa_copy_string(nameOut, maxLength, length,
+ attribs->Parameters[index].Name);
+
+ if (size)
+ *size = attribs->Parameters[index].Size
+ / _mesa_sizeof_glsl_type(attribs->Parameters[index].DataType);
+
+ if (type)
+ *type = attribs->Parameters[index].DataType;
+}
+
+
+/**
+ * Return list of shaders attached to shader program.
+ */
+static void
+get_attached_shaders(struct gl_context *ctx, GLuint program, GLsizei maxCount,
+ GLsizei *count, GLuint *obj)
+{
+ struct gl_shader_program *shProg =
+ _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
+ if (shProg) {
+ GLuint i;
+ for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
+ obj[i] = shProg->Shaders[i]->Name;
+ }
+ if (count)
+ *count = i;
+ }
+}
+
+
+static GLint
+get_frag_data_location(struct gl_context *ctx, GLuint program,
+ const GLchar *name)
+{
+ _mesa_problem(ctx, "get_frag_data_location() not implemented yet");
+ return -1;
+}
+
+
+
+/**
+ * glGetHandleARB() - return ID/name of currently bound shader program.
+ */
+static GLuint
+get_handle(struct gl_context *ctx, GLenum pname)
+{
+ if (pname == GL_PROGRAM_OBJECT_ARB) {
+ if (ctx->Shader.ActiveProgram)
+ return ctx->Shader.ActiveProgram->Name;
+ else
+ return 0;
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
+ return 0;
+ }
+}
+
+
+/**
+ * glGetProgramiv() - get shader program state.
+ * Note that this is for GLSL shader programs, not ARB vertex/fragment
+ * programs (see glGetProgramivARB).
+ */
+static void
+get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *params)
+{
+ const struct gl_program_parameter_list *attribs;
+ struct gl_shader_program *shProg
+ = _mesa_lookup_shader_program(ctx, program);
+
+ if (!shProg) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
+ return;
+ }
+
+ if (shProg->VertexProgram)
+ attribs = shProg->VertexProgram->Base.Attributes;
+ else
+ attribs = NULL;
+
+ switch (pname) {
+ case GL_DELETE_STATUS:
+ *params = shProg->DeletePending;
+ break;
+ case GL_LINK_STATUS:
+ *params = shProg->LinkStatus;
+ break;
+ case GL_VALIDATE_STATUS:
+ *params = shProg->Validated;
+ break;
+ case GL_INFO_LOG_LENGTH:
+ *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
+ break;
+ case GL_ATTACHED_SHADERS:
+ *params = shProg->NumShaders;
+ break;
+ case GL_ACTIVE_ATTRIBUTES:
+ *params = attribs ? attribs->NumParameters : 0;
+ break;
+ case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+ *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
+ break;
+ case GL_ACTIVE_UNIFORMS:
+ *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
+ break;
+ case GL_ACTIVE_UNIFORM_MAX_LENGTH:
+ *params = _mesa_longest_uniform_name(shProg->Uniforms);
+ if (*params > 0)
+ (*params)++; /* add one for terminating zero */
+ break;
+ case GL_PROGRAM_BINARY_LENGTH_OES:
+ *params = 0;
+ break;
+#if FEATURE_EXT_transform_feedback
+ case GL_TRANSFORM_FEEDBACK_VARYINGS:
+ *params = shProg->TransformFeedback.NumVarying;
+ break;
+ case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
+ *params = longest_feedback_varying_name(shProg) + 1;
+ break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
+ *params = shProg->TransformFeedback.BufferMode;
+ break;
+#endif
+#if FEATURE_ARB_geometry_shader4
+ case GL_GEOMETRY_VERTICES_OUT_ARB:
+ *params = shProg->Geom.VerticesOut;
+ break;
+ case GL_GEOMETRY_INPUT_TYPE_ARB:
+ *params = shProg->Geom.InputType;
+ break;
+ case GL_GEOMETRY_OUTPUT_TYPE_ARB:
+ *params = shProg->Geom.OutputType;
+ break;
+#endif
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
+ return;
+ }
+}
+
+
+/**
+ * glGetShaderiv() - get GLSL shader state
+ */
+static void
+get_shaderiv(struct gl_context *ctx, GLuint name, GLenum pname, GLint *params)
+{
+ struct gl_shader *shader =
+ _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
+
+ if (!shader) {
+ return;
+ }
+
+ switch (pname) {
+ case GL_SHADER_TYPE:
+ *params = shader->Type;
+ break;
+ case GL_DELETE_STATUS:
+ *params = shader->DeletePending;
+ break;
+ case GL_COMPILE_STATUS:
+ *params = shader->CompileStatus;
+ break;
+ case GL_INFO_LOG_LENGTH:
+ *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
+ break;
+ case GL_SHADER_SOURCE_LENGTH:
+ *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
+ return;
+ }
+}
+
+
+static void
+get_program_info_log(struct gl_context *ctx, GLuint program, GLsizei bufSize,
+ GLsizei *length, GLchar *infoLog)
+{
+ struct gl_shader_program *shProg
+ = _mesa_lookup_shader_program(ctx, program);
+ if (!shProg) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
+ return;
+ }
+ _mesa_copy_string(infoLog, bufSize, length, shProg->InfoLog);
+}
+
+
+static void
+get_shader_info_log(struct gl_context *ctx, GLuint shader, GLsizei bufSize,
+ GLsizei *length, GLchar *infoLog)
+{
+ struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
+ if (!sh) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
+ return;
+ }
+ _mesa_copy_string(infoLog, bufSize, length, sh->InfoLog);
+}
+
+
+/**
+ * Return shader source code.
+ */
+static void
+get_shader_source(struct gl_context *ctx, GLuint shader, GLsizei maxLength,
+ GLsizei *length, GLchar *sourceOut)
+{
+ struct gl_shader *sh;
+ sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
+ if (!sh) {
+ return;
+ }
+ _mesa_copy_string(sourceOut, maxLength, length, sh->Source);
+}
+
+
+/**
+ * Set/replace shader source code.
+ */
+static void
+shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source)
+{
+ struct gl_shader *sh;
+
+ sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
+ if (!sh)
+ return;
+
+ /* free old shader source string and install new one */
+ if (sh->Source) {
+ free((void *) sh->Source);
+ }
+ sh->Source = source;
+ sh->CompileStatus = GL_FALSE;
+#ifdef DEBUG
+ sh->SourceChecksum = _mesa_str_checksum(sh->Source);
+#endif
+}
+
+
+/**
+ * Compile a shader.
+ */
+static void
+compile_shader(struct gl_context *ctx, GLuint shaderObj)
+{
+ struct gl_shader *sh;
+ struct gl_shader_compiler_options *options;
+
+ sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
+ if (!sh)
+ return;
+
+ options = &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(sh->Type)];
+
+ /* set default pragma state for shader */
+ sh->Pragmas = options->DefaultPragmas;
+
+ /* this call will set the sh->CompileStatus field to indicate if
+ * compilation was successful.
+ */
+ _mesa_glsl_compile_shader(ctx, sh);
+}
+
+
+/**
+ * Link a program's shaders.
+ */
+static void
+link_program(struct gl_context *ctx, GLuint program)
+{
+ struct gl_shader_program *shProg;
+ struct gl_transform_feedback_object *obj =
+ ctx->TransformFeedback.CurrentObject;
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
+ if (!shProg)
+ return;
+
+ if (obj->Active
+ && (shProg == ctx->Shader.CurrentVertexProgram
+ || shProg == ctx->Shader.CurrentGeometryProgram
+ || shProg == ctx->Shader.CurrentFragmentProgram)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glLinkProgram(transform feedback active");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ _mesa_glsl_link_shader(ctx, shProg);
+
+ /* debug code */
+ if (0) {
+ GLuint i;
+
+ printf("Link %u shaders in program %u: %s\n",
+ shProg->NumShaders, shProg->Name,
+ shProg->LinkStatus ? "Success" : "Failed");
+
+ for (i = 0; i < shProg->NumShaders; i++) {
+ printf(" shader %u, type 0x%x\n",
+ shProg->Shaders[i]->Name,
+ shProg->Shaders[i]->Type);
+ }
+ }
+}
+
+
+/**
+ * Print basic shader info (for debug).
+ */
+static void
+print_shader_info(const struct gl_shader_program *shProg)
+{
+ GLuint i;
+
+ printf("Mesa: glUseProgram(%u)\n", shProg->Name);
+ for (i = 0; i < shProg->NumShaders; i++) {
+ const char *s;
+ switch (shProg->Shaders[i]->Type) {
+ case GL_VERTEX_SHADER:
+ s = "vertex";
+ break;
+ case GL_FRAGMENT_SHADER:
+ s = "fragment";
+ break;
+ case GL_GEOMETRY_SHADER:
+ s = "geometry";
+ break;
+ default:
+ s = "";
+ }
+ printf(" %s shader %u, checksum %u\n", s,
+ shProg->Shaders[i]->Name,
+ shProg->Shaders[i]->SourceChecksum);
+ }
+ if (shProg->VertexProgram)
+ printf(" vert prog %u\n", shProg->VertexProgram->Base.Id);
+ if (shProg->FragmentProgram)
+ printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id);
+}
+
+
+/**
+ * Use the named shader program for subsequent glUniform calls
+ */
+void
+_mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg,
+ const char *caller)
+{
+ if ((shProg != NULL) && !shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(program %u not linked)", caller, shProg->Name);
+ return;
+ }
+
+ if (ctx->Shader.ActiveProgram != shProg) {
+ _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, shProg);
+ }
+}
+
+/**
+ */
+static bool
+use_shader_program(struct gl_context *ctx, GLenum type,
+ struct gl_shader_program *shProg)
+{
+ struct gl_shader_program **target;
+
+ switch (type) {
+#if FEATURE_ARB_vertex_shader
+ case GL_VERTEX_SHADER:
+ target = &ctx->Shader.CurrentVertexProgram;
+ if ((shProg == NULL)
+ || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) {
+ shProg = NULL;
+ }
+ break;
+#endif
+#if FEATURE_ARB_geometry_shader4
+ case GL_GEOMETRY_SHADER_ARB:
+ target = &ctx->Shader.CurrentGeometryProgram;
+ if ((shProg == NULL)
+ || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) {
+ shProg = NULL;
+ }
+ break;
+#endif
+#if FEATURE_ARB_fragment_shader
+ case GL_FRAGMENT_SHADER:
+ target = &ctx->Shader.CurrentFragmentProgram;
+ if ((shProg == NULL)
+ || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) {
+ shProg = NULL;
+ }
+ break;
+#endif
+ default:
+ return false;
+ }
+
+ if (*target != shProg) {
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
+ _mesa_reference_shader_program(ctx, target, shProg);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Use the named shader program for subsequent rendering.
+ */
+void
+_mesa_use_program(struct gl_context *ctx, struct gl_shader_program *shProg)
+{
+ use_shader_program(ctx, GL_VERTEX_SHADER, shProg);
+ use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg);
+ use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg);
+ _mesa_active_program(ctx, shProg, "glUseProgram");
+
+ if (ctx->Driver.UseProgram)
+ ctx->Driver.UseProgram(ctx, shProg);
+}
+
+
+/**
+ * Validate a program's samplers.
+ * Specifically, check that there aren't two samplers of different types
+ * pointing to the same texture unit.
+ * \return GL_TRUE if valid, GL_FALSE if invalid
+ */
+static GLboolean
+validate_samplers(const struct gl_program *prog, char *errMsg)
+{
+ static const char *targetName[] = {
+ "TEXTURE_2D_ARRAY",
+ "TEXTURE_1D_ARRAY",
+ "TEXTURE_CUBE",
+ "TEXTURE_3D",
+ "TEXTURE_RECT",
+ "TEXTURE_2D",
+ "TEXTURE_1D",
+ };
+ GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS];
+ GLbitfield samplersUsed = prog->SamplersUsed;
+ GLuint i;
+
+ assert(Elements(targetName) == NUM_TEXTURE_TARGETS);
+
+ if (samplersUsed == 0x0)
+ return GL_TRUE;
+
+ for (i = 0; i < Elements(targetUsed); i++)
+ targetUsed[i] = -1;
+
+ /* walk over bits which are set in 'samplers' */
+ while (samplersUsed) {
+ GLuint unit;
+ gl_texture_index target;
+ GLint sampler = _mesa_ffs(samplersUsed) - 1;
+ assert(sampler >= 0);
+ assert(sampler < MAX_TEXTURE_IMAGE_UNITS);
+ unit = prog->SamplerUnits[sampler];
+ target = prog->SamplerTargets[sampler];
+ if (targetUsed[unit] != -1 && targetUsed[unit] != (int) target) {
+ _mesa_snprintf(errMsg, 100,
+ "Texture unit %d is accessed both as %s and %s",
+ unit, targetName[targetUsed[unit]], targetName[target]);
+ return GL_FALSE;
+ }
+ targetUsed[unit] = target;
+ samplersUsed ^= (1 << sampler);
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Do validation of the given shader program.
+ * \param errMsg returns error message if validation fails.
+ * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg)
+ */
+static GLboolean
+validate_shader_program(const struct gl_shader_program *shProg,
+ char *errMsg)
+{
+ const struct gl_vertex_program *vp = shProg->VertexProgram;
+ const struct gl_fragment_program *fp = shProg->FragmentProgram;
+
+ if (!shProg->LinkStatus) {
+ return GL_FALSE;
+ }
+
+ /* From the GL spec, a program is invalid if any of these are true:
+
+ any two active samplers in the current program object are of
+ different types, but refer to the same texture image unit,
+
+ any active sampler in the current program object refers to a texture
+ image unit where fixed-function fragment processing accesses a
+ texture target that does not match the sampler type, or
+
+ the sum of the number of active samplers in the program and the
+ number of texture image units enabled for fixed-function fragment
+ processing exceeds the combined limit on the total number of texture
+ image units allowed.
+ */
+
+
+ /*
+ * Check: any two active samplers in the current program object are of
+ * different types, but refer to the same texture image unit,
+ */
+ if (vp && !validate_samplers(&vp->Base, errMsg)) {
+ return GL_FALSE;
+ }
+ if (fp && !validate_samplers(&fp->Base, errMsg)) {
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Called via glValidateProgram()
+ */
+static void
+validate_program(struct gl_context *ctx, GLuint program)
+{
+ struct gl_shader_program *shProg;
+ char errMsg[100];
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
+ if (!shProg) {
+ return;
+ }
+
+ shProg->Validated = validate_shader_program(shProg, errMsg);
+ if (!shProg->Validated) {
+ /* update info log */
+ if (shProg->InfoLog) {
+ ralloc_free(shProg->InfoLog);
+ }
+ shProg->InfoLog = ralloc_strdup(shProg, errMsg);
+ }
+}
+
+
+
+void GLAPIENTRY
+_mesa_AttachObjectARB(GLhandleARB program, GLhandleARB shader)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ attach_shader(ctx, program, shader);
+}
+
+
+void GLAPIENTRY
+_mesa_AttachShader(GLuint program, GLuint shader)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ attach_shader(ctx, program, shader);
+}
+
+
+void GLAPIENTRY
+_mesa_BindAttribLocationARB(GLhandleARB program, GLuint index,
+ const GLcharARB *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ bind_attrib_location(ctx, program, index, name);
+}
+
+
+/* GL_EXT_gpu_shader4, GL3 */
+void GLAPIENTRY
+_mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
+ const GLchar *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ bind_frag_data_location(ctx, program, colorNumber, name);
+}
+
+
+void GLAPIENTRY
+_mesa_CompileShaderARB(GLhandleARB shaderObj)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glCompileShader %u\n", shaderObj);
+ compile_shader(ctx, shaderObj);
+}
+
+
+GLuint GLAPIENTRY
+_mesa_CreateShader(GLenum type)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glCreateShader %s\n", _mesa_lookup_enum_by_nr(type));
+ return create_shader(ctx, type);
+}
+
+
+GLhandleARB GLAPIENTRY
+_mesa_CreateShaderObjectARB(GLenum type)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ return create_shader(ctx, type);
+}
+
+
+GLuint GLAPIENTRY
+_mesa_CreateProgram(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glCreateProgram\n");
+ return create_shader_program(ctx);
+}
+
+
+GLhandleARB GLAPIENTRY
+_mesa_CreateProgramObjectARB(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ return create_shader_program(ctx);
+}
+
+
+void GLAPIENTRY
+_mesa_DeleteObjectARB(GLhandleARB obj)
+{
+ if (MESA_VERBOSE & VERBOSE_API) {
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_debug(ctx, "glDeleteObjectARB(%u)\n", obj);
+ }
+
+ if (obj) {
+ GET_CURRENT_CONTEXT(ctx);
+ if (is_program(ctx, obj)) {
+ delete_shader_program(ctx, obj);
+ }
+ else if (is_shader(ctx, obj)) {
+ delete_shader(ctx, obj);
+ }
+ else {
+ /* error? */
+ }
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_DeleteProgram(GLuint name)
+{
+ if (name) {
+ GET_CURRENT_CONTEXT(ctx);
+ delete_shader_program(ctx, name);
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_DeleteShader(GLuint name)
+{
+ if (name) {
+ GET_CURRENT_CONTEXT(ctx);
+ delete_shader(ctx, name);
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_DetachObjectARB(GLhandleARB program, GLhandleARB shader)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ detach_shader(ctx, program, shader);
+}
+
+
+void GLAPIENTRY
+_mesa_DetachShader(GLuint program, GLuint shader)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ detach_shader(ctx, program, shader);
+}
+
+
+void GLAPIENTRY
+_mesa_GetActiveAttribARB(GLhandleARB program, GLuint index,
+ GLsizei maxLength, GLsizei * length, GLint * size,
+ GLenum * type, GLcharARB * name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_active_attrib(ctx, program, index, maxLength, length, size, type, name);
+}
+
+
+void GLAPIENTRY
+_mesa_GetAttachedObjectsARB(GLhandleARB container, GLsizei maxCount,
+ GLsizei * count, GLhandleARB * obj)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_attached_shaders(ctx, container, maxCount, count, obj);
+}
+
+
+void GLAPIENTRY
+_mesa_GetAttachedShaders(GLuint program, GLsizei maxCount,
+ GLsizei *count, GLuint *obj)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_attached_shaders(ctx, program, maxCount, count, obj);
+}
+
+
+GLint GLAPIENTRY
+_mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ return get_attrib_location(ctx, program, name);
+}
+
+
+/* GL_EXT_gpu_shader4, GL3 */
+GLint GLAPIENTRY
+_mesa_GetFragDataLocation(GLuint program, const GLchar *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ return get_frag_data_location(ctx, program, name);
+}
+
+
+
+void GLAPIENTRY
+_mesa_GetInfoLogARB(GLhandleARB object, GLsizei maxLength, GLsizei * length,
+ GLcharARB * infoLog)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (is_program(ctx, object)) {
+ get_program_info_log(ctx, object, maxLength, length, infoLog);
+ }
+ else if (is_shader(ctx, object)) {
+ get_shader_info_log(ctx, object, maxLength, length, infoLog);
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInfoLogARB");
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetObjectParameterivARB(GLhandleARB object, GLenum pname, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ /* Implement in terms of GetProgramiv, GetShaderiv */
+ if (is_program(ctx, object)) {
+ if (pname == GL_OBJECT_TYPE_ARB) {
+ *params = GL_PROGRAM_OBJECT_ARB;
+ }
+ else {
+ get_programiv(ctx, object, pname, params);
+ }
+ }
+ else if (is_shader(ctx, object)) {
+ if (pname == GL_OBJECT_TYPE_ARB) {
+ *params = GL_SHADER_OBJECT_ARB;
+ }
+ else {
+ get_shaderiv(ctx, object, pname, params);
+ }
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetObjectParameterivARB");
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetObjectParameterfvARB(GLhandleARB object, GLenum pname,
+ GLfloat *params)
+{
+ GLint iparams[1]; /* XXX is one element enough? */
+ _mesa_GetObjectParameterivARB(object, pname, iparams);
+ params[0] = (GLfloat) iparams[0];
+}
+
+
+void GLAPIENTRY
+_mesa_GetProgramiv(GLuint program, GLenum pname, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_programiv(ctx, program, pname, params);
+}
+
+
+void GLAPIENTRY
+_mesa_GetShaderiv(GLuint shader, GLenum pname, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_shaderiv(ctx, shader, pname, params);
+}
+
+
+void GLAPIENTRY
+_mesa_GetProgramInfoLog(GLuint program, GLsizei bufSize,
+ GLsizei *length, GLchar *infoLog)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_program_info_log(ctx, program, bufSize, length, infoLog);
+}
+
+
+void GLAPIENTRY
+_mesa_GetShaderInfoLog(GLuint shader, GLsizei bufSize,
+ GLsizei *length, GLchar *infoLog)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_shader_info_log(ctx, shader, bufSize, length, infoLog);
+}
+
+
+void GLAPIENTRY
+_mesa_GetShaderSourceARB(GLhandleARB shader, GLsizei maxLength,
+ GLsizei *length, GLcharARB *sourceOut)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ get_shader_source(ctx, shader, maxLength, length, sourceOut);
+}
+
+
+GLhandleARB GLAPIENTRY
+_mesa_GetHandleARB(GLenum pname)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ return get_handle(ctx, pname);
+}
+
+
+GLboolean GLAPIENTRY
+_mesa_IsProgram(GLuint name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ return is_program(ctx, name);
+}
+
+
+GLboolean GLAPIENTRY
+_mesa_IsShader(GLuint name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ return is_shader(ctx, name);
+}
+
+
+void GLAPIENTRY
+_mesa_LinkProgramARB(GLhandleARB programObj)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ link_program(ctx, programObj);
+}
+
+
+
+/**
+ * Read shader source code from a file.
+ * Useful for debugging to override an app's shader.
+ */
+static GLcharARB *
+read_shader(const char *fname)
+{
+ const int max = 50*1000;
+ FILE *f = fopen(fname, "r");
+ GLcharARB *buffer, *shader;
+ int len;
+
+ if (!f) {
+ return NULL;
+ }
+
+ buffer = (char *) malloc(max);
+ len = fread(buffer, 1, max, f);
+ buffer[len] = 0;
+
+ fclose(f);
+
+ shader = _mesa_strdup(buffer);
+ free(buffer);
+
+ return shader;
+}
+
+
+/**
+ * Called via glShaderSource() and glShaderSourceARB() API functions.
+ * Basically, concatenate the source code strings into one long string
+ * and pass it to _mesa_shader_source().
+ */
+void GLAPIENTRY
+_mesa_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count,
+ const GLcharARB ** string, const GLint * length)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint *offsets;
+ GLsizei i, totalLength;
+ GLcharARB *source;
+ GLuint checksum;
+
+ if (!shaderObj || string == NULL) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB");
+ return;
+ }
+
+ /*
+ * This array holds offsets of where the appropriate string ends, thus the
+ * last element will be set to the total length of the source code.
+ */
+ offsets = (GLint *) malloc(count * sizeof(GLint));
+ if (offsets == NULL) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB");
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (string[i] == NULL) {
+ free((GLvoid *) offsets);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderSourceARB(null string)");
+ return;
+ }
+ if (length == NULL || length[i] < 0)
+ offsets[i] = strlen(string[i]);
+ else
+ offsets[i] = length[i];
+ /* accumulate string lengths */
+ if (i > 0)
+ offsets[i] += offsets[i - 1];
+ }
+
+ /* Total length of source string is sum off all strings plus two.
+ * One extra byte for terminating zero, another extra byte to silence
+ * valgrind warnings in the parser/grammer code.
+ */
+ totalLength = offsets[count - 1] + 2;
+ source = (GLcharARB *) malloc(totalLength * sizeof(GLcharARB));
+ if (source == NULL) {
+ free((GLvoid *) offsets);
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB");
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ GLint start = (i > 0) ? offsets[i - 1] : 0;
+ memcpy(source + start, string[i],
+ (offsets[i] - start) * sizeof(GLcharARB));
+ }
+ source[totalLength - 1] = '\0';
+ source[totalLength - 2] = '\0';
+
+ if (SHADER_SUBST) {
+ /* Compute the shader's source code checksum then try to open a file
+ * named newshader_<CHECKSUM>. If it exists, use it in place of the
+ * original shader source code. For debugging.
+ */
+ char filename[100];
+ GLcharARB *newSource;
+
+ checksum = _mesa_str_checksum(source);
+
+ _mesa_snprintf(filename, sizeof(filename), "newshader_%d", checksum);
+
+ newSource = read_shader(filename);
+ if (newSource) {
+ fprintf(stderr, "Mesa: Replacing shader %u chksum=%d with %s\n",
+ shaderObj, checksum, filename);
+ free(source);
+ source = newSource;
+ }
+ }
+
+ shader_source(ctx, shaderObj, source);
+
+ if (SHADER_SUBST) {
+ struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
+ if (sh)
+ sh->SourceChecksum = checksum; /* save original checksum */
+ }
+
+ free(offsets);
+}
+
+
+void GLAPIENTRY
+_mesa_UseProgramObjectARB(GLhandleARB program)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_shader_program *shProg;
+ struct gl_transform_feedback_object *obj =
+ ctx->TransformFeedback.CurrentObject;
+
+ if (obj->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUseProgram(transform feedback active)");
+ return;
+ }
+
+ if (program) {
+ shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
+ if (!shProg) {
+ return;
+ }
+ if (!shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUseProgram(program %u not linked)", program);
+ return;
+ }
+
+ /* debug code */
+ if (ctx->Shader.Flags & GLSL_USE_PROG) {
+ print_shader_info(shProg);
+ }
+ }
+ else {
+ shProg = NULL;
+ }
+
+ _mesa_use_program(ctx, shProg);
+}
+
+
+void GLAPIENTRY
+_mesa_ValidateProgramARB(GLhandleARB program)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ validate_program(ctx, program);
+}
+
+#ifdef FEATURE_ES2
+
+void GLAPIENTRY
+_mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype,
+ GLint* range, GLint* precision)
+{
+ const struct gl_program_constants *limits;
+ const struct gl_precision *p;
+ GET_CURRENT_CONTEXT(ctx);
+
+ switch (shadertype) {
+ case GL_VERTEX_SHADER:
+ limits = &ctx->Const.VertexProgram;
+ break;
+ case GL_FRAGMENT_SHADER:
+ limits = &ctx->Const.FragmentProgram;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetShaderPrecisionFormat(shadertype)");
+ return;
+ }
+
+ switch (precisiontype) {
+ case GL_LOW_FLOAT:
+ p = &limits->LowFloat;
+ break;
+ case GL_MEDIUM_FLOAT:
+ p = &limits->MediumFloat;
+ break;
+ case GL_HIGH_FLOAT:
+ p = &limits->HighFloat;
+ break;
+ case GL_LOW_INT:
+ p = &limits->LowInt;
+ break;
+ case GL_MEDIUM_INT:
+ p = &limits->MediumInt;
+ break;
+ case GL_HIGH_INT:
+ p = &limits->HighInt;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetShaderPrecisionFormat(precisiontype)");
+ return;
+ }
+
+ range[0] = p->RangeMin;
+ range[1] = p->RangeMax;
+ precision[0] = p->Precision;
+}
+
+
+void GLAPIENTRY
+_mesa_ReleaseShaderCompiler(void)
+{
+ _mesa_destroy_shader_compiler_caches();
+}
+
+
+void GLAPIENTRY
+_mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat,
+ const void* binary, GLint length)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) n;
+ (void) shaders;
+ (void) binaryformat;
+ (void) binary;
+ (void) length;
+ _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__);
+}
+
+#endif /* FEATURE_ES2 */
+
+
+#if FEATURE_ARB_geometry_shader4
+
+void GLAPIENTRY
+_mesa_ProgramParameteriARB(GLuint program, GLenum pname,
+ GLint value)
+{
+ struct gl_shader_program *shProg;
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program,
+ "glProgramParameteri");
+ if (!shProg)
+ return;
+
+ switch (pname) {
+ case GL_GEOMETRY_VERTICES_OUT_ARB:
+ if (value < 1 ||
+ (unsigned) value > ctx->Const.GeometryProgram.MaxGeometryOutputVertices) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d",
+ value);
+ return;
+ }
+ shProg->Geom.VerticesOut = value;
+ break;
+ case GL_GEOMETRY_INPUT_TYPE_ARB:
+ switch (value) {
+ case GL_POINTS:
+ case GL_LINES:
+ case GL_LINES_ADJACENCY_ARB:
+ case GL_TRIANGLES:
+ case GL_TRIANGLES_ADJACENCY_ARB:
+ shProg->Geom.InputType = value;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glProgramParameteri(geometry input type = %s",
+ _mesa_lookup_enum_by_nr(value));
+ return;
+ }
+ break;
+ case GL_GEOMETRY_OUTPUT_TYPE_ARB:
+ switch (value) {
+ case GL_POINTS:
+ case GL_LINE_STRIP:
+ case GL_TRIANGLE_STRIP:
+ shProg->Geom.OutputType = value;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glProgramParameteri(geometry output type = %s",
+ _mesa_lookup_enum_by_nr(value));
+ return;
+ }
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteriARB(pname=%s)",
+ _mesa_lookup_enum_by_nr(pname));
+ break;
+ }
+}
+
+#endif
+
+void
+_mesa_use_shader_program(struct gl_context *ctx, GLenum type,
+ struct gl_shader_program *shProg)
+{
+ use_shader_program(ctx, type, shProg);
+
+ if (ctx->Driver.UseProgram)
+ ctx->Driver.UseProgram(ctx, shProg);
+}
+
+void GLAPIENTRY
+_mesa_UseShaderProgramEXT(GLenum type, GLuint program)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_shader_program *shProg = NULL;
+
+ if (!validate_shader_target(ctx, type)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)");
+ return;
+ }
+
+ if (ctx->TransformFeedback.CurrentObject->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUseShaderProgramEXT(transform feedback is active)");
+ return;
+ }
+
+ if (program) {
+ shProg = _mesa_lookup_shader_program_err(ctx, program,
+ "glUseShaderProgramEXT");
+ if (shProg == NULL)
+ return;
+
+ if (!shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUseShaderProgramEXT(program not linked)");
+ return;
+ }
+ }
+
+ _mesa_use_shader_program(ctx, type, shProg);
+}
+
+void GLAPIENTRY
+_mesa_ActiveProgramEXT(GLuint program)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_shader_program *shProg = (program != 0)
+ ? _mesa_lookup_shader_program_err(ctx, program, "glActiveProgramEXT")
+ : NULL;
+
+ _mesa_active_program(ctx, shProg, "glActiveProgramEXT");
+ return;
+}
+
+GLuint GLAPIENTRY
+_mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ const GLuint shader = create_shader(ctx, type);
+ GLuint program = 0;
+
+ if (shader) {
+ shader_source(ctx, shader, _mesa_strdup(string));
+ compile_shader(ctx, shader);
+
+ program = create_shader_program(ctx);
+ if (program) {
+ struct gl_shader_program *shProg;
+ struct gl_shader *sh;
+ GLint compiled = GL_FALSE;
+
+ shProg = _mesa_lookup_shader_program(ctx, program);
+ sh = _mesa_lookup_shader(ctx, shader);
+
+ get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled);
+ if (compiled) {
+ attach_shader(ctx, program, shader);
+ link_program(ctx, program);
+ detach_shader(ctx, program, shader);
+
+#if 0
+ /* Possibly... */
+ if (active-user-defined-varyings-in-linked-program) {
+ append-error-to-info-log;
+ shProg->LinkStatus = GL_FALSE;
+ }
+#endif
+ }
+
+ ralloc_strcat(&shProg->InfoLog, sh->InfoLog);
+ }
+
+ delete_shader(ctx, shader);
+ }
+
+ return program;
+}
+
+/**
+ * Plug in shader-related functions into API dispatch table.
+ */
+void
+_mesa_init_shader_dispatch(struct _glapi_table *exec)
+{
+#if FEATURE_GL
+ /* GL_ARB_vertex/fragment_shader */
+ SET_DeleteObjectARB(exec, _mesa_DeleteObjectARB);
+ SET_GetHandleARB(exec, _mesa_GetHandleARB);
+ SET_DetachObjectARB(exec, _mesa_DetachObjectARB);
+ SET_CreateShaderObjectARB(exec, _mesa_CreateShaderObjectARB);
+ SET_ShaderSourceARB(exec, _mesa_ShaderSourceARB);
+ SET_CompileShaderARB(exec, _mesa_CompileShaderARB);
+ SET_CreateProgramObjectARB(exec, _mesa_CreateProgramObjectARB);
+ SET_AttachObjectARB(exec, _mesa_AttachObjectARB);
+ SET_LinkProgramARB(exec, _mesa_LinkProgramARB);
+ SET_UseProgramObjectARB(exec, _mesa_UseProgramObjectARB);
+ SET_ValidateProgramARB(exec, _mesa_ValidateProgramARB);
+ SET_GetObjectParameterfvARB(exec, _mesa_GetObjectParameterfvARB);
+ SET_GetObjectParameterivARB(exec, _mesa_GetObjectParameterivARB);
+ SET_GetInfoLogARB(exec, _mesa_GetInfoLogARB);
+ SET_GetAttachedObjectsARB(exec, _mesa_GetAttachedObjectsARB);
+ SET_GetShaderSourceARB(exec, _mesa_GetShaderSourceARB);
+
+ /* OpenGL 2.0 */
+ SET_AttachShader(exec, _mesa_AttachShader);
+ SET_CreateProgram(exec, _mesa_CreateProgram);
+ SET_CreateShader(exec, _mesa_CreateShader);
+ SET_DeleteProgram(exec, _mesa_DeleteProgram);
+ SET_DeleteShader(exec, _mesa_DeleteShader);
+ SET_DetachShader(exec, _mesa_DetachShader);
+ SET_GetAttachedShaders(exec, _mesa_GetAttachedShaders);
+ SET_GetProgramiv(exec, _mesa_GetProgramiv);
+ SET_GetProgramInfoLog(exec, _mesa_GetProgramInfoLog);
+ SET_GetShaderiv(exec, _mesa_GetShaderiv);
+ SET_GetShaderInfoLog(exec, _mesa_GetShaderInfoLog);
+ SET_IsProgram(exec, _mesa_IsProgram);
+ SET_IsShader(exec, _mesa_IsShader);
+
+#if FEATURE_ARB_vertex_shader
+ SET_BindAttribLocationARB(exec, _mesa_BindAttribLocationARB);
+ SET_GetActiveAttribARB(exec, _mesa_GetActiveAttribARB);
+ SET_GetAttribLocationARB(exec, _mesa_GetAttribLocationARB);
+#endif
+
+#if FEATURE_ARB_geometry_shader4
+ SET_ProgramParameteriARB(exec, _mesa_ProgramParameteriARB);
+#endif
+
+ SET_UseShaderProgramEXT(exec, _mesa_UseShaderProgramEXT);
+ SET_ActiveProgramEXT(exec, _mesa_ActiveProgramEXT);
+ SET_CreateShaderProgramEXT(exec, _mesa_CreateShaderProgramEXT);
+
+ /* GL_EXT_gpu_shader4 / GL 3.0 */
+ SET_BindFragDataLocationEXT(exec, _mesa_BindFragDataLocation);
+ SET_GetFragDataLocationEXT(exec, _mesa_GetFragDataLocation);
+
+ /* GL_ARB_ES2_compatibility */
+ SET_ReleaseShaderCompiler(exec, _mesa_ReleaseShaderCompiler);
+ SET_GetShaderPrecisionFormat(exec, _mesa_GetShaderPrecisionFormat);
+
+#endif /* FEATURE_GL */
+}
+
diff --git a/mesalib/src/mesa/main/stencil.c b/mesalib/src/mesa/main/stencil.c
index c63b14d27..b49ddbdbb 100644
--- a/mesalib/src/mesa/main/stencil.c
+++ b/mesalib/src/mesa/main/stencil.c
@@ -147,6 +147,9 @@ _mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLui
const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glStencilFuncSeparateATI()\n");
+
if (!validate_stencil_func(ctx, frontfunc)) {
_mesa_error(ctx, GL_INVALID_ENUM,
"glStencilFuncSeparateATI(frontfunc)");
@@ -203,6 +206,9 @@ _mesa_StencilFunc( GLenum func, GLint ref, GLuint mask )
const GLint face = ctx->Stencil.ActiveFace;
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glStencilFunc()\n");
+
if (!validate_stencil_func(ctx, func)) {
_mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)");
return;
@@ -267,6 +273,9 @@ _mesa_StencilMask( GLuint mask )
GET_CURRENT_CONTEXT(ctx);
const GLint face = ctx->Stencil.ActiveFace;
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glStencilMask()\n");
+
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (face != 0) {
@@ -321,6 +330,9 @@ _mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
GET_CURRENT_CONTEXT(ctx);
const GLint face = ctx->Stencil.ActiveFace;
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glStencilOp()\n");
+
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (!validate_stencil_op(ctx, fail)) {
@@ -386,6 +398,9 @@ _mesa_ActiveStencilFaceEXT(GLenum face)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glActiveStencilFaceEXT()\n");
+
if (!ctx->Extensions.EXT_stencil_two_side) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT");
return;
@@ -416,6 +431,9 @@ _mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glStencilOpSeparate()\n");
+
if (!validate_stencil_op(ctx, sfail)) {
_mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)");
return;
@@ -471,6 +489,9 @@ _mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glStencilFuncSeparate()\n");
+
if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
_mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)");
return;
@@ -509,6 +530,9 @@ _mesa_StencilMaskSeparate(GLenum face, GLuint mask)
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glStencilMaskSeparate()\n");
+
if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
_mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)");
return;
diff --git a/mesalib/src/mesa/program/ir_to_mesa.cpp b/mesalib/src/mesa/program/ir_to_mesa.cpp
index 3794c0de0..77946ad13 100644
--- a/mesalib/src/mesa/program/ir_to_mesa.cpp
+++ b/mesalib/src/mesa/program/ir_to_mesa.cpp
@@ -1,3234 +1,3267 @@
-/*
- * Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
- * Copyright (C) 2008 VMware, Inc. All Rights Reserved.
- * 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 ir_to_mesa.cpp
- *
- * Translate GLSL IR to Mesa's gl_program representation.
- */
-
-#include <stdio.h>
-#include "main/compiler.h"
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_print_visitor.h"
-#include "ir_expression_flattening.h"
-#include "glsl_types.h"
-#include "glsl_parser_extras.h"
-#include "../glsl/program.h"
-#include "ir_optimization.h"
-#include "ast.h"
-
-extern "C" {
-#include "main/mtypes.h"
-#include "main/shaderapi.h"
-#include "main/shaderobj.h"
-#include "main/uniforms.h"
-#include "program/hash_table.h"
-#include "program/prog_instruction.h"
-#include "program/prog_optimize.h"
-#include "program/prog_print.h"
-#include "program/program.h"
-#include "program/prog_uniform.h"
-#include "program/prog_parameter.h"
-#include "program/sampler.h"
-}
-
-static int swizzle_for_size(int size);
-
-/**
- * This struct is a corresponding struct to Mesa prog_src_register, with
- * wider fields.
- */
-typedef struct ir_to_mesa_src_reg {
- ir_to_mesa_src_reg(int file, int index, const glsl_type *type)
- {
- this->file = (gl_register_file) file;
- this->index = index;
- if (type && (type->is_scalar() || type->is_vector() || type->is_matrix()))
- this->swizzle = swizzle_for_size(type->vector_elements);
- else
- this->swizzle = SWIZZLE_XYZW;
- this->negate = 0;
- this->reladdr = NULL;
- }
-
- ir_to_mesa_src_reg()
- {
- this->file = PROGRAM_UNDEFINED;
- this->index = 0;
- this->swizzle = 0;
- this->negate = 0;
- this->reladdr = NULL;
- }
-
- gl_register_file file; /**< PROGRAM_* from Mesa */
- int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
- GLuint swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */
- int negate; /**< NEGATE_XYZW mask from mesa */
- /** Register index should be offset by the integer in this reg. */
- ir_to_mesa_src_reg *reladdr;
-} ir_to_mesa_src_reg;
-
-typedef struct ir_to_mesa_dst_reg {
- int file; /**< PROGRAM_* from Mesa */
- int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
- int writemask; /**< Bitfield of WRITEMASK_[XYZW] */
- GLuint cond_mask:4;
- /** Register index should be offset by the integer in this reg. */
- ir_to_mesa_src_reg *reladdr;
-} ir_to_mesa_dst_reg;
-
-extern ir_to_mesa_src_reg ir_to_mesa_undef;
-
-class ir_to_mesa_instruction : public exec_node {
-public:
- /* Callers of this ralloc-based new need not call delete. It's
- * easier to just ralloc_free 'ctx' (or any of its ancestors). */
- static void* operator new(size_t size, void *ctx)
- {
- void *node;
-
- node = rzalloc_size(ctx, size);
- assert(node != NULL);
-
- return node;
- }
-
- enum prog_opcode op;
- ir_to_mesa_dst_reg dst_reg;
- ir_to_mesa_src_reg src_reg[3];
- /** Pointer to the ir source this tree came from for debugging */
- ir_instruction *ir;
- GLboolean cond_update;
- bool saturate;
- int sampler; /**< sampler index */
- int tex_target; /**< One of TEXTURE_*_INDEX */
- GLboolean tex_shadow;
-
- class function_entry *function; /* Set on OPCODE_CAL or OPCODE_BGNSUB */
-};
-
-class variable_storage : public exec_node {
-public:
- variable_storage(ir_variable *var, gl_register_file file, int index)
- : file(file), index(index), var(var)
- {
- /* empty */
- }
-
- gl_register_file file;
- int index;
- ir_variable *var; /* variable that maps to this, if any */
-};
-
-class function_entry : public exec_node {
-public:
- ir_function_signature *sig;
-
- /**
- * identifier of this function signature used by the program.
- *
- * At the point that Mesa instructions for function calls are
- * generated, we don't know the address of the first instruction of
- * the function body. So we make the BranchTarget that is called a
- * small integer and rewrite them during set_branchtargets().
- */
- int sig_id;
-
- /**
- * Pointer to first instruction of the function body.
- *
- * Set during function body emits after main() is processed.
- */
- ir_to_mesa_instruction *bgn_inst;
-
- /**
- * Index of the first instruction of the function body in actual
- * Mesa IR.
- *
- * Set after convertion from ir_to_mesa_instruction to prog_instruction.
- */
- int inst;
-
- /** Storage for the return value. */
- ir_to_mesa_src_reg return_reg;
-};
-
-class ir_to_mesa_visitor : public ir_visitor {
-public:
- ir_to_mesa_visitor();
- ~ir_to_mesa_visitor();
-
- function_entry *current_function;
-
- struct gl_context *ctx;
- struct gl_program *prog;
- struct gl_shader_program *shader_program;
- struct gl_shader_compiler_options *options;
-
- int next_temp;
-
- variable_storage *find_variable_storage(ir_variable *var);
-
- function_entry *get_function_signature(ir_function_signature *sig);
-
- ir_to_mesa_src_reg get_temp(const glsl_type *type);
- void reladdr_to_temp(ir_instruction *ir,
- ir_to_mesa_src_reg *reg, int *num_reladdr);
-
- struct ir_to_mesa_src_reg src_reg_for_float(float val);
-
- /**
- * \name Visit methods
- *
- * As typical for the visitor pattern, there must be one \c visit method for
- * each concrete subclass of \c ir_instruction. Virtual base classes within
- * the hierarchy should not have \c visit methods.
- */
- /*@{*/
- virtual void visit(ir_variable *);
- virtual void visit(ir_loop *);
- virtual void visit(ir_loop_jump *);
- virtual void visit(ir_function_signature *);
- virtual void visit(ir_function *);
- virtual void visit(ir_expression *);
- virtual void visit(ir_swizzle *);
- virtual void visit(ir_dereference_variable *);
- virtual void visit(ir_dereference_array *);
- virtual void visit(ir_dereference_record *);
- virtual void visit(ir_assignment *);
- virtual void visit(ir_constant *);
- virtual void visit(ir_call *);
- virtual void visit(ir_return *);
- virtual void visit(ir_discard *);
- virtual void visit(ir_texture *);
- virtual void visit(ir_if *);
- /*@}*/
-
- struct ir_to_mesa_src_reg result;
-
- /** List of variable_storage */
- exec_list variables;
-
- /** List of function_entry */
- exec_list function_signatures;
- int next_signature_id;
-
- /** List of ir_to_mesa_instruction */
- exec_list instructions;
-
- ir_to_mesa_instruction *ir_to_mesa_emit_op0(ir_instruction *ir,
- enum prog_opcode op);
-
- ir_to_mesa_instruction *ir_to_mesa_emit_op1(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0);
-
- ir_to_mesa_instruction *ir_to_mesa_emit_op2(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0,
- ir_to_mesa_src_reg src1);
-
- ir_to_mesa_instruction *ir_to_mesa_emit_op3(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0,
- ir_to_mesa_src_reg src1,
- ir_to_mesa_src_reg src2);
-
- /**
- * Emit the correct dot-product instruction for the type of arguments
- *
- * \sa ir_to_mesa_emit_op2
- */
- void ir_to_mesa_emit_dp(ir_instruction *ir,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0,
- ir_to_mesa_src_reg src1,
- unsigned elements);
-
- void ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0);
-
- void ir_to_mesa_emit_scalar_op2(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0,
- ir_to_mesa_src_reg src1);
-
- void emit_scs(ir_instruction *ir, enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- const ir_to_mesa_src_reg &src);
-
- GLboolean try_emit_mad(ir_expression *ir,
- int mul_operand);
- GLboolean try_emit_sat(ir_expression *ir);
-
- void emit_swz(ir_expression *ir);
-
- bool process_move_condition(ir_rvalue *ir);
-
- void copy_propagate(void);
-
- void *mem_ctx;
-};
-
-ir_to_mesa_src_reg ir_to_mesa_undef = ir_to_mesa_src_reg(PROGRAM_UNDEFINED, 0, NULL);
-
-ir_to_mesa_dst_reg ir_to_mesa_undef_dst = {
- PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, COND_TR, NULL,
-};
-
-ir_to_mesa_dst_reg ir_to_mesa_address_reg = {
- PROGRAM_ADDRESS, 0, WRITEMASK_X, COND_TR, NULL
-};
-
-static void
-fail_link(struct gl_shader_program *prog, const char *fmt, ...) PRINTFLIKE(2, 3);
-
-static void
-fail_link(struct gl_shader_program *prog, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- ralloc_vasprintf_append(&prog->InfoLog, fmt, args);
- va_end(args);
-
- prog->LinkStatus = GL_FALSE;
-}
-
-static int
-swizzle_for_size(int size)
-{
- int size_swizzles[4] = {
- MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X),
- MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y),
- MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z),
- MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
- };
-
- assert((size >= 1) && (size <= 4));
- return size_swizzles[size - 1];
-}
-
-ir_to_mesa_instruction *
-ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0,
- ir_to_mesa_src_reg src1,
- ir_to_mesa_src_reg src2)
-{
- ir_to_mesa_instruction *inst = new(mem_ctx) ir_to_mesa_instruction();
- int num_reladdr = 0;
-
- /* If we have to do relative addressing, we want to load the ARL
- * reg directly for one of the regs, and preload the other reladdr
- * sources into temps.
- */
- num_reladdr += dst.reladdr != NULL;
- num_reladdr += src0.reladdr != NULL;
- num_reladdr += src1.reladdr != NULL;
- num_reladdr += src2.reladdr != NULL;
-
- reladdr_to_temp(ir, &src2, &num_reladdr);
- reladdr_to_temp(ir, &src1, &num_reladdr);
- reladdr_to_temp(ir, &src0, &num_reladdr);
-
- if (dst.reladdr) {
- ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg,
- *dst.reladdr);
-
- num_reladdr--;
- }
- assert(num_reladdr == 0);
-
- inst->op = op;
- inst->dst_reg = dst;
- inst->src_reg[0] = src0;
- inst->src_reg[1] = src1;
- inst->src_reg[2] = src2;
- inst->ir = ir;
-
- inst->function = NULL;
-
- this->instructions.push_tail(inst);
-
- return inst;
-}
-
-
-ir_to_mesa_instruction *
-ir_to_mesa_visitor::ir_to_mesa_emit_op2(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0,
- ir_to_mesa_src_reg src1)
-{
- return ir_to_mesa_emit_op3(ir, op, dst, src0, src1, ir_to_mesa_undef);
-}
-
-ir_to_mesa_instruction *
-ir_to_mesa_visitor::ir_to_mesa_emit_op1(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0)
-{
- assert(dst.writemask != 0);
- return ir_to_mesa_emit_op3(ir, op, dst,
- src0, ir_to_mesa_undef, ir_to_mesa_undef);
-}
-
-ir_to_mesa_instruction *
-ir_to_mesa_visitor::ir_to_mesa_emit_op0(ir_instruction *ir,
- enum prog_opcode op)
-{
- return ir_to_mesa_emit_op3(ir, op, ir_to_mesa_undef_dst,
- ir_to_mesa_undef,
- ir_to_mesa_undef,
- ir_to_mesa_undef);
-}
-
-void
-ir_to_mesa_visitor::ir_to_mesa_emit_dp(ir_instruction *ir,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0,
- ir_to_mesa_src_reg src1,
- unsigned elements)
-{
- static const gl_inst_opcode dot_opcodes[] = {
- OPCODE_DP2, OPCODE_DP3, OPCODE_DP4
- };
-
- ir_to_mesa_emit_op3(ir, dot_opcodes[elements - 2],
- dst, src0, src1, ir_to_mesa_undef);
-}
-
-inline ir_to_mesa_dst_reg
-ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg)
-{
- ir_to_mesa_dst_reg dst_reg;
-
- dst_reg.file = reg.file;
- dst_reg.index = reg.index;
- dst_reg.writemask = WRITEMASK_XYZW;
- dst_reg.cond_mask = COND_TR;
- dst_reg.reladdr = reg.reladdr;
-
- return dst_reg;
-}
-
-inline ir_to_mesa_src_reg
-ir_to_mesa_src_reg_from_dst(ir_to_mesa_dst_reg reg)
-{
- return ir_to_mesa_src_reg(reg.file, reg.index, NULL);
-}
-
-/**
- * Emits Mesa scalar opcodes to produce unique answers across channels.
- *
- * Some Mesa opcodes are scalar-only, like ARB_fp/vp. The src X
- * channel determines the result across all channels. So to do a vec4
- * of this operation, we want to emit a scalar per source channel used
- * to produce dest channels.
- */
-void
-ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op2(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg orig_src0,
- ir_to_mesa_src_reg orig_src1)
-{
- int i, j;
- int done_mask = ~dst.writemask;
-
- /* Mesa RCP is a scalar operation splatting results to all channels,
- * like ARB_fp/vp. So emit as many RCPs as necessary to cover our
- * dst channels.
- */
- for (i = 0; i < 4; i++) {
- GLuint this_mask = (1 << i);
- ir_to_mesa_instruction *inst;
- ir_to_mesa_src_reg src0 = orig_src0;
- ir_to_mesa_src_reg src1 = orig_src1;
-
- if (done_mask & this_mask)
- continue;
-
- GLuint src0_swiz = GET_SWZ(src0.swizzle, i);
- GLuint src1_swiz = GET_SWZ(src1.swizzle, i);
- for (j = i + 1; j < 4; j++) {
- /* If there is another enabled component in the destination that is
- * derived from the same inputs, generate its value on this pass as
- * well.
- */
- if (!(done_mask & (1 << j)) &&
- GET_SWZ(src0.swizzle, j) == src0_swiz &&
- GET_SWZ(src1.swizzle, j) == src1_swiz) {
- this_mask |= (1 << j);
- }
- }
- src0.swizzle = MAKE_SWIZZLE4(src0_swiz, src0_swiz,
- src0_swiz, src0_swiz);
- src1.swizzle = MAKE_SWIZZLE4(src1_swiz, src1_swiz,
- src1_swiz, src1_swiz);
-
- inst = ir_to_mesa_emit_op2(ir, op,
- dst,
- src0,
- src1);
- inst->dst_reg.writemask = this_mask;
- done_mask |= this_mask;
- }
-}
-
-void
-ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
- enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0)
-{
- ir_to_mesa_src_reg undef = ir_to_mesa_undef;
-
- undef.swizzle = SWIZZLE_XXXX;
-
- ir_to_mesa_emit_scalar_op2(ir, op, dst, src0, undef);
-}
-
-/**
- * Emit an OPCODE_SCS instruction
- *
- * The \c SCS opcode functions a bit differently than the other Mesa (or
- * ARB_fragment_program) opcodes. Instead of splatting its result across all
- * four components of the destination, it writes one value to the \c x
- * component and another value to the \c y component.
- *
- * \param ir IR instruction being processed
- * \param op Either \c OPCODE_SIN or \c OPCODE_COS depending on which
- * value is desired.
- * \param dst Destination register
- * \param src Source register
- */
-void
-ir_to_mesa_visitor::emit_scs(ir_instruction *ir, enum prog_opcode op,
- ir_to_mesa_dst_reg dst,
- const ir_to_mesa_src_reg &src)
-{
- /* Vertex programs cannot use the SCS opcode.
- */
- if (this->prog->Target == GL_VERTEX_PROGRAM_ARB) {
- ir_to_mesa_emit_scalar_op1(ir, op, dst, src);
- return;
- }
-
- const unsigned component = (op == OPCODE_SIN) ? 0 : 1;
- const unsigned scs_mask = (1U << component);
- int done_mask = ~dst.writemask;
- ir_to_mesa_src_reg tmp;
-
- assert(op == OPCODE_SIN || op == OPCODE_COS);
-
- /* If there are compnents in the destination that differ from the component
- * that will be written by the SCS instrution, we'll need a temporary.
- */
- if (scs_mask != unsigned(dst.writemask)) {
- tmp = get_temp(glsl_type::vec4_type);
- }
-
- for (unsigned i = 0; i < 4; i++) {
- unsigned this_mask = (1U << i);
- ir_to_mesa_src_reg src0 = src;
-
- if ((done_mask & this_mask) != 0)
- continue;
-
- /* The source swizzle specified which component of the source generates
- * sine / cosine for the current component in the destination. The SCS
- * instruction requires that this value be swizzle to the X component.
- * Replace the current swizzle with a swizzle that puts the source in
- * the X component.
- */
- unsigned src0_swiz = GET_SWZ(src.swizzle, i);
-
- src0.swizzle = MAKE_SWIZZLE4(src0_swiz, src0_swiz,
- src0_swiz, src0_swiz);
- for (unsigned j = i + 1; j < 4; j++) {
- /* If there is another enabled component in the destination that is
- * derived from the same inputs, generate its value on this pass as
- * well.
- */
- if (!(done_mask & (1 << j)) &&
- GET_SWZ(src0.swizzle, j) == src0_swiz) {
- this_mask |= (1 << j);
- }
- }
-
- if (this_mask != scs_mask) {
- ir_to_mesa_instruction *inst;
- ir_to_mesa_dst_reg tmp_dst = ir_to_mesa_dst_reg_from_src(tmp);
-
- /* Emit the SCS instruction.
- */
- inst = ir_to_mesa_emit_op1(ir, OPCODE_SCS, tmp_dst, src0);
- inst->dst_reg.writemask = scs_mask;
-
- /* Move the result of the SCS instruction to the desired location in
- * the destination.
- */
- tmp.swizzle = MAKE_SWIZZLE4(component, component,
- component, component);
- inst = ir_to_mesa_emit_op1(ir, OPCODE_SCS, dst, tmp);
- inst->dst_reg.writemask = this_mask;
- } else {
- /* Emit the SCS instruction to write directly to the destination.
- */
- ir_to_mesa_instruction *inst =
- ir_to_mesa_emit_op1(ir, OPCODE_SCS, dst, src0);
- inst->dst_reg.writemask = scs_mask;
- }
-
- done_mask |= this_mask;
- }
-}
-
-struct ir_to_mesa_src_reg
-ir_to_mesa_visitor::src_reg_for_float(float val)
-{
- ir_to_mesa_src_reg src_reg(PROGRAM_CONSTANT, -1, NULL);
-
- src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
- &val, 1, &src_reg.swizzle);
-
- return src_reg;
-}
-
-static int
-type_size(const struct glsl_type *type)
-{
- unsigned int i;
- int size;
-
- switch (type->base_type) {
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT:
- case GLSL_TYPE_FLOAT:
- case GLSL_TYPE_BOOL:
- if (type->is_matrix()) {
- return type->matrix_columns;
- } else {
- /* Regardless of size of vector, it gets a vec4. This is bad
- * packing for things like floats, but otherwise arrays become a
- * mess. Hopefully a later pass over the code can pack scalars
- * down if appropriate.
- */
- return 1;
- }
- case GLSL_TYPE_ARRAY:
- assert(type->length > 0);
- return type_size(type->fields.array) * type->length;
- case GLSL_TYPE_STRUCT:
- size = 0;
- for (i = 0; i < type->length; i++) {
- size += type_size(type->fields.structure[i].type);
- }
- return size;
- case GLSL_TYPE_SAMPLER:
- /* Samplers take up one slot in UNIFORMS[], but they're baked in
- * at link time.
- */
- return 1;
- default:
- assert(0);
- return 0;
- }
-}
-
-/**
- * In the initial pass of codegen, we assign temporary numbers to
- * intermediate results. (not SSA -- variable assignments will reuse
- * storage). Actual register allocation for the Mesa VM occurs in a
- * pass over the Mesa IR later.
- */
-ir_to_mesa_src_reg
-ir_to_mesa_visitor::get_temp(const glsl_type *type)
-{
- ir_to_mesa_src_reg src_reg;
- int swizzle[4];
- int i;
-
- src_reg.file = PROGRAM_TEMPORARY;
- src_reg.index = next_temp;
- src_reg.reladdr = NULL;
- next_temp += type_size(type);
-
- if (type->is_array() || type->is_record()) {
- src_reg.swizzle = SWIZZLE_NOOP;
- } else {
- for (i = 0; i < type->vector_elements; i++)
- swizzle[i] = i;
- for (; i < 4; i++)
- swizzle[i] = type->vector_elements - 1;
- src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1],
- swizzle[2], swizzle[3]);
- }
- src_reg.negate = 0;
-
- return src_reg;
-}
-
-variable_storage *
-ir_to_mesa_visitor::find_variable_storage(ir_variable *var)
-{
-
- variable_storage *entry;
-
- foreach_iter(exec_list_iterator, iter, this->variables) {
- entry = (variable_storage *)iter.get();
-
- if (entry->var == var)
- return entry;
- }
-
- return NULL;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_variable *ir)
-{
- if (strcmp(ir->name, "gl_FragCoord") == 0) {
- struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog;
-
- fp->OriginUpperLeft = ir->origin_upper_left;
- fp->PixelCenterInteger = ir->pixel_center_integer;
-
- } else if (strcmp(ir->name, "gl_FragDepth") == 0) {
- struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog;
- switch (ir->depth_layout) {
- case ir_depth_layout_none:
- fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_NONE;
- break;
- case ir_depth_layout_any:
- fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_ANY;
- break;
- case ir_depth_layout_greater:
- fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_GREATER;
- break;
- case ir_depth_layout_less:
- fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_LESS;
- break;
- case ir_depth_layout_unchanged:
- fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_UNCHANGED;
- break;
- default:
- assert(0);
- break;
- }
- }
-
- if (ir->mode == ir_var_uniform && strncmp(ir->name, "gl_", 3) == 0) {
- unsigned int i;
- const struct gl_builtin_uniform_desc *statevar;
-
- for (i = 0; _mesa_builtin_uniform_desc[i].name; i++) {
- if (strcmp(ir->name, _mesa_builtin_uniform_desc[i].name) == 0)
- break;
- }
-
- if (!_mesa_builtin_uniform_desc[i].name) {
- fail_link(this->shader_program,
- "Failed to find builtin uniform `%s'\n", ir->name);
- return;
- }
-
- statevar = &_mesa_builtin_uniform_desc[i];
-
- int array_count;
- if (ir->type->is_array()) {
- array_count = ir->type->length;
- } else {
- array_count = 1;
- }
-
- /* Check if this statevar's setup in the STATE file exactly
- * matches how we'll want to reference it as a
- * struct/array/whatever. If not, then we need to move it into
- * temporary storage and hope that it'll get copy-propagated
- * out.
- */
- for (i = 0; i < statevar->num_elements; i++) {
- if (statevar->elements[i].swizzle != SWIZZLE_XYZW) {
- break;
- }
- }
-
- struct variable_storage *storage;
- ir_to_mesa_dst_reg dst;
- if (i == statevar->num_elements) {
- /* We'll set the index later. */
- storage = new(mem_ctx) variable_storage(ir, PROGRAM_STATE_VAR, -1);
- this->variables.push_tail(storage);
-
- dst = ir_to_mesa_undef_dst;
- } else {
- storage = new(mem_ctx) variable_storage(ir, PROGRAM_TEMPORARY,
- this->next_temp);
- this->variables.push_tail(storage);
- this->next_temp += type_size(ir->type);
-
- dst = ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg(PROGRAM_TEMPORARY,
- storage->index,
- NULL));
- }
-
-
- for (int a = 0; a < array_count; a++) {
- for (unsigned int i = 0; i < statevar->num_elements; i++) {
- struct gl_builtin_uniform_element *element = &statevar->elements[i];
- int tokens[STATE_LENGTH];
-
- memcpy(tokens, element->tokens, sizeof(element->tokens));
- if (ir->type->is_array()) {
- tokens[1] = a;
- }
-
- int index = _mesa_add_state_reference(this->prog->Parameters,
- (gl_state_index *)tokens);
-
- if (storage->file == PROGRAM_STATE_VAR) {
- if (storage->index == -1) {
- storage->index = index;
- } else {
- assert(index ==
- (int)(storage->index + a * statevar->num_elements + i));
- }
- } else {
- ir_to_mesa_src_reg src(PROGRAM_STATE_VAR, index, NULL);
- src.swizzle = element->swizzle;
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, dst, src);
- /* even a float takes up a whole vec4 reg in a struct/array. */
- dst.index++;
- }
- }
- }
- if (storage->file == PROGRAM_TEMPORARY &&
- dst.index != storage->index + type_size(ir->type)) {
- fail_link(this->shader_program,
- "failed to load builtin uniform `%s' (%d/%d regs loaded)\n",
- ir->name, dst.index - storage->index,
- type_size(ir->type));
- }
- }
-}
-
-void
-ir_to_mesa_visitor::visit(ir_loop *ir)
-{
- ir_dereference_variable *counter = NULL;
-
- if (ir->counter != NULL)
- counter = new(ir) ir_dereference_variable(ir->counter);
-
- if (ir->from != NULL) {
- assert(ir->counter != NULL);
-
- ir_assignment *a = new(ir) ir_assignment(counter, ir->from, NULL);
-
- a->accept(this);
- delete a;
- }
-
- ir_to_mesa_emit_op0(NULL, OPCODE_BGNLOOP);
-
- if (ir->to) {
- ir_expression *e =
- new(ir) ir_expression(ir->cmp, glsl_type::bool_type,
- counter, ir->to);
- ir_if *if_stmt = new(ir) ir_if(e);
-
- ir_loop_jump *brk = new(ir) ir_loop_jump(ir_loop_jump::jump_break);
-
- if_stmt->then_instructions.push_tail(brk);
-
- if_stmt->accept(this);
-
- delete if_stmt;
- delete e;
- delete brk;
- }
-
- visit_exec_list(&ir->body_instructions, this);
-
- if (ir->increment) {
- ir_expression *e =
- new(ir) ir_expression(ir_binop_add, counter->type,
- counter, ir->increment);
-
- ir_assignment *a = new(ir) ir_assignment(counter, e, NULL);
-
- a->accept(this);
- delete a;
- delete e;
- }
-
- ir_to_mesa_emit_op0(NULL, OPCODE_ENDLOOP);
-}
-
-void
-ir_to_mesa_visitor::visit(ir_loop_jump *ir)
-{
- switch (ir->mode) {
- case ir_loop_jump::jump_break:
- ir_to_mesa_emit_op0(NULL, OPCODE_BRK);
- break;
- case ir_loop_jump::jump_continue:
- ir_to_mesa_emit_op0(NULL, OPCODE_CONT);
- break;
- }
-}
-
-
-void
-ir_to_mesa_visitor::visit(ir_function_signature *ir)
-{
- assert(0);
- (void)ir;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_function *ir)
-{
- /* Ignore function bodies other than main() -- we shouldn't see calls to
- * them since they should all be inlined before we get to ir_to_mesa.
- */
- if (strcmp(ir->name, "main") == 0) {
- const ir_function_signature *sig;
- exec_list empty;
-
- sig = ir->matching_signature(&empty);
-
- assert(sig);
-
- foreach_iter(exec_list_iterator, iter, sig->body) {
- ir_instruction *ir = (ir_instruction *)iter.get();
-
- ir->accept(this);
- }
- }
-}
-
-GLboolean
-ir_to_mesa_visitor::try_emit_mad(ir_expression *ir, int mul_operand)
-{
- int nonmul_operand = 1 - mul_operand;
- ir_to_mesa_src_reg a, b, c;
-
- ir_expression *expr = ir->operands[mul_operand]->as_expression();
- if (!expr || expr->operation != ir_binop_mul)
- return false;
-
- expr->operands[0]->accept(this);
- a = this->result;
- expr->operands[1]->accept(this);
- b = this->result;
- ir->operands[nonmul_operand]->accept(this);
- c = this->result;
-
- this->result = get_temp(ir->type);
- ir_to_mesa_emit_op3(ir, OPCODE_MAD,
- ir_to_mesa_dst_reg_from_src(this->result), a, b, c);
-
- return true;
-}
-
-GLboolean
-ir_to_mesa_visitor::try_emit_sat(ir_expression *ir)
-{
- /* Saturates were only introduced to vertex programs in
- * NV_vertex_program3, so don't give them to drivers in the VP.
- */
- if (this->prog->Target == GL_VERTEX_PROGRAM_ARB)
- return false;
-
- ir_rvalue *sat_src = ir->as_rvalue_to_saturate();
- if (!sat_src)
- return false;
-
- sat_src->accept(this);
- ir_to_mesa_src_reg src = this->result;
-
- this->result = get_temp(ir->type);
- ir_to_mesa_instruction *inst;
- inst = ir_to_mesa_emit_op1(ir, OPCODE_MOV,
- ir_to_mesa_dst_reg_from_src(this->result),
- src);
- inst->saturate = true;
-
- return true;
-}
-
-void
-ir_to_mesa_visitor::reladdr_to_temp(ir_instruction *ir,
- ir_to_mesa_src_reg *reg, int *num_reladdr)
-{
- if (!reg->reladdr)
- return;
-
- ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg, *reg->reladdr);
-
- if (*num_reladdr != 1) {
- ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
-
- ir_to_mesa_emit_op1(ir, OPCODE_MOV,
- ir_to_mesa_dst_reg_from_src(temp), *reg);
- *reg = temp;
- }
-
- (*num_reladdr)--;
-}
-
-void
-ir_to_mesa_visitor::emit_swz(ir_expression *ir)
-{
- /* Assume that the vector operator is in a form compatible with OPCODE_SWZ.
- * This means that each of the operands is either an immediate value of -1,
- * 0, or 1, or is a component from one source register (possibly with
- * negation).
- */
- uint8_t components[4] = { 0 };
- bool negate[4] = { false };
- ir_variable *var = NULL;
-
- for (unsigned i = 0; i < ir->type->vector_elements; i++) {
- ir_rvalue *op = ir->operands[i];
-
- assert(op->type->is_scalar());
-
- while (op != NULL) {
- switch (op->ir_type) {
- case ir_type_constant: {
-
- assert(op->type->is_scalar());
-
- const ir_constant *const c = op->as_constant();
- if (c->is_one()) {
- components[i] = SWIZZLE_ONE;
- } else if (c->is_zero()) {
- components[i] = SWIZZLE_ZERO;
- } else if (c->is_negative_one()) {
- components[i] = SWIZZLE_ONE;
- negate[i] = true;
- } else {
- assert(!"SWZ constant must be 0.0 or 1.0.");
- }
-
- op = NULL;
- break;
- }
-
- case ir_type_dereference_variable: {
- ir_dereference_variable *const deref =
- (ir_dereference_variable *) op;
-
- assert((var == NULL) || (deref->var == var));
- components[i] = SWIZZLE_X;
- var = deref->var;
- op = NULL;
- break;
- }
-
- case ir_type_expression: {
- ir_expression *const expr = (ir_expression *) op;
-
- assert(expr->operation == ir_unop_neg);
- negate[i] = true;
-
- op = expr->operands[0];
- break;
- }
-
- case ir_type_swizzle: {
- ir_swizzle *const swiz = (ir_swizzle *) op;
-
- components[i] = swiz->mask.x;
- op = swiz->val;
- break;
- }
-
- default:
- assert(!"Should not get here.");
- return;
- }
- }
- }
-
- assert(var != NULL);
-
- ir_dereference_variable *const deref =
- new(mem_ctx) ir_dereference_variable(var);
-
- this->result.file = PROGRAM_UNDEFINED;
- deref->accept(this);
- if (this->result.file == PROGRAM_UNDEFINED) {
- ir_print_visitor v;
- printf("Failed to get tree for expression operand:\n");
- deref->accept(&v);
- exit(1);
- }
-
- ir_to_mesa_src_reg src;
-
- src = this->result;
- src.swizzle = MAKE_SWIZZLE4(components[0],
- components[1],
- components[2],
- components[3]);
- src.negate = ((unsigned(negate[0]) << 0)
- | (unsigned(negate[1]) << 1)
- | (unsigned(negate[2]) << 2)
- | (unsigned(negate[3]) << 3));
-
- /* Storage for our result. Ideally for an assignment we'd be using the
- * actual storage for the result here, instead.
- */
- const ir_to_mesa_src_reg result_src = get_temp(ir->type);
- ir_to_mesa_dst_reg result_dst = ir_to_mesa_dst_reg_from_src(result_src);
-
- /* Limit writes to the channels that will be used by result_src later.
- * This does limit this temp's use as a temporary for multi-instruction
- * sequences.
- */
- result_dst.writemask = (1 << ir->type->vector_elements) - 1;
-
- ir_to_mesa_emit_op1(ir, OPCODE_SWZ, result_dst, src);
- this->result = result_src;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_expression *ir)
-{
- unsigned int operand;
- struct ir_to_mesa_src_reg op[Elements(ir->operands)];
- struct ir_to_mesa_src_reg result_src;
- struct ir_to_mesa_dst_reg result_dst;
-
- /* Quick peephole: Emit OPCODE_MAD(a, b, c) instead of ADD(MUL(a, b), c)
- */
- if (ir->operation == ir_binop_add) {
- if (try_emit_mad(ir, 1))
- return;
- if (try_emit_mad(ir, 0))
- return;
- }
- if (try_emit_sat(ir))
- return;
-
- if (ir->operation == ir_quadop_vector) {
- this->emit_swz(ir);
- return;
- }
-
- for (operand = 0; operand < ir->get_num_operands(); operand++) {
- this->result.file = PROGRAM_UNDEFINED;
- ir->operands[operand]->accept(this);
- if (this->result.file == PROGRAM_UNDEFINED) {
- ir_print_visitor v;
- printf("Failed to get tree for expression operand:\n");
- ir->operands[operand]->accept(&v);
- exit(1);
- }
- op[operand] = this->result;
-
- /* Matrix expression operands should have been broken down to vector
- * operations already.
- */
- assert(!ir->operands[operand]->type->is_matrix());
- }
-
- int vector_elements = ir->operands[0]->type->vector_elements;
- if (ir->operands[1]) {
- vector_elements = MAX2(vector_elements,
- ir->operands[1]->type->vector_elements);
- }
-
- this->result.file = PROGRAM_UNDEFINED;
-
- /* Storage for our result. Ideally for an assignment we'd be using
- * the actual storage for the result here, instead.
- */
- result_src = get_temp(ir->type);
- /* convenience for the emit functions below. */
- result_dst = ir_to_mesa_dst_reg_from_src(result_src);
- /* Limit writes to the channels that will be used by result_src later.
- * This does limit this temp's use as a temporary for multi-instruction
- * sequences.
- */
- result_dst.writemask = (1 << ir->type->vector_elements) - 1;
-
- switch (ir->operation) {
- case ir_unop_logic_not:
- ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst,
- op[0], src_reg_for_float(0.0));
- break;
- case ir_unop_neg:
- op[0].negate = ~op[0].negate;
- result_src = op[0];
- break;
- case ir_unop_abs:
- ir_to_mesa_emit_op1(ir, OPCODE_ABS, result_dst, op[0]);
- break;
- case ir_unop_sign:
- ir_to_mesa_emit_op1(ir, OPCODE_SSG, result_dst, op[0]);
- break;
- case ir_unop_rcp:
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_RCP, result_dst, op[0]);
- break;
-
- case ir_unop_exp2:
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_EX2, result_dst, op[0]);
- break;
- case ir_unop_exp:
- case ir_unop_log:
- assert(!"not reached: should be handled by ir_explog_to_explog2");
- break;
- case ir_unop_log2:
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_LG2, result_dst, op[0]);
- break;
- case ir_unop_sin:
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_SIN, result_dst, op[0]);
- break;
- case ir_unop_cos:
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_COS, result_dst, op[0]);
- break;
- case ir_unop_sin_reduced:
- emit_scs(ir, OPCODE_SIN, result_dst, op[0]);
- break;
- case ir_unop_cos_reduced:
- emit_scs(ir, OPCODE_COS, result_dst, op[0]);
- break;
-
- case ir_unop_dFdx:
- ir_to_mesa_emit_op1(ir, OPCODE_DDX, result_dst, op[0]);
- break;
- case ir_unop_dFdy:
- ir_to_mesa_emit_op1(ir, OPCODE_DDY, result_dst, op[0]);
- break;
-
- case ir_unop_noise: {
- const enum prog_opcode opcode =
- prog_opcode(OPCODE_NOISE1
- + (ir->operands[0]->type->vector_elements) - 1);
- assert((opcode >= OPCODE_NOISE1) && (opcode <= OPCODE_NOISE4));
-
- ir_to_mesa_emit_op1(ir, opcode, result_dst, op[0]);
- break;
- }
-
- case ir_binop_add:
- ir_to_mesa_emit_op2(ir, OPCODE_ADD, result_dst, op[0], op[1]);
- break;
- case ir_binop_sub:
- ir_to_mesa_emit_op2(ir, OPCODE_SUB, result_dst, op[0], op[1]);
- break;
-
- case ir_binop_mul:
- ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], op[1]);
- break;
- case ir_binop_div:
- assert(!"not reached: should be handled by ir_div_to_mul_rcp");
- case ir_binop_mod:
- assert(!"ir_binop_mod should have been converted to b * fract(a/b)");
- break;
-
- case ir_binop_less:
- ir_to_mesa_emit_op2(ir, OPCODE_SLT, result_dst, op[0], op[1]);
- break;
- case ir_binop_greater:
- ir_to_mesa_emit_op2(ir, OPCODE_SGT, result_dst, op[0], op[1]);
- break;
- case ir_binop_lequal:
- ir_to_mesa_emit_op2(ir, OPCODE_SLE, result_dst, op[0], op[1]);
- break;
- case ir_binop_gequal:
- ir_to_mesa_emit_op2(ir, OPCODE_SGE, result_dst, op[0], op[1]);
- break;
- case ir_binop_equal:
- ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
- break;
- case ir_binop_nequal:
- ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
- break;
- case ir_binop_all_equal:
- /* "==" operator producing a scalar boolean. */
- if (ir->operands[0]->type->is_vector() ||
- ir->operands[1]->type->is_vector()) {
- ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
- ir_to_mesa_emit_op2(ir, OPCODE_SNE,
- ir_to_mesa_dst_reg_from_src(temp), op[0], op[1]);
- ir_to_mesa_emit_dp(ir, result_dst, temp, temp, vector_elements);
- ir_to_mesa_emit_op2(ir, OPCODE_SEQ,
- result_dst, result_src, src_reg_for_float(0.0));
- } else {
- ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
- }
- break;
- case ir_binop_any_nequal:
- /* "!=" operator producing a scalar boolean. */
- if (ir->operands[0]->type->is_vector() ||
- ir->operands[1]->type->is_vector()) {
- ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
- ir_to_mesa_emit_op2(ir, OPCODE_SNE,
- ir_to_mesa_dst_reg_from_src(temp), op[0], op[1]);
- ir_to_mesa_emit_dp(ir, result_dst, temp, temp, vector_elements);
- ir_to_mesa_emit_op2(ir, OPCODE_SNE,
- result_dst, result_src, src_reg_for_float(0.0));
- } else {
- ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
- }
- break;
-
- case ir_unop_any:
- assert(ir->operands[0]->type->is_vector());
- ir_to_mesa_emit_dp(ir, result_dst, op[0], op[0],
- ir->operands[0]->type->vector_elements);
- ir_to_mesa_emit_op2(ir, OPCODE_SNE,
- result_dst, result_src, src_reg_for_float(0.0));
- break;
-
- case ir_binop_logic_xor:
- ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
- break;
-
- case ir_binop_logic_or:
- /* This could be a saturated add and skip the SNE. */
- ir_to_mesa_emit_op2(ir, OPCODE_ADD,
- result_dst,
- op[0], op[1]);
-
- ir_to_mesa_emit_op2(ir, OPCODE_SNE,
- result_dst,
- result_src, src_reg_for_float(0.0));
- break;
-
- case ir_binop_logic_and:
- /* the bool args are stored as float 0.0 or 1.0, so "mul" gives us "and". */
- ir_to_mesa_emit_op2(ir, OPCODE_MUL,
- result_dst,
- op[0], op[1]);
- break;
-
- case ir_binop_dot:
- assert(ir->operands[0]->type->is_vector());
- assert(ir->operands[0]->type == ir->operands[1]->type);
- ir_to_mesa_emit_dp(ir, result_dst, op[0], op[1],
- ir->operands[0]->type->vector_elements);
- break;
-
- case ir_unop_sqrt:
- /* sqrt(x) = x * rsq(x). */
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
- ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, result_src, op[0]);
- /* For incoming channels <= 0, set the result to 0. */
- op[0].negate = ~op[0].negate;
- ir_to_mesa_emit_op3(ir, OPCODE_CMP, result_dst,
- op[0], result_src, src_reg_for_float(0.0));
- break;
- case ir_unop_rsq:
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
- break;
- case ir_unop_i2f:
- case ir_unop_b2f:
- case ir_unop_b2i:
- /* Mesa IR lacks types, ints are stored as truncated floats. */
- result_src = op[0];
- break;
- case ir_unop_f2i:
- ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]);
- break;
- case ir_unop_f2b:
- case ir_unop_i2b:
- ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst,
- op[0], src_reg_for_float(0.0));
- break;
- case ir_unop_trunc:
- ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]);
- break;
- case ir_unop_ceil:
- op[0].negate = ~op[0].negate;
- ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]);
- result_src.negate = ~result_src.negate;
- break;
- case ir_unop_floor:
- ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]);
- break;
- case ir_unop_fract:
- ir_to_mesa_emit_op1(ir, OPCODE_FRC, result_dst, op[0]);
- break;
-
- case ir_binop_min:
- ir_to_mesa_emit_op2(ir, OPCODE_MIN, result_dst, op[0], op[1]);
- break;
- case ir_binop_max:
- ir_to_mesa_emit_op2(ir, OPCODE_MAX, result_dst, op[0], op[1]);
- break;
- case ir_binop_pow:
- ir_to_mesa_emit_scalar_op2(ir, OPCODE_POW, result_dst, op[0], op[1]);
- break;
-
- case ir_unop_bit_not:
- case ir_unop_u2f:
- case ir_binop_lshift:
- case ir_binop_rshift:
- case ir_binop_bit_and:
- case ir_binop_bit_xor:
- case ir_binop_bit_or:
- case ir_unop_round_even:
- assert(!"GLSL 1.30 features unsupported");
- break;
-
- case ir_quadop_vector:
- /* This operation should have already been handled.
- */
- assert(!"Should not get here.");
- break;
- }
-
- this->result = result_src;
-}
-
-
-void
-ir_to_mesa_visitor::visit(ir_swizzle *ir)
-{
- ir_to_mesa_src_reg src_reg;
- int i;
- int swizzle[4];
-
- /* Note that this is only swizzles in expressions, not those on the left
- * hand side of an assignment, which do write masking. See ir_assignment
- * for that.
- */
-
- ir->val->accept(this);
- src_reg = this->result;
- assert(src_reg.file != PROGRAM_UNDEFINED);
-
- for (i = 0; i < 4; i++) {
- if (i < ir->type->vector_elements) {
- switch (i) {
- case 0:
- swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.x);
- break;
- case 1:
- swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.y);
- break;
- case 2:
- swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.z);
- break;
- case 3:
- swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.w);
- break;
- }
- } else {
- /* If the type is smaller than a vec4, replicate the last
- * channel out.
- */
- swizzle[i] = swizzle[ir->type->vector_elements - 1];
- }
- }
-
- src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0],
- swizzle[1],
- swizzle[2],
- swizzle[3]);
-
- this->result = src_reg;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_dereference_variable *ir)
-{
- variable_storage *entry = find_variable_storage(ir->var);
- ir_variable *var = ir->var;
-
- if (!entry) {
- switch (var->mode) {
- case ir_var_uniform:
- entry = new(mem_ctx) variable_storage(var, PROGRAM_UNIFORM,
- var->location);
- this->variables.push_tail(entry);
- break;
- case ir_var_in:
- case ir_var_inout:
- /* The linker assigns locations for varyings and attributes,
- * including deprecated builtins (like gl_Color), user-assign
- * generic attributes (glBindVertexLocation), and
- * user-defined varyings.
- *
- * FINISHME: We would hit this path for function arguments. Fix!
- */
- assert(var->location != -1);
- entry = new(mem_ctx) variable_storage(var,
- PROGRAM_INPUT,
- var->location);
- if (this->prog->Target == GL_VERTEX_PROGRAM_ARB &&
- var->location >= VERT_ATTRIB_GENERIC0) {
- _mesa_add_attribute(this->prog->Attributes,
- var->name,
- _mesa_sizeof_glsl_type(var->type->gl_type),
- var->type->gl_type,
- var->location - VERT_ATTRIB_GENERIC0);
- }
- break;
- case ir_var_out:
- assert(var->location != -1);
- entry = new(mem_ctx) variable_storage(var,
- PROGRAM_OUTPUT,
- var->location);
- break;
- case ir_var_system_value:
- entry = new(mem_ctx) variable_storage(var,
- PROGRAM_SYSTEM_VALUE,
- var->location);
- break;
- case ir_var_auto:
- case ir_var_temporary:
- entry = new(mem_ctx) variable_storage(var, PROGRAM_TEMPORARY,
- this->next_temp);
- this->variables.push_tail(entry);
-
- next_temp += type_size(var->type);
- break;
- }
-
- if (!entry) {
- printf("Failed to make storage for %s\n", var->name);
- exit(1);
- }
- }
-
- this->result = ir_to_mesa_src_reg(entry->file, entry->index, var->type);
-}
-
-void
-ir_to_mesa_visitor::visit(ir_dereference_array *ir)
-{
- ir_constant *index;
- ir_to_mesa_src_reg src_reg;
- int element_size = type_size(ir->type);
-
- index = ir->array_index->constant_expression_value();
-
- ir->array->accept(this);
- src_reg = this->result;
-
- if (index) {
- src_reg.index += index->value.i[0] * element_size;
- } else {
- ir_to_mesa_src_reg array_base = this->result;
- /* Variable index array dereference. It eats the "vec4" of the
- * base of the array and an index that offsets the Mesa register
- * index.
- */
- ir->array_index->accept(this);
-
- ir_to_mesa_src_reg index_reg;
-
- if (element_size == 1) {
- index_reg = this->result;
- } else {
- index_reg = get_temp(glsl_type::float_type);
-
- ir_to_mesa_emit_op2(ir, OPCODE_MUL,
- ir_to_mesa_dst_reg_from_src(index_reg),
- this->result, src_reg_for_float(element_size));
- }
-
- src_reg.reladdr = ralloc(mem_ctx, ir_to_mesa_src_reg);
- memcpy(src_reg.reladdr, &index_reg, sizeof(index_reg));
- }
-
- /* If the type is smaller than a vec4, replicate the last channel out. */
- if (ir->type->is_scalar() || ir->type->is_vector())
- src_reg.swizzle = swizzle_for_size(ir->type->vector_elements);
- else
- src_reg.swizzle = SWIZZLE_NOOP;
-
- this->result = src_reg;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_dereference_record *ir)
-{
- unsigned int i;
- const glsl_type *struct_type = ir->record->type;
- int offset = 0;
-
- ir->record->accept(this);
-
- for (i = 0; i < struct_type->length; i++) {
- if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0)
- break;
- offset += type_size(struct_type->fields.structure[i].type);
- }
-
- /* If the type is smaller than a vec4, replicate the last channel out. */
- if (ir->type->is_scalar() || ir->type->is_vector())
- this->result.swizzle = swizzle_for_size(ir->type->vector_elements);
- else
- this->result.swizzle = SWIZZLE_NOOP;
-
- this->result.index += offset;
-}
-
-/**
- * We want to be careful in assignment setup to hit the actual storage
- * instead of potentially using a temporary like we might with the
- * ir_dereference handler.
- */
-static struct ir_to_mesa_dst_reg
-get_assignment_lhs(ir_dereference *ir, ir_to_mesa_visitor *v)
-{
- /* The LHS must be a dereference. If the LHS is a variable indexed array
- * access of a vector, it must be separated into a series conditional moves
- * before reaching this point (see ir_vec_index_to_cond_assign).
- */
- assert(ir->as_dereference());
- ir_dereference_array *deref_array = ir->as_dereference_array();
- if (deref_array) {
- assert(!deref_array->array->type->is_vector());
- }
-
- /* Use the rvalue deref handler for the most part. We'll ignore
- * swizzles in it and write swizzles using writemask, though.
- */
- ir->accept(v);
- return ir_to_mesa_dst_reg_from_src(v->result);
-}
-
-/**
- * Process the condition of a conditional assignment
- *
- * Examines the condition of a conditional assignment to generate the optimal
- * first operand of a \c CMP instruction. If the condition is a relational
- * operator with 0 (e.g., \c ir_binop_less), the value being compared will be
- * used as the source for the \c CMP instruction. Otherwise the comparison
- * is processed to a boolean result, and the boolean result is used as the
- * operand to the CMP instruction.
- */
-bool
-ir_to_mesa_visitor::process_move_condition(ir_rvalue *ir)
-{
- ir_rvalue *src_ir = ir;
- bool negate = true;
- bool switch_order = false;
-
- ir_expression *const expr = ir->as_expression();
- if ((expr != NULL) && (expr->get_num_operands() == 2)) {
- bool zero_on_left = false;
-
- if (expr->operands[0]->is_zero()) {
- src_ir = expr->operands[1];
- zero_on_left = true;
- } else if (expr->operands[1]->is_zero()) {
- src_ir = expr->operands[0];
- zero_on_left = false;
- }
-
- /* a is - 0 + - 0 +
- * (a < 0) T F F ( a < 0) T F F
- * (0 < a) F F T (-a < 0) F F T
- * (a <= 0) T T F (-a < 0) F F T (swap order of other operands)
- * (0 <= a) F T T ( a < 0) T F F (swap order of other operands)
- * (a > 0) F F T (-a < 0) F F T
- * (0 > a) T F F ( a < 0) T F F
- * (a >= 0) F T T ( a < 0) T F F (swap order of other operands)
- * (0 >= a) T T F (-a < 0) F F T (swap order of other operands)
- *
- * Note that exchanging the order of 0 and 'a' in the comparison simply
- * means that the value of 'a' should be negated.
- */
- if (src_ir != ir) {
- switch (expr->operation) {
- case ir_binop_less:
- switch_order = false;
- negate = zero_on_left;
- break;
-
- case ir_binop_greater:
- switch_order = false;
- negate = !zero_on_left;
- break;
-
- case ir_binop_lequal:
- switch_order = true;
- negate = !zero_on_left;
- break;
-
- case ir_binop_gequal:
- switch_order = true;
- negate = zero_on_left;
- break;
-
- default:
- /* This isn't the right kind of comparison afterall, so make sure
- * the whole condition is visited.
- */
- src_ir = ir;
- break;
- }
- }
- }
-
- src_ir->accept(this);
-
- /* We use the OPCODE_CMP (a < 0 ? b : c) for conditional moves, and the
- * condition we produced is 0.0 or 1.0. By flipping the sign, we can
- * choose which value OPCODE_CMP produces without an extra instruction
- * computing the condition.
- */
- if (negate)
- this->result.negate = ~this->result.negate;
-
- return switch_order;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_assignment *ir)
-{
- struct ir_to_mesa_dst_reg l;
- struct ir_to_mesa_src_reg r;
- int i;
-
- ir->rhs->accept(this);
- r = this->result;
-
- l = get_assignment_lhs(ir->lhs, this);
-
- /* FINISHME: This should really set to the correct maximal writemask for each
- * FINISHME: component written (in the loops below). This case can only
- * FINISHME: occur for matrices, arrays, and structures.
- */
- if (ir->write_mask == 0) {
- assert(!ir->lhs->type->is_scalar() && !ir->lhs->type->is_vector());
- l.writemask = WRITEMASK_XYZW;
- } else if (ir->lhs->type->is_scalar()) {
- /* FINISHME: This hack makes writing to gl_FragDepth, which lives in the
- * FINISHME: W component of fragment shader output zero, work correctly.
- */
- l.writemask = WRITEMASK_XYZW;
- } else {
- int swizzles[4];
- int first_enabled_chan = 0;
- int rhs_chan = 0;
-
- assert(ir->lhs->type->is_vector());
- l.writemask = ir->write_mask;
-
- for (int i = 0; i < 4; i++) {
- if (l.writemask & (1 << i)) {
- first_enabled_chan = GET_SWZ(r.swizzle, i);
- break;
- }
- }
-
- /* Swizzle a small RHS vector into the channels being written.
- *
- * glsl ir treats write_mask as dictating how many channels are
- * present on the RHS while Mesa IR treats write_mask as just
- * showing which channels of the vec4 RHS get written.
- */
- for (int i = 0; i < 4; i++) {
- if (l.writemask & (1 << i))
- swizzles[i] = GET_SWZ(r.swizzle, rhs_chan++);
- else
- swizzles[i] = first_enabled_chan;
- }
- r.swizzle = MAKE_SWIZZLE4(swizzles[0], swizzles[1],
- swizzles[2], swizzles[3]);
- }
-
- assert(l.file != PROGRAM_UNDEFINED);
- assert(r.file != PROGRAM_UNDEFINED);
-
- if (ir->condition) {
- const bool switch_order = this->process_move_condition(ir->condition);
- ir_to_mesa_src_reg condition = this->result;
-
- for (i = 0; i < type_size(ir->lhs->type); i++) {
- if (switch_order) {
- ir_to_mesa_emit_op3(ir, OPCODE_CMP, l,
- condition, ir_to_mesa_src_reg_from_dst(l), r);
- } else {
- ir_to_mesa_emit_op3(ir, OPCODE_CMP, l,
- condition, r, ir_to_mesa_src_reg_from_dst(l));
- }
-
- l.index++;
- r.index++;
- }
- } else {
- for (i = 0; i < type_size(ir->lhs->type); i++) {
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
- l.index++;
- r.index++;
- }
- }
-}
-
-
-void
-ir_to_mesa_visitor::visit(ir_constant *ir)
-{
- ir_to_mesa_src_reg src_reg;
- GLfloat stack_vals[4] = { 0 };
- GLfloat *values = stack_vals;
- unsigned int i;
-
- /* Unfortunately, 4 floats is all we can get into
- * _mesa_add_unnamed_constant. So, make a temp to store an
- * aggregate constant and move each constant value into it. If we
- * get lucky, copy propagation will eliminate the extra moves.
- */
-
- if (ir->type->base_type == GLSL_TYPE_STRUCT) {
- ir_to_mesa_src_reg temp_base = get_temp(ir->type);
- ir_to_mesa_dst_reg temp = ir_to_mesa_dst_reg_from_src(temp_base);
-
- foreach_iter(exec_list_iterator, iter, ir->components) {
- ir_constant *field_value = (ir_constant *)iter.get();
- int size = type_size(field_value->type);
-
- assert(size > 0);
-
- field_value->accept(this);
- src_reg = this->result;
-
- for (i = 0; i < (unsigned int)size; i++) {
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, temp, src_reg);
-
- src_reg.index++;
- temp.index++;
- }
- }
- this->result = temp_base;
- return;
- }
-
- if (ir->type->is_array()) {
- ir_to_mesa_src_reg temp_base = get_temp(ir->type);
- ir_to_mesa_dst_reg temp = ir_to_mesa_dst_reg_from_src(temp_base);
- int size = type_size(ir->type->fields.array);
-
- assert(size > 0);
-
- for (i = 0; i < ir->type->length; i++) {
- ir->array_elements[i]->accept(this);
- src_reg = this->result;
- for (int j = 0; j < size; j++) {
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, temp, src_reg);
-
- src_reg.index++;
- temp.index++;
- }
- }
- this->result = temp_base;
- return;
- }
-
- if (ir->type->is_matrix()) {
- ir_to_mesa_src_reg mat = get_temp(ir->type);
- ir_to_mesa_dst_reg mat_column = ir_to_mesa_dst_reg_from_src(mat);
-
- for (i = 0; i < ir->type->matrix_columns; i++) {
- assert(ir->type->base_type == GLSL_TYPE_FLOAT);
- values = &ir->value.f[i * ir->type->vector_elements];
-
- src_reg = ir_to_mesa_src_reg(PROGRAM_CONSTANT, -1, NULL);
- src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
- values,
- ir->type->vector_elements,
- &src_reg.swizzle);
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, mat_column, src_reg);
-
- mat_column.index++;
- }
-
- this->result = mat;
- return;
- }
-
- src_reg.file = PROGRAM_CONSTANT;
- switch (ir->type->base_type) {
- case GLSL_TYPE_FLOAT:
- values = &ir->value.f[0];
- break;
- case GLSL_TYPE_UINT:
- for (i = 0; i < ir->type->vector_elements; i++) {
- values[i] = ir->value.u[i];
- }
- break;
- case GLSL_TYPE_INT:
- for (i = 0; i < ir->type->vector_elements; i++) {
- values[i] = ir->value.i[i];
- }
- break;
- case GLSL_TYPE_BOOL:
- for (i = 0; i < ir->type->vector_elements; i++) {
- values[i] = ir->value.b[i];
- }
- break;
- default:
- assert(!"Non-float/uint/int/bool constant");
- }
-
- this->result = ir_to_mesa_src_reg(PROGRAM_CONSTANT, -1, ir->type);
- this->result.index = _mesa_add_unnamed_constant(this->prog->Parameters,
- values,
- ir->type->vector_elements,
- &this->result.swizzle);
-}
-
-function_entry *
-ir_to_mesa_visitor::get_function_signature(ir_function_signature *sig)
-{
- function_entry *entry;
-
- foreach_iter(exec_list_iterator, iter, this->function_signatures) {
- entry = (function_entry *)iter.get();
-
- if (entry->sig == sig)
- return entry;
- }
-
- entry = ralloc(mem_ctx, function_entry);
- entry->sig = sig;
- entry->sig_id = this->next_signature_id++;
- entry->bgn_inst = NULL;
-
- /* Allocate storage for all the parameters. */
- foreach_iter(exec_list_iterator, iter, sig->parameters) {
- ir_variable *param = (ir_variable *)iter.get();
- variable_storage *storage;
-
- storage = find_variable_storage(param);
- assert(!storage);
-
- storage = new(mem_ctx) variable_storage(param, PROGRAM_TEMPORARY,
- this->next_temp);
- this->variables.push_tail(storage);
-
- this->next_temp += type_size(param->type);
- }
-
- if (!sig->return_type->is_void()) {
- entry->return_reg = get_temp(sig->return_type);
- } else {
- entry->return_reg = ir_to_mesa_undef;
- }
-
- this->function_signatures.push_tail(entry);
- return entry;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_call *ir)
-{
- ir_to_mesa_instruction *call_inst;
- ir_function_signature *sig = ir->get_callee();
- function_entry *entry = get_function_signature(sig);
- int i;
-
- /* Process in parameters. */
- exec_list_iterator sig_iter = sig->parameters.iterator();
- foreach_iter(exec_list_iterator, iter, *ir) {
- ir_rvalue *param_rval = (ir_rvalue *)iter.get();
- ir_variable *param = (ir_variable *)sig_iter.get();
-
- if (param->mode == ir_var_in ||
- param->mode == ir_var_inout) {
- variable_storage *storage = find_variable_storage(param);
- assert(storage);
-
- param_rval->accept(this);
- ir_to_mesa_src_reg r = this->result;
-
- ir_to_mesa_dst_reg l;
- l.file = storage->file;
- l.index = storage->index;
- l.reladdr = NULL;
- l.writemask = WRITEMASK_XYZW;
- l.cond_mask = COND_TR;
-
- for (i = 0; i < type_size(param->type); i++) {
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
- l.index++;
- r.index++;
- }
- }
-
- sig_iter.next();
- }
- assert(!sig_iter.has_next());
-
- /* Emit call instruction */
- call_inst = ir_to_mesa_emit_op1(ir, OPCODE_CAL,
- ir_to_mesa_undef_dst, ir_to_mesa_undef);
- call_inst->function = entry;
-
- /* Process out parameters. */
- sig_iter = sig->parameters.iterator();
- foreach_iter(exec_list_iterator, iter, *ir) {
- ir_rvalue *param_rval = (ir_rvalue *)iter.get();
- ir_variable *param = (ir_variable *)sig_iter.get();
-
- if (param->mode == ir_var_out ||
- param->mode == ir_var_inout) {
- variable_storage *storage = find_variable_storage(param);
- assert(storage);
-
- ir_to_mesa_src_reg r;
- r.file = storage->file;
- r.index = storage->index;
- r.reladdr = NULL;
- r.swizzle = SWIZZLE_NOOP;
- r.negate = 0;
-
- param_rval->accept(this);
- ir_to_mesa_dst_reg l = ir_to_mesa_dst_reg_from_src(this->result);
-
- for (i = 0; i < type_size(param->type); i++) {
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
- l.index++;
- r.index++;
- }
- }
-
- sig_iter.next();
- }
- assert(!sig_iter.has_next());
-
- /* Process return value. */
- this->result = entry->return_reg;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_texture *ir)
-{
- ir_to_mesa_src_reg result_src, coord, lod_info, projector;
- ir_to_mesa_dst_reg result_dst, coord_dst;
- ir_to_mesa_instruction *inst = NULL;
- prog_opcode opcode = OPCODE_NOP;
-
- ir->coordinate->accept(this);
-
- /* Put our coords in a temp. We'll need to modify them for shadow,
- * projection, or LOD, so the only case we'd use it as is is if
- * we're doing plain old texturing. Mesa IR optimization should
- * handle cleaning up our mess in that case.
- */
- coord = get_temp(glsl_type::vec4_type);
- coord_dst = ir_to_mesa_dst_reg_from_src(coord);
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst,
- this->result);
-
- if (ir->projector) {
- ir->projector->accept(this);
- projector = this->result;
- }
-
- /* Storage for our result. Ideally for an assignment we'd be using
- * the actual storage for the result here, instead.
- */
- result_src = get_temp(glsl_type::vec4_type);
- result_dst = ir_to_mesa_dst_reg_from_src(result_src);
-
- switch (ir->op) {
- case ir_tex:
- opcode = OPCODE_TEX;
- break;
- case ir_txb:
- opcode = OPCODE_TXB;
- ir->lod_info.bias->accept(this);
- lod_info = this->result;
- break;
- case ir_txl:
- opcode = OPCODE_TXL;
- ir->lod_info.lod->accept(this);
- lod_info = this->result;
- break;
- case ir_txd:
- case ir_txf:
- assert(!"GLSL 1.30 features unsupported");
- break;
- }
-
- if (ir->projector) {
- if (opcode == OPCODE_TEX) {
- /* Slot the projector in as the last component of the coord. */
- coord_dst.writemask = WRITEMASK_W;
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, projector);
- coord_dst.writemask = WRITEMASK_XYZW;
- opcode = OPCODE_TXP;
- } else {
- ir_to_mesa_src_reg coord_w = coord;
- coord_w.swizzle = SWIZZLE_WWWW;
-
- /* For the other TEX opcodes there's no projective version
- * since the last slot is taken up by lod info. Do the
- * projective divide now.
- */
- coord_dst.writemask = WRITEMASK_W;
- ir_to_mesa_emit_op1(ir, OPCODE_RCP, coord_dst, projector);
-
- coord_dst.writemask = WRITEMASK_XYZ;
- ir_to_mesa_emit_op2(ir, OPCODE_MUL, coord_dst, coord, coord_w);
-
- coord_dst.writemask = WRITEMASK_XYZW;
- coord.swizzle = SWIZZLE_XYZW;
- }
- }
-
- if (ir->shadow_comparitor) {
- /* Slot the shadow value in as the second to last component of the
- * coord.
- */
- ir->shadow_comparitor->accept(this);
- coord_dst.writemask = WRITEMASK_Z;
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, this->result);
- coord_dst.writemask = WRITEMASK_XYZW;
- }
-
- if (opcode == OPCODE_TXL || opcode == OPCODE_TXB) {
- /* Mesa IR stores lod or lod bias in the last channel of the coords. */
- coord_dst.writemask = WRITEMASK_W;
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, lod_info);
- coord_dst.writemask = WRITEMASK_XYZW;
- }
-
- inst = ir_to_mesa_emit_op1(ir, opcode, result_dst, coord);
-
- if (ir->shadow_comparitor)
- inst->tex_shadow = GL_TRUE;
-
- inst->sampler = _mesa_get_sampler_uniform_value(ir->sampler,
- this->shader_program,
- this->prog);
-
- const glsl_type *sampler_type = ir->sampler->type;
-
- switch (sampler_type->sampler_dimensionality) {
- case GLSL_SAMPLER_DIM_1D:
- inst->tex_target = (sampler_type->sampler_array)
- ? TEXTURE_1D_ARRAY_INDEX : TEXTURE_1D_INDEX;
- break;
- case GLSL_SAMPLER_DIM_2D:
- inst->tex_target = (sampler_type->sampler_array)
- ? TEXTURE_2D_ARRAY_INDEX : TEXTURE_2D_INDEX;
- break;
- case GLSL_SAMPLER_DIM_3D:
- inst->tex_target = TEXTURE_3D_INDEX;
- break;
- case GLSL_SAMPLER_DIM_CUBE:
- inst->tex_target = TEXTURE_CUBE_INDEX;
- break;
- case GLSL_SAMPLER_DIM_RECT:
- inst->tex_target = TEXTURE_RECT_INDEX;
- break;
- case GLSL_SAMPLER_DIM_BUF:
- assert(!"FINISHME: Implement ARB_texture_buffer_object");
- break;
- default:
- assert(!"Should not get here.");
- }
-
- this->result = result_src;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_return *ir)
-{
- if (ir->get_value()) {
- ir_to_mesa_dst_reg l;
- int i;
-
- assert(current_function);
-
- ir->get_value()->accept(this);
- ir_to_mesa_src_reg r = this->result;
-
- l = ir_to_mesa_dst_reg_from_src(current_function->return_reg);
-
- for (i = 0; i < type_size(current_function->sig->return_type); i++) {
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
- l.index++;
- r.index++;
- }
- }
-
- ir_to_mesa_emit_op0(ir, OPCODE_RET);
-}
-
-void
-ir_to_mesa_visitor::visit(ir_discard *ir)
-{
- struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog;
-
- if (ir->condition) {
- ir->condition->accept(this);
- this->result.negate = ~this->result.negate;
- ir_to_mesa_emit_op1(ir, OPCODE_KIL, ir_to_mesa_undef_dst, this->result);
- } else {
- ir_to_mesa_emit_op0(ir, OPCODE_KIL_NV);
- }
-
- fp->UsesKill = GL_TRUE;
-}
-
-void
-ir_to_mesa_visitor::visit(ir_if *ir)
-{
- ir_to_mesa_instruction *cond_inst, *if_inst, *else_inst = NULL;
- ir_to_mesa_instruction *prev_inst;
-
- prev_inst = (ir_to_mesa_instruction *)this->instructions.get_tail();
-
- ir->condition->accept(this);
- assert(this->result.file != PROGRAM_UNDEFINED);
-
- if (this->options->EmitCondCodes) {
- cond_inst = (ir_to_mesa_instruction *)this->instructions.get_tail();
-
- /* See if we actually generated any instruction for generating
- * the condition. If not, then cook up a move to a temp so we
- * have something to set cond_update on.
- */
- if (cond_inst == prev_inst) {
- ir_to_mesa_src_reg temp = get_temp(glsl_type::bool_type);
- cond_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_MOV,
- ir_to_mesa_dst_reg_from_src(temp),
- result);
- }
- cond_inst->cond_update = GL_TRUE;
-
- if_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_IF);
- if_inst->dst_reg.cond_mask = COND_NE;
- } else {
- if_inst = ir_to_mesa_emit_op1(ir->condition,
- OPCODE_IF, ir_to_mesa_undef_dst,
- this->result);
- }
-
- this->instructions.push_tail(if_inst);
-
- visit_exec_list(&ir->then_instructions, this);
-
- if (!ir->else_instructions.is_empty()) {
- else_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_ELSE);
- visit_exec_list(&ir->else_instructions, this);
- }
-
- if_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ENDIF,
- ir_to_mesa_undef_dst, ir_to_mesa_undef);
-}
-
-ir_to_mesa_visitor::ir_to_mesa_visitor()
-{
- result.file = PROGRAM_UNDEFINED;
- next_temp = 1;
- next_signature_id = 1;
- current_function = NULL;
- mem_ctx = ralloc_context(NULL);
-}
-
-ir_to_mesa_visitor::~ir_to_mesa_visitor()
-{
- ralloc_free(mem_ctx);
-}
-
-static struct prog_src_register
-mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg)
-{
- struct prog_src_register mesa_reg;
-
- mesa_reg.File = reg.file;
- assert(reg.index < (1 << INST_INDEX_BITS));
- mesa_reg.Index = reg.index;
- mesa_reg.Swizzle = reg.swizzle;
- mesa_reg.RelAddr = reg.reladdr != NULL;
- mesa_reg.Negate = reg.negate;
- mesa_reg.Abs = 0;
- mesa_reg.HasIndex2 = GL_FALSE;
- mesa_reg.RelAddr2 = 0;
- mesa_reg.Index2 = 0;
-
- return mesa_reg;
-}
-
-static void
-set_branchtargets(ir_to_mesa_visitor *v,
- struct prog_instruction *mesa_instructions,
- int num_instructions)
-{
- int if_count = 0, loop_count = 0;
- int *if_stack, *loop_stack;
- int if_stack_pos = 0, loop_stack_pos = 0;
- int i, j;
-
- for (i = 0; i < num_instructions; i++) {
- switch (mesa_instructions[i].Opcode) {
- case OPCODE_IF:
- if_count++;
- break;
- case OPCODE_BGNLOOP:
- loop_count++;
- break;
- case OPCODE_BRK:
- case OPCODE_CONT:
- mesa_instructions[i].BranchTarget = -1;
- break;
- default:
- break;
- }
- }
-
- if_stack = rzalloc_array(v->mem_ctx, int, if_count);
- loop_stack = rzalloc_array(v->mem_ctx, int, loop_count);
-
- for (i = 0; i < num_instructions; i++) {
- switch (mesa_instructions[i].Opcode) {
- case OPCODE_IF:
- if_stack[if_stack_pos] = i;
- if_stack_pos++;
- break;
- case OPCODE_ELSE:
- mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
- if_stack[if_stack_pos - 1] = i;
- break;
- case OPCODE_ENDIF:
- mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
- if_stack_pos--;
- break;
- case OPCODE_BGNLOOP:
- loop_stack[loop_stack_pos] = i;
- loop_stack_pos++;
- break;
- case OPCODE_ENDLOOP:
- loop_stack_pos--;
- /* Rewrite any breaks/conts at this nesting level (haven't
- * already had a BranchTarget assigned) to point to the end
- * of the loop.
- */
- for (j = loop_stack[loop_stack_pos]; j < i; j++) {
- if (mesa_instructions[j].Opcode == OPCODE_BRK ||
- mesa_instructions[j].Opcode == OPCODE_CONT) {
- if (mesa_instructions[j].BranchTarget == -1) {
- mesa_instructions[j].BranchTarget = i;
- }
- }
- }
- /* The loop ends point at each other. */
- mesa_instructions[i].BranchTarget = loop_stack[loop_stack_pos];
- mesa_instructions[loop_stack[loop_stack_pos]].BranchTarget = i;
- break;
- case OPCODE_CAL:
- foreach_iter(exec_list_iterator, iter, v->function_signatures) {
- function_entry *entry = (function_entry *)iter.get();
-
- if (entry->sig_id == mesa_instructions[i].BranchTarget) {
- mesa_instructions[i].BranchTarget = entry->inst;
- break;
- }
- }
- break;
- default:
- break;
- }
- }
-}
-
-static void
-print_program(struct prog_instruction *mesa_instructions,
- ir_instruction **mesa_instruction_annotation,
- int num_instructions)
-{
- ir_instruction *last_ir = NULL;
- int i;
- int indent = 0;
-
- for (i = 0; i < num_instructions; i++) {
- struct prog_instruction *mesa_inst = mesa_instructions + i;
- ir_instruction *ir = mesa_instruction_annotation[i];
-
- fprintf(stdout, "%3d: ", i);
-
- if (last_ir != ir && ir) {
- int j;
-
- for (j = 0; j < indent; j++) {
- fprintf(stdout, " ");
- }
- ir->print();
- printf("\n");
- last_ir = ir;
-
- fprintf(stdout, " "); /* line number spacing. */
- }
-
- indent = _mesa_fprint_instruction_opt(stdout, mesa_inst, indent,
- PROG_PRINT_DEBUG, NULL);
- }
-}
-
-static void
-count_resources(struct gl_program *prog)
-{
- unsigned int i;
-
- prog->SamplersUsed = 0;
-
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = &prog->Instructions[i];
-
- if (_mesa_is_tex_instruction(inst->Opcode)) {
- prog->SamplerTargets[inst->TexSrcUnit] =
- (gl_texture_index)inst->TexSrcTarget;
- prog->SamplersUsed |= 1 << inst->TexSrcUnit;
- if (inst->TexShadow) {
- prog->ShadowSamplers |= 1 << inst->TexSrcUnit;
- }
- }
- }
-
- _mesa_update_shader_textures_used(prog);
-}
-
-struct uniform_sort {
- struct gl_uniform *u;
- int pos;
-};
-
-/* The shader_program->Uniforms list is almost sorted in increasing
- * uniform->{Frag,Vert}Pos locations, but not quite when there are
- * uniforms shared between targets. We need to add parameters in
- * increasing order for the targets.
- */
-static int
-sort_uniforms(const void *a, const void *b)
-{
- struct uniform_sort *u1 = (struct uniform_sort *)a;
- struct uniform_sort *u2 = (struct uniform_sort *)b;
-
- return u1->pos - u2->pos;
-}
-
-/* Add the uniforms to the parameters. The linker chose locations
- * in our parameters lists (which weren't created yet), which the
- * uniforms code will use to poke values into our parameters list
- * when uniforms are updated.
- */
-static void
-add_uniforms_to_parameters_list(struct gl_shader_program *shader_program,
- struct gl_shader *shader,
- struct gl_program *prog)
-{
- unsigned int i;
- unsigned int next_sampler = 0, num_uniforms = 0;
- struct uniform_sort *sorted_uniforms;
-
- sorted_uniforms = ralloc_array(NULL, struct uniform_sort,
- shader_program->Uniforms->NumUniforms);
-
- for (i = 0; i < shader_program->Uniforms->NumUniforms; i++) {
- struct gl_uniform *uniform = shader_program->Uniforms->Uniforms + i;
- int parameter_index = -1;
-
- switch (shader->Type) {
- case GL_VERTEX_SHADER:
- parameter_index = uniform->VertPos;
- break;
- case GL_FRAGMENT_SHADER:
- parameter_index = uniform->FragPos;
- break;
- case GL_GEOMETRY_SHADER:
- parameter_index = uniform->GeomPos;
- break;
- }
-
- /* Only add uniforms used in our target. */
- if (parameter_index != -1) {
- sorted_uniforms[num_uniforms].pos = parameter_index;
- sorted_uniforms[num_uniforms].u = uniform;
- num_uniforms++;
- }
- }
-
- qsort(sorted_uniforms, num_uniforms, sizeof(struct uniform_sort),
- sort_uniforms);
-
- for (i = 0; i < num_uniforms; i++) {
- struct gl_uniform *uniform = sorted_uniforms[i].u;
- int parameter_index = sorted_uniforms[i].pos;
- const glsl_type *type = uniform->Type;
- unsigned int size;
-
- if (type->is_vector() ||
- type->is_scalar()) {
- size = type->vector_elements;
- } else {
- size = type_size(type) * 4;
- }
-
- gl_register_file file;
- if (type->is_sampler() ||
- (type->is_array() && type->fields.array->is_sampler())) {
- file = PROGRAM_SAMPLER;
- } else {
- file = PROGRAM_UNIFORM;
- }
-
- GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1,
- uniform->Name);
-
- if (index < 0) {
- index = _mesa_add_parameter(prog->Parameters, file,
- uniform->Name, size, type->gl_type,
- NULL, NULL, 0x0);
-
- /* Sampler uniform values are stored in prog->SamplerUnits,
- * and the entry in that array is selected by this index we
- * store in ParameterValues[].
- */
- if (file == PROGRAM_SAMPLER) {
- for (unsigned int j = 0; j < size / 4; j++)
- prog->Parameters->ParameterValues[index + j][0] = next_sampler++;
- }
-
- /* The location chosen in the Parameters list here (returned
- * from _mesa_add_uniform) has to match what the linker chose.
- */
- if (index != parameter_index) {
- fail_link(shader_program, "Allocation of uniform `%s' to target "
- "failed (%d vs %d)\n",
- uniform->Name, index, parameter_index);
- }
- }
- }
-
- ralloc_free(sorted_uniforms);
-}
-
-static void
-set_uniform_initializer(struct gl_context *ctx, void *mem_ctx,
- struct gl_shader_program *shader_program,
- const char *name, const glsl_type *type,
- ir_constant *val)
-{
- if (type->is_record()) {
- ir_constant *field_constant;
-
- field_constant = (ir_constant *)val->components.get_head();
-
- for (unsigned int i = 0; i < type->length; i++) {
- const glsl_type *field_type = type->fields.structure[i].type;
- const char *field_name = ralloc_asprintf(mem_ctx, "%s.%s", name,
- type->fields.structure[i].name);
- set_uniform_initializer(ctx, mem_ctx, shader_program, field_name,
- field_type, field_constant);
- field_constant = (ir_constant *)field_constant->next;
- }
- return;
- }
-
- int loc = _mesa_get_uniform_location(ctx, shader_program, name);
-
- if (loc == -1) {
- fail_link(shader_program,
- "Couldn't find uniform for initializer %s\n", name);
- return;
- }
-
- for (unsigned int i = 0; i < (type->is_array() ? type->length : 1); i++) {
- ir_constant *element;
- const glsl_type *element_type;
- if (type->is_array()) {
- element = val->array_elements[i];
- element_type = type->fields.array;
- } else {
- element = val;
- element_type = type;
- }
-
- void *values;
-
- if (element_type->base_type == GLSL_TYPE_BOOL) {
- int *conv = ralloc_array(mem_ctx, int, element_type->components());
- for (unsigned int j = 0; j < element_type->components(); j++) {
- conv[j] = element->value.b[j];
- }
- values = (void *)conv;
- element_type = glsl_type::get_instance(GLSL_TYPE_INT,
- element_type->vector_elements,
- 1);
- } else {
- values = &element->value;
- }
-
- if (element_type->is_matrix()) {
- _mesa_uniform_matrix(ctx, shader_program,
- element_type->matrix_columns,
- element_type->vector_elements,
- loc, 1, GL_FALSE, (GLfloat *)values);
- loc += element_type->matrix_columns;
- } else {
- _mesa_uniform(ctx, shader_program, loc, element_type->matrix_columns,
- values, element_type->gl_type);
- loc += type_size(element_type);
- }
- }
-}
-
-static void
-set_uniform_initializers(struct gl_context *ctx,
- struct gl_shader_program *shader_program)
-{
- void *mem_ctx = NULL;
-
- for (unsigned int i = 0; i < MESA_SHADER_TYPES; i++) {
- struct gl_shader *shader = shader_program->_LinkedShaders[i];
-
- if (shader == NULL)
- continue;
-
- foreach_iter(exec_list_iterator, iter, *shader->ir) {
- ir_instruction *ir = (ir_instruction *)iter.get();
- ir_variable *var = ir->as_variable();
-
- if (!var || var->mode != ir_var_uniform || !var->constant_value)
- continue;
-
- if (!mem_ctx)
- mem_ctx = ralloc_context(NULL);
-
- set_uniform_initializer(ctx, mem_ctx, shader_program, var->name,
- var->type, var->constant_value);
- }
- }
-
- ralloc_free(mem_ctx);
-}
-
-/*
- * On a basic block basis, tracks available PROGRAM_TEMPORARY register
- * channels for copy propagation and updates following instructions to
- * use the original versions.
- *
- * The ir_to_mesa_visitor lazily produces code assuming that this pass
- * will occur. As an example, a TXP production before this pass:
- *
- * 0: MOV TEMP[1], INPUT[4].xyyy;
- * 1: MOV TEMP[1].w, INPUT[4].wwww;
- * 2: TXP TEMP[2], TEMP[1], texture[0], 2D;
- *
- * and after:
- *
- * 0: MOV TEMP[1], INPUT[4].xyyy;
- * 1: MOV TEMP[1].w, INPUT[4].wwww;
- * 2: TXP TEMP[2], INPUT[4].xyyw, texture[0], 2D;
- *
- * which allows for dead code elimination on TEMP[1]'s writes.
- */
-void
-ir_to_mesa_visitor::copy_propagate(void)
-{
- ir_to_mesa_instruction **acp = rzalloc_array(mem_ctx,
- ir_to_mesa_instruction *,
- this->next_temp * 4);
-
- foreach_iter(exec_list_iterator, iter, this->instructions) {
- ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get();
-
- assert(inst->dst_reg.file != PROGRAM_TEMPORARY
- || inst->dst_reg.index < this->next_temp);
-
- /* First, do any copy propagation possible into the src regs. */
- for (int r = 0; r < 3; r++) {
- ir_to_mesa_instruction *first = NULL;
- bool good = true;
- int acp_base = inst->src_reg[r].index * 4;
-
- if (inst->src_reg[r].file != PROGRAM_TEMPORARY ||
- inst->src_reg[r].reladdr)
- continue;
-
- /* See if we can find entries in the ACP consisting of MOVs
- * from the same src register for all the swizzled channels
- * of this src register reference.
- */
- for (int i = 0; i < 4; i++) {
- int src_chan = GET_SWZ(inst->src_reg[r].swizzle, i);
- ir_to_mesa_instruction *copy_chan = acp[acp_base + src_chan];
-
- if (!copy_chan) {
- good = false;
- break;
- }
-
- if (!first) {
- first = copy_chan;
- } else {
- if (first->src_reg[0].file != copy_chan->src_reg[0].file ||
- first->src_reg[0].index != copy_chan->src_reg[0].index) {
- good = false;
- break;
- }
- }
- }
-
- if (good) {
- /* We've now validated that we can copy-propagate to
- * replace this src register reference. Do it.
- */
- inst->src_reg[r].file = first->src_reg[0].file;
- inst->src_reg[r].index = first->src_reg[0].index;
-
- int swizzle = 0;
- for (int i = 0; i < 4; i++) {
- int src_chan = GET_SWZ(inst->src_reg[r].swizzle, i);
- ir_to_mesa_instruction *copy_inst = acp[acp_base + src_chan];
- swizzle |= (GET_SWZ(copy_inst->src_reg[0].swizzle, src_chan) <<
- (3 * i));
- }
- inst->src_reg[r].swizzle = swizzle;
- }
- }
-
- switch (inst->op) {
- case OPCODE_BGNLOOP:
- case OPCODE_ENDLOOP:
- case OPCODE_ELSE:
- case OPCODE_ENDIF:
- /* End of a basic block, clear the ACP entirely. */
- memset(acp, 0, sizeof(*acp) * this->next_temp * 4);
- break;
-
- default:
- /* Continuing the block, clear any written channels from
- * the ACP.
- */
- if (inst->dst_reg.file == PROGRAM_TEMPORARY) {
- if (inst->dst_reg.reladdr) {
- memset(acp, 0, sizeof(*acp) * this->next_temp * 4);
- } else {
- for (int i = 0; i < 4; i++) {
- if (inst->dst_reg.writemask & (1 << i)) {
- acp[4 * inst->dst_reg.index + i] = NULL;
- }
- }
- }
- }
- break;
- }
-
- /* If this is a copy, add it to the ACP. */
- if (inst->op == OPCODE_MOV &&
- inst->dst_reg.file == PROGRAM_TEMPORARY &&
- !inst->dst_reg.reladdr &&
- !inst->saturate &&
- !inst->src_reg[0].reladdr &&
- !inst->src_reg[0].negate) {
- for (int i = 0; i < 4; i++) {
- if (inst->dst_reg.writemask & (1 << i)) {
- acp[4 * inst->dst_reg.index + i] = inst;
- }
- }
- }
- }
-
- ralloc_free(acp);
-}
-
-
-/**
- * Convert a shader's GLSL IR into a Mesa gl_program.
- */
-static struct gl_program *
-get_mesa_program(struct gl_context *ctx,
- struct gl_shader_program *shader_program,
- struct gl_shader *shader)
-{
- ir_to_mesa_visitor v;
- struct prog_instruction *mesa_instructions, *mesa_inst;
- ir_instruction **mesa_instruction_annotation;
- int i;
- struct gl_program *prog;
- GLenum target;
- const char *target_string;
- GLboolean progress;
- struct gl_shader_compiler_options *options =
- &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(shader->Type)];
-
- switch (shader->Type) {
- case GL_VERTEX_SHADER:
- target = GL_VERTEX_PROGRAM_ARB;
- target_string = "vertex";
- break;
- case GL_FRAGMENT_SHADER:
- target = GL_FRAGMENT_PROGRAM_ARB;
- target_string = "fragment";
- break;
- case GL_GEOMETRY_SHADER:
- target = GL_GEOMETRY_PROGRAM_NV;
- target_string = "geometry";
- break;
- default:
- assert(!"should not be reached");
- return NULL;
- }
-
- validate_ir_tree(shader->ir);
-
- prog = ctx->Driver.NewProgram(ctx, target, shader_program->Name);
- if (!prog)
- return NULL;
- prog->Parameters = _mesa_new_parameter_list();
- prog->Varying = _mesa_new_parameter_list();
- prog->Attributes = _mesa_new_parameter_list();
- v.ctx = ctx;
- v.prog = prog;
- v.shader_program = shader_program;
- v.options = options;
-
- add_uniforms_to_parameters_list(shader_program, shader, prog);
-
- /* Emit Mesa IR for main(). */
- visit_exec_list(shader->ir, &v);
- v.ir_to_mesa_emit_op0(NULL, OPCODE_END);
-
- /* Now emit bodies for any functions that were used. */
- do {
- progress = GL_FALSE;
-
- foreach_iter(exec_list_iterator, iter, v.function_signatures) {
- function_entry *entry = (function_entry *)iter.get();
-
- if (!entry->bgn_inst) {
- v.current_function = entry;
-
- entry->bgn_inst = v.ir_to_mesa_emit_op0(NULL, OPCODE_BGNSUB);
- entry->bgn_inst->function = entry;
-
- visit_exec_list(&entry->sig->body, &v);
-
- ir_to_mesa_instruction *last;
- last = (ir_to_mesa_instruction *)v.instructions.get_tail();
- if (last->op != OPCODE_RET)
- v.ir_to_mesa_emit_op0(NULL, OPCODE_RET);
-
- ir_to_mesa_instruction *end;
- end = v.ir_to_mesa_emit_op0(NULL, OPCODE_ENDSUB);
- end->function = entry;
-
- progress = GL_TRUE;
- }
- }
- } while (progress);
-
- prog->NumTemporaries = v.next_temp;
-
- int num_instructions = 0;
- foreach_iter(exec_list_iterator, iter, v.instructions) {
- num_instructions++;
- }
-
- mesa_instructions =
- (struct prog_instruction *)calloc(num_instructions,
- sizeof(*mesa_instructions));
- mesa_instruction_annotation = ralloc_array(v.mem_ctx, ir_instruction *,
- num_instructions);
-
- v.copy_propagate();
-
- /* Convert ir_mesa_instructions into prog_instructions.
- */
- mesa_inst = mesa_instructions;
- i = 0;
- foreach_iter(exec_list_iterator, iter, v.instructions) {
- const ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get();
-
- mesa_inst->Opcode = inst->op;
- mesa_inst->CondUpdate = inst->cond_update;
- if (inst->saturate)
- mesa_inst->SaturateMode = SATURATE_ZERO_ONE;
- mesa_inst->DstReg.File = inst->dst_reg.file;
- mesa_inst->DstReg.Index = inst->dst_reg.index;
- mesa_inst->DstReg.CondMask = inst->dst_reg.cond_mask;
- mesa_inst->DstReg.WriteMask = inst->dst_reg.writemask;
- mesa_inst->DstReg.RelAddr = inst->dst_reg.reladdr != NULL;
- mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]);
- mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]);
- mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]);
- mesa_inst->TexSrcUnit = inst->sampler;
- mesa_inst->TexSrcTarget = inst->tex_target;
- mesa_inst->TexShadow = inst->tex_shadow;
- mesa_instruction_annotation[i] = inst->ir;
-
- /* Set IndirectRegisterFiles. */
- if (mesa_inst->DstReg.RelAddr)
- prog->IndirectRegisterFiles |= 1 << mesa_inst->DstReg.File;
-
- /* Update program's bitmask of indirectly accessed register files */
- for (unsigned src = 0; src < 3; src++)
- if (mesa_inst->SrcReg[src].RelAddr)
- prog->IndirectRegisterFiles |= 1 << mesa_inst->SrcReg[src].File;
-
- if (options->EmitNoIfs && mesa_inst->Opcode == OPCODE_IF) {
- fail_link(shader_program, "Couldn't flatten if statement\n");
- }
-
- switch (mesa_inst->Opcode) {
- case OPCODE_BGNSUB:
- inst->function->inst = i;
- mesa_inst->Comment = strdup(inst->function->sig->function_name());
- break;
- case OPCODE_ENDSUB:
- mesa_inst->Comment = strdup(inst->function->sig->function_name());
- break;
- case OPCODE_CAL:
- mesa_inst->BranchTarget = inst->function->sig_id; /* rewritten later */
- break;
- case OPCODE_ARL:
- prog->NumAddressRegs = 1;
- break;
- default:
- break;
- }
-
- mesa_inst++;
- i++;
-
- if (!shader_program->LinkStatus)
- break;
- }
-
- if (!shader_program->LinkStatus) {
- free(mesa_instructions);
- _mesa_reference_program(ctx, &shader->Program, NULL);
- return NULL;
- }
-
- set_branchtargets(&v, mesa_instructions, num_instructions);
-
- if (ctx->Shader.Flags & GLSL_DUMP) {
- printf("\n");
- printf("GLSL IR for linked %s program %d:\n", target_string,
- shader_program->Name);
- _mesa_print_ir(shader->ir, NULL);
- printf("\n");
- printf("\n");
- printf("Mesa IR for linked %s program %d:\n", target_string,
- shader_program->Name);
- print_program(mesa_instructions, mesa_instruction_annotation,
- num_instructions);
- }
-
- prog->Instructions = mesa_instructions;
- prog->NumInstructions = num_instructions;
-
- do_set_program_inouts(shader->ir, prog);
- count_resources(prog);
-
- _mesa_reference_program(ctx, &shader->Program, prog);
-
- if ((ctx->Shader.Flags & GLSL_NO_OPT) == 0) {
- _mesa_optimize_program(ctx, prog);
- }
-
- return prog;
-}
-
-extern "C" {
-
-/**
- * Called via ctx->Driver.CompilerShader().
- * This is a no-op.
- * XXX can we remove the ctx->Driver.CompileShader() hook?
- */
-GLboolean
-_mesa_ir_compile_shader(struct gl_context *ctx, struct gl_shader *shader)
-{
- assert(shader->CompileStatus);
- (void) ctx;
-
- return GL_TRUE;
-}
-
-
-/**
- * Link a shader.
- * Called via ctx->Driver.LinkShader()
- * This actually involves converting GLSL IR into Mesa gl_programs with
- * code lowering and other optimizations.
- */
-GLboolean
-_mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
-{
- assert(prog->LinkStatus);
-
- for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
- if (prog->_LinkedShaders[i] == NULL)
- continue;
-
- bool progress;
- exec_list *ir = prog->_LinkedShaders[i]->ir;
- const struct gl_shader_compiler_options *options =
- &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(prog->_LinkedShaders[i]->Type)];
-
- do {
- progress = false;
-
- /* Lowering */
- do_mat_op_to_vec(ir);
- lower_instructions(ir, (MOD_TO_FRACT | DIV_TO_MUL_RCP | EXP_TO_EXP2
- | LOG_TO_LOG2
- | ((options->EmitNoPow) ? POW_TO_EXP2 : 0)));
-
- progress = do_lower_jumps(ir, true, true, options->EmitNoMainReturn, options->EmitNoCont, options->EmitNoLoops) || progress;
-
- progress = do_common_optimization(ir, true, options->MaxUnrollIterations) || progress;
-
- progress = lower_quadop_vector(ir, true) || progress;
-
- if (options->EmitNoIfs) {
- progress = lower_discard(ir) || progress;
- progress = lower_if_to_cond_assign(ir) || progress;
- }
-
- if (options->EmitNoNoise)
- progress = lower_noise(ir) || progress;
-
- /* If there are forms of indirect addressing that the driver
- * cannot handle, perform the lowering pass.
- */
- if (options->EmitNoIndirectInput || options->EmitNoIndirectOutput
- || options->EmitNoIndirectTemp || options->EmitNoIndirectUniform)
- progress =
- lower_variable_index_to_cond_assign(ir,
- options->EmitNoIndirectInput,
- options->EmitNoIndirectOutput,
- options->EmitNoIndirectTemp,
- options->EmitNoIndirectUniform)
- || progress;
-
- progress = do_vec_index_to_cond_assign(ir) || progress;
- } while (progress);
-
- validate_ir_tree(ir);
- }
-
- for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
- struct gl_program *linked_prog;
-
- if (prog->_LinkedShaders[i] == NULL)
- continue;
-
- linked_prog = get_mesa_program(ctx, prog, prog->_LinkedShaders[i]);
-
- if (linked_prog) {
- bool ok = true;
-
- switch (prog->_LinkedShaders[i]->Type) {
- case GL_VERTEX_SHADER:
- _mesa_reference_vertprog(ctx, &prog->VertexProgram,
- (struct gl_vertex_program *)linked_prog);
- ok = ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB,
- linked_prog);
- break;
- case GL_FRAGMENT_SHADER:
- _mesa_reference_fragprog(ctx, &prog->FragmentProgram,
- (struct gl_fragment_program *)linked_prog);
- ok = ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB,
- linked_prog);
- break;
- case GL_GEOMETRY_SHADER:
- _mesa_reference_geomprog(ctx, &prog->GeometryProgram,
- (struct gl_geometry_program *)linked_prog);
- ok = ctx->Driver.ProgramStringNotify(ctx, GL_GEOMETRY_PROGRAM_NV,
- linked_prog);
- break;
- }
- if (!ok) {
- return GL_FALSE;
- }
- }
-
- _mesa_reference_program(ctx, &linked_prog, NULL);
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Compile a GLSL shader. Called via glCompileShader().
- */
-void
-_mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader)
-{
- struct _mesa_glsl_parse_state *state =
- new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader);
-
- const char *source = shader->Source;
- /* Check if the user called glCompileShader without first calling
- * glShaderSource. This should fail to compile, but not raise a GL_ERROR.
- */
- if (source == NULL) {
- shader->CompileStatus = GL_FALSE;
- return;
- }
-
- state->error = preprocess(state, &source, &state->info_log,
- &ctx->Extensions, ctx->API);
-
- if (ctx->Shader.Flags & GLSL_DUMP) {
- printf("GLSL source for shader %d:\n", shader->Name);
- printf("%s\n", shader->Source);
- }
-
- if (!state->error) {
- _mesa_glsl_lexer_ctor(state, source);
- _mesa_glsl_parse(state);
- _mesa_glsl_lexer_dtor(state);
- }
-
- ralloc_free(shader->ir);
- shader->ir = new(shader) exec_list;
- if (!state->error && !state->translation_unit.is_empty())
- _mesa_ast_to_hir(shader->ir, state);
-
- if (!state->error && !shader->ir->is_empty()) {
- validate_ir_tree(shader->ir);
-
- /* Do some optimization at compile time to reduce shader IR size
- * and reduce later work if the same shader is linked multiple times
- */
- while (do_common_optimization(shader->ir, false, 32))
- ;
-
- validate_ir_tree(shader->ir);
- }
-
- shader->symbols = state->symbols;
-
- shader->CompileStatus = !state->error;
- shader->InfoLog = state->info_log;
- shader->Version = state->language_version;
- memcpy(shader->builtins_to_link, state->builtins_to_link,
- sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link);
- shader->num_builtins_to_link = state->num_builtins_to_link;
-
- if (ctx->Shader.Flags & GLSL_LOG) {
- _mesa_write_shader_to_file(shader);
- }
-
- if (ctx->Shader.Flags & GLSL_DUMP) {
- if (shader->CompileStatus) {
- printf("GLSL IR for shader %d:\n", shader->Name);
- _mesa_print_ir(shader->ir, NULL);
- printf("\n\n");
- } else {
- printf("GLSL shader %d failed to compile.\n", shader->Name);
- }
- if (shader->InfoLog && shader->InfoLog[0] != 0) {
- printf("GLSL shader %d info log:\n", shader->Name);
- printf("%s\n", shader->InfoLog);
- }
- }
-
- /* Retain any live IR, but trash the rest. */
- reparent_ir(shader->ir, shader->ir);
-
- ralloc_free(state);
-
- if (shader->CompileStatus) {
- if (!ctx->Driver.CompileShader(ctx, shader))
- shader->CompileStatus = GL_FALSE;
- }
-}
-
-
-/**
- * Link a GLSL shader program. Called via glLinkProgram().
- */
-void
-_mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
-{
- unsigned int i;
-
- _mesa_clear_shader_program_data(ctx, prog);
-
- prog->LinkStatus = GL_TRUE;
-
- for (i = 0; i < prog->NumShaders; i++) {
- if (!prog->Shaders[i]->CompileStatus) {
- fail_link(prog, "linking with uncompiled shader");
- prog->LinkStatus = GL_FALSE;
- }
- }
-
- prog->Varying = _mesa_new_parameter_list();
- _mesa_reference_vertprog(ctx, &prog->VertexProgram, NULL);
- _mesa_reference_fragprog(ctx, &prog->FragmentProgram, NULL);
- _mesa_reference_geomprog(ctx, &prog->GeometryProgram, NULL);
-
- if (prog->LinkStatus) {
- link_shaders(ctx, prog);
- }
-
- if (prog->LinkStatus) {
- if (!ctx->Driver.LinkShader(ctx, prog)) {
- prog->LinkStatus = GL_FALSE;
- }
- }
-
- set_uniform_initializers(ctx, prog);
-
- if (ctx->Shader.Flags & GLSL_DUMP) {
- if (!prog->LinkStatus) {
- printf("GLSL shader program %d failed to link\n", prog->Name);
- }
-
- if (prog->InfoLog && prog->InfoLog[0] != 0) {
- printf("GLSL shader program %d info log:\n", prog->Name);
- printf("%s\n", prog->InfoLog);
- }
- }
-}
-
-} /* extern "C" */
+/*
+ * Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
+ * Copyright (C) 2008 VMware, Inc. All Rights Reserved.
+ * 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 ir_to_mesa.cpp
+ *
+ * Translate GLSL IR to Mesa's gl_program representation.
+ */
+
+#include <stdio.h>
+#include "main/compiler.h"
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_print_visitor.h"
+#include "ir_expression_flattening.h"
+#include "glsl_types.h"
+#include "glsl_parser_extras.h"
+#include "../glsl/program.h"
+#include "ir_optimization.h"
+#include "ast.h"
+
+extern "C" {
+#include "main/mtypes.h"
+#include "main/shaderapi.h"
+#include "main/shaderobj.h"
+#include "main/uniforms.h"
+#include "program/hash_table.h"
+#include "program/prog_instruction.h"
+#include "program/prog_optimize.h"
+#include "program/prog_print.h"
+#include "program/program.h"
+#include "program/prog_uniform.h"
+#include "program/prog_parameter.h"
+#include "program/sampler.h"
+}
+
+static int swizzle_for_size(int size);
+
+/**
+ * This struct is a corresponding struct to Mesa prog_src_register, with
+ * wider fields.
+ */
+typedef struct ir_to_mesa_src_reg {
+ ir_to_mesa_src_reg(int file, int index, const glsl_type *type)
+ {
+ this->file = (gl_register_file) file;
+ this->index = index;
+ if (type && (type->is_scalar() || type->is_vector() || type->is_matrix()))
+ this->swizzle = swizzle_for_size(type->vector_elements);
+ else
+ this->swizzle = SWIZZLE_XYZW;
+ this->negate = 0;
+ this->reladdr = NULL;
+ }
+
+ ir_to_mesa_src_reg()
+ {
+ this->file = PROGRAM_UNDEFINED;
+ this->index = 0;
+ this->swizzle = 0;
+ this->negate = 0;
+ this->reladdr = NULL;
+ }
+
+ gl_register_file file; /**< PROGRAM_* from Mesa */
+ int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
+ GLuint swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */
+ int negate; /**< NEGATE_XYZW mask from mesa */
+ /** Register index should be offset by the integer in this reg. */
+ ir_to_mesa_src_reg *reladdr;
+} ir_to_mesa_src_reg;
+
+typedef struct ir_to_mesa_dst_reg {
+ int file; /**< PROGRAM_* from Mesa */
+ int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
+ int writemask; /**< Bitfield of WRITEMASK_[XYZW] */
+ GLuint cond_mask:4;
+ /** Register index should be offset by the integer in this reg. */
+ ir_to_mesa_src_reg *reladdr;
+} ir_to_mesa_dst_reg;
+
+extern ir_to_mesa_src_reg ir_to_mesa_undef;
+
+class ir_to_mesa_instruction : public exec_node {
+public:
+ /* Callers of this ralloc-based new need not call delete. It's
+ * easier to just ralloc_free 'ctx' (or any of its ancestors). */
+ static void* operator new(size_t size, void *ctx)
+ {
+ void *node;
+
+ node = rzalloc_size(ctx, size);
+ assert(node != NULL);
+
+ return node;
+ }
+
+ enum prog_opcode op;
+ ir_to_mesa_dst_reg dst_reg;
+ ir_to_mesa_src_reg src_reg[3];
+ /** Pointer to the ir source this tree came from for debugging */
+ ir_instruction *ir;
+ GLboolean cond_update;
+ bool saturate;
+ int sampler; /**< sampler index */
+ int tex_target; /**< One of TEXTURE_*_INDEX */
+ GLboolean tex_shadow;
+
+ class function_entry *function; /* Set on OPCODE_CAL or OPCODE_BGNSUB */
+};
+
+class variable_storage : public exec_node {
+public:
+ variable_storage(ir_variable *var, gl_register_file file, int index)
+ : file(file), index(index), var(var)
+ {
+ /* empty */
+ }
+
+ gl_register_file file;
+ int index;
+ ir_variable *var; /* variable that maps to this, if any */
+};
+
+class function_entry : public exec_node {
+public:
+ ir_function_signature *sig;
+
+ /**
+ * identifier of this function signature used by the program.
+ *
+ * At the point that Mesa instructions for function calls are
+ * generated, we don't know the address of the first instruction of
+ * the function body. So we make the BranchTarget that is called a
+ * small integer and rewrite them during set_branchtargets().
+ */
+ int sig_id;
+
+ /**
+ * Pointer to first instruction of the function body.
+ *
+ * Set during function body emits after main() is processed.
+ */
+ ir_to_mesa_instruction *bgn_inst;
+
+ /**
+ * Index of the first instruction of the function body in actual
+ * Mesa IR.
+ *
+ * Set after convertion from ir_to_mesa_instruction to prog_instruction.
+ */
+ int inst;
+
+ /** Storage for the return value. */
+ ir_to_mesa_src_reg return_reg;
+};
+
+class ir_to_mesa_visitor : public ir_visitor {
+public:
+ ir_to_mesa_visitor();
+ ~ir_to_mesa_visitor();
+
+ function_entry *current_function;
+
+ struct gl_context *ctx;
+ struct gl_program *prog;
+ struct gl_shader_program *shader_program;
+ struct gl_shader_compiler_options *options;
+
+ int next_temp;
+
+ variable_storage *find_variable_storage(ir_variable *var);
+
+ function_entry *get_function_signature(ir_function_signature *sig);
+
+ ir_to_mesa_src_reg get_temp(const glsl_type *type);
+ void reladdr_to_temp(ir_instruction *ir,
+ ir_to_mesa_src_reg *reg, int *num_reladdr);
+
+ struct ir_to_mesa_src_reg src_reg_for_float(float val);
+
+ /**
+ * \name Visit methods
+ *
+ * As typical for the visitor pattern, there must be one \c visit method for
+ * each concrete subclass of \c ir_instruction. Virtual base classes within
+ * the hierarchy should not have \c visit methods.
+ */
+ /*@{*/
+ virtual void visit(ir_variable *);
+ virtual void visit(ir_loop *);
+ virtual void visit(ir_loop_jump *);
+ virtual void visit(ir_function_signature *);
+ virtual void visit(ir_function *);
+ virtual void visit(ir_expression *);
+ virtual void visit(ir_swizzle *);
+ virtual void visit(ir_dereference_variable *);
+ virtual void visit(ir_dereference_array *);
+ virtual void visit(ir_dereference_record *);
+ virtual void visit(ir_assignment *);
+ virtual void visit(ir_constant *);
+ virtual void visit(ir_call *);
+ virtual void visit(ir_return *);
+ virtual void visit(ir_discard *);
+ virtual void visit(ir_texture *);
+ virtual void visit(ir_if *);
+ /*@}*/
+
+ struct ir_to_mesa_src_reg result;
+
+ /** List of variable_storage */
+ exec_list variables;
+
+ /** List of function_entry */
+ exec_list function_signatures;
+ int next_signature_id;
+
+ /** List of ir_to_mesa_instruction */
+ exec_list instructions;
+
+ ir_to_mesa_instruction *ir_to_mesa_emit_op0(ir_instruction *ir,
+ enum prog_opcode op);
+
+ ir_to_mesa_instruction *ir_to_mesa_emit_op1(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0);
+
+ ir_to_mesa_instruction *ir_to_mesa_emit_op2(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1);
+
+ ir_to_mesa_instruction *ir_to_mesa_emit_op3(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1,
+ ir_to_mesa_src_reg src2);
+
+ /**
+ * Emit the correct dot-product instruction for the type of arguments
+ *
+ * \sa ir_to_mesa_emit_op2
+ */
+ void ir_to_mesa_emit_dp(ir_instruction *ir,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1,
+ unsigned elements);
+
+ void ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0);
+
+ void ir_to_mesa_emit_scalar_op2(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1);
+
+ void emit_scs(ir_instruction *ir, enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ const ir_to_mesa_src_reg &src);
+
+ GLboolean try_emit_mad(ir_expression *ir,
+ int mul_operand);
+ GLboolean try_emit_sat(ir_expression *ir);
+
+ void emit_swz(ir_expression *ir);
+
+ bool process_move_condition(ir_rvalue *ir);
+
+ void copy_propagate(void);
+
+ void *mem_ctx;
+};
+
+ir_to_mesa_src_reg ir_to_mesa_undef = ir_to_mesa_src_reg(PROGRAM_UNDEFINED, 0, NULL);
+
+ir_to_mesa_dst_reg ir_to_mesa_undef_dst = {
+ PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, COND_TR, NULL,
+};
+
+ir_to_mesa_dst_reg ir_to_mesa_address_reg = {
+ PROGRAM_ADDRESS, 0, WRITEMASK_X, COND_TR, NULL
+};
+
+static void
+fail_link(struct gl_shader_program *prog, const char *fmt, ...) PRINTFLIKE(2, 3);
+
+static void
+fail_link(struct gl_shader_program *prog, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ ralloc_vasprintf_append(&prog->InfoLog, fmt, args);
+ va_end(args);
+
+ prog->LinkStatus = GL_FALSE;
+}
+
+static int
+swizzle_for_size(int size)
+{
+ int size_swizzles[4] = {
+ MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X),
+ MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y),
+ MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z),
+ MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
+ };
+
+ assert((size >= 1) && (size <= 4));
+ return size_swizzles[size - 1];
+}
+
+ir_to_mesa_instruction *
+ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1,
+ ir_to_mesa_src_reg src2)
+{
+ ir_to_mesa_instruction *inst = new(mem_ctx) ir_to_mesa_instruction();
+ int num_reladdr = 0;
+
+ /* If we have to do relative addressing, we want to load the ARL
+ * reg directly for one of the regs, and preload the other reladdr
+ * sources into temps.
+ */
+ num_reladdr += dst.reladdr != NULL;
+ num_reladdr += src0.reladdr != NULL;
+ num_reladdr += src1.reladdr != NULL;
+ num_reladdr += src2.reladdr != NULL;
+
+ reladdr_to_temp(ir, &src2, &num_reladdr);
+ reladdr_to_temp(ir, &src1, &num_reladdr);
+ reladdr_to_temp(ir, &src0, &num_reladdr);
+
+ if (dst.reladdr) {
+ ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg,
+ *dst.reladdr);
+
+ num_reladdr--;
+ }
+ assert(num_reladdr == 0);
+
+ inst->op = op;
+ inst->dst_reg = dst;
+ inst->src_reg[0] = src0;
+ inst->src_reg[1] = src1;
+ inst->src_reg[2] = src2;
+ inst->ir = ir;
+
+ inst->function = NULL;
+
+ this->instructions.push_tail(inst);
+
+ return inst;
+}
+
+
+ir_to_mesa_instruction *
+ir_to_mesa_visitor::ir_to_mesa_emit_op2(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1)
+{
+ return ir_to_mesa_emit_op3(ir, op, dst, src0, src1, ir_to_mesa_undef);
+}
+
+ir_to_mesa_instruction *
+ir_to_mesa_visitor::ir_to_mesa_emit_op1(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0)
+{
+ assert(dst.writemask != 0);
+ return ir_to_mesa_emit_op3(ir, op, dst,
+ src0, ir_to_mesa_undef, ir_to_mesa_undef);
+}
+
+ir_to_mesa_instruction *
+ir_to_mesa_visitor::ir_to_mesa_emit_op0(ir_instruction *ir,
+ enum prog_opcode op)
+{
+ return ir_to_mesa_emit_op3(ir, op, ir_to_mesa_undef_dst,
+ ir_to_mesa_undef,
+ ir_to_mesa_undef,
+ ir_to_mesa_undef);
+}
+
+void
+ir_to_mesa_visitor::ir_to_mesa_emit_dp(ir_instruction *ir,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1,
+ unsigned elements)
+{
+ static const gl_inst_opcode dot_opcodes[] = {
+ OPCODE_DP2, OPCODE_DP3, OPCODE_DP4
+ };
+
+ ir_to_mesa_emit_op3(ir, dot_opcodes[elements - 2],
+ dst, src0, src1, ir_to_mesa_undef);
+}
+
+inline ir_to_mesa_dst_reg
+ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg)
+{
+ ir_to_mesa_dst_reg dst_reg;
+
+ dst_reg.file = reg.file;
+ dst_reg.index = reg.index;
+ dst_reg.writemask = WRITEMASK_XYZW;
+ dst_reg.cond_mask = COND_TR;
+ dst_reg.reladdr = reg.reladdr;
+
+ return dst_reg;
+}
+
+inline ir_to_mesa_src_reg
+ir_to_mesa_src_reg_from_dst(ir_to_mesa_dst_reg reg)
+{
+ return ir_to_mesa_src_reg(reg.file, reg.index, NULL);
+}
+
+/**
+ * Emits Mesa scalar opcodes to produce unique answers across channels.
+ *
+ * Some Mesa opcodes are scalar-only, like ARB_fp/vp. The src X
+ * channel determines the result across all channels. So to do a vec4
+ * of this operation, we want to emit a scalar per source channel used
+ * to produce dest channels.
+ */
+void
+ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op2(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg orig_src0,
+ ir_to_mesa_src_reg orig_src1)
+{
+ int i, j;
+ int done_mask = ~dst.writemask;
+
+ /* Mesa RCP is a scalar operation splatting results to all channels,
+ * like ARB_fp/vp. So emit as many RCPs as necessary to cover our
+ * dst channels.
+ */
+ for (i = 0; i < 4; i++) {
+ GLuint this_mask = (1 << i);
+ ir_to_mesa_instruction *inst;
+ ir_to_mesa_src_reg src0 = orig_src0;
+ ir_to_mesa_src_reg src1 = orig_src1;
+
+ if (done_mask & this_mask)
+ continue;
+
+ GLuint src0_swiz = GET_SWZ(src0.swizzle, i);
+ GLuint src1_swiz = GET_SWZ(src1.swizzle, i);
+ for (j = i + 1; j < 4; j++) {
+ /* If there is another enabled component in the destination that is
+ * derived from the same inputs, generate its value on this pass as
+ * well.
+ */
+ if (!(done_mask & (1 << j)) &&
+ GET_SWZ(src0.swizzle, j) == src0_swiz &&
+ GET_SWZ(src1.swizzle, j) == src1_swiz) {
+ this_mask |= (1 << j);
+ }
+ }
+ src0.swizzle = MAKE_SWIZZLE4(src0_swiz, src0_swiz,
+ src0_swiz, src0_swiz);
+ src1.swizzle = MAKE_SWIZZLE4(src1_swiz, src1_swiz,
+ src1_swiz, src1_swiz);
+
+ inst = ir_to_mesa_emit_op2(ir, op,
+ dst,
+ src0,
+ src1);
+ inst->dst_reg.writemask = this_mask;
+ done_mask |= this_mask;
+ }
+}
+
+void
+ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0)
+{
+ ir_to_mesa_src_reg undef = ir_to_mesa_undef;
+
+ undef.swizzle = SWIZZLE_XXXX;
+
+ ir_to_mesa_emit_scalar_op2(ir, op, dst, src0, undef);
+}
+
+/**
+ * Emit an OPCODE_SCS instruction
+ *
+ * The \c SCS opcode functions a bit differently than the other Mesa (or
+ * ARB_fragment_program) opcodes. Instead of splatting its result across all
+ * four components of the destination, it writes one value to the \c x
+ * component and another value to the \c y component.
+ *
+ * \param ir IR instruction being processed
+ * \param op Either \c OPCODE_SIN or \c OPCODE_COS depending on which
+ * value is desired.
+ * \param dst Destination register
+ * \param src Source register
+ */
+void
+ir_to_mesa_visitor::emit_scs(ir_instruction *ir, enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ const ir_to_mesa_src_reg &src)
+{
+ /* Vertex programs cannot use the SCS opcode.
+ */
+ if (this->prog->Target == GL_VERTEX_PROGRAM_ARB) {
+ ir_to_mesa_emit_scalar_op1(ir, op, dst, src);
+ return;
+ }
+
+ const unsigned component = (op == OPCODE_SIN) ? 0 : 1;
+ const unsigned scs_mask = (1U << component);
+ int done_mask = ~dst.writemask;
+ ir_to_mesa_src_reg tmp;
+
+ assert(op == OPCODE_SIN || op == OPCODE_COS);
+
+ /* If there are compnents in the destination that differ from the component
+ * that will be written by the SCS instrution, we'll need a temporary.
+ */
+ if (scs_mask != unsigned(dst.writemask)) {
+ tmp = get_temp(glsl_type::vec4_type);
+ }
+
+ for (unsigned i = 0; i < 4; i++) {
+ unsigned this_mask = (1U << i);
+ ir_to_mesa_src_reg src0 = src;
+
+ if ((done_mask & this_mask) != 0)
+ continue;
+
+ /* The source swizzle specified which component of the source generates
+ * sine / cosine for the current component in the destination. The SCS
+ * instruction requires that this value be swizzle to the X component.
+ * Replace the current swizzle with a swizzle that puts the source in
+ * the X component.
+ */
+ unsigned src0_swiz = GET_SWZ(src.swizzle, i);
+
+ src0.swizzle = MAKE_SWIZZLE4(src0_swiz, src0_swiz,
+ src0_swiz, src0_swiz);
+ for (unsigned j = i + 1; j < 4; j++) {
+ /* If there is another enabled component in the destination that is
+ * derived from the same inputs, generate its value on this pass as
+ * well.
+ */
+ if (!(done_mask & (1 << j)) &&
+ GET_SWZ(src0.swizzle, j) == src0_swiz) {
+ this_mask |= (1 << j);
+ }
+ }
+
+ if (this_mask != scs_mask) {
+ ir_to_mesa_instruction *inst;
+ ir_to_mesa_dst_reg tmp_dst = ir_to_mesa_dst_reg_from_src(tmp);
+
+ /* Emit the SCS instruction.
+ */
+ inst = ir_to_mesa_emit_op1(ir, OPCODE_SCS, tmp_dst, src0);
+ inst->dst_reg.writemask = scs_mask;
+
+ /* Move the result of the SCS instruction to the desired location in
+ * the destination.
+ */
+ tmp.swizzle = MAKE_SWIZZLE4(component, component,
+ component, component);
+ inst = ir_to_mesa_emit_op1(ir, OPCODE_SCS, dst, tmp);
+ inst->dst_reg.writemask = this_mask;
+ } else {
+ /* Emit the SCS instruction to write directly to the destination.
+ */
+ ir_to_mesa_instruction *inst =
+ ir_to_mesa_emit_op1(ir, OPCODE_SCS, dst, src0);
+ inst->dst_reg.writemask = scs_mask;
+ }
+
+ done_mask |= this_mask;
+ }
+}
+
+struct ir_to_mesa_src_reg
+ir_to_mesa_visitor::src_reg_for_float(float val)
+{
+ ir_to_mesa_src_reg src_reg(PROGRAM_CONSTANT, -1, NULL);
+
+ src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
+ &val, 1, &src_reg.swizzle);
+
+ return src_reg;
+}
+
+static int
+type_size(const struct glsl_type *type)
+{
+ unsigned int i;
+ int size;
+
+ switch (type->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_FLOAT:
+ case GLSL_TYPE_BOOL:
+ if (type->is_matrix()) {
+ return type->matrix_columns;
+ } else {
+ /* Regardless of size of vector, it gets a vec4. This is bad
+ * packing for things like floats, but otherwise arrays become a
+ * mess. Hopefully a later pass over the code can pack scalars
+ * down if appropriate.
+ */
+ return 1;
+ }
+ case GLSL_TYPE_ARRAY:
+ assert(type->length > 0);
+ return type_size(type->fields.array) * type->length;
+ case GLSL_TYPE_STRUCT:
+ size = 0;
+ for (i = 0; i < type->length; i++) {
+ size += type_size(type->fields.structure[i].type);
+ }
+ return size;
+ case GLSL_TYPE_SAMPLER:
+ /* Samplers take up one slot in UNIFORMS[], but they're baked in
+ * at link time.
+ */
+ return 1;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+/**
+ * In the initial pass of codegen, we assign temporary numbers to
+ * intermediate results. (not SSA -- variable assignments will reuse
+ * storage). Actual register allocation for the Mesa VM occurs in a
+ * pass over the Mesa IR later.
+ */
+ir_to_mesa_src_reg
+ir_to_mesa_visitor::get_temp(const glsl_type *type)
+{
+ ir_to_mesa_src_reg src_reg;
+ int swizzle[4];
+ int i;
+
+ src_reg.file = PROGRAM_TEMPORARY;
+ src_reg.index = next_temp;
+ src_reg.reladdr = NULL;
+ next_temp += type_size(type);
+
+ if (type->is_array() || type->is_record()) {
+ src_reg.swizzle = SWIZZLE_NOOP;
+ } else {
+ for (i = 0; i < type->vector_elements; i++)
+ swizzle[i] = i;
+ for (; i < 4; i++)
+ swizzle[i] = type->vector_elements - 1;
+ src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1],
+ swizzle[2], swizzle[3]);
+ }
+ src_reg.negate = 0;
+
+ return src_reg;
+}
+
+variable_storage *
+ir_to_mesa_visitor::find_variable_storage(ir_variable *var)
+{
+
+ variable_storage *entry;
+
+ foreach_iter(exec_list_iterator, iter, this->variables) {
+ entry = (variable_storage *)iter.get();
+
+ if (entry->var == var)
+ return entry;
+ }
+
+ return NULL;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_variable *ir)
+{
+ if (strcmp(ir->name, "gl_FragCoord") == 0) {
+ struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog;
+
+ fp->OriginUpperLeft = ir->origin_upper_left;
+ fp->PixelCenterInteger = ir->pixel_center_integer;
+
+ } else if (strcmp(ir->name, "gl_FragDepth") == 0) {
+ struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog;
+ switch (ir->depth_layout) {
+ case ir_depth_layout_none:
+ fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_NONE;
+ break;
+ case ir_depth_layout_any:
+ fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_ANY;
+ break;
+ case ir_depth_layout_greater:
+ fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_GREATER;
+ break;
+ case ir_depth_layout_less:
+ fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_LESS;
+ break;
+ case ir_depth_layout_unchanged:
+ fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_UNCHANGED;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+
+ if (ir->mode == ir_var_uniform && strncmp(ir->name, "gl_", 3) == 0) {
+ unsigned int i;
+ const struct gl_builtin_uniform_desc *statevar;
+
+ for (i = 0; _mesa_builtin_uniform_desc[i].name; i++) {
+ if (strcmp(ir->name, _mesa_builtin_uniform_desc[i].name) == 0)
+ break;
+ }
+
+ if (!_mesa_builtin_uniform_desc[i].name) {
+ fail_link(this->shader_program,
+ "Failed to find builtin uniform `%s'\n", ir->name);
+ return;
+ }
+
+ statevar = &_mesa_builtin_uniform_desc[i];
+
+ int array_count;
+ if (ir->type->is_array()) {
+ array_count = ir->type->length;
+ } else {
+ array_count = 1;
+ }
+
+ /* Check if this statevar's setup in the STATE file exactly
+ * matches how we'll want to reference it as a
+ * struct/array/whatever. If not, then we need to move it into
+ * temporary storage and hope that it'll get copy-propagated
+ * out.
+ */
+ for (i = 0; i < statevar->num_elements; i++) {
+ if (statevar->elements[i].swizzle != SWIZZLE_XYZW) {
+ break;
+ }
+ }
+
+ struct variable_storage *storage;
+ ir_to_mesa_dst_reg dst;
+ if (i == statevar->num_elements) {
+ /* We'll set the index later. */
+ storage = new(mem_ctx) variable_storage(ir, PROGRAM_STATE_VAR, -1);
+ this->variables.push_tail(storage);
+
+ dst = ir_to_mesa_undef_dst;
+ } else {
+ storage = new(mem_ctx) variable_storage(ir, PROGRAM_TEMPORARY,
+ this->next_temp);
+ this->variables.push_tail(storage);
+ this->next_temp += type_size(ir->type);
+
+ dst = ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg(PROGRAM_TEMPORARY,
+ storage->index,
+ NULL));
+ }
+
+
+ for (int a = 0; a < array_count; a++) {
+ for (unsigned int i = 0; i < statevar->num_elements; i++) {
+ struct gl_builtin_uniform_element *element = &statevar->elements[i];
+ int tokens[STATE_LENGTH];
+
+ memcpy(tokens, element->tokens, sizeof(element->tokens));
+ if (ir->type->is_array()) {
+ tokens[1] = a;
+ }
+
+ int index = _mesa_add_state_reference(this->prog->Parameters,
+ (gl_state_index *)tokens);
+
+ if (storage->file == PROGRAM_STATE_VAR) {
+ if (storage->index == -1) {
+ storage->index = index;
+ } else {
+ assert(index ==
+ (int)(storage->index + a * statevar->num_elements + i));
+ }
+ } else {
+ ir_to_mesa_src_reg src(PROGRAM_STATE_VAR, index, NULL);
+ src.swizzle = element->swizzle;
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, dst, src);
+ /* even a float takes up a whole vec4 reg in a struct/array. */
+ dst.index++;
+ }
+ }
+ }
+ if (storage->file == PROGRAM_TEMPORARY &&
+ dst.index != storage->index + type_size(ir->type)) {
+ fail_link(this->shader_program,
+ "failed to load builtin uniform `%s' (%d/%d regs loaded)\n",
+ ir->name, dst.index - storage->index,
+ type_size(ir->type));
+ }
+ }
+}
+
+void
+ir_to_mesa_visitor::visit(ir_loop *ir)
+{
+ ir_dereference_variable *counter = NULL;
+
+ if (ir->counter != NULL)
+ counter = new(ir) ir_dereference_variable(ir->counter);
+
+ if (ir->from != NULL) {
+ assert(ir->counter != NULL);
+
+ ir_assignment *a = new(ir) ir_assignment(counter, ir->from, NULL);
+
+ a->accept(this);
+ delete a;
+ }
+
+ ir_to_mesa_emit_op0(NULL, OPCODE_BGNLOOP);
+
+ if (ir->to) {
+ ir_expression *e =
+ new(ir) ir_expression(ir->cmp, glsl_type::bool_type,
+ counter, ir->to);
+ ir_if *if_stmt = new(ir) ir_if(e);
+
+ ir_loop_jump *brk = new(ir) ir_loop_jump(ir_loop_jump::jump_break);
+
+ if_stmt->then_instructions.push_tail(brk);
+
+ if_stmt->accept(this);
+
+ delete if_stmt;
+ delete e;
+ delete brk;
+ }
+
+ visit_exec_list(&ir->body_instructions, this);
+
+ if (ir->increment) {
+ ir_expression *e =
+ new(ir) ir_expression(ir_binop_add, counter->type,
+ counter, ir->increment);
+
+ ir_assignment *a = new(ir) ir_assignment(counter, e, NULL);
+
+ a->accept(this);
+ delete a;
+ delete e;
+ }
+
+ ir_to_mesa_emit_op0(NULL, OPCODE_ENDLOOP);
+}
+
+void
+ir_to_mesa_visitor::visit(ir_loop_jump *ir)
+{
+ switch (ir->mode) {
+ case ir_loop_jump::jump_break:
+ ir_to_mesa_emit_op0(NULL, OPCODE_BRK);
+ break;
+ case ir_loop_jump::jump_continue:
+ ir_to_mesa_emit_op0(NULL, OPCODE_CONT);
+ break;
+ }
+}
+
+
+void
+ir_to_mesa_visitor::visit(ir_function_signature *ir)
+{
+ assert(0);
+ (void)ir;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_function *ir)
+{
+ /* Ignore function bodies other than main() -- we shouldn't see calls to
+ * them since they should all be inlined before we get to ir_to_mesa.
+ */
+ if (strcmp(ir->name, "main") == 0) {
+ const ir_function_signature *sig;
+ exec_list empty;
+
+ sig = ir->matching_signature(&empty);
+
+ assert(sig);
+
+ foreach_iter(exec_list_iterator, iter, sig->body) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+
+ ir->accept(this);
+ }
+ }
+}
+
+GLboolean
+ir_to_mesa_visitor::try_emit_mad(ir_expression *ir, int mul_operand)
+{
+ int nonmul_operand = 1 - mul_operand;
+ ir_to_mesa_src_reg a, b, c;
+
+ ir_expression *expr = ir->operands[mul_operand]->as_expression();
+ if (!expr || expr->operation != ir_binop_mul)
+ return false;
+
+ expr->operands[0]->accept(this);
+ a = this->result;
+ expr->operands[1]->accept(this);
+ b = this->result;
+ ir->operands[nonmul_operand]->accept(this);
+ c = this->result;
+
+ this->result = get_temp(ir->type);
+ ir_to_mesa_emit_op3(ir, OPCODE_MAD,
+ ir_to_mesa_dst_reg_from_src(this->result), a, b, c);
+
+ return true;
+}
+
+GLboolean
+ir_to_mesa_visitor::try_emit_sat(ir_expression *ir)
+{
+ /* Saturates were only introduced to vertex programs in
+ * NV_vertex_program3, so don't give them to drivers in the VP.
+ */
+ if (this->prog->Target == GL_VERTEX_PROGRAM_ARB)
+ return false;
+
+ ir_rvalue *sat_src = ir->as_rvalue_to_saturate();
+ if (!sat_src)
+ return false;
+
+ sat_src->accept(this);
+ ir_to_mesa_src_reg src = this->result;
+
+ this->result = get_temp(ir->type);
+ ir_to_mesa_instruction *inst;
+ inst = ir_to_mesa_emit_op1(ir, OPCODE_MOV,
+ ir_to_mesa_dst_reg_from_src(this->result),
+ src);
+ inst->saturate = true;
+
+ return true;
+}
+
+void
+ir_to_mesa_visitor::reladdr_to_temp(ir_instruction *ir,
+ ir_to_mesa_src_reg *reg, int *num_reladdr)
+{
+ if (!reg->reladdr)
+ return;
+
+ ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg, *reg->reladdr);
+
+ if (*num_reladdr != 1) {
+ ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
+
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV,
+ ir_to_mesa_dst_reg_from_src(temp), *reg);
+ *reg = temp;
+ }
+
+ (*num_reladdr)--;
+}
+
+void
+ir_to_mesa_visitor::emit_swz(ir_expression *ir)
+{
+ /* Assume that the vector operator is in a form compatible with OPCODE_SWZ.
+ * This means that each of the operands is either an immediate value of -1,
+ * 0, or 1, or is a component from one source register (possibly with
+ * negation).
+ */
+ uint8_t components[4] = { 0 };
+ bool negate[4] = { false };
+ ir_variable *var = NULL;
+
+ for (unsigned i = 0; i < ir->type->vector_elements; i++) {
+ ir_rvalue *op = ir->operands[i];
+
+ assert(op->type->is_scalar());
+
+ while (op != NULL) {
+ switch (op->ir_type) {
+ case ir_type_constant: {
+
+ assert(op->type->is_scalar());
+
+ const ir_constant *const c = op->as_constant();
+ if (c->is_one()) {
+ components[i] = SWIZZLE_ONE;
+ } else if (c->is_zero()) {
+ components[i] = SWIZZLE_ZERO;
+ } else if (c->is_negative_one()) {
+ components[i] = SWIZZLE_ONE;
+ negate[i] = true;
+ } else {
+ assert(!"SWZ constant must be 0.0 or 1.0.");
+ }
+
+ op = NULL;
+ break;
+ }
+
+ case ir_type_dereference_variable: {
+ ir_dereference_variable *const deref =
+ (ir_dereference_variable *) op;
+
+ assert((var == NULL) || (deref->var == var));
+ components[i] = SWIZZLE_X;
+ var = deref->var;
+ op = NULL;
+ break;
+ }
+
+ case ir_type_expression: {
+ ir_expression *const expr = (ir_expression *) op;
+
+ assert(expr->operation == ir_unop_neg);
+ negate[i] = true;
+
+ op = expr->operands[0];
+ break;
+ }
+
+ case ir_type_swizzle: {
+ ir_swizzle *const swiz = (ir_swizzle *) op;
+
+ components[i] = swiz->mask.x;
+ op = swiz->val;
+ break;
+ }
+
+ default:
+ assert(!"Should not get here.");
+ return;
+ }
+ }
+ }
+
+ assert(var != NULL);
+
+ ir_dereference_variable *const deref =
+ new(mem_ctx) ir_dereference_variable(var);
+
+ this->result.file = PROGRAM_UNDEFINED;
+ deref->accept(this);
+ if (this->result.file == PROGRAM_UNDEFINED) {
+ ir_print_visitor v;
+ printf("Failed to get tree for expression operand:\n");
+ deref->accept(&v);
+ exit(1);
+ }
+
+ ir_to_mesa_src_reg src;
+
+ src = this->result;
+ src.swizzle = MAKE_SWIZZLE4(components[0],
+ components[1],
+ components[2],
+ components[3]);
+ src.negate = ((unsigned(negate[0]) << 0)
+ | (unsigned(negate[1]) << 1)
+ | (unsigned(negate[2]) << 2)
+ | (unsigned(negate[3]) << 3));
+
+ /* Storage for our result. Ideally for an assignment we'd be using the
+ * actual storage for the result here, instead.
+ */
+ const ir_to_mesa_src_reg result_src = get_temp(ir->type);
+ ir_to_mesa_dst_reg result_dst = ir_to_mesa_dst_reg_from_src(result_src);
+
+ /* Limit writes to the channels that will be used by result_src later.
+ * This does limit this temp's use as a temporary for multi-instruction
+ * sequences.
+ */
+ result_dst.writemask = (1 << ir->type->vector_elements) - 1;
+
+ ir_to_mesa_emit_op1(ir, OPCODE_SWZ, result_dst, src);
+ this->result = result_src;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_expression *ir)
+{
+ unsigned int operand;
+ struct ir_to_mesa_src_reg op[Elements(ir->operands)];
+ struct ir_to_mesa_src_reg result_src;
+ struct ir_to_mesa_dst_reg result_dst;
+
+ /* Quick peephole: Emit OPCODE_MAD(a, b, c) instead of ADD(MUL(a, b), c)
+ */
+ if (ir->operation == ir_binop_add) {
+ if (try_emit_mad(ir, 1))
+ return;
+ if (try_emit_mad(ir, 0))
+ return;
+ }
+ if (try_emit_sat(ir))
+ return;
+
+ if (ir->operation == ir_quadop_vector) {
+ this->emit_swz(ir);
+ return;
+ }
+
+ for (operand = 0; operand < ir->get_num_operands(); operand++) {
+ this->result.file = PROGRAM_UNDEFINED;
+ ir->operands[operand]->accept(this);
+ if (this->result.file == PROGRAM_UNDEFINED) {
+ ir_print_visitor v;
+ printf("Failed to get tree for expression operand:\n");
+ ir->operands[operand]->accept(&v);
+ exit(1);
+ }
+ op[operand] = this->result;
+
+ /* Matrix expression operands should have been broken down to vector
+ * operations already.
+ */
+ assert(!ir->operands[operand]->type->is_matrix());
+ }
+
+ int vector_elements = ir->operands[0]->type->vector_elements;
+ if (ir->operands[1]) {
+ vector_elements = MAX2(vector_elements,
+ ir->operands[1]->type->vector_elements);
+ }
+
+ this->result.file = PROGRAM_UNDEFINED;
+
+ /* Storage for our result. Ideally for an assignment we'd be using
+ * the actual storage for the result here, instead.
+ */
+ result_src = get_temp(ir->type);
+ /* convenience for the emit functions below. */
+ result_dst = ir_to_mesa_dst_reg_from_src(result_src);
+ /* Limit writes to the channels that will be used by result_src later.
+ * This does limit this temp's use as a temporary for multi-instruction
+ * sequences.
+ */
+ result_dst.writemask = (1 << ir->type->vector_elements) - 1;
+
+ switch (ir->operation) {
+ case ir_unop_logic_not:
+ ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst,
+ op[0], src_reg_for_float(0.0));
+ break;
+ case ir_unop_neg:
+ op[0].negate = ~op[0].negate;
+ result_src = op[0];
+ break;
+ case ir_unop_abs:
+ ir_to_mesa_emit_op1(ir, OPCODE_ABS, result_dst, op[0]);
+ break;
+ case ir_unop_sign:
+ ir_to_mesa_emit_op1(ir, OPCODE_SSG, result_dst, op[0]);
+ break;
+ case ir_unop_rcp:
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_RCP, result_dst, op[0]);
+ break;
+
+ case ir_unop_exp2:
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_EX2, result_dst, op[0]);
+ break;
+ case ir_unop_exp:
+ case ir_unop_log:
+ assert(!"not reached: should be handled by ir_explog_to_explog2");
+ break;
+ case ir_unop_log2:
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_LG2, result_dst, op[0]);
+ break;
+ case ir_unop_sin:
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_SIN, result_dst, op[0]);
+ break;
+ case ir_unop_cos:
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_COS, result_dst, op[0]);
+ break;
+ case ir_unop_sin_reduced:
+ emit_scs(ir, OPCODE_SIN, result_dst, op[0]);
+ break;
+ case ir_unop_cos_reduced:
+ emit_scs(ir, OPCODE_COS, result_dst, op[0]);
+ break;
+
+ case ir_unop_dFdx:
+ ir_to_mesa_emit_op1(ir, OPCODE_DDX, result_dst, op[0]);
+ break;
+ case ir_unop_dFdy:
+ ir_to_mesa_emit_op1(ir, OPCODE_DDY, result_dst, op[0]);
+ break;
+
+ case ir_unop_noise: {
+ const enum prog_opcode opcode =
+ prog_opcode(OPCODE_NOISE1
+ + (ir->operands[0]->type->vector_elements) - 1);
+ assert((opcode >= OPCODE_NOISE1) && (opcode <= OPCODE_NOISE4));
+
+ ir_to_mesa_emit_op1(ir, opcode, result_dst, op[0]);
+ break;
+ }
+
+ case ir_binop_add:
+ ir_to_mesa_emit_op2(ir, OPCODE_ADD, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_sub:
+ ir_to_mesa_emit_op2(ir, OPCODE_SUB, result_dst, op[0], op[1]);
+ break;
+
+ case ir_binop_mul:
+ ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_div:
+ assert(!"not reached: should be handled by ir_div_to_mul_rcp");
+ case ir_binop_mod:
+ assert(!"ir_binop_mod should have been converted to b * fract(a/b)");
+ break;
+
+ case ir_binop_less:
+ ir_to_mesa_emit_op2(ir, OPCODE_SLT, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_greater:
+ ir_to_mesa_emit_op2(ir, OPCODE_SGT, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_lequal:
+ ir_to_mesa_emit_op2(ir, OPCODE_SLE, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_gequal:
+ ir_to_mesa_emit_op2(ir, OPCODE_SGE, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_equal:
+ ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_nequal:
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_all_equal:
+ /* "==" operator producing a scalar boolean. */
+ if (ir->operands[0]->type->is_vector() ||
+ ir->operands[1]->type->is_vector()) {
+ ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE,
+ ir_to_mesa_dst_reg_from_src(temp), op[0], op[1]);
+ ir_to_mesa_emit_dp(ir, result_dst, temp, temp, vector_elements);
+ ir_to_mesa_emit_op2(ir, OPCODE_SEQ,
+ result_dst, result_src, src_reg_for_float(0.0));
+ } else {
+ ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
+ }
+ break;
+ case ir_binop_any_nequal:
+ /* "!=" operator producing a scalar boolean. */
+ if (ir->operands[0]->type->is_vector() ||
+ ir->operands[1]->type->is_vector()) {
+ ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE,
+ ir_to_mesa_dst_reg_from_src(temp), op[0], op[1]);
+ ir_to_mesa_emit_dp(ir, result_dst, temp, temp, vector_elements);
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE,
+ result_dst, result_src, src_reg_for_float(0.0));
+ } else {
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
+ }
+ break;
+
+ case ir_unop_any:
+ assert(ir->operands[0]->type->is_vector());
+ ir_to_mesa_emit_dp(ir, result_dst, op[0], op[0],
+ ir->operands[0]->type->vector_elements);
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE,
+ result_dst, result_src, src_reg_for_float(0.0));
+ break;
+
+ case ir_binop_logic_xor:
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
+ break;
+
+ case ir_binop_logic_or:
+ /* This could be a saturated add and skip the SNE. */
+ ir_to_mesa_emit_op2(ir, OPCODE_ADD,
+ result_dst,
+ op[0], op[1]);
+
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE,
+ result_dst,
+ result_src, src_reg_for_float(0.0));
+ break;
+
+ case ir_binop_logic_and:
+ /* the bool args are stored as float 0.0 or 1.0, so "mul" gives us "and". */
+ ir_to_mesa_emit_op2(ir, OPCODE_MUL,
+ result_dst,
+ op[0], op[1]);
+ break;
+
+ case ir_binop_dot:
+ assert(ir->operands[0]->type->is_vector());
+ assert(ir->operands[0]->type == ir->operands[1]->type);
+ ir_to_mesa_emit_dp(ir, result_dst, op[0], op[1],
+ ir->operands[0]->type->vector_elements);
+ break;
+
+ case ir_unop_sqrt:
+ /* sqrt(x) = x * rsq(x). */
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
+ ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, result_src, op[0]);
+ /* For incoming channels <= 0, set the result to 0. */
+ op[0].negate = ~op[0].negate;
+ ir_to_mesa_emit_op3(ir, OPCODE_CMP, result_dst,
+ op[0], result_src, src_reg_for_float(0.0));
+ break;
+ case ir_unop_rsq:
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
+ break;
+ case ir_unop_i2f:
+ case ir_unop_b2f:
+ case ir_unop_b2i:
+ /* Mesa IR lacks types, ints are stored as truncated floats. */
+ result_src = op[0];
+ break;
+ case ir_unop_f2i:
+ ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]);
+ break;
+ case ir_unop_f2b:
+ case ir_unop_i2b:
+ ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst,
+ op[0], src_reg_for_float(0.0));
+ break;
+ case ir_unop_trunc:
+ ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]);
+ break;
+ case ir_unop_ceil:
+ op[0].negate = ~op[0].negate;
+ ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]);
+ result_src.negate = ~result_src.negate;
+ break;
+ case ir_unop_floor:
+ ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]);
+ break;
+ case ir_unop_fract:
+ ir_to_mesa_emit_op1(ir, OPCODE_FRC, result_dst, op[0]);
+ break;
+
+ case ir_binop_min:
+ ir_to_mesa_emit_op2(ir, OPCODE_MIN, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_max:
+ ir_to_mesa_emit_op2(ir, OPCODE_MAX, result_dst, op[0], op[1]);
+ break;
+ case ir_binop_pow:
+ ir_to_mesa_emit_scalar_op2(ir, OPCODE_POW, result_dst, op[0], op[1]);
+ break;
+
+ case ir_unop_bit_not:
+ case ir_unop_u2f:
+ case ir_binop_lshift:
+ case ir_binop_rshift:
+ case ir_binop_bit_and:
+ case ir_binop_bit_xor:
+ case ir_binop_bit_or:
+ case ir_unop_round_even:
+ assert(!"GLSL 1.30 features unsupported");
+ break;
+
+ case ir_quadop_vector:
+ /* This operation should have already been handled.
+ */
+ assert(!"Should not get here.");
+ break;
+ }
+
+ this->result = result_src;
+}
+
+
+void
+ir_to_mesa_visitor::visit(ir_swizzle *ir)
+{
+ ir_to_mesa_src_reg src_reg;
+ int i;
+ int swizzle[4];
+
+ /* Note that this is only swizzles in expressions, not those on the left
+ * hand side of an assignment, which do write masking. See ir_assignment
+ * for that.
+ */
+
+ ir->val->accept(this);
+ src_reg = this->result;
+ assert(src_reg.file != PROGRAM_UNDEFINED);
+
+ for (i = 0; i < 4; i++) {
+ if (i < ir->type->vector_elements) {
+ switch (i) {
+ case 0:
+ swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.x);
+ break;
+ case 1:
+ swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.y);
+ break;
+ case 2:
+ swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.z);
+ break;
+ case 3:
+ swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.w);
+ break;
+ }
+ } else {
+ /* If the type is smaller than a vec4, replicate the last
+ * channel out.
+ */
+ swizzle[i] = swizzle[ir->type->vector_elements - 1];
+ }
+ }
+
+ src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0],
+ swizzle[1],
+ swizzle[2],
+ swizzle[3]);
+
+ this->result = src_reg;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_dereference_variable *ir)
+{
+ variable_storage *entry = find_variable_storage(ir->var);
+ ir_variable *var = ir->var;
+
+ if (!entry) {
+ switch (var->mode) {
+ case ir_var_uniform:
+ entry = new(mem_ctx) variable_storage(var, PROGRAM_UNIFORM,
+ var->location);
+ this->variables.push_tail(entry);
+ break;
+ case ir_var_in:
+ case ir_var_inout:
+ /* The linker assigns locations for varyings and attributes,
+ * including deprecated builtins (like gl_Color), user-assign
+ * generic attributes (glBindVertexLocation), and
+ * user-defined varyings.
+ *
+ * FINISHME: We would hit this path for function arguments. Fix!
+ */
+ assert(var->location != -1);
+ entry = new(mem_ctx) variable_storage(var,
+ PROGRAM_INPUT,
+ var->location);
+ if (this->prog->Target == GL_VERTEX_PROGRAM_ARB &&
+ var->location >= VERT_ATTRIB_GENERIC0) {
+ _mesa_add_attribute(this->prog->Attributes,
+ var->name,
+ _mesa_sizeof_glsl_type(var->type->gl_type),
+ var->type->gl_type,
+ var->location - VERT_ATTRIB_GENERIC0);
+ }
+ break;
+ case ir_var_out:
+ assert(var->location != -1);
+ entry = new(mem_ctx) variable_storage(var,
+ PROGRAM_OUTPUT,
+ var->location);
+ break;
+ case ir_var_system_value:
+ entry = new(mem_ctx) variable_storage(var,
+ PROGRAM_SYSTEM_VALUE,
+ var->location);
+ break;
+ case ir_var_auto:
+ case ir_var_temporary:
+ entry = new(mem_ctx) variable_storage(var, PROGRAM_TEMPORARY,
+ this->next_temp);
+ this->variables.push_tail(entry);
+
+ next_temp += type_size(var->type);
+ break;
+ }
+
+ if (!entry) {
+ printf("Failed to make storage for %s\n", var->name);
+ exit(1);
+ }
+ }
+
+ this->result = ir_to_mesa_src_reg(entry->file, entry->index, var->type);
+}
+
+void
+ir_to_mesa_visitor::visit(ir_dereference_array *ir)
+{
+ ir_constant *index;
+ ir_to_mesa_src_reg src_reg;
+ int element_size = type_size(ir->type);
+
+ index = ir->array_index->constant_expression_value();
+
+ ir->array->accept(this);
+ src_reg = this->result;
+
+ if (index) {
+ src_reg.index += index->value.i[0] * element_size;
+ } else {
+ ir_to_mesa_src_reg array_base = this->result;
+ /* Variable index array dereference. It eats the "vec4" of the
+ * base of the array and an index that offsets the Mesa register
+ * index.
+ */
+ ir->array_index->accept(this);
+
+ ir_to_mesa_src_reg index_reg;
+
+ if (element_size == 1) {
+ index_reg = this->result;
+ } else {
+ index_reg = get_temp(glsl_type::float_type);
+
+ ir_to_mesa_emit_op2(ir, OPCODE_MUL,
+ ir_to_mesa_dst_reg_from_src(index_reg),
+ this->result, src_reg_for_float(element_size));
+ }
+
+ src_reg.reladdr = ralloc(mem_ctx, ir_to_mesa_src_reg);
+ memcpy(src_reg.reladdr, &index_reg, sizeof(index_reg));
+ }
+
+ /* If the type is smaller than a vec4, replicate the last channel out. */
+ if (ir->type->is_scalar() || ir->type->is_vector())
+ src_reg.swizzle = swizzle_for_size(ir->type->vector_elements);
+ else
+ src_reg.swizzle = SWIZZLE_NOOP;
+
+ this->result = src_reg;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_dereference_record *ir)
+{
+ unsigned int i;
+ const glsl_type *struct_type = ir->record->type;
+ int offset = 0;
+
+ ir->record->accept(this);
+
+ for (i = 0; i < struct_type->length; i++) {
+ if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0)
+ break;
+ offset += type_size(struct_type->fields.structure[i].type);
+ }
+
+ /* If the type is smaller than a vec4, replicate the last channel out. */
+ if (ir->type->is_scalar() || ir->type->is_vector())
+ this->result.swizzle = swizzle_for_size(ir->type->vector_elements);
+ else
+ this->result.swizzle = SWIZZLE_NOOP;
+
+ this->result.index += offset;
+}
+
+/**
+ * We want to be careful in assignment setup to hit the actual storage
+ * instead of potentially using a temporary like we might with the
+ * ir_dereference handler.
+ */
+static struct ir_to_mesa_dst_reg
+get_assignment_lhs(ir_dereference *ir, ir_to_mesa_visitor *v)
+{
+ /* The LHS must be a dereference. If the LHS is a variable indexed array
+ * access of a vector, it must be separated into a series conditional moves
+ * before reaching this point (see ir_vec_index_to_cond_assign).
+ */
+ assert(ir->as_dereference());
+ ir_dereference_array *deref_array = ir->as_dereference_array();
+ if (deref_array) {
+ assert(!deref_array->array->type->is_vector());
+ }
+
+ /* Use the rvalue deref handler for the most part. We'll ignore
+ * swizzles in it and write swizzles using writemask, though.
+ */
+ ir->accept(v);
+ return ir_to_mesa_dst_reg_from_src(v->result);
+}
+
+/**
+ * Process the condition of a conditional assignment
+ *
+ * Examines the condition of a conditional assignment to generate the optimal
+ * first operand of a \c CMP instruction. If the condition is a relational
+ * operator with 0 (e.g., \c ir_binop_less), the value being compared will be
+ * used as the source for the \c CMP instruction. Otherwise the comparison
+ * is processed to a boolean result, and the boolean result is used as the
+ * operand to the CMP instruction.
+ */
+bool
+ir_to_mesa_visitor::process_move_condition(ir_rvalue *ir)
+{
+ ir_rvalue *src_ir = ir;
+ bool negate = true;
+ bool switch_order = false;
+
+ ir_expression *const expr = ir->as_expression();
+ if ((expr != NULL) && (expr->get_num_operands() == 2)) {
+ bool zero_on_left = false;
+
+ if (expr->operands[0]->is_zero()) {
+ src_ir = expr->operands[1];
+ zero_on_left = true;
+ } else if (expr->operands[1]->is_zero()) {
+ src_ir = expr->operands[0];
+ zero_on_left = false;
+ }
+
+ /* a is - 0 + - 0 +
+ * (a < 0) T F F ( a < 0) T F F
+ * (0 < a) F F T (-a < 0) F F T
+ * (a <= 0) T T F (-a < 0) F F T (swap order of other operands)
+ * (0 <= a) F T T ( a < 0) T F F (swap order of other operands)
+ * (a > 0) F F T (-a < 0) F F T
+ * (0 > a) T F F ( a < 0) T F F
+ * (a >= 0) F T T ( a < 0) T F F (swap order of other operands)
+ * (0 >= a) T T F (-a < 0) F F T (swap order of other operands)
+ *
+ * Note that exchanging the order of 0 and 'a' in the comparison simply
+ * means that the value of 'a' should be negated.
+ */
+ if (src_ir != ir) {
+ switch (expr->operation) {
+ case ir_binop_less:
+ switch_order = false;
+ negate = zero_on_left;
+ break;
+
+ case ir_binop_greater:
+ switch_order = false;
+ negate = !zero_on_left;
+ break;
+
+ case ir_binop_lequal:
+ switch_order = true;
+ negate = !zero_on_left;
+ break;
+
+ case ir_binop_gequal:
+ switch_order = true;
+ negate = zero_on_left;
+ break;
+
+ default:
+ /* This isn't the right kind of comparison afterall, so make sure
+ * the whole condition is visited.
+ */
+ src_ir = ir;
+ break;
+ }
+ }
+ }
+
+ src_ir->accept(this);
+
+ /* We use the OPCODE_CMP (a < 0 ? b : c) for conditional moves, and the
+ * condition we produced is 0.0 or 1.0. By flipping the sign, we can
+ * choose which value OPCODE_CMP produces without an extra instruction
+ * computing the condition.
+ */
+ if (negate)
+ this->result.negate = ~this->result.negate;
+
+ return switch_order;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_assignment *ir)
+{
+ struct ir_to_mesa_dst_reg l;
+ struct ir_to_mesa_src_reg r;
+ int i;
+
+ ir->rhs->accept(this);
+ r = this->result;
+
+ l = get_assignment_lhs(ir->lhs, this);
+
+ /* FINISHME: This should really set to the correct maximal writemask for each
+ * FINISHME: component written (in the loops below). This case can only
+ * FINISHME: occur for matrices, arrays, and structures.
+ */
+ if (ir->write_mask == 0) {
+ assert(!ir->lhs->type->is_scalar() && !ir->lhs->type->is_vector());
+ l.writemask = WRITEMASK_XYZW;
+ } else if (ir->lhs->type->is_scalar()) {
+ /* FINISHME: This hack makes writing to gl_FragDepth, which lives in the
+ * FINISHME: W component of fragment shader output zero, work correctly.
+ */
+ l.writemask = WRITEMASK_XYZW;
+ } else {
+ int swizzles[4];
+ int first_enabled_chan = 0;
+ int rhs_chan = 0;
+
+ assert(ir->lhs->type->is_vector());
+ l.writemask = ir->write_mask;
+
+ for (int i = 0; i < 4; i++) {
+ if (l.writemask & (1 << i)) {
+ first_enabled_chan = GET_SWZ(r.swizzle, i);
+ break;
+ }
+ }
+
+ /* Swizzle a small RHS vector into the channels being written.
+ *
+ * glsl ir treats write_mask as dictating how many channels are
+ * present on the RHS while Mesa IR treats write_mask as just
+ * showing which channels of the vec4 RHS get written.
+ */
+ for (int i = 0; i < 4; i++) {
+ if (l.writemask & (1 << i))
+ swizzles[i] = GET_SWZ(r.swizzle, rhs_chan++);
+ else
+ swizzles[i] = first_enabled_chan;
+ }
+ r.swizzle = MAKE_SWIZZLE4(swizzles[0], swizzles[1],
+ swizzles[2], swizzles[3]);
+ }
+
+ assert(l.file != PROGRAM_UNDEFINED);
+ assert(r.file != PROGRAM_UNDEFINED);
+
+ if (ir->condition) {
+ const bool switch_order = this->process_move_condition(ir->condition);
+ ir_to_mesa_src_reg condition = this->result;
+
+ for (i = 0; i < type_size(ir->lhs->type); i++) {
+ if (switch_order) {
+ ir_to_mesa_emit_op3(ir, OPCODE_CMP, l,
+ condition, ir_to_mesa_src_reg_from_dst(l), r);
+ } else {
+ ir_to_mesa_emit_op3(ir, OPCODE_CMP, l,
+ condition, r, ir_to_mesa_src_reg_from_dst(l));
+ }
+
+ l.index++;
+ r.index++;
+ }
+ } else {
+ for (i = 0; i < type_size(ir->lhs->type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
+ }
+}
+
+
+void
+ir_to_mesa_visitor::visit(ir_constant *ir)
+{
+ ir_to_mesa_src_reg src_reg;
+ GLfloat stack_vals[4] = { 0 };
+ GLfloat *values = stack_vals;
+ unsigned int i;
+
+ /* Unfortunately, 4 floats is all we can get into
+ * _mesa_add_unnamed_constant. So, make a temp to store an
+ * aggregate constant and move each constant value into it. If we
+ * get lucky, copy propagation will eliminate the extra moves.
+ */
+
+ if (ir->type->base_type == GLSL_TYPE_STRUCT) {
+ ir_to_mesa_src_reg temp_base = get_temp(ir->type);
+ ir_to_mesa_dst_reg temp = ir_to_mesa_dst_reg_from_src(temp_base);
+
+ foreach_iter(exec_list_iterator, iter, ir->components) {
+ ir_constant *field_value = (ir_constant *)iter.get();
+ int size = type_size(field_value->type);
+
+ assert(size > 0);
+
+ field_value->accept(this);
+ src_reg = this->result;
+
+ for (i = 0; i < (unsigned int)size; i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, temp, src_reg);
+
+ src_reg.index++;
+ temp.index++;
+ }
+ }
+ this->result = temp_base;
+ return;
+ }
+
+ if (ir->type->is_array()) {
+ ir_to_mesa_src_reg temp_base = get_temp(ir->type);
+ ir_to_mesa_dst_reg temp = ir_to_mesa_dst_reg_from_src(temp_base);
+ int size = type_size(ir->type->fields.array);
+
+ assert(size > 0);
+
+ for (i = 0; i < ir->type->length; i++) {
+ ir->array_elements[i]->accept(this);
+ src_reg = this->result;
+ for (int j = 0; j < size; j++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, temp, src_reg);
+
+ src_reg.index++;
+ temp.index++;
+ }
+ }
+ this->result = temp_base;
+ return;
+ }
+
+ if (ir->type->is_matrix()) {
+ ir_to_mesa_src_reg mat = get_temp(ir->type);
+ ir_to_mesa_dst_reg mat_column = ir_to_mesa_dst_reg_from_src(mat);
+
+ for (i = 0; i < ir->type->matrix_columns; i++) {
+ assert(ir->type->base_type == GLSL_TYPE_FLOAT);
+ values = &ir->value.f[i * ir->type->vector_elements];
+
+ src_reg = ir_to_mesa_src_reg(PROGRAM_CONSTANT, -1, NULL);
+ src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
+ values,
+ ir->type->vector_elements,
+ &src_reg.swizzle);
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, mat_column, src_reg);
+
+ mat_column.index++;
+ }
+
+ this->result = mat;
+ return;
+ }
+
+ src_reg.file = PROGRAM_CONSTANT;
+ switch (ir->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ values = &ir->value.f[0];
+ break;
+ case GLSL_TYPE_UINT:
+ for (i = 0; i < ir->type->vector_elements; i++) {
+ values[i] = ir->value.u[i];
+ }
+ break;
+ case GLSL_TYPE_INT:
+ for (i = 0; i < ir->type->vector_elements; i++) {
+ values[i] = ir->value.i[i];
+ }
+ break;
+ case GLSL_TYPE_BOOL:
+ for (i = 0; i < ir->type->vector_elements; i++) {
+ values[i] = ir->value.b[i];
+ }
+ break;
+ default:
+ assert(!"Non-float/uint/int/bool constant");
+ }
+
+ this->result = ir_to_mesa_src_reg(PROGRAM_CONSTANT, -1, ir->type);
+ this->result.index = _mesa_add_unnamed_constant(this->prog->Parameters,
+ values,
+ ir->type->vector_elements,
+ &this->result.swizzle);
+}
+
+function_entry *
+ir_to_mesa_visitor::get_function_signature(ir_function_signature *sig)
+{
+ function_entry *entry;
+
+ foreach_iter(exec_list_iterator, iter, this->function_signatures) {
+ entry = (function_entry *)iter.get();
+
+ if (entry->sig == sig)
+ return entry;
+ }
+
+ entry = ralloc(mem_ctx, function_entry);
+ entry->sig = sig;
+ entry->sig_id = this->next_signature_id++;
+ entry->bgn_inst = NULL;
+
+ /* Allocate storage for all the parameters. */
+ foreach_iter(exec_list_iterator, iter, sig->parameters) {
+ ir_variable *param = (ir_variable *)iter.get();
+ variable_storage *storage;
+
+ storage = find_variable_storage(param);
+ assert(!storage);
+
+ storage = new(mem_ctx) variable_storage(param, PROGRAM_TEMPORARY,
+ this->next_temp);
+ this->variables.push_tail(storage);
+
+ this->next_temp += type_size(param->type);
+ }
+
+ if (!sig->return_type->is_void()) {
+ entry->return_reg = get_temp(sig->return_type);
+ } else {
+ entry->return_reg = ir_to_mesa_undef;
+ }
+
+ this->function_signatures.push_tail(entry);
+ return entry;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_call *ir)
+{
+ ir_to_mesa_instruction *call_inst;
+ ir_function_signature *sig = ir->get_callee();
+ function_entry *entry = get_function_signature(sig);
+ int i;
+
+ /* Process in parameters. */
+ exec_list_iterator sig_iter = sig->parameters.iterator();
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_rvalue *param_rval = (ir_rvalue *)iter.get();
+ ir_variable *param = (ir_variable *)sig_iter.get();
+
+ if (param->mode == ir_var_in ||
+ param->mode == ir_var_inout) {
+ variable_storage *storage = find_variable_storage(param);
+ assert(storage);
+
+ param_rval->accept(this);
+ ir_to_mesa_src_reg r = this->result;
+
+ ir_to_mesa_dst_reg l;
+ l.file = storage->file;
+ l.index = storage->index;
+ l.reladdr = NULL;
+ l.writemask = WRITEMASK_XYZW;
+ l.cond_mask = COND_TR;
+
+ for (i = 0; i < type_size(param->type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
+ }
+
+ sig_iter.next();
+ }
+ assert(!sig_iter.has_next());
+
+ /* Emit call instruction */
+ call_inst = ir_to_mesa_emit_op1(ir, OPCODE_CAL,
+ ir_to_mesa_undef_dst, ir_to_mesa_undef);
+ call_inst->function = entry;
+
+ /* Process out parameters. */
+ sig_iter = sig->parameters.iterator();
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_rvalue *param_rval = (ir_rvalue *)iter.get();
+ ir_variable *param = (ir_variable *)sig_iter.get();
+
+ if (param->mode == ir_var_out ||
+ param->mode == ir_var_inout) {
+ variable_storage *storage = find_variable_storage(param);
+ assert(storage);
+
+ ir_to_mesa_src_reg r;
+ r.file = storage->file;
+ r.index = storage->index;
+ r.reladdr = NULL;
+ r.swizzle = SWIZZLE_NOOP;
+ r.negate = 0;
+
+ param_rval->accept(this);
+ ir_to_mesa_dst_reg l = ir_to_mesa_dst_reg_from_src(this->result);
+
+ for (i = 0; i < type_size(param->type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
+ }
+
+ sig_iter.next();
+ }
+ assert(!sig_iter.has_next());
+
+ /* Process return value. */
+ this->result = entry->return_reg;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_texture *ir)
+{
+ ir_to_mesa_src_reg result_src, coord, lod_info, projector;
+ ir_to_mesa_dst_reg result_dst, coord_dst;
+ ir_to_mesa_instruction *inst = NULL;
+ prog_opcode opcode = OPCODE_NOP;
+
+ ir->coordinate->accept(this);
+
+ /* Put our coords in a temp. We'll need to modify them for shadow,
+ * projection, or LOD, so the only case we'd use it as is is if
+ * we're doing plain old texturing. Mesa IR optimization should
+ * handle cleaning up our mess in that case.
+ */
+ coord = get_temp(glsl_type::vec4_type);
+ coord_dst = ir_to_mesa_dst_reg_from_src(coord);
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst,
+ this->result);
+
+ if (ir->projector) {
+ ir->projector->accept(this);
+ projector = this->result;
+ }
+
+ /* Storage for our result. Ideally for an assignment we'd be using
+ * the actual storage for the result here, instead.
+ */
+ result_src = get_temp(glsl_type::vec4_type);
+ result_dst = ir_to_mesa_dst_reg_from_src(result_src);
+
+ switch (ir->op) {
+ case ir_tex:
+ opcode = OPCODE_TEX;
+ break;
+ case ir_txb:
+ opcode = OPCODE_TXB;
+ ir->lod_info.bias->accept(this);
+ lod_info = this->result;
+ break;
+ case ir_txl:
+ opcode = OPCODE_TXL;
+ ir->lod_info.lod->accept(this);
+ lod_info = this->result;
+ break;
+ case ir_txd:
+ case ir_txf:
+ assert(!"GLSL 1.30 features unsupported");
+ break;
+ }
+
+ if (ir->projector) {
+ if (opcode == OPCODE_TEX) {
+ /* Slot the projector in as the last component of the coord. */
+ coord_dst.writemask = WRITEMASK_W;
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, projector);
+ coord_dst.writemask = WRITEMASK_XYZW;
+ opcode = OPCODE_TXP;
+ } else {
+ ir_to_mesa_src_reg coord_w = coord;
+ coord_w.swizzle = SWIZZLE_WWWW;
+
+ /* For the other TEX opcodes there's no projective version
+ * since the last slot is taken up by lod info. Do the
+ * projective divide now.
+ */
+ coord_dst.writemask = WRITEMASK_W;
+ ir_to_mesa_emit_op1(ir, OPCODE_RCP, coord_dst, projector);
+
+ coord_dst.writemask = WRITEMASK_XYZ;
+ ir_to_mesa_emit_op2(ir, OPCODE_MUL, coord_dst, coord, coord_w);
+
+ coord_dst.writemask = WRITEMASK_XYZW;
+ coord.swizzle = SWIZZLE_XYZW;
+ }
+ }
+
+ if (ir->shadow_comparitor) {
+ /* Slot the shadow value in as the second to last component of the
+ * coord.
+ */
+ ir->shadow_comparitor->accept(this);
+ coord_dst.writemask = WRITEMASK_Z;
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, this->result);
+ coord_dst.writemask = WRITEMASK_XYZW;
+ }
+
+ if (opcode == OPCODE_TXL || opcode == OPCODE_TXB) {
+ /* Mesa IR stores lod or lod bias in the last channel of the coords. */
+ coord_dst.writemask = WRITEMASK_W;
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, lod_info);
+ coord_dst.writemask = WRITEMASK_XYZW;
+ }
+
+ inst = ir_to_mesa_emit_op1(ir, opcode, result_dst, coord);
+
+ if (ir->shadow_comparitor)
+ inst->tex_shadow = GL_TRUE;
+
+ inst->sampler = _mesa_get_sampler_uniform_value(ir->sampler,
+ this->shader_program,
+ this->prog);
+
+ const glsl_type *sampler_type = ir->sampler->type;
+
+ switch (sampler_type->sampler_dimensionality) {
+ case GLSL_SAMPLER_DIM_1D:
+ inst->tex_target = (sampler_type->sampler_array)
+ ? TEXTURE_1D_ARRAY_INDEX : TEXTURE_1D_INDEX;
+ break;
+ case GLSL_SAMPLER_DIM_2D:
+ inst->tex_target = (sampler_type->sampler_array)
+ ? TEXTURE_2D_ARRAY_INDEX : TEXTURE_2D_INDEX;
+ break;
+ case GLSL_SAMPLER_DIM_3D:
+ inst->tex_target = TEXTURE_3D_INDEX;
+ break;
+ case GLSL_SAMPLER_DIM_CUBE:
+ inst->tex_target = TEXTURE_CUBE_INDEX;
+ break;
+ case GLSL_SAMPLER_DIM_RECT:
+ inst->tex_target = TEXTURE_RECT_INDEX;
+ break;
+ case GLSL_SAMPLER_DIM_BUF:
+ assert(!"FINISHME: Implement ARB_texture_buffer_object");
+ break;
+ default:
+ assert(!"Should not get here.");
+ }
+
+ this->result = result_src;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_return *ir)
+{
+ if (ir->get_value()) {
+ ir_to_mesa_dst_reg l;
+ int i;
+
+ assert(current_function);
+
+ ir->get_value()->accept(this);
+ ir_to_mesa_src_reg r = this->result;
+
+ l = ir_to_mesa_dst_reg_from_src(current_function->return_reg);
+
+ for (i = 0; i < type_size(current_function->sig->return_type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
+ }
+
+ ir_to_mesa_emit_op0(ir, OPCODE_RET);
+}
+
+void
+ir_to_mesa_visitor::visit(ir_discard *ir)
+{
+ struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog;
+
+ if (ir->condition) {
+ ir->condition->accept(this);
+ this->result.negate = ~this->result.negate;
+ ir_to_mesa_emit_op1(ir, OPCODE_KIL, ir_to_mesa_undef_dst, this->result);
+ } else {
+ ir_to_mesa_emit_op0(ir, OPCODE_KIL_NV);
+ }
+
+ fp->UsesKill = GL_TRUE;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_if *ir)
+{
+ ir_to_mesa_instruction *cond_inst, *if_inst, *else_inst = NULL;
+ ir_to_mesa_instruction *prev_inst;
+
+ prev_inst = (ir_to_mesa_instruction *)this->instructions.get_tail();
+
+ ir->condition->accept(this);
+ assert(this->result.file != PROGRAM_UNDEFINED);
+
+ if (this->options->EmitCondCodes) {
+ cond_inst = (ir_to_mesa_instruction *)this->instructions.get_tail();
+
+ /* See if we actually generated any instruction for generating
+ * the condition. If not, then cook up a move to a temp so we
+ * have something to set cond_update on.
+ */
+ if (cond_inst == prev_inst) {
+ ir_to_mesa_src_reg temp = get_temp(glsl_type::bool_type);
+ cond_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_MOV,
+ ir_to_mesa_dst_reg_from_src(temp),
+ result);
+ }
+ cond_inst->cond_update = GL_TRUE;
+
+ if_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_IF);
+ if_inst->dst_reg.cond_mask = COND_NE;
+ } else {
+ if_inst = ir_to_mesa_emit_op1(ir->condition,
+ OPCODE_IF, ir_to_mesa_undef_dst,
+ this->result);
+ }
+
+ this->instructions.push_tail(if_inst);
+
+ visit_exec_list(&ir->then_instructions, this);
+
+ if (!ir->else_instructions.is_empty()) {
+ else_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_ELSE);
+ visit_exec_list(&ir->else_instructions, this);
+ }
+
+ if_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ENDIF,
+ ir_to_mesa_undef_dst, ir_to_mesa_undef);
+}
+
+ir_to_mesa_visitor::ir_to_mesa_visitor()
+{
+ result.file = PROGRAM_UNDEFINED;
+ next_temp = 1;
+ next_signature_id = 1;
+ current_function = NULL;
+ mem_ctx = ralloc_context(NULL);
+}
+
+ir_to_mesa_visitor::~ir_to_mesa_visitor()
+{
+ ralloc_free(mem_ctx);
+}
+
+static struct prog_src_register
+mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg)
+{
+ struct prog_src_register mesa_reg;
+
+ mesa_reg.File = reg.file;
+ assert(reg.index < (1 << INST_INDEX_BITS));
+ mesa_reg.Index = reg.index;
+ mesa_reg.Swizzle = reg.swizzle;
+ mesa_reg.RelAddr = reg.reladdr != NULL;
+ mesa_reg.Negate = reg.negate;
+ mesa_reg.Abs = 0;
+ mesa_reg.HasIndex2 = GL_FALSE;
+ mesa_reg.RelAddr2 = 0;
+ mesa_reg.Index2 = 0;
+
+ return mesa_reg;
+}
+
+static void
+set_branchtargets(ir_to_mesa_visitor *v,
+ struct prog_instruction *mesa_instructions,
+ int num_instructions)
+{
+ int if_count = 0, loop_count = 0;
+ int *if_stack, *loop_stack;
+ int if_stack_pos = 0, loop_stack_pos = 0;
+ int i, j;
+
+ for (i = 0; i < num_instructions; i++) {
+ switch (mesa_instructions[i].Opcode) {
+ case OPCODE_IF:
+ if_count++;
+ break;
+ case OPCODE_BGNLOOP:
+ loop_count++;
+ break;
+ case OPCODE_BRK:
+ case OPCODE_CONT:
+ mesa_instructions[i].BranchTarget = -1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if_stack = rzalloc_array(v->mem_ctx, int, if_count);
+ loop_stack = rzalloc_array(v->mem_ctx, int, loop_count);
+
+ for (i = 0; i < num_instructions; i++) {
+ switch (mesa_instructions[i].Opcode) {
+ case OPCODE_IF:
+ if_stack[if_stack_pos] = i;
+ if_stack_pos++;
+ break;
+ case OPCODE_ELSE:
+ mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
+ if_stack[if_stack_pos - 1] = i;
+ break;
+ case OPCODE_ENDIF:
+ mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
+ if_stack_pos--;
+ break;
+ case OPCODE_BGNLOOP:
+ loop_stack[loop_stack_pos] = i;
+ loop_stack_pos++;
+ break;
+ case OPCODE_ENDLOOP:
+ loop_stack_pos--;
+ /* Rewrite any breaks/conts at this nesting level (haven't
+ * already had a BranchTarget assigned) to point to the end
+ * of the loop.
+ */
+ for (j = loop_stack[loop_stack_pos]; j < i; j++) {
+ if (mesa_instructions[j].Opcode == OPCODE_BRK ||
+ mesa_instructions[j].Opcode == OPCODE_CONT) {
+ if (mesa_instructions[j].BranchTarget == -1) {
+ mesa_instructions[j].BranchTarget = i;
+ }
+ }
+ }
+ /* The loop ends point at each other. */
+ mesa_instructions[i].BranchTarget = loop_stack[loop_stack_pos];
+ mesa_instructions[loop_stack[loop_stack_pos]].BranchTarget = i;
+ break;
+ case OPCODE_CAL:
+ foreach_iter(exec_list_iterator, iter, v->function_signatures) {
+ function_entry *entry = (function_entry *)iter.get();
+
+ if (entry->sig_id == mesa_instructions[i].BranchTarget) {
+ mesa_instructions[i].BranchTarget = entry->inst;
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void
+print_program(struct prog_instruction *mesa_instructions,
+ ir_instruction **mesa_instruction_annotation,
+ int num_instructions)
+{
+ ir_instruction *last_ir = NULL;
+ int i;
+ int indent = 0;
+
+ for (i = 0; i < num_instructions; i++) {
+ struct prog_instruction *mesa_inst = mesa_instructions + i;
+ ir_instruction *ir = mesa_instruction_annotation[i];
+
+ fprintf(stdout, "%3d: ", i);
+
+ if (last_ir != ir && ir) {
+ int j;
+
+ for (j = 0; j < indent; j++) {
+ fprintf(stdout, " ");
+ }
+ ir->print();
+ printf("\n");
+ last_ir = ir;
+
+ fprintf(stdout, " "); /* line number spacing. */
+ }
+
+ indent = _mesa_fprint_instruction_opt(stdout, mesa_inst, indent,
+ PROG_PRINT_DEBUG, NULL);
+ }
+}
+
+static void
+count_resources(struct gl_program *prog)
+{
+ unsigned int i;
+
+ prog->SamplersUsed = 0;
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = &prog->Instructions[i];
+
+ if (_mesa_is_tex_instruction(inst->Opcode)) {
+ prog->SamplerTargets[inst->TexSrcUnit] =
+ (gl_texture_index)inst->TexSrcTarget;
+ prog->SamplersUsed |= 1 << inst->TexSrcUnit;
+ if (inst->TexShadow) {
+ prog->ShadowSamplers |= 1 << inst->TexSrcUnit;
+ }
+ }
+ }
+
+ _mesa_update_shader_textures_used(prog);
+}
+
+struct uniform_sort {
+ struct gl_uniform *u;
+ int pos;
+};
+
+/* The shader_program->Uniforms list is almost sorted in increasing
+ * uniform->{Frag,Vert}Pos locations, but not quite when there are
+ * uniforms shared between targets. We need to add parameters in
+ * increasing order for the targets.
+ */
+static int
+sort_uniforms(const void *a, const void *b)
+{
+ struct uniform_sort *u1 = (struct uniform_sort *)a;
+ struct uniform_sort *u2 = (struct uniform_sort *)b;
+
+ return u1->pos - u2->pos;
+}
+
+/* Add the uniforms to the parameters. The linker chose locations
+ * in our parameters lists (which weren't created yet), which the
+ * uniforms code will use to poke values into our parameters list
+ * when uniforms are updated.
+ */
+static void
+add_uniforms_to_parameters_list(struct gl_shader_program *shader_program,
+ struct gl_shader *shader,
+ struct gl_program *prog)
+{
+ unsigned int i;
+ unsigned int next_sampler = 0, num_uniforms = 0;
+ struct uniform_sort *sorted_uniforms;
+
+ sorted_uniforms = ralloc_array(NULL, struct uniform_sort,
+ shader_program->Uniforms->NumUniforms);
+
+ for (i = 0; i < shader_program->Uniforms->NumUniforms; i++) {
+ struct gl_uniform *uniform = shader_program->Uniforms->Uniforms + i;
+ int parameter_index = -1;
+
+ switch (shader->Type) {
+ case GL_VERTEX_SHADER:
+ parameter_index = uniform->VertPos;
+ break;
+ case GL_FRAGMENT_SHADER:
+ parameter_index = uniform->FragPos;
+ break;
+ case GL_GEOMETRY_SHADER:
+ parameter_index = uniform->GeomPos;
+ break;
+ }
+
+ /* Only add uniforms used in our target. */
+ if (parameter_index != -1) {
+ sorted_uniforms[num_uniforms].pos = parameter_index;
+ sorted_uniforms[num_uniforms].u = uniform;
+ num_uniforms++;
+ }
+ }
+
+ qsort(sorted_uniforms, num_uniforms, sizeof(struct uniform_sort),
+ sort_uniforms);
+
+ for (i = 0; i < num_uniforms; i++) {
+ struct gl_uniform *uniform = sorted_uniforms[i].u;
+ int parameter_index = sorted_uniforms[i].pos;
+ const glsl_type *type = uniform->Type;
+ unsigned int size;
+
+ if (type->is_vector() ||
+ type->is_scalar()) {
+ size = type->vector_elements;
+ } else {
+ size = type_size(type) * 4;
+ }
+
+ gl_register_file file;
+ if (type->is_sampler() ||
+ (type->is_array() && type->fields.array->is_sampler())) {
+ file = PROGRAM_SAMPLER;
+ } else {
+ file = PROGRAM_UNIFORM;
+ }
+
+ GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1,
+ uniform->Name);
+
+ if (index < 0) {
+ index = _mesa_add_parameter(prog->Parameters, file,
+ uniform->Name, size, type->gl_type,
+ NULL, NULL, 0x0);
+
+ /* Sampler uniform values are stored in prog->SamplerUnits,
+ * and the entry in that array is selected by this index we
+ * store in ParameterValues[].
+ */
+ if (file == PROGRAM_SAMPLER) {
+ for (unsigned int j = 0; j < size / 4; j++)
+ prog->Parameters->ParameterValues[index + j][0] = next_sampler++;
+ }
+
+ /* The location chosen in the Parameters list here (returned
+ * from _mesa_add_uniform) has to match what the linker chose.
+ */
+ if (index != parameter_index) {
+ fail_link(shader_program, "Allocation of uniform `%s' to target "
+ "failed (%d vs %d)\n",
+ uniform->Name, index, parameter_index);
+ }
+ }
+ }
+
+ ralloc_free(sorted_uniforms);
+}
+
+static void
+set_uniform_initializer(struct gl_context *ctx, void *mem_ctx,
+ struct gl_shader_program *shader_program,
+ const char *name, const glsl_type *type,
+ ir_constant *val)
+{
+ if (type->is_record()) {
+ ir_constant *field_constant;
+
+ field_constant = (ir_constant *)val->components.get_head();
+
+ for (unsigned int i = 0; i < type->length; i++) {
+ const glsl_type *field_type = type->fields.structure[i].type;
+ const char *field_name = ralloc_asprintf(mem_ctx, "%s.%s", name,
+ type->fields.structure[i].name);
+ set_uniform_initializer(ctx, mem_ctx, shader_program, field_name,
+ field_type, field_constant);
+ field_constant = (ir_constant *)field_constant->next;
+ }
+ return;
+ }
+
+ int loc = _mesa_get_uniform_location(ctx, shader_program, name);
+
+ if (loc == -1) {
+ fail_link(shader_program,
+ "Couldn't find uniform for initializer %s\n", name);
+ return;
+ }
+
+ for (unsigned int i = 0; i < (type->is_array() ? type->length : 1); i++) {
+ ir_constant *element;
+ const glsl_type *element_type;
+ if (type->is_array()) {
+ element = val->array_elements[i];
+ element_type = type->fields.array;
+ } else {
+ element = val;
+ element_type = type;
+ }
+
+ void *values;
+
+ if (element_type->base_type == GLSL_TYPE_BOOL) {
+ int *conv = ralloc_array(mem_ctx, int, element_type->components());
+ for (unsigned int j = 0; j < element_type->components(); j++) {
+ conv[j] = element->value.b[j];
+ }
+ values = (void *)conv;
+ element_type = glsl_type::get_instance(GLSL_TYPE_INT,
+ element_type->vector_elements,
+ 1);
+ } else {
+ values = &element->value;
+ }
+
+ if (element_type->is_matrix()) {
+ _mesa_uniform_matrix(ctx, shader_program,
+ element_type->matrix_columns,
+ element_type->vector_elements,
+ loc, 1, GL_FALSE, (GLfloat *)values);
+ loc += element_type->matrix_columns;
+ } else {
+ _mesa_uniform(ctx, shader_program, loc, element_type->matrix_columns,
+ values, element_type->gl_type);
+ loc += type_size(element_type);
+ }
+ }
+}
+
+static void
+set_uniform_initializers(struct gl_context *ctx,
+ struct gl_shader_program *shader_program)
+{
+ void *mem_ctx = NULL;
+
+ for (unsigned int i = 0; i < MESA_SHADER_TYPES; i++) {
+ struct gl_shader *shader = shader_program->_LinkedShaders[i];
+
+ if (shader == NULL)
+ continue;
+
+ foreach_iter(exec_list_iterator, iter, *shader->ir) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ ir_variable *var = ir->as_variable();
+
+ if (!var || var->mode != ir_var_uniform || !var->constant_value)
+ continue;
+
+ if (!mem_ctx)
+ mem_ctx = ralloc_context(NULL);
+
+ set_uniform_initializer(ctx, mem_ctx, shader_program, var->name,
+ var->type, var->constant_value);
+ }
+ }
+
+ ralloc_free(mem_ctx);
+}
+
+/*
+ * On a basic block basis, tracks available PROGRAM_TEMPORARY register
+ * channels for copy propagation and updates following instructions to
+ * use the original versions.
+ *
+ * The ir_to_mesa_visitor lazily produces code assuming that this pass
+ * will occur. As an example, a TXP production before this pass:
+ *
+ * 0: MOV TEMP[1], INPUT[4].xyyy;
+ * 1: MOV TEMP[1].w, INPUT[4].wwww;
+ * 2: TXP TEMP[2], TEMP[1], texture[0], 2D;
+ *
+ * and after:
+ *
+ * 0: MOV TEMP[1], INPUT[4].xyyy;
+ * 1: MOV TEMP[1].w, INPUT[4].wwww;
+ * 2: TXP TEMP[2], INPUT[4].xyyw, texture[0], 2D;
+ *
+ * which allows for dead code elimination on TEMP[1]'s writes.
+ */
+void
+ir_to_mesa_visitor::copy_propagate(void)
+{
+ ir_to_mesa_instruction **acp = rzalloc_array(mem_ctx,
+ ir_to_mesa_instruction *,
+ this->next_temp * 4);
+
+ foreach_iter(exec_list_iterator, iter, this->instructions) {
+ ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get();
+
+ assert(inst->dst_reg.file != PROGRAM_TEMPORARY
+ || inst->dst_reg.index < this->next_temp);
+
+ /* First, do any copy propagation possible into the src regs. */
+ for (int r = 0; r < 3; r++) {
+ ir_to_mesa_instruction *first = NULL;
+ bool good = true;
+ int acp_base = inst->src_reg[r].index * 4;
+
+ if (inst->src_reg[r].file != PROGRAM_TEMPORARY ||
+ inst->src_reg[r].reladdr)
+ continue;
+
+ /* See if we can find entries in the ACP consisting of MOVs
+ * from the same src register for all the swizzled channels
+ * of this src register reference.
+ */
+ for (int i = 0; i < 4; i++) {
+ int src_chan = GET_SWZ(inst->src_reg[r].swizzle, i);
+ ir_to_mesa_instruction *copy_chan = acp[acp_base + src_chan];
+
+ if (!copy_chan) {
+ good = false;
+ break;
+ }
+
+ if (!first) {
+ first = copy_chan;
+ } else {
+ if (first->src_reg[0].file != copy_chan->src_reg[0].file ||
+ first->src_reg[0].index != copy_chan->src_reg[0].index) {
+ good = false;
+ break;
+ }
+ }
+ }
+
+ if (good) {
+ /* We've now validated that we can copy-propagate to
+ * replace this src register reference. Do it.
+ */
+ inst->src_reg[r].file = first->src_reg[0].file;
+ inst->src_reg[r].index = first->src_reg[0].index;
+
+ int swizzle = 0;
+ for (int i = 0; i < 4; i++) {
+ int src_chan = GET_SWZ(inst->src_reg[r].swizzle, i);
+ ir_to_mesa_instruction *copy_inst = acp[acp_base + src_chan];
+ swizzle |= (GET_SWZ(copy_inst->src_reg[0].swizzle, src_chan) <<
+ (3 * i));
+ }
+ inst->src_reg[r].swizzle = swizzle;
+ }
+ }
+
+ switch (inst->op) {
+ case OPCODE_BGNLOOP:
+ case OPCODE_ENDLOOP:
+ case OPCODE_ELSE:
+ case OPCODE_ENDIF:
+ /* End of a basic block, clear the ACP entirely. */
+ memset(acp, 0, sizeof(*acp) * this->next_temp * 4);
+ break;
+
+ default:
+ /* Continuing the block, clear any written channels from
+ * the ACP.
+ */
+ if (inst->dst_reg.file == PROGRAM_TEMPORARY && inst->dst_reg.reladdr) {
+ /* Any temporary might be written, so no copy propagation
+ * across this instruction.
+ */
+ memset(acp, 0, sizeof(*acp) * this->next_temp * 4);
+ } else if (inst->dst_reg.file == PROGRAM_OUTPUT &&
+ inst->dst_reg.reladdr) {
+ /* Any output might be written, so no copy propagation
+ * from outputs across this instruction.
+ */
+ for (int r = 0; r < this->next_temp; r++) {
+ for (int c = 0; c < 4; c++) {
+ if (acp[4 * r + c]->src_reg[0].file == PROGRAM_OUTPUT)
+ acp[4 * r + c] = NULL;
+ }
+ }
+ } else if (inst->dst_reg.file == PROGRAM_TEMPORARY ||
+ inst->dst_reg.file == PROGRAM_OUTPUT) {
+ /* Clear where it's used as dst. */
+ if (inst->dst_reg.file == PROGRAM_TEMPORARY) {
+ for (int c = 0; c < 4; c++) {
+ if (inst->dst_reg.writemask & (1 << c)) {
+ acp[4 * inst->dst_reg.index + c] = NULL;
+ }
+ }
+ }
+
+ /* Clear where it's used as src. */
+ for (int r = 0; r < this->next_temp; r++) {
+ for (int c = 0; c < 4; c++) {
+ if (!acp[4 * r + c])
+ continue;
+
+ int src_chan = GET_SWZ(acp[4 * r + c]->src_reg[0].swizzle, c);
+
+ if (acp[4 * r + c]->src_reg[0].file == inst->dst_reg.file &&
+ acp[4 * r + c]->src_reg[0].index == inst->dst_reg.index &&
+ inst->dst_reg.writemask & (1 << src_chan))
+ {
+ acp[4 * r + c] = NULL;
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ /* If this is a copy, add it to the ACP. */
+ if (inst->op == OPCODE_MOV &&
+ inst->dst_reg.file == PROGRAM_TEMPORARY &&
+ !inst->dst_reg.reladdr &&
+ !inst->saturate &&
+ !inst->src_reg[0].reladdr &&
+ !inst->src_reg[0].negate) {
+ for (int i = 0; i < 4; i++) {
+ if (inst->dst_reg.writemask & (1 << i)) {
+ acp[4 * inst->dst_reg.index + i] = inst;
+ }
+ }
+ }
+ }
+
+ ralloc_free(acp);
+}
+
+
+/**
+ * Convert a shader's GLSL IR into a Mesa gl_program.
+ */
+static struct gl_program *
+get_mesa_program(struct gl_context *ctx,
+ struct gl_shader_program *shader_program,
+ struct gl_shader *shader)
+{
+ ir_to_mesa_visitor v;
+ struct prog_instruction *mesa_instructions, *mesa_inst;
+ ir_instruction **mesa_instruction_annotation;
+ int i;
+ struct gl_program *prog;
+ GLenum target;
+ const char *target_string;
+ GLboolean progress;
+ struct gl_shader_compiler_options *options =
+ &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(shader->Type)];
+
+ switch (shader->Type) {
+ case GL_VERTEX_SHADER:
+ target = GL_VERTEX_PROGRAM_ARB;
+ target_string = "vertex";
+ break;
+ case GL_FRAGMENT_SHADER:
+ target = GL_FRAGMENT_PROGRAM_ARB;
+ target_string = "fragment";
+ break;
+ case GL_GEOMETRY_SHADER:
+ target = GL_GEOMETRY_PROGRAM_NV;
+ target_string = "geometry";
+ break;
+ default:
+ assert(!"should not be reached");
+ return NULL;
+ }
+
+ validate_ir_tree(shader->ir);
+
+ prog = ctx->Driver.NewProgram(ctx, target, shader_program->Name);
+ if (!prog)
+ return NULL;
+ prog->Parameters = _mesa_new_parameter_list();
+ prog->Varying = _mesa_new_parameter_list();
+ prog->Attributes = _mesa_new_parameter_list();
+ v.ctx = ctx;
+ v.prog = prog;
+ v.shader_program = shader_program;
+ v.options = options;
+
+ add_uniforms_to_parameters_list(shader_program, shader, prog);
+
+ /* Emit Mesa IR for main(). */
+ visit_exec_list(shader->ir, &v);
+ v.ir_to_mesa_emit_op0(NULL, OPCODE_END);
+
+ /* Now emit bodies for any functions that were used. */
+ do {
+ progress = GL_FALSE;
+
+ foreach_iter(exec_list_iterator, iter, v.function_signatures) {
+ function_entry *entry = (function_entry *)iter.get();
+
+ if (!entry->bgn_inst) {
+ v.current_function = entry;
+
+ entry->bgn_inst = v.ir_to_mesa_emit_op0(NULL, OPCODE_BGNSUB);
+ entry->bgn_inst->function = entry;
+
+ visit_exec_list(&entry->sig->body, &v);
+
+ ir_to_mesa_instruction *last;
+ last = (ir_to_mesa_instruction *)v.instructions.get_tail();
+ if (last->op != OPCODE_RET)
+ v.ir_to_mesa_emit_op0(NULL, OPCODE_RET);
+
+ ir_to_mesa_instruction *end;
+ end = v.ir_to_mesa_emit_op0(NULL, OPCODE_ENDSUB);
+ end->function = entry;
+
+ progress = GL_TRUE;
+ }
+ }
+ } while (progress);
+
+ prog->NumTemporaries = v.next_temp;
+
+ int num_instructions = 0;
+ foreach_iter(exec_list_iterator, iter, v.instructions) {
+ num_instructions++;
+ }
+
+ mesa_instructions =
+ (struct prog_instruction *)calloc(num_instructions,
+ sizeof(*mesa_instructions));
+ mesa_instruction_annotation = ralloc_array(v.mem_ctx, ir_instruction *,
+ num_instructions);
+
+ v.copy_propagate();
+
+ /* Convert ir_mesa_instructions into prog_instructions.
+ */
+ mesa_inst = mesa_instructions;
+ i = 0;
+ foreach_iter(exec_list_iterator, iter, v.instructions) {
+ const ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get();
+
+ mesa_inst->Opcode = inst->op;
+ mesa_inst->CondUpdate = inst->cond_update;
+ if (inst->saturate)
+ mesa_inst->SaturateMode = SATURATE_ZERO_ONE;
+ mesa_inst->DstReg.File = inst->dst_reg.file;
+ mesa_inst->DstReg.Index = inst->dst_reg.index;
+ mesa_inst->DstReg.CondMask = inst->dst_reg.cond_mask;
+ mesa_inst->DstReg.WriteMask = inst->dst_reg.writemask;
+ mesa_inst->DstReg.RelAddr = inst->dst_reg.reladdr != NULL;
+ mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]);
+ mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]);
+ mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]);
+ mesa_inst->TexSrcUnit = inst->sampler;
+ mesa_inst->TexSrcTarget = inst->tex_target;
+ mesa_inst->TexShadow = inst->tex_shadow;
+ mesa_instruction_annotation[i] = inst->ir;
+
+ /* Set IndirectRegisterFiles. */
+ if (mesa_inst->DstReg.RelAddr)
+ prog->IndirectRegisterFiles |= 1 << mesa_inst->DstReg.File;
+
+ /* Update program's bitmask of indirectly accessed register files */
+ for (unsigned src = 0; src < 3; src++)
+ if (mesa_inst->SrcReg[src].RelAddr)
+ prog->IndirectRegisterFiles |= 1 << mesa_inst->SrcReg[src].File;
+
+ if (options->EmitNoIfs && mesa_inst->Opcode == OPCODE_IF) {
+ fail_link(shader_program, "Couldn't flatten if statement\n");
+ }
+
+ switch (mesa_inst->Opcode) {
+ case OPCODE_BGNSUB:
+ inst->function->inst = i;
+ mesa_inst->Comment = strdup(inst->function->sig->function_name());
+ break;
+ case OPCODE_ENDSUB:
+ mesa_inst->Comment = strdup(inst->function->sig->function_name());
+ break;
+ case OPCODE_CAL:
+ mesa_inst->BranchTarget = inst->function->sig_id; /* rewritten later */
+ break;
+ case OPCODE_ARL:
+ prog->NumAddressRegs = 1;
+ break;
+ default:
+ break;
+ }
+
+ mesa_inst++;
+ i++;
+
+ if (!shader_program->LinkStatus)
+ break;
+ }
+
+ if (!shader_program->LinkStatus) {
+ free(mesa_instructions);
+ _mesa_reference_program(ctx, &shader->Program, NULL);
+ return NULL;
+ }
+
+ set_branchtargets(&v, mesa_instructions, num_instructions);
+
+ if (ctx->Shader.Flags & GLSL_DUMP) {
+ printf("\n");
+ printf("GLSL IR for linked %s program %d:\n", target_string,
+ shader_program->Name);
+ _mesa_print_ir(shader->ir, NULL);
+ printf("\n");
+ printf("\n");
+ printf("Mesa IR for linked %s program %d:\n", target_string,
+ shader_program->Name);
+ print_program(mesa_instructions, mesa_instruction_annotation,
+ num_instructions);
+ }
+
+ prog->Instructions = mesa_instructions;
+ prog->NumInstructions = num_instructions;
+
+ do_set_program_inouts(shader->ir, prog);
+ count_resources(prog);
+
+ _mesa_reference_program(ctx, &shader->Program, prog);
+
+ if ((ctx->Shader.Flags & GLSL_NO_OPT) == 0) {
+ _mesa_optimize_program(ctx, prog);
+ }
+
+ return prog;
+}
+
+extern "C" {
+
+/**
+ * Called via ctx->Driver.CompilerShader().
+ * This is a no-op.
+ * XXX can we remove the ctx->Driver.CompileShader() hook?
+ */
+GLboolean
+_mesa_ir_compile_shader(struct gl_context *ctx, struct gl_shader *shader)
+{
+ assert(shader->CompileStatus);
+ (void) ctx;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Link a shader.
+ * Called via ctx->Driver.LinkShader()
+ * This actually involves converting GLSL IR into Mesa gl_programs with
+ * code lowering and other optimizations.
+ */
+GLboolean
+_mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
+{
+ assert(prog->LinkStatus);
+
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ if (prog->_LinkedShaders[i] == NULL)
+ continue;
+
+ bool progress;
+ exec_list *ir = prog->_LinkedShaders[i]->ir;
+ const struct gl_shader_compiler_options *options =
+ &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(prog->_LinkedShaders[i]->Type)];
+
+ do {
+ progress = false;
+
+ /* Lowering */
+ do_mat_op_to_vec(ir);
+ lower_instructions(ir, (MOD_TO_FRACT | DIV_TO_MUL_RCP | EXP_TO_EXP2
+ | LOG_TO_LOG2
+ | ((options->EmitNoPow) ? POW_TO_EXP2 : 0)));
+
+ progress = do_lower_jumps(ir, true, true, options->EmitNoMainReturn, options->EmitNoCont, options->EmitNoLoops) || progress;
+
+ progress = do_common_optimization(ir, true, options->MaxUnrollIterations) || progress;
+
+ progress = lower_quadop_vector(ir, true) || progress;
+
+ if (options->EmitNoIfs) {
+ progress = lower_discard(ir) || progress;
+ progress = lower_if_to_cond_assign(ir) || progress;
+ }
+
+ if (options->EmitNoNoise)
+ progress = lower_noise(ir) || progress;
+
+ /* If there are forms of indirect addressing that the driver
+ * cannot handle, perform the lowering pass.
+ */
+ if (options->EmitNoIndirectInput || options->EmitNoIndirectOutput
+ || options->EmitNoIndirectTemp || options->EmitNoIndirectUniform)
+ progress =
+ lower_variable_index_to_cond_assign(ir,
+ options->EmitNoIndirectInput,
+ options->EmitNoIndirectOutput,
+ options->EmitNoIndirectTemp,
+ options->EmitNoIndirectUniform)
+ || progress;
+
+ progress = do_vec_index_to_cond_assign(ir) || progress;
+ } while (progress);
+
+ validate_ir_tree(ir);
+ }
+
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ struct gl_program *linked_prog;
+
+ if (prog->_LinkedShaders[i] == NULL)
+ continue;
+
+ linked_prog = get_mesa_program(ctx, prog, prog->_LinkedShaders[i]);
+
+ if (linked_prog) {
+ bool ok = true;
+
+ switch (prog->_LinkedShaders[i]->Type) {
+ case GL_VERTEX_SHADER:
+ _mesa_reference_vertprog(ctx, &prog->VertexProgram,
+ (struct gl_vertex_program *)linked_prog);
+ ok = ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB,
+ linked_prog);
+ break;
+ case GL_FRAGMENT_SHADER:
+ _mesa_reference_fragprog(ctx, &prog->FragmentProgram,
+ (struct gl_fragment_program *)linked_prog);
+ ok = ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB,
+ linked_prog);
+ break;
+ case GL_GEOMETRY_SHADER:
+ _mesa_reference_geomprog(ctx, &prog->GeometryProgram,
+ (struct gl_geometry_program *)linked_prog);
+ ok = ctx->Driver.ProgramStringNotify(ctx, GL_GEOMETRY_PROGRAM_NV,
+ linked_prog);
+ break;
+ }
+ if (!ok) {
+ return GL_FALSE;
+ }
+ }
+
+ _mesa_reference_program(ctx, &linked_prog, NULL);
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Compile a GLSL shader. Called via glCompileShader().
+ */
+void
+_mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader)
+{
+ struct _mesa_glsl_parse_state *state =
+ new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader);
+
+ const char *source = shader->Source;
+ /* Check if the user called glCompileShader without first calling
+ * glShaderSource. This should fail to compile, but not raise a GL_ERROR.
+ */
+ if (source == NULL) {
+ shader->CompileStatus = GL_FALSE;
+ return;
+ }
+
+ state->error = preprocess(state, &source, &state->info_log,
+ &ctx->Extensions, ctx->API);
+
+ if (ctx->Shader.Flags & GLSL_DUMP) {
+ printf("GLSL source for shader %d:\n", shader->Name);
+ printf("%s\n", shader->Source);
+ }
+
+ if (!state->error) {
+ _mesa_glsl_lexer_ctor(state, source);
+ _mesa_glsl_parse(state);
+ _mesa_glsl_lexer_dtor(state);
+ }
+
+ ralloc_free(shader->ir);
+ shader->ir = new(shader) exec_list;
+ if (!state->error && !state->translation_unit.is_empty())
+ _mesa_ast_to_hir(shader->ir, state);
+
+ if (!state->error && !shader->ir->is_empty()) {
+ validate_ir_tree(shader->ir);
+
+ /* Do some optimization at compile time to reduce shader IR size
+ * and reduce later work if the same shader is linked multiple times
+ */
+ while (do_common_optimization(shader->ir, false, 32))
+ ;
+
+ validate_ir_tree(shader->ir);
+ }
+
+ shader->symbols = state->symbols;
+
+ shader->CompileStatus = !state->error;
+ shader->InfoLog = state->info_log;
+ shader->Version = state->language_version;
+ memcpy(shader->builtins_to_link, state->builtins_to_link,
+ sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link);
+ shader->num_builtins_to_link = state->num_builtins_to_link;
+
+ if (ctx->Shader.Flags & GLSL_LOG) {
+ _mesa_write_shader_to_file(shader);
+ }
+
+ if (ctx->Shader.Flags & GLSL_DUMP) {
+ if (shader->CompileStatus) {
+ printf("GLSL IR for shader %d:\n", shader->Name);
+ _mesa_print_ir(shader->ir, NULL);
+ printf("\n\n");
+ } else {
+ printf("GLSL shader %d failed to compile.\n", shader->Name);
+ }
+ if (shader->InfoLog && shader->InfoLog[0] != 0) {
+ printf("GLSL shader %d info log:\n", shader->Name);
+ printf("%s\n", shader->InfoLog);
+ }
+ }
+
+ /* Retain any live IR, but trash the rest. */
+ reparent_ir(shader->ir, shader->ir);
+
+ ralloc_free(state);
+
+ if (shader->CompileStatus) {
+ if (!ctx->Driver.CompileShader(ctx, shader))
+ shader->CompileStatus = GL_FALSE;
+ }
+}
+
+
+/**
+ * Link a GLSL shader program. Called via glLinkProgram().
+ */
+void
+_mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
+{
+ unsigned int i;
+
+ _mesa_clear_shader_program_data(ctx, prog);
+
+ prog->LinkStatus = GL_TRUE;
+
+ for (i = 0; i < prog->NumShaders; i++) {
+ if (!prog->Shaders[i]->CompileStatus) {
+ fail_link(prog, "linking with uncompiled shader");
+ prog->LinkStatus = GL_FALSE;
+ }
+ }
+
+ prog->Varying = _mesa_new_parameter_list();
+ _mesa_reference_vertprog(ctx, &prog->VertexProgram, NULL);
+ _mesa_reference_fragprog(ctx, &prog->FragmentProgram, NULL);
+ _mesa_reference_geomprog(ctx, &prog->GeometryProgram, NULL);
+
+ if (prog->LinkStatus) {
+ link_shaders(ctx, prog);
+ }
+
+ if (prog->LinkStatus) {
+ if (!ctx->Driver.LinkShader(ctx, prog)) {
+ prog->LinkStatus = GL_FALSE;
+ }
+ }
+
+ set_uniform_initializers(ctx, prog);
+
+ if (ctx->Shader.Flags & GLSL_DUMP) {
+ if (!prog->LinkStatus) {
+ printf("GLSL shader program %d failed to link\n", prog->Name);
+ }
+
+ if (prog->InfoLog && prog->InfoLog[0] != 0) {
+ printf("GLSL shader program %d info log:\n", prog->Name);
+ printf("%s\n", prog->InfoLog);
+ }
+ }
+}
+
+} /* extern "C" */
diff --git a/mesalib/src/mesa/state_tracker/st_context.c b/mesalib/src/mesa/state_tracker/st_context.c
index 593da8fa6..b16d965f8 100644
--- a/mesalib/src/mesa/state_tracker/st_context.c
+++ b/mesalib/src/mesa/state_tracker/st_context.c
@@ -178,7 +178,7 @@ struct st_context *st_create_context(gl_api api, struct pipe_context *pipe,
memset(&funcs, 0, sizeof(funcs));
st_init_driver_functions(&funcs);
- ctx = _mesa_create_context_for_api(api, visual, shareCtx, &funcs, NULL);
+ ctx = _mesa_create_context(api, visual, shareCtx, &funcs, NULL);
/* XXX: need a capability bit in gallium to query if the pipe
* driver prefers DP4 or MUL/MAD for vertex transformation.
diff --git a/mesalib/src/mesa/state_tracker/st_draw_feedback.c b/mesalib/src/mesa/state_tracker/st_draw_feedback.c
index 72ed75e73..b694be04f 100644
--- a/mesalib/src/mesa/state_tracker/st_draw_feedback.c
+++ b/mesalib/src/mesa/state_tracker/st_draw_feedback.c
@@ -261,6 +261,7 @@ st_feedback_draw_vbo(struct gl_context *ctx,
pipe_buffer_unmap(pipe, vb_transfer[i]);
pipe_resource_reference(&draw->pt.vertex_buffer[i].buffer, NULL);
draw_set_mapped_vertex_buffer(draw, i, NULL);
+ pipe_resource_reference(&vbuffers[i].buffer, NULL);
}
}
diff --git a/mesalib/src/mesa/state_tracker/st_program.c b/mesalib/src/mesa/state_tracker/st_program.c
index f70e5005f..e5c26c563 100644
--- a/mesalib/src/mesa/state_tracker/st_program.c
+++ b/mesalib/src/mesa/state_tracker/st_program.c
@@ -108,6 +108,8 @@ delete_fp_variant(struct st_context *st, struct st_fp_variant *fpv)
{
if (fpv->driver_shader)
cso_delete_fragment_shader(st->cso_context, fpv->driver_shader);
+ if (fpv->parameters)
+ _mesa_free_parameter_list(fpv->parameters);
FREE(fpv);
}
@@ -404,6 +406,7 @@ st_translate_fragment_program(struct st_context *st,
{
struct pipe_context *pipe = st->pipe;
struct st_fp_variant *variant = CALLOC_STRUCT(st_fp_variant);
+ GLboolean deleteFP = GL_FALSE;
if (!variant)
return NULL;
@@ -413,17 +416,18 @@ st_translate_fragment_program(struct st_context *st,
#if FEATURE_drawpix
if (key->bitmap) {
/* glBitmap drawing */
- struct gl_fragment_program *fp;
+ struct gl_fragment_program *fp; /* we free this temp program below */
st_make_bitmap_fragment_program(st, &stfp->Base,
&fp, &variant->bitmap_sampler);
variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters);
stfp = st_fragment_program(fp);
+ deleteFP = GL_TRUE;
}
else if (key->drawpixels) {
/* glDrawPixels drawing */
- struct gl_fragment_program *fp;
+ struct gl_fragment_program *fp; /* we free this temp program below */
if (key->drawpixels_z || key->drawpixels_stencil) {
fp = st_make_drawpix_z_stencil_program(st, key->drawpixels_z,
@@ -433,6 +437,7 @@ st_translate_fragment_program(struct st_context *st,
/* RGBA */
st_make_drawpix_fragment_program(st, &stfp->Base, &fp);
variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters);
+ deleteFP = GL_TRUE;
}
stfp = st_fragment_program(fp);
}
@@ -630,6 +635,12 @@ st_translate_fragment_program(struct st_context *st,
debug_printf("\n");
}
+ if (deleteFP) {
+ /* Free the temporary program made above */
+ struct gl_fragment_program *fp = &stfp->Base;
+ _mesa_reference_fragprog(st->ctx, &fp, NULL);
+ }
+
return variant;
}