diff options
Diffstat (limited to 'mesalib/src')
45 files changed, 22731 insertions, 22116 deletions
diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h index 878f48b20..6963b83af 100644 --- a/mesalib/src/glsl/ast.h +++ b/mesalib/src/glsl/ast.h @@ -63,6 +63,10 @@ public: /* If the user *does* call delete, that's OK, we will just * ralloc_free in that case. */ + static void operator delete(void *table, void *ctx) + { + ralloc_free(table); + } static void operator delete(void *table) { ralloc_free(table); diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index bef099cca..27c4301a0 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -1,3463 +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) -{ - 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; -} +/*
+ * 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/getopt.cpp b/mesalib/src/glsl/getopt.cpp new file mode 100644 index 000000000..ea5dd3927 --- /dev/null +++ b/mesalib/src/glsl/getopt.cpp @@ -0,0 +1,552 @@ +/* $OpenBSD: getopt_long.c,v 1.20 2005/10/25 15:49:37 jmc Exp $ */ +/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ +// Adapted for Box Backup by Chris Wilson <chris+boxbackup@qwirx.com> + +/* + * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +// #include "Box.h" + +#include <errno.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#define __STDC__ 1 + +#include "getopt.h" + +#if defined _MSC_VER || defined __MINGW32__ +#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ + +#ifdef REPLACE_GETOPT +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ +#endif + +#define PRINT_ERROR ((opterr) && (*options != ':')) + +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#define EMSG "" + +static void warnx(const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + } + + static int getopt_internal(int, char * const *, const char *, + const struct option *, int *, int); + static int parse_long_options(char * const *, const char *, + const struct option *, int *, int); + static int gcd(int, int); + static void permute_args(int, int, int, char * const *); + + static char *place = EMSG; /* option letter processing */ + + /* XXX: set optreset to 1 rather than these two */ + static int nonopt_start = -1; /* first non option argument (for permute) */ + static int nonopt_end = -1; /* first option after non options (for permute) */ + + /* Error messages */ + static const char recargchar[] = "option requires an argument -- %c"; + static const char recargstring[] = "option requires an argument -- %s"; + static const char ambig[] = "ambiguous option -- %.*s"; + static const char noarg[] = "option doesn't take an argument -- %.*s"; + static const char illoptchar[] = "unknown option -- %c"; + static const char illoptstring[] = "unknown option -- %s"; + + /* + * Compute the greatest common divisor of a and b. + */ + static int + gcd(int a, int b) + { + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); + } + + /* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ + static void + permute_args(int panonopt_start, int panonopt_end, int opt_end, + char * const *nargv) + { + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } + } + + /* + * parse_long_options -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ + static int + parse_long_options(char * const *nargv, const char *options, + const struct option *long_options, int *idx, int short_too) + { + char *current_argv, *has_equal; + size_t current_argv_len; + int i, match; + + current_argv = place; + match = -1; + + optind++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) /* partial match */ + match = i; + else { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); + optopt = 0; + return (BADCH); + } + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return (BADARG); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else + return (long_options[match].val); + } + + /* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + */ + static int + getopt_internal(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx, int flags) + { + const char * oli; /* option letter list index */ + int optchar, short_too; + static int posixly_correct = -1; + + if (options == NULL) + return (-1); + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + */ + if (posixly_correct == -1) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + else if (*options == '-') + flags |= FLAG_ALLARGS; + if (*options == '+' || *options == '-') + options++; + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; + + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; + start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + if (*(place = nargv[optind]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; + if (*place == '-') + place++; /* --foo long option */ + else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = parse_long_options(nargv, options, long_options, + idx, short_too); + if (optchar != -1) { + place = EMSG; + return (optchar); + } + } + + if ((optchar = (int)*place++) == (int)':' || + optchar == (int)'-' && *place != '\0' || + (oli = strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else /* white space */ + place = nargv[optind]; + optchar = parse_long_options(nargv, options, long_options, + idx, 0); + place = EMSG; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + /* XXX: disable test for :: if PC? (GNU doesn't) */ + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else + optarg = nargv[optind]; + } else if (!(flags & FLAG_PERMUTE)) { + /* + * If permutation is disabled, we can accept an + * optional arg separated by whitespace so long + * as it does not start with a dash (-). + */ + if (optind + 1 < nargc && *nargv[optind + 1] != '-') + optarg = nargv[++optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return (optchar); + } + + #ifdef REPLACE_GETOPT + /* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the BSD getopt] + */ + int + getopt(int nargc, char * const *nargv, const char *options) + { + + /* + * We don't pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); + } + #endif /* REPLACE_GETOPT */ + + /* + * getopt_long -- + * Parse argc/argv argument vector. + */ + int + getopt_long(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) + { + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); + } + + /* + * getopt_long_only -- + * Parse argc/argv argument vector. + */ + int + getopt_long_only(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) + { + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE|FLAG_LONGONLY)); + } + +#endif // defined _MSC_VER || defined __MINGW32__
\ No newline at end of file diff --git a/mesalib/src/glsl/glcpp/glcpp.c b/mesalib/src/glsl/glcpp/glcpp.c index 564194caa..62065481c 100644 --- a/mesalib/src/glsl/glcpp/glcpp.c +++ b/mesalib/src/glsl/glcpp/glcpp.c @@ -31,6 +31,14 @@ #include "main/mtypes.h" #include "main/shaderobj.h" +#ifdef _MSC_VER +#include <io.h> +#define STDIN_FILENO 0 +#define read _read +#define open _open +#define close _close +#endif + extern int yydebug; void diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp index d7a37aef4..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/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h index 8d4fca787..c628db94e 100644 --- a/mesalib/src/glsl/glsl_parser_extras.h +++ b/mesalib/src/glsl/glsl_parser_extras.h @@ -58,6 +58,10 @@ struct _mesa_glsl_parse_state { /* If the user *does* call delete, that's OK, we will just * ralloc_free in that case. */ + static void operator delete(void *mem, void *ctx) + { + ralloc_free(mem); + } static void operator delete(void *mem) { ralloc_free(mem); diff --git a/mesalib/src/glsl/glsl_symbol_table.cpp b/mesalib/src/glsl/glsl_symbol_table.cpp index 2f291d4f9..9714384eb 100644 --- a/mesalib/src/glsl/glsl_symbol_table.cpp +++ b/mesalib/src/glsl/glsl_symbol_table.cpp @@ -36,6 +36,10 @@ public: } /* If the user *does* call delete, that's OK, we will just ralloc_free. */ + static void operator delete(void *entry, void *ctx) + { + ralloc_free(entry); + } static void operator delete(void *entry) { ralloc_free(entry); diff --git a/mesalib/src/glsl/glsl_symbol_table.h b/mesalib/src/glsl/glsl_symbol_table.h index 637bc033b..1afeddb33 100644 --- a/mesalib/src/glsl/glsl_symbol_table.h +++ b/mesalib/src/glsl/glsl_symbol_table.h @@ -68,6 +68,11 @@ public: /* If the user *does* call delete, that's OK, we will just * ralloc_free in that case. Here, C++ will have already called the * destructor so tell ralloc not to do that again. */ + static void operator delete(void *table, void *ctx) + { + ralloc_set_destructor(table, NULL); + ralloc_free(table); + } static void operator delete(void *table) { ralloc_set_destructor(table, NULL); diff --git a/mesalib/src/glsl/list.h b/mesalib/src/glsl/list.h index 1d46365fa..fb6f0fbba 100644 --- a/mesalib/src/glsl/list.h +++ b/mesalib/src/glsl/list.h @@ -90,6 +90,10 @@ struct exec_node { /* If the user *does* call delete, that's OK, we will just * ralloc_free in that case. */ + static void operator delete(void *node, void *ctx) + { + ralloc_free(node); + } static void operator delete(void *node) { ralloc_free(node); @@ -299,6 +303,10 @@ struct exec_list { /* If the user *does* call delete, that's OK, we will just * ralloc_free in that case. */ + static void operator delete(void *node, void *ctx) + { + ralloc_free(node); + } static void operator delete(void *node) { ralloc_free(node); diff --git a/mesalib/src/glsl/main.cpp b/mesalib/src/glsl/main.cpp index 6f0552931..6321a4a17 100644 --- a/mesalib/src/glsl/main.cpp +++ b/mesalib/src/glsl/main.cpp @@ -22,7 +22,18 @@ */ #include <cstdlib> #include <cstdio> +#include <io.h> + +#ifdef _MSC_VER +#define __STDC__ 1 #include <getopt.h> +#define open _open +#define read _read +#define fstat _fstat +#define stat _stat +#define close _close +#define O_RDONLY _O_RDONLY +#endif #include "ast.h" #include "glsl_parser_extras.h" diff --git a/mesalib/src/mapi/glapi/gen/gen.bat b/mesalib/src/mapi/glapi/gen/gen.bat new file mode 100644 index 000000000..2b1826a81 --- /dev/null +++ b/mesalib/src/mapi/glapi/gen/gen.bat @@ -0,0 +1,20 @@ +echo on +glx_server_table.py -f gl_and_glX_API.xml > indirect_table.c +glx_proto_size.py -m size_h --only-set -h _INDIRECT_SIZE_H_ > indirect_size.h +glx_proto_size.py -m size_c --only-set > indirect_size.c +glx_proto_size.py -m size_h --only-get -h _INDIRECT_SIZE_GET_H_ > indirect_size_get.h +glx_proto_size.py -m size_c --only-get > indirect_size_get.c +glx_proto_size.py -m reqsize_c > indirect_reqsize.c +glx_proto_size.py -m reqsize_h --only-get -h _INDIRECT_SIZE_GET_H_ > indirect_reqsize.h +glx_proto_recv.py -m dispatch_c > indirect_dispatch.c +glx_proto_recv.py -m dispatch_c -s > indirect_dispatch_swap.c +glx_proto_recv.py -m dispatch_h -f gl_and_glX_API.xml -s > indirect_dispatch.h +gl_table.py > glapitable.h +gl_table.py -m remap_table > dispatch.h +rem gl_offsets.py > glapioffsets.h +gl_apitemp.py > glapitemp.h +gl_procs.py > glprocs.h + +glX_proto_send.py -m proto > indirect.c +glX_proto_send.py -m init_h > indirect.h +glX_proto_send.py -m init_c > indirect_init.c diff --git a/mesalib/src/mapi/glapi/gen/gl_API.xml b/mesalib/src/mapi/glapi/gen/gl_API.xml index 1f12c4234..b792c7815 100644 --- a/mesalib/src/mapi/glapi/gen/gl_API.xml +++ b/mesalib/src/mapi/glapi/gen/gl_API.xml @@ -183,18 +183,18 @@ <size name="Get" mode="get"/>
</enum>
<enum name="LIGHT_MODEL_LOCAL_VIEWER" count="1" value="0x0B51">
- <size name="LightModelfv"/>
- <size name="LightModeliv"/>
+ <size name="LightModelfv" mode="get"/>
+ <size name="LightModeliv" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="LIGHT_MODEL_TWO_SIDE" count="1" value="0x0B52">
- <size name="LightModelfv"/>
- <size name="LightModeliv"/>
+ <size name="LightModelfv" mode="get"/>
+ <size name="LightModeliv" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="LIGHT_MODEL_AMBIENT" count="4" value="0x0B53">
- <size name="LightModelfv"/>
- <size name="LightModeliv"/>
+ <size name="LightModelfv" mode="get"/>
+ <size name="LightModeliv" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="SHADE_MODEL" count="1" value="0x0B54">
@@ -213,33 +213,33 @@ <size name="Get" mode="get"/>
</enum>
<enum name="FOG_INDEX" count="1" value="0x0B61">
- <size name="Fogfv"/>
- <size name="Fogiv"/>
+ <size name="Fogfv" mode="get"/>
+ <size name="Fogiv" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="FOG_DENSITY" count="1" value="0x0B62">
- <size name="Fogfv"/>
- <size name="Fogiv"/>
+ <size name="Fogfv" mode="get"/>
+ <size name="Fogiv" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="FOG_START" count="1" value="0x0B63">
- <size name="Fogfv"/>
- <size name="Fogiv"/>
+ <size name="Fogfv" mode="get"/>
+ <size name="Fogiv" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="FOG_END" count="1" value="0x0B64">
- <size name="Fogfv"/>
- <size name="Fogiv"/>
+ <size name="Fogfv" mode="get"/>
+ <size name="Fogiv" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="FOG_MODE" count="1" value="0x0B65">
- <size name="Fogfv"/>
- <size name="Fogiv"/>
+ <size name="Fogfv" mode="get"/>
+ <size name="Fogiv" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="FOG_COLOR" count="4" value="0x0B66">
- <size name="Fogfv"/>
- <size name="Fogiv"/>
+ <size name="Fogfv" mode="get"/>
+ <size name="Fogiv" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="DEPTH_RANGE" count="2" value="0x0B70">
@@ -531,8 +531,8 @@ <size name="Get" mode="get"/>
</enum>
<enum name="ALPHA_SCALE" count="1" value="0x0D1C">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
<size name="Get" mode="get"/>
@@ -625,93 +625,93 @@ <size name="Get" mode="get"/>
</enum>
<enum name="MAP1_COLOR_4" count="4" value="0x0D90">
- <size name="Map1d"/>
- <size name="Map1f"/>
+ <size name="Map1d" mode="get"/>
+ <size name="Map1f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP1_INDEX" count="1" value="0x0D91">
- <size name="Map1d"/>
- <size name="Map1f"/>
+ <size name="Map1d" mode="get"/>
+ <size name="Map1f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP1_NORMAL" count="3" value="0x0D92">
- <size name="Map1d"/>
- <size name="Map1f"/>
+ <size name="Map1d" mode="get"/>
+ <size name="Map1f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP1_TEXTURE_COORD_1" count="1" value="0x0D93">
- <size name="Map1d"/>
- <size name="Map1f"/>
+ <size name="Map1d" mode="get"/>
+ <size name="Map1f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP1_TEXTURE_COORD_2" count="2" value="0x0D94">
- <size name="Map1d"/>
- <size name="Map1f"/>
+ <size name="Map1d" mode="get"/>
+ <size name="Map1f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP1_TEXTURE_COORD_3" count="3" value="0x0D95">
- <size name="Map1d"/>
- <size name="Map1f"/>
+ <size name="Map1d" mode="get"/>
+ <size name="Map1f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP1_TEXTURE_COORD_4" count="4" value="0x0D96">
- <size name="Map1d"/>
- <size name="Map1f"/>
+ <size name="Map1d" mode="get"/>
+ <size name="Map1f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP1_VERTEX_3" count="3" value="0x0D97">
- <size name="Map1d"/>
- <size name="Map1f"/>
+ <size name="Map1d" mode="get"/>
+ <size name="Map1f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP1_VERTEX_4" count="4" value="0x0D98">
- <size name="Map1d"/>
- <size name="Map1f"/>
+ <size name="Map1d" mode="get"/>
+ <size name="Map1f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP2_COLOR_4" count="4" value="0x0DB0">
- <size name="Map2d"/>
- <size name="Map2f"/>
+ <size name="Map2d" mode="get"/>
+ <size name="Map2f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP2_INDEX" count="1" value="0x0DB1">
- <size name="Map2d"/>
- <size name="Map2f"/>
+ <size name="Map2d" mode="get"/>
+ <size name="Map2f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP2_NORMAL" count="3" value="0x0DB2">
- <size name="Map2d"/>
- <size name="Map2f"/>
+ <size name="Map2d" mode="get"/>
+ <size name="Map2f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP2_TEXTURE_COORD_1" count="1" value="0x0DB3">
- <size name="Map2d"/>
- <size name="Map2f"/>
+ <size name="Map2d" mode="get"/>
+ <size name="Map2f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP2_TEXTURE_COORD_2" count="2" value="0x0DB4">
- <size name="Map2d"/>
- <size name="Map2f"/>
+ <size name="Map2d" mode="get"/>
+ <size name="Map2f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP2_TEXTURE_COORD_3" count="3" value="0x0DB5">
- <size name="Map2d"/>
- <size name="Map2f"/>
+ <size name="Map2d" mode="get"/>
+ <size name="Map2f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP2_TEXTURE_COORD_4" count="4" value="0x0DB6">
- <size name="Map2d"/>
- <size name="Map2f"/>
+ <size name="Map2d" mode="get"/>
+ <size name="Map2f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP2_VERTEX_3" count="3" value="0x0DB7">
- <size name="Map2d"/>
- <size name="Map2f"/>
+ <size name="Map2d" mode="get"/>
+ <size name="Map2f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP2_VERTEX_4" count="4" value="0x0DB8">
- <size name="Map2d"/>
- <size name="Map2f"/>
+ <size name="Map2d" mode="get"/>
+ <size name="Map2f" mode="get"/>
<size name="Get" count="1" mode="get"/>
</enum>
<enum name="MAP1_GRID_DOMAIN" count="2" value="0x0DD0">
@@ -754,8 +754,8 @@ <size name="GetTexLevelParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_BORDER_COLOR" count="4" value="0x1004">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -763,111 +763,111 @@ <enum name="FASTEST" value="0x1101"/>
<enum name="NICEST" value="0x1102"/>
<enum name="AMBIENT" count="4" value="0x1200">
- <size name="Materialfv"/>
- <size name="Materialiv"/>
- <size name="Lightfv"/>
- <size name="Lightiv"/>
+ <size name="Materialfv" mode="get"/>
+ <size name="Materialiv" mode="get"/>
+ <size name="Lightfv" mode="get"/>
+ <size name="Lightiv" mode="get"/>
<size name="GetMaterialfv" mode="get"/>
<size name="GetMaterialiv" mode="get"/>
<size name="GetLightfv" mode="get"/>
<size name="GetLightiv" mode="get"/>
</enum>
<enum name="DIFFUSE" count="4" value="0x1201">
- <size name="Materialfv"/>
- <size name="Materialiv"/>
- <size name="Lightfv"/>
- <size name="Lightiv"/>
+ <size name="Materialfv" mode="get"/>
+ <size name="Materialiv" mode="get"/>
+ <size name="Lightfv" mode="get"/>
+ <size name="Lightiv" mode="get"/>
<size name="GetMaterialfv" mode="get"/>
<size name="GetMaterialiv" mode="get"/>
<size name="GetLightfv" mode="get"/>
<size name="GetLightiv" mode="get"/>
</enum>
<enum name="SPECULAR" count="4" value="0x1202">
- <size name="Materialfv"/>
- <size name="Materialiv"/>
- <size name="Lightfv"/>
- <size name="Lightiv"/>
+ <size name="Materialfv" mode="get"/>
+ <size name="Materialiv" mode="get"/>
+ <size name="Lightfv" mode="get"/>
+ <size name="Lightiv" mode="get"/>
<size name="GetMaterialfv" mode="get"/>
<size name="GetMaterialiv" mode="get"/>
<size name="GetLightfv" mode="get"/>
<size name="GetLightiv" mode="get"/>
</enum>
<enum name="POSITION" count="4" value="0x1203">
- <size name="Lightfv"/>
- <size name="Lightiv"/>
+ <size name="Lightfv" mode="get"/>
+ <size name="Lightiv" mode="get"/>
<size name="GetLightfv" mode="get"/>
<size name="GetLightiv" mode="get"/>
</enum>
<enum name="SPOT_DIRECTION" count="3" value="0x1204">
- <size name="Lightfv"/>
- <size name="Lightiv"/>
+ <size name="Lightfv" mode="get"/>
+ <size name="Lightiv" mode="get"/>
<size name="GetLightfv" mode="get"/>
<size name="GetLightiv" mode="get"/>
</enum>
<enum name="SPOT_EXPONENT" count="1" value="0x1205">
- <size name="Lightfv"/>
- <size name="Lightiv"/>
+ <size name="Lightfv" mode="get"/>
+ <size name="Lightiv" mode="get"/>
<size name="GetLightfv" mode="get"/>
<size name="GetLightiv" mode="get"/>
</enum>
<enum name="SPOT_CUTOFF" count="1" value="0x1206">
- <size name="Lightfv"/>
- <size name="Lightiv"/>
+ <size name="Lightfv" mode="get"/>
+ <size name="Lightiv" mode="get"/>
<size name="GetLightfv" mode="get"/>
<size name="GetLightiv" mode="get"/>
</enum>
<enum name="CONSTANT_ATTENUATION" count="1" value="0x1207">
- <size name="Lightfv"/>
- <size name="Lightiv"/>
+ <size name="Lightfv" mode="get"/>
+ <size name="Lightiv" mode="get"/>
<size name="GetLightfv" mode="get"/>
<size name="GetLightiv" mode="get"/>
</enum>
<enum name="LINEAR_ATTENUATION" count="1" value="0x1208">
- <size name="Lightfv"/>
- <size name="Lightiv"/>
+ <size name="Lightfv" mode="get"/>
+ <size name="Lightiv" mode="get"/>
<size name="GetLightfv" mode="get"/>
<size name="GetLightiv" mode="get"/>
</enum>
<enum name="QUADRATIC_ATTENUATION" count="1" value="0x1209">
- <size name="Lightfv"/>
- <size name="Lightiv"/>
+ <size name="Lightfv" mode="get"/>
+ <size name="Lightiv" mode="get"/>
<size name="GetLightfv" mode="get"/>
<size name="GetLightiv" mode="get"/>
</enum>
<enum name="COMPILE" value="0x1300"/>
<enum name="COMPILE_AND_EXECUTE" value="0x1301"/>
<enum name="BYTE" count="1" value="0x1400">
- <size name="CallLists"/>
+ <size name="CallLists" mode="get"/>
</enum>
<enum name="UNSIGNED_BYTE" count="1" value="0x1401">
- <size name="CallLists"/>
+ <size name="CallLists" mode="get"/>
</enum>
<enum name="SHORT" count="2" value="0x1402">
- <size name="CallLists"/>
+ <size name="CallLists" mode="get"/>
</enum>
<enum name="UNSIGNED_SHORT" count="2" value="0x1403">
- <size name="CallLists"/>
+ <size name="CallLists" mode="get"/>
</enum>
<enum name="INT" count="4" value="0x1404">
- <size name="CallLists"/>
+ <size name="CallLists" mode="get"/>
</enum>
<enum name="UNSIGNED_INT" count="4" value="0x1405">
- <size name="CallLists"/>
+ <size name="CallLists" mode="get"/>
</enum>
<enum name="FLOAT" count="4" value="0x1406">
- <size name="CallLists"/>
+ <size name="CallLists" mode="get"/>
</enum>
<enum name="2_BYTES" count="2" value="0x1407">
- <size name="CallLists"/>
+ <size name="CallLists" mode="get"/>
</enum>
<enum name="3_BYTES" count="3" value="0x1408">
- <size name="CallLists"/>
+ <size name="CallLists" mode="get"/>
</enum>
<enum name="4_BYTES" count="4" value="0x1409">
- <size name="CallLists"/>
+ <size name="CallLists" mode="get"/>
</enum>
<enum name="HALF_FLOAT" count="2" value="0x140B">
- <size name="CallLists"/>
+ <size name="CallLists" mode="get"/>
</enum>
<enum name="CLEAR" value="0x1500"/>
<enum name="AND" value="0x1501"/>
@@ -886,26 +886,26 @@ <enum name="NAND" value="0x150E"/>
<enum name="SET" value="0x150F"/>
<enum name="EMISSION" count="4" value="0x1600">
- <size name="Materialfv"/>
- <size name="Materialiv"/>
+ <size name="Materialfv" mode="get"/>
+ <size name="Materialiv" mode="get"/>
<size name="GetMaterialfv" mode="get"/>
<size name="GetMaterialiv" mode="get"/>
</enum>
<enum name="SHININESS" count="1" value="0x1601">
- <size name="Materialfv"/>
- <size name="Materialiv"/>
+ <size name="Materialfv" mode="get"/>
+ <size name="Materialiv" mode="get"/>
<size name="GetMaterialfv" mode="get"/>
<size name="GetMaterialiv" mode="get"/>
</enum>
<enum name="AMBIENT_AND_DIFFUSE" count="4" value="0x1602">
- <size name="Materialfv"/>
- <size name="Materialiv"/>
+ <size name="Materialfv" mode="get"/>
+ <size name="Materialiv" mode="get"/>
<size name="GetMaterialfv" mode="get"/>
<size name="GetMaterialiv" mode="get"/>
</enum>
<enum name="COLOR_INDEXES" count="3" value="0x1603">
- <size name="Materialfv"/>
- <size name="Materialiv"/>
+ <size name="Materialfv" mode="get"/>
+ <size name="Materialiv" mode="get"/>
<size name="GetMaterialfv" mode="get"/>
<size name="GetMaterialiv" mode="get"/>
</enum>
@@ -950,14 +950,14 @@ <enum name="MODULATE" value="0x2100"/>
<enum name="DECAL" value="0x2101"/>
<enum name="TEXTURE_ENV_MODE" count="1" value="0x2200">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="TEXTURE_ENV_COLOR" count="4" value="0x2201">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
@@ -966,25 +966,25 @@ <enum name="OBJECT_LINEAR" value="0x2401"/>
<enum name="SPHERE_MAP" value="0x2402"/>
<enum name="TEXTURE_GEN_MODE" count="1" value="0x2500">
- <size name="TexGendv"/>
- <size name="TexGenfv"/>
- <size name="TexGeniv"/>
+ <size name="TexGendv" mode="get"/>
+ <size name="TexGenfv" mode="get"/>
+ <size name="TexGeniv" mode="get"/>
<size name="GetTexGendv" mode="get"/>
<size name="GetTexGenfv" mode="get"/>
<size name="GetTexGeniv" mode="get"/>
</enum>
<enum name="OBJECT_PLANE" count="4" value="0x2501">
- <size name="TexGendv"/>
- <size name="TexGenfv"/>
- <size name="TexGeniv"/>
+ <size name="TexGendv" mode="get"/>
+ <size name="TexGenfv" mode="get"/>
+ <size name="TexGeniv" mode="get"/>
<size name="GetTexGendv" mode="get"/>
<size name="GetTexGenfv" mode="get"/>
<size name="GetTexGeniv" mode="get"/>
</enum>
<enum name="EYE_PLANE" count="4" value="0x2502">
- <size name="TexGendv"/>
- <size name="TexGenfv"/>
- <size name="TexGeniv"/>
+ <size name="TexGendv" mode="get"/>
+ <size name="TexGenfv" mode="get"/>
+ <size name="TexGeniv" mode="get"/>
<size name="GetTexGendv" mode="get"/>
<size name="GetTexGenfv" mode="get"/>
<size name="GetTexGeniv" mode="get"/>
@@ -996,26 +996,26 @@ <enum name="NEAREST_MIPMAP_LINEAR" value="0x2702"/>
<enum name="LINEAR_MIPMAP_LINEAR" value="0x2703"/>
<enum name="TEXTURE_MAG_FILTER" count="1" value="0x2800">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_MIN_FILTER" count="1" value="0x2801">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_WRAP_S" count="1" value="0x2802">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_WRAP_T" count="1" value="0x2803">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -3039,8 +3039,8 @@ <enum name="PROXY_TEXTURE_1D" value="0x8063"/>
<enum name="PROXY_TEXTURE_2D" value="0x8064"/>
<enum name="TEXTURE_PRIORITY" count="1" value="0x8066">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -3380,8 +3380,8 @@ <size name="GetTexLevelParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_WRAP_R" count="1" value="0x8072">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -3405,32 +3405,32 @@ </enum>
<enum name="CLAMP_TO_EDGE" value="0x812F"/>
<enum name="TEXTURE_MIN_LOD" count="1" value="0x813A">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_MAX_LOD" count="1" value="0x813B">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_BASE_LEVEL" count="1" value="0x813C">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_MAX_LEVEL" count="1" value="0x813D">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="LIGHT_MODEL_COLOR_CONTROL" count="1" value="0x81F8">
- <size name="LightModelfv"/>
- <size name="LightModeliv"/>
+ <size name="LightModelfv" mode="get"/>
+ <size name="LightModeliv" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="SINGLE_COLOR" value="0x81F9"/>
@@ -3482,26 +3482,26 @@ </enum>
<enum name="CONVOLUTION_BORDER_MODE" count="1" value="0x8013">
- <size name="ConvolutionParameterfv"/>
- <size name="ConvolutionParameteriv"/>
+ <size name="ConvolutionParameterfv" mode="get"/>
+ <size name="ConvolutionParameteriv" mode="get"/>
<size name="GetConvolutionParameterfv" mode="get"/>
<size name="GetConvolutionParameteriv" mode="get"/>
</enum>
<enum name="CONVOLUTION_BORDER_COLOR" count="4" value="0x8154">
- <size name="ConvolutionParameterfv"/>
- <size name="ConvolutionParameteriv"/>
+ <size name="ConvolutionParameterfv" mode="get"/>
+ <size name="ConvolutionParameteriv" mode="get"/>
<size name="GetConvolutionParameterfv" mode="get"/>
<size name="GetConvolutionParameteriv" mode="get"/>
</enum>
<enum name="CONVOLUTION_FILTER_SCALE" count="4" value="0x8014">
- <size name="ConvolutionParameterfv"/>
- <size name="ConvolutionParameteriv"/>
+ <size name="ConvolutionParameterfv" mode="get"/>
+ <size name="ConvolutionParameteriv" mode="get"/>
<size name="GetConvolutionParameterfv" mode="get"/>
<size name="GetConvolutionParameteriv" mode="get"/>
</enum>
<enum name="CONVOLUTION_FILTER_BIAS" count="4" value="0x8015">
- <size name="ConvolutionParameterfv"/>
- <size name="ConvolutionParameteriv"/>
+ <size name="ConvolutionParameterfv" mode="get"/>
+ <size name="ConvolutionParameteriv" mode="get"/>
<size name="GetConvolutionParameterfv" mode="get"/>
<size name="GetConvolutionParameteriv" mode="get"/>
</enum>
@@ -3649,14 +3649,14 @@ <enum name="PROXY_POST_COLOR_MATRIX_COLOR_TABLE" value="0x80D5"/>
<enum name="COLOR_TABLE_SCALE" count="4" value="0x80D6">
- <size name="ColorTableParameterfv"/>
- <size name="ColorTableParameteriv"/>
+ <size name="ColorTableParameterfv" mode="get"/>
+ <size name="ColorTableParameteriv" mode="get"/>
<size name="GetColorTableParameterfv" mode="get"/>
<size name="GetColorTableParameteriv" mode="get"/>
</enum>
<enum name="COLOR_TABLE_BIAS" count="4" value="0x80D7">
- <size name="ColorTableParameterfv"/>
- <size name="ColorTableParameteriv"/>
+ <size name="ColorTableParameterfv" mode="get"/>
+ <size name="ColorTableParameteriv" mode="get"/>
<size name="GetColorTableParameterfv" mode="get"/>
<size name="GetColorTableParameteriv" mode="get"/>
</enum>
@@ -4133,92 +4133,92 @@ <enum name="CLAMP_TO_BORDER" value="0x812D"/>
<enum name="COMBINE" value="0x8570"/>
<enum name="COMBINE_RGB" count="1" value="0x8571">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="COMBINE_ALPHA" count="1" value="0x8572">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="SOURCE0_RGB" count="1" value="0x8580">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="SOURCE1_RGB" count="1" value="0x8581">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="SOURCE2_RGB" count="1" value="0x8582">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="SOURCE0_ALPHA" count="1" value="0x8588">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="SOURCE1_ALPHA" count="1" value="0x8589">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="SOURCE2_ALPHA" count="1" value="0x858A">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="OPERAND0_RGB" count="1" value="0x8590">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="OPERAND1_RGB" count="1" value="0x8591">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="OPERAND2_RGB" count="1" value="0x8592">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="OPERAND0_ALPHA" count="1" value="0x8598">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="OPERAND1_ALPHA" count="1" value="0x8599">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="OPERAND2_ALPHA" count="1" value="0x859A">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="RGB_SCALE" count="1" value="0x8573">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
@@ -4534,24 +4534,24 @@ <size name="Get" mode="get"/>
</enum>
<enum name="POINT_SIZE_MIN" count="1" value="0x8126">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="POINT_SIZE_MAX" count="1" value="0x8127">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="POINT_FADE_THRESHOLD_SIZE" count="1" value="0x8128">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="POINT_DISTANCE_ATTENUATION" count="3" value="0x8129">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="GENERATE_MIPMAP" count="1" value="0x8191">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -4600,10 +4600,10 @@ </enum>
<enum name="TEXTURE_FILTER_CONTROL" value="0x8500"/>
<enum name="TEXTURE_LOD_BIAS" count="1" value="0x8501">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
@@ -4616,20 +4616,20 @@ <size name="GetTexLevelParameteriv" mode="get"/>
</enum>
<enum name="DEPTH_TEXTURE_MODE" count="1" value="0x884B">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_COMPARE_MODE" count="1" value="0x884C">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_COMPARE_FUNC" count="1" value="0x884D">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -5121,8 +5121,8 @@ <enum name="SHADING_LANGUAGE_VERSION" value="0x8B8C"/>
<enum name="CURRENT_PROGRAM" value="0x8B8D"/>
<enum name="POINT_SPRITE_COORD_ORIGIN" count="1" value="0x8CA0">
- <size name="PointParameterfvEXT"/>
- <size name="PointParameterivNV"/>
+ <size name="PointParameterfvEXT" mode="get"/>
+ <size name="PointParameterivNV" mode="get"/>
</enum>
<enum name="LOWER_LEFT" value="0x8CA1"/>
<enum name="UPPER_LEFT" value="0x8CA2"/>
@@ -6226,16 +6226,16 @@ <category name="GL_ARB_point_parameters" number="14">
<enum name="POINT_SIZE_MIN_ARB" count="1" value="0x8126">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
</enum>
<enum name="POINT_SIZE_MAX_ARB" count="1" value="0x8127">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
</enum>
<enum name="POINT_FADE_THRESHOLD_SIZE_ARB" count="1" value="0x8128">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
</enum>
<enum name="POINT_DISTANCE_ATTENUATION_ARB" count="3" value="0x8129">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
</enum>
<function name="PointParameterfARB" alias="PointParameterfEXT">
@@ -6541,8 +6541,8 @@ <size name="GetTexLevelParameteriv" mode="get"/>
</enum>
<enum name="DEPTH_TEXTURE_MODE_ARB" count="1" value="0x884B">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -6550,14 +6550,14 @@ <category name="GL_ARB_shadow" number="23">
<enum name="TEXTURE_COMPARE_MODE_ARB" count="1" value="0x884C">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_COMPARE_FUNC_ARB" count="1" value="0x884D">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -6566,8 +6566,8 @@ <category name="GL_ARB_shadow_ambient" number="24">
<enum name="TEXTURE_COMPARE_FAIL_VALUE_ARB" count="1" value="0x80BF">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -7865,8 +7865,8 @@ <size name="Get" mode="get"/>
</enum>
<enum name="COORD_REPLACE_ARB" count="1" value="0x8862">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
@@ -8317,20 +8317,20 @@ <category name="GL_EXT_convolution" number="12">
<enum name="CONVOLUTION_BORDER_MODE_EXT" count="1" value="0x8013">
- <size name="ConvolutionParameterfv"/>
- <size name="ConvolutionParameteriv"/>
+ <size name="ConvolutionParameterfv" mode="get"/>
+ <size name="ConvolutionParameteriv" mode="get"/>
<size name="GetConvolutionParameterfv" mode="get"/>
<size name="GetConvolutionParameteriv" mode="get"/>
</enum>
<enum name="CONVOLUTION_FILTER_SCALE_EXT" count="4" value="0x8014">
- <size name="ConvolutionParameterfv"/>
- <size name="ConvolutionParameteriv"/>
+ <size name="ConvolutionParameterfv" mode="get"/>
+ <size name="ConvolutionParameteriv" mode="get"/>
<size name="GetConvolutionParameterfv" mode="get"/>
<size name="GetConvolutionParameteriv" mode="get"/>
</enum>
<enum name="CONVOLUTION_FILTER_BIAS_EXT" count="4" value="0x8015">
- <size name="ConvolutionParameterfv"/>
- <size name="ConvolutionParameteriv"/>
+ <size name="ConvolutionParameterfv" mode="get"/>
+ <size name="ConvolutionParameteriv" mode="get"/>
<size name="GetConvolutionParameterfv" mode="get"/>
<size name="GetConvolutionParameteriv" mode="get"/>
</enum>
@@ -8840,8 +8840,8 @@ <category name="GL_SGIS_generate_mipmap" number="32">
<enum name="GENERATE_MIPMAP_SGIS" count="1" value="0x8191">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -8851,26 +8851,26 @@ <category name="GL_SGIX_clipmap" number="33">
<enum name="LINEAR_CLIPMAP_LINEAR_SGIX" value="0x8170"/>
<enum name="TEXTURE_CLIPMAP_CENTER_SGIX" count="2" value="0x8171">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_CLIPMAP_FRAME_SGIX" count="1" value="0x8172">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_CLIPMAP_OFFSET_SGIX" count="2" value="0x8173">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX" count="3" value="0x8174">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -8885,14 +8885,14 @@ <category name="GL_SGIX_shadow" number="34">
<enum name="TEXTURE_COMPARE_SGIX" count="1" value="0x819A">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_COMPARE_OPERATOR_SGIX" count="1" value="0x819B">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -8969,16 +8969,16 @@ <category name="GL_EXT_point_parameters" number="54">
<enum name="POINT_SIZE_MIN_EXT" count="1" value="0x8126">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
</enum>
<enum name="POINT_SIZE_MAX_EXT" count="1" value="0x8127">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
</enum>
<enum name="POINT_FADE_THRESHOLD_SIZE_EXT" count="1" value="0x8128">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
</enum>
<enum name="POINT_DISTANCE_ATTENUATION_EXT" count="3" value="0x8129">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
</enum>
<function name="PointParameterfEXT" offset="assign">
@@ -9029,14 +9029,14 @@ <category name="GL_SGIX_texture_scale_bias" number="56">
<enum name="POST_TEXTURE_FILTER_BIAS_SGIX" count="4" value="0x8179">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="POST_TEXTURE_FILTER_SCALE_SGIX" count="4" value="0x817A">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -9096,8 +9096,8 @@ <category name="GL_SGIX_fog_offset" number="65">
<enum name="FOG_OFFSET_SGIX" value="0x8198"/>
<enum name="FOG_OFFSET_VALUE_SGIX" count="1" value="0x8199">
- <size name="Fogfv"/>
- <size name="Fogiv"/>
+ <size name="Fogfv" mode="get"/>
+ <size name="Fogiv" mode="get"/>
</enum>
</category>
@@ -9144,8 +9144,8 @@ <enum name="CONSTANT_BORDER_HP" value="0x8151"/>
<enum name="REPLICATE_BORDER_HP" value="0x8153"/>
<enum name="CONVOLUTION_BORDER_COLOR_HP" count="4" value="0x8154">
- <size name="ConvolutionParameterfv"/>
- <size name="ConvolutionParameteriv"/>
+ <size name="ConvolutionParameterfv" mode="get"/>
+ <size name="ConvolutionParameteriv" mode="get"/>
<size name="GetConvolutionParameterfv" mode="get"/>
<size name="GetConvolutionParameteriv" mode="get"/>
</enum>
@@ -9311,20 +9311,20 @@ <category name="GL_SGIX_texture_lod_bias" number="84">
<enum name="TEXTURE_LOD_BIAS_S_SGIX" count="1" value="0x818E">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_LOD_BIAS_T_SGIX" count="1" value="0x818F">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_LOD_BIAS_R_SGIX" count="1" value="0x8190">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -9339,8 +9339,8 @@ <category name="GL_SGIX_shadow_ambient" number="90">
<enum name="SHADOW_AMBIENT_SGIX" count="1" value="0x80BF">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -9684,8 +9684,8 @@ <category name="GL_EXT_separate_specular_color" number="144">
<enum name="LIGHT_MODEL_COLOR_CONTROL_EXT" count="1" value="0x81F8">
- <size name="LightModelfv"/>
- <size name="LightModeliv"/>
+ <size name="LightModelfv" mode="get"/>
+ <size name="LightModeliv" mode="get"/>
</enum>
<enum name="SINGLE_COLOR_EXT" value="0x81F9"/>
<enum name="SEPARATE_SPECULAR_COLOR_EXT" value="0x81FA"/>
@@ -10458,8 +10458,8 @@ <category name="GL_EXT_texture_lod_bias" number="186">
<enum name="TEXTURE_LOD_BIAS_EXT" count="1" value="0x8501">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -10467,8 +10467,8 @@ <category name="GL_EXT_texture_filter_anisotropic" number="187">
<enum name="TEXTURE_MAX_ANISOTROPY_EXT" count="1" value="0x84FE">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -10626,8 +10626,8 @@ <category name="GL_NV_fog_distance" number="192">
<enum name="FOG_DISTANCE_MODE_NV" count="1" value="0x855A">
- <size name="Fogfv"/>
- <size name="Fogiv"/>
+ <size name="Fogfv" mode="get"/>
+ <size name="Fogiv" mode="get"/>
<size name="Get" mode="get"/>
</enum>
<enum name="EYE_RADIAL_NV" value="0x855B"/>
@@ -10641,26 +10641,26 @@ <category name="GL_NV_texture_env_combine4" number="195">
<enum name="COMBINE4" value="0x8503"/>
<enum name="SOURCE3_RGB_NV" count="1" value="0x8583">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="SOURCE3_ALPHA_NV" count="1" value="0x858B">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="OPERAND3_RGB_NV" count="1" value="0x8593">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="OPERAND3_ALPHA_NV" count="1" value="0x859B">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
@@ -11681,20 +11681,20 @@ <category name="GL_SGIX_texture_coordinate_clamp" number="235">
<enum name="TEXTURE_MAX_CLAMP_S_SGIX" count="1" value="0x8369">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_MAX_CLAMP_T_SGIX" count="1" value="0x836A">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
<enum name="TEXTURE_MAX_CLAMP_R_SGIX" count="1" value="0x836B">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -11733,8 +11733,8 @@ <enum name="DU8DV8_ATI" value="0x877A"/>
<enum name="BUMP_ENVMAP_ATI" value="0x877B"/>
<enum name="BUMP_TARGET_ATI" count="1" value="0x877C">
- <size name="TexEnviv"/>
- <size name="TexEnvfv"/>
+ <size name="TexEnviv" mode="get"/>
+ <size name="TexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
</enum>
@@ -11927,30 +11927,30 @@ added for this extension. -->
<enum name="POINT_SIZE_MIN_EXT" count="1" value="0x8126">
- <size name="PointParameterivNV"/>
+ <size name="PointParameterivNV" mode="get"/>
</enum>
<enum name="POINT_SIZE_MAX_EXT" count="1" value="0x8127">
- <size name="PointParameterivNV"/>
+ <size name="PointParameterivNV" mode="get"/>
</enum>
<enum name="POINT_FADE_THRESHOLD_SIZE_EXT" count="1" value="0x8128">
- <size name="PointParameterivNV"/>
+ <size name="PointParameterivNV" mode="get"/>
</enum>
<enum name="POINT_DISTANCE_ATTENUATION_EXT" count="3" value="0x8129">
- <size name="PointParameterivNV"/>
+ <size name="PointParameterivNV" mode="get"/>
</enum>
<enum name="POINT_SPRITE_NV" count="1" value="0x8861">
<size name="Get" mode="get"/>
</enum>
<enum name="COORD_REPLACE_NV" count="1" value="0x8862">
- <size name="TexEnvfv"/>
- <size name="TexEnviv"/>
+ <size name="TexEnvfv" mode="get"/>
+ <size name="TexEnviv" mode="get"/>
<size name="GetTexEnvfv" mode="get"/>
<size name="GetTexEnviv" mode="get"/>
</enum>
<enum name="POINT_SPRITE_R_MODE_NV" count="1" value="0x8863">
- <size name="PointParameterfvEXT"/>
- <size name="PointParameterivNV"/>
+ <size name="PointParameterfvEXT" mode="get"/>
+ <size name="PointParameterivNV" mode="get"/>
<size name="Get" mode="get"/>
</enum>
@@ -12129,8 +12129,8 @@ <category name="GL_NV_texture_expand_normal" number="286">
<enum name="TEXTURE_UNSIGNED_REMAP_MODE_NV" count="1" value="0x888F">
- <size name="TexParameterfv"/>
- <size name="TexParameteriv"/>
+ <size name="TexParameterfv" mode="get"/>
+ <size name="TexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
</enum>
@@ -12284,22 +12284,22 @@ <category name="GL_APPLE_texture_range" number="367">
<enum name="TEXTURE_STORAGE_HINT_APPLE" count="1" value="0x85BC">
- <size name="TexParameteriv"/>
- <size name="TexParameterfv"/>
+ <size name="TexParameteriv" mode="get"/>
+ <size name="TexParameterfv" mode="get"/>
<size name="GetTexParameteriv" mode="get"/>
<size name="GetTexParameterfv" mode="get"/>
</enum>
<enum name="STORAGE_PRIVATE_APPLE" count="1" value="0x85BD">
- <size name="TexParameteriv"/>
- <size name="TexParameterfv"/>
+ <size name="TexParameteriv" mode="get"/>
+ <size name="TexParameterfv" mode="get"/>
</enum>
<enum name="STORAGE_CACHED_APPLE" count="1" value="0x85BE">
- <size name="TexParameteriv"/>
- <size name="TexParameterfv"/>
+ <size name="TexParameteriv" mode="get"/>
+ <size name="TexParameterfv" mode="get"/>
</enum>
<enum name="STORAGE_SHARED_APPLE" count="1" value="0x85BF">
- <size name="TexParameteriv"/>
- <size name="TexParameterfv"/>
+ <size name="TexParameteriv" mode="get"/>
+ <size name="TexParameterfv" mode="get"/>
</enum>
<enum name="TEXTURE_RANGE_LENGTH_APPLE" count="1" value="0x85B7">
<size name="GetTexParameteriv" mode="get"/>
@@ -12442,16 +12442,16 @@ <category name="GL_SGIS_point_parameters">
<enum name="POINT_SIZE_MIN_SGIS" count="1" value="0x8126">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
</enum>
<enum name="POINT_SIZE_MAX_SGIS" count="1" value="0x8127">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
</enum>
<enum name="POINT_FADE_THRESHOLD_SIZE_SGIS" count="1" value="0x8128">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
</enum>
<enum name="POINT_DISTANCE_ATTENUATION_SGIS" count="3" value="0x8129">
- <size name="PointParameterfvEXT"/>
+ <size name="PointParameterfvEXT" mode="get"/>
</enum>
<function name="PointParameterfSGIS" alias="PointParameterfEXT" static_dispatch="false">
diff --git a/mesalib/src/mapi/glapi/glapi.h b/mesalib/src/mapi/glapi/glapi.h index 1d4ac4674..a99317ad0 100644 --- a/mesalib/src/mapi/glapi/glapi.h +++ b/mesalib/src/mapi/glapi/glapi.h @@ -39,12 +39,9 @@ * This module is intended to be non-Mesa-specific so it can be used
* with the X/DRI libGL also.
*/
-
-
#ifndef _GLAPI_H
#define _GLAPI_H
-
#ifdef _GLAPI_NO_EXPORTS
# define _GLAPI_EXPORT
#else /* _GLAPI_NO_EXPORTS */
@@ -72,7 +69,7 @@ #define _glapi_Context _mglapi_Context
#endif
-#include "glapi/glthread.h"
+#include "glthread.h"
typedef void (*_glapi_proc)(void);
struct _glapi_table;
@@ -94,8 +91,14 @@ _GLAPI_EXPORT extern const void *_glapi_Context; #else
-_GLAPI_EXPORT extern struct _glapi_table *_glapi_Dispatch;
-_GLAPI_EXPORT extern void *_glapi_Context;
+#ifdef INSERVER
+#define SERVEXTERN _declspec(dllimport)
+#else
+#define SERVEXTERN _declspec(dllexport)
+#endif
+
+SERVEXTERN struct _glapi_table *_glapi_Dispatch;
+SERVEXTERN void *_glapi_Context;
# ifdef THREADS
@@ -119,31 +122,31 @@ void _glapi_destroy_multithread(void);
-_GLAPI_EXPORT void
+SERVEXTERN void
_glapi_check_multithread(void);
-_GLAPI_EXPORT void
+SERVEXTERN void
_glapi_set_context(void *context);
-_GLAPI_EXPORT void *
+SERVEXTERN void *
_glapi_get_context(void);
-_GLAPI_EXPORT void
+SERVEXTERN void
_glapi_set_dispatch(struct _glapi_table *dispatch);
-_GLAPI_EXPORT struct _glapi_table *
+SERVEXTERN struct _glapi_table *
_glapi_get_dispatch(void);
-_GLAPI_EXPORT unsigned int
+SERVEXTERN unsigned int
_glapi_get_dispatch_table_size(void);
-_GLAPI_EXPORT int
+SERVEXTERN int
_glapi_add_dispatch( const char * const * function_names,
const char * parameter_signature );
@@ -166,7 +169,7 @@ _glthread_GetID(void); /*
* These stubs are kept so that the old DRI drivers still load.
*/
-_GLAPI_EXPORT void
+SERVEXTERN void
_glapi_noop_enable_warnings(unsigned char enable);
diff --git a/mesalib/src/mapi/glapi/glapi_getproc.c b/mesalib/src/mapi/glapi/glapi_getproc.c index 21380ea41..d5c72f29b 100644 --- a/mesalib/src/mapi/glapi/glapi_getproc.c +++ b/mesalib/src/mapi/glapi/glapi_getproc.c @@ -369,6 +369,7 @@ set_entry_info( struct _glapi_function * entry, const char * signature, unsigned * the parameter signature of a static function.
*/
+#ifndef INSERVER
int
_glapi_add_dispatch( const char * const * function_names,
const char * parameter_signature )
@@ -478,12 +479,12 @@ _glapi_add_dispatch( const char * const * function_names, return offset;
}
-
+#endif
/**
* Return offset of entrypoint for named function within dispatch table.
*/
-GLint
+GLint _GLAPI_EXPORT
_glapi_get_proc_offset(const char *funcName)
{
GLint offset;
@@ -504,7 +505,7 @@ _glapi_get_proc_offset(const char *funcName) * in the name of static functions, try generating a new API entrypoint on
* the fly with assembly language.
*/
-_glapi_proc
+_glapi_proc _GLAPI_EXPORT
_glapi_get_proc_address(const char *funcName)
{
_glapi_proc func;
@@ -545,7 +546,7 @@ _glapi_get_proc_address(const char *funcName) * Return the name of the function at the given dispatch offset.
* This is only intended for debugging.
*/
-const char *
+const char * _GLAPI_EXPORT
_glapi_get_proc_name(GLuint offset)
{
const char * n;
@@ -571,7 +572,7 @@ _glapi_get_proc_name(GLuint offset) * Return size of dispatch table struct as number of functions (or
* slots).
*/
-GLuint
+GLuint _GLAPI_EXPORT
_glapi_get_dispatch_table_size(void)
{
/*
diff --git a/mesalib/src/mapi/glapi/glapi_nop.c b/mesalib/src/mapi/glapi/glapi_nop.c index 9b0929715..365a6e1c8 100644 --- a/mesalib/src/mapi/glapi/glapi_nop.c +++ b/mesalib/src/mapi/glapi/glapi_nop.c @@ -41,12 +41,12 @@ #include "glapi/glapi_priv.h" -void +void _GLAPI_EXPORT _glapi_noop_enable_warnings(unsigned char enable) { } -void +void _GLAPI_EXPORT _glapi_set_warning_func(_glapi_proc func) { } diff --git a/mesalib/src/mapi/glapi/glthread.c b/mesalib/src/mapi/glapi/glthread.c index 00915380f..239090ecf 100644 --- a/mesalib/src/mapi/glapi/glthread.c +++ b/mesalib/src/mapi/glapi/glthread.c @@ -1,6 +1,6 @@ #include "glapi/glapi.h" -unsigned long +unsigned long _GLAPI_EXPORT _glthread_GetID(void) { return u_thread_self(); diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.c b/mesalib/src/mesa/drivers/dri/common/dri_util.c index 82638fa72..6d3dd0a2c 100644 --- a/mesalib/src/mesa/drivers/dri/common/dri_util.c +++ b/mesalib/src/mesa/drivers/dri/common/dri_util.c @@ -1,1030 +1,1030 @@ -/** - * \file dri_util.c - * DRI utility functions. - * - * This module acts as glue between GLX and the actual hardware driver. A DRI - * driver doesn't really \e have to use any of this - it's optional. But, some - * useful stuff is done here that otherwise would have to be duplicated in most - * drivers. - * - * Basically, these utility functions take care of some of the dirty details of - * screen initialization, context creation, context binding, DRM setup, etc. - * - * These functions are compiled into each DRI driver so libGL.so knows nothing - * about them. - */ - - -#include <assert.h> -#include <stdarg.h> -#include <unistd.h> -#include <sys/mman.h> -#include <stdio.h> - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *)-1) -#endif - -#include "main/imports.h" -#define None 0 - -#include "dri_util.h" -#include "drm_sarea.h" -#include "utils.h" -#include "xmlpool.h" -#include "../glsl/glsl_parser_extras.h" - -PUBLIC const char __dri2ConfigOptions[] = - DRI_CONF_BEGIN - DRI_CONF_SECTION_PERFORMANCE - DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1) - DRI_CONF_SECTION_END - DRI_CONF_END; - -static const uint __dri2NConfigOptions = 1; - -#ifndef GLX_OML_sync_control -typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRIdrawable *drawable, int32_t *numerator, int32_t *denominator); -#endif - -static void dri_get_drawable(__DRIdrawable *pdp); -static void dri_put_drawable(__DRIdrawable *pdp); - -/** - * This is just a token extension used to signal that the driver - * supports setting a read drawable. - */ -const __DRIextension driReadDrawableExtension = { - __DRI_READ_DRAWABLE, __DRI_READ_DRAWABLE_VERSION -}; - -GLint -driIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 ) -{ - if (rect2.x1 > rect1.x1) rect1.x1 = rect2.x1; - if (rect2.x2 < rect1.x2) rect1.x2 = rect2.x2; - if (rect2.y1 > rect1.y1) rect1.y1 = rect2.y1; - if (rect2.y2 < rect1.y2) rect1.y2 = rect2.y2; - - if (rect1.x1 > rect1.x2 || rect1.y1 > rect1.y2) return 0; - - return (rect1.x2 - rect1.x1) * (rect1.y2 - rect1.y1); -} - -/*****************************************************************/ -/** \name Context (un)binding functions */ -/*****************************************************************/ -/*@{*/ - -/** - * Unbind context. - * - * \param scrn the screen. - * \param gc context. - * - * \return \c GL_TRUE on success, or \c GL_FALSE on failure. - * - * \internal - * This function calls __DriverAPIRec::UnbindContext, and then decrements - * __DRIdrawableRec::refcount which must be non-zero for a successful - * return. - * - * While casting the opaque private pointers associated with the parameters - * into their respective real types it also assures they are not \c NULL. - */ -static int driUnbindContext(__DRIcontext *pcp) -{ - __DRIscreen *psp; - __DRIdrawable *pdp; - __DRIdrawable *prp; - - /* - ** Assume error checking is done properly in glXMakeCurrent before - ** calling driUnbindContext. - */ - - if (pcp == NULL) - return GL_FALSE; - - psp = pcp->driScreenPriv; - pdp = pcp->driDrawablePriv; - prp = pcp->driReadablePriv; - - /* already unbound */ - if (!pdp && !prp) - return GL_TRUE; - /* Let driver unbind drawable from context */ - (*psp->DriverAPI.UnbindContext)(pcp); - - assert(pdp); - if (pdp->refcount == 0) { - /* ERROR!!! */ - return GL_FALSE; - } - - dri_put_drawable(pdp); - - if (prp != pdp) { - if (prp->refcount == 0) { - /* ERROR!!! */ - return GL_FALSE; - } - - dri_put_drawable(prp); - } - - - /* XXX this is disabled so that if we call SwapBuffers on an unbound - * window we can determine the last context bound to the window and - * use that context's lock. (BrianP, 2-Dec-2000) - */ - pcp->driDrawablePriv = pcp->driReadablePriv = NULL; - - return GL_TRUE; -} - -/** - * This function takes both a read buffer and a draw buffer. This is needed - * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent - * function. - */ -static int driBindContext(__DRIcontext *pcp, - __DRIdrawable *pdp, - __DRIdrawable *prp) -{ - __DRIscreen *psp = NULL; - - /* - ** Assume error checking is done properly in glXMakeCurrent before - ** calling driUnbindContext. - */ - - if (!pcp) - return GL_FALSE; - - /* Bind the drawable to the context */ - psp = pcp->driScreenPriv; - pcp->driDrawablePriv = pdp; - pcp->driReadablePriv = prp; - if (pdp) { - pdp->driContextPriv = pcp; - dri_get_drawable(pdp); - } - if (prp && pdp != prp) { - dri_get_drawable(prp); - } - - /* - ** Now that we have a context associated with this drawable, we can - ** initialize the drawable information if has not been done before. - */ - - if (!psp->dri2.enabled) { - if (pdp && !pdp->pStamp) { - DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); - __driUtilUpdateDrawableInfo(pdp); - DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); - } - if (prp && pdp != prp && !prp->pStamp) { - DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); - __driUtilUpdateDrawableInfo(prp); - DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); - } - } - - /* Call device-specific MakeCurrent */ - return (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp); -} - -/*@}*/ - - -/*****************************************************************/ -/** \name Drawable handling functions */ -/*****************************************************************/ -/*@{*/ - -/** - * Update private drawable information. - * - * \param pdp pointer to the private drawable information to update. - * - * This function basically updates the __DRIdrawable struct's - * cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo. - * This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which - * compares the __DRIdrwablePrivate pStamp and lastStamp values. If - * the values are different that means we have to update the clipping - * info. - */ -void -__driUtilUpdateDrawableInfo(__DRIdrawable *pdp) -{ - __DRIscreen *psp = pdp->driScreenPriv; - __DRIcontext *pcp = pdp->driContextPriv; - - if (!pcp - || ((pdp != pcp->driDrawablePriv) && (pdp != pcp->driReadablePriv))) { - /* ERROR!!! - * ...but we must ignore it. There can be many contexts bound to a - * drawable. - */ - } - - if (pdp->pClipRects) { - free(pdp->pClipRects); - pdp->pClipRects = NULL; - } - - if (pdp->pBackClipRects) { - free(pdp->pBackClipRects); - pdp->pBackClipRects = NULL; - } - - DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); - - if (! (*psp->getDrawableInfo->getDrawableInfo)(pdp, - &pdp->index, &pdp->lastStamp, - &pdp->x, &pdp->y, &pdp->w, &pdp->h, - &pdp->numClipRects, &pdp->pClipRects, - &pdp->backX, - &pdp->backY, - &pdp->numBackClipRects, - &pdp->pBackClipRects, - pdp->loaderPrivate)) { - /* Error -- eg the window may have been destroyed. Keep going - * with no cliprects. - */ - pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */ - pdp->numClipRects = 0; - pdp->pClipRects = NULL; - pdp->numBackClipRects = 0; - pdp->pBackClipRects = NULL; - } - else - pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp); - - DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); -} - -/*@}*/ - -/*****************************************************************/ -/** \name GLX callbacks */ -/*****************************************************************/ -/*@{*/ - -static void driReportDamage(__DRIdrawable *pdp, - struct drm_clip_rect *pClipRects, int numClipRects) -{ - __DRIscreen *psp = pdp->driScreenPriv; - - /* Check that we actually have the new damage report method */ - if (psp->damage) { - /* Report the damage. Currently, all our drivers draw - * directly to the front buffer, so we report the damage there - * rather than to the backing storein (if any). - */ - (*psp->damage->reportDamage)(pdp, - pdp->x, pdp->y, - pClipRects, numClipRects, - GL_TRUE, pdp->loaderPrivate); - } -} - - -/** - * Swap buffers. - * - * \param drawablePrivate opaque pointer to the per-drawable private info. - * - * \internal - * This function calls __DRIdrawable::swapBuffers. - * - * Is called directly from glXSwapBuffers(). - */ -static void driSwapBuffers(__DRIdrawable *dPriv) -{ - __DRIscreen *psp = dPriv->driScreenPriv; - drm_clip_rect_t *rects; - int i; - - psp->DriverAPI.SwapBuffers(dPriv); - - if (!dPriv->numClipRects) - return; - - rects = malloc(sizeof(*rects) * dPriv->numClipRects); - - if (!rects) - return; - - for (i = 0; i < dPriv->numClipRects; i++) { - rects[i].x1 = dPriv->pClipRects[i].x1 - dPriv->x; - rects[i].y1 = dPriv->pClipRects[i].y1 - dPriv->y; - rects[i].x2 = dPriv->pClipRects[i].x2 - dPriv->x; - rects[i].y2 = dPriv->pClipRects[i].y2 - dPriv->y; - } - - driReportDamage(dPriv, rects, dPriv->numClipRects); - free(rects); -} - -static int driDrawableGetMSC( __DRIscreen *sPriv, __DRIdrawable *dPriv, - int64_t *msc ) -{ - return sPriv->DriverAPI.GetDrawableMSC(sPriv, dPriv, msc); -} - - -static int driWaitForMSC(__DRIdrawable *dPriv, int64_t target_msc, - int64_t divisor, int64_t remainder, - int64_t * msc, int64_t * sbc) -{ - __DRIswapInfo sInfo; - int status; - - status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc, - divisor, remainder, - msc ); - - /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync - * is supported but GLX_OML_sync_control is not. Therefore, don't return - * an error value if GetSwapInfo() is not implemented. - */ - if ( status == 0 - && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) { - status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo ); - *sbc = sInfo.swap_count; - } - - return status; -} - - -const __DRImediaStreamCounterExtension driMediaStreamCounterExtension = { - { __DRI_MEDIA_STREAM_COUNTER, __DRI_MEDIA_STREAM_COUNTER_VERSION }, - driWaitForMSC, - driDrawableGetMSC, -}; - - -static void driCopySubBuffer(__DRIdrawable *dPriv, - int x, int y, int w, int h) -{ - drm_clip_rect_t rect; - - rect.x1 = x; - rect.y1 = dPriv->h - y - h; - rect.x2 = x + w; - rect.y2 = rect.y1 + h; - driReportDamage(dPriv, &rect, 1); - - dPriv->driScreenPriv->DriverAPI.CopySubBuffer(dPriv, x, y, w, h); -} - -const __DRIcopySubBufferExtension driCopySubBufferExtension = { - { __DRI_COPY_SUB_BUFFER, __DRI_COPY_SUB_BUFFER_VERSION }, - driCopySubBuffer -}; - -static void driSetSwapInterval(__DRIdrawable *dPriv, unsigned int interval) -{ - dPriv->swap_interval = interval; -} - -static unsigned int driGetSwapInterval(__DRIdrawable *dPriv) -{ - return dPriv->swap_interval; -} - -const __DRIswapControlExtension driSwapControlExtension = { - { __DRI_SWAP_CONTROL, __DRI_SWAP_CONTROL_VERSION }, - driSetSwapInterval, - driGetSwapInterval -}; - - -/** - * This is called via __DRIscreenRec's createNewDrawable pointer. - */ -static __DRIdrawable * -driCreateNewDrawable(__DRIscreen *psp, const __DRIconfig *config, - drm_drawable_t hwDrawable, int renderType, - const int *attrs, void *data) -{ - __DRIdrawable *pdp; - - /* Since pbuffers are not yet supported, no drawable attributes are - * supported either. - */ - (void) attrs; - - pdp = malloc(sizeof *pdp); - if (!pdp) { - return NULL; - } - - pdp->driContextPriv = NULL; - pdp->loaderPrivate = data; - pdp->hHWDrawable = hwDrawable; - pdp->refcount = 1; - pdp->pStamp = NULL; - pdp->lastStamp = 0; - pdp->index = 0; - pdp->x = 0; - pdp->y = 0; - pdp->w = 0; - pdp->h = 0; - pdp->numClipRects = 0; - pdp->numBackClipRects = 0; - pdp->pClipRects = NULL; - pdp->pBackClipRects = NULL; - pdp->vblSeq = 0; - pdp->vblFlags = 0; - - pdp->driScreenPriv = psp; - - if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, &config->modes, 0)) { - free(pdp); - return NULL; - } - - pdp->msc_base = 0; - - /* This special default value is replaced with the configured - * default value when the drawable is first bound to a direct - * rendering context. - */ - pdp->swap_interval = (unsigned)-1; - - return pdp; -} - - -static __DRIdrawable * -dri2CreateNewDrawable(__DRIscreen *screen, - const __DRIconfig *config, - void *loaderPrivate) -{ - __DRIdrawable *pdraw; - - pdraw = driCreateNewDrawable(screen, config, 0, 0, NULL, loaderPrivate); - if (!pdraw) - return NULL; - - pdraw->pClipRects = &pdraw->dri2.clipRect; - pdraw->pBackClipRects = &pdraw->dri2.clipRect; - - pdraw->pStamp = &pdraw->dri2.stamp; - *pdraw->pStamp = pdraw->lastStamp + 1; - - 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) -{ - if (!driCheckOption(&screen->optionCache, var, DRI_BOOL)) - return -1; - - *val = driQueryOptionb(&screen->optionCache, var); - - return 0; -} - -static int -dri2ConfigQueryi(__DRIscreen *screen, const char *var, GLint *val) -{ - if (!driCheckOption(&screen->optionCache, var, DRI_INT) && - !driCheckOption(&screen->optionCache, var, DRI_ENUM)) - return -1; - - *val = driQueryOptioni(&screen->optionCache, var); - - return 0; -} - -static int -dri2ConfigQueryf(__DRIscreen *screen, const char *var, GLfloat *val) -{ - if (!driCheckOption(&screen->optionCache, var, DRI_FLOAT)) - return -1; - - *val = driQueryOptionf(&screen->optionCache, var); - - return 0; -} - - -static void dri_get_drawable(__DRIdrawable *pdp) -{ - pdp->refcount++; -} - -static void dri_put_drawable(__DRIdrawable *pdp) -{ - __DRIscreen *psp; - - if (pdp) { - pdp->refcount--; - if (pdp->refcount) - return; - - psp = pdp->driScreenPriv; - (*psp->DriverAPI.DestroyBuffer)(pdp); - if (pdp->pClipRects && pdp->pClipRects != &pdp->dri2.clipRect) { - free(pdp->pClipRects); - pdp->pClipRects = NULL; - } - if (pdp->pBackClipRects && pdp->pClipRects != &pdp->dri2.clipRect) { - free(pdp->pBackClipRects); - pdp->pBackClipRects = NULL; - } - free(pdp); - } -} - -static void -driDestroyDrawable(__DRIdrawable *pdp) -{ - dri_put_drawable(pdp); -} - -/*@}*/ - - -/*****************************************************************/ -/** \name Context handling functions */ -/*****************************************************************/ -/*@{*/ - -/** - * Destroy the per-context private information. - * - * \internal - * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls - * drmDestroyContext(), and finally frees \p contextPrivate. - */ -static void -driDestroyContext(__DRIcontext *pcp) -{ - if (pcp) { - (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp); - free(pcp); - } -} - - -/** - * Create the per-drawable private driver information. - * - * \param render_type Type of rendering target. \c GLX_RGBA is the only - * type likely to ever be supported for direct-rendering. - * \param shared Context with which to share textures, etc. or NULL - * - * \returns An opaque pointer to the per-context private information on - * success, or \c NULL on failure. - * - * \internal - * This function allocates and fills a __DRIcontextRec structure. It - * performs some device independent initialization and passes all the - * relevent information to __DriverAPIRec::CreateContext to create the - * context. - * - */ -static __DRIcontext * -driCreateNewContext(__DRIscreen *psp, const __DRIconfig *config, - int render_type, __DRIcontext *shared, - drm_context_t hwContext, void *data) -{ - __DRIcontext *pcp; - void * const shareCtx = (shared != NULL) ? shared->driverPrivate : NULL; - - pcp = malloc(sizeof *pcp); - if (!pcp) - return NULL; - - pcp->driScreenPriv = psp; - pcp->driDrawablePriv = NULL; - pcp->loaderPrivate = data; - - pcp->dri2.draw_stamp = 0; - pcp->dri2.read_stamp = 0; - - pcp->hHWContext = hwContext; - - if ( !(*psp->DriverAPI.CreateContext)(API_OPENGL, - &config->modes, pcp, shareCtx) ) { - free(pcp); - return NULL; - } - - return pcp; -} - -static unsigned int -dri2GetAPIMask(__DRIscreen *screen) -{ - return screen->api_mask; -} - -static __DRIcontext * -dri2CreateNewContextForAPI(__DRIscreen *screen, int api, - const __DRIconfig *config, - __DRIcontext *shared, void *data) -{ - __DRIcontext *context; - const struct gl_config *modes = (config != NULL) ? &config->modes : NULL; - void *shareCtx = (shared != NULL) ? shared->driverPrivate : NULL; - gl_api mesa_api; - - if (!(screen->api_mask & (1 << api))) - return NULL; - - switch (api) { - case __DRI_API_OPENGL: - mesa_api = API_OPENGL; - break; - case __DRI_API_GLES: - mesa_api = API_OPENGLES; - break; - case __DRI_API_GLES2: - mesa_api = API_OPENGLES2; - break; - default: - return NULL; - } - - context = malloc(sizeof *context); - if (!context) - return NULL; - - context->driScreenPriv = screen; - context->driDrawablePriv = NULL; - context->loaderPrivate = data; - - if (!(*screen->DriverAPI.CreateContext)(mesa_api, modes, - context, shareCtx) ) { - free(context); - return NULL; - } - - return context; -} - - -static __DRIcontext * -dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config, - __DRIcontext *shared, void *data) -{ - return dri2CreateNewContextForAPI(screen, __DRI_API_OPENGL, - config, shared, data); -} - -static int -driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask) -{ - return GL_FALSE; -} - -/*@}*/ - - -/*****************************************************************/ -/** \name Screen handling functions */ -/*****************************************************************/ -/*@{*/ - -/** - * Destroy the per-screen private information. - * - * \internal - * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls - * drmClose(), and finally frees \p screenPrivate. - */ -static void driDestroyScreen(__DRIscreen *psp) -{ - if (psp) { - /* No interaction with the X-server is possible at this point. This - * routine is called after XCloseDisplay, so there is no protocol - * stream open to the X-server anymore. - */ - - _mesa_destroy_shader_compiler(); - - if (psp->DriverAPI.DestroyScreen) - (*psp->DriverAPI.DestroyScreen)(psp); - - if (!psp->dri2.enabled) { - (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX); - (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize); - (void)drmCloseOnce(psp->fd); - } else { - driDestroyOptionCache(&psp->optionCache); - driDestroyOptionInfo(&psp->optionInfo); - } - - free(psp); - } -} - -static void -setupLoaderExtensions(__DRIscreen *psp, - const __DRIextension **extensions) -{ - int i; - - for (i = 0; extensions[i]; i++) { - if (strcmp(extensions[i]->name, __DRI_GET_DRAWABLE_INFO) == 0) - psp->getDrawableInfo = (__DRIgetDrawableInfoExtension *) extensions[i]; - if (strcmp(extensions[i]->name, __DRI_DAMAGE) == 0) - psp->damage = (__DRIdamageExtension *) extensions[i]; - if (strcmp(extensions[i]->name, __DRI_SYSTEM_TIME) == 0) - psp->systemTime = (__DRIsystemTimeExtension *) extensions[i]; - if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0) - psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i]; - if (strcmp(extensions[i]->name, __DRI_IMAGE_LOOKUP) == 0) - psp->dri2.image = (__DRIimageLookupExtension *) extensions[i]; - if (strcmp(extensions[i]->name, __DRI_USE_INVALIDATE) == 0) - psp->dri2.useInvalidate = (__DRIuseInvalidateExtension *) extensions[i]; - } -} - -/** - * This is the bootstrap function for the driver. libGL supplies all of the - * requisite information about the system, and the driver initializes itself. - * This routine also fills in the linked list pointed to by \c driver_modes - * with the \c struct gl_config that the driver can support for windows or - * pbuffers. - * - * For legacy DRI. - * - * \param scrn Index of the screen - * \param ddx_version Version of the 2D DDX. This may not be meaningful for - * all drivers. - * \param dri_version Version of the "server-side" DRI. - * \param drm_version Version of the kernel DRM. - * \param frame_buffer Data describing the location and layout of the - * framebuffer. - * \param pSAREA Pointer to the SAREA. - * \param fd Device handle for the DRM. - * \param extensions ?? - * \param driver_modes Returns modes suppoted by the driver - * \param loaderPrivate ?? - * - * \note There is no need to check the minimum API version in this - * function. Since the name of this function is versioned, it is - * impossible for a loader that is too old to even load this driver. - */ -static __DRIscreen * -driCreateNewScreen(int scrn, - const __DRIversion *ddx_version, - const __DRIversion *dri_version, - const __DRIversion *drm_version, - const __DRIframebuffer *frame_buffer, - drmAddress pSAREA, int fd, - const __DRIextension **extensions, - const __DRIconfig ***driver_modes, - void *loaderPrivate) -{ - static const __DRIextension *emptyExtensionList[] = { NULL }; - __DRIscreen *psp; - - if (driDriverAPI.InitScreen == NULL) - return NULL; - - psp = calloc(1, sizeof *psp); - if (!psp) - return NULL; - - setupLoaderExtensions(psp, extensions); - - /* - ** NOT_DONE: This is used by the X server to detect when the client - ** has died while holding the drawable lock. The client sets the - ** drawable lock to this value. - */ - psp->drawLockID = 1; - - psp->drm_version = *drm_version; - psp->ddx_version = *ddx_version; - psp->dri_version = *dri_version; - - psp->pSAREA = pSAREA; - psp->lock = (drmLock *) &psp->pSAREA->lock; - - psp->pFB = frame_buffer->base; - psp->fbSize = frame_buffer->size; - psp->fbStride = frame_buffer->stride; - psp->fbWidth = frame_buffer->width; - psp->fbHeight = frame_buffer->height; - psp->devPrivSize = frame_buffer->dev_priv_size; - psp->pDevPriv = frame_buffer->dev_priv; - psp->fbBPP = psp->fbStride * 8 / frame_buffer->width; - - psp->extensions = emptyExtensionList; - psp->fd = fd; - psp->myNum = scrn; - psp->dri2.enabled = GL_FALSE; - - psp->DriverAPI = driDriverAPI; - psp->api_mask = (1 << __DRI_API_OPENGL); - - *driver_modes = driDriverAPI.InitScreen(psp); - if (*driver_modes == NULL) { - free(psp); - return NULL; - } - - return psp; -} - -/** - * DRI2 - */ -static __DRIscreen * -dri2CreateNewScreen(int scrn, int fd, - const __DRIextension **extensions, - const __DRIconfig ***driver_configs, void *data) -{ - static const __DRIextension *emptyExtensionList[] = { NULL }; - __DRIscreen *psp; - drmVersionPtr version; - - if (driDriverAPI.InitScreen2 == NULL) - return NULL; - - psp = calloc(1, sizeof(*psp)); - if (!psp) - return NULL; - - setupLoaderExtensions(psp, extensions); - - version = drmGetVersion(fd); - if (version) { - psp->drm_version.major = version->version_major; - psp->drm_version.minor = version->version_minor; - psp->drm_version.patch = version->version_patchlevel; - drmFreeVersion(version); - } - - psp->extensions = emptyExtensionList; - psp->fd = fd; - psp->myNum = scrn; - psp->dri2.enabled = GL_TRUE; - - psp->DriverAPI = driDriverAPI; - psp->api_mask = (1 << __DRI_API_OPENGL); - *driver_configs = driDriverAPI.InitScreen2(psp); - if (*driver_configs == NULL) { - free(psp); - return NULL; - } - - psp->DriverAPI = driDriverAPI; - psp->loaderPrivate = data; - - driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions, - __dri2NConfigOptions); - driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum, - "dri2"); - - return psp; -} - -static const __DRIextension **driGetExtensions(__DRIscreen *psp) -{ - return psp->extensions; -} - -/** Core interface */ -const __DRIcoreExtension driCoreExtension = { - { __DRI_CORE, __DRI_CORE_VERSION }, - NULL, - driDestroyScreen, - driGetExtensions, - driGetConfigAttrib, - driIndexConfigAttrib, - NULL, - driDestroyDrawable, - driSwapBuffers, - NULL, - driCopyContext, - driDestroyContext, - driBindContext, - driUnbindContext -}; - -/** Legacy DRI interface */ -const __DRIlegacyExtension driLegacyExtension = { - { __DRI_LEGACY, __DRI_LEGACY_VERSION }, - driCreateNewScreen, - driCreateNewDrawable, - driCreateNewContext, -}; - -/** DRI2 interface */ -const __DRIdri2Extension driDRI2Extension = { - { __DRI_DRI2, __DRI_DRI2_VERSION }, - dri2CreateNewScreen, - dri2CreateNewDrawable, - dri2CreateNewContext, - dri2GetAPIMask, - dri2CreateNewContextForAPI, - dri2AllocateBuffer, - dri2ReleaseBuffer -}; - -const __DRI2configQueryExtension dri2ConfigQueryExtension = { - { __DRI2_CONFIG_QUERY, __DRI2_CONFIG_QUERY_VERSION }, - dri2ConfigQueryb, - dri2ConfigQueryi, - dri2ConfigQueryf, -}; - -/** - * Calculate amount of swap interval used between GLX buffer swaps. - * - * The usage value, on the range [0,max], is the fraction of total swap - * interval time used between GLX buffer swaps is calculated. - * - * \f$p = t_d / (i * t_r)\f$ - * - * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the - * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time - * required for a single vertical refresh period (as returned by \c - * glXGetMscRateOML). - * - * See the documentation for the GLX_MESA_swap_frame_usage extension for more - * details. - * - * \param dPriv Pointer to the private drawable structure. - * \return If less than a single swap interval time period was required - * between GLX buffer swaps, a number greater than 0 and less than - * 1.0 is returned. If exactly one swap interval time period is - * required, 1.0 is returned, and if more than one is required then - * a number greater than 1.0 will be returned. - * - * \sa glXSwapIntervalSGI glXGetMscRateOML - * - * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it - * be possible to cache the sync rate? - */ -float -driCalculateSwapUsage( __DRIdrawable *dPriv, int64_t last_swap_ust, - int64_t current_ust ) -{ - int32_t n; - int32_t d; - int interval; - float usage = 1.0; - __DRIscreen *psp = dPriv->driScreenPriv; - - if ( (*psp->systemTime->getMSCRate)(dPriv, &n, &d, dPriv->loaderPrivate) ) { - interval = (dPriv->swap_interval != 0) ? dPriv->swap_interval : 1; - - - /* We want to calculate - * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get - * current_UST by calling __glXGetUST. last_swap_UST is stored in - * dPriv->swap_ust. interval has already been calculated. - * - * The only tricky part is us_per_refresh. us_per_refresh is - * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it - * around and say us_per_refresh = 1000000 * d / n. Since this goes in - * the denominator of the final calculation, we calculate - * (interval * 1000000 * d) and move n into the numerator. - */ - - usage = (current_ust - last_swap_ust); - usage *= n; - usage /= (interval * d); - usage /= 1000000.0; - } - - return usage; -} - -void -dri2InvalidateDrawable(__DRIdrawable *drawable) -{ - drawable->dri2.stamp++; -} - -/*@}*/ +/**
+ * \file dri_util.c
+ * DRI utility functions.
+ *
+ * This module acts as glue between GLX and the actual hardware driver. A DRI
+ * driver doesn't really \e have to use any of this - it's optional. But, some
+ * useful stuff is done here that otherwise would have to be duplicated in most
+ * drivers.
+ *
+ * Basically, these utility functions take care of some of the dirty details of
+ * screen initialization, context creation, context binding, DRM setup, etc.
+ *
+ * These functions are compiled into each DRI driver so libGL.so knows nothing
+ * about them.
+ */
+
+
+#include <assert.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <stdio.h>
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+#include "main/imports.h"
+#define None 0
+
+#include "dri_util.h"
+#include "drm_sarea.h"
+#include "utils.h"
+#include "xmlpool.h"
+#include "../glsl/glsl_parser_extras.h"
+
+PUBLIC const char __dri2ConfigOptions[] =
+ DRI_CONF_BEGIN
+ DRI_CONF_SECTION_PERFORMANCE
+ DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1)
+ DRI_CONF_SECTION_END
+ DRI_CONF_END;
+
+static const uint __dri2NConfigOptions = 1;
+
+#ifndef GLX_OML_sync_control
+typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRIdrawable *drawable, int32_t *numerator, int32_t *denominator);
+#endif
+
+static void dri_get_drawable(__DRIdrawable *pdp);
+static void dri_put_drawable(__DRIdrawable *pdp);
+
+/**
+ * This is just a token extension used to signal that the driver
+ * supports setting a read drawable.
+ */
+const __DRIextension driReadDrawableExtension = {
+ __DRI_READ_DRAWABLE, __DRI_READ_DRAWABLE_VERSION
+};
+
+GLint
+driIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 )
+{
+ if (rect2.x1 > rect1.x1) rect1.x1 = rect2.x1;
+ if (rect2.x2 < rect1.x2) rect1.x2 = rect2.x2;
+ if (rect2.y1 > rect1.y1) rect1.y1 = rect2.y1;
+ if (rect2.y2 < rect1.y2) rect1.y2 = rect2.y2;
+
+ if (rect1.x1 > rect1.x2 || rect1.y1 > rect1.y2) return 0;
+
+ return (rect1.x2 - rect1.x1) * (rect1.y2 - rect1.y1);
+}
+
+/*****************************************************************/
+/** \name Context (un)binding functions */
+/*****************************************************************/
+/*@{*/
+
+/**
+ * Unbind context.
+ *
+ * \param scrn the screen.
+ * \param gc context.
+ *
+ * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::UnbindContext, and then decrements
+ * __DRIdrawableRec::refcount which must be non-zero for a successful
+ * return.
+ *
+ * While casting the opaque private pointers associated with the parameters
+ * into their respective real types it also assures they are not \c NULL.
+ */
+static int driUnbindContext(__DRIcontext *pcp)
+{
+ __DRIscreen *psp;
+ __DRIdrawable *pdp;
+ __DRIdrawable *prp;
+
+ /*
+ ** Assume error checking is done properly in glXMakeCurrent before
+ ** calling driUnbindContext.
+ */
+
+ if (pcp == NULL)
+ return GL_FALSE;
+
+ psp = pcp->driScreenPriv;
+ pdp = pcp->driDrawablePriv;
+ prp = pcp->driReadablePriv;
+
+ /* already unbound */
+ if (!pdp && !prp)
+ return GL_TRUE;
+ /* Let driver unbind drawable from context */
+ (*psp->DriverAPI.UnbindContext)(pcp);
+
+ assert(pdp);
+ if (pdp->refcount == 0) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ dri_put_drawable(pdp);
+
+ if (prp != pdp) {
+ if (prp->refcount == 0) {
+ /* ERROR!!! */
+ return GL_FALSE;
+ }
+
+ dri_put_drawable(prp);
+ }
+
+
+ /* XXX this is disabled so that if we call SwapBuffers on an unbound
+ * window we can determine the last context bound to the window and
+ * use that context's lock. (BrianP, 2-Dec-2000)
+ */
+ pcp->driDrawablePriv = pcp->driReadablePriv = NULL;
+
+ return GL_TRUE;
+}
+
+/**
+ * This function takes both a read buffer and a draw buffer. This is needed
+ * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
+ * function.
+ */
+static int driBindContext(__DRIcontext *pcp,
+ __DRIdrawable *pdp,
+ __DRIdrawable *prp)
+{
+ __DRIscreen *psp = NULL;
+
+ /*
+ ** Assume error checking is done properly in glXMakeCurrent before
+ ** calling driUnbindContext.
+ */
+
+ if (!pcp)
+ return GL_FALSE;
+
+ /* Bind the drawable to the context */
+ psp = pcp->driScreenPriv;
+ pcp->driDrawablePriv = pdp;
+ pcp->driReadablePriv = prp;
+ if (pdp) {
+ pdp->driContextPriv = pcp;
+ dri_get_drawable(pdp);
+ }
+ if (prp && pdp != prp) {
+ dri_get_drawable(prp);
+ }
+
+ /*
+ ** Now that we have a context associated with this drawable, we can
+ ** initialize the drawable information if has not been done before.
+ */
+
+ if (!psp->dri2.enabled) {
+ if (pdp && !pdp->pStamp) {
+ DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
+ __driUtilUpdateDrawableInfo(pdp);
+ DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
+ }
+ if (prp && pdp != prp && !prp->pStamp) {
+ DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
+ __driUtilUpdateDrawableInfo(prp);
+ DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
+ }
+ }
+
+ /* Call device-specific MakeCurrent */
+ return (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp);
+}
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Drawable handling functions */
+/*****************************************************************/
+/*@{*/
+
+/**
+ * Update private drawable information.
+ *
+ * \param pdp pointer to the private drawable information to update.
+ *
+ * This function basically updates the __DRIdrawable struct's
+ * cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo.
+ * This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which
+ * compares the __DRIdrwablePrivate pStamp and lastStamp values. If
+ * the values are different that means we have to update the clipping
+ * info.
+ */
+void
+__driUtilUpdateDrawableInfo(__DRIdrawable *pdp)
+{
+ __DRIscreen *psp = pdp->driScreenPriv;
+ __DRIcontext *pcp = pdp->driContextPriv;
+
+ if (!pcp
+ || ((pdp != pcp->driDrawablePriv) && (pdp != pcp->driReadablePriv))) {
+ /* ERROR!!!
+ * ...but we must ignore it. There can be many contexts bound to a
+ * drawable.
+ */
+ }
+
+ if (pdp->pClipRects) {
+ free(pdp->pClipRects);
+ pdp->pClipRects = NULL;
+ }
+
+ if (pdp->pBackClipRects) {
+ free(pdp->pBackClipRects);
+ pdp->pBackClipRects = NULL;
+ }
+
+ DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
+
+ if (! (*psp->getDrawableInfo->getDrawableInfo)(pdp,
+ &pdp->index, &pdp->lastStamp,
+ &pdp->x, &pdp->y, &pdp->w, &pdp->h,
+ &pdp->numClipRects, &pdp->pClipRects,
+ &pdp->backX,
+ &pdp->backY,
+ &pdp->numBackClipRects,
+ &pdp->pBackClipRects,
+ pdp->loaderPrivate)) {
+ /* Error -- eg the window may have been destroyed. Keep going
+ * with no cliprects.
+ */
+ pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */
+ pdp->numClipRects = 0;
+ pdp->pClipRects = NULL;
+ pdp->numBackClipRects = 0;
+ pdp->pBackClipRects = NULL;
+ }
+ else
+ pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp);
+
+ DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
+}
+
+/*@}*/
+
+/*****************************************************************/
+/** \name GLX callbacks */
+/*****************************************************************/
+/*@{*/
+
+static void driReportDamage(__DRIdrawable *pdp,
+ struct drm_clip_rect *pClipRects, int numClipRects)
+{
+ __DRIscreen *psp = pdp->driScreenPriv;
+
+ /* Check that we actually have the new damage report method */
+ if (psp->damage) {
+ /* Report the damage. Currently, all our drivers draw
+ * directly to the front buffer, so we report the damage there
+ * rather than to the backing storein (if any).
+ */
+ (*psp->damage->reportDamage)(pdp,
+ pdp->x, pdp->y,
+ pClipRects, numClipRects,
+ GL_TRUE, pdp->loaderPrivate);
+ }
+}
+
+
+/**
+ * Swap buffers.
+ *
+ * \param drawablePrivate opaque pointer to the per-drawable private info.
+ *
+ * \internal
+ * This function calls __DRIdrawable::swapBuffers.
+ *
+ * Is called directly from glXSwapBuffers().
+ */
+static void driSwapBuffers(__DRIdrawable *dPriv)
+{
+ __DRIscreen *psp = dPriv->driScreenPriv;
+ drm_clip_rect_t *rects;
+ int i;
+
+ psp->DriverAPI.SwapBuffers(dPriv);
+
+ if (!dPriv->numClipRects)
+ return;
+
+ rects = malloc(sizeof(*rects) * dPriv->numClipRects);
+
+ if (!rects)
+ return;
+
+ for (i = 0; i < dPriv->numClipRects; i++) {
+ rects[i].x1 = dPriv->pClipRects[i].x1 - dPriv->x;
+ rects[i].y1 = dPriv->pClipRects[i].y1 - dPriv->y;
+ rects[i].x2 = dPriv->pClipRects[i].x2 - dPriv->x;
+ rects[i].y2 = dPriv->pClipRects[i].y2 - dPriv->y;
+ }
+
+ driReportDamage(dPriv, rects, dPriv->numClipRects);
+ free(rects);
+}
+
+static int driDrawableGetMSC( __DRIscreen *sPriv, __DRIdrawable *dPriv,
+ int64_t *msc )
+{
+ return sPriv->DriverAPI.GetDrawableMSC(sPriv, dPriv, msc);
+}
+
+
+static int driWaitForMSC(__DRIdrawable *dPriv, int64_t target_msc,
+ int64_t divisor, int64_t remainder,
+ int64_t * msc, int64_t * sbc)
+{
+ __DRIswapInfo sInfo;
+ int status;
+
+ status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc,
+ divisor, remainder,
+ msc );
+
+ /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync
+ * is supported but GLX_OML_sync_control is not. Therefore, don't return
+ * an error value if GetSwapInfo() is not implemented.
+ */
+ if ( status == 0
+ && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) {
+ status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo );
+ *sbc = sInfo.swap_count;
+ }
+
+ return status;
+}
+
+
+const __DRImediaStreamCounterExtension driMediaStreamCounterExtension = {
+ { __DRI_MEDIA_STREAM_COUNTER, __DRI_MEDIA_STREAM_COUNTER_VERSION },
+ driWaitForMSC,
+ driDrawableGetMSC,
+};
+
+
+static void driCopySubBuffer(__DRIdrawable *dPriv,
+ int x, int y, int w, int h)
+{
+ drm_clip_rect_t rect;
+
+ rect.x1 = x;
+ rect.y1 = dPriv->h - y - h;
+ rect.x2 = x + w;
+ rect.y2 = rect.y1 + h;
+ driReportDamage(dPriv, &rect, 1);
+
+ dPriv->driScreenPriv->DriverAPI.CopySubBuffer(dPriv, x, y, w, h);
+}
+
+const __DRIcopySubBufferExtension driCopySubBufferExtension = {
+ { __DRI_COPY_SUB_BUFFER, __DRI_COPY_SUB_BUFFER_VERSION },
+ driCopySubBuffer
+};
+
+static void driSetSwapInterval(__DRIdrawable *dPriv, unsigned int interval)
+{
+ dPriv->swap_interval = interval;
+}
+
+static unsigned int driGetSwapInterval(__DRIdrawable *dPriv)
+{
+ return dPriv->swap_interval;
+}
+
+const __DRIswapControlExtension driSwapControlExtension = {
+ { __DRI_SWAP_CONTROL, __DRI_SWAP_CONTROL_VERSION },
+ driSetSwapInterval,
+ driGetSwapInterval
+};
+
+
+/**
+ * This is called via __DRIscreenRec's createNewDrawable pointer.
+ */
+static __DRIdrawable *
+driCreateNewDrawable(__DRIscreen *psp, const __DRIconfig *config,
+ drm_drawable_t hwDrawable, int renderType,
+ const int *attrs, void *data)
+{
+ __DRIdrawable *pdp;
+
+ /* Since pbuffers are not yet supported, no drawable attributes are
+ * supported either.
+ */
+ (void) attrs;
+
+ pdp = malloc(sizeof *pdp);
+ if (!pdp) {
+ return NULL;
+ }
+
+ pdp->driContextPriv = NULL;
+ pdp->loaderPrivate = data;
+ pdp->hHWDrawable = hwDrawable;
+ pdp->refcount = 1;
+ pdp->pStamp = NULL;
+ pdp->lastStamp = 0;
+ pdp->index = 0;
+ pdp->x = 0;
+ pdp->y = 0;
+ pdp->w = 0;
+ pdp->h = 0;
+ pdp->numClipRects = 0;
+ pdp->numBackClipRects = 0;
+ pdp->pClipRects = NULL;
+ pdp->pBackClipRects = NULL;
+ pdp->vblSeq = 0;
+ pdp->vblFlags = 0;
+
+ pdp->driScreenPriv = psp;
+
+ if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, &config->modes, 0)) {
+ free(pdp);
+ return NULL;
+ }
+
+ pdp->msc_base = 0;
+
+ /* This special default value is replaced with the configured
+ * default value when the drawable is first bound to a direct
+ * rendering context.
+ */
+ pdp->swap_interval = (unsigned)-1;
+
+ return pdp;
+}
+
+
+static __DRIdrawable *
+dri2CreateNewDrawable(__DRIscreen *screen,
+ const __DRIconfig *config,
+ void *loaderPrivate)
+{
+ __DRIdrawable *pdraw;
+
+ pdraw = driCreateNewDrawable(screen, config, 0, 0, NULL, loaderPrivate);
+ if (!pdraw)
+ return NULL;
+
+ pdraw->pClipRects = &pdraw->dri2.clipRect;
+ pdraw->pBackClipRects = &pdraw->dri2.clipRect;
+
+ pdraw->pStamp = &pdraw->dri2.stamp;
+ *pdraw->pStamp = pdraw->lastStamp + 1;
+
+ 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)
+{
+ if (!driCheckOption(&screen->optionCache, var, DRI_BOOL))
+ return -1;
+
+ *val = driQueryOptionb(&screen->optionCache, var);
+
+ return 0;
+}
+
+static int
+dri2ConfigQueryi(__DRIscreen *screen, const char *var, GLint *val)
+{
+ if (!driCheckOption(&screen->optionCache, var, DRI_INT) &&
+ !driCheckOption(&screen->optionCache, var, DRI_ENUM))
+ return -1;
+
+ *val = driQueryOptioni(&screen->optionCache, var);
+
+ return 0;
+}
+
+static int
+dri2ConfigQueryf(__DRIscreen *screen, const char *var, GLfloat *val)
+{
+ if (!driCheckOption(&screen->optionCache, var, DRI_FLOAT))
+ return -1;
+
+ *val = driQueryOptionf(&screen->optionCache, var);
+
+ return 0;
+}
+
+
+static void dri_get_drawable(__DRIdrawable *pdp)
+{
+ pdp->refcount++;
+}
+
+static void dri_put_drawable(__DRIdrawable *pdp)
+{
+ __DRIscreen *psp;
+
+ if (pdp) {
+ pdp->refcount--;
+ if (pdp->refcount)
+ return;
+
+ psp = pdp->driScreenPriv;
+ (*psp->DriverAPI.DestroyBuffer)(pdp);
+ if (pdp->pClipRects && pdp->pClipRects != &pdp->dri2.clipRect) {
+ free(pdp->pClipRects);
+ pdp->pClipRects = NULL;
+ }
+ if (pdp->pBackClipRects && pdp->pClipRects != &pdp->dri2.clipRect) {
+ free(pdp->pBackClipRects);
+ pdp->pBackClipRects = NULL;
+ }
+ free(pdp);
+ }
+}
+
+static void
+driDestroyDrawable(__DRIdrawable *pdp)
+{
+ dri_put_drawable(pdp);
+}
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Context handling functions */
+/*****************************************************************/
+/*@{*/
+
+/**
+ * Destroy the per-context private information.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
+ * drmDestroyContext(), and finally frees \p contextPrivate.
+ */
+static void
+driDestroyContext(__DRIcontext *pcp)
+{
+ if (pcp) {
+ (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
+ free(pcp);
+ }
+}
+
+
+/**
+ * Create the per-drawable private driver information.
+ *
+ * \param render_type Type of rendering target. \c GLX_RGBA is the only
+ * type likely to ever be supported for direct-rendering.
+ * \param shared Context with which to share textures, etc. or NULL
+ *
+ * \returns An opaque pointer to the per-context private information on
+ * success, or \c NULL on failure.
+ *
+ * \internal
+ * This function allocates and fills a __DRIcontextRec structure. It
+ * performs some device independent initialization and passes all the
+ * relevent information to __DriverAPIRec::CreateContext to create the
+ * context.
+ *
+ */
+static __DRIcontext *
+driCreateNewContext(__DRIscreen *psp, const __DRIconfig *config,
+ int render_type, __DRIcontext *shared,
+ drm_context_t hwContext, void *data)
+{
+ __DRIcontext *pcp;
+ void * const shareCtx = (shared != NULL) ? shared->driverPrivate : NULL;
+
+ pcp = malloc(sizeof *pcp);
+ if (!pcp)
+ return NULL;
+
+ pcp->driScreenPriv = psp;
+ pcp->driDrawablePriv = NULL;
+ pcp->loaderPrivate = data;
+
+ pcp->dri2.draw_stamp = 0;
+ pcp->dri2.read_stamp = 0;
+
+ pcp->hHWContext = hwContext;
+
+ if ( !(*psp->DriverAPI.CreateContext)(API_OPENGL,
+ &config->modes, pcp, shareCtx) ) {
+ free(pcp);
+ return NULL;
+ }
+
+ return pcp;
+}
+
+static unsigned int
+dri2GetAPIMask(__DRIscreen *screen)
+{
+ return screen->api_mask;
+}
+
+static __DRIcontext *
+dri2CreateNewContextForAPI(__DRIscreen *screen, int api,
+ const __DRIconfig *config,
+ __DRIcontext *shared, void *data)
+{
+ __DRIcontext *context;
+ const struct gl_config *modes = (config != NULL) ? &config->modes : NULL;
+ void *shareCtx = (shared != NULL) ? shared->driverPrivate : NULL;
+ gl_api mesa_api;
+
+ if (!(screen->api_mask & (1 << api)))
+ return NULL;
+
+ switch (api) {
+ case __DRI_API_OPENGL:
+ mesa_api = API_OPENGL;
+ break;
+ case __DRI_API_GLES:
+ mesa_api = API_OPENGLES;
+ break;
+ case __DRI_API_GLES2:
+ mesa_api = API_OPENGLES2;
+ break;
+ default:
+ return NULL;
+ }
+
+ context = malloc(sizeof *context);
+ if (!context)
+ return NULL;
+
+ context->driScreenPriv = screen;
+ context->driDrawablePriv = NULL;
+ context->loaderPrivate = data;
+
+ if (!(*screen->DriverAPI.CreateContext)(mesa_api, modes,
+ context, shareCtx) ) {
+ free(context);
+ return NULL;
+ }
+
+ return context;
+}
+
+
+static __DRIcontext *
+dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config,
+ __DRIcontext *shared, void *data)
+{
+ return dri2CreateNewContextForAPI(screen, __DRI_API_OPENGL,
+ config, shared, data);
+}
+
+static int
+driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask)
+{
+ return GL_FALSE;
+}
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Screen handling functions */
+/*****************************************************************/
+/*@{*/
+
+/**
+ * Destroy the per-screen private information.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
+ * drmClose(), and finally frees \p screenPrivate.
+ */
+static void driDestroyScreen(__DRIscreen *psp)
+{
+ if (psp) {
+ /* No interaction with the X-server is possible at this point. This
+ * routine is called after XCloseDisplay, so there is no protocol
+ * stream open to the X-server anymore.
+ */
+
+ _mesa_destroy_shader_compiler();
+
+ if (psp->DriverAPI.DestroyScreen)
+ (*psp->DriverAPI.DestroyScreen)(psp);
+
+ if (!psp->dri2.enabled) {
+ (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX);
+ (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
+ (void)drmCloseOnce(psp->fd);
+ } else {
+ driDestroyOptionCache(&psp->optionCache);
+ driDestroyOptionInfo(&psp->optionInfo);
+ }
+
+ free(psp);
+ }
+}
+
+static void
+setupLoaderExtensions(__DRIscreen *psp,
+ const __DRIextension **extensions)
+{
+ int i;
+
+ for (i = 0; extensions[i]; i++) {
+ if (strcmp(extensions[i]->name, __DRI_GET_DRAWABLE_INFO) == 0)
+ psp->getDrawableInfo = (__DRIgetDrawableInfoExtension *) extensions[i];
+ if (strcmp(extensions[i]->name, __DRI_DAMAGE) == 0)
+ psp->damage = (__DRIdamageExtension *) extensions[i];
+ if (strcmp(extensions[i]->name, __DRI_SYSTEM_TIME) == 0)
+ psp->systemTime = (__DRIsystemTimeExtension *) extensions[i];
+ if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0)
+ psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i];
+ if (strcmp(extensions[i]->name, __DRI_IMAGE_LOOKUP) == 0)
+ psp->dri2.image = (__DRIimageLookupExtension *) extensions[i];
+ if (strcmp(extensions[i]->name, __DRI_USE_INVALIDATE) == 0)
+ psp->dri2.useInvalidate = (__DRIuseInvalidateExtension *) extensions[i];
+ }
+}
+
+/**
+ * This is the bootstrap function for the driver. libGL supplies all of the
+ * requisite information about the system, and the driver initializes itself.
+ * This routine also fills in the linked list pointed to by \c driver_modes
+ * with the \c struct gl_config that the driver can support for windows or
+ * pbuffers.
+ *
+ * For legacy DRI.
+ *
+ * \param scrn Index of the screen
+ * \param ddx_version Version of the 2D DDX. This may not be meaningful for
+ * all drivers.
+ * \param dri_version Version of the "server-side" DRI.
+ * \param drm_version Version of the kernel DRM.
+ * \param frame_buffer Data describing the location and layout of the
+ * framebuffer.
+ * \param pSAREA Pointer to the SAREA.
+ * \param fd Device handle for the DRM.
+ * \param extensions ??
+ * \param driver_modes Returns modes suppoted by the driver
+ * \param loaderPrivate ??
+ *
+ * \note There is no need to check the minimum API version in this
+ * function. Since the name of this function is versioned, it is
+ * impossible for a loader that is too old to even load this driver.
+ */
+static __DRIscreen *
+driCreateNewScreen(int scrn,
+ const __DRIversion *ddx_version,
+ const __DRIversion *dri_version,
+ const __DRIversion *drm_version,
+ const __DRIframebuffer *frame_buffer,
+ drmAddress pSAREA, int fd,
+ const __DRIextension **extensions,
+ const __DRIconfig ***driver_modes,
+ void *loaderPrivate)
+{
+ static const __DRIextension *emptyExtensionList[] = { NULL };
+ __DRIscreen *psp;
+
+ if (driDriverAPI.InitScreen == NULL)
+ return NULL;
+
+ psp = calloc(1, sizeof *psp);
+ if (!psp)
+ return NULL;
+
+ setupLoaderExtensions(psp, extensions);
+
+ /*
+ ** NOT_DONE: This is used by the X server to detect when the client
+ ** has died while holding the drawable lock. The client sets the
+ ** drawable lock to this value.
+ */
+ psp->drawLockID = 1;
+
+ psp->drm_version = *drm_version;
+ psp->ddx_version = *ddx_version;
+ psp->dri_version = *dri_version;
+
+ psp->pSAREA = pSAREA;
+ psp->lock = (drmLock *) &psp->pSAREA->lock;
+
+ psp->pFB = frame_buffer->base;
+ psp->fbSize = frame_buffer->size;
+ psp->fbStride = frame_buffer->stride;
+ psp->fbWidth = frame_buffer->width;
+ psp->fbHeight = frame_buffer->height;
+ psp->devPrivSize = frame_buffer->dev_priv_size;
+ psp->pDevPriv = frame_buffer->dev_priv;
+ psp->fbBPP = psp->fbStride * 8 / frame_buffer->width;
+
+ psp->extensions = emptyExtensionList;
+ psp->fd = fd;
+ psp->myNum = scrn;
+ psp->dri2.enabled = GL_FALSE;
+
+ psp->DriverAPI = driDriverAPI;
+ psp->api_mask = (1 << __DRI_API_OPENGL);
+
+ *driver_modes = driDriverAPI.InitScreen(psp);
+ if (*driver_modes == NULL) {
+ free(psp);
+ return NULL;
+ }
+
+ return psp;
+}
+
+/**
+ * DRI2
+ */
+static __DRIscreen *
+dri2CreateNewScreen(int scrn, int fd,
+ const __DRIextension **extensions,
+ const __DRIconfig ***driver_configs, void *data)
+{
+ static const __DRIextension *emptyExtensionList[] = { NULL };
+ __DRIscreen *psp;
+ drmVersionPtr version;
+
+ if (driDriverAPI.InitScreen2 == NULL)
+ return NULL;
+
+ psp = calloc(1, sizeof(*psp));
+ if (!psp)
+ return NULL;
+
+ setupLoaderExtensions(psp, extensions);
+
+ version = drmGetVersion(fd);
+ if (version) {
+ psp->drm_version.major = version->version_major;
+ psp->drm_version.minor = version->version_minor;
+ psp->drm_version.patch = version->version_patchlevel;
+ drmFreeVersion(version);
+ }
+
+ psp->extensions = emptyExtensionList;
+ psp->fd = fd;
+ psp->myNum = scrn;
+ psp->dri2.enabled = GL_TRUE;
+
+ psp->DriverAPI = driDriverAPI;
+ psp->api_mask = (1 << __DRI_API_OPENGL);
+ *driver_configs = driDriverAPI.InitScreen2(psp);
+ if (*driver_configs == NULL) {
+ free(psp);
+ return NULL;
+ }
+
+ psp->DriverAPI = driDriverAPI;
+ psp->loaderPrivate = data;
+
+ driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions,
+ __dri2NConfigOptions);
+ driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum,
+ "dri2");
+
+ return psp;
+}
+
+static const __DRIextension **driGetExtensions(__DRIscreen *psp)
+{
+ return psp->extensions;
+}
+
+/** Core interface */
+const __DRIcoreExtension driCoreExtension = {
+ { __DRI_CORE, __DRI_CORE_VERSION },
+ NULL,
+ driDestroyScreen,
+ driGetExtensions,
+ driGetConfigAttrib,
+ driIndexConfigAttrib,
+ NULL,
+ driDestroyDrawable,
+ driSwapBuffers,
+ NULL,
+ driCopyContext,
+ driDestroyContext,
+ driBindContext,
+ driUnbindContext
+};
+
+/** Legacy DRI interface */
+const __DRIlegacyExtension driLegacyExtension = {
+ { __DRI_LEGACY, __DRI_LEGACY_VERSION },
+ driCreateNewScreen,
+ driCreateNewDrawable,
+ driCreateNewContext,
+};
+
+/** DRI2 interface */
+const __DRIdri2Extension driDRI2Extension = {
+ { __DRI_DRI2, __DRI_DRI2_VERSION },
+ dri2CreateNewScreen,
+ dri2CreateNewDrawable,
+ dri2CreateNewContext,
+ dri2GetAPIMask,
+ dri2CreateNewContextForAPI,
+ dri2AllocateBuffer,
+ dri2ReleaseBuffer
+};
+
+const __DRI2configQueryExtension dri2ConfigQueryExtension = {
+ { __DRI2_CONFIG_QUERY, __DRI2_CONFIG_QUERY_VERSION },
+ dri2ConfigQueryb,
+ dri2ConfigQueryi,
+ dri2ConfigQueryf,
+};
+
+/**
+ * Calculate amount of swap interval used between GLX buffer swaps.
+ *
+ * The usage value, on the range [0,max], is the fraction of total swap
+ * interval time used between GLX buffer swaps is calculated.
+ *
+ * \f$p = t_d / (i * t_r)\f$
+ *
+ * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
+ * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
+ * required for a single vertical refresh period (as returned by \c
+ * glXGetMscRateOML).
+ *
+ * See the documentation for the GLX_MESA_swap_frame_usage extension for more
+ * details.
+ *
+ * \param dPriv Pointer to the private drawable structure.
+ * \return If less than a single swap interval time period was required
+ * between GLX buffer swaps, a number greater than 0 and less than
+ * 1.0 is returned. If exactly one swap interval time period is
+ * required, 1.0 is returned, and if more than one is required then
+ * a number greater than 1.0 will be returned.
+ *
+ * \sa glXSwapIntervalSGI glXGetMscRateOML
+ *
+ * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
+ * be possible to cache the sync rate?
+ */
+float
+driCalculateSwapUsage( __DRIdrawable *dPriv, int64_t last_swap_ust,
+ int64_t current_ust )
+{
+ int32_t n;
+ int32_t d;
+ int interval;
+ float usage = 1.0;
+ __DRIscreen *psp = dPriv->driScreenPriv;
+
+ if ( (*psp->systemTime->getMSCRate)(dPriv, &n, &d, dPriv->loaderPrivate) ) {
+ interval = (dPriv->swap_interval != 0) ? dPriv->swap_interval : 1;
+
+
+ /* We want to calculate
+ * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
+ * current_UST by calling __glXGetUST. last_swap_UST is stored in
+ * dPriv->swap_ust. interval has already been calculated.
+ *
+ * The only tricky part is us_per_refresh. us_per_refresh is
+ * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
+ * around and say us_per_refresh = 1000000 * d / n. Since this goes in
+ * the denominator of the final calculation, we calculate
+ * (interval * 1000000 * d) and move n into the numerator.
+ */
+
+ usage = (current_ust - last_swap_ust);
+ usage *= n;
+ usage /= (interval * d);
+ usage /= 1000000.0;
+ }
+
+ return usage;
+}
+
+void
+dri2InvalidateDrawable(__DRIdrawable *drawable)
+{
+ drawable->dri2.stamp++;
+}
+
+/*@}*/
diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.h b/mesalib/src/mesa/drivers/dri/common/dri_util.h index 3d3d5c9cd..8d2a38524 100644 --- a/mesalib/src/mesa/drivers/dri/common/dri_util.h +++ b/mesalib/src/mesa/drivers/dri/common/dri_util.h @@ -1,563 +1,563 @@ -/* - * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file dri_util.h - * DRI utility functions definitions. - * - * This module acts as glue between GLX and the actual hardware driver. A DRI - * driver doesn't really \e have to use any of this - it's optional. But, some - * useful stuff is done here that otherwise would have to be duplicated in most - * drivers. - * - * Basically, these utility functions take care of some of the dirty details of - * screen initialization, context creation, context binding, DRM setup, etc. - * - * These functions are compiled into each DRI driver so libGL.so knows nothing - * about them. - * - * \sa dri_util.c. - * - * \author Kevin E. Martin <kevin@precisioninsight.com> - * \author Brian Paul <brian@precisioninsight.com> - */ - -#ifndef _DRI_UTIL_H_ -#define _DRI_UTIL_H_ - -#include <GL/gl.h> -#include <drm.h> -#include <drm_sarea.h> -#include <xf86drm.h> -#include "xmlconfig.h" -#include "main/glheader.h" -#include "main/mtypes.h" -#include "GL/internal/dri_interface.h" - -#define GLX_BAD_CONTEXT 5 - -typedef struct __DRIswapInfoRec __DRIswapInfo; - -/** - * Extensions. - */ -extern const __DRIlegacyExtension driLegacyExtension; -extern const __DRIcoreExtension driCoreExtension; -extern const __DRIdri2Extension driDRI2Extension; -extern const __DRIextension driReadDrawableExtension; -extern const __DRIcopySubBufferExtension driCopySubBufferExtension; -extern const __DRIswapControlExtension driSwapControlExtension; -extern const __DRImediaStreamCounterExtension driMediaStreamCounterExtension; -extern const __DRI2configQueryExtension dri2ConfigQueryExtension; - -/** - * Used by DRI_VALIDATE_DRAWABLE_INFO - */ -#define DRI_VALIDATE_DRAWABLE_INFO_ONCE(pDrawPriv) \ - do { \ - if (*(pDrawPriv->pStamp) != pDrawPriv->lastStamp) { \ - __driUtilUpdateDrawableInfo(pDrawPriv); \ - } \ - } while (0) - - -/** - * Utility macro to validate the drawable information. - * - * See __DRIdrawable::pStamp and __DRIdrawable::lastStamp. - */ -#define DRI_VALIDATE_DRAWABLE_INFO(psp, pdp) \ -do { \ - while (*(pdp->pStamp) != pdp->lastStamp) { \ - register unsigned int hwContext = psp->pSAREA->lock.lock & \ - ~(DRM_LOCK_HELD | DRM_LOCK_CONT); \ - DRM_UNLOCK(psp->fd, &psp->pSAREA->lock, hwContext); \ - \ - DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); \ - DRI_VALIDATE_DRAWABLE_INFO_ONCE(pdp); \ - DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); \ - \ - DRM_LIGHT_LOCK(psp->fd, &psp->pSAREA->lock, hwContext); \ - } \ -} while (0) - -/** - * Same as above, but for two drawables simultaneously. - * - */ - -#define DRI_VALIDATE_TWO_DRAWABLES_INFO(psp, pdp, prp) \ -do { \ - while (*((pdp)->pStamp) != (pdp)->lastStamp || \ - *((prp)->pStamp) != (prp)->lastStamp) { \ - register unsigned int hwContext = (psp)->pSAREA->lock.lock & \ - ~(DRM_LOCK_HELD | DRM_LOCK_CONT); \ - DRM_UNLOCK((psp)->fd, &(psp)->pSAREA->lock, hwContext); \ - \ - DRM_SPINLOCK(&(psp)->pSAREA->drawable_lock, (psp)->drawLockID); \ - DRI_VALIDATE_DRAWABLE_INFO_ONCE(pdp); \ - DRI_VALIDATE_DRAWABLE_INFO_ONCE(prp); \ - DRM_SPINUNLOCK(&(psp)->pSAREA->drawable_lock, (psp)->drawLockID); \ - \ - DRM_LIGHT_LOCK((psp)->fd, &(psp)->pSAREA->lock, hwContext); \ - } \ -} while (0) - - -/** - * Driver callback functions. - * - * Each DRI driver must have one of these structures with all the pointers set - * to appropriate functions within the driver. - * - * When glXCreateContext() is called, for example, it'll call a helper function - * dri_util.c which in turn will jump through the \a CreateContext pointer in - * this structure. - */ -struct __DriverAPIRec { - const __DRIconfig **(*InitScreen) (__DRIscreen * priv); - - /** - * Screen destruction callback - */ - void (*DestroyScreen)(__DRIscreen *driScrnPriv); - - /** - * Context creation callback - */ - GLboolean (*CreateContext)(gl_api api, - const struct gl_config *glVis, - __DRIcontext *driContextPriv, - void *sharedContextPrivate); - - /** - * Context destruction callback - */ - void (*DestroyContext)(__DRIcontext *driContextPriv); - - /** - * Buffer (drawable) creation callback - */ - GLboolean (*CreateBuffer)(__DRIscreen *driScrnPriv, - __DRIdrawable *driDrawPriv, - const struct gl_config *glVis, - GLboolean pixmapBuffer); - - /** - * Buffer (drawable) destruction callback - */ - void (*DestroyBuffer)(__DRIdrawable *driDrawPriv); - - /** - * Buffer swapping callback - */ - void (*SwapBuffers)(__DRIdrawable *driDrawPriv); - - /** - * Context activation callback - */ - GLboolean (*MakeCurrent)(__DRIcontext *driContextPriv, - __DRIdrawable *driDrawPriv, - __DRIdrawable *driReadPriv); - - /** - * Context unbinding callback - */ - GLboolean (*UnbindContext)(__DRIcontext *driContextPriv); - - /** - * Retrieves statistics about buffer swap operations. Required if - * GLX_OML_sync_control or GLX_MESA_swap_frame_usage is supported. - */ - int (*GetSwapInfo)( __DRIdrawable *dPriv, __DRIswapInfo * sInfo ); - - - /** - * These are required if GLX_OML_sync_control is supported. - */ - /*@{*/ - int (*WaitForMSC)( __DRIdrawable *priv, int64_t target_msc, - int64_t divisor, int64_t remainder, - int64_t * msc ); - int (*WaitForSBC)( __DRIdrawable *priv, int64_t target_sbc, - int64_t * msc, int64_t * sbc ); - - int64_t (*SwapBuffersMSC)( __DRIdrawable *priv, int64_t target_msc, - int64_t divisor, int64_t remainder ); - /*@}*/ - void (*CopySubBuffer)(__DRIdrawable *driDrawPriv, - int x, int y, int w, int h); - - /** - * New version of GetMSC so we can pass drawable data to the low - * level DRM driver (e.g. pipe info). Required if - * GLX_SGI_video_sync or GLX_OML_sync_control is supported. - */ - int (*GetDrawableMSC) ( __DRIscreen * priv, - __DRIdrawable *drawablePrivate, - int64_t *count); - - - - /* 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; - - -struct __DRIswapInfoRec { - /** - * Number of swapBuffers operations that have been *completed*. - */ - uint64_t swap_count; - - /** - * Unadjusted system time of the last buffer swap. This is the time - * when the swap completed, not the time when swapBuffers was called. - */ - int64_t swap_ust; - - /** - * Number of swap operations that occurred after the swap deadline. That - * is if a swap happens more than swap_interval frames after the previous - * swap, it has missed its deadline. If swap_interval is 0, then the - * swap deadline is 1 frame after the previous swap. - */ - uint64_t swap_missed_count; - - /** - * Amount of time used by the last swap that missed its deadline. This - * is calculated as (__glXGetUST() - swap_ust) / (swap_interval * - * time_for_single_vrefresh)). If the actual value of swap_interval is - * 0, then 1 is used instead. If swap_missed_count is non-zero, this - * should be greater-than 1.0. - */ - float swap_missed_usage; -}; - - -/** - * Per-drawable private DRI driver information. - */ -struct __DRIdrawableRec { - /** - * Kernel drawable handle - */ - drm_drawable_t hHWDrawable; - - /** - * Driver's private drawable information. - * - * This structure is opaque. - */ - void *driverPrivate; - - /** - * Private data from the loader. We just hold on to it and pass - * it back when calling into loader provided functions. - */ - void *loaderPrivate; - - /** - * Reference count for number of context's currently bound to this - * drawable. - * - * Once it reaches zero, the drawable can be destroyed. - * - * \note This behavior will change with GLX 1.3. - */ - int refcount; - - /** - * Index of this drawable information in the SAREA. - */ - unsigned int index; - - /** - * Pointer to the "drawable has changed ID" stamp in the SAREA (or - * to dri2.stamp if DRI2 is being used). - */ - unsigned int *pStamp; - - /** - * Last value of the stamp. - * - * If this differs from the value stored at __DRIdrawable::pStamp, - * then the drawable information has been modified by the X server, and the - * drawable information (below) should be retrieved from the X server. - */ - unsigned int lastStamp; - - /** - * \name Drawable - * - * Drawable information used in software fallbacks. - */ - /*@{*/ - int x; - int y; - int w; - int h; - int numClipRects; - drm_clip_rect_t *pClipRects; - /*@}*/ - - /** - * \name Back and depthbuffer - * - * Information about the back and depthbuffer where different from above. - */ - /*@{*/ - int backX; - int backY; - int backClipRectType; - int numBackClipRects; - drm_clip_rect_t *pBackClipRects; - /*@}*/ - - /** - * \name Vertical blank tracking information - * Used for waiting on vertical blank events. - */ - /*@{*/ - unsigned int vblSeq; - unsigned int vblFlags; - /*@}*/ - - /** - * \name Monotonic MSC tracking - * - * Low level driver is responsible for updating msc_base and - * vblSeq values so that higher level code can calculate - * a new msc value or msc target for a WaitMSC call. The new value - * will be: - * msc = msc_base + get_vblank_count() - vblank_base; - * - * And for waiting on a value, core code will use: - * actual_target = target_msc - msc_base + vblank_base; - */ - /*@{*/ - int64_t vblank_base; - int64_t msc_base; - /*@}*/ - - /** - * Pointer to context to which this drawable is currently bound. - */ - __DRIcontext *driContextPriv; - - /** - * Pointer to screen on which this drawable was created. - */ - __DRIscreen *driScreenPriv; - - /** - * Controls swap interval as used by GLX_SGI_swap_control and - * GLX_MESA_swap_control. - */ - unsigned int swap_interval; - - struct { - unsigned int stamp; - drm_clip_rect_t clipRect; - } dri2; -}; - -/** - * Per-context private driver information. - */ -struct __DRIcontextRec { - /** - * Kernel context handle used to access the device lock. - */ - drm_context_t hHWContext; - - /** - * Device driver's private context data. This structure is opaque. - */ - void *driverPrivate; - - /** - * Pointer to drawable currently bound to this context for drawing. - */ - __DRIdrawable *driDrawablePriv; - - /** - * Pointer to drawable currently bound to this context for reading. - */ - __DRIdrawable *driReadablePriv; - - /** - * Pointer to screen on which this context was created. - */ - __DRIscreen *driScreenPriv; - - /** - * The loaders's private context data. This structure is opaque. - */ - void *loaderPrivate; - - struct { - int draw_stamp; - int read_stamp; - } dri2; -}; - -/** - * Per-screen private driver information. - */ -struct __DRIscreenRec { - /** - * Current screen's number - */ - int myNum; - - /** - * Callback functions into the hardware-specific DRI driver code. - */ - struct __DriverAPIRec DriverAPI; - - const __DRIextension **extensions; - /** - * DDX / 2D driver version information. - */ - __DRIversion ddx_version; - - /** - * DRI X extension version information. - */ - __DRIversion dri_version; - - /** - * DRM (kernel module) version information. - */ - __DRIversion drm_version; - - /** - * ID used when the client sets the drawable lock. - * - * The X server uses this value to detect if the client has died while - * holding the drawable lock. - */ - int drawLockID; - - /** - * File descriptor returned when the kernel device driver is opened. - * - * Used to: - * - authenticate client to kernel - * - map the frame buffer, SAREA, etc. - * - close the kernel device driver - */ - int fd; - - /** - * SAREA pointer - * - * Used to access: - * - the device lock - * - the device-independent per-drawable and per-context(?) information - */ - drm_sarea_t *pSAREA; - - /** - * \name Direct frame buffer access information - * Used for software fallbacks. - */ - /*@{*/ - unsigned char *pFB; - int fbSize; - int fbOrigin; - int fbStride; - int fbWidth; - int fbHeight; - int fbBPP; - /*@}*/ - - /** - * \name Device-dependent private information (stored in the SAREA). - * - * This data is accessed by the client driver only. - */ - /*@{*/ - void *pDevPriv; - int devPrivSize; - /*@}*/ - - /** - * Device-dependent private information (not stored in the SAREA). - * - * This pointer is never touched by the DRI layer. - */ -#ifdef __cplusplus - void *priv; -#else - void *private; -#endif - - /* Extensions provided by the loader. */ - const __DRIgetDrawableInfoExtension *getDrawableInfo; - const __DRIsystemTimeExtension *systemTime; - const __DRIdamageExtension *damage; - - struct { - /* Flag to indicate that this is a DRI2 screen. Many of the above - * fields will not be valid or initializaed in that case. */ - int enabled; - __DRIdri2LoaderExtension *loader; - __DRIimageLookupExtension *image; - __DRIuseInvalidateExtension *useInvalidate; - } dri2; - - /* The lock actually in use, old sarea or DRI2 */ - drmLock *lock; - - driOptionCache optionInfo; - driOptionCache optionCache; - unsigned int api_mask; - void *loaderPrivate; -}; - -extern void -__driUtilUpdateDrawableInfo(__DRIdrawable *pdp); - -extern float -driCalculateSwapUsage( __DRIdrawable *dPriv, - int64_t last_swap_ust, int64_t current_ust ); - -extern GLint -driIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 ); - -extern void -dri2InvalidateDrawable(__DRIdrawable *drawable); - -#endif /* _DRI_UTIL_H_ */ +/*
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file dri_util.h
+ * DRI utility functions definitions.
+ *
+ * This module acts as glue between GLX and the actual hardware driver. A DRI
+ * driver doesn't really \e have to use any of this - it's optional. But, some
+ * useful stuff is done here that otherwise would have to be duplicated in most
+ * drivers.
+ *
+ * Basically, these utility functions take care of some of the dirty details of
+ * screen initialization, context creation, context binding, DRM setup, etc.
+ *
+ * These functions are compiled into each DRI driver so libGL.so knows nothing
+ * about them.
+ *
+ * \sa dri_util.c.
+ *
+ * \author Kevin E. Martin <kevin@precisioninsight.com>
+ * \author Brian Paul <brian@precisioninsight.com>
+ */
+
+#ifndef _DRI_UTIL_H_
+#define _DRI_UTIL_H_
+
+#include <GL/gl.h>
+#include <drm.h>
+#include <drm_sarea.h>
+#include <xf86drm.h>
+#include "xmlconfig.h"
+#include "main/glheader.h"
+#include "main/mtypes.h"
+#include "GL/internal/dri_interface.h"
+
+#define GLX_BAD_CONTEXT 5
+
+typedef struct __DRIswapInfoRec __DRIswapInfo;
+
+/**
+ * Extensions.
+ */
+extern const __DRIlegacyExtension driLegacyExtension;
+extern const __DRIcoreExtension driCoreExtension;
+extern const __DRIdri2Extension driDRI2Extension;
+extern const __DRIextension driReadDrawableExtension;
+extern const __DRIcopySubBufferExtension driCopySubBufferExtension;
+extern const __DRIswapControlExtension driSwapControlExtension;
+extern const __DRImediaStreamCounterExtension driMediaStreamCounterExtension;
+extern const __DRI2configQueryExtension dri2ConfigQueryExtension;
+
+/**
+ * Used by DRI_VALIDATE_DRAWABLE_INFO
+ */
+#define DRI_VALIDATE_DRAWABLE_INFO_ONCE(pDrawPriv) \
+ do { \
+ if (*(pDrawPriv->pStamp) != pDrawPriv->lastStamp) { \
+ __driUtilUpdateDrawableInfo(pDrawPriv); \
+ } \
+ } while (0)
+
+
+/**
+ * Utility macro to validate the drawable information.
+ *
+ * See __DRIdrawable::pStamp and __DRIdrawable::lastStamp.
+ */
+#define DRI_VALIDATE_DRAWABLE_INFO(psp, pdp) \
+do { \
+ while (*(pdp->pStamp) != pdp->lastStamp) { \
+ register unsigned int hwContext = psp->pSAREA->lock.lock & \
+ ~(DRM_LOCK_HELD | DRM_LOCK_CONT); \
+ DRM_UNLOCK(psp->fd, &psp->pSAREA->lock, hwContext); \
+ \
+ DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); \
+ DRI_VALIDATE_DRAWABLE_INFO_ONCE(pdp); \
+ DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); \
+ \
+ DRM_LIGHT_LOCK(psp->fd, &psp->pSAREA->lock, hwContext); \
+ } \
+} while (0)
+
+/**
+ * Same as above, but for two drawables simultaneously.
+ *
+ */
+
+#define DRI_VALIDATE_TWO_DRAWABLES_INFO(psp, pdp, prp) \
+do { \
+ while (*((pdp)->pStamp) != (pdp)->lastStamp || \
+ *((prp)->pStamp) != (prp)->lastStamp) { \
+ register unsigned int hwContext = (psp)->pSAREA->lock.lock & \
+ ~(DRM_LOCK_HELD | DRM_LOCK_CONT); \
+ DRM_UNLOCK((psp)->fd, &(psp)->pSAREA->lock, hwContext); \
+ \
+ DRM_SPINLOCK(&(psp)->pSAREA->drawable_lock, (psp)->drawLockID); \
+ DRI_VALIDATE_DRAWABLE_INFO_ONCE(pdp); \
+ DRI_VALIDATE_DRAWABLE_INFO_ONCE(prp); \
+ DRM_SPINUNLOCK(&(psp)->pSAREA->drawable_lock, (psp)->drawLockID); \
+ \
+ DRM_LIGHT_LOCK((psp)->fd, &(psp)->pSAREA->lock, hwContext); \
+ } \
+} while (0)
+
+
+/**
+ * Driver callback functions.
+ *
+ * Each DRI driver must have one of these structures with all the pointers set
+ * to appropriate functions within the driver.
+ *
+ * When glXCreateContext() is called, for example, it'll call a helper function
+ * dri_util.c which in turn will jump through the \a CreateContext pointer in
+ * this structure.
+ */
+struct __DriverAPIRec {
+ const __DRIconfig **(*InitScreen) (__DRIscreen * priv);
+
+ /**
+ * Screen destruction callback
+ */
+ void (*DestroyScreen)(__DRIscreen *driScrnPriv);
+
+ /**
+ * Context creation callback
+ */
+ GLboolean (*CreateContext)(gl_api api,
+ const struct gl_config *glVis,
+ __DRIcontext *driContextPriv,
+ void *sharedContextPrivate);
+
+ /**
+ * Context destruction callback
+ */
+ void (*DestroyContext)(__DRIcontext *driContextPriv);
+
+ /**
+ * Buffer (drawable) creation callback
+ */
+ GLboolean (*CreateBuffer)(__DRIscreen *driScrnPriv,
+ __DRIdrawable *driDrawPriv,
+ const struct gl_config *glVis,
+ GLboolean pixmapBuffer);
+
+ /**
+ * Buffer (drawable) destruction callback
+ */
+ void (*DestroyBuffer)(__DRIdrawable *driDrawPriv);
+
+ /**
+ * Buffer swapping callback
+ */
+ void (*SwapBuffers)(__DRIdrawable *driDrawPriv);
+
+ /**
+ * Context activation callback
+ */
+ GLboolean (*MakeCurrent)(__DRIcontext *driContextPriv,
+ __DRIdrawable *driDrawPriv,
+ __DRIdrawable *driReadPriv);
+
+ /**
+ * Context unbinding callback
+ */
+ GLboolean (*UnbindContext)(__DRIcontext *driContextPriv);
+
+ /**
+ * Retrieves statistics about buffer swap operations. Required if
+ * GLX_OML_sync_control or GLX_MESA_swap_frame_usage is supported.
+ */
+ int (*GetSwapInfo)( __DRIdrawable *dPriv, __DRIswapInfo * sInfo );
+
+
+ /**
+ * These are required if GLX_OML_sync_control is supported.
+ */
+ /*@{*/
+ int (*WaitForMSC)( __DRIdrawable *priv, int64_t target_msc,
+ int64_t divisor, int64_t remainder,
+ int64_t * msc );
+ int (*WaitForSBC)( __DRIdrawable *priv, int64_t target_sbc,
+ int64_t * msc, int64_t * sbc );
+
+ int64_t (*SwapBuffersMSC)( __DRIdrawable *priv, int64_t target_msc,
+ int64_t divisor, int64_t remainder );
+ /*@}*/
+ void (*CopySubBuffer)(__DRIdrawable *driDrawPriv,
+ int x, int y, int w, int h);
+
+ /**
+ * New version of GetMSC so we can pass drawable data to the low
+ * level DRM driver (e.g. pipe info). Required if
+ * GLX_SGI_video_sync or GLX_OML_sync_control is supported.
+ */
+ int (*GetDrawableMSC) ( __DRIscreen * priv,
+ __DRIdrawable *drawablePrivate,
+ int64_t *count);
+
+
+
+ /* 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;
+
+
+struct __DRIswapInfoRec {
+ /**
+ * Number of swapBuffers operations that have been *completed*.
+ */
+ uint64_t swap_count;
+
+ /**
+ * Unadjusted system time of the last buffer swap. This is the time
+ * when the swap completed, not the time when swapBuffers was called.
+ */
+ int64_t swap_ust;
+
+ /**
+ * Number of swap operations that occurred after the swap deadline. That
+ * is if a swap happens more than swap_interval frames after the previous
+ * swap, it has missed its deadline. If swap_interval is 0, then the
+ * swap deadline is 1 frame after the previous swap.
+ */
+ uint64_t swap_missed_count;
+
+ /**
+ * Amount of time used by the last swap that missed its deadline. This
+ * is calculated as (__glXGetUST() - swap_ust) / (swap_interval *
+ * time_for_single_vrefresh)). If the actual value of swap_interval is
+ * 0, then 1 is used instead. If swap_missed_count is non-zero, this
+ * should be greater-than 1.0.
+ */
+ float swap_missed_usage;
+};
+
+
+/**
+ * Per-drawable private DRI driver information.
+ */
+struct __DRIdrawableRec {
+ /**
+ * Kernel drawable handle
+ */
+ drm_drawable_t hHWDrawable;
+
+ /**
+ * Driver's private drawable information.
+ *
+ * This structure is opaque.
+ */
+ void *driverPrivate;
+
+ /**
+ * Private data from the loader. We just hold on to it and pass
+ * it back when calling into loader provided functions.
+ */
+ void *loaderPrivate;
+
+ /**
+ * Reference count for number of context's currently bound to this
+ * drawable.
+ *
+ * Once it reaches zero, the drawable can be destroyed.
+ *
+ * \note This behavior will change with GLX 1.3.
+ */
+ int refcount;
+
+ /**
+ * Index of this drawable information in the SAREA.
+ */
+ unsigned int index;
+
+ /**
+ * Pointer to the "drawable has changed ID" stamp in the SAREA (or
+ * to dri2.stamp if DRI2 is being used).
+ */
+ unsigned int *pStamp;
+
+ /**
+ * Last value of the stamp.
+ *
+ * If this differs from the value stored at __DRIdrawable::pStamp,
+ * then the drawable information has been modified by the X server, and the
+ * drawable information (below) should be retrieved from the X server.
+ */
+ unsigned int lastStamp;
+
+ /**
+ * \name Drawable
+ *
+ * Drawable information used in software fallbacks.
+ */
+ /*@{*/
+ int x;
+ int y;
+ int w;
+ int h;
+ int numClipRects;
+ drm_clip_rect_t *pClipRects;
+ /*@}*/
+
+ /**
+ * \name Back and depthbuffer
+ *
+ * Information about the back and depthbuffer where different from above.
+ */
+ /*@{*/
+ int backX;
+ int backY;
+ int backClipRectType;
+ int numBackClipRects;
+ drm_clip_rect_t *pBackClipRects;
+ /*@}*/
+
+ /**
+ * \name Vertical blank tracking information
+ * Used for waiting on vertical blank events.
+ */
+ /*@{*/
+ unsigned int vblSeq;
+ unsigned int vblFlags;
+ /*@}*/
+
+ /**
+ * \name Monotonic MSC tracking
+ *
+ * Low level driver is responsible for updating msc_base and
+ * vblSeq values so that higher level code can calculate
+ * a new msc value or msc target for a WaitMSC call. The new value
+ * will be:
+ * msc = msc_base + get_vblank_count() - vblank_base;
+ *
+ * And for waiting on a value, core code will use:
+ * actual_target = target_msc - msc_base + vblank_base;
+ */
+ /*@{*/
+ int64_t vblank_base;
+ int64_t msc_base;
+ /*@}*/
+
+ /**
+ * Pointer to context to which this drawable is currently bound.
+ */
+ __DRIcontext *driContextPriv;
+
+ /**
+ * Pointer to screen on which this drawable was created.
+ */
+ __DRIscreen *driScreenPriv;
+
+ /**
+ * Controls swap interval as used by GLX_SGI_swap_control and
+ * GLX_MESA_swap_control.
+ */
+ unsigned int swap_interval;
+
+ struct {
+ unsigned int stamp;
+ drm_clip_rect_t clipRect;
+ } dri2;
+};
+
+/**
+ * Per-context private driver information.
+ */
+struct __DRIcontextRec {
+ /**
+ * Kernel context handle used to access the device lock.
+ */
+ drm_context_t hHWContext;
+
+ /**
+ * Device driver's private context data. This structure is opaque.
+ */
+ void *driverPrivate;
+
+ /**
+ * Pointer to drawable currently bound to this context for drawing.
+ */
+ __DRIdrawable *driDrawablePriv;
+
+ /**
+ * Pointer to drawable currently bound to this context for reading.
+ */
+ __DRIdrawable *driReadablePriv;
+
+ /**
+ * Pointer to screen on which this context was created.
+ */
+ __DRIscreen *driScreenPriv;
+
+ /**
+ * The loaders's private context data. This structure is opaque.
+ */
+ void *loaderPrivate;
+
+ struct {
+ int draw_stamp;
+ int read_stamp;
+ } dri2;
+};
+
+/**
+ * Per-screen private driver information.
+ */
+struct __DRIscreenRec {
+ /**
+ * Current screen's number
+ */
+ int myNum;
+
+ /**
+ * Callback functions into the hardware-specific DRI driver code.
+ */
+ struct __DriverAPIRec DriverAPI;
+
+ const __DRIextension **extensions;
+ /**
+ * DDX / 2D driver version information.
+ */
+ __DRIversion ddx_version;
+
+ /**
+ * DRI X extension version information.
+ */
+ __DRIversion dri_version;
+
+ /**
+ * DRM (kernel module) version information.
+ */
+ __DRIversion drm_version;
+
+ /**
+ * ID used when the client sets the drawable lock.
+ *
+ * The X server uses this value to detect if the client has died while
+ * holding the drawable lock.
+ */
+ int drawLockID;
+
+ /**
+ * File descriptor returned when the kernel device driver is opened.
+ *
+ * Used to:
+ * - authenticate client to kernel
+ * - map the frame buffer, SAREA, etc.
+ * - close the kernel device driver
+ */
+ int fd;
+
+ /**
+ * SAREA pointer
+ *
+ * Used to access:
+ * - the device lock
+ * - the device-independent per-drawable and per-context(?) information
+ */
+ drm_sarea_t *pSAREA;
+
+ /**
+ * \name Direct frame buffer access information
+ * Used for software fallbacks.
+ */
+ /*@{*/
+ unsigned char *pFB;
+ int fbSize;
+ int fbOrigin;
+ int fbStride;
+ int fbWidth;
+ int fbHeight;
+ int fbBPP;
+ /*@}*/
+
+ /**
+ * \name Device-dependent private information (stored in the SAREA).
+ *
+ * This data is accessed by the client driver only.
+ */
+ /*@{*/
+ void *pDevPriv;
+ int devPrivSize;
+ /*@}*/
+
+ /**
+ * Device-dependent private information (not stored in the SAREA).
+ *
+ * This pointer is never touched by the DRI layer.
+ */
+#ifdef __cplusplus
+ void *priv;
+#else
+ void *private;
+#endif
+
+ /* Extensions provided by the loader. */
+ const __DRIgetDrawableInfoExtension *getDrawableInfo;
+ const __DRIsystemTimeExtension *systemTime;
+ const __DRIdamageExtension *damage;
+
+ struct {
+ /* Flag to indicate that this is a DRI2 screen. Many of the above
+ * fields will not be valid or initializaed in that case. */
+ int enabled;
+ __DRIdri2LoaderExtension *loader;
+ __DRIimageLookupExtension *image;
+ __DRIuseInvalidateExtension *useInvalidate;
+ } dri2;
+
+ /* The lock actually in use, old sarea or DRI2 */
+ drmLock *lock;
+
+ driOptionCache optionInfo;
+ driOptionCache optionCache;
+ unsigned int api_mask;
+ void *loaderPrivate;
+};
+
+extern void
+__driUtilUpdateDrawableInfo(__DRIdrawable *pdp);
+
+extern float
+driCalculateSwapUsage( __DRIdrawable *dPriv,
+ int64_t last_swap_ust, int64_t current_ust );
+
+extern GLint
+driIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 );
+
+extern void
+dri2InvalidateDrawable(__DRIdrawable *drawable);
+
+#endif /* _DRI_UTIL_H_ */
diff --git a/mesalib/src/mesa/drivers/dri/common/utils.c b/mesalib/src/mesa/drivers/dri/common/utils.c index a2b0b4e94..02c8cc6f5 100644 --- a/mesalib/src/mesa/drivers/dri/common/utils.c +++ b/mesalib/src/mesa/drivers/dri/common/utils.c @@ -219,7 +219,9 @@ void driInitExtensions( struct gl_context * ctx, /* Map the static functions. Together with those mapped by remap
* table, this should cover everything mesa core knows.
*/
+#ifdef _GLAPI_USE_REMAP_TABLE
_mesa_map_static_functions();
+#endif
return;
}
diff --git a/mesalib/src/mesa/drivers/dri/swrast/swrast.c b/mesalib/src/mesa/drivers/dri/swrast/swrast.c index 719b406ec..e6d1ab741 100644 --- a/mesalib/src/mesa/drivers/dri/swrast/swrast.c +++ b/mesalib/src/mesa/drivers/dri/swrast/swrast.c @@ -1,806 +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. - */ - -#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", __func__, __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", __func__, - __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 -}; +/*
+ * 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/dri/swrast/swrast_priv.h b/mesalib/src/mesa/drivers/dri/swrast/swrast_priv.h index 4c3c9830f..e61965147 100644 --- a/mesalib/src/mesa/drivers/dri/swrast/swrast_priv.h +++ b/mesalib/src/mesa/drivers/dri/swrast/swrast_priv.h @@ -32,6 +32,13 @@ #include "main/mtypes.h"
#include "drisw_util.h"
+#ifdef _MSC_VER
+#ifdef PUBLIC
+#undef PUBLIC
+#endif
+#define PUBLIC __declspec(dllexport)
+#endif
+
/**
* Debugging
diff --git a/mesalib/src/mesa/drivers/windows/gdi/wmesa.c b/mesalib/src/mesa/drivers/windows/gdi/wmesa.c index 4a8b1b283..1a13e9f5c 100644 --- a/mesalib/src/mesa/drivers/windows/gdi/wmesa.c +++ b/mesalib/src/mesa/drivers/windows/gdi/wmesa.c @@ -1,1662 +1,1662 @@ -/* - * Windows (Win32/Win64) device driver for Mesa - * - */ - -#include "wmesadef.h" -#include "colors.h" -#include <GL/wmesa.h> -#include <winuser.h> -#include "context.h" -#include "extensions.h" -#include "framebuffer.h" -#include "renderbuffer.h" -#include "drivers/common/driverfuncs.h" -#include "drivers/common/meta.h" -#include "vbo/vbo.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" - - -/* linked list of our Framebuffers (windows) */ -static WMesaFramebuffer FirstFramebuffer = NULL; - - -/** - * Create a new WMesaFramebuffer object which will correspond to the - * given HDC (Window handle). - */ -WMesaFramebuffer -wmesa_new_framebuffer(HDC hdc, struct gl_config *visual) -{ - WMesaFramebuffer pwfb - = (WMesaFramebuffer) malloc(sizeof(struct wmesa_framebuffer)); - if (pwfb) { - _mesa_initialize_window_framebuffer(&pwfb->Base, visual); - pwfb->hDC = hdc; - /* insert at head of list */ - pwfb->next = FirstFramebuffer; - FirstFramebuffer = pwfb; - } - return pwfb; -} - -/** - * Given an hdc, free the corresponding WMesaFramebuffer - */ -void -wmesa_free_framebuffer(HDC hdc) -{ - WMesaFramebuffer pwfb, prev; - for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) { - if (pwfb->hDC == hdc) - break; - prev = pwfb; - } - if (pwfb) { - struct gl_framebuffer *fb; - if (pwfb == FirstFramebuffer) - FirstFramebuffer = pwfb->next; - else - prev->next = pwfb->next; - fb = &pwfb->Base; - _mesa_reference_framebuffer(&fb, NULL); - } -} - -/** - * Given an hdc, return the corresponding WMesaFramebuffer - */ -WMesaFramebuffer -wmesa_lookup_framebuffer(HDC hdc) -{ - WMesaFramebuffer pwfb; - for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) { - if (pwfb->hDC == hdc) - return pwfb; - } - return NULL; -} - - -/** - * Given a struct gl_framebuffer, return the corresponding WMesaFramebuffer. - */ -static WMesaFramebuffer wmesa_framebuffer(struct gl_framebuffer *fb) -{ - return (WMesaFramebuffer) fb; -} - - -/** - * Given a struct gl_context, return the corresponding WMesaContext. - */ -static WMesaContext wmesa_context(const struct gl_context *ctx) -{ - return (WMesaContext) ctx; -} - - -/* - * Every driver should implement a GetString function in order to - * return a meaningful GL_RENDERER string. - */ -static const GLubyte *wmesa_get_string(struct gl_context *ctx, GLenum name) -{ - return (name == GL_RENDERER) ? - (GLubyte *) "Mesa Windows GDI Driver" : NULL; -} - - -/* - * Determine the pixel format based on the pixel size. - */ -static void wmSetPixelFormat(WMesaFramebuffer pwfb, HDC hDC) -{ - pwfb->cColorBits = GetDeviceCaps(hDC, BITSPIXEL); - - /* Only 16 and 32 bit targets are supported now */ - assert(pwfb->cColorBits == 0 || - pwfb->cColorBits == 16 || - pwfb->cColorBits == 24 || - pwfb->cColorBits == 32); - - switch(pwfb->cColorBits){ - case 8: - pwfb->pixelformat = PF_INDEX8; - break; - case 16: - pwfb->pixelformat = PF_5R6G5B; - break; - case 24: - case 32: - pwfb->pixelformat = PF_8R8G8B; - break; - default: - pwfb->pixelformat = PF_BADFORMAT; - } -} - - -/** - * Create DIB for back buffer. - * We write into this memory with the span routines and then blit it - * to the window on a buffer swap. - */ -BOOL wmCreateBackingStore(WMesaFramebuffer pwfb, long lxSize, long lySize) -{ - HDC hdc = pwfb->hDC; - LPBITMAPINFO pbmi = &(pwfb->bmi); - HDC hic; - - pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - pbmi->bmiHeader.biWidth = lxSize; - pbmi->bmiHeader.biHeight= -lySize; - pbmi->bmiHeader.biPlanes = 1; - pbmi->bmiHeader.biBitCount = GetDeviceCaps(pwfb->hDC, BITSPIXEL); - pbmi->bmiHeader.biCompression = BI_RGB; - pbmi->bmiHeader.biSizeImage = 0; - pbmi->bmiHeader.biXPelsPerMeter = 0; - pbmi->bmiHeader.biYPelsPerMeter = 0; - pbmi->bmiHeader.biClrUsed = 0; - pbmi->bmiHeader.biClrImportant = 0; - - pwfb->cColorBits = pbmi->bmiHeader.biBitCount; - pwfb->ScanWidth = (lxSize * (pwfb->cColorBits / 8) + 3) & ~3; - - hic = CreateIC("display", NULL, NULL, NULL); - pwfb->dib_hDC = CreateCompatibleDC(hic); - - pwfb->hbmDIB = CreateDIBSection(hic, - &pwfb->bmi, - DIB_RGB_COLORS, - (void **)&(pwfb->pbPixels), - 0, - 0); - pwfb->hOldBitmap = SelectObject(pwfb->dib_hDC, pwfb->hbmDIB); - - DeleteDC(hic); - - wmSetPixelFormat(pwfb, pwfb->hDC); - return TRUE; -} - - -static wmDeleteBackingStore(WMesaFramebuffer pwfb) -{ - if (pwfb->hbmDIB) { - SelectObject(pwfb->dib_hDC, pwfb->hOldBitmap); - DeleteDC(pwfb->dib_hDC); - DeleteObject(pwfb->hbmDIB); - } -} - - -/** - * Find the width and height of the window named by hdc. - */ -static void -get_window_size(HDC hdc, GLuint *width, GLuint *height) -{ - if (WindowFromDC(hdc)) { - RECT rect; - GetClientRect(WindowFromDC(hdc), &rect); - *width = rect.right - rect.left; - *height = rect.bottom - rect.top; - } - else { /* Memory context */ - /* From contributed code - use the size of the desktop - * for the size of a memory context (?) */ - *width = GetDeviceCaps(hdc, HORZRES); - *height = GetDeviceCaps(hdc, VERTRES); - } -} - - -static void -wmesa_get_buffer_size(struct gl_framebuffer *buffer, GLuint *width, GLuint *height) -{ - WMesaFramebuffer pwfb = wmesa_framebuffer(buffer); - get_window_size(pwfb->hDC, width, height); -} - - -static void wmesa_flush(struct gl_context *ctx) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->WinSysDrawBuffer); - - if (ctx->Visual.doubleBufferMode == 1) { - BitBlt(pwfb->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height, - pwfb->dib_hDC, 0, 0, SRCCOPY); - } - else { - /* Do nothing for single buffer */ - } -} - - -/**********************************************************************/ -/***** CLEAR Functions *****/ -/**********************************************************************/ - -/* If we do not implement these, Mesa clears the buffers via the pixel - * span writing interface, which is very slow for a clear operation. - */ - -/* - * Set the color used to clear the color buffer. - */ -static void clear_color(struct gl_context *ctx, const GLfloat color[4]) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - GLubyte col[3]; - UINT bytesPerPixel = pwfb->cColorBits / 8; - - CLAMPED_FLOAT_TO_UBYTE(col[0], color[0]); - CLAMPED_FLOAT_TO_UBYTE(col[1], color[1]); - CLAMPED_FLOAT_TO_UBYTE(col[2], color[2]); - pwc->clearColorRef = RGB(col[0], col[1], col[2]); - DeleteObject(pwc->clearPen); - DeleteObject(pwc->clearBrush); - pwc->clearPen = CreatePen(PS_SOLID, 1, pwc->clearColorRef); - pwc->clearBrush = CreateSolidBrush(pwc->clearColorRef); -} - - -/* - * Clear the specified region of the color buffer using the clear color - * or index as specified by one of the two functions above. - * - * This procedure clears either the front and/or the back COLOR buffers. - * Only the "left" buffer is cleared since we are not stereo. - * Clearing of the other non-color buffers is left to the swrast. - */ - -static void clear(struct gl_context *ctx, GLbitfield mask) -{ -#define FLIP(Y) (ctx->DrawBuffer->Height - (Y) - 1) - const GLint x = ctx->DrawBuffer->_Xmin; - const GLint y = ctx->DrawBuffer->_Ymin; - const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; - const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; - - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - int done = 0; - - /* Let swrast do all the work if the masks are not set to - * clear all channels. */ - if (!ctx->Color.ColorMask[0][0] || - !ctx->Color.ColorMask[0][1] || - !ctx->Color.ColorMask[0][2] || - !ctx->Color.ColorMask[0][3]) { - _swrast_Clear(ctx, mask); - return; - } - - /* Back buffer */ - if (mask & BUFFER_BIT_BACK_LEFT) { - - int i, rowSize; - UINT bytesPerPixel = pwfb->cColorBits / 8; - LPBYTE lpb, clearRow; - LPWORD lpw; - BYTE bColor; - WORD wColor; - BYTE r, g, b; - DWORD dwColor; - LPDWORD lpdw; - - /* Try for a fast clear - clearing entire buffer with a single - * byte value. */ - if (width == ctx->DrawBuffer->Width && - height == ctx->DrawBuffer->Height) { /* entire buffer */ - /* Now check for an easy clear value */ - switch (bytesPerPixel) { - case 1: - bColor = BGR8(GetRValue(pwc->clearColorRef), - GetGValue(pwc->clearColorRef), - GetBValue(pwc->clearColorRef)); - memset(pwfb->pbPixels, bColor, - pwfb->ScanWidth * height); - done = 1; - break; - case 2: - wColor = BGR16(GetRValue(pwc->clearColorRef), - GetGValue(pwc->clearColorRef), - GetBValue(pwc->clearColorRef)); - if (((wColor >> 8) & 0xff) == (wColor & 0xff)) { - memset(pwfb->pbPixels, wColor & 0xff, - pwfb->ScanWidth * height); - done = 1; - } - break; - case 3: - /* fall through */ - case 4: - if (GetRValue(pwc->clearColorRef) == - GetGValue(pwc->clearColorRef) && - GetRValue(pwc->clearColorRef) == - GetBValue(pwc->clearColorRef)) { - memset(pwfb->pbPixels, - GetRValue(pwc->clearColorRef), - pwfb->ScanWidth * height); - done = 1; - } - break; - default: - break; - } - } /* all */ - - if (!done) { - /* Need to clear a row at a time. Begin by setting the first - * row in the area to be cleared to the clear color. */ - - clearRow = pwfb->pbPixels + - pwfb->ScanWidth * FLIP(y) + - bytesPerPixel * x; - switch (bytesPerPixel) { - case 1: - lpb = clearRow; - bColor = BGR8(GetRValue(pwc->clearColorRef), - GetGValue(pwc->clearColorRef), - GetBValue(pwc->clearColorRef)); - memset(lpb, bColor, width); - break; - case 2: - lpw = (LPWORD)clearRow; - wColor = BGR16(GetRValue(pwc->clearColorRef), - GetGValue(pwc->clearColorRef), - GetBValue(pwc->clearColorRef)); - for (i=0; i<width; i++) - *lpw++ = wColor; - break; - case 3: - lpb = clearRow; - r = GetRValue(pwc->clearColorRef); - g = GetGValue(pwc->clearColorRef); - b = GetBValue(pwc->clearColorRef); - for (i=0; i<width; i++) { - *lpb++ = b; - *lpb++ = g; - *lpb++ = r; - } - break; - case 4: - lpdw = (LPDWORD)clearRow; - dwColor = BGR32(GetRValue(pwc->clearColorRef), - GetGValue(pwc->clearColorRef), - GetBValue(pwc->clearColorRef)); - for (i=0; i<width; i++) - *lpdw++ = dwColor; - break; - default: - break; - } /* switch */ - - /* copy cleared row to other rows in buffer */ - lpb = clearRow - pwfb->ScanWidth; - rowSize = width * bytesPerPixel; - for (i=1; i<height; i++) { - memcpy(lpb, clearRow, rowSize); - lpb -= pwfb->ScanWidth; - } - } /* not done */ - mask &= ~BUFFER_BIT_BACK_LEFT; - } /* back buffer */ - - /* front buffer */ - if (mask & BUFFER_BIT_FRONT_LEFT) { - HDC DC = pwc->hDC; - HPEN Old_Pen = SelectObject(DC, pwc->clearPen); - HBRUSH Old_Brush = SelectObject(DC, pwc->clearBrush); - Rectangle(DC, - x, - FLIP(y) + 1, - x + width + 1, - FLIP(y) - height + 1); - SelectObject(DC, Old_Pen); - SelectObject(DC, Old_Brush); - mask &= ~BUFFER_BIT_FRONT_LEFT; - } /* front buffer */ - - /* Call swrast if there is anything left to clear (like DEPTH) */ - if (mask) - _swrast_Clear(ctx, mask); - -#undef FLIP -} - - -/**********************************************************************/ -/***** PIXEL Functions *****/ -/**********************************************************************/ - -#define FLIP(Y) (rb->Height - (Y) - 1) - - -/** - ** Front Buffer reading/writing - ** These are slow, but work with all non-indexed visual types. - **/ - -/* Write a horizontal span of RGBA color pixels with a boolean mask. */ -static void write_rgba_span_front(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLubyte rgba[][4], - const GLubyte mask[] ) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(pwc->hDC); - CONST BITMAPINFO bmi= - { - { - sizeof(BITMAPINFOHEADER), - n, 1, 1, 32, BI_RGB, 0, 1, 1, 0, 0 - } - }; - HBITMAP bmp=0; - HDC mdc=0; - typedef union - { - unsigned i; - struct { - unsigned b:8, g:8, r:8, a:8; - }; - } BGRA; - BGRA *bgra, c; - GLuint i; - - if (n < 16) { // the value 16 is just guessed - y=FLIP(y); - if (mask) { - for (i=0; i<n; i++) - if (mask[i]) - SetPixel(pwc->hDC, x+i, y, - RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP])); - } - else { - for (i=0; i<n; i++) - SetPixel(pwc->hDC, x+i, y, - RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP])); - } - } - else { - if (!pwfb) { - _mesa_problem(NULL, "wmesa: write_rgba_span_front on unknown hdc"); - return; - } - bgra=malloc(n*sizeof(BGRA)); - if (!bgra) { - _mesa_problem(NULL, "wmesa: write_rgba_span_front: out of memory"); - return; - } - c.a=0; - if (mask) { - for (i=0; i<n; i++) { - if (mask[i]) { - c.r=rgba[i][RCOMP]; - c.g=rgba[i][GCOMP]; - c.b=rgba[i][BCOMP]; - c.a=rgba[i][ACOMP]; - bgra[i]=c; - } - else - bgra[i].i=0; - } - } - else { - for (i=0; i<n; i++) { - c.r=rgba[i][RCOMP]; - c.g=rgba[i][GCOMP]; - c.b=rgba[i][BCOMP]; - c.a=rgba[i][ACOMP]; - bgra[i]=c; - } - } - bmp=CreateBitmap(n, 1, 1, 32, bgra); - mdc=CreateCompatibleDC(pwfb->hDC); - SelectObject(mdc, bmp); - y=FLIP(y); - BitBlt(pwfb->hDC, x, y, n, 1, mdc, 0, 0, SRCCOPY); - SelectObject(mdc, 0); - DeleteObject(bmp); - DeleteDC(mdc); - free(bgra); - } -} - -/* Write a horizontal span of RGB color pixels with a boolean mask. */ -static void write_rgb_span_front(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLubyte rgb[][3], - const GLubyte mask[] ) -{ - WMesaContext pwc = wmesa_context(ctx); - GLuint i; - - (void) ctx; - y=FLIP(y); - if (mask) { - for (i=0; i<n; i++) - if (mask[i]) - SetPixel(pwc->hDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP], - rgb[i][BCOMP])); - } - else { - for (i=0; i<n; i++) - SetPixel(pwc->hDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP], - rgb[i][BCOMP])); - } - -} - -/* - * Write a horizontal span of pixels with a boolean mask. The current color - * is used for all pixels. - */ -static void write_mono_rgba_span_front(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLchan color[4], - const GLubyte mask[]) -{ - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - COLORREF colorref; - - (void) ctx; - colorref = RGB(color[RCOMP], color[GCOMP], color[BCOMP]); - y=FLIP(y); - if (mask) { - for (i=0; i<n; i++) - if (mask[i]) - SetPixel(pwc->hDC, x+i, y, colorref); - } - else - for (i=0; i<n; i++) - SetPixel(pwc->hDC, x+i, y, colorref); - -} - -/* Write an array of RGBA pixels with a boolean mask. */ -static void write_rgba_pixels_front(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, - const GLint x[], const GLint y[], - const GLubyte rgba[][4], - const GLubyte mask[] ) -{ - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - (void) ctx; - for (i=0; i<n; i++) - if (mask[i]) - SetPixel(pwc->hDC, x[i], FLIP(y[i]), - RGB(rgba[i][RCOMP], rgba[i][GCOMP], - rgba[i][BCOMP])); -} - - - -/* - * Write an array of pixels with a boolean mask. The current color - * is used for all pixels. - */ -static void write_mono_rgba_pixels_front(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, - const GLint x[], const GLint y[], - const GLchan color[4], - const GLubyte mask[] ) -{ - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - COLORREF colorref; - (void) ctx; - colorref = RGB(color[RCOMP], color[GCOMP], color[BCOMP]); - for (i=0; i<n; i++) - if (mask[i]) - SetPixel(pwc->hDC, x[i], FLIP(y[i]), colorref); -} - -/* Read a horizontal span of color pixels. */ -static void read_rgba_span_front(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - GLubyte rgba[][4] ) -{ - WMesaContext pwc = wmesa_context(ctx); - GLuint i; - COLORREF Color; - y = FLIP(y); - for (i=0; i<n; i++) { - Color = GetPixel(pwc->hDC, x+i, y); - rgba[i][RCOMP] = GetRValue(Color); - rgba[i][GCOMP] = GetGValue(Color); - rgba[i][BCOMP] = GetBValue(Color); - rgba[i][ACOMP] = 255; - } -} - - -/* Read an array of color pixels. */ -static void read_rgba_pixels_front(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - GLubyte rgba[][4]) -{ - WMesaContext pwc = wmesa_context(ctx); - GLuint i; - COLORREF Color; - for (i=0; i<n; i++) { - GLint y2 = FLIP(y[i]); - Color = GetPixel(pwc->hDC, x[i], y2); - rgba[i][RCOMP] = GetRValue(Color); - rgba[i][GCOMP] = GetGValue(Color); - rgba[i][BCOMP] = GetBValue(Color); - rgba[i][ACOMP] = 255; - } -} - -/*********************************************************************/ - -/* DOUBLE BUFFER 32-bit */ - -#define WMSETPIXEL32(pwc, y, x, r, g, b) { \ -LPDWORD lpdw = ((LPDWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \ -*lpdw = BGR32((r),(g),(b)); } - - - -/* Write a horizontal span of RGBA color pixels with a boolean mask. */ -static void write_rgba_span_32(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLubyte rgba[][4], - const GLubyte mask[] ) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - GLuint i; - LPDWORD lpdw; - - (void) ctx; - - y=FLIP(y); - lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - if (mask) { - for (i=0; i<n; i++) - if (mask[i]) - lpdw[i] = BGR32(rgba[i][RCOMP], rgba[i][GCOMP], - rgba[i][BCOMP]); - } - else { - for (i=0; i<n; i++) - *lpdw++ = BGR32(rgba[i][RCOMP], rgba[i][GCOMP], - rgba[i][BCOMP]); - } -} - - -/* Write a horizontal span of RGB color pixels with a boolean mask. */ -static void write_rgb_span_32(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLubyte rgb[][3], - const GLubyte mask[] ) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - GLuint i; - LPDWORD lpdw; - - (void) ctx; - - y=FLIP(y); - lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - if (mask) { - for (i=0; i<n; i++) - if (mask[i]) - lpdw[i] = BGR32(rgb[i][RCOMP], rgb[i][GCOMP], - rgb[i][BCOMP]); - } - else { - for (i=0; i<n; i++) - *lpdw++ = BGR32(rgb[i][RCOMP], rgb[i][GCOMP], - rgb[i][BCOMP]); - } -} - -/* - * Write a horizontal span of pixels with a boolean mask. The current color - * is used for all pixels. - */ -static void write_mono_rgba_span_32(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLchan color[4], - const GLubyte mask[]) -{ - LPDWORD lpdw; - DWORD pixel; - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - y=FLIP(y); - pixel = BGR32(color[RCOMP], color[GCOMP], color[BCOMP]); - if (mask) { - for (i=0; i<n; i++) - if (mask[i]) - lpdw[i] = pixel; - } - else - for (i=0; i<n; i++) - *lpdw++ = pixel; - -} - -/* Write an array of RGBA pixels with a boolean mask. */ -static void write_rgba_pixels_32(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - const GLubyte rgba[][4], - const GLubyte mask[]) -{ - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - for (i=0; i<n; i++) - if (mask[i]) - WMSETPIXEL32(pwfb, FLIP(y[i]), x[i], - rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]); -} - -/* - * Write an array of pixels with a boolean mask. The current color - * is used for all pixels. - */ -static void write_mono_rgba_pixels_32(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, - const GLint x[], const GLint y[], - const GLchan color[4], - const GLubyte mask[]) -{ - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - for (i=0; i<n; i++) - if (mask[i]) - WMSETPIXEL32(pwfb, FLIP(y[i]),x[i],color[RCOMP], - color[GCOMP], color[BCOMP]); -} - -/* Read a horizontal span of color pixels. */ -static void read_rgba_span_32(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - GLubyte rgba[][4] ) -{ - GLuint i; - DWORD pixel; - LPDWORD lpdw; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - - y = FLIP(y); - lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - for (i=0; i<n; i++) { - pixel = lpdw[i]; - rgba[i][RCOMP] = (GLubyte)((pixel & 0x00ff0000) >> 16); - rgba[i][GCOMP] = (GLubyte)((pixel & 0x0000ff00) >> 8); - rgba[i][BCOMP] = (GLubyte)(pixel & 0x000000ff); - rgba[i][ACOMP] = 255; - } -} - - -/* Read an array of color pixels. */ -static void read_rgba_pixels_32(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - GLubyte rgba[][4]) -{ - GLuint i; - DWORD pixel; - LPDWORD lpdw; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - - for (i=0; i<n; i++) { - GLint y2 = FLIP(y[i]); - lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y2)) + x[i]; - pixel = *lpdw; - rgba[i][RCOMP] = (GLubyte)((pixel & 0x00ff0000) >> 16); - rgba[i][GCOMP] = (GLubyte)((pixel & 0x0000ff00) >> 8); - rgba[i][BCOMP] = (GLubyte)(pixel & 0x000000ff); - rgba[i][ACOMP] = 255; - } -} - - -/*********************************************************************/ - -/* DOUBLE BUFFER 24-bit */ - -#define WMSETPIXEL24(pwc, y, x, r, g, b) { \ -LPBYTE lpb = ((LPBYTE)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (3 * x)); \ -lpb[0] = (b); \ -lpb[1] = (g); \ -lpb[2] = (r); } - -/* Write a horizontal span of RGBA color pixels with a boolean mask. */ -static void write_rgba_span_24(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLubyte rgba[][4], - const GLubyte mask[] ) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - GLuint i; - LPBYTE lpb; - - (void) ctx; - - y=FLIP(y); - lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); - if (mask) { - for (i=0; i<n; i++) - if (mask[i]) { - lpb[3*i] = rgba[i][BCOMP]; - lpb[3*i+1] = rgba[i][GCOMP]; - lpb[3*i+2] = rgba[i][RCOMP]; - } - } - else { - for (i=0; i<n; i++) { - *lpb++ = rgba[i][BCOMP]; - *lpb++ = rgba[i][GCOMP]; - *lpb++ = rgba[i][RCOMP]; - } - } -} - - -/* Write a horizontal span of RGB color pixels with a boolean mask. */ -static void write_rgb_span_24(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLubyte rgb[][3], - const GLubyte mask[] ) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - GLuint i; - LPBYTE lpb; - - (void) ctx; - - y=FLIP(y); - lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); - if (mask) { - for (i=0; i<n; i++) - if (mask[i]) { - lpb[3*i] = rgb[i][BCOMP]; - lpb[3*i+1] = rgb[i][GCOMP]; - lpb[3*i+2] = rgb[i][RCOMP]; - } - } - else { - for (i=0; i<n; i++) { - *lpb++ = rgb[i][BCOMP]; - *lpb++ = rgb[i][GCOMP]; - *lpb++ = rgb[i][RCOMP]; - } - } -} - -/* - * Write a horizontal span of pixels with a boolean mask. The current color - * is used for all pixels. - */ -static void write_mono_rgba_span_24(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLchan color[4], - const GLubyte mask[]) -{ - LPBYTE lpb; - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); - y=FLIP(y); - if (mask) { - for (i=0; i<n; i++) - if (mask[i]) { - lpb[3*i] = color[BCOMP]; - lpb[3*i+1] = color[GCOMP]; - lpb[3*i+2] = color[RCOMP]; - } - } - else - for (i=0; i<n; i++) { - *lpb++ = color[BCOMP]; - *lpb++ = color[GCOMP]; - *lpb++ = color[RCOMP]; - } -} - -/* Write an array of RGBA pixels with a boolean mask. */ -static void write_rgba_pixels_24(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - const GLubyte rgba[][4], - const GLubyte mask[]) -{ - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - for (i=0; i<n; i++) - if (mask[i]) - WMSETPIXEL24(pwfb, FLIP(y[i]), x[i], - rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]); -} - -/* - * Write an array of pixels with a boolean mask. The current color - * is used for all pixels. - */ -static void write_mono_rgba_pixels_24(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, - const GLint x[], const GLint y[], - const GLchan color[4], - const GLubyte mask[]) -{ - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - for (i=0; i<n; i++) - if (mask[i]) - WMSETPIXEL24(pwfb, FLIP(y[i]),x[i],color[RCOMP], - color[GCOMP], color[BCOMP]); -} - -/* Read a horizontal span of color pixels. */ -static void read_rgba_span_24(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - GLubyte rgba[][4] ) -{ - GLuint i; - LPBYTE lpb; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - - y = FLIP(y); - lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); - for (i=0; i<n; i++) { - rgba[i][RCOMP] = lpb[3*i+2]; - rgba[i][GCOMP] = lpb[3*i+1]; - rgba[i][BCOMP] = lpb[3*i]; - rgba[i][ACOMP] = 255; - } -} - - -/* Read an array of color pixels. */ -static void read_rgba_pixels_24(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - GLubyte rgba[][4]) -{ - GLuint i; - LPBYTE lpb; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - - for (i=0; i<n; i++) { - GLint y2 = FLIP(y[i]); - lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y2)) + (3 * x[i]); - rgba[i][RCOMP] = lpb[3*i+2]; - rgba[i][GCOMP] = lpb[3*i+1]; - rgba[i][BCOMP] = lpb[3*i]; - rgba[i][ACOMP] = 255; - } -} - - -/*********************************************************************/ - -/* DOUBLE BUFFER 16-bit */ - -#define WMSETPIXEL16(pwc, y, x, r, g, b) { \ -LPWORD lpw = ((LPWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \ -*lpw = BGR16((r),(g),(b)); } - - - -/* Write a horizontal span of RGBA color pixels with a boolean mask. */ -static void write_rgba_span_16(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLubyte rgba[][4], - const GLubyte mask[] ) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - GLuint i; - LPWORD lpw; - - (void) ctx; - - y=FLIP(y); - lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - if (mask) { - for (i=0; i<n; i++) - if (mask[i]) - lpw[i] = BGR16(rgba[i][RCOMP], rgba[i][GCOMP], - rgba[i][BCOMP]); - } - else { - for (i=0; i<n; i++) - *lpw++ = BGR16(rgba[i][RCOMP], rgba[i][GCOMP], - rgba[i][BCOMP]); - } -} - - -/* Write a horizontal span of RGB color pixels with a boolean mask. */ -static void write_rgb_span_16(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLubyte rgb[][3], - const GLubyte mask[] ) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - GLuint i; - LPWORD lpw; - - (void) ctx; - - y=FLIP(y); - lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - if (mask) { - for (i=0; i<n; i++) - if (mask[i]) - lpw[i] = BGR16(rgb[i][RCOMP], rgb[i][GCOMP], - rgb[i][BCOMP]); - } - else { - for (i=0; i<n; i++) - *lpw++ = BGR16(rgb[i][RCOMP], rgb[i][GCOMP], - rgb[i][BCOMP]); - } -} - -/* - * Write a horizontal span of pixels with a boolean mask. The current color - * is used for all pixels. - */ -static void write_mono_rgba_span_16(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - const GLchan color[4], - const GLubyte mask[]) -{ - LPWORD lpw; - WORD pixel; - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - (void) ctx; - lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - y=FLIP(y); - pixel = BGR16(color[RCOMP], color[GCOMP], color[BCOMP]); - if (mask) { - for (i=0; i<n; i++) - if (mask[i]) - lpw[i] = pixel; - } - else - for (i=0; i<n; i++) - *lpw++ = pixel; - -} - -/* Write an array of RGBA pixels with a boolean mask. */ -static void write_rgba_pixels_16(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - const GLubyte rgba[][4], - const GLubyte mask[]) -{ - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - (void) ctx; - for (i=0; i<n; i++) - if (mask[i]) - WMSETPIXEL16(pwfb, FLIP(y[i]), x[i], - rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]); -} - -/* - * Write an array of pixels with a boolean mask. The current color - * is used for all pixels. - */ -static void write_mono_rgba_pixels_16(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, - const GLint x[], const GLint y[], - const GLchan color[4], - const GLubyte mask[]) -{ - GLuint i; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - (void) ctx; - for (i=0; i<n; i++) - if (mask[i]) - WMSETPIXEL16(pwfb, FLIP(y[i]),x[i],color[RCOMP], - color[GCOMP], color[BCOMP]); -} - -/* Read a horizontal span of color pixels. */ -static void read_rgba_span_16(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, GLint x, GLint y, - GLubyte rgba[][4] ) -{ - GLuint i, pixel; - LPWORD lpw; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - - y = FLIP(y); - lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; - for (i=0; i<n; i++) { - pixel = lpw[i]; - /* Windows uses 5,5,5 for 16-bit */ - rgba[i][RCOMP] = (pixel & 0x7c00) >> 7; - rgba[i][GCOMP] = (pixel & 0x03e0) >> 2; - rgba[i][BCOMP] = (pixel & 0x001f) << 3; - rgba[i][ACOMP] = 255; - } -} - - -/* Read an array of color pixels. */ -static void read_rgba_pixels_16(const struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint n, const GLint x[], const GLint y[], - GLubyte rgba[][4]) -{ - GLuint i, pixel; - LPWORD lpw; - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); - - for (i=0; i<n; i++) { - GLint y2 = FLIP(y[i]); - lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y2)) + x[i]; - pixel = *lpw; - /* Windows uses 5,5,5 for 16-bit */ - rgba[i][RCOMP] = (pixel & 0x7c00) >> 7; - rgba[i][GCOMP] = (pixel & 0x03e0) >> 2; - rgba[i][BCOMP] = (pixel & 0x001f) << 3; - rgba[i][ACOMP] = 255; - } -} - - - - -/**********************************************************************/ -/***** BUFFER Functions *****/ -/**********************************************************************/ - - - - -static void -wmesa_delete_renderbuffer(struct gl_renderbuffer *rb) -{ - free(rb); -} - - -/** - * This is called by Mesa whenever it determines that the window size - * has changed. Do whatever's needed to cope with that. - */ -static GLboolean -wmesa_renderbuffer_storage(struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLenum internalFormat, - GLuint width, - GLuint height) -{ - rb->Width = width; - rb->Height = height; - return GL_TRUE; -} - - -/** - * Plug in the Get/PutRow/Values functions for a renderbuffer depending - * on if we're drawing to the front or back color buffer. - */ -void wmesa_set_renderbuffer_funcs(struct gl_renderbuffer *rb, int pixelformat, - int cColorBits, int double_buffer) -{ - if (double_buffer) { - /* back buffer */ - /* Picking the correct span functions is important because - * the DIB was allocated with the indicated depth. */ - switch(pixelformat) { - case PF_5R6G5B: - rb->PutRow = write_rgba_span_16; - rb->PutRowRGB = write_rgb_span_16; - rb->PutMonoRow = write_mono_rgba_span_16; - rb->PutValues = write_rgba_pixels_16; - rb->PutMonoValues = write_mono_rgba_pixels_16; - rb->GetRow = read_rgba_span_16; - rb->GetValues = read_rgba_pixels_16; - break; - case PF_8R8G8B: - if (cColorBits == 24) - { - rb->PutRow = write_rgba_span_24; - rb->PutRowRGB = write_rgb_span_24; - rb->PutMonoRow = write_mono_rgba_span_24; - rb->PutValues = write_rgba_pixels_24; - rb->PutMonoValues = write_mono_rgba_pixels_24; - rb->GetRow = read_rgba_span_24; - rb->GetValues = read_rgba_pixels_24; - } - else - { - rb->PutRow = write_rgba_span_32; - rb->PutRowRGB = write_rgb_span_32; - rb->PutMonoRow = write_mono_rgba_span_32; - rb->PutValues = write_rgba_pixels_32; - rb->PutMonoValues = write_mono_rgba_pixels_32; - rb->GetRow = read_rgba_span_32; - rb->GetValues = read_rgba_pixels_32; - } - break; - default: - break; - } - } - else { - /* front buffer (actual Windows window) */ - rb->PutRow = write_rgba_span_front; - rb->PutRowRGB = write_rgb_span_front; - rb->PutMonoRow = write_mono_rgba_span_front; - rb->PutValues = write_rgba_pixels_front; - rb->PutMonoValues = write_mono_rgba_pixels_front; - rb->GetRow = read_rgba_span_front; - rb->GetValues = read_rgba_pixels_front; - } -} - -/** - * Called by ctx->Driver.ResizeBuffers() - * Resize the front/back colorbuffers to match the latest window size. - */ -static void -wmesa_resize_buffers(struct gl_context *ctx, struct gl_framebuffer *buffer, - GLuint width, GLuint height) -{ - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_framebuffer(buffer); - - if (pwfb->Base.Width != width || pwfb->Base.Height != height) { - /* Realloc back buffer */ - if (ctx->Visual.doubleBufferMode == 1) { - wmDeleteBackingStore(pwfb); - wmCreateBackingStore(pwfb, width, height); - } - } - _mesa_resize_framebuffer(ctx, buffer, width, height); -} - - -/** - * Called by glViewport. - * This is a good time for us to poll the current window size and adjust - * our renderbuffers to match the current window size. - * Remember, we have no opportunity to respond to conventional - * resize events since the driver has no event loop. - * Thus, we poll. - * MakeCurrent also ends up making a call here, so that ensures - * we get the viewport set correctly, even if the app does not call - * glViewport and relies on the defaults. - */ -static void wmesa_viewport(struct gl_context *ctx, - GLint x, GLint y, - GLsizei width, GLsizei height) -{ - WMesaContext pwc = wmesa_context(ctx); - GLuint new_width, new_height; - - wmesa_get_buffer_size(ctx->WinSysDrawBuffer, &new_width, &new_height); - - /** - * Resize buffers if the window size changed. - */ - wmesa_resize_buffers(ctx, ctx->WinSysDrawBuffer, new_width, new_height); - ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */ -} - - - - -/** - * Called when the driver should update it's state, based on the new_state - * flags. - */ -static void wmesa_update_state(struct gl_context *ctx, GLuint new_state) -{ - _swrast_InvalidateState(ctx, new_state); - _swsetup_InvalidateState(ctx, new_state); - _vbo_InvalidateState(ctx, new_state); - _tnl_InvalidateState(ctx, new_state); - - /* TODO - This code is not complete yet because I - * don't know what to do for all state updates. - */ - - if (new_state & _NEW_BUFFERS) { - } -} - - - - - -/**********************************************************************/ -/***** WMESA Functions *****/ -/**********************************************************************/ - -WMesaContext WMesaCreateContext(HDC hDC, - HPALETTE* Pal, - GLboolean rgb_flag, - GLboolean db_flag, - GLboolean alpha_flag) -{ - WMesaContext c; - struct dd_function_table functions; - GLint red_bits, green_bits, blue_bits, alpha_bits; - struct gl_context *ctx; - struct gl_config *visual; - - (void) Pal; - - /* Indexed mode not supported */ - if (!rgb_flag) - return NULL; - - /* Allocate wmesa context */ - c = CALLOC_STRUCT(wmesa_context); - if (!c) - return NULL; - -#if 0 - /* I do not understand this contributed code */ - /* Support memory and device contexts */ - if(WindowFromDC(hDC) != NULL) { - c->hDC = GetDC(WindowFromDC(hDC)); /* huh ???? */ - } - else { - c->hDC = hDC; - } -#else - c->hDC = hDC; -#endif - - /* Get data for visual */ - /* Dealing with this is actually a bit of overkill because Mesa will end - * up treating all color component size requests less than 8 by using - * a single byte per channel. In addition, the interface to the span - * routines passes colors as an entire byte per channel anyway, so there - * is nothing to be saved by telling the visual to be 16 bits if the device - * is 16 bits. That is, Mesa is going to compute colors down to 8 bits per - * channel anyway. - * But we go through the motions here anyway. - */ - switch (GetDeviceCaps(c->hDC, BITSPIXEL)) { - case 16: - red_bits = green_bits = blue_bits = 5; - alpha_bits = 0; - break; - default: - red_bits = green_bits = blue_bits = 8; - alpha_bits = 8; - break; - } - /* Create visual based on flags */ - visual = _mesa_create_visual(db_flag, /* db_flag */ - GL_FALSE, /* stereo */ - red_bits, green_bits, blue_bits, /* color RGB */ - alpha_flag ? alpha_bits : 0, /* color A */ - DEFAULT_SOFTWARE_DEPTH_BITS, /* depth_bits */ - 8, /* stencil_bits */ - 16,16,16, /* accum RGB */ - alpha_flag ? 16 : 0, /* accum A */ - 1); /* num samples */ - - if (!visual) { - free(c); - return NULL; - } - - /* Set up driver functions */ - _mesa_init_driver_functions(&functions); - functions.GetString = wmesa_get_string; - functions.UpdateState = wmesa_update_state; - functions.GetBufferSize = wmesa_get_buffer_size; - functions.Flush = wmesa_flush; - functions.Clear = clear; - functions.ClearColor = clear_color; - functions.ResizeBuffers = wmesa_resize_buffers; - functions.Viewport = wmesa_viewport; - - /* initialize the Mesa context data */ - ctx = &c->gl_ctx; - _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); - - _mesa_enable_sw_extensions(ctx); - _mesa_enable_1_3_extensions(ctx); - _mesa_enable_1_4_extensions(ctx); - _mesa_enable_1_5_extensions(ctx); - _mesa_enable_2_0_extensions(ctx); - _mesa_enable_2_1_extensions(ctx); - - _mesa_meta_init(ctx); - - /* Initialize the software rasterizer and helper modules. */ - if (!_swrast_CreateContext(ctx) || - !_vbo_CreateContext(ctx) || - !_tnl_CreateContext(ctx) || - !_swsetup_CreateContext(ctx)) { - _mesa_free_context_data(ctx); - free(c); - return NULL; - } - _swsetup_Wakeup(ctx); - TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline; - - return c; -} - - -void WMesaDestroyContext( WMesaContext pwc ) -{ - struct gl_context *ctx = &pwc->gl_ctx; - WMesaFramebuffer pwfb; - GET_CURRENT_CONTEXT(cur_ctx); - - if (cur_ctx == ctx) { - /* unbind current if deleting current context */ - WMesaMakeCurrent(NULL, NULL); - } - - /* clean up frame buffer resources */ - pwfb = wmesa_lookup_framebuffer(pwc->hDC); - if (pwfb) { - if (ctx->Visual.doubleBufferMode == 1) - wmDeleteBackingStore(pwfb); - wmesa_free_framebuffer(pwc->hDC); - } - - /* Release for device, not memory contexts */ - if (WindowFromDC(pwc->hDC) != NULL) - { - ReleaseDC(WindowFromDC(pwc->hDC), pwc->hDC); - } - DeleteObject(pwc->clearPen); - DeleteObject(pwc->clearBrush); - - _mesa_meta_free(ctx); - - _swsetup_DestroyContext(ctx); - _tnl_DestroyContext(ctx); - _vbo_DestroyContext(ctx); - _swrast_DestroyContext(ctx); - - _mesa_free_context_data(ctx); - free(pwc); -} - - -/** - * Create a new color renderbuffer. - */ -struct gl_renderbuffer * -wmesa_new_renderbuffer(void) -{ - struct gl_renderbuffer *rb = CALLOC_STRUCT(gl_renderbuffer); - if (!rb) - return NULL; - - _mesa_init_renderbuffer(rb, (GLuint)0); - - rb->_BaseFormat = GL_RGBA; - rb->InternalFormat = GL_RGBA; - rb->DataType = CHAN_TYPE; - rb->Delete = wmesa_delete_renderbuffer; - rb->AllocStorage = wmesa_renderbuffer_storage; - return rb; -} - - -void WMesaMakeCurrent(WMesaContext c, HDC hdc) -{ - WMesaFramebuffer pwfb; - - { - /* return if already current */ - GET_CURRENT_CONTEXT(ctx); - WMesaContext pwc = wmesa_context(ctx); - if (pwc && c == pwc && pwc->hDC == hdc) - return; - } - - pwfb = wmesa_lookup_framebuffer(hdc); - - /* Lazy creation of framebuffers */ - if (c && !pwfb && hdc) { - struct gl_renderbuffer *rb; - struct gl_config *visual = &c->gl_ctx.Visual; - GLuint width, height; - - get_window_size(hdc, &width, &height); - - c->clearPen = CreatePen(PS_SOLID, 1, 0); - c->clearBrush = CreateSolidBrush(0); - - pwfb = wmesa_new_framebuffer(hdc, visual); - - /* Create back buffer if double buffered */ - if (visual->doubleBufferMode == 1) { - wmCreateBackingStore(pwfb, width, height); - } - - /* make render buffers */ - if (visual->doubleBufferMode == 1) { - rb = wmesa_new_renderbuffer(); - _mesa_add_renderbuffer(&pwfb->Base, BUFFER_BACK_LEFT, rb); - wmesa_set_renderbuffer_funcs(rb, pwfb->pixelformat, pwfb->cColorBits, 1); - } - rb = wmesa_new_renderbuffer(); - _mesa_add_renderbuffer(&pwfb->Base, BUFFER_FRONT_LEFT, rb); - wmesa_set_renderbuffer_funcs(rb, pwfb->pixelformat, pwfb->cColorBits, 0); - - /* Let Mesa own the Depth, Stencil, and Accum buffers */ - _mesa_add_soft_renderbuffers(&pwfb->Base, - GL_FALSE, /* color */ - visual->depthBits > 0, - visual->stencilBits > 0, - visual->accumRedBits > 0, - visual->alphaBits >0, - GL_FALSE); - } - - if (c && pwfb) - _mesa_make_current(&c->gl_ctx, &pwfb->Base, &pwfb->Base); - else - _mesa_make_current(NULL, NULL, NULL); -} - - -void WMesaSwapBuffers( HDC hdc ) -{ - GET_CURRENT_CONTEXT(ctx); - WMesaContext pwc = wmesa_context(ctx); - WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(hdc); - - if (!pwfb) { - _mesa_problem(NULL, "wmesa: swapbuffers on unknown hdc"); - return; - } - - /* If we're swapping the buffer associated with the current context - * we have to flush any pending rendering commands first. - */ - if (pwc->hDC == hdc) { - _mesa_notifySwapBuffers(ctx); - - BitBlt(pwfb->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height, - pwfb->dib_hDC, 0, 0, SRCCOPY); - } - else { - /* XXX for now only allow swapping current window */ - _mesa_problem(NULL, "wmesa: can't swap non-current window"); - } -} - -void WMesaShareLists(WMesaContext ctx_to_share, WMesaContext ctx) -{ - _mesa_share_state(&ctx->gl_ctx, &ctx_to_share->gl_ctx); -} - +/*
+ * Windows (Win32/Win64) device driver for Mesa
+ *
+ */
+
+#include "wmesadef.h"
+#include "colors.h"
+#include <GL/wmesa.h>
+#include <winuser.h>
+#include "context.h"
+#include "extensions.h"
+#include "framebuffer.h"
+#include "renderbuffer.h"
+#include "drivers/common/driverfuncs.h"
+#include "drivers/common/meta.h"
+#include "vbo/vbo.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"
+
+
+/* linked list of our Framebuffers (windows) */
+static WMesaFramebuffer FirstFramebuffer = NULL;
+
+
+/**
+ * Create a new WMesaFramebuffer object which will correspond to the
+ * given HDC (Window handle).
+ */
+WMesaFramebuffer
+wmesa_new_framebuffer(HDC hdc, struct gl_config *visual)
+{
+ WMesaFramebuffer pwfb
+ = (WMesaFramebuffer) malloc(sizeof(struct wmesa_framebuffer));
+ if (pwfb) {
+ _mesa_initialize_window_framebuffer(&pwfb->Base, visual);
+ pwfb->hDC = hdc;
+ /* insert at head of list */
+ pwfb->next = FirstFramebuffer;
+ FirstFramebuffer = pwfb;
+ }
+ return pwfb;
+}
+
+/**
+ * Given an hdc, free the corresponding WMesaFramebuffer
+ */
+void
+wmesa_free_framebuffer(HDC hdc)
+{
+ WMesaFramebuffer pwfb, prev;
+ for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) {
+ if (pwfb->hDC == hdc)
+ break;
+ prev = pwfb;
+ }
+ if (pwfb) {
+ struct gl_framebuffer *fb;
+ if (pwfb == FirstFramebuffer)
+ FirstFramebuffer = pwfb->next;
+ else
+ prev->next = pwfb->next;
+ fb = &pwfb->Base;
+ _mesa_reference_framebuffer(&fb, NULL);
+ }
+}
+
+/**
+ * Given an hdc, return the corresponding WMesaFramebuffer
+ */
+WMesaFramebuffer
+wmesa_lookup_framebuffer(HDC hdc)
+{
+ WMesaFramebuffer pwfb;
+ for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) {
+ if (pwfb->hDC == hdc)
+ return pwfb;
+ }
+ return NULL;
+}
+
+
+/**
+ * Given a struct gl_framebuffer, return the corresponding WMesaFramebuffer.
+ */
+static WMesaFramebuffer wmesa_framebuffer(struct gl_framebuffer *fb)
+{
+ return (WMesaFramebuffer) fb;
+}
+
+
+/**
+ * Given a struct gl_context, return the corresponding WMesaContext.
+ */
+static WMesaContext wmesa_context(const struct gl_context *ctx)
+{
+ return (WMesaContext) ctx;
+}
+
+
+/*
+ * Every driver should implement a GetString function in order to
+ * return a meaningful GL_RENDERER string.
+ */
+static const GLubyte *wmesa_get_string(struct gl_context *ctx, GLenum name)
+{
+ return (name == GL_RENDERER) ?
+ (GLubyte *) "Mesa Windows GDI Driver" : NULL;
+}
+
+
+/*
+ * Determine the pixel format based on the pixel size.
+ */
+static void wmSetPixelFormat(WMesaFramebuffer pwfb, HDC hDC)
+{
+ pwfb->cColorBits = GetDeviceCaps(hDC, BITSPIXEL);
+
+ /* Only 16 and 32 bit targets are supported now */
+ assert(pwfb->cColorBits == 0 ||
+ pwfb->cColorBits == 16 ||
+ pwfb->cColorBits == 24 ||
+ pwfb->cColorBits == 32);
+
+ switch(pwfb->cColorBits){
+ case 8:
+ pwfb->pixelformat = PF_INDEX8;
+ break;
+ case 16:
+ pwfb->pixelformat = PF_5R6G5B;
+ break;
+ case 24:
+ case 32:
+ pwfb->pixelformat = PF_8R8G8B;
+ break;
+ default:
+ pwfb->pixelformat = PF_BADFORMAT;
+ }
+}
+
+
+/**
+ * Create DIB for back buffer.
+ * We write into this memory with the span routines and then blit it
+ * to the window on a buffer swap.
+ */
+BOOL wmCreateBackingStore(WMesaFramebuffer pwfb, long lxSize, long lySize)
+{
+ HDC hdc = pwfb->hDC;
+ LPBITMAPINFO pbmi = &(pwfb->bmi);
+ HDC hic;
+
+ pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ pbmi->bmiHeader.biWidth = lxSize;
+ pbmi->bmiHeader.biHeight= -lySize;
+ pbmi->bmiHeader.biPlanes = 1;
+ pbmi->bmiHeader.biBitCount = GetDeviceCaps(pwfb->hDC, BITSPIXEL);
+ pbmi->bmiHeader.biCompression = BI_RGB;
+ pbmi->bmiHeader.biSizeImage = 0;
+ pbmi->bmiHeader.biXPelsPerMeter = 0;
+ pbmi->bmiHeader.biYPelsPerMeter = 0;
+ pbmi->bmiHeader.biClrUsed = 0;
+ pbmi->bmiHeader.biClrImportant = 0;
+
+ pwfb->cColorBits = pbmi->bmiHeader.biBitCount;
+ pwfb->ScanWidth = (lxSize * (pwfb->cColorBits / 8) + 3) & ~3;
+
+ hic = CreateIC("display", NULL, NULL, NULL);
+ pwfb->dib_hDC = CreateCompatibleDC(hic);
+
+ pwfb->hbmDIB = CreateDIBSection(hic,
+ &pwfb->bmi,
+ DIB_RGB_COLORS,
+ (void **)&(pwfb->pbPixels),
+ 0,
+ 0);
+ pwfb->hOldBitmap = SelectObject(pwfb->dib_hDC, pwfb->hbmDIB);
+
+ DeleteDC(hic);
+
+ wmSetPixelFormat(pwfb, pwfb->hDC);
+ return TRUE;
+}
+
+
+static wmDeleteBackingStore(WMesaFramebuffer pwfb)
+{
+ if (pwfb->hbmDIB) {
+ SelectObject(pwfb->dib_hDC, pwfb->hOldBitmap);
+ DeleteDC(pwfb->dib_hDC);
+ DeleteObject(pwfb->hbmDIB);
+ }
+}
+
+
+/**
+ * Find the width and height of the window named by hdc.
+ */
+static void
+get_window_size(HDC hdc, GLuint *width, GLuint *height)
+{
+ if (WindowFromDC(hdc)) {
+ RECT rect;
+ GetClientRect(WindowFromDC(hdc), &rect);
+ *width = rect.right - rect.left;
+ *height = rect.bottom - rect.top;
+ }
+ else { /* Memory context */
+ /* From contributed code - use the size of the desktop
+ * for the size of a memory context (?) */
+ *width = GetDeviceCaps(hdc, HORZRES);
+ *height = GetDeviceCaps(hdc, VERTRES);
+ }
+}
+
+
+static void
+wmesa_get_buffer_size(struct gl_framebuffer *buffer, GLuint *width, GLuint *height)
+{
+ WMesaFramebuffer pwfb = wmesa_framebuffer(buffer);
+ get_window_size(pwfb->hDC, width, height);
+}
+
+
+static void wmesa_flush(struct gl_context *ctx)
+{
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->WinSysDrawBuffer);
+
+ if (ctx->Visual.doubleBufferMode == 1) {
+ BitBlt(pwfb->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height,
+ pwfb->dib_hDC, 0, 0, SRCCOPY);
+ }
+ else {
+ /* Do nothing for single buffer */
+ }
+}
+
+
+/**********************************************************************/
+/***** CLEAR Functions *****/
+/**********************************************************************/
+
+/* If we do not implement these, Mesa clears the buffers via the pixel
+ * span writing interface, which is very slow for a clear operation.
+ */
+
+/*
+ * Set the color used to clear the color buffer.
+ */
+static void clear_color(struct gl_context *ctx, const GLfloat color[4])
+{
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ GLubyte col[3];
+ UINT bytesPerPixel = pwfb->cColorBits / 8;
+
+ CLAMPED_FLOAT_TO_UBYTE(col[0], color[0]);
+ CLAMPED_FLOAT_TO_UBYTE(col[1], color[1]);
+ CLAMPED_FLOAT_TO_UBYTE(col[2], color[2]);
+ pwc->clearColorRef = RGB(col[0], col[1], col[2]);
+ DeleteObject(pwc->clearPen);
+ DeleteObject(pwc->clearBrush);
+ pwc->clearPen = CreatePen(PS_SOLID, 1, pwc->clearColorRef);
+ pwc->clearBrush = CreateSolidBrush(pwc->clearColorRef);
+}
+
+
+/*
+ * Clear the specified region of the color buffer using the clear color
+ * or index as specified by one of the two functions above.
+ *
+ * This procedure clears either the front and/or the back COLOR buffers.
+ * Only the "left" buffer is cleared since we are not stereo.
+ * Clearing of the other non-color buffers is left to the swrast.
+ */
+
+static void clear(struct gl_context *ctx, GLbitfield mask)
+{
+#define FLIP(Y) (ctx->DrawBuffer->Height - (Y) - 1)
+ const GLint x = ctx->DrawBuffer->_Xmin;
+ const GLint y = ctx->DrawBuffer->_Ymin;
+ const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
+ const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
+
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ int done = 0;
+
+ /* Let swrast do all the work if the masks are not set to
+ * clear all channels. */
+ if (!ctx->Color.ColorMask[0][0] ||
+ !ctx->Color.ColorMask[0][1] ||
+ !ctx->Color.ColorMask[0][2] ||
+ !ctx->Color.ColorMask[0][3]) {
+ _swrast_Clear(ctx, mask);
+ return;
+ }
+
+ /* Back buffer */
+ if (mask & BUFFER_BIT_BACK_LEFT) {
+
+ int i, rowSize;
+ UINT bytesPerPixel = pwfb->cColorBits / 8;
+ LPBYTE lpb, clearRow;
+ LPWORD lpw;
+ BYTE bColor;
+ WORD wColor;
+ BYTE r, g, b;
+ DWORD dwColor;
+ LPDWORD lpdw;
+
+ /* Try for a fast clear - clearing entire buffer with a single
+ * byte value. */
+ if (width == ctx->DrawBuffer->Width &&
+ height == ctx->DrawBuffer->Height) { /* entire buffer */
+ /* Now check for an easy clear value */
+ switch (bytesPerPixel) {
+ case 1:
+ bColor = BGR8(GetRValue(pwc->clearColorRef),
+ GetGValue(pwc->clearColorRef),
+ GetBValue(pwc->clearColorRef));
+ memset(pwfb->pbPixels, bColor,
+ pwfb->ScanWidth * height);
+ done = 1;
+ break;
+ case 2:
+ wColor = BGR16(GetRValue(pwc->clearColorRef),
+ GetGValue(pwc->clearColorRef),
+ GetBValue(pwc->clearColorRef));
+ if (((wColor >> 8) & 0xff) == (wColor & 0xff)) {
+ memset(pwfb->pbPixels, wColor & 0xff,
+ pwfb->ScanWidth * height);
+ done = 1;
+ }
+ break;
+ case 3:
+ /* fall through */
+ case 4:
+ if (GetRValue(pwc->clearColorRef) ==
+ GetGValue(pwc->clearColorRef) &&
+ GetRValue(pwc->clearColorRef) ==
+ GetBValue(pwc->clearColorRef)) {
+ memset(pwfb->pbPixels,
+ GetRValue(pwc->clearColorRef),
+ pwfb->ScanWidth * height);
+ done = 1;
+ }
+ break;
+ default:
+ break;
+ }
+ } /* all */
+
+ if (!done) {
+ /* Need to clear a row at a time. Begin by setting the first
+ * row in the area to be cleared to the clear color. */
+
+ clearRow = pwfb->pbPixels +
+ pwfb->ScanWidth * FLIP(y) +
+ bytesPerPixel * x;
+ switch (bytesPerPixel) {
+ case 1:
+ lpb = clearRow;
+ bColor = BGR8(GetRValue(pwc->clearColorRef),
+ GetGValue(pwc->clearColorRef),
+ GetBValue(pwc->clearColorRef));
+ memset(lpb, bColor, width);
+ break;
+ case 2:
+ lpw = (LPWORD)clearRow;
+ wColor = BGR16(GetRValue(pwc->clearColorRef),
+ GetGValue(pwc->clearColorRef),
+ GetBValue(pwc->clearColorRef));
+ for (i=0; i<width; i++)
+ *lpw++ = wColor;
+ break;
+ case 3:
+ lpb = clearRow;
+ r = GetRValue(pwc->clearColorRef);
+ g = GetGValue(pwc->clearColorRef);
+ b = GetBValue(pwc->clearColorRef);
+ for (i=0; i<width; i++) {
+ *lpb++ = b;
+ *lpb++ = g;
+ *lpb++ = r;
+ }
+ break;
+ case 4:
+ lpdw = (LPDWORD)clearRow;
+ dwColor = BGR32(GetRValue(pwc->clearColorRef),
+ GetGValue(pwc->clearColorRef),
+ GetBValue(pwc->clearColorRef));
+ for (i=0; i<width; i++)
+ *lpdw++ = dwColor;
+ break;
+ default:
+ break;
+ } /* switch */
+
+ /* copy cleared row to other rows in buffer */
+ lpb = clearRow - pwfb->ScanWidth;
+ rowSize = width * bytesPerPixel;
+ for (i=1; i<height; i++) {
+ memcpy(lpb, clearRow, rowSize);
+ lpb -= pwfb->ScanWidth;
+ }
+ } /* not done */
+ mask &= ~BUFFER_BIT_BACK_LEFT;
+ } /* back buffer */
+
+ /* front buffer */
+ if (mask & BUFFER_BIT_FRONT_LEFT) {
+ HDC DC = pwc->hDC;
+ HPEN Old_Pen = SelectObject(DC, pwc->clearPen);
+ HBRUSH Old_Brush = SelectObject(DC, pwc->clearBrush);
+ Rectangle(DC,
+ x,
+ FLIP(y) + 1,
+ x + width + 1,
+ FLIP(y) - height + 1);
+ SelectObject(DC, Old_Pen);
+ SelectObject(DC, Old_Brush);
+ mask &= ~BUFFER_BIT_FRONT_LEFT;
+ } /* front buffer */
+
+ /* Call swrast if there is anything left to clear (like DEPTH) */
+ if (mask)
+ _swrast_Clear(ctx, mask);
+
+#undef FLIP
+}
+
+
+/**********************************************************************/
+/***** PIXEL Functions *****/
+/**********************************************************************/
+
+#define FLIP(Y) (rb->Height - (Y) - 1)
+
+
+/**
+ ** Front Buffer reading/writing
+ ** These are slow, but work with all non-indexed visual types.
+ **/
+
+/* Write a horizontal span of RGBA color pixels with a boolean mask. */
+static void write_rgba_span_front(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLubyte rgba[][4],
+ const GLubyte mask[] )
+{
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(pwc->hDC);
+ CONST BITMAPINFO bmi=
+ {
+ {
+ sizeof(BITMAPINFOHEADER),
+ n, 1, 1, 32, BI_RGB, 0, 1, 1, 0, 0
+ }
+ };
+ HBITMAP bmp=0;
+ HDC mdc=0;
+ typedef union
+ {
+ unsigned i;
+ struct {
+ unsigned b:8, g:8, r:8, a:8;
+ };
+ } BGRA;
+ BGRA *bgra, c;
+ GLuint i;
+
+ if (n < 16) { // the value 16 is just guessed
+ y=FLIP(y);
+ if (mask) {
+ for (i=0; i<n; i++)
+ if (mask[i])
+ SetPixel(pwc->hDC, x+i, y,
+ RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]));
+ }
+ else {
+ for (i=0; i<n; i++)
+ SetPixel(pwc->hDC, x+i, y,
+ RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]));
+ }
+ }
+ else {
+ if (!pwfb) {
+ _mesa_problem(NULL, "wmesa: write_rgba_span_front on unknown hdc");
+ return;
+ }
+ bgra=malloc(n*sizeof(BGRA));
+ if (!bgra) {
+ _mesa_problem(NULL, "wmesa: write_rgba_span_front: out of memory");
+ return;
+ }
+ c.a=0;
+ if (mask) {
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ c.r=rgba[i][RCOMP];
+ c.g=rgba[i][GCOMP];
+ c.b=rgba[i][BCOMP];
+ c.a=rgba[i][ACOMP];
+ bgra[i]=c;
+ }
+ else
+ bgra[i].i=0;
+ }
+ }
+ else {
+ for (i=0; i<n; i++) {
+ c.r=rgba[i][RCOMP];
+ c.g=rgba[i][GCOMP];
+ c.b=rgba[i][BCOMP];
+ c.a=rgba[i][ACOMP];
+ bgra[i]=c;
+ }
+ }
+ bmp=CreateBitmap(n, 1, 1, 32, bgra);
+ mdc=CreateCompatibleDC(pwfb->hDC);
+ SelectObject(mdc, bmp);
+ y=FLIP(y);
+ BitBlt(pwfb->hDC, x, y, n, 1, mdc, 0, 0, SRCCOPY);
+ SelectObject(mdc, 0);
+ DeleteObject(bmp);
+ DeleteDC(mdc);
+ free(bgra);
+ }
+}
+
+/* Write a horizontal span of RGB color pixels with a boolean mask. */
+static void write_rgb_span_front(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLubyte rgb[][3],
+ const GLubyte mask[] )
+{
+ WMesaContext pwc = wmesa_context(ctx);
+ GLuint i;
+
+ (void) ctx;
+ y=FLIP(y);
+ if (mask) {
+ for (i=0; i<n; i++)
+ if (mask[i])
+ SetPixel(pwc->hDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP],
+ rgb[i][BCOMP]));
+ }
+ else {
+ for (i=0; i<n; i++)
+ SetPixel(pwc->hDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP],
+ rgb[i][BCOMP]));
+ }
+
+}
+
+/*
+ * Write a horizontal span of pixels with a boolean mask. The current color
+ * is used for all pixels.
+ */
+static void write_mono_rgba_span_front(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLchan color[4],
+ const GLubyte mask[])
+{
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ COLORREF colorref;
+
+ (void) ctx;
+ colorref = RGB(color[RCOMP], color[GCOMP], color[BCOMP]);
+ y=FLIP(y);
+ if (mask) {
+ for (i=0; i<n; i++)
+ if (mask[i])
+ SetPixel(pwc->hDC, x+i, y, colorref);
+ }
+ else
+ for (i=0; i<n; i++)
+ SetPixel(pwc->hDC, x+i, y, colorref);
+
+}
+
+/* Write an array of RGBA pixels with a boolean mask. */
+static void write_rgba_pixels_front(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n,
+ const GLint x[], const GLint y[],
+ const GLubyte rgba[][4],
+ const GLubyte mask[] )
+{
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ (void) ctx;
+ for (i=0; i<n; i++)
+ if (mask[i])
+ SetPixel(pwc->hDC, x[i], FLIP(y[i]),
+ RGB(rgba[i][RCOMP], rgba[i][GCOMP],
+ rgba[i][BCOMP]));
+}
+
+
+
+/*
+ * Write an array of pixels with a boolean mask. The current color
+ * is used for all pixels.
+ */
+static void write_mono_rgba_pixels_front(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n,
+ const GLint x[], const GLint y[],
+ const GLchan color[4],
+ const GLubyte mask[] )
+{
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ COLORREF colorref;
+ (void) ctx;
+ colorref = RGB(color[RCOMP], color[GCOMP], color[BCOMP]);
+ for (i=0; i<n; i++)
+ if (mask[i])
+ SetPixel(pwc->hDC, x[i], FLIP(y[i]), colorref);
+}
+
+/* Read a horizontal span of color pixels. */
+static void read_rgba_span_front(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ GLubyte rgba[][4] )
+{
+ WMesaContext pwc = wmesa_context(ctx);
+ GLuint i;
+ COLORREF Color;
+ y = FLIP(y);
+ for (i=0; i<n; i++) {
+ Color = GetPixel(pwc->hDC, x+i, y);
+ rgba[i][RCOMP] = GetRValue(Color);
+ rgba[i][GCOMP] = GetGValue(Color);
+ rgba[i][BCOMP] = GetBValue(Color);
+ rgba[i][ACOMP] = 255;
+ }
+}
+
+
+/* Read an array of color pixels. */
+static void read_rgba_pixels_front(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, const GLint x[], const GLint y[],
+ GLubyte rgba[][4])
+{
+ WMesaContext pwc = wmesa_context(ctx);
+ GLuint i;
+ COLORREF Color;
+ for (i=0; i<n; i++) {
+ GLint y2 = FLIP(y[i]);
+ Color = GetPixel(pwc->hDC, x[i], y2);
+ rgba[i][RCOMP] = GetRValue(Color);
+ rgba[i][GCOMP] = GetGValue(Color);
+ rgba[i][BCOMP] = GetBValue(Color);
+ rgba[i][ACOMP] = 255;
+ }
+}
+
+/*********************************************************************/
+
+/* DOUBLE BUFFER 32-bit */
+
+#define WMSETPIXEL32(pwc, y, x, r, g, b) { \
+LPDWORD lpdw = ((LPDWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \
+*lpdw = BGR32((r),(g),(b)); }
+
+
+
+/* Write a horizontal span of RGBA color pixels with a boolean mask. */
+static void write_rgba_span_32(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLubyte rgba[][4],
+ const GLubyte mask[] )
+{
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ GLuint i;
+ LPDWORD lpdw;
+
+ (void) ctx;
+
+ y=FLIP(y);
+ lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
+ if (mask) {
+ for (i=0; i<n; i++)
+ if (mask[i])
+ lpdw[i] = BGR32(rgba[i][RCOMP], rgba[i][GCOMP],
+ rgba[i][BCOMP]);
+ }
+ else {
+ for (i=0; i<n; i++)
+ *lpdw++ = BGR32(rgba[i][RCOMP], rgba[i][GCOMP],
+ rgba[i][BCOMP]);
+ }
+}
+
+
+/* Write a horizontal span of RGB color pixels with a boolean mask. */
+static void write_rgb_span_32(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLubyte rgb[][3],
+ const GLubyte mask[] )
+{
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ GLuint i;
+ LPDWORD lpdw;
+
+ (void) ctx;
+
+ y=FLIP(y);
+ lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
+ if (mask) {
+ for (i=0; i<n; i++)
+ if (mask[i])
+ lpdw[i] = BGR32(rgb[i][RCOMP], rgb[i][GCOMP],
+ rgb[i][BCOMP]);
+ }
+ else {
+ for (i=0; i<n; i++)
+ *lpdw++ = BGR32(rgb[i][RCOMP], rgb[i][GCOMP],
+ rgb[i][BCOMP]);
+ }
+}
+
+/*
+ * Write a horizontal span of pixels with a boolean mask. The current color
+ * is used for all pixels.
+ */
+static void write_mono_rgba_span_32(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLchan color[4],
+ const GLubyte mask[])
+{
+ LPDWORD lpdw;
+ DWORD pixel;
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
+ y=FLIP(y);
+ pixel = BGR32(color[RCOMP], color[GCOMP], color[BCOMP]);
+ if (mask) {
+ for (i=0; i<n; i++)
+ if (mask[i])
+ lpdw[i] = pixel;
+ }
+ else
+ for (i=0; i<n; i++)
+ *lpdw++ = pixel;
+
+}
+
+/* Write an array of RGBA pixels with a boolean mask. */
+static void write_rgba_pixels_32(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, const GLint x[], const GLint y[],
+ const GLubyte rgba[][4],
+ const GLubyte mask[])
+{
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ for (i=0; i<n; i++)
+ if (mask[i])
+ WMSETPIXEL32(pwfb, FLIP(y[i]), x[i],
+ rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]);
+}
+
+/*
+ * Write an array of pixels with a boolean mask. The current color
+ * is used for all pixels.
+ */
+static void write_mono_rgba_pixels_32(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n,
+ const GLint x[], const GLint y[],
+ const GLchan color[4],
+ const GLubyte mask[])
+{
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ for (i=0; i<n; i++)
+ if (mask[i])
+ WMSETPIXEL32(pwfb, FLIP(y[i]),x[i],color[RCOMP],
+ color[GCOMP], color[BCOMP]);
+}
+
+/* Read a horizontal span of color pixels. */
+static void read_rgba_span_32(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ GLubyte rgba[][4] )
+{
+ GLuint i;
+ DWORD pixel;
+ LPDWORD lpdw;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+
+ y = FLIP(y);
+ lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
+ for (i=0; i<n; i++) {
+ pixel = lpdw[i];
+ rgba[i][RCOMP] = (GLubyte)((pixel & 0x00ff0000) >> 16);
+ rgba[i][GCOMP] = (GLubyte)((pixel & 0x0000ff00) >> 8);
+ rgba[i][BCOMP] = (GLubyte)(pixel & 0x000000ff);
+ rgba[i][ACOMP] = 255;
+ }
+}
+
+
+/* Read an array of color pixels. */
+static void read_rgba_pixels_32(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, const GLint x[], const GLint y[],
+ GLubyte rgba[][4])
+{
+ GLuint i;
+ DWORD pixel;
+ LPDWORD lpdw;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+
+ for (i=0; i<n; i++) {
+ GLint y2 = FLIP(y[i]);
+ lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y2)) + x[i];
+ pixel = *lpdw;
+ rgba[i][RCOMP] = (GLubyte)((pixel & 0x00ff0000) >> 16);
+ rgba[i][GCOMP] = (GLubyte)((pixel & 0x0000ff00) >> 8);
+ rgba[i][BCOMP] = (GLubyte)(pixel & 0x000000ff);
+ rgba[i][ACOMP] = 255;
+ }
+}
+
+
+/*********************************************************************/
+
+/* DOUBLE BUFFER 24-bit */
+
+#define WMSETPIXEL24(pwc, y, x, r, g, b) { \
+LPBYTE lpb = ((LPBYTE)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (3 * x)); \
+lpb[0] = (b); \
+lpb[1] = (g); \
+lpb[2] = (r); }
+
+/* Write a horizontal span of RGBA color pixels with a boolean mask. */
+static void write_rgba_span_24(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLubyte rgba[][4],
+ const GLubyte mask[] )
+{
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ GLuint i;
+ LPBYTE lpb;
+
+ (void) ctx;
+
+ y=FLIP(y);
+ lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x);
+ if (mask) {
+ for (i=0; i<n; i++)
+ if (mask[i]) {
+ lpb[3*i] = rgba[i][BCOMP];
+ lpb[3*i+1] = rgba[i][GCOMP];
+ lpb[3*i+2] = rgba[i][RCOMP];
+ }
+ }
+ else {
+ for (i=0; i<n; i++) {
+ *lpb++ = rgba[i][BCOMP];
+ *lpb++ = rgba[i][GCOMP];
+ *lpb++ = rgba[i][RCOMP];
+ }
+ }
+}
+
+
+/* Write a horizontal span of RGB color pixels with a boolean mask. */
+static void write_rgb_span_24(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLubyte rgb[][3],
+ const GLubyte mask[] )
+{
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ GLuint i;
+ LPBYTE lpb;
+
+ (void) ctx;
+
+ y=FLIP(y);
+ lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x);
+ if (mask) {
+ for (i=0; i<n; i++)
+ if (mask[i]) {
+ lpb[3*i] = rgb[i][BCOMP];
+ lpb[3*i+1] = rgb[i][GCOMP];
+ lpb[3*i+2] = rgb[i][RCOMP];
+ }
+ }
+ else {
+ for (i=0; i<n; i++) {
+ *lpb++ = rgb[i][BCOMP];
+ *lpb++ = rgb[i][GCOMP];
+ *lpb++ = rgb[i][RCOMP];
+ }
+ }
+}
+
+/*
+ * Write a horizontal span of pixels with a boolean mask. The current color
+ * is used for all pixels.
+ */
+static void write_mono_rgba_span_24(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLchan color[4],
+ const GLubyte mask[])
+{
+ LPBYTE lpb;
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x);
+ y=FLIP(y);
+ if (mask) {
+ for (i=0; i<n; i++)
+ if (mask[i]) {
+ lpb[3*i] = color[BCOMP];
+ lpb[3*i+1] = color[GCOMP];
+ lpb[3*i+2] = color[RCOMP];
+ }
+ }
+ else
+ for (i=0; i<n; i++) {
+ *lpb++ = color[BCOMP];
+ *lpb++ = color[GCOMP];
+ *lpb++ = color[RCOMP];
+ }
+}
+
+/* Write an array of RGBA pixels with a boolean mask. */
+static void write_rgba_pixels_24(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, const GLint x[], const GLint y[],
+ const GLubyte rgba[][4],
+ const GLubyte mask[])
+{
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ for (i=0; i<n; i++)
+ if (mask[i])
+ WMSETPIXEL24(pwfb, FLIP(y[i]), x[i],
+ rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]);
+}
+
+/*
+ * Write an array of pixels with a boolean mask. The current color
+ * is used for all pixels.
+ */
+static void write_mono_rgba_pixels_24(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n,
+ const GLint x[], const GLint y[],
+ const GLchan color[4],
+ const GLubyte mask[])
+{
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ for (i=0; i<n; i++)
+ if (mask[i])
+ WMSETPIXEL24(pwfb, FLIP(y[i]),x[i],color[RCOMP],
+ color[GCOMP], color[BCOMP]);
+}
+
+/* Read a horizontal span of color pixels. */
+static void read_rgba_span_24(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ GLubyte rgba[][4] )
+{
+ GLuint i;
+ LPBYTE lpb;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+
+ y = FLIP(y);
+ lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x);
+ for (i=0; i<n; i++) {
+ rgba[i][RCOMP] = lpb[3*i+2];
+ rgba[i][GCOMP] = lpb[3*i+1];
+ rgba[i][BCOMP] = lpb[3*i];
+ rgba[i][ACOMP] = 255;
+ }
+}
+
+
+/* Read an array of color pixels. */
+static void read_rgba_pixels_24(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, const GLint x[], const GLint y[],
+ GLubyte rgba[][4])
+{
+ GLuint i;
+ LPBYTE lpb;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+
+ for (i=0; i<n; i++) {
+ GLint y2 = FLIP(y[i]);
+ lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y2)) + (3 * x[i]);
+ rgba[i][RCOMP] = lpb[3*i+2];
+ rgba[i][GCOMP] = lpb[3*i+1];
+ rgba[i][BCOMP] = lpb[3*i];
+ rgba[i][ACOMP] = 255;
+ }
+}
+
+
+/*********************************************************************/
+
+/* DOUBLE BUFFER 16-bit */
+
+#define WMSETPIXEL16(pwc, y, x, r, g, b) { \
+LPWORD lpw = ((LPWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \
+*lpw = BGR16((r),(g),(b)); }
+
+
+
+/* Write a horizontal span of RGBA color pixels with a boolean mask. */
+static void write_rgba_span_16(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLubyte rgba[][4],
+ const GLubyte mask[] )
+{
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ GLuint i;
+ LPWORD lpw;
+
+ (void) ctx;
+
+ y=FLIP(y);
+ lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
+ if (mask) {
+ for (i=0; i<n; i++)
+ if (mask[i])
+ lpw[i] = BGR16(rgba[i][RCOMP], rgba[i][GCOMP],
+ rgba[i][BCOMP]);
+ }
+ else {
+ for (i=0; i<n; i++)
+ *lpw++ = BGR16(rgba[i][RCOMP], rgba[i][GCOMP],
+ rgba[i][BCOMP]);
+ }
+}
+
+
+/* Write a horizontal span of RGB color pixels with a boolean mask. */
+static void write_rgb_span_16(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLubyte rgb[][3],
+ const GLubyte mask[] )
+{
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ GLuint i;
+ LPWORD lpw;
+
+ (void) ctx;
+
+ y=FLIP(y);
+ lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
+ if (mask) {
+ for (i=0; i<n; i++)
+ if (mask[i])
+ lpw[i] = BGR16(rgb[i][RCOMP], rgb[i][GCOMP],
+ rgb[i][BCOMP]);
+ }
+ else {
+ for (i=0; i<n; i++)
+ *lpw++ = BGR16(rgb[i][RCOMP], rgb[i][GCOMP],
+ rgb[i][BCOMP]);
+ }
+}
+
+/*
+ * Write a horizontal span of pixels with a boolean mask. The current color
+ * is used for all pixels.
+ */
+static void write_mono_rgba_span_16(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ const GLchan color[4],
+ const GLubyte mask[])
+{
+ LPWORD lpw;
+ WORD pixel;
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ (void) ctx;
+ lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
+ y=FLIP(y);
+ pixel = BGR16(color[RCOMP], color[GCOMP], color[BCOMP]);
+ if (mask) {
+ for (i=0; i<n; i++)
+ if (mask[i])
+ lpw[i] = pixel;
+ }
+ else
+ for (i=0; i<n; i++)
+ *lpw++ = pixel;
+
+}
+
+/* Write an array of RGBA pixels with a boolean mask. */
+static void write_rgba_pixels_16(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, const GLint x[], const GLint y[],
+ const GLubyte rgba[][4],
+ const GLubyte mask[])
+{
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ (void) ctx;
+ for (i=0; i<n; i++)
+ if (mask[i])
+ WMSETPIXEL16(pwfb, FLIP(y[i]), x[i],
+ rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]);
+}
+
+/*
+ * Write an array of pixels with a boolean mask. The current color
+ * is used for all pixels.
+ */
+static void write_mono_rgba_pixels_16(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n,
+ const GLint x[], const GLint y[],
+ const GLchan color[4],
+ const GLubyte mask[])
+{
+ GLuint i;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+ (void) ctx;
+ for (i=0; i<n; i++)
+ if (mask[i])
+ WMSETPIXEL16(pwfb, FLIP(y[i]),x[i],color[RCOMP],
+ color[GCOMP], color[BCOMP]);
+}
+
+/* Read a horizontal span of color pixels. */
+static void read_rgba_span_16(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, GLint x, GLint y,
+ GLubyte rgba[][4] )
+{
+ GLuint i, pixel;
+ LPWORD lpw;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+
+ y = FLIP(y);
+ lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
+ for (i=0; i<n; i++) {
+ pixel = lpw[i];
+ /* Windows uses 5,5,5 for 16-bit */
+ rgba[i][RCOMP] = (pixel & 0x7c00) >> 7;
+ rgba[i][GCOMP] = (pixel & 0x03e0) >> 2;
+ rgba[i][BCOMP] = (pixel & 0x001f) << 3;
+ rgba[i][ACOMP] = 255;
+ }
+}
+
+
+/* Read an array of color pixels. */
+static void read_rgba_pixels_16(const struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint n, const GLint x[], const GLint y[],
+ GLubyte rgba[][4])
+{
+ GLuint i, pixel;
+ LPWORD lpw;
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
+
+ for (i=0; i<n; i++) {
+ GLint y2 = FLIP(y[i]);
+ lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y2)) + x[i];
+ pixel = *lpw;
+ /* Windows uses 5,5,5 for 16-bit */
+ rgba[i][RCOMP] = (pixel & 0x7c00) >> 7;
+ rgba[i][GCOMP] = (pixel & 0x03e0) >> 2;
+ rgba[i][BCOMP] = (pixel & 0x001f) << 3;
+ rgba[i][ACOMP] = 255;
+ }
+}
+
+
+
+
+/**********************************************************************/
+/***** BUFFER Functions *****/
+/**********************************************************************/
+
+
+
+
+static void
+wmesa_delete_renderbuffer(struct gl_renderbuffer *rb)
+{
+ free(rb);
+}
+
+
+/**
+ * This is called by Mesa whenever it determines that the window size
+ * has changed. Do whatever's needed to cope with that.
+ */
+static GLboolean
+wmesa_renderbuffer_storage(struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLenum internalFormat,
+ GLuint width,
+ GLuint height)
+{
+ rb->Width = width;
+ rb->Height = height;
+ return GL_TRUE;
+}
+
+
+/**
+ * Plug in the Get/PutRow/Values functions for a renderbuffer depending
+ * on if we're drawing to the front or back color buffer.
+ */
+void wmesa_set_renderbuffer_funcs(struct gl_renderbuffer *rb, int pixelformat,
+ int cColorBits, int double_buffer)
+{
+ if (double_buffer) {
+ /* back buffer */
+ /* Picking the correct span functions is important because
+ * the DIB was allocated with the indicated depth. */
+ switch(pixelformat) {
+ case PF_5R6G5B:
+ rb->PutRow = write_rgba_span_16;
+ rb->PutRowRGB = write_rgb_span_16;
+ rb->PutMonoRow = write_mono_rgba_span_16;
+ rb->PutValues = write_rgba_pixels_16;
+ rb->PutMonoValues = write_mono_rgba_pixels_16;
+ rb->GetRow = read_rgba_span_16;
+ rb->GetValues = read_rgba_pixels_16;
+ break;
+ case PF_8R8G8B:
+ if (cColorBits == 24)
+ {
+ rb->PutRow = write_rgba_span_24;
+ rb->PutRowRGB = write_rgb_span_24;
+ rb->PutMonoRow = write_mono_rgba_span_24;
+ rb->PutValues = write_rgba_pixels_24;
+ rb->PutMonoValues = write_mono_rgba_pixels_24;
+ rb->GetRow = read_rgba_span_24;
+ rb->GetValues = read_rgba_pixels_24;
+ }
+ else
+ {
+ rb->PutRow = write_rgba_span_32;
+ rb->PutRowRGB = write_rgb_span_32;
+ rb->PutMonoRow = write_mono_rgba_span_32;
+ rb->PutValues = write_rgba_pixels_32;
+ rb->PutMonoValues = write_mono_rgba_pixels_32;
+ rb->GetRow = read_rgba_span_32;
+ rb->GetValues = read_rgba_pixels_32;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ /* front buffer (actual Windows window) */
+ rb->PutRow = write_rgba_span_front;
+ rb->PutRowRGB = write_rgb_span_front;
+ rb->PutMonoRow = write_mono_rgba_span_front;
+ rb->PutValues = write_rgba_pixels_front;
+ rb->PutMonoValues = write_mono_rgba_pixels_front;
+ rb->GetRow = read_rgba_span_front;
+ rb->GetValues = read_rgba_pixels_front;
+ }
+}
+
+/**
+ * Called by ctx->Driver.ResizeBuffers()
+ * Resize the front/back colorbuffers to match the latest window size.
+ */
+static void
+wmesa_resize_buffers(struct gl_context *ctx, struct gl_framebuffer *buffer,
+ GLuint width, GLuint height)
+{
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_framebuffer(buffer);
+
+ if (pwfb->Base.Width != width || pwfb->Base.Height != height) {
+ /* Realloc back buffer */
+ if (ctx->Visual.doubleBufferMode == 1) {
+ wmDeleteBackingStore(pwfb);
+ wmCreateBackingStore(pwfb, width, height);
+ }
+ }
+ _mesa_resize_framebuffer(ctx, buffer, width, height);
+}
+
+
+/**
+ * Called by glViewport.
+ * This is a good time for us to poll the current window size and adjust
+ * our renderbuffers to match the current window size.
+ * Remember, we have no opportunity to respond to conventional
+ * resize events since the driver has no event loop.
+ * Thus, we poll.
+ * MakeCurrent also ends up making a call here, so that ensures
+ * we get the viewport set correctly, even if the app does not call
+ * glViewport and relies on the defaults.
+ */
+static void wmesa_viewport(struct gl_context *ctx,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height)
+{
+ WMesaContext pwc = wmesa_context(ctx);
+ GLuint new_width, new_height;
+
+ wmesa_get_buffer_size(ctx->WinSysDrawBuffer, &new_width, &new_height);
+
+ /**
+ * Resize buffers if the window size changed.
+ */
+ wmesa_resize_buffers(ctx, ctx->WinSysDrawBuffer, new_width, new_height);
+ ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */
+}
+
+
+
+
+/**
+ * Called when the driver should update it's state, based on the new_state
+ * flags.
+ */
+static void wmesa_update_state(struct gl_context *ctx, GLuint new_state)
+{
+ _swrast_InvalidateState(ctx, new_state);
+ _swsetup_InvalidateState(ctx, new_state);
+ _vbo_InvalidateState(ctx, new_state);
+ _tnl_InvalidateState(ctx, new_state);
+
+ /* TODO - This code is not complete yet because I
+ * don't know what to do for all state updates.
+ */
+
+ if (new_state & _NEW_BUFFERS) {
+ }
+}
+
+
+
+
+
+/**********************************************************************/
+/***** WMESA Functions *****/
+/**********************************************************************/
+
+WMesaContext WMesaCreateContext(HDC hDC,
+ HPALETTE* Pal,
+ GLboolean rgb_flag,
+ GLboolean db_flag,
+ GLboolean alpha_flag)
+{
+ WMesaContext c;
+ struct dd_function_table functions;
+ GLint red_bits, green_bits, blue_bits, alpha_bits;
+ struct gl_context *ctx;
+ struct gl_config *visual;
+
+ (void) Pal;
+
+ /* Indexed mode not supported */
+ if (!rgb_flag)
+ return NULL;
+
+ /* Allocate wmesa context */
+ c = CALLOC_STRUCT(wmesa_context);
+ if (!c)
+ return NULL;
+
+#if 0
+ /* I do not understand this contributed code */
+ /* Support memory and device contexts */
+ if(WindowFromDC(hDC) != NULL) {
+ c->hDC = GetDC(WindowFromDC(hDC)); /* huh ???? */
+ }
+ else {
+ c->hDC = hDC;
+ }
+#else
+ c->hDC = hDC;
+#endif
+
+ /* Get data for visual */
+ /* Dealing with this is actually a bit of overkill because Mesa will end
+ * up treating all color component size requests less than 8 by using
+ * a single byte per channel. In addition, the interface to the span
+ * routines passes colors as an entire byte per channel anyway, so there
+ * is nothing to be saved by telling the visual to be 16 bits if the device
+ * is 16 bits. That is, Mesa is going to compute colors down to 8 bits per
+ * channel anyway.
+ * But we go through the motions here anyway.
+ */
+ switch (GetDeviceCaps(c->hDC, BITSPIXEL)) {
+ case 16:
+ red_bits = green_bits = blue_bits = 5;
+ alpha_bits = 0;
+ break;
+ default:
+ red_bits = green_bits = blue_bits = 8;
+ alpha_bits = 8;
+ break;
+ }
+ /* Create visual based on flags */
+ visual = _mesa_create_visual(db_flag, /* db_flag */
+ GL_FALSE, /* stereo */
+ red_bits, green_bits, blue_bits, /* color RGB */
+ alpha_flag ? alpha_bits : 0, /* color A */
+ DEFAULT_SOFTWARE_DEPTH_BITS, /* depth_bits */
+ 8, /* stencil_bits */
+ 16,16,16, /* accum RGB */
+ alpha_flag ? 16 : 0, /* accum A */
+ 1); /* num samples */
+
+ if (!visual) {
+ free(c);
+ return NULL;
+ }
+
+ /* Set up driver functions */
+ _mesa_init_driver_functions(&functions);
+ functions.GetString = wmesa_get_string;
+ functions.UpdateState = wmesa_update_state;
+ functions.GetBufferSize = wmesa_get_buffer_size;
+ functions.Flush = wmesa_flush;
+ functions.Clear = clear;
+ functions.ClearColor = clear_color;
+ functions.ResizeBuffers = wmesa_resize_buffers;
+ functions.Viewport = wmesa_viewport;
+
+ /* initialize the Mesa context data */
+ ctx = &c->gl_ctx;
+ _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);
+
+ _mesa_enable_sw_extensions(ctx);
+ _mesa_enable_1_3_extensions(ctx);
+ _mesa_enable_1_4_extensions(ctx);
+ _mesa_enable_1_5_extensions(ctx);
+ _mesa_enable_2_0_extensions(ctx);
+ _mesa_enable_2_1_extensions(ctx);
+
+ _mesa_meta_init(ctx);
+
+ /* Initialize the software rasterizer and helper modules. */
+ if (!_swrast_CreateContext(ctx) ||
+ !_vbo_CreateContext(ctx) ||
+ !_tnl_CreateContext(ctx) ||
+ !_swsetup_CreateContext(ctx)) {
+ _mesa_free_context_data(ctx);
+ free(c);
+ return NULL;
+ }
+ _swsetup_Wakeup(ctx);
+ TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline;
+
+ return c;
+}
+
+
+void WMesaDestroyContext( WMesaContext pwc )
+{
+ struct gl_context *ctx = &pwc->gl_ctx;
+ WMesaFramebuffer pwfb;
+ GET_CURRENT_CONTEXT(cur_ctx);
+
+ if (cur_ctx == ctx) {
+ /* unbind current if deleting current context */
+ WMesaMakeCurrent(NULL, NULL);
+ }
+
+ /* clean up frame buffer resources */
+ pwfb = wmesa_lookup_framebuffer(pwc->hDC);
+ if (pwfb) {
+ if (ctx->Visual.doubleBufferMode == 1)
+ wmDeleteBackingStore(pwfb);
+ wmesa_free_framebuffer(pwc->hDC);
+ }
+
+ /* Release for device, not memory contexts */
+ if (WindowFromDC(pwc->hDC) != NULL)
+ {
+ ReleaseDC(WindowFromDC(pwc->hDC), pwc->hDC);
+ }
+ DeleteObject(pwc->clearPen);
+ DeleteObject(pwc->clearBrush);
+
+ _mesa_meta_free(ctx);
+
+ _swsetup_DestroyContext(ctx);
+ _tnl_DestroyContext(ctx);
+ _vbo_DestroyContext(ctx);
+ _swrast_DestroyContext(ctx);
+
+ _mesa_free_context_data(ctx);
+ free(pwc);
+}
+
+
+/**
+ * Create a new color renderbuffer.
+ */
+struct gl_renderbuffer *
+wmesa_new_renderbuffer(void)
+{
+ struct gl_renderbuffer *rb = CALLOC_STRUCT(gl_renderbuffer);
+ if (!rb)
+ return NULL;
+
+ _mesa_init_renderbuffer(rb, (GLuint)0);
+
+ rb->_BaseFormat = GL_RGBA;
+ rb->InternalFormat = GL_RGBA;
+ rb->DataType = CHAN_TYPE;
+ rb->Delete = wmesa_delete_renderbuffer;
+ rb->AllocStorage = wmesa_renderbuffer_storage;
+ return rb;
+}
+
+
+void WMesaMakeCurrent(WMesaContext c, HDC hdc)
+{
+ WMesaFramebuffer pwfb;
+
+ {
+ /* return if already current */
+ GET_CURRENT_CONTEXT(ctx);
+ WMesaContext pwc = wmesa_context(ctx);
+ if (pwc && c == pwc && pwc->hDC == hdc)
+ return;
+ }
+
+ pwfb = wmesa_lookup_framebuffer(hdc);
+
+ /* Lazy creation of framebuffers */
+ if (c && !pwfb && hdc) {
+ struct gl_renderbuffer *rb;
+ struct gl_config *visual = &c->gl_ctx.Visual;
+ GLuint width, height;
+
+ get_window_size(hdc, &width, &height);
+
+ c->clearPen = CreatePen(PS_SOLID, 1, 0);
+ c->clearBrush = CreateSolidBrush(0);
+
+ pwfb = wmesa_new_framebuffer(hdc, visual);
+
+ /* Create back buffer if double buffered */
+ if (visual->doubleBufferMode == 1) {
+ wmCreateBackingStore(pwfb, width, height);
+ }
+
+ /* make render buffers */
+ if (visual->doubleBufferMode == 1) {
+ rb = wmesa_new_renderbuffer();
+ _mesa_add_renderbuffer(&pwfb->Base, BUFFER_BACK_LEFT, rb);
+ wmesa_set_renderbuffer_funcs(rb, pwfb->pixelformat, pwfb->cColorBits, 1);
+ }
+ rb = wmesa_new_renderbuffer();
+ _mesa_add_renderbuffer(&pwfb->Base, BUFFER_FRONT_LEFT, rb);
+ wmesa_set_renderbuffer_funcs(rb, pwfb->pixelformat, pwfb->cColorBits, 0);
+
+ /* Let Mesa own the Depth, Stencil, and Accum buffers */
+ _mesa_add_soft_renderbuffers(&pwfb->Base,
+ GL_FALSE, /* color */
+ visual->depthBits > 0,
+ visual->stencilBits > 0,
+ visual->accumRedBits > 0,
+ visual->alphaBits >0,
+ GL_FALSE);
+ }
+
+ if (c && pwfb)
+ _mesa_make_current(&c->gl_ctx, &pwfb->Base, &pwfb->Base);
+ else
+ _mesa_make_current(NULL, NULL, NULL);
+}
+
+
+void WMesaSwapBuffers( HDC hdc )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ WMesaContext pwc = wmesa_context(ctx);
+ WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(hdc);
+
+ if (!pwfb) {
+ _mesa_problem(NULL, "wmesa: swapbuffers on unknown hdc");
+ return;
+ }
+
+ /* If we're swapping the buffer associated with the current context
+ * we have to flush any pending rendering commands first.
+ */
+ if (pwc->hDC == hdc) {
+ _mesa_notifySwapBuffers(ctx);
+
+ BitBlt(pwfb->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height,
+ pwfb->dib_hDC, 0, 0, SRCCOPY);
+ }
+ else {
+ /* XXX for now only allow swapping current window */
+ _mesa_problem(NULL, "wmesa: can't swap non-current window");
+ }
+}
+
+void WMesaShareLists(WMesaContext ctx_to_share, WMesaContext ctx)
+{
+ _mesa_share_state(&ctx->gl_ctx, &ctx_to_share->gl_ctx);
+}
+
diff --git a/mesalib/src/mesa/drivers/windows/gldirect/dglcontext.c b/mesalib/src/mesa/drivers/windows/gldirect/dglcontext.c index 9aedd2e3c..bc4839cfe 100644 --- a/mesalib/src/mesa/drivers/windows/gldirect/dglcontext.c +++ b/mesalib/src/mesa/drivers/windows/gldirect/dglcontext.c @@ -1,2212 +1,2212 @@ -/**************************************************************************** -* -* Mesa 3-D graphics library -* Direct3D Driver Interface -* -* ======================================================================== -* -* Copyright (C) 1991-2004 SciTech Software, 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 -* SCITECH SOFTWARE INC 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. -* -* ====================================================================== -* -* Language: ANSI C -* Environment: Windows 9x (Win32) -* -* Description: Context handling. -* -****************************************************************************/ - -#include "dglcontext.h" - -// Get compile errors without this. KeithH -//#include "scitech.h" // ibool, etc. - -#ifdef _USE_GLD3_WGL -#include "gld_driver.h" - -extern void _gld_mesa_warning(struct gl_context *, char *); -extern void _gld_mesa_fatal(struct gl_context *, char *); -#endif // _USE_GLD3_WGL - -// TODO: Clean out old DX6-specific code from GLD 2.x CAD driver -// if it is no longer being built as part of GLDirect. (DaveM) - -// *********************************************************************** - -#define GLDERR_NONE 0 -#define GLDERR_MEM 1 -#define GLDERR_DDRAW 2 -#define GLDERR_D3D 3 -#define GLDERR_BPP 4 - -char szResourceWarning[] = -"GLDirect does not have enough video memory resources\n" -"to support the requested OpenGL rendering context.\n\n" -"You may have to reduce the current display resolution\n" -"to obtain satisfactory OpenGL performance.\n"; - -char szDDrawWarning[] = -"GLDirect is unable to initialize DirectDraw for the\n" -"requested OpenGL rendering context.\n\n" -"You will have to check the DirectX control panel\n" -"for further information.\n"; - -char szD3DWarning[] = -"GLDirect is unable to initialize Direct3D for the\n" -"requested OpenGL rendering context.\n\n" -"You may have to change the display mode resolution\n" -"color depth or check the DirectX control panel for\n" -"further information.\n"; - -char szBPPWarning[] = -"GLDirect is unable to use the selected color depth for\n" -"the requested OpenGL rendering context.\n\n" -"You will have to change the display mode resolution\n" -"color depth with the Display Settings control panel.\n"; - -int nContextError = GLDERR_NONE; - -// *********************************************************************** - -#define VENDORID_ATI 0x1002 - -static DWORD devATIRagePro[] = { - 0x4742, // 3D RAGE PRO BGA AGP 1X/2X - 0x4744, // 3D RAGE PRO BGA AGP 1X only - 0x4749, // 3D RAGE PRO BGA PCI 33 MHz - 0x4750, // 3D RAGE PRO PQFP PCI 33 MHz - 0x4751, // 3D RAGE PRO PQFP PCI 33 MHz limited 3D - 0x4C42, // 3D RAGE LT PRO BGA-312 AGP 133 MHz - 0x4C44, // 3D RAGE LT PRO BGA-312 AGP 66 MHz - 0x4C49, // 3D RAGE LT PRO BGA-312 PCI 33 MHz - 0x4C50, // 3D RAGE LT PRO BGA-256 PCI 33 MHz - 0x4C51, // 3D RAGE LT PRO BGA-256 PCI 33 MHz limited 3D -}; - -static DWORD devATIRageIIplus[] = { - 0x4755, // 3D RAGE II+ - 0x4756, // 3D RAGE IIC PQFP PCI - 0x4757, // 3D RAGE IIC BGA AGP - 0x475A, // 3D RAGE IIC PQFP AGP - 0x4C47, // 3D RAGE LT-G -}; - -// *********************************************************************** - -#ifndef _USE_GLD3_WGL -extern DGL_mesaFuncs mesaFuncs; -#endif - -extern DWORD dwLogging; - -#ifdef GLD_THREADS -#pragma message("compiling DGLCONTEXT.C vars for multi-threaded support") -CRITICAL_SECTION CriticalSection; // for serialized access -DWORD dwTLSCurrentContext = 0xFFFFFFFF; // TLS index for current context -DWORD dwTLSPixelFormat = 0xFFFFFFFF; // TLS index for current pixel format -#endif -HGLRC iCurrentContext = 0; // Index of current context (static) -BOOL bContextReady = FALSE; // Context state ready ? - -DGL_ctx ctxlist[DGL_MAX_CONTEXTS]; // Context list - -// *********************************************************************** - -static BOOL bHaveWin95 = FALSE; -static BOOL bHaveWinNT = FALSE; -static BOOL bHaveWin2K = FALSE; - -/**************************************************************************** -REMARKS: -Detect the installed OS type. -****************************************************************************/ -static void DetectOS(void) -{ - OSVERSIONINFO VersionInformation; - LPOSVERSIONINFO lpVersionInformation = &VersionInformation; - - VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation); - - GetVersionEx(lpVersionInformation); - - switch (VersionInformation.dwPlatformId) { - case VER_PLATFORM_WIN32_WINDOWS: - bHaveWin95 = TRUE; - bHaveWinNT = FALSE; - bHaveWin2K = FALSE; - break; - case VER_PLATFORM_WIN32_NT: - bHaveWin95 = FALSE; - if (VersionInformation.dwMajorVersion <= 4) { - bHaveWinNT = TRUE; - bHaveWin2K = FALSE; - } - else { - bHaveWinNT = FALSE; - bHaveWin2K = TRUE; - } - break; - case VER_PLATFORM_WIN32s: - bHaveWin95 = FALSE; - bHaveWinNT = FALSE; - bHaveWin2K = FALSE; - break; - } -} - -// *********************************************************************** - -HWND hWndEvent = NULL; // event monitor window -HWND hWndLastActive = NULL; // last active client window -LONG __stdcall GLD_EventWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); - -// *********************************************************************** - -// Checks if the HGLRC is valid in range of context list. -BOOL dglIsValidContext( - HGLRC a) -{ - return ((int)a > 0 && (int)a <= DGL_MAX_CONTEXTS); -} - -// *********************************************************************** - -// Convert a HGLRC to a pointer into the context list. -DGL_ctx* dglGetContextAddress( - const HGLRC a) -{ - if (dglIsValidContext(a)) - return &ctxlist[(int)a-1]; - return NULL; -} - -// *********************************************************************** - -// Return the current HGLRC (however it may be stored for multi-threading). -HGLRC dglGetCurrentContext(void) -{ -#ifdef GLD_THREADS - HGLRC hGLRC; - // load from thread-specific instance - if (glb.bMultiThreaded) { - // protect against calls from arbitrary threads - __try { - hGLRC = (HGLRC)TlsGetValue(dwTLSCurrentContext); - } - __except(EXCEPTION_EXECUTE_HANDLER) { - hGLRC = iCurrentContext; - } - } - // load from global static var - else { - hGLRC = iCurrentContext; - } - return hGLRC; -#else - return iCurrentContext; -#endif -} - -// *********************************************************************** - -// Set the current HGLRC (however it may be stored for multi-threading). -void dglSetCurrentContext(HGLRC hGLRC) -{ -#ifdef GLD_THREADS - // store in thread-specific instance - if (glb.bMultiThreaded) { - // protect against calls from arbitrary threads - __try { - TlsSetValue(dwTLSCurrentContext, (LPVOID)hGLRC); - } - __except(EXCEPTION_EXECUTE_HANDLER) { - iCurrentContext = hGLRC; - } - } - // store in global static var - else { - iCurrentContext = hGLRC; - } -#else - iCurrentContext = hGLRC; -#endif -} - -// *********************************************************************** - -// Return the current HDC only for a currently active HGLRC. -HDC dglGetCurrentDC(void) -{ - HGLRC hGLRC; - DGL_ctx* lpCtx; - - hGLRC = dglGetCurrentContext(); - if (hGLRC) { - lpCtx = dglGetContextAddress(hGLRC); - return lpCtx->hDC; - } - return 0; -} - -// *********************************************************************** - -void dglInitContextState() -{ - int i; - WNDCLASS wc; - -#ifdef GLD_THREADS - // Allocate thread local storage indexes for current context and pixel format - dwTLSCurrentContext = TlsAlloc(); - dwTLSPixelFormat = TlsAlloc(); -#endif - - dglSetCurrentContext(NULL); // No current rendering context - - // Clear all context data - ZeroMemory(ctxlist, sizeof(ctxlist[0]) * DGL_MAX_CONTEXTS); - - for (i=0; i<DGL_MAX_CONTEXTS; i++) - ctxlist[i].bAllocated = FALSE; // Flag context as unused - - // This section of code crashes the dll in circumstances where the app - // creates and destroys contexts. -/* - // Register the class for our event monitor window - wc.style = 0; - wc.lpfnWndProc = GLD_EventWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = GetModuleHandle(NULL); - wc.hIcon = LoadIcon(GetModuleHandle(NULL), IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - wc.lpszMenuName = NULL; - wc.lpszClassName = "GLDIRECT"; - RegisterClass(&wc); - - // Create the non-visible window to monitor all broadcast messages - hWndEvent = CreateWindowEx( - WS_EX_TOOLWINDOW,"GLDIRECT","GLDIRECT",WS_POPUP, - 0,0,0,0, - NULL,NULL,GetModuleHandle(NULL),NULL); -*/ - -#ifdef GLD_THREADS - // Create a critical section object for serializing access to - // DirectDraw and DDStereo create/destroy functions in multiple threads - if (glb.bMultiThreaded) - InitializeCriticalSection(&CriticalSection); -#endif - - // Context state is now initialized and ready - bContextReady = TRUE; -} - -// *********************************************************************** - -void dglDeleteContextState() -{ - int i; - static BOOL bOnceIsEnough = FALSE; - - // Only call once, from either DGL_exitDriver(), or DLL_PROCESS_DETACH - if (bOnceIsEnough) - return; - bOnceIsEnough = TRUE; - - for (i=0; i<DGL_MAX_CONTEXTS; i++) { - if (ctxlist[i].bAllocated == TRUE) { - ddlogPrintf(DDLOG_WARN, "** Context %i not deleted - cleaning up.", (i+1)); - dglDeleteContext((HGLRC)(i+1)); - } - } - - // Context state is no longer ready - bContextReady = FALSE; - - // If executed when DLL unloads, DDraw objects may be invalid. - // So catch any page faults with this exception handler. -__try { - - // Release final DirectDraw interfaces - if (glb.bDirectDrawPersistant) { -// RELEASE(glb.lpGlobalPalette); -// RELEASE(glb.lpDepth4); -// RELEASE(glb.lpBack4); -// RELEASE(glb.lpPrimary4); -// RELEASE(glb.lpDD4); - } -} -__except(EXCEPTION_EXECUTE_HANDLER) { - ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContextState."); -} - - // Destroy our event monitor window - if (hWndEvent) { - DestroyWindow(hWndEvent); - hWndEvent = hWndLastActive = NULL; - } - -#ifdef GLD_THREADS - // Destroy the critical section object - if (glb.bMultiThreaded) - DeleteCriticalSection(&CriticalSection); - - // Release thread local storage indexes for current HGLRC and pixel format - TlsFree(dwTLSPixelFormat); - TlsFree(dwTLSCurrentContext); -#endif -} - -// *********************************************************************** - -// Application Window message handler interception -static LONG __stdcall dglWndProc( - HWND hwnd, - UINT msg, - WPARAM wParam, - LPARAM lParam) -{ - DGL_ctx* lpCtx = NULL; - LONG lpfnWndProc = 0L; - int i; - HGLRC hGLRC; - RECT rect; - PAINTSTRUCT ps; - BOOL bQuit = FALSE; - BOOL bMain = FALSE; - LONG rc; - - // Get the window's message handler *before* it is unhooked in WM_DESTROY - - // Is this the main window? - if (hwnd == glb.hWndActive) { - bMain = TRUE; - lpfnWndProc = glb.lpfnWndProc; - } - // Search for DGL context matching window handle - for (i=0; i<DGL_MAX_CONTEXTS; i++) { - if (ctxlist[i].hWnd == hwnd) { - lpCtx = &ctxlist[i]; - lpfnWndProc = lpCtx->lpfnWndProc; - break; - } - } - // Not one of ours... - if (!lpfnWndProc) - return DefWindowProc(hwnd, msg, wParam, lParam); - - // Intercept messages amd process *before* passing on to window - switch (msg) { -#ifdef _USE_GLD3_WGL - case WM_DISPLAYCHANGE: - glb.bPixelformatsDirty = TRUE; - break; -#endif - case WM_ACTIVATEAPP: - glb.bAppActive = (BOOL)wParam; - ddlogPrintf(DDLOG_INFO, "Calling app has been %s", glb.bAppActive ? "activated" : "de-activated"); - break; - case WM_ERASEBKGND: - // Eat the GDI erase event for the GL window - if (!lpCtx || !lpCtx->bHasBeenCurrent) - break; - lpCtx->bGDIEraseBkgnd = TRUE; - return TRUE; - case WM_PAINT: - // Eat the invalidated update region if render scene is in progress - if (!lpCtx || !lpCtx->bHasBeenCurrent) - break; - if (lpCtx->bFrameStarted) { - if (GetUpdateRect(hwnd, &rect, FALSE)) { - BeginPaint(hwnd, &ps); - EndPaint(hwnd, &ps); - ValidateRect(hwnd, &rect); - return TRUE; - } - } - break; - } - // Call the appropriate window message handler - rc = CallWindowProc((WNDPROC)lpfnWndProc, hwnd, msg, wParam, lParam); - - // Intercept messages and process *after* passing on to window - switch (msg) { - case WM_QUIT: - case WM_DESTROY: - bQuit = TRUE; - if (lpCtx && lpCtx->bAllocated) { - ddlogPrintf(DDLOG_WARN, "WM_DESTROY detected for HWND=%X, HDC=%X, HGLRC=%d", hwnd, lpCtx->hDC, i+1); - dglDeleteContext((HGLRC)(i+1)); - } - break; -#if 0 - case WM_SIZE: - // Resize surfaces to fit window but not viewport (in case app did not bother) - if (!lpCtx || !lpCtx->bHasBeenCurrent) - break; - w = LOWORD(lParam); - h = HIWORD(lParam); - if (lpCtx->dwWidth < w || lpCtx->dwHeight < h) { - if (!dglWglResizeBuffers(lpCtx->glCtx, TRUE)) - dglWglResizeBuffers(lpCtx->glCtx, FALSE); - } - break; -#endif - } - - // If the main window is quitting, then so should we... - if (bMain && bQuit) { - ddlogPrintf(DDLOG_SYSTEM, "shutting down after WM_DESTROY detected for main HWND=%X", hwnd); - dglDeleteContextState(); - dglExitDriver(); - } - - return rc; -} - -// *********************************************************************** - -// Driver Window message handler -static LONG __stdcall GLD_EventWndProc( - HWND hwnd, - UINT msg, - WPARAM wParam, - LPARAM lParam) -{ - switch (msg) { - // May be sent by splash screen dialog on exit - case WM_ACTIVATE: - if (LOWORD(wParam) == WA_ACTIVE && glb.hWndActive) { - SetForegroundWindow(glb.hWndActive); - return 0; - } - break; - } - return DefWindowProc(hwnd, msg, wParam, lParam); -} - -// *********************************************************************** - -// Intercepted Keyboard handler for detecting hot keys. -LRESULT CALLBACK dglKeyProc( - int code, - WPARAM wParam, - LPARAM lParam) -{ - HWND hWnd, hWndFrame; - HGLRC hGLRC = NULL; - DGL_ctx* lpCtx = NULL; - int cmd = 0, dx1 = 0, dx2 = 0, i; - static BOOL bAltPressed = FALSE; - static BOOL bCtrlPressed = FALSE; - static BOOL bShiftPressed = FALSE; - RECT r, rf, rc; - POINT pt; - BOOL bForceReshape = FALSE; - - return CallNextHookEx(hKeyHook, code, wParam, lParam); -} - -// *********************************************************************** - -HWND hWndMatch; - -// Window handle enumeration procedure. -BOOL CALLBACK dglEnumChildProc( - HWND hWnd, - LPARAM lParam) -{ - RECT rect; - - // Find window handle with matching client rect. - GetClientRect(hWnd, &rect); - if (EqualRect(&rect, (RECT*)lParam)) { - hWndMatch = hWnd; - return FALSE; - } - // Continue with next child window. - return TRUE; -} - -// *********************************************************************** - -// Find window handle with matching client rect. -HWND dglFindWindowRect( - RECT* pRect) -{ - hWndMatch = NULL; - EnumChildWindows(GetForegroundWindow(), dglEnumChildProc, (LPARAM)pRect); - return hWndMatch; -} - -// *********************************************************************** -#ifndef _USE_GLD3_WGL -void dglChooseDisplayMode( - DGL_ctx *lpCtx) -{ - // Note: Choose an exact match if possible. - - int i; - DWORD area; - DWORD bestarea; - DDSURFACEDESC2 *lpDDSD = NULL; // Mode list pointer - DDSURFACEDESC2 *lpBestDDSD = NULL; // Pointer to best - - lpDDSD = glb.lpDisplayModes; - for (i=0; i<glb.nDisplayModeCount; i++, lpDDSD++) { - if ((lpDDSD->dwWidth == lpCtx->dwWidth) && - (lpDDSD->dwHeight == lpCtx->dwHeight)) - goto matched; // Mode has been exactly matched - // Choose modes that are larger in both dimensions than - // the window, but smaller in area than the current best. - if ( (lpDDSD->dwWidth >= lpCtx->dwWidth) && - (lpDDSD->dwHeight >= lpCtx->dwHeight)) - { - if (lpBestDDSD == NULL) { - lpBestDDSD = lpDDSD; - bestarea = lpDDSD->dwWidth * lpDDSD->dwHeight; - continue; - } - area = lpDDSD->dwWidth * lpDDSD->dwHeight; - if (area < bestarea) { - lpBestDDSD = lpDDSD; - bestarea = area; - } - } - } - - // Safety check - if (lpBestDDSD == NULL) { - ddlogMessage(DDLOG_CRITICAL, "dglChooseDisplayMode"); - return; - } - - lpCtx->dwModeWidth = lpBestDDSD->dwWidth; - lpCtx->dwModeHeight = lpBestDDSD->dwHeight; -matched: - ddlogPrintf(DDLOG_INFO, "Matched (%ldx%ld) to (%ldx%ld)", - lpCtx->dwWidth, lpCtx->dwHeight, lpCtx->dwModeWidth, lpCtx->dwModeHeight); -} -#endif // _USE_GLD3_WGL -// *********************************************************************** - -static BOOL IsDevice( - DWORD *lpDeviceIdList, - DWORD dwDeviceId, - int count) -{ - int i; - - for (i=0; i<count; i++) - if (dwDeviceId == lpDeviceIdList[i]) - return TRUE; - - return FALSE; -} - -// *********************************************************************** - -void dglTestForBrokenCards( - DGL_ctx *lpCtx) -{ -#ifndef _GLD3 - DDDEVICEIDENTIFIER dddi; // DX6 device identifier - - // Sanity check. - if (lpCtx == NULL) { - // Testing for broken cards is sensitive area, so we don't want - // anything saying "broken cards" in the error message. ;) - ddlogMessage(DDLOG_ERROR, "Null context passed to TFBC\n"); - return; - } - - if (lpCtx->lpDD4 == NULL) { - // Testing for broken cards is sensitive area, so we don't want - // anything saying "broken cards" in the error message. ;) - ddlogMessage(DDLOG_ERROR, "Null DD4 passed to TFBC\n"); - return; - } - - // Microsoft really fucked up with the GetDeviceIdentifier function - // on Windows 2000, since it locks up on stock driers on the CD. Updated - // drivers from vendors appear to work, but we can't identify the drivers - // without this function!!! For now we skip these tests on Windows 2000. - if ((GetVersion() & 0x80000000UL) == 0) - return; - - // Obtain device info - if (FAILED(IDirectDraw4_GetDeviceIdentifier(lpCtx->lpDD4, &dddi, 0))) - return; - - // Useful info. Log it. - ddlogPrintf(DDLOG_INFO, "DirectDraw: VendorId=0x%x, DeviceId=0x%x", dddi.dwVendorId, dddi.dwDeviceId); - - // Vendor 1: ATI - if (dddi.dwVendorId == VENDORID_ATI) { - // Test A: ATI Rage PRO - if (IsDevice(devATIRagePro, dddi.dwDeviceId, sizeof(devATIRagePro))) - glb.bUseMipmaps = FALSE; - // Test B: ATI Rage II+ - if (IsDevice(devATIRageIIplus, dddi.dwDeviceId, sizeof(devATIRageIIplus))) - glb.bEmulateAlphaTest = TRUE; - } - - // Vendor 2: Matrox - if (dddi.dwVendorId == 0x102B) { - // Test: Matrox G400 stencil buffer support does not work for AutoCAD - if (dddi.dwDeviceId == 0x0525) { - lpCtx->lpPF->pfd.cStencilBits = 0; - if (lpCtx->lpPF->iZBufferPF != -1) { - glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwStencilBitDepth = 0; - glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwStencilBitMask = 0; - glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwFlags &= ~DDPF_STENCILBUFFER; - } - } - } -#endif // _GLD3 -} - -// *********************************************************************** - -BOOL dglCreateContextBuffers( - HDC a, - DGL_ctx *lpCtx, - BOOL bFallback) -{ - HRESULT hResult; - - int i; -// HGLRC hGLRC; -// DGL_ctx* lpCtx; - -#ifndef _USE_GLD3_WGL - DWORD dwFlags; - DDSURFACEDESC2 ddsd2; - DDSCAPS2 ddscaps2; - LPDIRECTDRAWCLIPPER lpddClipper; - D3DDEVICEDESC D3DHWDevDesc; // Direct3D Hardware description - D3DDEVICEDESC D3DHELDevDesc; // Direct3D Hardware Emulation Layer -#endif // _USE_GLD3_WGL - - float inv_aspect; - - GLenum bDoubleBuffer; // TRUE if double buffer required - GLenum bDepthBuffer; // TRUE if depth buffer required - - const PIXELFORMATDESCRIPTOR *lpPFD = &lpCtx->lpPF->pfd; - - // Vars for Mesa visual - DWORD dwDepthBits = 0; - DWORD dwStencilBits = 0; - DWORD dwAlphaBits = 0; - DWORD bAlphaSW = GL_FALSE; - DWORD bDouble = GL_FALSE; - - DDSURFACEDESC2 ddsd2DisplayMode; - BOOL bFullScrnWin = FALSE; // fullscreen-size window ? - DDBLTFX ddbltfx; - DWORD dwMemoryType = (bFallback) ? DDSCAPS_SYSTEMMEMORY : glb.dwMemoryType; - BOOL bBogusWindow = FALSE; // non-drawable window ? - DWORD dwColorRef = 0; // GDI background color - RECT rcDst; // GDI window rect - POINT pt; // GDI window point - - // Palette used for creating default global palette - PALETTEENTRY ppe[256]; - -#ifndef _USE_GLD3_WGL - // Vertex buffer description. Used for creation of vertex buffers - D3DVERTEXBUFFERDESC vbufdesc; -#endif // _USE_GLD3_WGL - -#define DDLOG_CRITICAL_OR_WARN (bFallback ? DDLOG_CRITICAL : DDLOG_WARN) - - ddlogPrintf(DDLOG_SYSTEM, "dglCreateContextBuffers for HDC=%X", a); - nContextError = GLDERR_NONE; - -#ifdef GLD_THREADS - // Serialize access to DirectDraw object creation or DDS start - if (glb.bMultiThreaded) - EnterCriticalSection(&CriticalSection); -#endif - - // Check for back buffer - bDoubleBuffer = GL_TRUE; //(lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? GL_TRUE : GL_FALSE; - // Since we always do back buffering, check if we emulate front buffering - lpCtx->EmulateSingle = - (lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? FALSE : TRUE; -#if 0 // Don't have to mimic MS OpenGL behavior for front-buffering (DaveM) - lpCtx->EmulateSingle |= - (lpPFD->dwFlags & PFD_SUPPORT_GDI) ? TRUE : FALSE; -#endif - - // Check for depth buffer - bDepthBuffer = (lpPFD->cDepthBits) ? GL_TRUE : GL_FALSE; - - lpCtx->bDoubleBuffer = bDoubleBuffer; - lpCtx->bDepthBuffer = bDepthBuffer; - - // Set the Fullscreen flag for the context. -// lpCtx->bFullscreen = glb.bFullscreen; - - // Obtain the dimensions of the rendering window - lpCtx->hDC = a; // Cache DC - lpCtx->hWnd = WindowFromDC(lpCtx->hDC); - // Check for non-window DC = memory DC ? - if (lpCtx->hWnd == NULL) { - // bitmap memory contexts are always single-buffered - lpCtx->EmulateSingle = TRUE; - bBogusWindow = TRUE; - ddlogPrintf(DDLOG_INFO, "Non-Window Memory Device Context"); - if (GetClipBox(lpCtx->hDC, &lpCtx->rcScreenRect) == ERROR) { - ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglCreateContext\n"); - SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0); - } - } - else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) { - bBogusWindow = TRUE; - ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglCreateContext\n"); - SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0); - } - lpCtx->dwWidth = lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left; - lpCtx->dwHeight = lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top; - - ddlogPrintf(DDLOG_INFO, "Input window %X: w=%i, h=%i", - lpCtx->hWnd, lpCtx->dwWidth, lpCtx->dwHeight); - - // What if app only zeroes one dimension instead of both? (DaveM) - if ( (lpCtx->dwWidth == 0) || (lpCtx->dwHeight == 0) ) { - // Make the buffer size something sensible - lpCtx->dwWidth = 8; - lpCtx->dwHeight = 8; - } - - // Set defaults - lpCtx->dwModeWidth = lpCtx->dwWidth; - lpCtx->dwModeHeight = lpCtx->dwHeight; -/* - // Find best display mode for fullscreen - if (glb.bFullscreen || !glb.bPrimary) { - dglChooseDisplayMode(lpCtx); - } -*/ - // Misc initialisation - lpCtx->bCanRender = FALSE; // No rendering allowed yet - lpCtx->bSceneStarted = FALSE; - lpCtx->bFrameStarted = FALSE; - - // Detect OS (specifically 'Windows 2000' or 'Windows XP') - DetectOS(); - - // NOTE: WinNT not supported - ddlogPrintf(DDLOG_INFO, "OS: %s", bHaveWin95 ? "Win9x" : (bHaveWin2K ? "Win2000/XP" : "Unsupported") ); - - // Test for Fullscreen - if (bHaveWin95) { // Problems with fullscreen on Win2K/XP - if ((GetSystemMetrics(SM_CXSCREEN) == lpCtx->dwWidth) && - (GetSystemMetrics(SM_CYSCREEN) == lpCtx->dwHeight)) - { - // Workaround for some apps that crash when going fullscreen. - //lpCtx->bFullscreen = TRUE; - } - - } - -#ifdef _USE_GLD3_WGL - _gldDriver.CreateDrawable(lpCtx, glb.bDirectDrawPersistant, glb.bPersistantBuffers); -#else - // Check if DirectDraw has already been created by original GLRC (DaveM) - if (glb.bDirectDrawPersistant && glb.bDirectDraw) { - lpCtx->lpDD4 = glb.lpDD4; - IDirectDraw4_AddRef(lpCtx->lpDD4); - goto SkipDirectDrawCreate; - } - - // Create DirectDraw object - if (glb.bPrimary) - hResult = DirectDrawCreate(NULL, &lpCtx->lpDD1, NULL); - else { - // A non-primary device is to be used. - // Force context to be Fullscreen, secondary adaptors can not - // be used in a window. - hResult = DirectDrawCreate(&glb.ddGuid, &lpCtx->lpDD1, NULL); - lpCtx->bFullscreen = TRUE; - } - if (FAILED(hResult)) { - MessageBox(NULL, "Unable to initialize DirectDraw", "GLDirect", MB_OK); - ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create DirectDraw interface", hResult); - nContextError = GLDERR_DDRAW; - goto return_with_error; - } - - // Query for DX6 IDirectDraw4. - hResult = IDirectDraw_QueryInterface(lpCtx->lpDD1, - &IID_IDirectDraw4, - (void**)&lpCtx->lpDD4); - if (FAILED(hResult)) { - MessageBox(NULL, "GLDirect requires DirectX 6.0 or above", "GLDirect", MB_OK); - ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create DirectDraw4 interface", hResult); - nContextError = GLDERR_DDRAW; - goto return_with_error; - } - - // Cache DirectDraw interface for subsequent GLRCs - if (glb.bDirectDrawPersistant && !glb.bDirectDraw) { - glb.lpDD4 = lpCtx->lpDD4; - IDirectDraw4_AddRef(glb.lpDD4); - glb.bDirectDraw = TRUE; - } -SkipDirectDrawCreate: - - // Now we have a DD4 interface we can check for broken cards - dglTestForBrokenCards(lpCtx); - - // Test if primary device can use flipping instead of blitting - ZeroMemory(&ddsd2DisplayMode, sizeof(ddsd2DisplayMode)); - ddsd2DisplayMode.dwSize = sizeof(ddsd2DisplayMode); - hResult = IDirectDraw4_GetDisplayMode( - lpCtx->lpDD4, - &ddsd2DisplayMode); - if (SUCCEEDED(hResult)) { - if ( (lpCtx->dwWidth == ddsd2DisplayMode.dwWidth) && - (lpCtx->dwHeight == ddsd2DisplayMode.dwHeight) ) { - // We have a fullscreen-size window - bFullScrnWin = TRUE; - // OK to use DirectDraw fullscreen mode ? - if (glb.bPrimary && !glb.bFullscreenBlit && !lpCtx->EmulateSingle && !glb.bDirectDrawPersistant) { - lpCtx->bFullscreen = TRUE; - ddlogMessage(DDLOG_INFO, "Primary upgraded to page flipping.\n"); - } - } - // Cache the display mode dimensions - lpCtx->dwModeWidth = ddsd2DisplayMode.dwWidth; - lpCtx->dwModeHeight = ddsd2DisplayMode.dwHeight; - } - - // Clamp the effective window dimensions to primary surface. - // We need to do this for D3D viewport dimensions even if wide - // surfaces are supported. This also is a good idea for handling - // whacked-out window dimensions passed for non-drawable windows - // like Solid Edge. (DaveM) - if (lpCtx->dwWidth > ddsd2DisplayMode.dwWidth) - lpCtx->dwWidth = ddsd2DisplayMode.dwWidth; - if (lpCtx->dwHeight > ddsd2DisplayMode.dwHeight) - lpCtx->dwHeight = ddsd2DisplayMode.dwHeight; - - // Check for non-RGB desktop resolution - if (!lpCtx->bFullscreen && ddsd2DisplayMode.ddpfPixelFormat.dwRGBBitCount <= 8) { - ddlogPrintf(DDLOG_CRITICAL_OR_WARN, "Desktop color depth %d bpp not supported", - ddsd2DisplayMode.ddpfPixelFormat.dwRGBBitCount); - nContextError = GLDERR_BPP; - goto return_with_error; - } -#endif // _USE_GLD3_WGL - - ddlogPrintf(DDLOG_INFO, "Window: w=%i, h=%i (%s)", - lpCtx->dwWidth, - lpCtx->dwHeight, - lpCtx->bFullscreen ? "fullscreen" : "windowed"); - -#ifndef _USE_GLD3_WGL - // Obtain ddraw caps - ZeroMemory(&lpCtx->ddCaps, sizeof(DDCAPS)); - lpCtx->ddCaps.dwSize = sizeof(DDCAPS); - if (glb.bHardware) { - // Get HAL caps - IDirectDraw4_GetCaps(lpCtx->lpDD4, &lpCtx->ddCaps, NULL); - } else { - // Get HEL caps - IDirectDraw4_GetCaps(lpCtx->lpDD4, NULL, &lpCtx->ddCaps); - } - - // If this flag is present then we can't default to Mesa - // SW rendering between BeginScene() and EndScene(). - if (lpCtx->ddCaps.dwCaps2 & DDCAPS2_NO2DDURING3DSCENE) { - ddlogMessage(DDLOG_INFO, - "Warning : No 2D allowed during 3D scene.\n"); - } - - // Query for DX6 Direct3D3 interface - hResult = IDirectDraw4_QueryInterface(lpCtx->lpDD4, - &IID_IDirect3D3, - (void**)&lpCtx->lpD3D3); - if (FAILED(hResult)) { - MessageBox(NULL, "Unable to initialize Direct3D", "GLDirect", MB_OK); - ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D interface", hResult); - nContextError = GLDERR_D3D; - goto return_with_error; - } - - // Context creation - if (lpCtx->bFullscreen) { - // FULLSCREEN - - // Disable warning popups when in fullscreen mode - ddlogWarnOption(FALSE); - - // Have to release persistant primary surface if fullscreen mode - if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) { - RELEASE(glb.lpPrimary4); - glb.bDirectDrawPrimary = FALSE; - } - - dwFlags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT; - if (glb.bFastFPU) - dwFlags |= DDSCL_FPUSETUP; // fast FPU setup optional (DaveM) - hResult = IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, lpCtx->hWnd, dwFlags); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to set Exclusive Fullscreen mode", hResult); - goto return_with_error; - } - - hResult = IDirectDraw4_SetDisplayMode(lpCtx->lpDD4, - lpCtx->dwModeWidth, - lpCtx->dwModeHeight, - lpPFD->cColorBits, - 0, - 0); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "SetDisplayMode failed", hResult); - goto return_with_error; - } - - // ** The display mode has changed, so dont use MessageBox! ** - - ZeroMemory(&ddsd2, sizeof(ddsd2)); - ddsd2.dwSize = sizeof(ddsd2); - - if (bDoubleBuffer) { - // Double buffered - // Primary surface - ddsd2.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; - ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | - DDSCAPS_FLIP | - DDSCAPS_COMPLEX | - DDSCAPS_3DDEVICE | - dwMemoryType; - ddsd2.dwBackBufferCount = 1; - - hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult); - nContextError = GLDERR_MEM; - goto return_with_error; - } - - // Render target surface - ZeroMemory(&ddscaps2, sizeof(ddscaps2)); // Clear the entire struct. - ddscaps2.dwCaps = DDSCAPS_BACKBUFFER; - hResult = IDirectDrawSurface4_GetAttachedSurface(lpCtx->lpFront4, &ddscaps2, &lpCtx->lpBack4); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "GetAttachedSurface failed", hResult); - nContextError = GLDERR_MEM; - goto return_with_error; - } - } else { - // Single buffered - // Primary surface - ddsd2.dwFlags = DDSD_CAPS; - ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | - //DDSCAPS_3DDEVICE | - dwMemoryType; - - hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult); - nContextError = GLDERR_MEM; - goto return_with_error; - } - - lpCtx->lpBack4 = NULL; - } - } else { - // WINDOWED - - // OK to enable warning popups in windowed mode - ddlogWarnOption(glb.bMessageBoxWarnings); - - dwFlags = DDSCL_NORMAL; - if (glb.bMultiThreaded) - dwFlags |= DDSCL_MULTITHREADED; - if (glb.bFastFPU) - dwFlags |= DDSCL_FPUSETUP; // fast FPU setup optional (DaveM) - hResult = IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, - lpCtx->hWnd, - dwFlags); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to set Normal coop level", hResult); - goto return_with_error; - } - // Has Primary surface already been created for original GLRC ? - // Note this can only be applicable for windowed modes - if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) { - lpCtx->lpFront4 = glb.lpPrimary4; - IDirectDrawSurface4_AddRef(lpCtx->lpFront4); - // Update the window on the default clipper - IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper); - IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd); - IDirectDrawClipper_Release(lpddClipper); - goto SkipPrimaryCreate; - } - - // Primary surface - ZeroMemory(&ddsd2, sizeof(ddsd2)); - ddsd2.dwSize = sizeof(ddsd2); - ddsd2.dwFlags = DDSD_CAPS; - ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult); - nContextError = GLDERR_MEM; - goto return_with_error; - } - - // Cache Primary surface for subsequent GLRCs - // Note this can only be applicable to subsequent windowed modes - if (glb.bDirectDrawPersistant && !glb.bDirectDrawPrimary) { - glb.lpPrimary4 = lpCtx->lpFront4; - IDirectDrawSurface4_AddRef(glb.lpPrimary4); - glb.bDirectDrawPrimary = TRUE; - } - - // Clipper object - hResult = DirectDrawCreateClipper(0, &lpddClipper, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateClipper failed", hResult); - goto return_with_error; - } - hResult = IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd); - if (FAILED(hResult)) { - RELEASE(lpddClipper); - ddlogError(DDLOG_CRITICAL_OR_WARN, "SetHWnd failed", hResult); - goto return_with_error; - } - hResult = IDirectDrawSurface4_SetClipper(lpCtx->lpFront4, lpddClipper); - RELEASE(lpddClipper); // We have finished with it. - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "SetClipper failed", hResult); - goto return_with_error; - } -SkipPrimaryCreate: - - if (bDoubleBuffer) { - // Render target surface - ZeroMemory(&ddsd2, sizeof(ddsd2)); - ddsd2.dwSize = sizeof(ddsd2); - ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd2.dwWidth = lpCtx->dwWidth; - ddsd2.dwHeight = lpCtx->dwHeight; - ddsd2.ddsCaps.dwCaps = DDSCAPS_3DDEVICE | - DDSCAPS_OFFSCREENPLAIN | - dwMemoryType; - - // Reserve the entire desktop size for persistant buffers option - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) { - ddsd2.dwWidth = ddsd2DisplayMode.dwWidth; - ddsd2.dwHeight = ddsd2DisplayMode.dwHeight; - } - // Re-use original back buffer if persistant buffers exist - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpBack4) - hResult = IDirectDrawSurface4_AddRef(lpCtx->lpBack4 = glb.lpBack4); - else - hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpBack4, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "Create Backbuffer failed", hResult); - nContextError = GLDERR_MEM; - goto return_with_error; - } - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpBack4) - IDirectDrawSurface4_AddRef(glb.lpBack4 = lpCtx->lpBack4); - } else { - lpCtx->lpBack4 = NULL; - } - } - - // - // Now create the Z-buffer - // - lpCtx->bStencil = FALSE; // Default to no stencil buffer - if (bDepthBuffer && (lpCtx->lpPF->iZBufferPF != -1)) { - // Get z-buffer dimensions from the render target - // Setup the surface desc for the z-buffer. - ZeroMemory(&ddsd2, sizeof(ddsd2)); - ddsd2.dwSize = sizeof(ddsd2); - ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; - ddsd2.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | dwMemoryType; - ddsd2.dwWidth = lpCtx->dwWidth; - ddsd2.dwHeight = lpCtx->dwHeight; - memcpy(&ddsd2.ddpfPixelFormat, - &glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF], - sizeof(DDPIXELFORMAT) ); - - // Reserve the entire desktop size for persistant buffers option - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) { - ddsd2.dwWidth = ddsd2DisplayMode.dwWidth; - ddsd2.dwHeight = ddsd2DisplayMode.dwHeight; - } - - // Create a z-buffer - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpDepth4) - hResult = IDirectDrawSurface4_AddRef(lpCtx->lpDepth4 = glb.lpDepth4); - else - hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpDepth4, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (ZBuffer) failed", hResult); - nContextError = GLDERR_MEM; - goto return_with_error; - } - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpDepth4) - IDirectDrawSurface4_AddRef(glb.lpDepth4 = lpCtx->lpDepth4); - else if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpDepth4 && glb.lpBack4) - IDirectDrawSurface4_DeleteAttachedSurface(glb.lpBack4, 0, glb.lpDepth4); - - // Attach Zbuffer to render target - TRY(IDirectDrawSurface4_AddAttachedSurface( - bDoubleBuffer ? lpCtx->lpBack4 : lpCtx->lpFront4, - lpCtx->lpDepth4), - "dglCreateContext: Attach Zbuffer"); - if (glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwFlags & DDPF_STENCILBUFFER) { - lpCtx->bStencil = TRUE; - ddlogMessage(DDLOG_INFO, "Depth buffer has stencil\n"); - } - } - - // Clear all back buffers and Z-buffers in case of memory recycling. - ZeroMemory(&ddbltfx, sizeof(ddbltfx)); - ddbltfx.dwSize = sizeof(ddbltfx); - IDirectDrawSurface4_Blt(lpCtx->lpBack4, NULL, NULL, NULL, - DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); - if (lpCtx->lpDepth4) - IDirectDrawSurface4_Blt(lpCtx->lpDepth4, NULL, NULL, NULL, - DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); - - // Now that we have a Z-buffer we can create the 3D device - hResult = IDirect3D3_CreateDevice(lpCtx->lpD3D3, - &glb.d3dGuid, - bDoubleBuffer ? lpCtx->lpBack4 : lpCtx->lpFront4, - &lpCtx->lpDev3, - NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D device", hResult); - nContextError = GLDERR_D3D; - goto return_with_error; - } - - // We must do this as soon as the device is created - dglInitStateCaches(lpCtx); - - // Obtain the D3D Device Description - D3DHWDevDesc.dwSize = D3DHELDevDesc.dwSize = sizeof(D3DDEVICEDESC); - TRY(IDirect3DDevice3_GetCaps(lpCtx->lpDev3, - &D3DHWDevDesc, - &D3DHELDevDesc), - "dglCreateContext: GetCaps failed"); - - // Choose the relevant description and cache it in the context. - // We will use this description later for caps checking - memcpy( &lpCtx->D3DDevDesc, - glb.bHardware ? &D3DHWDevDesc : &D3DHELDevDesc, - sizeof(D3DDEVICEDESC)); - - // Now we can examine the texture formats - if (!dglBuildTextureFormatList(lpCtx->lpDev3)) { - ddlogMessage(DDLOG_CRITICAL_OR_WARN, "dglBuildTextureFormatList failed\n"); - goto return_with_error; - } - - // Get the pixel format of the back buffer - lpCtx->ddpfRender.dwSize = sizeof(lpCtx->ddpfRender); - if (bDoubleBuffer) - hResult = IDirectDrawSurface4_GetPixelFormat( - lpCtx->lpBack4, - &lpCtx->ddpfRender); - else - hResult = IDirectDrawSurface4_GetPixelFormat( - lpCtx->lpFront4, - &lpCtx->ddpfRender); - - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "GetPixelFormat failed", hResult); - goto return_with_error; - } - // Find a pixel packing function suitable for this surface - pxClassifyPixelFormat(&lpCtx->ddpfRender, - &lpCtx->fnPackFunc, - &lpCtx->fnUnpackFunc, - &lpCtx->fnPackSpanFunc); - - // Viewport - hResult = IDirect3D3_CreateViewport(lpCtx->lpD3D3, &lpCtx->lpViewport3, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateViewport failed", hResult); - goto return_with_error; - } - - hResult = IDirect3DDevice3_AddViewport(lpCtx->lpDev3, lpCtx->lpViewport3); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "AddViewport failed", hResult); - goto return_with_error; - } - - // Initialise the viewport - // Note screen coordinates are used for viewport clipping since D3D - // transform operations are not used in the GLD CAD driver. (DaveM) - inv_aspect = (float)lpCtx->dwHeight/(float)lpCtx->dwWidth; - - lpCtx->d3dViewport.dwSize = sizeof(lpCtx->d3dViewport); - lpCtx->d3dViewport.dwX = 0; - lpCtx->d3dViewport.dwY = 0; - lpCtx->d3dViewport.dwWidth = lpCtx->dwWidth; - lpCtx->d3dViewport.dwHeight = lpCtx->dwHeight; - lpCtx->d3dViewport.dvClipX = 0; // -1.0f; - lpCtx->d3dViewport.dvClipY = 0; // inv_aspect; - lpCtx->d3dViewport.dvClipWidth = lpCtx->dwWidth; // 2.0f; - lpCtx->d3dViewport.dvClipHeight = lpCtx->dwHeight; // 2.0f * inv_aspect; - lpCtx->d3dViewport.dvMinZ = 0.0f; - lpCtx->d3dViewport.dvMaxZ = 1.0f; - TRY(IDirect3DViewport3_SetViewport2(lpCtx->lpViewport3, &lpCtx->d3dViewport), "dglCreateContext: SetViewport2"); - - hResult = IDirect3DDevice3_SetCurrentViewport(lpCtx->lpDev3, lpCtx->lpViewport3); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "SetCurrentViewport failed", hResult); - goto return_with_error; - } - - lpCtx->dwBPP = lpPFD->cColorBits; - lpCtx->iZBufferPF = lpCtx->lpPF->iZBufferPF; - - // Set last texture to NULL - for (i=0; i<MAX_TEXTURE_UNITS; i++) { - lpCtx->ColorOp[i] = D3DTOP_DISABLE; - lpCtx->AlphaOp[i] = D3DTOP_DISABLE; - lpCtx->tObj[i] = NULL; - } - - // Default to perspective correct texture mapping - dglSetRenderState(lpCtx, D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, "TexturePersp"); - - // Set the default culling mode - lpCtx->cullmode = D3DCULL_NONE; - dglSetRenderState(lpCtx, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE, "CullMode"); - - // Disable specular - dglSetRenderState(lpCtx, D3DRENDERSTATE_SPECULARENABLE, FALSE, "SpecularEnable"); - // Disable subpixel correction -// dglSetRenderState(lpCtx, D3DRENDERSTATE_SUBPIXEL, FALSE, "SubpixelEnable"); - // Disable dithering - dglSetRenderState(lpCtx, D3DRENDERSTATE_DITHERENABLE, FALSE, "DitherEnable"); - - // Initialise the primitive caches -// lpCtx->dwNextLineVert = 0; -// lpCtx->dwNextTriVert = 0; - - // Init the global texture palette - lpCtx->lpGlobalPalette = NULL; - - // Init the HW/SW usage counters -// lpCtx->dwHWUsageCount = lpCtx->dwSWUsageCount = 0L; - - // - // Create two D3D vertex buffers. - // One will hold the pre-transformed data with the other one - // being used to hold the post-transformed & clipped verts. - // -#if 0 // never used (DaveM) - vbufdesc.dwSize = sizeof(D3DVERTEXBUFFERDESC); - vbufdesc.dwCaps = D3DVBCAPS_WRITEONLY; - if (glb.bHardware == FALSE) - vbufdesc.dwCaps = D3DVBCAPS_SYSTEMMEMORY; - vbufdesc.dwNumVertices = 32768; // For the time being - - // Source vertex buffer - vbufdesc.dwFVF = DGL_LVERTEX; - hResult = IDirect3D3_CreateVertexBuffer(lpCtx->lpD3D3, &vbufdesc, &lpCtx->m_vbuf, 0, NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateVertexBuffer(src) failed", hResult); - goto return_with_error; - } - - // Destination vertex buffer - vbufdesc.dwFVF = (glb.bMultitexture == FALSE) ? D3DFVF_TLVERTEX : (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX2); - hResult = IDirect3D3_CreateVertexBuffer(lpCtx->lpD3D3, &vbufdesc, &lpCtx->m_pvbuf, 0, NULL); - if(FAILED(hResult)) { - ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateVertexBuffer(dst) failed", hResult); - goto return_with_error; - } -#endif - -#endif _USE_GLD3_WGL - - // - // Now create the Mesa context - // - - // Create the Mesa visual - if (lpPFD->cDepthBits) - dwDepthBits = 16; - if (lpPFD->cStencilBits) - dwStencilBits = 8; - if (lpPFD->cAlphaBits) { - dwAlphaBits = 8; - bAlphaSW = GL_TRUE; - } - if (lpPFD->dwFlags & PFD_DOUBLEBUFFER) - bDouble = GL_TRUE; -// lpCtx->EmulateSingle = -// (lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? FALSE : TRUE; - -#ifdef _USE_GLD3_WGL - lpCtx->glVis = _mesa_create_visual( - bDouble, /* double buffer */ - GL_FALSE, // stereo - lpPFD->cRedBits, - lpPFD->cGreenBits, - lpPFD->cBlueBits, - dwAlphaBits, - dwDepthBits, - dwStencilBits, - lpPFD->cAccumRedBits, // accum bits - lpPFD->cAccumGreenBits, // accum bits - lpPFD->cAccumBlueBits, // accum bits - lpPFD->cAccumAlphaBits, // accum alpha bits - 1 // num samples - ); -#else // _USE_GLD3_WGL - lpCtx->glVis = (*mesaFuncs.gl_create_visual)( - GL_TRUE, // RGB mode - bAlphaSW, // Is an alpha buffer required? - bDouble, // Is an double-buffering required? - GL_FALSE, // stereo - dwDepthBits, // depth_size - dwStencilBits, // stencil_size - lpPFD->cAccumBits, // accum_size - 0, // colour-index bits - lpPFD->cRedBits, // Red bit count - lpPFD->cGreenBits, // Green bit count - lpPFD->cBlueBits, // Blue bit count - dwAlphaBits // Alpha bit count - ); -#endif // _USE_GLD3_WGL - - if (lpCtx->glVis == NULL) { - ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_visual failed\n"); - goto return_with_error; - } - -#ifdef _USE_GLD3_WGL - 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)( - lpCtx->glVis, // Mesa visual - NULL, // share list context - (void *)lpCtx, // Pointer to our driver context - GL_TRUE // Direct context flag - ); -#endif // _USE_GLD3_WGL - - if (lpCtx->glCtx == NULL) { - ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_context failed\n"); - goto return_with_error; - } - - // Create the Mesa framebuffer -#ifdef _USE_GLD3_WGL - lpCtx->glBuffer = _mesa_create_framebuffer( - lpCtx->glVis, - lpCtx->glVis->depthBits > 0, - lpCtx->glVis->stencilBits > 0, - lpCtx->glVis->accumRedBits > 0, - GL_FALSE //swalpha - ); -#else - lpCtx->glBuffer = (*mesaFuncs.gl_create_framebuffer)(lpCtx->glVis); -#endif // _USE_GLD3_WGL - - if (lpCtx->glBuffer == NULL) { - ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_framebuffer failed\n"); - goto return_with_error; - } - -#ifdef _USE_GLD3_WGL - // Init Mesa internals - _swrast_CreateContext( lpCtx->glCtx ); - _vbo_CreateContext( lpCtx->glCtx ); - _tnl_CreateContext( lpCtx->glCtx ); - _swsetup_CreateContext( lpCtx->glCtx ); - - _gldDriver.InitialiseMesa(lpCtx); - - lpCtx->glCtx->imports.warning = _gld_mesa_warning; - lpCtx->glCtx->imports.fatal = _gld_mesa_fatal; - -#else - // Tell Mesa how many texture stages we have - glb.wMaxSimultaneousTextures = lpCtx->D3DDevDesc.wMaxSimultaneousTextures; - // Only use as many Units as the spec requires - if (glb.wMaxSimultaneousTextures > MAX_TEXTURE_UNITS) - glb.wMaxSimultaneousTextures = MAX_TEXTURE_UNITS; - lpCtx->glCtx->Const.MaxTextureUnits = glb.wMaxSimultaneousTextures; - ddlogPrintf(DDLOG_INFO, "Texture stages : %d", glb.wMaxSimultaneousTextures); - - // Set the max texture size. - // NOTE: clamped to a max of 1024 for extra performance! - lpCtx->dwMaxTextureSize = (lpCtx->D3DDevDesc.dwMaxTextureWidth <= 1024) ? lpCtx->D3DDevDesc.dwMaxTextureWidth : 1024; - -// Texture resize takes place elsewhere. KH -// NOTE: This was added to workaround an issue with the Intel app. -#if 0 - lpCtx->glCtx->Const.MaxTextureSize = lpCtx->dwMaxTextureSize; -#else - lpCtx->glCtx->Const.MaxTextureSize = 1024; -#endif - lpCtx->glCtx->Const.MaxDrawBuffers = 1; - - // Setup the Display Driver pointers - dglSetupDDPointers(lpCtx->glCtx); - - // Initialise all the Direct3D renderstates - dglInitStateD3D(lpCtx->glCtx); - -#if 0 - // Signal a reload of texture state on next glBegin - lpCtx->m_texHandleValid = FALSE; - lpCtx->m_mtex = FALSE; - lpCtx->m_texturing = FALSE; -#else - // Set default texture unit state -// dglSetTexture(lpCtx, 0, NULL); -// dglSetTexture(lpCtx, 1, NULL); -#endif - - // - // Set the global texture palette to default values. - // - - // Clear the entire palette - ZeroMemory(ppe, sizeof(PALETTEENTRY) * 256); - - // Fill the palette with a default colour. - // A garish colour is used to catch bugs. Here Magenta is used. - for (i=0; i < 256; i++) { - ppe[i].peRed = 255; - ppe[i].peGreen = 0; - ppe[i].peBlue = 255; - } - - RELEASE(lpCtx->lpGlobalPalette); - - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpGlobalPalette) - hResult = IDirectDrawPalette_AddRef(lpCtx->lpGlobalPalette = glb.lpGlobalPalette); - else - hResult = IDirectDraw4_CreatePalette( - lpCtx->lpDD4, - DDPCAPS_INITIALIZE | DDPCAPS_8BIT | DDPCAPS_ALLOW256, - ppe, - &(lpCtx->lpGlobalPalette), - NULL); - if (FAILED(hResult)) { - ddlogError(DDLOG_ERROR, "Default CreatePalette failed\n", hResult); - lpCtx->lpGlobalPalette = NULL; - goto return_with_error; - } - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpGlobalPalette) - IDirectDrawPalette_AddRef(glb.lpGlobalPalette = lpCtx->lpGlobalPalette); - -#endif // _USE_GLD3_WGL - - // ** If we have made it to here then we can enable rendering ** - lpCtx->bCanRender = TRUE; - -// ddlogMessage(DDLOG_SYSTEM, "dglCreateContextBuffers succeded\n"); - -#ifdef GLD_THREADS - // Release serialized access - if (glb.bMultiThreaded) - LeaveCriticalSection(&CriticalSection); -#endif - - return TRUE; - -return_with_error: - // Clean up before returning. - // This is critical for secondary devices. - - lpCtx->bCanRender = FALSE; - -#ifdef _USE_GLD3_WGL - // Destroy the Mesa context - if (lpCtx->glBuffer) - _mesa_destroy_framebuffer(lpCtx->glBuffer); - if (lpCtx->glCtx) - _mesa_destroy_context(lpCtx->glCtx); - if (lpCtx->glVis) - _mesa_destroy_visual(lpCtx->glVis); - - // Destroy driver data - _gldDriver.DestroyDrawable(lpCtx); -#else - // Destroy the Mesa context - if (lpCtx->glBuffer) - (*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer); - if (lpCtx->glCtx) - (*mesaFuncs.gl_destroy_context)(lpCtx->glCtx); - if (lpCtx->glVis) - (*mesaFuncs.gl_destroy_visual)(lpCtx->glVis); - - RELEASE(lpCtx->m_pvbuf); // Release D3D vertex buffer - RELEASE(lpCtx->m_vbuf); // Release D3D vertex buffer - - if (lpCtx->lpViewport3) { - if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3); - RELEASE(lpCtx->lpViewport3); - lpCtx->lpViewport3 = NULL; - } - - RELEASE(lpCtx->lpDev3); - if (lpCtx->lpDepth4) { - if (lpCtx->lpBack4) - IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4); - else - IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4); - RELEASE(lpCtx->lpDepth4); - lpCtx->lpDepth4 = NULL; - } - RELEASE(lpCtx->lpBack4); - RELEASE(lpCtx->lpFront4); - else - if (lpCtx->bFullscreen) { - IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4); - IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL); - } - RELEASE(lpCtx->lpD3D3); - RELEASE(lpCtx->lpDD4); - RELEASE(lpCtx->lpDD1); -#endif // _USE_GLD3_WGL - - lpCtx->bAllocated = FALSE; - -#ifdef GLD_THREADS - // Release serialized access - if (glb.bMultiThreaded) - LeaveCriticalSection(&CriticalSection); -#endif - - return FALSE; - -#undef DDLOG_CRITICAL_OR_WARN -} - -// *********************************************************************** - -HGLRC dglCreateContext( - HDC a, - const DGL_pixelFormat *lpPF) -{ - int i; - HGLRC hGLRC; - DGL_ctx* lpCtx; - static BOOL bWarnOnce = TRUE; - DWORD dwThreadId = GetCurrentThreadId(); - char szMsg[256]; - HWND hWnd; - LONG lpfnWndProc; - - // Validate license - if (!dglValidate()) - return NULL; - - // Is context state ready ? - if (!bContextReady) - return NULL; - - ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext for HDC=%X, ThreadId=%X", a, dwThreadId); - - // Find next free context. - // Also ensure that only one Fullscreen context is created at any one time. - hGLRC = 0; // Default to Not Found - for (i=0; i<DGL_MAX_CONTEXTS; i++) { - if (ctxlist[i].bAllocated) { - if (/*glb.bFullscreen && */ctxlist[i].bFullscreen) - break; - } else { - hGLRC = (HGLRC)(i+1); - break; - } - } - - // Bail if no GLRC was found - if (!hGLRC) - return NULL; - - // Set the context pointer - lpCtx = dglGetContextAddress(hGLRC); - // Make sure that context is zeroed before we do anything. - // MFC and C++ apps call wglCreateContext() and wglDeleteContext() multiple times, - // even though only one context is ever used by the app, so keep it clean. (DaveM) - ZeroMemory(lpCtx, sizeof(DGL_ctx)); - lpCtx->bAllocated = TRUE; - // Flag that buffers need creating on next wglMakeCurrent call. - lpCtx->bHasBeenCurrent = FALSE; - lpCtx->lpPF = (DGL_pixelFormat *)lpPF; // cache pixel format - lpCtx->bCanRender = FALSE; - - // Create all the internal resources here, not in dglMakeCurrent(). - // We do a re-size check in dglMakeCurrent in case of re-allocations. (DaveM) - // We now try context allocations twice, first with video memory, - // then again with system memory. This is similar to technique - // used for dglWglResizeBuffers(). (DaveM) - if (lpCtx->bHasBeenCurrent == FALSE) { - if (!dglCreateContextBuffers(a, lpCtx, FALSE)) { - if (glb.bMessageBoxWarnings && bWarnOnce && dwLogging) { - bWarnOnce = FALSE; - switch (nContextError) { - case GLDERR_DDRAW: strcpy(szMsg, szDDrawWarning); break; - case GLDERR_D3D: strcpy(szMsg, szD3DWarning); break; - case GLDERR_MEM: strcpy(szMsg, szResourceWarning); break; - case GLDERR_BPP: strcpy(szMsg, szBPPWarning); break; - default: strcpy(szMsg, ""); - } - if (strlen(szMsg)) - MessageBox(NULL, szMsg, "GLDirect", MB_OK | MB_ICONWARNING); - } - // Only need to try again if memory error - if (nContextError == GLDERR_MEM) { - ddlogPrintf(DDLOG_WARN, "dglCreateContext failed 1st time with video memory"); - } - else { - ddlogPrintf(DDLOG_ERROR, "dglCreateContext failed"); - return NULL; - } - } - } - - // Now that we have a hWnd, we can intercept the WindowProc. - hWnd = lpCtx->hWnd; - if (hWnd) { - // Only hook individual window handler once if not hooked before. - lpfnWndProc = GetWindowLong(hWnd, GWL_WNDPROC); - if (lpfnWndProc != (LONG)dglWndProc) { - lpCtx->lpfnWndProc = lpfnWndProc; - SetWindowLong(hWnd, GWL_WNDPROC, (LONG)dglWndProc); - } - // Find the parent window of the app too. - if (glb.hWndActive == NULL) { - while (hWnd != NULL) { - glb.hWndActive = hWnd; - hWnd = GetParent(hWnd); - } - // Hook the parent window too. - lpfnWndProc = GetWindowLong(glb.hWndActive, GWL_WNDPROC); - if (glb.hWndActive == lpCtx->hWnd) - glb.lpfnWndProc = lpCtx->lpfnWndProc; - else if (lpfnWndProc != (LONG)dglWndProc) - glb.lpfnWndProc = lpfnWndProc; - if (glb.lpfnWndProc) - SetWindowLong(glb.hWndActive, GWL_WNDPROC, (LONG)dglWndProc); - } - } - - ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext succeeded for HGLRC=%d", (int)hGLRC); - - return hGLRC; -} - -// *********************************************************************** -// Make a DirectGL context current -// Used by wgl functions and dgl functions -BOOL dglMakeCurrent( - HDC a, - HGLRC b) -{ - int context; - DGL_ctx* lpCtx; - HWND hWnd; - BOOL bNeedResize = FALSE; - BOOL bWindowChanged, bContextChanged; - LPDIRECTDRAWCLIPPER lpddClipper; - DWORD dwThreadId = GetCurrentThreadId(); - LONG lpfnWndProc; - - // Validate license - if (!dglValidate()) - return FALSE; - - // Is context state ready ? - if (!bContextReady) - return FALSE; - - context = (int)b; // This is as a result of STRICT! - ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: HDC=%X, HGLRC=%d, ThreadId=%X", a, context, dwThreadId); - - // If the HGLRC is NULL then make no context current; - // Ditto if the HDC is NULL either. (DaveM) - if (context == 0 || a == 0) { - // Corresponding Mesa operation -#ifdef _USE_GLD3_WGL - _mesa_make_current(NULL, NULL); -#else - (*mesaFuncs.gl_make_current)(NULL, NULL); -#endif - dglSetCurrentContext(0); - return TRUE; - } - - // Make sure the HGLRC is in range - if ((context > DGL_MAX_CONTEXTS) || (context < 0)) { - ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: HGLRC out of range\n"); - return FALSE; - } - - // Find address of context and make sure that it has been allocated - lpCtx = dglGetContextAddress(b); - if (!lpCtx->bAllocated) { - ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: Context not allocated\n"); -// return FALSE; - return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH - } - -#ifdef GLD_THREADS - // Serialize access to DirectDraw or DDS operations - if (glb.bMultiThreaded) - EnterCriticalSection(&CriticalSection); -#endif - - // Check if window has changed - hWnd = (a != lpCtx->hDC) ? WindowFromDC(a) : lpCtx->hWnd; - bWindowChanged = (hWnd != lpCtx->hWnd) ? TRUE : FALSE; - bContextChanged = (b != dglGetCurrentContext()) ? TRUE : FALSE; - - // If the window has changed, make sure the clipper is updated. (DaveM) - if (glb.bDirectDrawPersistant && !lpCtx->bFullscreen && (bWindowChanged || bContextChanged)) { - lpCtx->hWnd = hWnd; -#ifndef _USE_GLD3_WGL - IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper); - IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd); - IDirectDrawClipper_Release(lpddClipper); -#endif // _USE_GLD3_WGL - } - - // Make sure hDC and hWnd is current. (DaveM) - // Obtain the dimensions of the rendering window - lpCtx->hDC = a; // Cache DC - lpCtx->hWnd = hWnd; - hWndLastActive = hWnd; - - // Check for non-window DC = memory DC ? - if (hWnd == NULL) { - if (GetClipBox(a, &lpCtx->rcScreenRect) == ERROR) { - ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglMakeCurrent\n"); - SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0); - } - } - else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) { - ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglMakeCurrent\n"); - SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0); - } - // Check if buffers need to be re-sized; - // If so, wait until Mesa GL stuff is setup before re-sizing; - if (lpCtx->dwWidth != lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left || - lpCtx->dwHeight != lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top) - bNeedResize = TRUE; - - // Now we can update our globals - dglSetCurrentContext(b); - - // Corresponding Mesa operation -#ifdef _USE_GLD3_WGL - _mesa_make_current(lpCtx->glCtx, lpCtx->glBuffer); - lpCtx->glCtx->Driver.UpdateState(lpCtx->glCtx, _NEW_ALL); - if (bNeedResize) { - // Resize buffers (Note Mesa GL needs to be setup beforehand); - // Resize Mesa internal buffer too via glViewport() command, - // which subsequently calls dglWglResizeBuffers() too. - lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); - lpCtx->bHasBeenCurrent = TRUE; - } -#else - (*mesaFuncs.gl_make_current)(lpCtx->glCtx, lpCtx->glBuffer); - - dglSetupDDPointers(lpCtx->glCtx); - - // Insure DirectDraw surfaces fit current window DC - if (bNeedResize) { - // Resize buffers (Note Mesa GL needs to be setup beforehand); - // Resize Mesa internal buffer too via glViewport() command, - // which subsequently calls dglWglResizeBuffers() too. - (*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); - lpCtx->bHasBeenCurrent = TRUE; - } -#endif // _USE_GLD3_WGL - ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: width = %d, height = %d", lpCtx->dwWidth, lpCtx->dwHeight); - - // We have to clear D3D back buffer and render state if emulated front buffering - // for different window (but not context) like in Solid Edge. - if (glb.bDirectDrawPersistant && glb.bPersistantBuffers - && (bWindowChanged /* || bContextChanged */) && lpCtx->EmulateSingle) { -#ifdef _USE_GLD3_WGL -// IDirect3DDevice8_EndScene(lpCtx->pDev); -// lpCtx->bSceneStarted = FALSE; - lpCtx->glCtx->Driver.Clear(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, - GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); -#else - IDirect3DDevice3_EndScene(lpCtx->lpDev3); - lpCtx->bSceneStarted = FALSE; - dglClearD3D(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, - GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); -#endif // _USE_GLD3_WGL - } - - // The first time we call MakeCurrent we set the initial viewport size - if (lpCtx->bHasBeenCurrent == FALSE) -#ifdef _USE_GLD3_WGL - lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); -#else - (*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight); -#endif // _USE_GLD3_WGL - lpCtx->bHasBeenCurrent = TRUE; - -#ifdef GLD_THREADS - // Release serialized access - if (glb.bMultiThreaded) - LeaveCriticalSection(&CriticalSection); -#endif - - return TRUE; -} - -// *********************************************************************** - -BOOL dglDeleteContext( - HGLRC a) -{ - DGL_ctx* lpCtx; - DWORD dwThreadId = GetCurrentThreadId(); - char argstr[256]; - -#if 0 // We have enough trouble throwing exceptions as it is... (DaveM) - // Validate license - if (!dglValidate()) - return FALSE; -#endif - - // Is context state ready ? - if (!bContextReady) - return FALSE; - - ddlogPrintf(DDLOG_SYSTEM, "dglDeleteContext: Deleting context HGLRC=%d, ThreadId=%X", (int)a, dwThreadId); - - // Make sure the HGLRC is in range - if (((int) a> DGL_MAX_CONTEXTS) || ((int)a < 0)) { - ddlogMessage(DDLOG_ERROR, "dglDeleteCurrent: HGLRC out of range\n"); - return FALSE; - } - - // Make sure context is valid - lpCtx = dglGetContextAddress(a); - if (!lpCtx->bAllocated) { - ddlogPrintf(DDLOG_WARN, "Tried to delete unallocated context HGLRC=%d", (int)a); -// return FALSE; - return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH - } - - // Make sure context is de-activated - if (a == dglGetCurrentContext()) { - ddlogPrintf(DDLOG_WARN, "dglDeleteContext: context HGLRC=%d still active", (int)a); - dglMakeCurrent(NULL, NULL); - } - -#ifdef GLD_THREADS - // Serialize access to DirectDraw or DDS operations - if (glb.bMultiThreaded) - EnterCriticalSection(&CriticalSection); -#endif - - // We are about to destroy all Direct3D objects. - // Therefore we must disable rendering - lpCtx->bCanRender = FALSE; - - // This exception handler was installed to catch some - // particularly nasty apps. Console apps that call exit() - // fall into this catagory (i.e. Win32 Glut). - - // VC cannot successfully implement multiple exception handlers - // if more than one exception occurs. Therefore reverting back to - // single exception handler as Keith originally had it. (DaveM) - -#define WARN_MESSAGE(p) strcpy(argstr, (#p)); -#define SAFE_RELEASE(p) WARN_MESSAGE(p); RELEASE(p); - -__try { -#ifdef _USE_GLD3_WGL - WARN_MESSAGE(gl_destroy_framebuffer); - if (lpCtx->glBuffer) - _mesa_destroy_framebuffer(lpCtx->glBuffer); - WARN_MESSAGE(gl_destroy_context); - if (lpCtx->glCtx) - _mesa_destroy_context(lpCtx->glCtx); - WARN_MESSAGE(gl_destroy_visual); - if (lpCtx->glVis) - _mesa_destroy_visual(lpCtx->glVis); - - _gldDriver.DestroyDrawable(lpCtx); -#else - // Destroy the Mesa context - WARN_MESSAGE(gl_destroy_framebuffer); - if (lpCtx->glBuffer) - (*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer); - WARN_MESSAGE(gl_destroy_context); - if (lpCtx->glCtx) - (*mesaFuncs.gl_destroy_context)(lpCtx->glCtx); - WARN_MESSAGE(gl_destroy_visual); - if (lpCtx->glVis) - (*mesaFuncs.gl_destroy_visual)(lpCtx->glVis); - - SAFE_RELEASE(lpCtx->m_pvbuf); // release D3D vertex buffer - SAFE_RELEASE(lpCtx->m_vbuf); // release D3D vertex buffer - - // Delete the global palette - SAFE_RELEASE(lpCtx->lpGlobalPalette); - - // Clean up. - if (lpCtx->lpViewport3) { - if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3); - SAFE_RELEASE(lpCtx->lpViewport3); - lpCtx->lpViewport3 = NULL; - } - - SAFE_RELEASE(lpCtx->lpDev3); - if (lpCtx->lpDepth4) { - if (lpCtx->lpBack4) - IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4); - else - IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4); - SAFE_RELEASE(lpCtx->lpDepth4); - lpCtx->lpDepth4 = NULL; - } - SAFE_RELEASE(lpCtx->lpBack4); - SAFE_RELEASE(lpCtx->lpFront4); - if (lpCtx->bFullscreen) { - IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4); - IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL); - } - SAFE_RELEASE(lpCtx->lpD3D3); - SAFE_RELEASE(lpCtx->lpDD4); - SAFE_RELEASE(lpCtx->lpDD1); -#endif // _ULSE_GLD3_WGL - -} -__except(EXCEPTION_EXECUTE_HANDLER) { - ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContext: %s", argstr); -} - - // Restore the window message handler because this context may be used - // again by another window with a *different* message handler. (DaveM) - if (lpCtx->lpfnWndProc) { - SetWindowLong(lpCtx->hWnd, GWL_WNDPROC, (LONG)lpCtx->lpfnWndProc); - lpCtx->lpfnWndProc = (LONG)NULL; - } - - lpCtx->bAllocated = FALSE; // This context is now free for use - -#ifdef GLD_THREADS - // Release serialized access - if (glb.bMultiThreaded) - LeaveCriticalSection(&CriticalSection); -#endif - - return TRUE; -} - -// *********************************************************************** - -BOOL dglSwapBuffers( - HDC hDC) -{ - RECT rSrcRect; // Source rectangle - RECT rDstRect; // Destination rectangle - POINT pt; - HRESULT hResult; - - DDBLTFX bltFX; - DWORD dwBlitFlags; - DDBLTFX *lpBltFX; - -// DWORD dwThreadId = GetCurrentThreadId(); - HGLRC hGLRC = dglGetCurrentContext(); - DGL_ctx *lpCtx = dglGetContextAddress(hGLRC); - HWND hWnd; - - HDC hDCAux; // for memory DC - int x,y,w,h; // for memory DC BitBlt - -#if 0 // Perhaps not a good idea. Called too often. KH - // Validate license - if (!dglValidate()) - return FALSE; -#endif - - if (!lpCtx) { - return TRUE; //FALSE; // No current context - } - - if (!lpCtx->bCanRender) { - // Don't return false else some apps will bail. - return TRUE; - } - - hWnd = lpCtx->hWnd; - if (hDC != lpCtx->hDC) { - ddlogPrintf(DDLOG_WARN, "dglSwapBuffers: HDC=%X does not match HDC=%X for HGLRC=%d", hDC, lpCtx->hDC, hGLRC); - hWnd = WindowFromDC(hDC); - } - -#ifndef _USE_GLD3_WGL - // Ensure that the surfaces exist before we tell - // the device to render to them. - IDirectDraw4_RestoreAllSurfaces(lpCtx->lpDD4); - - // Make sure that the vertex caches have been emptied -// dglStateChange(lpCtx); - - // Some OpenGL programs don't issue a glFinish - check for it here. - if (lpCtx->bSceneStarted) { - IDirect3DDevice3_EndScene(lpCtx->lpDev3); - lpCtx->bSceneStarted = FALSE; - } -#endif - -#if 0 - // If the calling app is not active then we don't need to Blit/Flip. - // We can therefore simply return TRUE. - if (!glb.bAppActive) - return TRUE; - // Addendum: This is WRONG! We should bail if the app is *minimized*, - // not merely if the app is just plain 'not active'. - // KeithH, 27/May/2000. -#endif - - // Check for non-window DC = memory DC ? - if (hWnd == NULL) { - if (GetClipBox(hDC, &rSrcRect) == ERROR) - return TRUE; - // Use GDI BitBlt instead from compatible DirectDraw DC - x = rSrcRect.left; - y = rSrcRect.top; - w = rSrcRect.right - rSrcRect.left; - h = rSrcRect.bottom - rSrcRect.top; - - // Ack. DX8 does not have a GetDC() function... - // TODO: Defer to DX7 or DX9 drivers... (DaveM) - return TRUE; - } - - // Bail if window client region is not drawable, like in Solid Edge - if (!IsWindow(hWnd) /* || !IsWindowVisible(hWnd) */ || !GetClientRect(hWnd, &rSrcRect)) - return TRUE; - -#ifdef GLD_THREADS - // Serialize access to DirectDraw or DDS operations - if (glb.bMultiThreaded) - EnterCriticalSection(&CriticalSection); -#endif - -#ifdef _USE_GLD3_WGL - // Notify Mesa of impending swap, so Mesa can flush internal buffers. - _mesa_notifySwapBuffers(lpCtx->glCtx); - // Now perform driver buffer swap - _gldDriver.SwapBuffers(lpCtx, hDC, hWnd); -#else - if (lpCtx->bFullscreen) { - // Sync with retrace if required - if (glb.bWaitForRetrace) { - IDirectDraw4_WaitForVerticalBlank( - lpCtx->lpDD4, - DDWAITVB_BLOCKBEGIN, - 0); - } - - // Perform the fullscreen flip - TRY(IDirectDrawSurface4_Flip( - lpCtx->lpFront4, - NULL, - DDFLIP_WAIT), - "dglSwapBuffers: Flip"); - } else { - // Calculate current window position and size - pt.x = pt.y = 0; - ClientToScreen(hWnd, &pt); - GetClientRect(hWnd, &rDstRect); - if (rDstRect.right > lpCtx->dwModeWidth) - rDstRect.right = lpCtx->dwModeWidth; - if (rDstRect.bottom > lpCtx->dwModeHeight) - rDstRect.bottom = lpCtx->dwModeHeight; - OffsetRect(&rDstRect, pt.x, pt.y); - rSrcRect.left = rSrcRect.top = 0; - rSrcRect.right = lpCtx->dwWidth; - rSrcRect.bottom = lpCtx->dwHeight; - if (rSrcRect.right > lpCtx->dwModeWidth) - rSrcRect.right = lpCtx->dwModeWidth; - if (rSrcRect.bottom > lpCtx->dwModeHeight) - rSrcRect.bottom = lpCtx->dwModeHeight; - - if (glb.bWaitForRetrace) { - // Sync the blit to the vertical retrace - ZeroMemory(&bltFX, sizeof(bltFX)); - bltFX.dwSize = sizeof(bltFX); - bltFX.dwDDFX = DDBLTFX_NOTEARING; - dwBlitFlags = DDBLT_WAIT | DDBLT_DDFX; - lpBltFX = &bltFX; - } else { - dwBlitFlags = DDBLT_WAIT; - lpBltFX = NULL; - } - - // Perform the actual blit - TRY(IDirectDrawSurface4_Blt( - lpCtx->lpFront4, - &rDstRect, - lpCtx->lpBack4, // Blit source - &rSrcRect, - dwBlitFlags, - lpBltFX), - "dglSwapBuffers: Blt"); - } -#endif // _USE_GLD3_WGL - -#ifdef GLD_THREADS - // Release serialized access - if (glb.bMultiThreaded) - LeaveCriticalSection(&CriticalSection); -#endif - - // TODO: Re-instate rendering bitmap snapshot feature??? (DaveM) - - // Render frame is completed - ValidateRect(hWnd, NULL); - lpCtx->bFrameStarted = FALSE; - - return TRUE; -} - -// *********************************************************************** +/****************************************************************************
+*
+* Mesa 3-D graphics library
+* Direct3D Driver Interface
+*
+* ========================================================================
+*
+* Copyright (C) 1991-2004 SciTech Software, 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
+* SCITECH SOFTWARE INC 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.
+*
+* ======================================================================
+*
+* Language: ANSI C
+* Environment: Windows 9x (Win32)
+*
+* Description: Context handling.
+*
+****************************************************************************/
+
+#include "dglcontext.h"
+
+// Get compile errors without this. KeithH
+//#include "scitech.h" // ibool, etc.
+
+#ifdef _USE_GLD3_WGL
+#include "gld_driver.h"
+
+extern void _gld_mesa_warning(struct gl_context *, char *);
+extern void _gld_mesa_fatal(struct gl_context *, char *);
+#endif // _USE_GLD3_WGL
+
+// TODO: Clean out old DX6-specific code from GLD 2.x CAD driver
+// if it is no longer being built as part of GLDirect. (DaveM)
+
+// ***********************************************************************
+
+#define GLDERR_NONE 0
+#define GLDERR_MEM 1
+#define GLDERR_DDRAW 2
+#define GLDERR_D3D 3
+#define GLDERR_BPP 4
+
+char szResourceWarning[] =
+"GLDirect does not have enough video memory resources\n"
+"to support the requested OpenGL rendering context.\n\n"
+"You may have to reduce the current display resolution\n"
+"to obtain satisfactory OpenGL performance.\n";
+
+char szDDrawWarning[] =
+"GLDirect is unable to initialize DirectDraw for the\n"
+"requested OpenGL rendering context.\n\n"
+"You will have to check the DirectX control panel\n"
+"for further information.\n";
+
+char szD3DWarning[] =
+"GLDirect is unable to initialize Direct3D for the\n"
+"requested OpenGL rendering context.\n\n"
+"You may have to change the display mode resolution\n"
+"color depth or check the DirectX control panel for\n"
+"further information.\n";
+
+char szBPPWarning[] =
+"GLDirect is unable to use the selected color depth for\n"
+"the requested OpenGL rendering context.\n\n"
+"You will have to change the display mode resolution\n"
+"color depth with the Display Settings control panel.\n";
+
+int nContextError = GLDERR_NONE;
+
+// ***********************************************************************
+
+#define VENDORID_ATI 0x1002
+
+static DWORD devATIRagePro[] = {
+ 0x4742, // 3D RAGE PRO BGA AGP 1X/2X
+ 0x4744, // 3D RAGE PRO BGA AGP 1X only
+ 0x4749, // 3D RAGE PRO BGA PCI 33 MHz
+ 0x4750, // 3D RAGE PRO PQFP PCI 33 MHz
+ 0x4751, // 3D RAGE PRO PQFP PCI 33 MHz limited 3D
+ 0x4C42, // 3D RAGE LT PRO BGA-312 AGP 133 MHz
+ 0x4C44, // 3D RAGE LT PRO BGA-312 AGP 66 MHz
+ 0x4C49, // 3D RAGE LT PRO BGA-312 PCI 33 MHz
+ 0x4C50, // 3D RAGE LT PRO BGA-256 PCI 33 MHz
+ 0x4C51, // 3D RAGE LT PRO BGA-256 PCI 33 MHz limited 3D
+};
+
+static DWORD devATIRageIIplus[] = {
+ 0x4755, // 3D RAGE II+
+ 0x4756, // 3D RAGE IIC PQFP PCI
+ 0x4757, // 3D RAGE IIC BGA AGP
+ 0x475A, // 3D RAGE IIC PQFP AGP
+ 0x4C47, // 3D RAGE LT-G
+};
+
+// ***********************************************************************
+
+#ifndef _USE_GLD3_WGL
+extern DGL_mesaFuncs mesaFuncs;
+#endif
+
+extern DWORD dwLogging;
+
+#ifdef GLD_THREADS
+#pragma message("compiling DGLCONTEXT.C vars for multi-threaded support")
+CRITICAL_SECTION CriticalSection; // for serialized access
+DWORD dwTLSCurrentContext = 0xFFFFFFFF; // TLS index for current context
+DWORD dwTLSPixelFormat = 0xFFFFFFFF; // TLS index for current pixel format
+#endif
+HGLRC iCurrentContext = 0; // Index of current context (static)
+BOOL bContextReady = FALSE; // Context state ready ?
+
+DGL_ctx ctxlist[DGL_MAX_CONTEXTS]; // Context list
+
+// ***********************************************************************
+
+static BOOL bHaveWin95 = FALSE;
+static BOOL bHaveWinNT = FALSE;
+static BOOL bHaveWin2K = FALSE;
+
+/****************************************************************************
+REMARKS:
+Detect the installed OS type.
+****************************************************************************/
+static void DetectOS(void)
+{
+ OSVERSIONINFO VersionInformation;
+ LPOSVERSIONINFO lpVersionInformation = &VersionInformation;
+
+ VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation);
+
+ GetVersionEx(lpVersionInformation);
+
+ switch (VersionInformation.dwPlatformId) {
+ case VER_PLATFORM_WIN32_WINDOWS:
+ bHaveWin95 = TRUE;
+ bHaveWinNT = FALSE;
+ bHaveWin2K = FALSE;
+ break;
+ case VER_PLATFORM_WIN32_NT:
+ bHaveWin95 = FALSE;
+ if (VersionInformation.dwMajorVersion <= 4) {
+ bHaveWinNT = TRUE;
+ bHaveWin2K = FALSE;
+ }
+ else {
+ bHaveWinNT = FALSE;
+ bHaveWin2K = TRUE;
+ }
+ break;
+ case VER_PLATFORM_WIN32s:
+ bHaveWin95 = FALSE;
+ bHaveWinNT = FALSE;
+ bHaveWin2K = FALSE;
+ break;
+ }
+}
+
+// ***********************************************************************
+
+HWND hWndEvent = NULL; // event monitor window
+HWND hWndLastActive = NULL; // last active client window
+LONG __stdcall GLD_EventWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
+
+// ***********************************************************************
+
+// Checks if the HGLRC is valid in range of context list.
+BOOL dglIsValidContext(
+ HGLRC a)
+{
+ return ((int)a > 0 && (int)a <= DGL_MAX_CONTEXTS);
+}
+
+// ***********************************************************************
+
+// Convert a HGLRC to a pointer into the context list.
+DGL_ctx* dglGetContextAddress(
+ const HGLRC a)
+{
+ if (dglIsValidContext(a))
+ return &ctxlist[(int)a-1];
+ return NULL;
+}
+
+// ***********************************************************************
+
+// Return the current HGLRC (however it may be stored for multi-threading).
+HGLRC dglGetCurrentContext(void)
+{
+#ifdef GLD_THREADS
+ HGLRC hGLRC;
+ // load from thread-specific instance
+ if (glb.bMultiThreaded) {
+ // protect against calls from arbitrary threads
+ __try {
+ hGLRC = (HGLRC)TlsGetValue(dwTLSCurrentContext);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER) {
+ hGLRC = iCurrentContext;
+ }
+ }
+ // load from global static var
+ else {
+ hGLRC = iCurrentContext;
+ }
+ return hGLRC;
+#else
+ return iCurrentContext;
+#endif
+}
+
+// ***********************************************************************
+
+// Set the current HGLRC (however it may be stored for multi-threading).
+void dglSetCurrentContext(HGLRC hGLRC)
+{
+#ifdef GLD_THREADS
+ // store in thread-specific instance
+ if (glb.bMultiThreaded) {
+ // protect against calls from arbitrary threads
+ __try {
+ TlsSetValue(dwTLSCurrentContext, (LPVOID)hGLRC);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER) {
+ iCurrentContext = hGLRC;
+ }
+ }
+ // store in global static var
+ else {
+ iCurrentContext = hGLRC;
+ }
+#else
+ iCurrentContext = hGLRC;
+#endif
+}
+
+// ***********************************************************************
+
+// Return the current HDC only for a currently active HGLRC.
+HDC dglGetCurrentDC(void)
+{
+ HGLRC hGLRC;
+ DGL_ctx* lpCtx;
+
+ hGLRC = dglGetCurrentContext();
+ if (hGLRC) {
+ lpCtx = dglGetContextAddress(hGLRC);
+ return lpCtx->hDC;
+ }
+ return 0;
+}
+
+// ***********************************************************************
+
+void dglInitContextState()
+{
+ int i;
+ WNDCLASS wc;
+
+#ifdef GLD_THREADS
+ // Allocate thread local storage indexes for current context and pixel format
+ dwTLSCurrentContext = TlsAlloc();
+ dwTLSPixelFormat = TlsAlloc();
+#endif
+
+ dglSetCurrentContext(NULL); // No current rendering context
+
+ // Clear all context data
+ ZeroMemory(ctxlist, sizeof(ctxlist[0]) * DGL_MAX_CONTEXTS);
+
+ for (i=0; i<DGL_MAX_CONTEXTS; i++)
+ ctxlist[i].bAllocated = FALSE; // Flag context as unused
+
+ // This section of code crashes the dll in circumstances where the app
+ // creates and destroys contexts.
+/*
+ // Register the class for our event monitor window
+ wc.style = 0;
+ wc.lpfnWndProc = GLD_EventWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = LoadIcon(GetModuleHandle(NULL), IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "GLDIRECT";
+ RegisterClass(&wc);
+
+ // Create the non-visible window to monitor all broadcast messages
+ hWndEvent = CreateWindowEx(
+ WS_EX_TOOLWINDOW,"GLDIRECT","GLDIRECT",WS_POPUP,
+ 0,0,0,0,
+ NULL,NULL,GetModuleHandle(NULL),NULL);
+*/
+
+#ifdef GLD_THREADS
+ // Create a critical section object for serializing access to
+ // DirectDraw and DDStereo create/destroy functions in multiple threads
+ if (glb.bMultiThreaded)
+ InitializeCriticalSection(&CriticalSection);
+#endif
+
+ // Context state is now initialized and ready
+ bContextReady = TRUE;
+}
+
+// ***********************************************************************
+
+void dglDeleteContextState()
+{
+ int i;
+ static BOOL bOnceIsEnough = FALSE;
+
+ // Only call once, from either DGL_exitDriver(), or DLL_PROCESS_DETACH
+ if (bOnceIsEnough)
+ return;
+ bOnceIsEnough = TRUE;
+
+ for (i=0; i<DGL_MAX_CONTEXTS; i++) {
+ if (ctxlist[i].bAllocated == TRUE) {
+ ddlogPrintf(DDLOG_WARN, "** Context %i not deleted - cleaning up.", (i+1));
+ dglDeleteContext((HGLRC)(i+1));
+ }
+ }
+
+ // Context state is no longer ready
+ bContextReady = FALSE;
+
+ // If executed when DLL unloads, DDraw objects may be invalid.
+ // So catch any page faults with this exception handler.
+__try {
+
+ // Release final DirectDraw interfaces
+ if (glb.bDirectDrawPersistant) {
+// RELEASE(glb.lpGlobalPalette);
+// RELEASE(glb.lpDepth4);
+// RELEASE(glb.lpBack4);
+// RELEASE(glb.lpPrimary4);
+// RELEASE(glb.lpDD4);
+ }
+}
+__except(EXCEPTION_EXECUTE_HANDLER) {
+ ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContextState.");
+}
+
+ // Destroy our event monitor window
+ if (hWndEvent) {
+ DestroyWindow(hWndEvent);
+ hWndEvent = hWndLastActive = NULL;
+ }
+
+#ifdef GLD_THREADS
+ // Destroy the critical section object
+ if (glb.bMultiThreaded)
+ DeleteCriticalSection(&CriticalSection);
+
+ // Release thread local storage indexes for current HGLRC and pixel format
+ TlsFree(dwTLSPixelFormat);
+ TlsFree(dwTLSCurrentContext);
+#endif
+}
+
+// ***********************************************************************
+
+// Application Window message handler interception
+static LONG __stdcall dglWndProc(
+ HWND hwnd,
+ UINT msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ DGL_ctx* lpCtx = NULL;
+ LONG lpfnWndProc = 0L;
+ int i;
+ HGLRC hGLRC;
+ RECT rect;
+ PAINTSTRUCT ps;
+ BOOL bQuit = FALSE;
+ BOOL bMain = FALSE;
+ LONG rc;
+
+ // Get the window's message handler *before* it is unhooked in WM_DESTROY
+
+ // Is this the main window?
+ if (hwnd == glb.hWndActive) {
+ bMain = TRUE;
+ lpfnWndProc = glb.lpfnWndProc;
+ }
+ // Search for DGL context matching window handle
+ for (i=0; i<DGL_MAX_CONTEXTS; i++) {
+ if (ctxlist[i].hWnd == hwnd) {
+ lpCtx = &ctxlist[i];
+ lpfnWndProc = lpCtx->lpfnWndProc;
+ break;
+ }
+ }
+ // Not one of ours...
+ if (!lpfnWndProc)
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ // Intercept messages amd process *before* passing on to window
+ switch (msg) {
+#ifdef _USE_GLD3_WGL
+ case WM_DISPLAYCHANGE:
+ glb.bPixelformatsDirty = TRUE;
+ break;
+#endif
+ case WM_ACTIVATEAPP:
+ glb.bAppActive = (BOOL)wParam;
+ ddlogPrintf(DDLOG_INFO, "Calling app has been %s", glb.bAppActive ? "activated" : "de-activated");
+ break;
+ case WM_ERASEBKGND:
+ // Eat the GDI erase event for the GL window
+ if (!lpCtx || !lpCtx->bHasBeenCurrent)
+ break;
+ lpCtx->bGDIEraseBkgnd = TRUE;
+ return TRUE;
+ case WM_PAINT:
+ // Eat the invalidated update region if render scene is in progress
+ if (!lpCtx || !lpCtx->bHasBeenCurrent)
+ break;
+ if (lpCtx->bFrameStarted) {
+ if (GetUpdateRect(hwnd, &rect, FALSE)) {
+ BeginPaint(hwnd, &ps);
+ EndPaint(hwnd, &ps);
+ ValidateRect(hwnd, &rect);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ // Call the appropriate window message handler
+ rc = CallWindowProc((WNDPROC)lpfnWndProc, hwnd, msg, wParam, lParam);
+
+ // Intercept messages and process *after* passing on to window
+ switch (msg) {
+ case WM_QUIT:
+ case WM_DESTROY:
+ bQuit = TRUE;
+ if (lpCtx && lpCtx->bAllocated) {
+ ddlogPrintf(DDLOG_WARN, "WM_DESTROY detected for HWND=%X, HDC=%X, HGLRC=%d", hwnd, lpCtx->hDC, i+1);
+ dglDeleteContext((HGLRC)(i+1));
+ }
+ break;
+#if 0
+ case WM_SIZE:
+ // Resize surfaces to fit window but not viewport (in case app did not bother)
+ if (!lpCtx || !lpCtx->bHasBeenCurrent)
+ break;
+ w = LOWORD(lParam);
+ h = HIWORD(lParam);
+ if (lpCtx->dwWidth < w || lpCtx->dwHeight < h) {
+ if (!dglWglResizeBuffers(lpCtx->glCtx, TRUE))
+ dglWglResizeBuffers(lpCtx->glCtx, FALSE);
+ }
+ break;
+#endif
+ }
+
+ // If the main window is quitting, then so should we...
+ if (bMain && bQuit) {
+ ddlogPrintf(DDLOG_SYSTEM, "shutting down after WM_DESTROY detected for main HWND=%X", hwnd);
+ dglDeleteContextState();
+ dglExitDriver();
+ }
+
+ return rc;
+}
+
+// ***********************************************************************
+
+// Driver Window message handler
+static LONG __stdcall GLD_EventWndProc(
+ HWND hwnd,
+ UINT msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ switch (msg) {
+ // May be sent by splash screen dialog on exit
+ case WM_ACTIVATE:
+ if (LOWORD(wParam) == WA_ACTIVE && glb.hWndActive) {
+ SetForegroundWindow(glb.hWndActive);
+ return 0;
+ }
+ break;
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+// ***********************************************************************
+
+// Intercepted Keyboard handler for detecting hot keys.
+LRESULT CALLBACK dglKeyProc(
+ int code,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ HWND hWnd, hWndFrame;
+ HGLRC hGLRC = NULL;
+ DGL_ctx* lpCtx = NULL;
+ int cmd = 0, dx1 = 0, dx2 = 0, i;
+ static BOOL bAltPressed = FALSE;
+ static BOOL bCtrlPressed = FALSE;
+ static BOOL bShiftPressed = FALSE;
+ RECT r, rf, rc;
+ POINT pt;
+ BOOL bForceReshape = FALSE;
+
+ return CallNextHookEx(hKeyHook, code, wParam, lParam);
+}
+
+// ***********************************************************************
+
+HWND hWndMatch;
+
+// Window handle enumeration procedure.
+BOOL CALLBACK dglEnumChildProc(
+ HWND hWnd,
+ LPARAM lParam)
+{
+ RECT rect;
+
+ // Find window handle with matching client rect.
+ GetClientRect(hWnd, &rect);
+ if (EqualRect(&rect, (RECT*)lParam)) {
+ hWndMatch = hWnd;
+ return FALSE;
+ }
+ // Continue with next child window.
+ return TRUE;
+}
+
+// ***********************************************************************
+
+// Find window handle with matching client rect.
+HWND dglFindWindowRect(
+ RECT* pRect)
+{
+ hWndMatch = NULL;
+ EnumChildWindows(GetForegroundWindow(), dglEnumChildProc, (LPARAM)pRect);
+ return hWndMatch;
+}
+
+// ***********************************************************************
+#ifndef _USE_GLD3_WGL
+void dglChooseDisplayMode(
+ DGL_ctx *lpCtx)
+{
+ // Note: Choose an exact match if possible.
+
+ int i;
+ DWORD area;
+ DWORD bestarea;
+ DDSURFACEDESC2 *lpDDSD = NULL; // Mode list pointer
+ DDSURFACEDESC2 *lpBestDDSD = NULL; // Pointer to best
+
+ lpDDSD = glb.lpDisplayModes;
+ for (i=0; i<glb.nDisplayModeCount; i++, lpDDSD++) {
+ if ((lpDDSD->dwWidth == lpCtx->dwWidth) &&
+ (lpDDSD->dwHeight == lpCtx->dwHeight))
+ goto matched; // Mode has been exactly matched
+ // Choose modes that are larger in both dimensions than
+ // the window, but smaller in area than the current best.
+ if ( (lpDDSD->dwWidth >= lpCtx->dwWidth) &&
+ (lpDDSD->dwHeight >= lpCtx->dwHeight))
+ {
+ if (lpBestDDSD == NULL) {
+ lpBestDDSD = lpDDSD;
+ bestarea = lpDDSD->dwWidth * lpDDSD->dwHeight;
+ continue;
+ }
+ area = lpDDSD->dwWidth * lpDDSD->dwHeight;
+ if (area < bestarea) {
+ lpBestDDSD = lpDDSD;
+ bestarea = area;
+ }
+ }
+ }
+
+ // Safety check
+ if (lpBestDDSD == NULL) {
+ ddlogMessage(DDLOG_CRITICAL, "dglChooseDisplayMode");
+ return;
+ }
+
+ lpCtx->dwModeWidth = lpBestDDSD->dwWidth;
+ lpCtx->dwModeHeight = lpBestDDSD->dwHeight;
+matched:
+ ddlogPrintf(DDLOG_INFO, "Matched (%ldx%ld) to (%ldx%ld)",
+ lpCtx->dwWidth, lpCtx->dwHeight, lpCtx->dwModeWidth, lpCtx->dwModeHeight);
+}
+#endif // _USE_GLD3_WGL
+// ***********************************************************************
+
+static BOOL IsDevice(
+ DWORD *lpDeviceIdList,
+ DWORD dwDeviceId,
+ int count)
+{
+ int i;
+
+ for (i=0; i<count; i++)
+ if (dwDeviceId == lpDeviceIdList[i])
+ return TRUE;
+
+ return FALSE;
+}
+
+// ***********************************************************************
+
+void dglTestForBrokenCards(
+ DGL_ctx *lpCtx)
+{
+#ifndef _GLD3
+ DDDEVICEIDENTIFIER dddi; // DX6 device identifier
+
+ // Sanity check.
+ if (lpCtx == NULL) {
+ // Testing for broken cards is sensitive area, so we don't want
+ // anything saying "broken cards" in the error message. ;)
+ ddlogMessage(DDLOG_ERROR, "Null context passed to TFBC\n");
+ return;
+ }
+
+ if (lpCtx->lpDD4 == NULL) {
+ // Testing for broken cards is sensitive area, so we don't want
+ // anything saying "broken cards" in the error message. ;)
+ ddlogMessage(DDLOG_ERROR, "Null DD4 passed to TFBC\n");
+ return;
+ }
+
+ // Microsoft really fucked up with the GetDeviceIdentifier function
+ // on Windows 2000, since it locks up on stock driers on the CD. Updated
+ // drivers from vendors appear to work, but we can't identify the drivers
+ // without this function!!! For now we skip these tests on Windows 2000.
+ if ((GetVersion() & 0x80000000UL) == 0)
+ return;
+
+ // Obtain device info
+ if (FAILED(IDirectDraw4_GetDeviceIdentifier(lpCtx->lpDD4, &dddi, 0)))
+ return;
+
+ // Useful info. Log it.
+ ddlogPrintf(DDLOG_INFO, "DirectDraw: VendorId=0x%x, DeviceId=0x%x", dddi.dwVendorId, dddi.dwDeviceId);
+
+ // Vendor 1: ATI
+ if (dddi.dwVendorId == VENDORID_ATI) {
+ // Test A: ATI Rage PRO
+ if (IsDevice(devATIRagePro, dddi.dwDeviceId, sizeof(devATIRagePro)))
+ glb.bUseMipmaps = FALSE;
+ // Test B: ATI Rage II+
+ if (IsDevice(devATIRageIIplus, dddi.dwDeviceId, sizeof(devATIRageIIplus)))
+ glb.bEmulateAlphaTest = TRUE;
+ }
+
+ // Vendor 2: Matrox
+ if (dddi.dwVendorId == 0x102B) {
+ // Test: Matrox G400 stencil buffer support does not work for AutoCAD
+ if (dddi.dwDeviceId == 0x0525) {
+ lpCtx->lpPF->pfd.cStencilBits = 0;
+ if (lpCtx->lpPF->iZBufferPF != -1) {
+ glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwStencilBitDepth = 0;
+ glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwStencilBitMask = 0;
+ glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwFlags &= ~DDPF_STENCILBUFFER;
+ }
+ }
+ }
+#endif // _GLD3
+}
+
+// ***********************************************************************
+
+BOOL dglCreateContextBuffers(
+ HDC a,
+ DGL_ctx *lpCtx,
+ BOOL bFallback)
+{
+ HRESULT hResult;
+
+ int i;
+// HGLRC hGLRC;
+// DGL_ctx* lpCtx;
+
+#ifndef _USE_GLD3_WGL
+ DWORD dwFlags;
+ DDSURFACEDESC2 ddsd2;
+ DDSCAPS2 ddscaps2;
+ LPDIRECTDRAWCLIPPER lpddClipper;
+ D3DDEVICEDESC D3DHWDevDesc; // Direct3D Hardware description
+ D3DDEVICEDESC D3DHELDevDesc; // Direct3D Hardware Emulation Layer
+#endif // _USE_GLD3_WGL
+
+ float inv_aspect;
+
+ GLenum bDoubleBuffer; // TRUE if double buffer required
+ GLenum bDepthBuffer; // TRUE if depth buffer required
+
+ const PIXELFORMATDESCRIPTOR *lpPFD = &lpCtx->lpPF->pfd;
+
+ // Vars for Mesa visual
+ DWORD dwDepthBits = 0;
+ DWORD dwStencilBits = 0;
+ DWORD dwAlphaBits = 0;
+ DWORD bAlphaSW = GL_FALSE;
+ DWORD bDouble = GL_FALSE;
+
+ DDSURFACEDESC2 ddsd2DisplayMode;
+ BOOL bFullScrnWin = FALSE; // fullscreen-size window ?
+ DDBLTFX ddbltfx;
+ DWORD dwMemoryType = (bFallback) ? DDSCAPS_SYSTEMMEMORY : glb.dwMemoryType;
+ BOOL bBogusWindow = FALSE; // non-drawable window ?
+ DWORD dwColorRef = 0; // GDI background color
+ RECT rcDst; // GDI window rect
+ POINT pt; // GDI window point
+
+ // Palette used for creating default global palette
+ PALETTEENTRY ppe[256];
+
+#ifndef _USE_GLD3_WGL
+ // Vertex buffer description. Used for creation of vertex buffers
+ D3DVERTEXBUFFERDESC vbufdesc;
+#endif // _USE_GLD3_WGL
+
+#define DDLOG_CRITICAL_OR_WARN (bFallback ? DDLOG_CRITICAL : DDLOG_WARN)
+
+ ddlogPrintf(DDLOG_SYSTEM, "dglCreateContextBuffers for HDC=%X", a);
+ nContextError = GLDERR_NONE;
+
+#ifdef GLD_THREADS
+ // Serialize access to DirectDraw object creation or DDS start
+ if (glb.bMultiThreaded)
+ EnterCriticalSection(&CriticalSection);
+#endif
+
+ // Check for back buffer
+ bDoubleBuffer = GL_TRUE; //(lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? GL_TRUE : GL_FALSE;
+ // Since we always do back buffering, check if we emulate front buffering
+ lpCtx->EmulateSingle =
+ (lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? FALSE : TRUE;
+#if 0 // Don't have to mimic MS OpenGL behavior for front-buffering (DaveM)
+ lpCtx->EmulateSingle |=
+ (lpPFD->dwFlags & PFD_SUPPORT_GDI) ? TRUE : FALSE;
+#endif
+
+ // Check for depth buffer
+ bDepthBuffer = (lpPFD->cDepthBits) ? GL_TRUE : GL_FALSE;
+
+ lpCtx->bDoubleBuffer = bDoubleBuffer;
+ lpCtx->bDepthBuffer = bDepthBuffer;
+
+ // Set the Fullscreen flag for the context.
+// lpCtx->bFullscreen = glb.bFullscreen;
+
+ // Obtain the dimensions of the rendering window
+ lpCtx->hDC = a; // Cache DC
+ lpCtx->hWnd = WindowFromDC(lpCtx->hDC);
+ // Check for non-window DC = memory DC ?
+ if (lpCtx->hWnd == NULL) {
+ // bitmap memory contexts are always single-buffered
+ lpCtx->EmulateSingle = TRUE;
+ bBogusWindow = TRUE;
+ ddlogPrintf(DDLOG_INFO, "Non-Window Memory Device Context");
+ if (GetClipBox(lpCtx->hDC, &lpCtx->rcScreenRect) == ERROR) {
+ ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglCreateContext\n");
+ SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
+ }
+ }
+ else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) {
+ bBogusWindow = TRUE;
+ ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglCreateContext\n");
+ SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
+ }
+ lpCtx->dwWidth = lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left;
+ lpCtx->dwHeight = lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top;
+
+ ddlogPrintf(DDLOG_INFO, "Input window %X: w=%i, h=%i",
+ lpCtx->hWnd, lpCtx->dwWidth, lpCtx->dwHeight);
+
+ // What if app only zeroes one dimension instead of both? (DaveM)
+ if ( (lpCtx->dwWidth == 0) || (lpCtx->dwHeight == 0) ) {
+ // Make the buffer size something sensible
+ lpCtx->dwWidth = 8;
+ lpCtx->dwHeight = 8;
+ }
+
+ // Set defaults
+ lpCtx->dwModeWidth = lpCtx->dwWidth;
+ lpCtx->dwModeHeight = lpCtx->dwHeight;
+/*
+ // Find best display mode for fullscreen
+ if (glb.bFullscreen || !glb.bPrimary) {
+ dglChooseDisplayMode(lpCtx);
+ }
+*/
+ // Misc initialisation
+ lpCtx->bCanRender = FALSE; // No rendering allowed yet
+ lpCtx->bSceneStarted = FALSE;
+ lpCtx->bFrameStarted = FALSE;
+
+ // Detect OS (specifically 'Windows 2000' or 'Windows XP')
+ DetectOS();
+
+ // NOTE: WinNT not supported
+ ddlogPrintf(DDLOG_INFO, "OS: %s", bHaveWin95 ? "Win9x" : (bHaveWin2K ? "Win2000/XP" : "Unsupported") );
+
+ // Test for Fullscreen
+ if (bHaveWin95) { // Problems with fullscreen on Win2K/XP
+ if ((GetSystemMetrics(SM_CXSCREEN) == lpCtx->dwWidth) &&
+ (GetSystemMetrics(SM_CYSCREEN) == lpCtx->dwHeight))
+ {
+ // Workaround for some apps that crash when going fullscreen.
+ //lpCtx->bFullscreen = TRUE;
+ }
+
+ }
+
+#ifdef _USE_GLD3_WGL
+ _gldDriver.CreateDrawable(lpCtx, glb.bDirectDrawPersistant, glb.bPersistantBuffers);
+#else
+ // Check if DirectDraw has already been created by original GLRC (DaveM)
+ if (glb.bDirectDrawPersistant && glb.bDirectDraw) {
+ lpCtx->lpDD4 = glb.lpDD4;
+ IDirectDraw4_AddRef(lpCtx->lpDD4);
+ goto SkipDirectDrawCreate;
+ }
+
+ // Create DirectDraw object
+ if (glb.bPrimary)
+ hResult = DirectDrawCreate(NULL, &lpCtx->lpDD1, NULL);
+ else {
+ // A non-primary device is to be used.
+ // Force context to be Fullscreen, secondary adaptors can not
+ // be used in a window.
+ hResult = DirectDrawCreate(&glb.ddGuid, &lpCtx->lpDD1, NULL);
+ lpCtx->bFullscreen = TRUE;
+ }
+ if (FAILED(hResult)) {
+ MessageBox(NULL, "Unable to initialize DirectDraw", "GLDirect", MB_OK);
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create DirectDraw interface", hResult);
+ nContextError = GLDERR_DDRAW;
+ goto return_with_error;
+ }
+
+ // Query for DX6 IDirectDraw4.
+ hResult = IDirectDraw_QueryInterface(lpCtx->lpDD1,
+ &IID_IDirectDraw4,
+ (void**)&lpCtx->lpDD4);
+ if (FAILED(hResult)) {
+ MessageBox(NULL, "GLDirect requires DirectX 6.0 or above", "GLDirect", MB_OK);
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create DirectDraw4 interface", hResult);
+ nContextError = GLDERR_DDRAW;
+ goto return_with_error;
+ }
+
+ // Cache DirectDraw interface for subsequent GLRCs
+ if (glb.bDirectDrawPersistant && !glb.bDirectDraw) {
+ glb.lpDD4 = lpCtx->lpDD4;
+ IDirectDraw4_AddRef(glb.lpDD4);
+ glb.bDirectDraw = TRUE;
+ }
+SkipDirectDrawCreate:
+
+ // Now we have a DD4 interface we can check for broken cards
+ dglTestForBrokenCards(lpCtx);
+
+ // Test if primary device can use flipping instead of blitting
+ ZeroMemory(&ddsd2DisplayMode, sizeof(ddsd2DisplayMode));
+ ddsd2DisplayMode.dwSize = sizeof(ddsd2DisplayMode);
+ hResult = IDirectDraw4_GetDisplayMode(
+ lpCtx->lpDD4,
+ &ddsd2DisplayMode);
+ if (SUCCEEDED(hResult)) {
+ if ( (lpCtx->dwWidth == ddsd2DisplayMode.dwWidth) &&
+ (lpCtx->dwHeight == ddsd2DisplayMode.dwHeight) ) {
+ // We have a fullscreen-size window
+ bFullScrnWin = TRUE;
+ // OK to use DirectDraw fullscreen mode ?
+ if (glb.bPrimary && !glb.bFullscreenBlit && !lpCtx->EmulateSingle && !glb.bDirectDrawPersistant) {
+ lpCtx->bFullscreen = TRUE;
+ ddlogMessage(DDLOG_INFO, "Primary upgraded to page flipping.\n");
+ }
+ }
+ // Cache the display mode dimensions
+ lpCtx->dwModeWidth = ddsd2DisplayMode.dwWidth;
+ lpCtx->dwModeHeight = ddsd2DisplayMode.dwHeight;
+ }
+
+ // Clamp the effective window dimensions to primary surface.
+ // We need to do this for D3D viewport dimensions even if wide
+ // surfaces are supported. This also is a good idea for handling
+ // whacked-out window dimensions passed for non-drawable windows
+ // like Solid Edge. (DaveM)
+ if (lpCtx->dwWidth > ddsd2DisplayMode.dwWidth)
+ lpCtx->dwWidth = ddsd2DisplayMode.dwWidth;
+ if (lpCtx->dwHeight > ddsd2DisplayMode.dwHeight)
+ lpCtx->dwHeight = ddsd2DisplayMode.dwHeight;
+
+ // Check for non-RGB desktop resolution
+ if (!lpCtx->bFullscreen && ddsd2DisplayMode.ddpfPixelFormat.dwRGBBitCount <= 8) {
+ ddlogPrintf(DDLOG_CRITICAL_OR_WARN, "Desktop color depth %d bpp not supported",
+ ddsd2DisplayMode.ddpfPixelFormat.dwRGBBitCount);
+ nContextError = GLDERR_BPP;
+ goto return_with_error;
+ }
+#endif // _USE_GLD3_WGL
+
+ ddlogPrintf(DDLOG_INFO, "Window: w=%i, h=%i (%s)",
+ lpCtx->dwWidth,
+ lpCtx->dwHeight,
+ lpCtx->bFullscreen ? "fullscreen" : "windowed");
+
+#ifndef _USE_GLD3_WGL
+ // Obtain ddraw caps
+ ZeroMemory(&lpCtx->ddCaps, sizeof(DDCAPS));
+ lpCtx->ddCaps.dwSize = sizeof(DDCAPS);
+ if (glb.bHardware) {
+ // Get HAL caps
+ IDirectDraw4_GetCaps(lpCtx->lpDD4, &lpCtx->ddCaps, NULL);
+ } else {
+ // Get HEL caps
+ IDirectDraw4_GetCaps(lpCtx->lpDD4, NULL, &lpCtx->ddCaps);
+ }
+
+ // If this flag is present then we can't default to Mesa
+ // SW rendering between BeginScene() and EndScene().
+ if (lpCtx->ddCaps.dwCaps2 & DDCAPS2_NO2DDURING3DSCENE) {
+ ddlogMessage(DDLOG_INFO,
+ "Warning : No 2D allowed during 3D scene.\n");
+ }
+
+ // Query for DX6 Direct3D3 interface
+ hResult = IDirectDraw4_QueryInterface(lpCtx->lpDD4,
+ &IID_IDirect3D3,
+ (void**)&lpCtx->lpD3D3);
+ if (FAILED(hResult)) {
+ MessageBox(NULL, "Unable to initialize Direct3D", "GLDirect", MB_OK);
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D interface", hResult);
+ nContextError = GLDERR_D3D;
+ goto return_with_error;
+ }
+
+ // Context creation
+ if (lpCtx->bFullscreen) {
+ // FULLSCREEN
+
+ // Disable warning popups when in fullscreen mode
+ ddlogWarnOption(FALSE);
+
+ // Have to release persistant primary surface if fullscreen mode
+ if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) {
+ RELEASE(glb.lpPrimary4);
+ glb.bDirectDrawPrimary = FALSE;
+ }
+
+ dwFlags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT;
+ if (glb.bFastFPU)
+ dwFlags |= DDSCL_FPUSETUP; // fast FPU setup optional (DaveM)
+ hResult = IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, lpCtx->hWnd, dwFlags);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to set Exclusive Fullscreen mode", hResult);
+ goto return_with_error;
+ }
+
+ hResult = IDirectDraw4_SetDisplayMode(lpCtx->lpDD4,
+ lpCtx->dwModeWidth,
+ lpCtx->dwModeHeight,
+ lpPFD->cColorBits,
+ 0,
+ 0);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "SetDisplayMode failed", hResult);
+ goto return_with_error;
+ }
+
+ // ** The display mode has changed, so dont use MessageBox! **
+
+ ZeroMemory(&ddsd2, sizeof(ddsd2));
+ ddsd2.dwSize = sizeof(ddsd2);
+
+ if (bDoubleBuffer) {
+ // Double buffered
+ // Primary surface
+ ddsd2.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+ ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
+ DDSCAPS_FLIP |
+ DDSCAPS_COMPLEX |
+ DDSCAPS_3DDEVICE |
+ dwMemoryType;
+ ddsd2.dwBackBufferCount = 1;
+
+ hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult);
+ nContextError = GLDERR_MEM;
+ goto return_with_error;
+ }
+
+ // Render target surface
+ ZeroMemory(&ddscaps2, sizeof(ddscaps2)); // Clear the entire struct.
+ ddscaps2.dwCaps = DDSCAPS_BACKBUFFER;
+ hResult = IDirectDrawSurface4_GetAttachedSurface(lpCtx->lpFront4, &ddscaps2, &lpCtx->lpBack4);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "GetAttachedSurface failed", hResult);
+ nContextError = GLDERR_MEM;
+ goto return_with_error;
+ }
+ } else {
+ // Single buffered
+ // Primary surface
+ ddsd2.dwFlags = DDSD_CAPS;
+ ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
+ //DDSCAPS_3DDEVICE |
+ dwMemoryType;
+
+ hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult);
+ nContextError = GLDERR_MEM;
+ goto return_with_error;
+ }
+
+ lpCtx->lpBack4 = NULL;
+ }
+ } else {
+ // WINDOWED
+
+ // OK to enable warning popups in windowed mode
+ ddlogWarnOption(glb.bMessageBoxWarnings);
+
+ dwFlags = DDSCL_NORMAL;
+ if (glb.bMultiThreaded)
+ dwFlags |= DDSCL_MULTITHREADED;
+ if (glb.bFastFPU)
+ dwFlags |= DDSCL_FPUSETUP; // fast FPU setup optional (DaveM)
+ hResult = IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4,
+ lpCtx->hWnd,
+ dwFlags);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to set Normal coop level", hResult);
+ goto return_with_error;
+ }
+ // Has Primary surface already been created for original GLRC ?
+ // Note this can only be applicable for windowed modes
+ if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) {
+ lpCtx->lpFront4 = glb.lpPrimary4;
+ IDirectDrawSurface4_AddRef(lpCtx->lpFront4);
+ // Update the window on the default clipper
+ IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper);
+ IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd);
+ IDirectDrawClipper_Release(lpddClipper);
+ goto SkipPrimaryCreate;
+ }
+
+ // Primary surface
+ ZeroMemory(&ddsd2, sizeof(ddsd2));
+ ddsd2.dwSize = sizeof(ddsd2);
+ ddsd2.dwFlags = DDSD_CAPS;
+ ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+ hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult);
+ nContextError = GLDERR_MEM;
+ goto return_with_error;
+ }
+
+ // Cache Primary surface for subsequent GLRCs
+ // Note this can only be applicable to subsequent windowed modes
+ if (glb.bDirectDrawPersistant && !glb.bDirectDrawPrimary) {
+ glb.lpPrimary4 = lpCtx->lpFront4;
+ IDirectDrawSurface4_AddRef(glb.lpPrimary4);
+ glb.bDirectDrawPrimary = TRUE;
+ }
+
+ // Clipper object
+ hResult = DirectDrawCreateClipper(0, &lpddClipper, NULL);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateClipper failed", hResult);
+ goto return_with_error;
+ }
+ hResult = IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd);
+ if (FAILED(hResult)) {
+ RELEASE(lpddClipper);
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "SetHWnd failed", hResult);
+ goto return_with_error;
+ }
+ hResult = IDirectDrawSurface4_SetClipper(lpCtx->lpFront4, lpddClipper);
+ RELEASE(lpddClipper); // We have finished with it.
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "SetClipper failed", hResult);
+ goto return_with_error;
+ }
+SkipPrimaryCreate:
+
+ if (bDoubleBuffer) {
+ // Render target surface
+ ZeroMemory(&ddsd2, sizeof(ddsd2));
+ ddsd2.dwSize = sizeof(ddsd2);
+ ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd2.dwWidth = lpCtx->dwWidth;
+ ddsd2.dwHeight = lpCtx->dwHeight;
+ ddsd2.ddsCaps.dwCaps = DDSCAPS_3DDEVICE |
+ DDSCAPS_OFFSCREENPLAIN |
+ dwMemoryType;
+
+ // Reserve the entire desktop size for persistant buffers option
+ if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) {
+ ddsd2.dwWidth = ddsd2DisplayMode.dwWidth;
+ ddsd2.dwHeight = ddsd2DisplayMode.dwHeight;
+ }
+ // Re-use original back buffer if persistant buffers exist
+ if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpBack4)
+ hResult = IDirectDrawSurface4_AddRef(lpCtx->lpBack4 = glb.lpBack4);
+ else
+ hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpBack4, NULL);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "Create Backbuffer failed", hResult);
+ nContextError = GLDERR_MEM;
+ goto return_with_error;
+ }
+ if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpBack4)
+ IDirectDrawSurface4_AddRef(glb.lpBack4 = lpCtx->lpBack4);
+ } else {
+ lpCtx->lpBack4 = NULL;
+ }
+ }
+
+ //
+ // Now create the Z-buffer
+ //
+ lpCtx->bStencil = FALSE; // Default to no stencil buffer
+ if (bDepthBuffer && (lpCtx->lpPF->iZBufferPF != -1)) {
+ // Get z-buffer dimensions from the render target
+ // Setup the surface desc for the z-buffer.
+ ZeroMemory(&ddsd2, sizeof(ddsd2));
+ ddsd2.dwSize = sizeof(ddsd2);
+ ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+ ddsd2.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | dwMemoryType;
+ ddsd2.dwWidth = lpCtx->dwWidth;
+ ddsd2.dwHeight = lpCtx->dwHeight;
+ memcpy(&ddsd2.ddpfPixelFormat,
+ &glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF],
+ sizeof(DDPIXELFORMAT) );
+
+ // Reserve the entire desktop size for persistant buffers option
+ if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) {
+ ddsd2.dwWidth = ddsd2DisplayMode.dwWidth;
+ ddsd2.dwHeight = ddsd2DisplayMode.dwHeight;
+ }
+
+ // Create a z-buffer
+ if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpDepth4)
+ hResult = IDirectDrawSurface4_AddRef(lpCtx->lpDepth4 = glb.lpDepth4);
+ else
+ hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpDepth4, NULL);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (ZBuffer) failed", hResult);
+ nContextError = GLDERR_MEM;
+ goto return_with_error;
+ }
+ if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpDepth4)
+ IDirectDrawSurface4_AddRef(glb.lpDepth4 = lpCtx->lpDepth4);
+ else if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpDepth4 && glb.lpBack4)
+ IDirectDrawSurface4_DeleteAttachedSurface(glb.lpBack4, 0, glb.lpDepth4);
+
+ // Attach Zbuffer to render target
+ TRY(IDirectDrawSurface4_AddAttachedSurface(
+ bDoubleBuffer ? lpCtx->lpBack4 : lpCtx->lpFront4,
+ lpCtx->lpDepth4),
+ "dglCreateContext: Attach Zbuffer");
+ if (glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwFlags & DDPF_STENCILBUFFER) {
+ lpCtx->bStencil = TRUE;
+ ddlogMessage(DDLOG_INFO, "Depth buffer has stencil\n");
+ }
+ }
+
+ // Clear all back buffers and Z-buffers in case of memory recycling.
+ ZeroMemory(&ddbltfx, sizeof(ddbltfx));
+ ddbltfx.dwSize = sizeof(ddbltfx);
+ IDirectDrawSurface4_Blt(lpCtx->lpBack4, NULL, NULL, NULL,
+ DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
+ if (lpCtx->lpDepth4)
+ IDirectDrawSurface4_Blt(lpCtx->lpDepth4, NULL, NULL, NULL,
+ DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
+
+ // Now that we have a Z-buffer we can create the 3D device
+ hResult = IDirect3D3_CreateDevice(lpCtx->lpD3D3,
+ &glb.d3dGuid,
+ bDoubleBuffer ? lpCtx->lpBack4 : lpCtx->lpFront4,
+ &lpCtx->lpDev3,
+ NULL);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D device", hResult);
+ nContextError = GLDERR_D3D;
+ goto return_with_error;
+ }
+
+ // We must do this as soon as the device is created
+ dglInitStateCaches(lpCtx);
+
+ // Obtain the D3D Device Description
+ D3DHWDevDesc.dwSize = D3DHELDevDesc.dwSize = sizeof(D3DDEVICEDESC);
+ TRY(IDirect3DDevice3_GetCaps(lpCtx->lpDev3,
+ &D3DHWDevDesc,
+ &D3DHELDevDesc),
+ "dglCreateContext: GetCaps failed");
+
+ // Choose the relevant description and cache it in the context.
+ // We will use this description later for caps checking
+ memcpy( &lpCtx->D3DDevDesc,
+ glb.bHardware ? &D3DHWDevDesc : &D3DHELDevDesc,
+ sizeof(D3DDEVICEDESC));
+
+ // Now we can examine the texture formats
+ if (!dglBuildTextureFormatList(lpCtx->lpDev3)) {
+ ddlogMessage(DDLOG_CRITICAL_OR_WARN, "dglBuildTextureFormatList failed\n");
+ goto return_with_error;
+ }
+
+ // Get the pixel format of the back buffer
+ lpCtx->ddpfRender.dwSize = sizeof(lpCtx->ddpfRender);
+ if (bDoubleBuffer)
+ hResult = IDirectDrawSurface4_GetPixelFormat(
+ lpCtx->lpBack4,
+ &lpCtx->ddpfRender);
+ else
+ hResult = IDirectDrawSurface4_GetPixelFormat(
+ lpCtx->lpFront4,
+ &lpCtx->ddpfRender);
+
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "GetPixelFormat failed", hResult);
+ goto return_with_error;
+ }
+ // Find a pixel packing function suitable for this surface
+ pxClassifyPixelFormat(&lpCtx->ddpfRender,
+ &lpCtx->fnPackFunc,
+ &lpCtx->fnUnpackFunc,
+ &lpCtx->fnPackSpanFunc);
+
+ // Viewport
+ hResult = IDirect3D3_CreateViewport(lpCtx->lpD3D3, &lpCtx->lpViewport3, NULL);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateViewport failed", hResult);
+ goto return_with_error;
+ }
+
+ hResult = IDirect3DDevice3_AddViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "AddViewport failed", hResult);
+ goto return_with_error;
+ }
+
+ // Initialise the viewport
+ // Note screen coordinates are used for viewport clipping since D3D
+ // transform operations are not used in the GLD CAD driver. (DaveM)
+ inv_aspect = (float)lpCtx->dwHeight/(float)lpCtx->dwWidth;
+
+ lpCtx->d3dViewport.dwSize = sizeof(lpCtx->d3dViewport);
+ lpCtx->d3dViewport.dwX = 0;
+ lpCtx->d3dViewport.dwY = 0;
+ lpCtx->d3dViewport.dwWidth = lpCtx->dwWidth;
+ lpCtx->d3dViewport.dwHeight = lpCtx->dwHeight;
+ lpCtx->d3dViewport.dvClipX = 0; // -1.0f;
+ lpCtx->d3dViewport.dvClipY = 0; // inv_aspect;
+ lpCtx->d3dViewport.dvClipWidth = lpCtx->dwWidth; // 2.0f;
+ lpCtx->d3dViewport.dvClipHeight = lpCtx->dwHeight; // 2.0f * inv_aspect;
+ lpCtx->d3dViewport.dvMinZ = 0.0f;
+ lpCtx->d3dViewport.dvMaxZ = 1.0f;
+ TRY(IDirect3DViewport3_SetViewport2(lpCtx->lpViewport3, &lpCtx->d3dViewport), "dglCreateContext: SetViewport2");
+
+ hResult = IDirect3DDevice3_SetCurrentViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "SetCurrentViewport failed", hResult);
+ goto return_with_error;
+ }
+
+ lpCtx->dwBPP = lpPFD->cColorBits;
+ lpCtx->iZBufferPF = lpCtx->lpPF->iZBufferPF;
+
+ // Set last texture to NULL
+ for (i=0; i<MAX_TEXTURE_UNITS; i++) {
+ lpCtx->ColorOp[i] = D3DTOP_DISABLE;
+ lpCtx->AlphaOp[i] = D3DTOP_DISABLE;
+ lpCtx->tObj[i] = NULL;
+ }
+
+ // Default to perspective correct texture mapping
+ dglSetRenderState(lpCtx, D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, "TexturePersp");
+
+ // Set the default culling mode
+ lpCtx->cullmode = D3DCULL_NONE;
+ dglSetRenderState(lpCtx, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE, "CullMode");
+
+ // Disable specular
+ dglSetRenderState(lpCtx, D3DRENDERSTATE_SPECULARENABLE, FALSE, "SpecularEnable");
+ // Disable subpixel correction
+// dglSetRenderState(lpCtx, D3DRENDERSTATE_SUBPIXEL, FALSE, "SubpixelEnable");
+ // Disable dithering
+ dglSetRenderState(lpCtx, D3DRENDERSTATE_DITHERENABLE, FALSE, "DitherEnable");
+
+ // Initialise the primitive caches
+// lpCtx->dwNextLineVert = 0;
+// lpCtx->dwNextTriVert = 0;
+
+ // Init the global texture palette
+ lpCtx->lpGlobalPalette = NULL;
+
+ // Init the HW/SW usage counters
+// lpCtx->dwHWUsageCount = lpCtx->dwSWUsageCount = 0L;
+
+ //
+ // Create two D3D vertex buffers.
+ // One will hold the pre-transformed data with the other one
+ // being used to hold the post-transformed & clipped verts.
+ //
+#if 0 // never used (DaveM)
+ vbufdesc.dwSize = sizeof(D3DVERTEXBUFFERDESC);
+ vbufdesc.dwCaps = D3DVBCAPS_WRITEONLY;
+ if (glb.bHardware == FALSE)
+ vbufdesc.dwCaps = D3DVBCAPS_SYSTEMMEMORY;
+ vbufdesc.dwNumVertices = 32768; // For the time being
+
+ // Source vertex buffer
+ vbufdesc.dwFVF = DGL_LVERTEX;
+ hResult = IDirect3D3_CreateVertexBuffer(lpCtx->lpD3D3, &vbufdesc, &lpCtx->m_vbuf, 0, NULL);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateVertexBuffer(src) failed", hResult);
+ goto return_with_error;
+ }
+
+ // Destination vertex buffer
+ vbufdesc.dwFVF = (glb.bMultitexture == FALSE) ? D3DFVF_TLVERTEX : (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX2);
+ hResult = IDirect3D3_CreateVertexBuffer(lpCtx->lpD3D3, &vbufdesc, &lpCtx->m_pvbuf, 0, NULL);
+ if(FAILED(hResult)) {
+ ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateVertexBuffer(dst) failed", hResult);
+ goto return_with_error;
+ }
+#endif
+
+#endif _USE_GLD3_WGL
+
+ //
+ // Now create the Mesa context
+ //
+
+ // Create the Mesa visual
+ if (lpPFD->cDepthBits)
+ dwDepthBits = 16;
+ if (lpPFD->cStencilBits)
+ dwStencilBits = 8;
+ if (lpPFD->cAlphaBits) {
+ dwAlphaBits = 8;
+ bAlphaSW = GL_TRUE;
+ }
+ if (lpPFD->dwFlags & PFD_DOUBLEBUFFER)
+ bDouble = GL_TRUE;
+// lpCtx->EmulateSingle =
+// (lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? FALSE : TRUE;
+
+#ifdef _USE_GLD3_WGL
+ lpCtx->glVis = _mesa_create_visual(
+ bDouble, /* double buffer */
+ GL_FALSE, // stereo
+ lpPFD->cRedBits,
+ lpPFD->cGreenBits,
+ lpPFD->cBlueBits,
+ dwAlphaBits,
+ dwDepthBits,
+ dwStencilBits,
+ lpPFD->cAccumRedBits, // accum bits
+ lpPFD->cAccumGreenBits, // accum bits
+ lpPFD->cAccumBlueBits, // accum bits
+ lpPFD->cAccumAlphaBits, // accum alpha bits
+ 1 // num samples
+ );
+#else // _USE_GLD3_WGL
+ lpCtx->glVis = (*mesaFuncs.gl_create_visual)(
+ GL_TRUE, // RGB mode
+ bAlphaSW, // Is an alpha buffer required?
+ bDouble, // Is an double-buffering required?
+ GL_FALSE, // stereo
+ dwDepthBits, // depth_size
+ dwStencilBits, // stencil_size
+ lpPFD->cAccumBits, // accum_size
+ 0, // colour-index bits
+ lpPFD->cRedBits, // Red bit count
+ lpPFD->cGreenBits, // Green bit count
+ lpPFD->cBlueBits, // Blue bit count
+ dwAlphaBits // Alpha bit count
+ );
+#endif // _USE_GLD3_WGL
+
+ if (lpCtx->glVis == NULL) {
+ ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_visual failed\n");
+ goto return_with_error;
+ }
+
+#ifdef _USE_GLD3_WGL
+ 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)(
+ lpCtx->glVis, // Mesa visual
+ NULL, // share list context
+ (void *)lpCtx, // Pointer to our driver context
+ GL_TRUE // Direct context flag
+ );
+#endif // _USE_GLD3_WGL
+
+ if (lpCtx->glCtx == NULL) {
+ ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_context failed\n");
+ goto return_with_error;
+ }
+
+ // Create the Mesa framebuffer
+#ifdef _USE_GLD3_WGL
+ lpCtx->glBuffer = _mesa_create_framebuffer(
+ lpCtx->glVis,
+ lpCtx->glVis->depthBits > 0,
+ lpCtx->glVis->stencilBits > 0,
+ lpCtx->glVis->accumRedBits > 0,
+ GL_FALSE //swalpha
+ );
+#else
+ lpCtx->glBuffer = (*mesaFuncs.gl_create_framebuffer)(lpCtx->glVis);
+#endif // _USE_GLD3_WGL
+
+ if (lpCtx->glBuffer == NULL) {
+ ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_framebuffer failed\n");
+ goto return_with_error;
+ }
+
+#ifdef _USE_GLD3_WGL
+ // Init Mesa internals
+ _swrast_CreateContext( lpCtx->glCtx );
+ _vbo_CreateContext( lpCtx->glCtx );
+ _tnl_CreateContext( lpCtx->glCtx );
+ _swsetup_CreateContext( lpCtx->glCtx );
+
+ _gldDriver.InitialiseMesa(lpCtx);
+
+ lpCtx->glCtx->imports.warning = _gld_mesa_warning;
+ lpCtx->glCtx->imports.fatal = _gld_mesa_fatal;
+
+#else
+ // Tell Mesa how many texture stages we have
+ glb.wMaxSimultaneousTextures = lpCtx->D3DDevDesc.wMaxSimultaneousTextures;
+ // Only use as many Units as the spec requires
+ if (glb.wMaxSimultaneousTextures > MAX_TEXTURE_UNITS)
+ glb.wMaxSimultaneousTextures = MAX_TEXTURE_UNITS;
+ lpCtx->glCtx->Const.MaxTextureUnits = glb.wMaxSimultaneousTextures;
+ ddlogPrintf(DDLOG_INFO, "Texture stages : %d", glb.wMaxSimultaneousTextures);
+
+ // Set the max texture size.
+ // NOTE: clamped to a max of 1024 for extra performance!
+ lpCtx->dwMaxTextureSize = (lpCtx->D3DDevDesc.dwMaxTextureWidth <= 1024) ? lpCtx->D3DDevDesc.dwMaxTextureWidth : 1024;
+
+// Texture resize takes place elsewhere. KH
+// NOTE: This was added to workaround an issue with the Intel app.
+#if 0
+ lpCtx->glCtx->Const.MaxTextureSize = lpCtx->dwMaxTextureSize;
+#else
+ lpCtx->glCtx->Const.MaxTextureSize = 1024;
+#endif
+ lpCtx->glCtx->Const.MaxDrawBuffers = 1;
+
+ // Setup the Display Driver pointers
+ dglSetupDDPointers(lpCtx->glCtx);
+
+ // Initialise all the Direct3D renderstates
+ dglInitStateD3D(lpCtx->glCtx);
+
+#if 0
+ // Signal a reload of texture state on next glBegin
+ lpCtx->m_texHandleValid = FALSE;
+ lpCtx->m_mtex = FALSE;
+ lpCtx->m_texturing = FALSE;
+#else
+ // Set default texture unit state
+// dglSetTexture(lpCtx, 0, NULL);
+// dglSetTexture(lpCtx, 1, NULL);
+#endif
+
+ //
+ // Set the global texture palette to default values.
+ //
+
+ // Clear the entire palette
+ ZeroMemory(ppe, sizeof(PALETTEENTRY) * 256);
+
+ // Fill the palette with a default colour.
+ // A garish colour is used to catch bugs. Here Magenta is used.
+ for (i=0; i < 256; i++) {
+ ppe[i].peRed = 255;
+ ppe[i].peGreen = 0;
+ ppe[i].peBlue = 255;
+ }
+
+ RELEASE(lpCtx->lpGlobalPalette);
+
+ if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpGlobalPalette)
+ hResult = IDirectDrawPalette_AddRef(lpCtx->lpGlobalPalette = glb.lpGlobalPalette);
+ else
+ hResult = IDirectDraw4_CreatePalette(
+ lpCtx->lpDD4,
+ DDPCAPS_INITIALIZE | DDPCAPS_8BIT | DDPCAPS_ALLOW256,
+ ppe,
+ &(lpCtx->lpGlobalPalette),
+ NULL);
+ if (FAILED(hResult)) {
+ ddlogError(DDLOG_ERROR, "Default CreatePalette failed\n", hResult);
+ lpCtx->lpGlobalPalette = NULL;
+ goto return_with_error;
+ }
+ if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpGlobalPalette)
+ IDirectDrawPalette_AddRef(glb.lpGlobalPalette = lpCtx->lpGlobalPalette);
+
+#endif // _USE_GLD3_WGL
+
+ // ** If we have made it to here then we can enable rendering **
+ lpCtx->bCanRender = TRUE;
+
+// ddlogMessage(DDLOG_SYSTEM, "dglCreateContextBuffers succeded\n");
+
+#ifdef GLD_THREADS
+ // Release serialized access
+ if (glb.bMultiThreaded)
+ LeaveCriticalSection(&CriticalSection);
+#endif
+
+ return TRUE;
+
+return_with_error:
+ // Clean up before returning.
+ // This is critical for secondary devices.
+
+ lpCtx->bCanRender = FALSE;
+
+#ifdef _USE_GLD3_WGL
+ // Destroy the Mesa context
+ if (lpCtx->glBuffer)
+ _mesa_destroy_framebuffer(lpCtx->glBuffer);
+ if (lpCtx->glCtx)
+ _mesa_destroy_context(lpCtx->glCtx);
+ if (lpCtx->glVis)
+ _mesa_destroy_visual(lpCtx->glVis);
+
+ // Destroy driver data
+ _gldDriver.DestroyDrawable(lpCtx);
+#else
+ // Destroy the Mesa context
+ if (lpCtx->glBuffer)
+ (*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer);
+ if (lpCtx->glCtx)
+ (*mesaFuncs.gl_destroy_context)(lpCtx->glCtx);
+ if (lpCtx->glVis)
+ (*mesaFuncs.gl_destroy_visual)(lpCtx->glVis);
+
+ RELEASE(lpCtx->m_pvbuf); // Release D3D vertex buffer
+ RELEASE(lpCtx->m_vbuf); // Release D3D vertex buffer
+
+ if (lpCtx->lpViewport3) {
+ if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
+ RELEASE(lpCtx->lpViewport3);
+ lpCtx->lpViewport3 = NULL;
+ }
+
+ RELEASE(lpCtx->lpDev3);
+ if (lpCtx->lpDepth4) {
+ if (lpCtx->lpBack4)
+ IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4);
+ else
+ IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4);
+ RELEASE(lpCtx->lpDepth4);
+ lpCtx->lpDepth4 = NULL;
+ }
+ RELEASE(lpCtx->lpBack4);
+ RELEASE(lpCtx->lpFront4);
+ else
+ if (lpCtx->bFullscreen) {
+ IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4);
+ IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL);
+ }
+ RELEASE(lpCtx->lpD3D3);
+ RELEASE(lpCtx->lpDD4);
+ RELEASE(lpCtx->lpDD1);
+#endif // _USE_GLD3_WGL
+
+ lpCtx->bAllocated = FALSE;
+
+#ifdef GLD_THREADS
+ // Release serialized access
+ if (glb.bMultiThreaded)
+ LeaveCriticalSection(&CriticalSection);
+#endif
+
+ return FALSE;
+
+#undef DDLOG_CRITICAL_OR_WARN
+}
+
+// ***********************************************************************
+
+HGLRC dglCreateContext(
+ HDC a,
+ const DGL_pixelFormat *lpPF)
+{
+ int i;
+ HGLRC hGLRC;
+ DGL_ctx* lpCtx;
+ static BOOL bWarnOnce = TRUE;
+ DWORD dwThreadId = GetCurrentThreadId();
+ char szMsg[256];
+ HWND hWnd;
+ LONG lpfnWndProc;
+
+ // Validate license
+ if (!dglValidate())
+ return NULL;
+
+ // Is context state ready ?
+ if (!bContextReady)
+ return NULL;
+
+ ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext for HDC=%X, ThreadId=%X", a, dwThreadId);
+
+ // Find next free context.
+ // Also ensure that only one Fullscreen context is created at any one time.
+ hGLRC = 0; // Default to Not Found
+ for (i=0; i<DGL_MAX_CONTEXTS; i++) {
+ if (ctxlist[i].bAllocated) {
+ if (/*glb.bFullscreen && */ctxlist[i].bFullscreen)
+ break;
+ } else {
+ hGLRC = (HGLRC)(i+1);
+ break;
+ }
+ }
+
+ // Bail if no GLRC was found
+ if (!hGLRC)
+ return NULL;
+
+ // Set the context pointer
+ lpCtx = dglGetContextAddress(hGLRC);
+ // Make sure that context is zeroed before we do anything.
+ // MFC and C++ apps call wglCreateContext() and wglDeleteContext() multiple times,
+ // even though only one context is ever used by the app, so keep it clean. (DaveM)
+ ZeroMemory(lpCtx, sizeof(DGL_ctx));
+ lpCtx->bAllocated = TRUE;
+ // Flag that buffers need creating on next wglMakeCurrent call.
+ lpCtx->bHasBeenCurrent = FALSE;
+ lpCtx->lpPF = (DGL_pixelFormat *)lpPF; // cache pixel format
+ lpCtx->bCanRender = FALSE;
+
+ // Create all the internal resources here, not in dglMakeCurrent().
+ // We do a re-size check in dglMakeCurrent in case of re-allocations. (DaveM)
+ // We now try context allocations twice, first with video memory,
+ // then again with system memory. This is similar to technique
+ // used for dglWglResizeBuffers(). (DaveM)
+ if (lpCtx->bHasBeenCurrent == FALSE) {
+ if (!dglCreateContextBuffers(a, lpCtx, FALSE)) {
+ if (glb.bMessageBoxWarnings && bWarnOnce && dwLogging) {
+ bWarnOnce = FALSE;
+ switch (nContextError) {
+ case GLDERR_DDRAW: strcpy(szMsg, szDDrawWarning); break;
+ case GLDERR_D3D: strcpy(szMsg, szD3DWarning); break;
+ case GLDERR_MEM: strcpy(szMsg, szResourceWarning); break;
+ case GLDERR_BPP: strcpy(szMsg, szBPPWarning); break;
+ default: strcpy(szMsg, "");
+ }
+ if (strlen(szMsg))
+ MessageBox(NULL, szMsg, "GLDirect", MB_OK | MB_ICONWARNING);
+ }
+ // Only need to try again if memory error
+ if (nContextError == GLDERR_MEM) {
+ ddlogPrintf(DDLOG_WARN, "dglCreateContext failed 1st time with video memory");
+ }
+ else {
+ ddlogPrintf(DDLOG_ERROR, "dglCreateContext failed");
+ return NULL;
+ }
+ }
+ }
+
+ // Now that we have a hWnd, we can intercept the WindowProc.
+ hWnd = lpCtx->hWnd;
+ if (hWnd) {
+ // Only hook individual window handler once if not hooked before.
+ lpfnWndProc = GetWindowLong(hWnd, GWL_WNDPROC);
+ if (lpfnWndProc != (LONG)dglWndProc) {
+ lpCtx->lpfnWndProc = lpfnWndProc;
+ SetWindowLong(hWnd, GWL_WNDPROC, (LONG)dglWndProc);
+ }
+ // Find the parent window of the app too.
+ if (glb.hWndActive == NULL) {
+ while (hWnd != NULL) {
+ glb.hWndActive = hWnd;
+ hWnd = GetParent(hWnd);
+ }
+ // Hook the parent window too.
+ lpfnWndProc = GetWindowLong(glb.hWndActive, GWL_WNDPROC);
+ if (glb.hWndActive == lpCtx->hWnd)
+ glb.lpfnWndProc = lpCtx->lpfnWndProc;
+ else if (lpfnWndProc != (LONG)dglWndProc)
+ glb.lpfnWndProc = lpfnWndProc;
+ if (glb.lpfnWndProc)
+ SetWindowLong(glb.hWndActive, GWL_WNDPROC, (LONG)dglWndProc);
+ }
+ }
+
+ ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext succeeded for HGLRC=%d", (int)hGLRC);
+
+ return hGLRC;
+}
+
+// ***********************************************************************
+// Make a DirectGL context current
+// Used by wgl functions and dgl functions
+BOOL dglMakeCurrent(
+ HDC a,
+ HGLRC b)
+{
+ int context;
+ DGL_ctx* lpCtx;
+ HWND hWnd;
+ BOOL bNeedResize = FALSE;
+ BOOL bWindowChanged, bContextChanged;
+ LPDIRECTDRAWCLIPPER lpddClipper;
+ DWORD dwThreadId = GetCurrentThreadId();
+ LONG lpfnWndProc;
+
+ // Validate license
+ if (!dglValidate())
+ return FALSE;
+
+ // Is context state ready ?
+ if (!bContextReady)
+ return FALSE;
+
+ context = (int)b; // This is as a result of STRICT!
+ ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: HDC=%X, HGLRC=%d, ThreadId=%X", a, context, dwThreadId);
+
+ // If the HGLRC is NULL then make no context current;
+ // Ditto if the HDC is NULL either. (DaveM)
+ if (context == 0 || a == 0) {
+ // Corresponding Mesa operation
+#ifdef _USE_GLD3_WGL
+ _mesa_make_current(NULL, NULL);
+#else
+ (*mesaFuncs.gl_make_current)(NULL, NULL);
+#endif
+ dglSetCurrentContext(0);
+ return TRUE;
+ }
+
+ // Make sure the HGLRC is in range
+ if ((context > DGL_MAX_CONTEXTS) || (context < 0)) {
+ ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: HGLRC out of range\n");
+ return FALSE;
+ }
+
+ // Find address of context and make sure that it has been allocated
+ lpCtx = dglGetContextAddress(b);
+ if (!lpCtx->bAllocated) {
+ ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: Context not allocated\n");
+// return FALSE;
+ return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH
+ }
+
+#ifdef GLD_THREADS
+ // Serialize access to DirectDraw or DDS operations
+ if (glb.bMultiThreaded)
+ EnterCriticalSection(&CriticalSection);
+#endif
+
+ // Check if window has changed
+ hWnd = (a != lpCtx->hDC) ? WindowFromDC(a) : lpCtx->hWnd;
+ bWindowChanged = (hWnd != lpCtx->hWnd) ? TRUE : FALSE;
+ bContextChanged = (b != dglGetCurrentContext()) ? TRUE : FALSE;
+
+ // If the window has changed, make sure the clipper is updated. (DaveM)
+ if (glb.bDirectDrawPersistant && !lpCtx->bFullscreen && (bWindowChanged || bContextChanged)) {
+ lpCtx->hWnd = hWnd;
+#ifndef _USE_GLD3_WGL
+ IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper);
+ IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd);
+ IDirectDrawClipper_Release(lpddClipper);
+#endif // _USE_GLD3_WGL
+ }
+
+ // Make sure hDC and hWnd is current. (DaveM)
+ // Obtain the dimensions of the rendering window
+ lpCtx->hDC = a; // Cache DC
+ lpCtx->hWnd = hWnd;
+ hWndLastActive = hWnd;
+
+ // Check for non-window DC = memory DC ?
+ if (hWnd == NULL) {
+ if (GetClipBox(a, &lpCtx->rcScreenRect) == ERROR) {
+ ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglMakeCurrent\n");
+ SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
+ }
+ }
+ else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) {
+ ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglMakeCurrent\n");
+ SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
+ }
+ // Check if buffers need to be re-sized;
+ // If so, wait until Mesa GL stuff is setup before re-sizing;
+ if (lpCtx->dwWidth != lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left ||
+ lpCtx->dwHeight != lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top)
+ bNeedResize = TRUE;
+
+ // Now we can update our globals
+ dglSetCurrentContext(b);
+
+ // Corresponding Mesa operation
+#ifdef _USE_GLD3_WGL
+ _mesa_make_current(lpCtx->glCtx, lpCtx->glBuffer);
+ lpCtx->glCtx->Driver.UpdateState(lpCtx->glCtx, _NEW_ALL);
+ if (bNeedResize) {
+ // Resize buffers (Note Mesa GL needs to be setup beforehand);
+ // Resize Mesa internal buffer too via glViewport() command,
+ // which subsequently calls dglWglResizeBuffers() too.
+ lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
+ lpCtx->bHasBeenCurrent = TRUE;
+ }
+#else
+ (*mesaFuncs.gl_make_current)(lpCtx->glCtx, lpCtx->glBuffer);
+
+ dglSetupDDPointers(lpCtx->glCtx);
+
+ // Insure DirectDraw surfaces fit current window DC
+ if (bNeedResize) {
+ // Resize buffers (Note Mesa GL needs to be setup beforehand);
+ // Resize Mesa internal buffer too via glViewport() command,
+ // which subsequently calls dglWglResizeBuffers() too.
+ (*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
+ lpCtx->bHasBeenCurrent = TRUE;
+ }
+#endif // _USE_GLD3_WGL
+ ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: width = %d, height = %d", lpCtx->dwWidth, lpCtx->dwHeight);
+
+ // We have to clear D3D back buffer and render state if emulated front buffering
+ // for different window (but not context) like in Solid Edge.
+ if (glb.bDirectDrawPersistant && glb.bPersistantBuffers
+ && (bWindowChanged /* || bContextChanged */) && lpCtx->EmulateSingle) {
+#ifdef _USE_GLD3_WGL
+// IDirect3DDevice8_EndScene(lpCtx->pDev);
+// lpCtx->bSceneStarted = FALSE;
+ lpCtx->glCtx->Driver.Clear(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
+ GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
+#else
+ IDirect3DDevice3_EndScene(lpCtx->lpDev3);
+ lpCtx->bSceneStarted = FALSE;
+ dglClearD3D(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
+ GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
+#endif // _USE_GLD3_WGL
+ }
+
+ // The first time we call MakeCurrent we set the initial viewport size
+ if (lpCtx->bHasBeenCurrent == FALSE)
+#ifdef _USE_GLD3_WGL
+ lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
+#else
+ (*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
+#endif // _USE_GLD3_WGL
+ lpCtx->bHasBeenCurrent = TRUE;
+
+#ifdef GLD_THREADS
+ // Release serialized access
+ if (glb.bMultiThreaded)
+ LeaveCriticalSection(&CriticalSection);
+#endif
+
+ return TRUE;
+}
+
+// ***********************************************************************
+
+BOOL dglDeleteContext(
+ HGLRC a)
+{
+ DGL_ctx* lpCtx;
+ DWORD dwThreadId = GetCurrentThreadId();
+ char argstr[256];
+
+#if 0 // We have enough trouble throwing exceptions as it is... (DaveM)
+ // Validate license
+ if (!dglValidate())
+ return FALSE;
+#endif
+
+ // Is context state ready ?
+ if (!bContextReady)
+ return FALSE;
+
+ ddlogPrintf(DDLOG_SYSTEM, "dglDeleteContext: Deleting context HGLRC=%d, ThreadId=%X", (int)a, dwThreadId);
+
+ // Make sure the HGLRC is in range
+ if (((int) a> DGL_MAX_CONTEXTS) || ((int)a < 0)) {
+ ddlogMessage(DDLOG_ERROR, "dglDeleteCurrent: HGLRC out of range\n");
+ return FALSE;
+ }
+
+ // Make sure context is valid
+ lpCtx = dglGetContextAddress(a);
+ if (!lpCtx->bAllocated) {
+ ddlogPrintf(DDLOG_WARN, "Tried to delete unallocated context HGLRC=%d", (int)a);
+// return FALSE;
+ return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH
+ }
+
+ // Make sure context is de-activated
+ if (a == dglGetCurrentContext()) {
+ ddlogPrintf(DDLOG_WARN, "dglDeleteContext: context HGLRC=%d still active", (int)a);
+ dglMakeCurrent(NULL, NULL);
+ }
+
+#ifdef GLD_THREADS
+ // Serialize access to DirectDraw or DDS operations
+ if (glb.bMultiThreaded)
+ EnterCriticalSection(&CriticalSection);
+#endif
+
+ // We are about to destroy all Direct3D objects.
+ // Therefore we must disable rendering
+ lpCtx->bCanRender = FALSE;
+
+ // This exception handler was installed to catch some
+ // particularly nasty apps. Console apps that call exit()
+ // fall into this catagory (i.e. Win32 Glut).
+
+ // VC cannot successfully implement multiple exception handlers
+ // if more than one exception occurs. Therefore reverting back to
+ // single exception handler as Keith originally had it. (DaveM)
+
+#define WARN_MESSAGE(p) strcpy(argstr, (#p));
+#define SAFE_RELEASE(p) WARN_MESSAGE(p); RELEASE(p);
+
+__try {
+#ifdef _USE_GLD3_WGL
+ WARN_MESSAGE(gl_destroy_framebuffer);
+ if (lpCtx->glBuffer)
+ _mesa_destroy_framebuffer(lpCtx->glBuffer);
+ WARN_MESSAGE(gl_destroy_context);
+ if (lpCtx->glCtx)
+ _mesa_destroy_context(lpCtx->glCtx);
+ WARN_MESSAGE(gl_destroy_visual);
+ if (lpCtx->glVis)
+ _mesa_destroy_visual(lpCtx->glVis);
+
+ _gldDriver.DestroyDrawable(lpCtx);
+#else
+ // Destroy the Mesa context
+ WARN_MESSAGE(gl_destroy_framebuffer);
+ if (lpCtx->glBuffer)
+ (*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer);
+ WARN_MESSAGE(gl_destroy_context);
+ if (lpCtx->glCtx)
+ (*mesaFuncs.gl_destroy_context)(lpCtx->glCtx);
+ WARN_MESSAGE(gl_destroy_visual);
+ if (lpCtx->glVis)
+ (*mesaFuncs.gl_destroy_visual)(lpCtx->glVis);
+
+ SAFE_RELEASE(lpCtx->m_pvbuf); // release D3D vertex buffer
+ SAFE_RELEASE(lpCtx->m_vbuf); // release D3D vertex buffer
+
+ // Delete the global palette
+ SAFE_RELEASE(lpCtx->lpGlobalPalette);
+
+ // Clean up.
+ if (lpCtx->lpViewport3) {
+ if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
+ SAFE_RELEASE(lpCtx->lpViewport3);
+ lpCtx->lpViewport3 = NULL;
+ }
+
+ SAFE_RELEASE(lpCtx->lpDev3);
+ if (lpCtx->lpDepth4) {
+ if (lpCtx->lpBack4)
+ IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4);
+ else
+ IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4);
+ SAFE_RELEASE(lpCtx->lpDepth4);
+ lpCtx->lpDepth4 = NULL;
+ }
+ SAFE_RELEASE(lpCtx->lpBack4);
+ SAFE_RELEASE(lpCtx->lpFront4);
+ if (lpCtx->bFullscreen) {
+ IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4);
+ IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL);
+ }
+ SAFE_RELEASE(lpCtx->lpD3D3);
+ SAFE_RELEASE(lpCtx->lpDD4);
+ SAFE_RELEASE(lpCtx->lpDD1);
+#endif // _ULSE_GLD3_WGL
+
+}
+__except(EXCEPTION_EXECUTE_HANDLER) {
+ ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContext: %s", argstr);
+}
+
+ // Restore the window message handler because this context may be used
+ // again by another window with a *different* message handler. (DaveM)
+ if (lpCtx->lpfnWndProc) {
+ SetWindowLong(lpCtx->hWnd, GWL_WNDPROC, (LONG)lpCtx->lpfnWndProc);
+ lpCtx->lpfnWndProc = (LONG)NULL;
+ }
+
+ lpCtx->bAllocated = FALSE; // This context is now free for use
+
+#ifdef GLD_THREADS
+ // Release serialized access
+ if (glb.bMultiThreaded)
+ LeaveCriticalSection(&CriticalSection);
+#endif
+
+ return TRUE;
+}
+
+// ***********************************************************************
+
+BOOL dglSwapBuffers(
+ HDC hDC)
+{
+ RECT rSrcRect; // Source rectangle
+ RECT rDstRect; // Destination rectangle
+ POINT pt;
+ HRESULT hResult;
+
+ DDBLTFX bltFX;
+ DWORD dwBlitFlags;
+ DDBLTFX *lpBltFX;
+
+// DWORD dwThreadId = GetCurrentThreadId();
+ HGLRC hGLRC = dglGetCurrentContext();
+ DGL_ctx *lpCtx = dglGetContextAddress(hGLRC);
+ HWND hWnd;
+
+ HDC hDCAux; // for memory DC
+ int x,y,w,h; // for memory DC BitBlt
+
+#if 0 // Perhaps not a good idea. Called too often. KH
+ // Validate license
+ if (!dglValidate())
+ return FALSE;
+#endif
+
+ if (!lpCtx) {
+ return TRUE; //FALSE; // No current context
+ }
+
+ if (!lpCtx->bCanRender) {
+ // Don't return false else some apps will bail.
+ return TRUE;
+ }
+
+ hWnd = lpCtx->hWnd;
+ if (hDC != lpCtx->hDC) {
+ ddlogPrintf(DDLOG_WARN, "dglSwapBuffers: HDC=%X does not match HDC=%X for HGLRC=%d", hDC, lpCtx->hDC, hGLRC);
+ hWnd = WindowFromDC(hDC);
+ }
+
+#ifndef _USE_GLD3_WGL
+ // Ensure that the surfaces exist before we tell
+ // the device to render to them.
+ IDirectDraw4_RestoreAllSurfaces(lpCtx->lpDD4);
+
+ // Make sure that the vertex caches have been emptied
+// dglStateChange(lpCtx);
+
+ // Some OpenGL programs don't issue a glFinish - check for it here.
+ if (lpCtx->bSceneStarted) {
+ IDirect3DDevice3_EndScene(lpCtx->lpDev3);
+ lpCtx->bSceneStarted = FALSE;
+ }
+#endif
+
+#if 0
+ // If the calling app is not active then we don't need to Blit/Flip.
+ // We can therefore simply return TRUE.
+ if (!glb.bAppActive)
+ return TRUE;
+ // Addendum: This is WRONG! We should bail if the app is *minimized*,
+ // not merely if the app is just plain 'not active'.
+ // KeithH, 27/May/2000.
+#endif
+
+ // Check for non-window DC = memory DC ?
+ if (hWnd == NULL) {
+ if (GetClipBox(hDC, &rSrcRect) == ERROR)
+ return TRUE;
+ // Use GDI BitBlt instead from compatible DirectDraw DC
+ x = rSrcRect.left;
+ y = rSrcRect.top;
+ w = rSrcRect.right - rSrcRect.left;
+ h = rSrcRect.bottom - rSrcRect.top;
+
+ // Ack. DX8 does not have a GetDC() function...
+ // TODO: Defer to DX7 or DX9 drivers... (DaveM)
+ return TRUE;
+ }
+
+ // Bail if window client region is not drawable, like in Solid Edge
+ if (!IsWindow(hWnd) /* || !IsWindowVisible(hWnd) */ || !GetClientRect(hWnd, &rSrcRect))
+ return TRUE;
+
+#ifdef GLD_THREADS
+ // Serialize access to DirectDraw or DDS operations
+ if (glb.bMultiThreaded)
+ EnterCriticalSection(&CriticalSection);
+#endif
+
+#ifdef _USE_GLD3_WGL
+ // Notify Mesa of impending swap, so Mesa can flush internal buffers.
+ _mesa_notifySwapBuffers(lpCtx->glCtx);
+ // Now perform driver buffer swap
+ _gldDriver.SwapBuffers(lpCtx, hDC, hWnd);
+#else
+ if (lpCtx->bFullscreen) {
+ // Sync with retrace if required
+ if (glb.bWaitForRetrace) {
+ IDirectDraw4_WaitForVerticalBlank(
+ lpCtx->lpDD4,
+ DDWAITVB_BLOCKBEGIN,
+ 0);
+ }
+
+ // Perform the fullscreen flip
+ TRY(IDirectDrawSurface4_Flip(
+ lpCtx->lpFront4,
+ NULL,
+ DDFLIP_WAIT),
+ "dglSwapBuffers: Flip");
+ } else {
+ // Calculate current window position and size
+ pt.x = pt.y = 0;
+ ClientToScreen(hWnd, &pt);
+ GetClientRect(hWnd, &rDstRect);
+ if (rDstRect.right > lpCtx->dwModeWidth)
+ rDstRect.right = lpCtx->dwModeWidth;
+ if (rDstRect.bottom > lpCtx->dwModeHeight)
+ rDstRect.bottom = lpCtx->dwModeHeight;
+ OffsetRect(&rDstRect, pt.x, pt.y);
+ rSrcRect.left = rSrcRect.top = 0;
+ rSrcRect.right = lpCtx->dwWidth;
+ rSrcRect.bottom = lpCtx->dwHeight;
+ if (rSrcRect.right > lpCtx->dwModeWidth)
+ rSrcRect.right = lpCtx->dwModeWidth;
+ if (rSrcRect.bottom > lpCtx->dwModeHeight)
+ rSrcRect.bottom = lpCtx->dwModeHeight;
+
+ if (glb.bWaitForRetrace) {
+ // Sync the blit to the vertical retrace
+ ZeroMemory(&bltFX, sizeof(bltFX));
+ bltFX.dwSize = sizeof(bltFX);
+ bltFX.dwDDFX = DDBLTFX_NOTEARING;
+ dwBlitFlags = DDBLT_WAIT | DDBLT_DDFX;
+ lpBltFX = &bltFX;
+ } else {
+ dwBlitFlags = DDBLT_WAIT;
+ lpBltFX = NULL;
+ }
+
+ // Perform the actual blit
+ TRY(IDirectDrawSurface4_Blt(
+ lpCtx->lpFront4,
+ &rDstRect,
+ lpCtx->lpBack4, // Blit source
+ &rSrcRect,
+ dwBlitFlags,
+ lpBltFX),
+ "dglSwapBuffers: Blt");
+ }
+#endif // _USE_GLD3_WGL
+
+#ifdef GLD_THREADS
+ // Release serialized access
+ if (glb.bMultiThreaded)
+ LeaveCriticalSection(&CriticalSection);
+#endif
+
+ // TODO: Re-instate rendering bitmap snapshot feature??? (DaveM)
+
+ // Render frame is completed
+ ValidateRect(hWnd, NULL);
+ lpCtx->bFrameStarted = FALSE;
+
+ return TRUE;
+}
+
+// ***********************************************************************
diff --git a/mesalib/src/mesa/main/api_arrayelt.c b/mesalib/src/mesa/main/api_arrayelt.c index 080c20606..3c59e9be3 100644 --- a/mesalib/src/mesa/main/api_arrayelt.c +++ b/mesalib/src/mesa/main/api_arrayelt.c @@ -51,7 +51,7 @@ typedef struct { int offset;
} AEarray;
-typedef void (GLAPIENTRY *attrib_func)( GLuint indx, const void *data );
+typedef void (*attrib_func)( GLuint indx, const void *data );
typedef struct {
const struct gl_client_array *array;
diff --git a/mesalib/src/mesa/main/api_exec.c b/mesalib/src/mesa/main/api_exec.c index d7a4c90d7..02e39c189 100644 --- a/mesalib/src/mesa/main/api_exec.c +++ b/mesalib/src/mesa/main/api_exec.c @@ -104,7 +104,6 @@ #if FEATURE_GL
-
/**
* Initialize a dispatch table with pointers to Mesa's immediate-mode
* commands.
diff --git a/mesalib/src/mesa/main/blend.c b/mesalib/src/mesa/main/blend.c index c74a16803..22031fd2a 100644 --- a/mesalib/src/mesa/main/blend.c +++ b/mesalib/src/mesa/main/blend.c @@ -1,822 +1,822 @@ -/** - * \file blend.c - * Blending operations. - */ - -/* - * Mesa 3-D graphics library - * Version: 6.5.1 - * - * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - - -#include "glheader.h" -#include "blend.h" -#include "context.h" -#include "enums.h" -#include "macros.h" -#include "mtypes.h" - - - -/** - * Check if given blend source factor is legal. - * \return GL_TRUE if legal, GL_FALSE otherwise. - */ -static GLboolean -legal_src_factor(const struct gl_context *ctx, GLenum factor) -{ - switch (factor) { - case GL_SRC_COLOR: - case GL_ONE_MINUS_SRC_COLOR: - return ctx->Extensions.NV_blend_square; - case GL_ZERO: - case GL_ONE: - case GL_DST_COLOR: - case GL_ONE_MINUS_DST_COLOR: - case GL_SRC_ALPHA: - case GL_ONE_MINUS_SRC_ALPHA: - case GL_DST_ALPHA: - case GL_ONE_MINUS_DST_ALPHA: - case GL_SRC_ALPHA_SATURATE: - case GL_CONSTANT_COLOR: - case GL_ONE_MINUS_CONSTANT_COLOR: - case GL_CONSTANT_ALPHA: - case GL_ONE_MINUS_CONSTANT_ALPHA: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Check if given blend destination factor is legal. - * \return GL_TRUE if legal, GL_FALSE otherwise. - */ -static GLboolean -legal_dst_factor(const struct gl_context *ctx, GLenum factor) -{ - switch (factor) { - case GL_DST_COLOR: - case GL_ONE_MINUS_DST_COLOR: - return ctx->Extensions.NV_blend_square; - case GL_ZERO: - case GL_ONE: - case GL_SRC_COLOR: - case GL_ONE_MINUS_SRC_COLOR: - case GL_SRC_ALPHA: - case GL_ONE_MINUS_SRC_ALPHA: - case GL_DST_ALPHA: - case GL_ONE_MINUS_DST_ALPHA: - case GL_CONSTANT_COLOR: - case GL_ONE_MINUS_CONSTANT_COLOR: - case GL_CONSTANT_ALPHA: - case GL_ONE_MINUS_CONSTANT_ALPHA: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Check if src/dest RGB/A blend factors are legal. If not generate - * a GL error. - * \return GL_TRUE if factors are legal, GL_FALSE otherwise. - */ -static GLboolean -validate_blend_factors(struct gl_context *ctx, const char *func, - GLenum sfactorRGB, GLenum dfactorRGB, - GLenum sfactorA, GLenum dfactorA) -{ - if (!legal_src_factor(ctx, sfactorRGB)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(sfactorRGB = %s)", func, - _mesa_lookup_enum_by_nr(sfactorRGB)); - return GL_FALSE; - } - - if (!legal_dst_factor(ctx, dfactorRGB)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(dfactorRGB = %s)", func, - _mesa_lookup_enum_by_nr(dfactorRGB)); - return GL_FALSE; - } - - if (sfactorA != sfactorRGB && !legal_src_factor(ctx, sfactorA)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(sfactorA = %s)", func, - _mesa_lookup_enum_by_nr(sfactorA)); - return GL_FALSE; - } - - if (dfactorA != dfactorRGB && !legal_dst_factor(ctx, dfactorA)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(dfactorA = %s)", func, - _mesa_lookup_enum_by_nr(dfactorA)); - return GL_FALSE; - } - - return GL_TRUE; -} - - -/** - * Specify the blending operation. - * - * \param sfactor source factor operator. - * \param dfactor destination factor operator. - * - * \sa glBlendFunc, glBlendFuncSeparateEXT - */ -void GLAPIENTRY -_mesa_BlendFunc( GLenum sfactor, GLenum dfactor ) -{ - _mesa_BlendFuncSeparateEXT(sfactor, dfactor, sfactor, dfactor); -} - - -/** - * Set the separate blend source/dest factors for all draw buffers. - * - * \param sfactorRGB RGB source factor operator. - * \param dfactorRGB RGB destination factor operator. - * \param sfactorA alpha source factor operator. - * \param dfactorA alpha destination factor operator. - */ -void GLAPIENTRY -_mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB, - GLenum sfactorA, GLenum dfactorA ) -{ - GLuint buf, numBuffers; - GLboolean changed; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n", - _mesa_lookup_enum_by_nr(sfactorRGB), - _mesa_lookup_enum_by_nr(dfactorRGB), - _mesa_lookup_enum_by_nr(sfactorA), - _mesa_lookup_enum_by_nr(dfactorA)); - - if (!validate_blend_factors(ctx, "glBlendFuncSeparate", - sfactorRGB, dfactorRGB, - sfactorA, dfactorA)) { - return; - } - - numBuffers = ctx->Extensions.ARB_draw_buffers_blend - ? ctx->Const.MaxDrawBuffers : 1; - - changed = GL_FALSE; - for (buf = 0; buf < numBuffers; buf++) { - if (ctx->Color.Blend[buf].SrcRGB != sfactorRGB || - ctx->Color.Blend[buf].DstRGB != dfactorRGB || - ctx->Color.Blend[buf].SrcA != sfactorA || - ctx->Color.Blend[buf].DstA != dfactorA) { - changed = GL_TRUE; - break; - } - } - if (!changed) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - - for (buf = 0; buf < numBuffers; buf++) { - ctx->Color.Blend[buf].SrcRGB = sfactorRGB; - ctx->Color.Blend[buf].DstRGB = dfactorRGB; - ctx->Color.Blend[buf].SrcA = sfactorA; - ctx->Color.Blend[buf].DstA = dfactorA; - } - ctx->Color._BlendFuncPerBuffer = GL_FALSE; - - if (ctx->Driver.BlendFuncSeparate) { - ctx->Driver.BlendFuncSeparate(ctx, sfactorRGB, dfactorRGB, - sfactorA, dfactorA); - } -} - - -#if _HAVE_FULL_GL - - -/** - * Set blend source/dest factors for one color buffer/target. - */ -void GLAPIENTRY -_mesa_BlendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) -{ - _mesa_BlendFuncSeparatei(buf, sfactor, dfactor, sfactor, dfactor); -} - - -/** - * Set separate blend source/dest factors for one color buffer/target. - */ -void GLAPIENTRY -_mesa_BlendFuncSeparatei(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB, - GLenum sfactorA, GLenum dfactorA) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!ctx->Extensions.ARB_draw_buffers_blend) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBlendFunc[Separate]i()"); - return; - } - - if (buf >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", - buf); - return; - } - - if (!validate_blend_factors(ctx, "glBlendFuncSeparatei", - sfactorRGB, dfactorRGB, - sfactorA, dfactorA)) { - return; - } - - if (ctx->Color.Blend[buf].SrcRGB == sfactorRGB && - ctx->Color.Blend[buf].DstRGB == dfactorRGB && - ctx->Color.Blend[buf].SrcA == sfactorA && - ctx->Color.Blend[buf].DstA == dfactorA) - return; /* no change */ - - FLUSH_VERTICES(ctx, _NEW_COLOR); - - ctx->Color.Blend[buf].SrcRGB = sfactorRGB; - ctx->Color.Blend[buf].DstRGB = dfactorRGB; - ctx->Color.Blend[buf].SrcA = sfactorA; - ctx->Color.Blend[buf].DstA = dfactorA; - ctx->Color._BlendFuncPerBuffer = GL_TRUE; - - if (ctx->Driver.BlendFuncSeparatei) { - ctx->Driver.BlendFuncSeparatei(ctx, buf, sfactorRGB, dfactorRGB, - sfactorA, dfactorA); - } -} - - -/** - * Check if given blend equation is legal. - * \return GL_TRUE if legal, GL_FALSE otherwise. - */ -static GLboolean -legal_blend_equation(const struct gl_context *ctx, - GLenum mode, GLboolean is_separate) -{ - switch (mode) { - case GL_FUNC_ADD: - return GL_TRUE; - case GL_MIN: - case GL_MAX: - return ctx->Extensions.EXT_blend_minmax; - case GL_LOGIC_OP: - /* glBlendEquationSeparate cannot take GL_LOGIC_OP as a parameter. - */ - return ctx->Extensions.EXT_blend_logic_op && !is_separate; - case GL_FUNC_SUBTRACT: - case GL_FUNC_REVERSE_SUBTRACT: - return ctx->Extensions.EXT_blend_subtract; - default: - return GL_FALSE; - } -} - - -/* This is really an extension function! */ -void GLAPIENTRY -_mesa_BlendEquation( GLenum mode ) -{ - GLuint buf, numBuffers; - GLboolean changed; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendEquation(%s)\n", - _mesa_lookup_enum_by_nr(mode)); - - if (!legal_blend_equation(ctx, mode, GL_FALSE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); - return; - } - - numBuffers = ctx->Extensions.ARB_draw_buffers_blend - ? ctx->Const.MaxDrawBuffers : 1; - - changed = GL_FALSE; - for (buf = 0; buf < numBuffers; buf++) { - if (ctx->Color.Blend[buf].EquationRGB != mode || - ctx->Color.Blend[buf].EquationA != mode) { - changed = GL_TRUE; - break; - } - } - if (!changed) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - for (buf = 0; buf < numBuffers; buf++) { - ctx->Color.Blend[buf].EquationRGB = mode; - ctx->Color.Blend[buf].EquationA = mode; - } - ctx->Color._BlendEquationPerBuffer = GL_FALSE; - - if (ctx->Driver.BlendEquationSeparate) - (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode ); -} - - -/** - * Set blend equation for one color buffer/target. - */ -void GLAPIENTRY -_mesa_BlendEquationi(GLuint buf, GLenum mode) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n", - buf, _mesa_lookup_enum_by_nr(mode)); - - if (buf >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", - buf); - return; - } - - if (!legal_blend_equation(ctx, mode, GL_FALSE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi"); - return; - } - - if (ctx->Color.Blend[buf].EquationRGB == mode && - ctx->Color.Blend[buf].EquationA == mode) - return; /* no change */ - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.Blend[buf].EquationRGB = mode; - ctx->Color.Blend[buf].EquationA = mode; - ctx->Color._BlendEquationPerBuffer = GL_TRUE; - - if (ctx->Driver.BlendEquationSeparatei) - ctx->Driver.BlendEquationSeparatei(ctx, buf, mode, mode); -} - - -void GLAPIENTRY -_mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA ) -{ - GLuint buf, numBuffers; - GLboolean changed; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n", - _mesa_lookup_enum_by_nr(modeRGB), - _mesa_lookup_enum_by_nr(modeA)); - - if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlendEquationSeparateEXT not supported by driver"); - return; - } - - if (!legal_blend_equation(ctx, modeRGB, GL_TRUE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)"); - return; - } - - if (!legal_blend_equation(ctx, modeA, GL_TRUE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); - return; - } - - numBuffers = ctx->Extensions.ARB_draw_buffers_blend - ? ctx->Const.MaxDrawBuffers : 1; - - changed = GL_FALSE; - for (buf = 0; buf < numBuffers; buf++) { - if (ctx->Color.Blend[buf].EquationRGB != modeRGB || - ctx->Color.Blend[buf].EquationA != modeA) { - changed = GL_TRUE; - break; - } - } - if (!changed) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - for (buf = 0; buf < numBuffers; buf++) { - ctx->Color.Blend[buf].EquationRGB = modeRGB; - ctx->Color.Blend[buf].EquationA = modeA; - } - ctx->Color._BlendEquationPerBuffer = GL_FALSE; - - if (ctx->Driver.BlendEquationSeparate) - ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA); -} - - -/** - * Set separate blend equations for one color buffer/target. - */ -void -_mesa_BlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeA) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf, - _mesa_lookup_enum_by_nr(modeRGB), - _mesa_lookup_enum_by_nr(modeA)); - - if (buf >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)", - buf); - return; - } - - if (!legal_blend_equation(ctx, modeRGB, GL_TRUE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)"); - return; - } - - if (!legal_blend_equation(ctx, modeA, GL_TRUE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)"); - return; - } - - if (ctx->Color.Blend[buf].EquationRGB == modeRGB && - ctx->Color.Blend[buf].EquationA == modeA) - return; /* no change */ - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.Blend[buf].EquationRGB = modeRGB; - ctx->Color.Blend[buf].EquationA = modeA; - ctx->Color._BlendEquationPerBuffer = GL_TRUE; - - if (ctx->Driver.BlendEquationSeparatei) - ctx->Driver.BlendEquationSeparatei(ctx, buf, modeRGB, modeA); -} - - - -#endif /* _HAVE_FULL_GL */ - - -/** - * Set the blending color. - * - * \param red red color component. - * \param green green color component. - * \param blue blue color component. - * \param alpha alpha color component. - * - * \sa glBlendColor(). - * - * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a - * change, flushes the vertices and notifies the driver via - * dd_function_table::BlendColor callback. - */ -void GLAPIENTRY -_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) -{ - GLfloat tmp[4]; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - tmp[0] = CLAMP( red, 0.0F, 1.0F ); - tmp[1] = CLAMP( green, 0.0F, 1.0F ); - tmp[2] = CLAMP( blue, 0.0F, 1.0F ); - tmp[3] = CLAMP( alpha, 0.0F, 1.0F ); - - if (TEST_EQ_4V(tmp, ctx->Color.BlendColor)) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - COPY_4FV( ctx->Color.BlendColor, tmp ); - - if (ctx->Driver.BlendColor) - (*ctx->Driver.BlendColor)(ctx, tmp); -} - - -/** - * Specify the alpha test function. - * - * \param func alpha comparison function. - * \param ref reference value. - * - * Verifies the parameters and updates gl_colorbuffer_attrib. - * On a change, flushes the vertices and notifies the driver via - * dd_function_table::AlphaFunc callback. - */ -void GLAPIENTRY -_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: - case GL_EQUAL: - case GL_LEQUAL: - case GL_GREATER: - case GL_NOTEQUAL: - case GL_GEQUAL: - case GL_ALWAYS: - ref = CLAMP(ref, 0.0F, 1.0F); - - if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRef == ref) - return; /* no change */ - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.AlphaFunc = func; - ctx->Color.AlphaRef = ref; - - if (ctx->Driver.AlphaFunc) - ctx->Driver.AlphaFunc(ctx, func, ref); - return; - - default: - _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); - return; - } -} - - -/** - * Specify a logic pixel operation for color index rendering. - * - * \param opcode operation. - * - * Verifies that \p opcode is a valid enum and updates -gl_colorbuffer_attrib::LogicOp. - * On a change, flushes the vertices and notifies the driver via the - * dd_function_table::LogicOpcode callback. - */ -void GLAPIENTRY -_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: - case GL_COPY: - case GL_COPY_INVERTED: - case GL_NOOP: - case GL_INVERT: - case GL_AND: - case GL_NAND: - case GL_OR: - case GL_NOR: - case GL_XOR: - case GL_EQUIV: - case GL_AND_REVERSE: - case GL_AND_INVERTED: - case GL_OR_REVERSE: - case GL_OR_INVERTED: - break; - default: - _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); - return; - } - - if (ctx->Color.LogicOp == opcode) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.LogicOp = opcode; - - if (ctx->Driver.LogicOpcode) - ctx->Driver.LogicOpcode( ctx, opcode ); -} - -#if _HAVE_FULL_GL -void GLAPIENTRY -_mesa_IndexMask( GLuint mask ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (ctx->Color.IndexMask == mask) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.IndexMask = mask; -} -#endif - - -/** - * Enable or disable writing of frame buffer color components. - * - * \param red whether to mask writing of the red color component. - * \param green whether to mask writing of the green color component. - * \param blue whether to mask writing of the blue color component. - * \param alpha whether to mask writing of the alpha color component. - * - * \sa glColorMask(). - * - * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a - * change, flushes the vertices and notifies the driver via the - * dd_function_table::ColorMask callback. - */ -void GLAPIENTRY -_mesa_ColorMask( GLboolean red, GLboolean green, - GLboolean blue, GLboolean alpha ) -{ - GET_CURRENT_CONTEXT(ctx); - GLubyte tmp[4]; - GLuint i; - GLboolean flushed; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _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: - */ - tmp[RCOMP] = red ? 0xff : 0x0; - tmp[GCOMP] = green ? 0xff : 0x0; - tmp[BCOMP] = blue ? 0xff : 0x0; - tmp[ACOMP] = alpha ? 0xff : 0x0; - - flushed = GL_FALSE; - for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { - if (!TEST_EQ_4V(tmp, ctx->Color.ColorMask[i])) { - if (!flushed) { - FLUSH_VERTICES(ctx, _NEW_COLOR); - } - flushed = GL_TRUE; - COPY_4UBV(ctx->Color.ColorMask[i], tmp); - } - } - - if (ctx->Driver.ColorMask) - ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); -} - - -/** - * For GL_EXT_draw_buffers2 and GL3 - */ -void GLAPIENTRY -_mesa_ColorMaskIndexed( GLuint buf, GLboolean red, GLboolean green, - GLboolean blue, GLboolean alpha ) -{ - GLubyte tmp[4]; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glColorMaskIndexed %u %d %d %d %d\n", - buf, red, green, blue, alpha); - - if (buf >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaskIndexed(buf=%u)", buf); - return; - } - - /* Shouldn't have any information about channel depth in core mesa - * -- should probably store these as the native booleans: - */ - tmp[RCOMP] = red ? 0xff : 0x0; - tmp[GCOMP] = green ? 0xff : 0x0; - tmp[BCOMP] = blue ? 0xff : 0x0; - tmp[ACOMP] = alpha ? 0xff : 0x0; - - if (TEST_EQ_4V(tmp, ctx->Color.ColorMask[buf])) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - COPY_4UBV(ctx->Color.ColorMask[buf], tmp); - - if (ctx->Driver.ColorMaskIndexed) - ctx->Driver.ColorMaskIndexed(ctx, buf, red, green, blue, alpha); -} - - -extern void GLAPIENTRY -_mesa_ClampColorARB(GLenum target, GLenum clamp) -{ - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) { - _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)"); - return; - } - - switch (target) { - case GL_CLAMP_VERTEX_COLOR_ARB: - ctx->Light.ClampVertexColor = clamp; - break; - case GL_CLAMP_FRAGMENT_COLOR_ARB: - ctx->Color.ClampFragmentColor = clamp; - break; - case GL_CLAMP_READ_COLOR_ARB: - ctx->Color.ClampReadColor = clamp; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(target)"); - return; - } -} - - - - -/**********************************************************************/ -/** \name Initialization */ -/*@{*/ - -/** - * Initialization of the context's Color attribute group. - * - * \param ctx GL context. - * - * Initializes the related fields in the context color attribute group, - * __struct gl_contextRec::Color. - */ -void _mesa_init_color( struct gl_context * ctx ) -{ - GLuint i; - - /* Color buffer group */ - ctx->Color.IndexMask = ~0u; - memset(ctx->Color.ColorMask, 0xff, sizeof(ctx->Color.ColorMask)); - ctx->Color.ClearIndex = 0; - ASSIGN_4V( ctx->Color.ClearColor, 0, 0, 0, 0 ); - ctx->Color.AlphaEnabled = GL_FALSE; - ctx->Color.AlphaFunc = GL_ALWAYS; - ctx->Color.AlphaRef = 0; - ctx->Color.BlendEnabled = 0x0; - for (i = 0; i < Elements(ctx->Color.Blend); i++) { - ctx->Color.Blend[i].SrcRGB = GL_ONE; - ctx->Color.Blend[i].DstRGB = GL_ZERO; - ctx->Color.Blend[i].SrcA = GL_ONE; - ctx->Color.Blend[i].DstA = GL_ZERO; - ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD; - ctx->Color.Blend[i].EquationA = GL_FUNC_ADD; - } - ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); - ctx->Color.IndexLogicOpEnabled = GL_FALSE; - ctx->Color.ColorLogicOpEnabled = GL_FALSE; - ctx->Color._LogicOpEnabled = GL_FALSE; - ctx->Color.LogicOp = GL_COPY; - ctx->Color.DitherFlag = GL_TRUE; - - if (ctx->Visual.doubleBufferMode) { - ctx->Color.DrawBuffer[0] = GL_BACK; - } - else { - ctx->Color.DrawBuffer[0] = GL_FRONT; - } - - ctx->Color.ClampFragmentColor = GL_FIXED_ONLY_ARB; - ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB; -} - -/*@}*/ +/**
+ * \file blend.c
+ * Blending operations.
+ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.1
+ *
+ * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+
+#include "glheader.h"
+#include "blend.h"
+#include "context.h"
+#include "enums.h"
+#include "macros.h"
+#include "mtypes.h"
+
+
+
+/**
+ * Check if given blend source factor is legal.
+ * \return GL_TRUE if legal, GL_FALSE otherwise.
+ */
+static GLboolean
+legal_src_factor(const struct gl_context *ctx, GLenum factor)
+{
+ switch (factor) {
+ case GL_SRC_COLOR:
+ case GL_ONE_MINUS_SRC_COLOR:
+ return ctx->Extensions.NV_blend_square;
+ case GL_ZERO:
+ case GL_ONE:
+ case GL_DST_COLOR:
+ case GL_ONE_MINUS_DST_COLOR:
+ case GL_SRC_ALPHA:
+ case GL_ONE_MINUS_SRC_ALPHA:
+ case GL_DST_ALPHA:
+ case GL_ONE_MINUS_DST_ALPHA:
+ case GL_SRC_ALPHA_SATURATE:
+ case GL_CONSTANT_COLOR:
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ case GL_CONSTANT_ALPHA:
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ return GL_TRUE;
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Check if given blend destination factor is legal.
+ * \return GL_TRUE if legal, GL_FALSE otherwise.
+ */
+static GLboolean
+legal_dst_factor(const struct gl_context *ctx, GLenum factor)
+{
+ switch (factor) {
+ case GL_DST_COLOR:
+ case GL_ONE_MINUS_DST_COLOR:
+ return ctx->Extensions.NV_blend_square;
+ case GL_ZERO:
+ case GL_ONE:
+ case GL_SRC_COLOR:
+ case GL_ONE_MINUS_SRC_COLOR:
+ case GL_SRC_ALPHA:
+ case GL_ONE_MINUS_SRC_ALPHA:
+ case GL_DST_ALPHA:
+ case GL_ONE_MINUS_DST_ALPHA:
+ case GL_CONSTANT_COLOR:
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ case GL_CONSTANT_ALPHA:
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ return GL_TRUE;
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Check if src/dest RGB/A blend factors are legal. If not generate
+ * a GL error.
+ * \return GL_TRUE if factors are legal, GL_FALSE otherwise.
+ */
+static GLboolean
+validate_blend_factors(struct gl_context *ctx, const char *func,
+ GLenum sfactorRGB, GLenum dfactorRGB,
+ GLenum sfactorA, GLenum dfactorA)
+{
+ if (!legal_src_factor(ctx, sfactorRGB)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(sfactorRGB = %s)", func,
+ _mesa_lookup_enum_by_nr(sfactorRGB));
+ return GL_FALSE;
+ }
+
+ if (!legal_dst_factor(ctx, dfactorRGB)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(dfactorRGB = %s)", func,
+ _mesa_lookup_enum_by_nr(dfactorRGB));
+ return GL_FALSE;
+ }
+
+ if (sfactorA != sfactorRGB && !legal_src_factor(ctx, sfactorA)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(sfactorA = %s)", func,
+ _mesa_lookup_enum_by_nr(sfactorA));
+ return GL_FALSE;
+ }
+
+ if (dfactorA != dfactorRGB && !legal_dst_factor(ctx, dfactorA)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(dfactorA = %s)", func,
+ _mesa_lookup_enum_by_nr(dfactorA));
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Specify the blending operation.
+ *
+ * \param sfactor source factor operator.
+ * \param dfactor destination factor operator.
+ *
+ * \sa glBlendFunc, glBlendFuncSeparateEXT
+ */
+void GLAPIENTRY
+_mesa_BlendFunc( GLenum sfactor, GLenum dfactor )
+{
+ _mesa_BlendFuncSeparateEXT(sfactor, dfactor, sfactor, dfactor);
+}
+
+
+/**
+ * Set the separate blend source/dest factors for all draw buffers.
+ *
+ * \param sfactorRGB RGB source factor operator.
+ * \param dfactorRGB RGB destination factor operator.
+ * \param sfactorA alpha source factor operator.
+ * \param dfactorA alpha destination factor operator.
+ */
+void GLAPIENTRY
+_mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB,
+ GLenum sfactorA, GLenum dfactorA )
+{
+ GLuint buf, numBuffers;
+ GLboolean changed;
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n",
+ _mesa_lookup_enum_by_nr(sfactorRGB),
+ _mesa_lookup_enum_by_nr(dfactorRGB),
+ _mesa_lookup_enum_by_nr(sfactorA),
+ _mesa_lookup_enum_by_nr(dfactorA));
+
+ if (!validate_blend_factors(ctx, "glBlendFuncSeparate",
+ sfactorRGB, dfactorRGB,
+ sfactorA, dfactorA)) {
+ return;
+ }
+
+ numBuffers = ctx->Extensions.ARB_draw_buffers_blend
+ ? ctx->Const.MaxDrawBuffers : 1;
+
+ changed = GL_FALSE;
+ for (buf = 0; buf < numBuffers; buf++) {
+ if (ctx->Color.Blend[buf].SrcRGB != sfactorRGB ||
+ ctx->Color.Blend[buf].DstRGB != dfactorRGB ||
+ ctx->Color.Blend[buf].SrcA != sfactorA ||
+ ctx->Color.Blend[buf].DstA != dfactorA) {
+ changed = GL_TRUE;
+ break;
+ }
+ }
+ if (!changed)
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+
+ for (buf = 0; buf < numBuffers; buf++) {
+ ctx->Color.Blend[buf].SrcRGB = sfactorRGB;
+ ctx->Color.Blend[buf].DstRGB = dfactorRGB;
+ ctx->Color.Blend[buf].SrcA = sfactorA;
+ ctx->Color.Blend[buf].DstA = dfactorA;
+ }
+ ctx->Color._BlendFuncPerBuffer = GL_FALSE;
+
+ if (ctx->Driver.BlendFuncSeparate) {
+ ctx->Driver.BlendFuncSeparate(ctx, sfactorRGB, dfactorRGB,
+ sfactorA, dfactorA);
+ }
+}
+
+
+#if _HAVE_FULL_GL
+
+
+/**
+ * Set blend source/dest factors for one color buffer/target.
+ */
+void GLAPIENTRY
+_mesa_BlendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
+{
+ _mesa_BlendFuncSeparatei(buf, sfactor, dfactor, sfactor, dfactor);
+}
+
+
+/**
+ * Set separate blend source/dest factors for one color buffer/target.
+ */
+void GLAPIENTRY
+_mesa_BlendFuncSeparatei(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB,
+ GLenum sfactorA, GLenum dfactorA)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (!ctx->Extensions.ARB_draw_buffers_blend) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glBlendFunc[Separate]i()");
+ return;
+ }
+
+ if (buf >= ctx->Const.MaxDrawBuffers) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)",
+ buf);
+ return;
+ }
+
+ if (!validate_blend_factors(ctx, "glBlendFuncSeparatei",
+ sfactorRGB, dfactorRGB,
+ sfactorA, dfactorA)) {
+ return;
+ }
+
+ if (ctx->Color.Blend[buf].SrcRGB == sfactorRGB &&
+ ctx->Color.Blend[buf].DstRGB == dfactorRGB &&
+ ctx->Color.Blend[buf].SrcA == sfactorA &&
+ ctx->Color.Blend[buf].DstA == dfactorA)
+ return; /* no change */
+
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+
+ ctx->Color.Blend[buf].SrcRGB = sfactorRGB;
+ ctx->Color.Blend[buf].DstRGB = dfactorRGB;
+ ctx->Color.Blend[buf].SrcA = sfactorA;
+ ctx->Color.Blend[buf].DstA = dfactorA;
+ ctx->Color._BlendFuncPerBuffer = GL_TRUE;
+
+ if (ctx->Driver.BlendFuncSeparatei) {
+ ctx->Driver.BlendFuncSeparatei(ctx, buf, sfactorRGB, dfactorRGB,
+ sfactorA, dfactorA);
+ }
+}
+
+
+/**
+ * Check if given blend equation is legal.
+ * \return GL_TRUE if legal, GL_FALSE otherwise.
+ */
+static GLboolean
+legal_blend_equation(const struct gl_context *ctx,
+ GLenum mode, GLboolean is_separate)
+{
+ switch (mode) {
+ case GL_FUNC_ADD:
+ return GL_TRUE;
+ case GL_MIN:
+ case GL_MAX:
+ return ctx->Extensions.EXT_blend_minmax;
+ case GL_LOGIC_OP:
+ /* glBlendEquationSeparate cannot take GL_LOGIC_OP as a parameter.
+ */
+ return ctx->Extensions.EXT_blend_logic_op && !is_separate;
+ case GL_FUNC_SUBTRACT:
+ case GL_FUNC_REVERSE_SUBTRACT:
+ return ctx->Extensions.EXT_blend_subtract;
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+/* This is really an extension function! */
+void GLAPIENTRY
+_mesa_BlendEquation( GLenum mode )
+{
+ GLuint buf, numBuffers;
+ GLboolean changed;
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glBlendEquation(%s)\n",
+ _mesa_lookup_enum_by_nr(mode));
+
+ if (!legal_blend_equation(ctx, mode, GL_FALSE)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation");
+ return;
+ }
+
+ numBuffers = ctx->Extensions.ARB_draw_buffers_blend
+ ? ctx->Const.MaxDrawBuffers : 1;
+
+ changed = GL_FALSE;
+ for (buf = 0; buf < numBuffers; buf++) {
+ if (ctx->Color.Blend[buf].EquationRGB != mode ||
+ ctx->Color.Blend[buf].EquationA != mode) {
+ changed = GL_TRUE;
+ break;
+ }
+ }
+ if (!changed)
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ for (buf = 0; buf < numBuffers; buf++) {
+ ctx->Color.Blend[buf].EquationRGB = mode;
+ ctx->Color.Blend[buf].EquationA = mode;
+ }
+ ctx->Color._BlendEquationPerBuffer = GL_FALSE;
+
+ if (ctx->Driver.BlendEquationSeparate)
+ (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode );
+}
+
+
+/**
+ * Set blend equation for one color buffer/target.
+ */
+void GLAPIENTRY
+_mesa_BlendEquationi(GLuint buf, GLenum mode)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n",
+ buf, _mesa_lookup_enum_by_nr(mode));
+
+ if (buf >= ctx->Const.MaxDrawBuffers) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)",
+ buf);
+ return;
+ }
+
+ if (!legal_blend_equation(ctx, mode, GL_FALSE)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi");
+ return;
+ }
+
+ if (ctx->Color.Blend[buf].EquationRGB == mode &&
+ ctx->Color.Blend[buf].EquationA == mode)
+ return; /* no change */
+
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ ctx->Color.Blend[buf].EquationRGB = mode;
+ ctx->Color.Blend[buf].EquationA = mode;
+ ctx->Color._BlendEquationPerBuffer = GL_TRUE;
+
+ if (ctx->Driver.BlendEquationSeparatei)
+ ctx->Driver.BlendEquationSeparatei(ctx, buf, mode, mode);
+}
+
+
+void GLAPIENTRY
+_mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA )
+{
+ GLuint buf, numBuffers;
+ GLboolean changed;
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n",
+ _mesa_lookup_enum_by_nr(modeRGB),
+ _mesa_lookup_enum_by_nr(modeA));
+
+ if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBlendEquationSeparateEXT not supported by driver");
+ return;
+ }
+
+ if (!legal_blend_equation(ctx, modeRGB, GL_TRUE)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)");
+ return;
+ }
+
+ if (!legal_blend_equation(ctx, modeA, GL_TRUE)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)");
+ return;
+ }
+
+ numBuffers = ctx->Extensions.ARB_draw_buffers_blend
+ ? ctx->Const.MaxDrawBuffers : 1;
+
+ changed = GL_FALSE;
+ for (buf = 0; buf < numBuffers; buf++) {
+ if (ctx->Color.Blend[buf].EquationRGB != modeRGB ||
+ ctx->Color.Blend[buf].EquationA != modeA) {
+ changed = GL_TRUE;
+ break;
+ }
+ }
+ if (!changed)
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ for (buf = 0; buf < numBuffers; buf++) {
+ ctx->Color.Blend[buf].EquationRGB = modeRGB;
+ ctx->Color.Blend[buf].EquationA = modeA;
+ }
+ ctx->Color._BlendEquationPerBuffer = GL_FALSE;
+
+ if (ctx->Driver.BlendEquationSeparate)
+ ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA);
+}
+
+
+/**
+ * Set separate blend equations for one color buffer/target.
+ */
+void
+_mesa_BlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeA)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf,
+ _mesa_lookup_enum_by_nr(modeRGB),
+ _mesa_lookup_enum_by_nr(modeA));
+
+ if (buf >= ctx->Const.MaxDrawBuffers) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)",
+ buf);
+ return;
+ }
+
+ if (!legal_blend_equation(ctx, modeRGB, GL_TRUE)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)");
+ return;
+ }
+
+ if (!legal_blend_equation(ctx, modeA, GL_TRUE)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)");
+ return;
+ }
+
+ if (ctx->Color.Blend[buf].EquationRGB == modeRGB &&
+ ctx->Color.Blend[buf].EquationA == modeA)
+ return; /* no change */
+
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ ctx->Color.Blend[buf].EquationRGB = modeRGB;
+ ctx->Color.Blend[buf].EquationA = modeA;
+ ctx->Color._BlendEquationPerBuffer = GL_TRUE;
+
+ if (ctx->Driver.BlendEquationSeparatei)
+ ctx->Driver.BlendEquationSeparatei(ctx, buf, modeRGB, modeA);
+}
+
+
+
+#endif /* _HAVE_FULL_GL */
+
+
+/**
+ * Set the blending color.
+ *
+ * \param red red color component.
+ * \param green green color component.
+ * \param blue blue color component.
+ * \param alpha alpha color component.
+ *
+ * \sa glBlendColor().
+ *
+ * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a
+ * change, flushes the vertices and notifies the driver via
+ * dd_function_table::BlendColor callback.
+ */
+void GLAPIENTRY
+_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
+{
+ GLfloat tmp[4];
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ tmp[0] = CLAMP( red, 0.0F, 1.0F );
+ tmp[1] = CLAMP( green, 0.0F, 1.0F );
+ tmp[2] = CLAMP( blue, 0.0F, 1.0F );
+ tmp[3] = CLAMP( alpha, 0.0F, 1.0F );
+
+ if (TEST_EQ_4V(tmp, ctx->Color.BlendColor))
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ COPY_4FV( ctx->Color.BlendColor, tmp );
+
+ if (ctx->Driver.BlendColor)
+ (*ctx->Driver.BlendColor)(ctx, tmp);
+}
+
+
+/**
+ * Specify the alpha test function.
+ *
+ * \param func alpha comparison function.
+ * \param ref reference value.
+ *
+ * Verifies the parameters and updates gl_colorbuffer_attrib.
+ * On a change, flushes the vertices and notifies the driver via
+ * dd_function_table::AlphaFunc callback.
+ */
+void GLAPIENTRY
+_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:
+ case GL_EQUAL:
+ case GL_LEQUAL:
+ case GL_GREATER:
+ case GL_NOTEQUAL:
+ case GL_GEQUAL:
+ case GL_ALWAYS:
+ ref = CLAMP(ref, 0.0F, 1.0F);
+
+ if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRef == ref)
+ return; /* no change */
+
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ ctx->Color.AlphaFunc = func;
+ ctx->Color.AlphaRef = ref;
+
+ if (ctx->Driver.AlphaFunc)
+ ctx->Driver.AlphaFunc(ctx, func, ref);
+ return;
+
+ default:
+ _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" );
+ return;
+ }
+}
+
+
+/**
+ * Specify a logic pixel operation for color index rendering.
+ *
+ * \param opcode operation.
+ *
+ * Verifies that \p opcode is a valid enum and updates
+gl_colorbuffer_attrib::LogicOp.
+ * On a change, flushes the vertices and notifies the driver via the
+ * dd_function_table::LogicOpcode callback.
+ */
+void GLAPIENTRY
+_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:
+ case GL_COPY:
+ case GL_COPY_INVERTED:
+ case GL_NOOP:
+ case GL_INVERT:
+ case GL_AND:
+ case GL_NAND:
+ case GL_OR:
+ case GL_NOR:
+ case GL_XOR:
+ case GL_EQUIV:
+ case GL_AND_REVERSE:
+ case GL_AND_INVERTED:
+ case GL_OR_REVERSE:
+ case GL_OR_INVERTED:
+ break;
+ default:
+ _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" );
+ return;
+ }
+
+ if (ctx->Color.LogicOp == opcode)
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ ctx->Color.LogicOp = opcode;
+
+ if (ctx->Driver.LogicOpcode)
+ ctx->Driver.LogicOpcode( ctx, opcode );
+}
+
+#if _HAVE_FULL_GL
+void GLAPIENTRY
+_mesa_IndexMask( GLuint mask )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (ctx->Color.IndexMask == mask)
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ ctx->Color.IndexMask = mask;
+}
+#endif
+
+
+/**
+ * Enable or disable writing of frame buffer color components.
+ *
+ * \param red whether to mask writing of the red color component.
+ * \param green whether to mask writing of the green color component.
+ * \param blue whether to mask writing of the blue color component.
+ * \param alpha whether to mask writing of the alpha color component.
+ *
+ * \sa glColorMask().
+ *
+ * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a
+ * change, flushes the vertices and notifies the driver via the
+ * dd_function_table::ColorMask callback.
+ */
+void GLAPIENTRY
+_mesa_ColorMask( GLboolean red, GLboolean green,
+ GLboolean blue, GLboolean alpha )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLubyte tmp[4];
+ GLuint i;
+ GLboolean flushed;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _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:
+ */
+ tmp[RCOMP] = red ? 0xff : 0x0;
+ tmp[GCOMP] = green ? 0xff : 0x0;
+ tmp[BCOMP] = blue ? 0xff : 0x0;
+ tmp[ACOMP] = alpha ? 0xff : 0x0;
+
+ flushed = GL_FALSE;
+ for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
+ if (!TEST_EQ_4V(tmp, ctx->Color.ColorMask[i])) {
+ if (!flushed) {
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ }
+ flushed = GL_TRUE;
+ COPY_4UBV(ctx->Color.ColorMask[i], tmp);
+ }
+ }
+
+ if (ctx->Driver.ColorMask)
+ ctx->Driver.ColorMask( ctx, red, green, blue, alpha );
+}
+
+
+/**
+ * For GL_EXT_draw_buffers2 and GL3
+ */
+void GLAPIENTRY
+_mesa_ColorMaskIndexed( GLuint buf, GLboolean red, GLboolean green,
+ GLboolean blue, GLboolean alpha )
+{
+ GLubyte tmp[4];
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glColorMaskIndexed %u %d %d %d %d\n",
+ buf, red, green, blue, alpha);
+
+ if (buf >= ctx->Const.MaxDrawBuffers) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaskIndexed(buf=%u)", buf);
+ return;
+ }
+
+ /* Shouldn't have any information about channel depth in core mesa
+ * -- should probably store these as the native booleans:
+ */
+ tmp[RCOMP] = red ? 0xff : 0x0;
+ tmp[GCOMP] = green ? 0xff : 0x0;
+ tmp[BCOMP] = blue ? 0xff : 0x0;
+ tmp[ACOMP] = alpha ? 0xff : 0x0;
+
+ if (TEST_EQ_4V(tmp, ctx->Color.ColorMask[buf]))
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_COLOR);
+ COPY_4UBV(ctx->Color.ColorMask[buf], tmp);
+
+ if (ctx->Driver.ColorMaskIndexed)
+ ctx->Driver.ColorMaskIndexed(ctx, buf, red, green, blue, alpha);
+}
+
+
+extern void GLAPIENTRY
+_mesa_ClampColorARB(GLenum target, GLenum clamp)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)");
+ return;
+ }
+
+ switch (target) {
+ case GL_CLAMP_VERTEX_COLOR_ARB:
+ ctx->Light.ClampVertexColor = clamp;
+ break;
+ case GL_CLAMP_FRAGMENT_COLOR_ARB:
+ ctx->Color.ClampFragmentColor = clamp;
+ break;
+ case GL_CLAMP_READ_COLOR_ARB:
+ ctx->Color.ClampReadColor = clamp;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(target)");
+ return;
+ }
+}
+
+
+
+
+/**********************************************************************/
+/** \name Initialization */
+/*@{*/
+
+/**
+ * Initialization of the context's Color attribute group.
+ *
+ * \param ctx GL context.
+ *
+ * Initializes the related fields in the context color attribute group,
+ * __struct gl_contextRec::Color.
+ */
+void _mesa_init_color( struct gl_context * ctx )
+{
+ GLuint i;
+
+ /* Color buffer group */
+ ctx->Color.IndexMask = ~0u;
+ memset(ctx->Color.ColorMask, 0xff, sizeof(ctx->Color.ColorMask));
+ ctx->Color.ClearIndex = 0;
+ ASSIGN_4V( ctx->Color.ClearColor, 0, 0, 0, 0 );
+ ctx->Color.AlphaEnabled = GL_FALSE;
+ ctx->Color.AlphaFunc = GL_ALWAYS;
+ ctx->Color.AlphaRef = 0;
+ ctx->Color.BlendEnabled = 0x0;
+ for (i = 0; i < Elements(ctx->Color.Blend); i++) {
+ ctx->Color.Blend[i].SrcRGB = GL_ONE;
+ ctx->Color.Blend[i].DstRGB = GL_ZERO;
+ ctx->Color.Blend[i].SrcA = GL_ONE;
+ ctx->Color.Blend[i].DstA = GL_ZERO;
+ ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD;
+ ctx->Color.Blend[i].EquationA = GL_FUNC_ADD;
+ }
+ ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 );
+ ctx->Color.IndexLogicOpEnabled = GL_FALSE;
+ ctx->Color.ColorLogicOpEnabled = GL_FALSE;
+ ctx->Color._LogicOpEnabled = GL_FALSE;
+ ctx->Color.LogicOp = GL_COPY;
+ ctx->Color.DitherFlag = GL_TRUE;
+
+ if (ctx->Visual.doubleBufferMode) {
+ ctx->Color.DrawBuffer[0] = GL_BACK;
+ }
+ else {
+ ctx->Color.DrawBuffer[0] = GL_FRONT;
+ }
+
+ ctx->Color.ClampFragmentColor = GL_FIXED_ONLY_ARB;
+ ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB;
+}
+
+/*@}*/
diff --git a/mesalib/src/mesa/main/bufferobj.c b/mesalib/src/mesa/main/bufferobj.c index 75afae0ad..2de4602b8 100644 --- a/mesalib/src/mesa/main/bufferobj.c +++ b/mesalib/src/mesa/main/bufferobj.c @@ -1,2158 +1,2158 @@ -/* - * Mesa 3-D graphics library - * Version: 7.6 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * Copyright (C) 2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -/** - * \file bufferobj.c - * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions. - * \author Brian Paul, Ian Romanick - */ - - -#include "glheader.h" -#include "enums.h" -#include "hash.h" -#include "imports.h" -#include "image.h" -#include "context.h" -#include "bufferobj.h" -#include "fbobject.h" -#include "mfeatures.h" -#include "mtypes.h" -#include "texobj.h" - - -/* Debug flags */ -/*#define VBO_DEBUG*/ -/*#define BOUNDS_CHECK*/ - - -#if FEATURE_OES_mapbuffer -#define DEFAULT_ACCESS GL_MAP_WRITE_BIT -#else -#define DEFAULT_ACCESS (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT) -#endif - - -/** - * Used as a placeholder for buffer objects between glGenBuffers() and - * glBindBuffer() so that glIsBuffer() can work correctly. - */ -static struct gl_buffer_object DummyBufferObject; - - -/** - * Return pointer to address of a buffer object target. - * \param ctx the GL context - * \param target the buffer object target to be retrieved. - * \return pointer to pointer to the buffer object bound to \c target in the - * specified context or \c NULL if \c target is invalid. - */ -static INLINE struct gl_buffer_object ** -get_buffer_target(struct gl_context *ctx, GLenum target) -{ - switch (target) { - case GL_ARRAY_BUFFER_ARB: - return &ctx->Array.ArrayBufferObj; - case GL_ELEMENT_ARRAY_BUFFER_ARB: - return &ctx->Array.ElementArrayBufferObj; - case GL_PIXEL_PACK_BUFFER_EXT: - return &ctx->Pack.BufferObj; - case GL_PIXEL_UNPACK_BUFFER_EXT: - return &ctx->Unpack.BufferObj; - case GL_COPY_READ_BUFFER: - return &ctx->CopyReadBuffer; - case GL_COPY_WRITE_BUFFER: - return &ctx->CopyWriteBuffer; -#if FEATURE_EXT_transform_feedback - case GL_TRANSFORM_FEEDBACK_BUFFER: - if (ctx->Extensions.EXT_transform_feedback) { - return &ctx->TransformFeedback.CurrentBuffer; - } - break; -#endif - default: - return NULL; - } - return NULL; -} - - -/** - * Get the buffer object bound to the specified target in a GL context. - * \param ctx the GL context - * \param target the buffer object target to be retrieved. - * \return pointer to the buffer object bound to \c target in the - * specified context or \c NULL if \c target is invalid. - */ -static INLINE struct gl_buffer_object * -get_buffer(struct gl_context *ctx, GLenum target) -{ - struct gl_buffer_object **bufObj = get_buffer_target(ctx, target); - if (bufObj) - return *bufObj; - return NULL; -} - - -/** - * Convert a GLbitfield describing the mapped buffer access flags - * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY. - */ -static GLenum -simplified_access_mode(GLbitfield access) -{ - const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; - if ((access & rwFlags) == rwFlags) - return GL_READ_WRITE; - if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT) - return GL_READ_ONLY; - if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT) - return GL_WRITE_ONLY; - return GL_READ_WRITE; /* this should never happen, but no big deal */ -} - - -/** - * Tests the subdata range parameters and sets the GL error code for - * \c glBufferSubDataARB and \c glGetBufferSubDataARB. - * - * \param ctx GL context. - * \param target Buffer object target on which to operate. - * \param offset Offset of the first byte of the subdata range. - * \param size Size, in bytes, of the subdata range. - * \param caller Name of calling function for recording errors. - * \return A pointer to the buffer object bound to \c target in the - * specified context or \c NULL if any of the parameter or state - * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB - * are invalid. - * - * \sa glBufferSubDataARB, glGetBufferSubDataARB - */ -static struct gl_buffer_object * -buffer_object_subdata_range_good( struct gl_context * ctx, GLenum target, - GLintptrARB offset, GLsizeiptrARB size, - const char *caller ) -{ - struct gl_buffer_object *bufObj; - - if (size < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller); - return NULL; - } - - if (offset < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller); - return NULL; - } - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller); - return NULL; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); - return NULL; - } - if (offset + size > bufObj->Size) { - _mesa_error(ctx, GL_INVALID_VALUE, - "%s(size + offset > buffer size)", caller); - return NULL; - } - if (_mesa_bufferobj_mapped(bufObj)) { - /* Buffer is currently mapped */ - _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); - return NULL; - } - - return bufObj; -} - - -/** - * Allocate and initialize a new buffer object. - * - * Default callback for the \c dd_function_table::NewBufferObject() hook. - */ -static struct gl_buffer_object * -_mesa_new_buffer_object( struct gl_context *ctx, GLuint name, GLenum target ) -{ - struct gl_buffer_object *obj; - - (void) ctx; - - obj = MALLOC_STRUCT(gl_buffer_object); - _mesa_initialize_buffer_object(obj, name, target); - return obj; -} - - -/** - * Delete a buffer object. - * - * Default callback for the \c dd_function_table::DeleteBuffer() hook. - */ -static void -_mesa_delete_buffer_object( struct gl_context *ctx, struct gl_buffer_object *bufObj ) -{ - (void) ctx; - - if (bufObj->Data) - free(bufObj->Data); - - /* assign strange values here to help w/ debugging */ - bufObj->RefCount = -1000; - bufObj->Name = ~0; - - _glthread_DESTROY_MUTEX(bufObj->Mutex); - free(bufObj); -} - - - -/** - * Set ptr to bufObj w/ reference counting. - */ -void -_mesa_reference_buffer_object(struct gl_context *ctx, - struct gl_buffer_object **ptr, - struct gl_buffer_object *bufObj) -{ - if (*ptr == bufObj) - return; - - if (*ptr) { - /* Unreference the old buffer */ - GLboolean deleteFlag = GL_FALSE; - struct gl_buffer_object *oldObj = *ptr; - - _glthread_LOCK_MUTEX(oldObj->Mutex); - ASSERT(oldObj->RefCount > 0); - oldObj->RefCount--; -#if 0 - printf("BufferObj %p %d DECR to %d\n", - (void *) oldObj, oldObj->Name, oldObj->RefCount); -#endif - deleteFlag = (oldObj->RefCount == 0); - _glthread_UNLOCK_MUTEX(oldObj->Mutex); - - if (deleteFlag) { - - /* some sanity checking: don't delete a buffer still in use */ -#if 0 - /* unfortunately, these tests are invalid during context tear-down */ - ASSERT(ctx->Array.ArrayBufferObj != bufObj); - ASSERT(ctx->Array.ElementArrayBufferObj != bufObj); - ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj); -#endif - - ASSERT(ctx->Driver.DeleteBuffer); - ctx->Driver.DeleteBuffer(ctx, oldObj); - } - - *ptr = NULL; - } - ASSERT(!*ptr); - - if (bufObj) { - /* reference new buffer */ - _glthread_LOCK_MUTEX(bufObj->Mutex); - if (bufObj->RefCount == 0) { - /* this buffer's being deleted (look just above) */ - /* Not sure this can every really happen. Warn if it does. */ - _mesa_problem(NULL, "referencing deleted buffer object"); - *ptr = NULL; - } - else { - bufObj->RefCount++; -#if 0 - printf("BufferObj %p %d INCR to %d\n", - (void *) bufObj, bufObj->Name, bufObj->RefCount); -#endif - *ptr = bufObj; - } - _glthread_UNLOCK_MUTEX(bufObj->Mutex); - } -} - - -/** - * Initialize a buffer object to default values. - */ -void -_mesa_initialize_buffer_object( struct gl_buffer_object *obj, - GLuint name, GLenum target ) -{ - (void) target; - - memset(obj, 0, sizeof(struct gl_buffer_object)); - _glthread_INIT_MUTEX(obj->Mutex); - obj->RefCount = 1; - obj->Name = name; - obj->Usage = GL_STATIC_DRAW_ARB; - obj->AccessFlags = DEFAULT_ACCESS; -} - - -/** - * Allocate space for and store data in a buffer object. Any data that was - * previously stored in the buffer object is lost. If \c data is \c NULL, - * memory will be allocated, but no copy will occur. - * - * This is the default callback for \c dd_function_table::BufferData() - * Note that all GL error checking will have been done already. - * - * \param ctx GL context. - * \param target Buffer object target on which to operate. - * \param size Size, in bytes, of the new data store. - * \param data Pointer to the data to store in the buffer object. This - * pointer may be \c NULL. - * \param usage Hints about how the data will be used. - * \param bufObj Object to be used. - * - * \return GL_TRUE for success, GL_FALSE for failure - * \sa glBufferDataARB, dd_function_table::BufferData. - */ -static GLboolean -_mesa_buffer_data( struct gl_context *ctx, GLenum target, GLsizeiptrARB size, - const GLvoid * data, GLenum usage, - struct gl_buffer_object * bufObj ) -{ - void * new_data; - - (void) ctx; (void) target; - - new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size ); - if (new_data) { - bufObj->Data = (GLubyte *) new_data; - bufObj->Size = size; - bufObj->Usage = usage; - - if (data) { - memcpy( bufObj->Data, data, size ); - } - - return GL_TRUE; - } - else { - return GL_FALSE; - } -} - - -/** - * Replace data in a subrange of buffer object. If the data range - * specified by \c size + \c offset extends beyond the end of the buffer or - * if \c data is \c NULL, no copy is performed. - * - * This is the default callback for \c dd_function_table::BufferSubData() - * Note that all GL error checking will have been done already. - * - * \param ctx GL context. - * \param target Buffer object target on which to operate. - * \param offset Offset of the first byte to be modified. - * \param size Size, in bytes, of the data range. - * \param data Pointer to the data to store in the buffer object. - * \param bufObj Object to be used. - * - * \sa glBufferSubDataARB, dd_function_table::BufferSubData. - */ -static void -_mesa_buffer_subdata( struct gl_context *ctx, GLenum target, GLintptrARB offset, - GLsizeiptrARB size, const GLvoid * data, - struct gl_buffer_object * bufObj ) -{ - (void) ctx; (void) target; - - /* this should have been caught in _mesa_BufferSubData() */ - ASSERT(size + offset <= bufObj->Size); - - if (bufObj->Data) { - memcpy( (GLubyte *) bufObj->Data + offset, data, size ); - } -} - - -/** - * Retrieve data from a subrange of buffer object. If the data range - * specified by \c size + \c offset extends beyond the end of the buffer or - * if \c data is \c NULL, no copy is performed. - * - * This is the default callback for \c dd_function_table::GetBufferSubData() - * Note that all GL error checking will have been done already. - * - * \param ctx GL context. - * \param target Buffer object target on which to operate. - * \param offset Offset of the first byte to be fetched. - * \param size Size, in bytes, of the data range. - * \param data Destination for data - * \param bufObj Object to be used. - * - * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData. - */ -static void -_mesa_buffer_get_subdata( struct gl_context *ctx, GLenum target, GLintptrARB offset, - GLsizeiptrARB size, GLvoid * data, - struct gl_buffer_object * bufObj ) -{ - (void) ctx; (void) target; - - if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) { - memcpy( data, (GLubyte *) bufObj->Data + offset, size ); - } -} - - -/** - * Default callback for \c dd_function_tabel::MapBuffer(). - * - * The function parameters will have been already tested for errors. - * - * \param ctx GL context. - * \param target Buffer object target on which to operate. - * \param access Information about how the buffer will be accessed. - * \param bufObj Object to be mapped. - * \return A pointer to the object's internal data store that can be accessed - * by the processor - * - * \sa glMapBufferARB, dd_function_table::MapBuffer - */ -static void * -_mesa_buffer_map( struct gl_context *ctx, GLenum target, GLenum access, - struct gl_buffer_object *bufObj ) -{ - (void) ctx; - (void) target; - (void) access; - /* Just return a direct pointer to the data */ - if (_mesa_bufferobj_mapped(bufObj)) { - /* already mapped! */ - return NULL; - } - bufObj->Pointer = bufObj->Data; - bufObj->Length = bufObj->Size; - bufObj->Offset = 0; - return bufObj->Pointer; -} - - -/** - * Default fallback for \c dd_function_table::MapBufferRange(). - * Called via glMapBufferRange(). - */ -static void * -_mesa_buffer_map_range( struct gl_context *ctx, GLenum target, GLintptr offset, - GLsizeiptr length, GLbitfield access, - struct gl_buffer_object *bufObj ) -{ - (void) ctx; - (void) target; - assert(!_mesa_bufferobj_mapped(bufObj)); - /* Just return a direct pointer to the data */ - bufObj->Pointer = bufObj->Data + offset; - bufObj->Length = length; - bufObj->Offset = offset; - bufObj->AccessFlags = access; - return bufObj->Pointer; -} - - -/** - * Default fallback for \c dd_function_table::FlushMappedBufferRange(). - * Called via glFlushMappedBufferRange(). - */ -static void -_mesa_buffer_flush_mapped_range( struct gl_context *ctx, GLenum target, - GLintptr offset, GLsizeiptr length, - struct gl_buffer_object *obj ) -{ - (void) ctx; - (void) target; - (void) offset; - (void) length; - (void) obj; - /* no-op */ -} - - -/** - * Default callback for \c dd_function_table::MapBuffer(). - * - * The input parameters will have been already tested for errors. - * - * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer - */ -static GLboolean -_mesa_buffer_unmap( struct gl_context *ctx, GLenum target, - struct gl_buffer_object *bufObj ) -{ - (void) ctx; - (void) target; - /* XXX we might assert here that bufObj->Pointer is non-null */ - bufObj->Pointer = NULL; - bufObj->Length = 0; - bufObj->Offset = 0; - bufObj->AccessFlags = 0x0; - return GL_TRUE; -} - - -/** - * Default fallback for \c dd_function_table::CopyBufferSubData(). - * Called via glCopyBuffserSubData(). - */ -static void -_mesa_copy_buffer_subdata(struct gl_context *ctx, - struct gl_buffer_object *src, - struct gl_buffer_object *dst, - GLintptr readOffset, GLintptr writeOffset, - GLsizeiptr size) -{ - GLubyte *srcPtr, *dstPtr; - - /* buffer should not already be mapped */ - assert(!_mesa_bufferobj_mapped(src)); - assert(!_mesa_bufferobj_mapped(dst)); - - srcPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_READ_BUFFER, - GL_READ_ONLY, src); - dstPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_WRITE_BUFFER, - GL_WRITE_ONLY, dst); - - if (srcPtr && dstPtr) - memcpy(dstPtr + writeOffset, srcPtr + readOffset, size); - - ctx->Driver.UnmapBuffer(ctx, GL_COPY_READ_BUFFER, src); - ctx->Driver.UnmapBuffer(ctx, GL_COPY_WRITE_BUFFER, dst); -} - - - -/** - * Initialize the state associated with buffer objects - */ -void -_mesa_init_buffer_objects( struct gl_context *ctx ) -{ - memset(&DummyBufferObject, 0, sizeof(DummyBufferObject)); - DummyBufferObject.RefCount = 1000*1000*1000; /* never delete */ - - _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, - ctx->Shared->NullBufferObj); - _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, - ctx->Shared->NullBufferObj); - - _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, - ctx->Shared->NullBufferObj); - _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, - ctx->Shared->NullBufferObj); -} - - -void -_mesa_free_buffer_objects( struct gl_context *ctx ) -{ - _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL); - _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL); - - _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL); - _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL); -} - - -/** - * Bind the specified target to buffer for the specified context. - * Called by glBindBuffer() and other functions. - */ -static void -bind_buffer_object(struct gl_context *ctx, GLenum target, GLuint buffer) -{ - struct gl_buffer_object *oldBufObj; - struct gl_buffer_object *newBufObj = NULL; - struct gl_buffer_object **bindTarget = NULL; - - bindTarget = get_buffer_target(ctx, target); - if (!bindTarget) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target); - return; - } - - /* Get pointer to old buffer object (to be unbound) */ - oldBufObj = *bindTarget; - if (oldBufObj && oldBufObj->Name == buffer) - return; /* rebinding the same buffer object- no change */ - - /* - * Get pointer to new buffer object (newBufObj) - */ - if (buffer == 0) { - /* The spec says there's not a buffer object named 0, but we use - * one internally because it simplifies things. - */ - newBufObj = ctx->Shared->NullBufferObj; - } - else { - /* non-default buffer object */ - newBufObj = _mesa_lookup_bufferobj(ctx, buffer); - if (!newBufObj || newBufObj == &DummyBufferObject) { - /* If this is a new buffer object id, or one which was generated but - * never used before, allocate a buffer object now. - */ - ASSERT(ctx->Driver.NewBufferObject); - newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target); - if (!newBufObj) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB"); - return; - } - _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj); - } - } - - /* bind new buffer */ - _mesa_reference_buffer_object(ctx, bindTarget, newBufObj); - - /* Pass BindBuffer call to device driver */ - if (ctx->Driver.BindBuffer) - ctx->Driver.BindBuffer( ctx, target, newBufObj ); -} - - -/** - * Update the default buffer objects in the given context to reference those - * specified in the shared state and release those referencing the old - * shared state. - */ -void -_mesa_update_default_objects_buffer_objects(struct gl_context *ctx) -{ - /* Bind the NullBufferObj to remove references to those - * in the shared context hash table. - */ - bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0); - bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0); - bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0); -} - - -/** - * When we're about to read pixel data out of a PBO (via glDrawPixels, - * glTexImage, etc) or write data into a PBO (via glReadPixels, - * glGetTexImage, etc) we call this function to check that we're not - * going to read out of bounds. - * - * XXX This would also be a convenient time to check that the PBO isn't - * currently mapped. Whoever calls this function should check for that. - * Remember, we can't use a PBO when it's mapped! - * - * If we're not using a PBO, this is a no-op. - * - * \param width width of image to read/write - * \param height height of image to read/write - * \param depth depth of image to read/write - * \param format format of image to read/write - * \param type datatype of image to read/write - * \param ptr the user-provided pointer/offset - * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would - * go out of bounds. - */ -GLboolean -_mesa_validate_pbo_access(GLuint dimensions, - const struct gl_pixelstore_attrib *pack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *ptr) -{ - GLvoid *start, *end; - const GLubyte *sizeAddr; /* buffer size, cast to a pointer */ - - if (!_mesa_is_bufferobj(pack->BufferObj)) - return GL_TRUE; /* no PBO, OK */ - - if (pack->BufferObj->Size == 0) - /* no buffer! */ - return GL_FALSE; - - /* get address of first pixel we'll read */ - start = _mesa_image_address(dimensions, pack, ptr, width, height, - format, type, 0, 0, 0); - - /* get address just past the last pixel we'll read */ - end = _mesa_image_address(dimensions, pack, ptr, width, height, - format, type, depth-1, height-1, width); - - - sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size; - - if ((const GLubyte *) start > sizeAddr) { - /* This will catch negative values / wrap-around */ - return GL_FALSE; - } - if ((const GLubyte *) end > sizeAddr) { - /* Image read goes beyond end of buffer */ - return GL_FALSE; - } - - /* OK! */ - return GL_TRUE; -} - - -/** - * For commands that read from a PBO (glDrawPixels, glTexImage, - * glPolygonStipple, etc), if we're reading from a PBO, map it read-only - * and return the pointer into the PBO. If we're not reading from a - * PBO, return \p src as-is. - * If non-null return, must call _mesa_unmap_pbo_source() when done. - * - * \return NULL if error, else pointer to start of data - */ -const GLvoid * -_mesa_map_pbo_source(struct gl_context *ctx, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *src) -{ - const GLubyte *buf; - - if (_mesa_is_bufferobj(unpack->BufferObj)) { - /* unpack from PBO */ - buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, - GL_READ_ONLY_ARB, - unpack->BufferObj); - if (!buf) - return NULL; - - buf = ADD_POINTERS(buf, src); - } - else { - /* unpack from normal memory */ - buf = src; - } - - return buf; -} - - -/** - * Combine PBO-read validation and mapping. - * If any GL errors are detected, they'll be recorded and NULL returned. - * \sa _mesa_validate_pbo_access - * \sa _mesa_map_pbo_source - * A call to this function should have a matching call to - * _mesa_unmap_pbo_source(). - */ -const GLvoid * -_mesa_map_validate_pbo_source(struct gl_context *ctx, - GLuint dimensions, - const struct gl_pixelstore_attrib *unpack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *ptr, - const char *where) -{ - ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); - - if (!_mesa_is_bufferobj(unpack->BufferObj)) { - /* non-PBO access: no validation to be done */ - return ptr; - } - - if (!_mesa_validate_pbo_access(dimensions, unpack, - width, height, depth, format, type, ptr)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(out of bounds PBO access)", where); - return NULL; - } - - if (_mesa_bufferobj_mapped(unpack->BufferObj)) { - /* buffer is already mapped - that's an error */ - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); - return NULL; - } - - ptr = _mesa_map_pbo_source(ctx, unpack, ptr); - return ptr; -} - - -/** - * Counterpart to _mesa_map_pbo_source() - */ -void -_mesa_unmap_pbo_source(struct gl_context *ctx, - const struct gl_pixelstore_attrib *unpack) -{ - ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */ - if (_mesa_is_bufferobj(unpack->BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, - unpack->BufferObj); - } -} - - -/** - * For commands that write to a PBO (glReadPixels, glGetColorTable, etc), - * if we're writing to a PBO, map it write-only and return the pointer - * into the PBO. If we're not writing to a PBO, return \p dst as-is. - * If non-null return, must call _mesa_unmap_pbo_dest() when done. - * - * \return NULL if error, else pointer to start of data - */ -void * -_mesa_map_pbo_dest(struct gl_context *ctx, - const struct gl_pixelstore_attrib *pack, - GLvoid *dest) -{ - void *buf; - - if (_mesa_is_bufferobj(pack->BufferObj)) { - /* pack into PBO */ - buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, - GL_WRITE_ONLY_ARB, - pack->BufferObj); - if (!buf) - return NULL; - - buf = ADD_POINTERS(buf, dest); - } - else { - /* pack to normal memory */ - buf = dest; - } - - return buf; -} - - -/** - * Combine PBO-write validation and mapping. - * If any GL errors are detected, they'll be recorded and NULL returned. - * \sa _mesa_validate_pbo_access - * \sa _mesa_map_pbo_dest - * A call to this function should have a matching call to - * _mesa_unmap_pbo_dest(). - */ -GLvoid * -_mesa_map_validate_pbo_dest(struct gl_context *ctx, - GLuint dimensions, - const struct gl_pixelstore_attrib *unpack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, GLvoid *ptr, - const char *where) -{ - ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); - - if (!_mesa_is_bufferobj(unpack->BufferObj)) { - /* non-PBO access: no validation to be done */ - return ptr; - } - - if (!_mesa_validate_pbo_access(dimensions, unpack, - width, height, depth, format, type, ptr)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(out of bounds PBO access)", where); - return NULL; - } - - if (_mesa_bufferobj_mapped(unpack->BufferObj)) { - /* buffer is already mapped - that's an error */ - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); - return NULL; - } - - ptr = _mesa_map_pbo_dest(ctx, unpack, ptr); - return ptr; -} - - -/** - * Counterpart to _mesa_map_pbo_dest() - */ -void -_mesa_unmap_pbo_dest(struct gl_context *ctx, - const struct gl_pixelstore_attrib *pack) -{ - ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */ - if (_mesa_is_bufferobj(pack->BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj); - } -} - - - -/** - * Return the gl_buffer_object for the given ID. - * Always return NULL for ID 0. - */ -struct gl_buffer_object * -_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer) -{ - if (buffer == 0) - return NULL; - else - return (struct gl_buffer_object *) - _mesa_HashLookup(ctx->Shared->BufferObjects, buffer); -} - - -/** - * If *ptr points to obj, set ptr = the Null/default buffer object. - * This is a helper for buffer object deletion. - * The GL spec says that deleting a buffer object causes it to get - * unbound from all arrays in the current context. - */ -static void -unbind(struct gl_context *ctx, - struct gl_buffer_object **ptr, - struct gl_buffer_object *obj) -{ - if (*ptr == obj) { - _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj); - } -} - - -/** - * Plug default/fallback buffer object functions into the device - * driver hooks. - */ -void -_mesa_init_buffer_object_functions(struct dd_function_table *driver) -{ - /* GL_ARB_vertex/pixel_buffer_object */ - driver->NewBufferObject = _mesa_new_buffer_object; - driver->DeleteBuffer = _mesa_delete_buffer_object; - driver->BindBuffer = NULL; - driver->BufferData = _mesa_buffer_data; - driver->BufferSubData = _mesa_buffer_subdata; - driver->GetBufferSubData = _mesa_buffer_get_subdata; - driver->MapBuffer = _mesa_buffer_map; - driver->UnmapBuffer = _mesa_buffer_unmap; - - /* GL_ARB_map_buffer_range */ - driver->MapBufferRange = _mesa_buffer_map_range; - driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range; - - /* GL_ARB_copy_buffer */ - driver->CopyBufferSubData = _mesa_copy_buffer_subdata; -} - - - -/**********************************************************************/ -/* API Functions */ -/**********************************************************************/ - -void GLAPIENTRY -_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); -} - - -/** - * Delete a set of buffer objects. - * - * \param n Number of buffer objects to delete. - * \param ids Array of \c n buffer object IDs. - */ -void GLAPIENTRY -_mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids) -{ - GET_CURRENT_CONTEXT(ctx); - GLsizei i; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)"); - return; - } - - _glthread_LOCK_MUTEX(ctx->Shared->Mutex); - - for (i = 0; i < n; i++) { - struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]); - if (bufObj) { - struct gl_array_object *arrayObj = ctx->Array.ArrayObj; - GLuint j; - - ASSERT(bufObj->Name == ids[i] || bufObj == &DummyBufferObject); - - if (_mesa_bufferobj_mapped(bufObj)) { - /* if mapped, unmap it now */ - ctx->Driver.UnmapBuffer(ctx, 0, bufObj); - bufObj->AccessFlags = DEFAULT_ACCESS; - bufObj->Pointer = NULL; - } - - /* unbind any vertex pointers bound to this buffer */ - unbind(ctx, &arrayObj->Vertex.BufferObj, bufObj); - unbind(ctx, &arrayObj->Weight.BufferObj, bufObj); - unbind(ctx, &arrayObj->Normal.BufferObj, bufObj); - unbind(ctx, &arrayObj->Color.BufferObj, bufObj); - unbind(ctx, &arrayObj->SecondaryColor.BufferObj, bufObj); - unbind(ctx, &arrayObj->FogCoord.BufferObj, bufObj); - unbind(ctx, &arrayObj->Index.BufferObj, bufObj); - unbind(ctx, &arrayObj->EdgeFlag.BufferObj, bufObj); - for (j = 0; j < Elements(arrayObj->TexCoord); j++) { - unbind(ctx, &arrayObj->TexCoord[j].BufferObj, bufObj); - } - for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) { - unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj); - } - - if (ctx->Array.ArrayBufferObj == bufObj) { - _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 ); - } - if (ctx->Array.ElementArrayBufferObj == bufObj) { - _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); - } - - /* unbind any pixel pack/unpack pointers bound to this buffer */ - if (ctx->Pack.BufferObj == bufObj) { - _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 ); - } - if (ctx->Unpack.BufferObj == bufObj) { - _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 ); - } - - /* The ID is immediately freed for re-use */ - _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]); - _mesa_reference_buffer_object(ctx, &bufObj, NULL); - } - } - - _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); -} - - -/** - * Generate a set of unique buffer object IDs and store them in \c buffer. - * - * \param n Number of IDs to generate. - * \param buffer Array of \c n locations to store the IDs. - */ -void GLAPIENTRY -_mesa_GenBuffersARB(GLsizei n, GLuint *buffer) -{ - GET_CURRENT_CONTEXT(ctx); - GLuint first; - 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; - } - - if (!buffer) { - return; - } - - /* - * This must be atomic (generation and allocation of buffer object IDs) - */ - _glthread_LOCK_MUTEX(ctx->Shared->Mutex); - - first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n); - - /* Insert the ID and pointer to dummy buffer object into hash table */ - for (i = 0; i < n; i++) { - _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, - &DummyBufferObject); - buffer[i] = first + i; - } - - _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); -} - - -/** - * Determine if ID is the name of a buffer object. - * - * \param id ID of the potential buffer object. - * \return \c GL_TRUE if \c id is the name of a buffer object, - * \c GL_FALSE otherwise. - */ -GLboolean GLAPIENTRY -_mesa_IsBufferARB(GLuint id) -{ - struct gl_buffer_object *bufObj; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - - _glthread_LOCK_MUTEX(ctx->Shared->Mutex); - bufObj = _mesa_lookup_bufferobj(ctx, id); - _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); - - return bufObj && bufObj != &DummyBufferObject; -} - - -void GLAPIENTRY -_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, - const GLvoid * data, GLenum usage) -{ - GET_CURRENT_CONTEXT(ctx); - 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; - } - - switch (usage) { - case GL_STREAM_DRAW_ARB: - case GL_STREAM_READ_ARB: - case GL_STREAM_COPY_ARB: - case GL_STATIC_DRAW_ARB: - case GL_STATIC_READ_ARB: - case GL_STATIC_COPY_ARB: - case GL_DYNAMIC_DRAW_ARB: - case GL_DYNAMIC_READ_ARB: - case GL_DYNAMIC_COPY_ARB: - /* OK */ - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)"); - return; - } - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" ); - return; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer 0)" ); - return; - } - - if (_mesa_bufferobj_mapped(bufObj)) { - /* Unmap the existing buffer. We'll replace it now. Not an error. */ - ctx->Driver.UnmapBuffer(ctx, target, bufObj); - bufObj->AccessFlags = DEFAULT_ACCESS; - ASSERT(bufObj->Pointer == NULL); - } - - FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT); - - bufObj->Written = GL_TRUE; - -#ifdef VBO_DEBUG - printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n", - bufObj->Name, size, data, usage); -#endif - -#ifdef BOUNDS_CHECK - size += 100; -#endif - - ASSERT(ctx->Driver.BufferData); - if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()"); - } -} - - -void GLAPIENTRY -_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset, - GLsizeiptrARB size, const GLvoid * data) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, - "glBufferSubDataARB" ); - if (!bufObj) { - /* error already recorded */ - return; - } - - if (size == 0) - return; - - bufObj->Written = GL_TRUE; - - ASSERT(ctx->Driver.BufferSubData); - ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj ); -} - - -void GLAPIENTRY -_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset, - GLsizeiptrARB size, void * data) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, - "glGetBufferSubDataARB" ); - if (!bufObj) { - /* error already recorded */ - return; - } - - ASSERT(ctx->Driver.GetBufferSubData); - ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj ); -} - - -void * GLAPIENTRY -_mesa_MapBufferARB(GLenum target, GLenum access) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object * bufObj; - GLbitfield accessFlags; - void *map; - - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); - - switch (access) { - case GL_READ_ONLY_ARB: - accessFlags = GL_MAP_READ_BIT; - break; - case GL_WRITE_ONLY_ARB: - accessFlags = GL_MAP_WRITE_BIT; - break; - case GL_READ_WRITE_ARB: - accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)"); - return NULL; - } - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" ); - return NULL; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(buffer 0)" ); - return NULL; - } - if (_mesa_bufferobj_mapped(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)"); - return NULL; - } - - ASSERT(ctx->Driver.MapBuffer); - map = ctx->Driver.MapBuffer( ctx, target, access, bufObj ); - if (!map) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); - return NULL; - } - else { - /* The driver callback should have set these fields. - * This is important because other modules (like VBO) might call - * the driver function directly. - */ - ASSERT(bufObj->Pointer == map); - ASSERT(bufObj->Length == bufObj->Size); - ASSERT(bufObj->Offset == 0); - bufObj->AccessFlags = accessFlags; - } - - if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB) - bufObj->Written = GL_TRUE; - -#ifdef VBO_DEBUG - printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n", - bufObj->Name, bufObj->Size, access); - if (access == GL_WRITE_ONLY_ARB) { - GLuint i; - GLubyte *b = (GLubyte *) bufObj->Pointer; - for (i = 0; i < bufObj->Size; i++) - b[i] = i & 0xff; - } -#endif - -#ifdef BOUNDS_CHECK - { - GLubyte *buf = (GLubyte *) bufObj->Pointer; - GLuint i; - /* buffer is 100 bytes larger than requested, fill with magic value */ - for (i = 0; i < 100; i++) { - buf[bufObj->Size - i - 1] = 123; - } - } -#endif - - return bufObj->Pointer; -} - - -GLboolean GLAPIENTRY -_mesa_UnmapBufferARB(GLenum target) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - GLboolean status = GL_TRUE; - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" ); - return GL_FALSE; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" ); - return GL_FALSE; - } - if (!_mesa_bufferobj_mapped(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB"); - return GL_FALSE; - } - -#ifdef BOUNDS_CHECK - if (bufObj->Access != GL_READ_ONLY_ARB) { - GLubyte *buf = (GLubyte *) bufObj->Pointer; - GLuint i; - /* check that last 100 bytes are still = magic value */ - for (i = 0; i < 100; i++) { - GLuint pos = bufObj->Size - i - 1; - if (buf[pos] != 123) { - _mesa_warning(ctx, "Out of bounds buffer object write detected" - " at position %d (value = %u)\n", - pos, buf[pos]); - } - } - } -#endif - -#ifdef VBO_DEBUG - if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) { - GLuint i, unchanged = 0; - GLubyte *b = (GLubyte *) bufObj->Pointer; - GLint pos = -1; - /* check which bytes changed */ - for (i = 0; i < bufObj->Size - 1; i++) { - if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) { - unchanged++; - if (pos == -1) - pos = i; - } - } - if (unchanged) { - printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n", - bufObj->Name, unchanged, bufObj->Size, pos); - } - } -#endif - - status = ctx->Driver.UnmapBuffer( ctx, target, bufObj ); - bufObj->AccessFlags = DEFAULT_ACCESS; - ASSERT(bufObj->Pointer == NULL); - ASSERT(bufObj->Offset == 0); - ASSERT(bufObj->Length == 0); - - return status; -} - - -void GLAPIENTRY -_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(target)" ); - return; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameterivARB" ); - return; - } - - switch (pname) { - case GL_BUFFER_SIZE_ARB: - *params = (GLint) bufObj->Size; - return; - case GL_BUFFER_USAGE_ARB: - *params = bufObj->Usage; - return; - case GL_BUFFER_ACCESS_ARB: - *params = simplified_access_mode(bufObj->AccessFlags); - return; - case GL_BUFFER_MAPPED_ARB: - *params = _mesa_bufferobj_mapped(bufObj); - return; - case GL_BUFFER_ACCESS_FLAGS: - if (ctx->VersionMajor < 3) - goto invalid_pname; - *params = bufObj->AccessFlags; - return; - case GL_BUFFER_MAP_OFFSET: - if (ctx->VersionMajor < 3) - goto invalid_pname; - *params = (GLint) bufObj->Offset; - return; - case GL_BUFFER_MAP_LENGTH: - if (ctx->VersionMajor < 3) - goto invalid_pname; - *params = (GLint) bufObj->Length; - return; - default: - ; /* fall-through */ - } - -invalid_pname: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)", - _mesa_lookup_enum_by_nr(pname)); -} - - -/** - * New in GL 3.2 - * This is pretty much a duplicate of GetBufferParameteriv() but the - * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system. - */ -void GLAPIENTRY -_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(target)" ); - return; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameteri64v" ); - return; - } - - switch (pname) { - case GL_BUFFER_SIZE_ARB: - *params = bufObj->Size; - return; - case GL_BUFFER_USAGE_ARB: - *params = bufObj->Usage; - return; - case GL_BUFFER_ACCESS_ARB: - *params = simplified_access_mode(bufObj->AccessFlags); - return; - case GL_BUFFER_ACCESS_FLAGS: - if (ctx->VersionMajor < 3) - goto invalid_pname; - *params = bufObj->AccessFlags; - return; - case GL_BUFFER_MAPPED_ARB: - *params = _mesa_bufferobj_mapped(bufObj); - return; - case GL_BUFFER_MAP_OFFSET: - if (ctx->VersionMajor < 3) - goto invalid_pname; - *params = bufObj->Offset; - return; - case GL_BUFFER_MAP_LENGTH: - if (ctx->VersionMajor < 3) - goto invalid_pname; - *params = bufObj->Length; - return; - default: - ; /* fall-through */ - } - -invalid_pname: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)", - _mesa_lookup_enum_by_nr(pname)); -} - - -void GLAPIENTRY -_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object * bufObj; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (pname != GL_BUFFER_MAP_POINTER_ARB) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)"); - return; - } - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" ); - return; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" ); - return; - } - - *params = bufObj->Pointer; -} - - -void GLAPIENTRY -_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, - GLintptr readOffset, GLintptr writeOffset, - GLsizeiptr size) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *src, *dst; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - src = get_buffer(ctx, readTarget); - if (!src || !_mesa_is_bufferobj(src)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glCopyBuffserSubData(readTarget = 0x%x)", readTarget); - return; - } - - dst = get_buffer(ctx, writeTarget); - if (!dst || !_mesa_is_bufferobj(dst)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget); - return; - } - - if (_mesa_bufferobj_mapped(src)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyBuffserSubData(readBuffer is mapped)"); - return; - } - - if (_mesa_bufferobj_mapped(dst)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyBuffserSubData(writeBuffer is mapped)"); - return; - } - - if (readOffset < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBuffserSubData(readOffset = %d)", (int) readOffset); - return; - } - - if (writeOffset < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBuffserSubData(writeOffset = %d)", (int) writeOffset); - return; - } - - if (readOffset + size > src->Size) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBuffserSubData(readOffset + size = %d)", - (int) (readOffset + size)); - return; - } - - if (writeOffset + size > dst->Size) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBuffserSubData(writeOffset + size = %d)", - (int) (writeOffset + size)); - return; - } - - if (src == dst) { - if (readOffset + size <= writeOffset) { - /* OK */ - } - else if (writeOffset + size <= readOffset) { - /* OK */ - } - else { - /* overlapping src/dst is illegal */ - _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyBuffserSubData(overlapping src/dst)"); - return; - } - } - - ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size); -} - - -/** - * See GL_ARB_map_buffer_range spec - */ -void * GLAPIENTRY -_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, - GLbitfield access) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - void *map; - - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); - - if (!ctx->Extensions.ARB_map_buffer_range) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(extension not supported)"); - return NULL; - } - - if (offset < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(offset = %ld)", (long)offset); - return NULL; - } - - if (length < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(length = %ld)", (long)length); - return NULL; - } - - if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(access indicates neither read or write)"); - return NULL; - } - - if (access & GL_MAP_READ_BIT) { - if ((access & GL_MAP_INVALIDATE_RANGE_BIT) || - (access & GL_MAP_INVALIDATE_BUFFER_BIT) || - (access & GL_MAP_UNSYNCHRONIZED_BIT)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(invalid access flags)"); - return NULL; - } - } - - if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) && - ((access & GL_MAP_WRITE_BIT) == 0)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(invalid access flags)"); - return NULL; - } - - bufObj = get_buffer(ctx, target); - if (!bufObj || !_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glMapBufferRange(target = 0x%x)", target); - return NULL; - } - - if (offset + length > bufObj->Size) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(offset + length > size)"); - return NULL; - } - - if (_mesa_bufferobj_mapped(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(buffer already mapped)"); - return NULL; - } - - ASSERT(ctx->Driver.MapBufferRange); - map = ctx->Driver.MapBufferRange(ctx, target, offset, length, - access, bufObj); - if (!map) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); - } - else { - /* The driver callback should have set all these fields. - * This is important because other modules (like VBO) might call - * the driver function directly. - */ - ASSERT(bufObj->Pointer == map); - ASSERT(bufObj->Length == length); - ASSERT(bufObj->Offset == offset); - ASSERT(bufObj->AccessFlags == access); - } - - return map; -} - - -/** - * See GL_ARB_map_buffer_range spec - */ -void GLAPIENTRY -_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) -{ - GET_CURRENT_CONTEXT(ctx); - struct gl_buffer_object *bufObj; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!ctx->Extensions.ARB_map_buffer_range) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(extension not supported)"); - return; - } - - if (offset < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(offset = %ld)", (long)offset); - return; - } - - if (length < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(length = %ld)", (long)length); - return; - } - - bufObj = get_buffer(ctx, target); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glMapBufferRange(target = 0x%x)", target); - return; - } - - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(current buffer is 0)"); - return; - } - - if (!_mesa_bufferobj_mapped(bufObj)) { - /* buffer is not mapped */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(buffer is not mapped)"); - return; - } - - if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glMapBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)"); - return; - } - - if (offset + length > bufObj->Length) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glMapBufferRange(offset %ld + length %ld > mapped length %ld)", - (long)offset, (long)length, (long)bufObj->Length); - return; - } - - ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT); - - if (ctx->Driver.FlushMappedBufferRange) - ctx->Driver.FlushMappedBufferRange(ctx, target, offset, length, bufObj); -} - - -#if FEATURE_APPLE_object_purgeable -static GLenum -_mesa_BufferObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option) -{ - struct gl_buffer_object *bufObj; - GLenum retval; - - bufObj = _mesa_lookup_bufferobj(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectPurgeable(name = 0x%x)", name); - return 0; - } - if (!_mesa_is_bufferobj(bufObj)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" ); - return 0; - } - - if (bufObj->Purgeable) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glObjectPurgeable(name = 0x%x) is already purgeable", name); - return GL_VOLATILE_APPLE; - } - - bufObj->Purgeable = GL_TRUE; - - retval = GL_VOLATILE_APPLE; - if (ctx->Driver.BufferObjectPurgeable) - retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option); - - return retval; -} - - -static GLenum -_mesa_RenderObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option) -{ - struct gl_renderbuffer *bufObj; - GLenum retval; - - bufObj = _mesa_lookup_renderbuffer(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectUnpurgeable(name = 0x%x)", name); - return 0; - } - - if (bufObj->Purgeable) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glObjectPurgeable(name = 0x%x) is already purgeable", name); - return GL_VOLATILE_APPLE; - } - - bufObj->Purgeable = GL_TRUE; - - retval = GL_VOLATILE_APPLE; - if (ctx->Driver.RenderObjectPurgeable) - retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option); - - return retval; -} - - -static GLenum -_mesa_TextureObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option) -{ - struct gl_texture_object *bufObj; - GLenum retval; - - bufObj = _mesa_lookup_texture(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectPurgeable(name = 0x%x)", name); - return 0; - } - - if (bufObj->Purgeable) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glObjectPurgeable(name = 0x%x) is already purgeable", name); - return GL_VOLATILE_APPLE; - } - - bufObj->Purgeable = GL_TRUE; - - retval = GL_VOLATILE_APPLE; - if (ctx->Driver.TextureObjectPurgeable) - retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option); - - return retval; -} - - -GLenum GLAPIENTRY -_mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option) -{ - GLenum retval; - - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); - - if (name == 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectPurgeable(name = 0x%x)", name); - return 0; - } - - switch (option) { - case GL_VOLATILE_APPLE: - case GL_RELEASED_APPLE: - /* legal */ - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glObjectPurgeable(name = 0x%x) invalid option: %d", - name, option); - return 0; - } - - switch (objectType) { - case GL_TEXTURE: - retval = _mesa_TextureObjectPurgeable (ctx, name, option); - break; - case GL_RENDERBUFFER_EXT: - retval = _mesa_RenderObjectPurgeable (ctx, name, option); - break; - case GL_BUFFER_OBJECT_APPLE: - retval = _mesa_BufferObjectPurgeable (ctx, name, option); - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glObjectPurgeable(name = 0x%x) invalid type: %d", - name, objectType); - return 0; - } - - /* In strict conformance to the spec, we must only return VOLATILE when - * when passed the VOLATILE option. Madness. - * - * XXX First fix the spec, then fix me. - */ - return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval; -} - - -static GLenum -_mesa_BufferObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option) -{ - struct gl_buffer_object *bufObj; - GLenum retval; - - bufObj = _mesa_lookup_bufferobj(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectUnpurgeable(name = 0x%x)", name); - return 0; - } - - if (! bufObj->Purgeable) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glObjectUnpurgeable(name = 0x%x) object is " - " already \"unpurged\"", name); - return 0; - } - - bufObj->Purgeable = GL_FALSE; - - retval = option; - if (ctx->Driver.BufferObjectUnpurgeable) - retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option); - - return retval; -} - - -static GLenum -_mesa_RenderObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option) -{ - struct gl_renderbuffer *bufObj; - GLenum retval; - - bufObj = _mesa_lookup_renderbuffer(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectUnpurgeable(name = 0x%x)", name); - return 0; - } - - if (! bufObj->Purgeable) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glObjectUnpurgeable(name = 0x%x) object is " - " already \"unpurged\"", name); - return 0; - } - - bufObj->Purgeable = GL_FALSE; - - retval = option; - if (ctx->Driver.RenderObjectUnpurgeable) - retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option); - - return retval; -} - - -static GLenum -_mesa_TextureObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option) -{ - struct gl_texture_object *bufObj; - GLenum retval; - - bufObj = _mesa_lookup_texture(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectUnpurgeable(name = 0x%x)", name); - return 0; - } - - if (! bufObj->Purgeable) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glObjectUnpurgeable(name = 0x%x) object is" - " already \"unpurged\"", name); - return 0; - } - - bufObj->Purgeable = GL_FALSE; - - retval = option; - if (ctx->Driver.TextureObjectUnpurgeable) - retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option); - - return retval; -} - - -GLenum GLAPIENTRY -_mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); - - if (name == 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectUnpurgeable(name = 0x%x)", name); - return 0; - } - - switch (option) { - case GL_RETAINED_APPLE: - case GL_UNDEFINED_APPLE: - /* legal */ - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glObjectUnpurgeable(name = 0x%x) invalid option: %d", - name, option); - return 0; - } - - switch (objectType) { - case GL_BUFFER_OBJECT_APPLE: - return _mesa_BufferObjectUnpurgeable(ctx, name, option); - case GL_TEXTURE: - return _mesa_TextureObjectUnpurgeable(ctx, name, option); - case GL_RENDERBUFFER_EXT: - return _mesa_RenderObjectUnpurgeable(ctx, name, option); - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glObjectUnpurgeable(name = 0x%x) invalid type: %d", - name, objectType); - return 0; - } -} - - -static void -_mesa_GetBufferObjectParameterivAPPLE(struct gl_context *ctx, GLuint name, - GLenum pname, GLint* params) -{ - struct gl_buffer_object *bufObj; - - bufObj = _mesa_lookup_bufferobj(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetObjectParameteriv(name = 0x%x) invalid object", name); - return; - } - - switch (pname) { - case GL_PURGEABLE_APPLE: - *params = bufObj->Purgeable; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", - name, pname); - break; - } -} - - -static void -_mesa_GetRenderObjectParameterivAPPLE(struct gl_context *ctx, GLuint name, - GLenum pname, GLint* params) -{ - struct gl_renderbuffer *bufObj; - - bufObj = _mesa_lookup_renderbuffer(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectUnpurgeable(name = 0x%x)", name); - return; - } - - switch (pname) { - case GL_PURGEABLE_APPLE: - *params = bufObj->Purgeable; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", - name, pname); - break; - } -} - - -static void -_mesa_GetTextureObjectParameterivAPPLE(struct gl_context *ctx, GLuint name, - GLenum pname, GLint* params) -{ - struct gl_texture_object *bufObj; - - bufObj = _mesa_lookup_texture(ctx, name); - if (!bufObj) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glObjectUnpurgeable(name = 0x%x)", name); - return; - } - - switch (pname) { - case GL_PURGEABLE_APPLE: - *params = bufObj->Purgeable; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", - name, pname); - break; - } -} - - -void GLAPIENTRY -_mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname, - GLint* params) -{ - GET_CURRENT_CONTEXT(ctx); - - if (name == 0) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glGetObjectParameteriv(name = 0x%x)", name); - return; - } - - switch (objectType) { - case GL_TEXTURE: - _mesa_GetTextureObjectParameterivAPPLE (ctx, name, pname, params); - break; - case GL_BUFFER_OBJECT_APPLE: - _mesa_GetBufferObjectParameterivAPPLE (ctx, name, pname, params); - break; - case GL_RENDERBUFFER_EXT: - _mesa_GetRenderObjectParameterivAPPLE (ctx, name, pname, params); - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetObjectParameteriv(name = 0x%x) invalid type: %d", - name, objectType); - } -} - -#endif /* FEATURE_APPLE_object_purgeable */ +/*
+ * Mesa 3-D graphics library
+ * Version: 7.6
+ *
+ * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/**
+ * \file bufferobj.c
+ * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions.
+ * \author Brian Paul, Ian Romanick
+ */
+
+
+#include "glheader.h"
+#include "enums.h"
+#include "hash.h"
+#include "imports.h"
+#include "image.h"
+#include "context.h"
+#include "bufferobj.h"
+#include "fbobject.h"
+#include "mfeatures.h"
+#include "mtypes.h"
+#include "texobj.h"
+
+
+/* Debug flags */
+/*#define VBO_DEBUG*/
+/*#define BOUNDS_CHECK*/
+
+
+#if FEATURE_OES_mapbuffer
+#define DEFAULT_ACCESS GL_MAP_WRITE_BIT
+#else
+#define DEFAULT_ACCESS (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)
+#endif
+
+
+/**
+ * Used as a placeholder for buffer objects between glGenBuffers() and
+ * glBindBuffer() so that glIsBuffer() can work correctly.
+ */
+static struct gl_buffer_object DummyBufferObject;
+
+
+/**
+ * Return pointer to address of a buffer object target.
+ * \param ctx the GL context
+ * \param target the buffer object target to be retrieved.
+ * \return pointer to pointer to the buffer object bound to \c target in the
+ * specified context or \c NULL if \c target is invalid.
+ */
+static INLINE struct gl_buffer_object **
+get_buffer_target(struct gl_context *ctx, GLenum target)
+{
+ switch (target) {
+ case GL_ARRAY_BUFFER_ARB:
+ return &ctx->Array.ArrayBufferObj;
+ case GL_ELEMENT_ARRAY_BUFFER_ARB:
+ return &ctx->Array.ElementArrayBufferObj;
+ case GL_PIXEL_PACK_BUFFER_EXT:
+ return &ctx->Pack.BufferObj;
+ case GL_PIXEL_UNPACK_BUFFER_EXT:
+ return &ctx->Unpack.BufferObj;
+ case GL_COPY_READ_BUFFER:
+ return &ctx->CopyReadBuffer;
+ case GL_COPY_WRITE_BUFFER:
+ return &ctx->CopyWriteBuffer;
+#if FEATURE_EXT_transform_feedback
+ case GL_TRANSFORM_FEEDBACK_BUFFER:
+ if (ctx->Extensions.EXT_transform_feedback) {
+ return &ctx->TransformFeedback.CurrentBuffer;
+ }
+ break;
+#endif
+ default:
+ return NULL;
+ }
+ return NULL;
+}
+
+
+/**
+ * Get the buffer object bound to the specified target in a GL context.
+ * \param ctx the GL context
+ * \param target the buffer object target to be retrieved.
+ * \return pointer to the buffer object bound to \c target in the
+ * specified context or \c NULL if \c target is invalid.
+ */
+static INLINE struct gl_buffer_object *
+get_buffer(struct gl_context *ctx, GLenum target)
+{
+ struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
+ if (bufObj)
+ return *bufObj;
+ return NULL;
+}
+
+
+/**
+ * Convert a GLbitfield describing the mapped buffer access flags
+ * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY.
+ */
+static GLenum
+simplified_access_mode(GLbitfield access)
+{
+ const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
+ if ((access & rwFlags) == rwFlags)
+ return GL_READ_WRITE;
+ if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT)
+ return GL_READ_ONLY;
+ if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT)
+ return GL_WRITE_ONLY;
+ return GL_READ_WRITE; /* this should never happen, but no big deal */
+}
+
+
+/**
+ * Tests the subdata range parameters and sets the GL error code for
+ * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
+ *
+ * \param ctx GL context.
+ * \param target Buffer object target on which to operate.
+ * \param offset Offset of the first byte of the subdata range.
+ * \param size Size, in bytes, of the subdata range.
+ * \param caller Name of calling function for recording errors.
+ * \return A pointer to the buffer object bound to \c target in the
+ * specified context or \c NULL if any of the parameter or state
+ * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
+ * are invalid.
+ *
+ * \sa glBufferSubDataARB, glGetBufferSubDataARB
+ */
+static struct gl_buffer_object *
+buffer_object_subdata_range_good( struct gl_context * ctx, GLenum target,
+ GLintptrARB offset, GLsizeiptrARB size,
+ const char *caller )
+{
+ struct gl_buffer_object *bufObj;
+
+ if (size < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
+ return NULL;
+ }
+
+ if (offset < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
+ return NULL;
+ }
+
+ bufObj = get_buffer(ctx, target);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller);
+ return NULL;
+ }
+ if (!_mesa_is_bufferobj(bufObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
+ return NULL;
+ }
+ if (offset + size > bufObj->Size) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(size + offset > buffer size)", caller);
+ return NULL;
+ }
+ if (_mesa_bufferobj_mapped(bufObj)) {
+ /* Buffer is currently mapped */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
+ return NULL;
+ }
+
+ return bufObj;
+}
+
+
+/**
+ * Allocate and initialize a new buffer object.
+ *
+ * Default callback for the \c dd_function_table::NewBufferObject() hook.
+ */
+struct gl_buffer_object *
+_mesa_new_buffer_object( struct gl_context *ctx, GLuint name, GLenum target )
+{
+ struct gl_buffer_object *obj;
+
+ (void) ctx;
+
+ obj = MALLOC_STRUCT(gl_buffer_object);
+ _mesa_initialize_buffer_object(obj, name, target);
+ return obj;
+}
+
+
+/**
+ * Delete a buffer object.
+ *
+ * Default callback for the \c dd_function_table::DeleteBuffer() hook.
+ */
+void
+_mesa_delete_buffer_object( struct gl_context *ctx, struct gl_buffer_object *bufObj )
+{
+ (void) ctx;
+
+ if (bufObj->Data)
+ free(bufObj->Data);
+
+ /* assign strange values here to help w/ debugging */
+ bufObj->RefCount = -1000;
+ bufObj->Name = ~0;
+
+ _glthread_DESTROY_MUTEX(bufObj->Mutex);
+ free(bufObj);
+}
+
+
+
+/**
+ * Set ptr to bufObj w/ reference counting.
+ */
+void
+_mesa_reference_buffer_object(struct gl_context *ctx,
+ struct gl_buffer_object **ptr,
+ struct gl_buffer_object *bufObj)
+{
+ if (*ptr == bufObj)
+ return;
+
+ if (*ptr) {
+ /* Unreference the old buffer */
+ GLboolean deleteFlag = GL_FALSE;
+ struct gl_buffer_object *oldObj = *ptr;
+
+ _glthread_LOCK_MUTEX(oldObj->Mutex);
+ ASSERT(oldObj->RefCount > 0);
+ oldObj->RefCount--;
+#if 0
+ printf("BufferObj %p %d DECR to %d\n",
+ (void *) oldObj, oldObj->Name, oldObj->RefCount);
+#endif
+ deleteFlag = (oldObj->RefCount == 0);
+ _glthread_UNLOCK_MUTEX(oldObj->Mutex);
+
+ if (deleteFlag) {
+
+ /* some sanity checking: don't delete a buffer still in use */
+#if 0
+ /* unfortunately, these tests are invalid during context tear-down */
+ ASSERT(ctx->Array.ArrayBufferObj != bufObj);
+ ASSERT(ctx->Array.ElementArrayBufferObj != bufObj);
+ ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj);
+#endif
+
+ ASSERT(ctx->Driver.DeleteBuffer);
+ ctx->Driver.DeleteBuffer(ctx, oldObj);
+ }
+
+ *ptr = NULL;
+ }
+ ASSERT(!*ptr);
+
+ if (bufObj) {
+ /* reference new buffer */
+ _glthread_LOCK_MUTEX(bufObj->Mutex);
+ if (bufObj->RefCount == 0) {
+ /* this buffer's being deleted (look just above) */
+ /* Not sure this can every really happen. Warn if it does. */
+ _mesa_problem(NULL, "referencing deleted buffer object");
+ *ptr = NULL;
+ }
+ else {
+ bufObj->RefCount++;
+#if 0
+ printf("BufferObj %p %d INCR to %d\n",
+ (void *) bufObj, bufObj->Name, bufObj->RefCount);
+#endif
+ *ptr = bufObj;
+ }
+ _glthread_UNLOCK_MUTEX(bufObj->Mutex);
+ }
+}
+
+
+/**
+ * Initialize a buffer object to default values.
+ */
+void
+_mesa_initialize_buffer_object( struct gl_buffer_object *obj,
+ GLuint name, GLenum target )
+{
+ (void) target;
+
+ memset(obj, 0, sizeof(struct gl_buffer_object));
+ _glthread_INIT_MUTEX(obj->Mutex);
+ obj->RefCount = 1;
+ obj->Name = name;
+ obj->Usage = GL_STATIC_DRAW_ARB;
+ obj->AccessFlags = DEFAULT_ACCESS;
+}
+
+
+/**
+ * Allocate space for and store data in a buffer object. Any data that was
+ * previously stored in the buffer object is lost. If \c data is \c NULL,
+ * memory will be allocated, but no copy will occur.
+ *
+ * This is the default callback for \c dd_function_table::BufferData()
+ * Note that all GL error checking will have been done already.
+ *
+ * \param ctx GL context.
+ * \param target Buffer object target on which to operate.
+ * \param size Size, in bytes, of the new data store.
+ * \param data Pointer to the data to store in the buffer object. This
+ * pointer may be \c NULL.
+ * \param usage Hints about how the data will be used.
+ * \param bufObj Object to be used.
+ *
+ * \return GL_TRUE for success, GL_FALSE for failure
+ * \sa glBufferDataARB, dd_function_table::BufferData.
+ */
+GLboolean
+_mesa_buffer_data( struct gl_context *ctx, GLenum target, GLsizeiptrARB size,
+ const GLvoid * data, GLenum usage,
+ struct gl_buffer_object * bufObj )
+{
+ void * new_data;
+
+ (void) ctx; (void) target;
+
+ new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size );
+ if (new_data) {
+ bufObj->Data = (GLubyte *) new_data;
+ bufObj->Size = size;
+ bufObj->Usage = usage;
+
+ if (data) {
+ memcpy( bufObj->Data, data, size );
+ }
+
+ return GL_TRUE;
+ }
+ else {
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Replace data in a subrange of buffer object. If the data range
+ * specified by \c size + \c offset extends beyond the end of the buffer or
+ * if \c data is \c NULL, no copy is performed.
+ *
+ * This is the default callback for \c dd_function_table::BufferSubData()
+ * Note that all GL error checking will have been done already.
+ *
+ * \param ctx GL context.
+ * \param target Buffer object target on which to operate.
+ * \param offset Offset of the first byte to be modified.
+ * \param size Size, in bytes, of the data range.
+ * \param data Pointer to the data to store in the buffer object.
+ * \param bufObj Object to be used.
+ *
+ * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
+ */
+void
+_mesa_buffer_subdata( struct gl_context *ctx, GLenum target, GLintptrARB offset,
+ GLsizeiptrARB size, const GLvoid * data,
+ struct gl_buffer_object * bufObj )
+{
+ (void) ctx; (void) target;
+
+ /* this should have been caught in _mesa_BufferSubData() */
+ ASSERT(size + offset <= bufObj->Size);
+
+ if (bufObj->Data) {
+ memcpy( (GLubyte *) bufObj->Data + offset, data, size );
+ }
+}
+
+
+/**
+ * Retrieve data from a subrange of buffer object. If the data range
+ * specified by \c size + \c offset extends beyond the end of the buffer or
+ * if \c data is \c NULL, no copy is performed.
+ *
+ * This is the default callback for \c dd_function_table::GetBufferSubData()
+ * Note that all GL error checking will have been done already.
+ *
+ * \param ctx GL context.
+ * \param target Buffer object target on which to operate.
+ * \param offset Offset of the first byte to be fetched.
+ * \param size Size, in bytes, of the data range.
+ * \param data Destination for data
+ * \param bufObj Object to be used.
+ *
+ * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
+ */
+void
+_mesa_buffer_get_subdata( struct gl_context *ctx, GLenum target, GLintptrARB offset,
+ GLsizeiptrARB size, GLvoid * data,
+ struct gl_buffer_object * bufObj )
+{
+ (void) ctx; (void) target;
+
+ if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
+ memcpy( data, (GLubyte *) bufObj->Data + offset, size );
+ }
+}
+
+
+/**
+ * Default callback for \c dd_function_tabel::MapBuffer().
+ *
+ * The function parameters will have been already tested for errors.
+ *
+ * \param ctx GL context.
+ * \param target Buffer object target on which to operate.
+ * \param access Information about how the buffer will be accessed.
+ * \param bufObj Object to be mapped.
+ * \return A pointer to the object's internal data store that can be accessed
+ * by the processor
+ *
+ * \sa glMapBufferARB, dd_function_table::MapBuffer
+ */
+void *
+_mesa_buffer_map( struct gl_context *ctx, GLenum target, GLenum access,
+ struct gl_buffer_object *bufObj )
+{
+ (void) ctx;
+ (void) target;
+ (void) access;
+ /* Just return a direct pointer to the data */
+ if (_mesa_bufferobj_mapped(bufObj)) {
+ /* already mapped! */
+ return NULL;
+ }
+ bufObj->Pointer = bufObj->Data;
+ bufObj->Length = bufObj->Size;
+ bufObj->Offset = 0;
+ return bufObj->Pointer;
+}
+
+
+/**
+ * Default fallback for \c dd_function_table::MapBufferRange().
+ * Called via glMapBufferRange().
+ */
+static void *
+_mesa_buffer_map_range( struct gl_context *ctx, GLenum target, GLintptr offset,
+ GLsizeiptr length, GLbitfield access,
+ struct gl_buffer_object *bufObj )
+{
+ (void) ctx;
+ (void) target;
+ assert(!_mesa_bufferobj_mapped(bufObj));
+ /* Just return a direct pointer to the data */
+ bufObj->Pointer = bufObj->Data + offset;
+ bufObj->Length = length;
+ bufObj->Offset = offset;
+ bufObj->AccessFlags = access;
+ return bufObj->Pointer;
+}
+
+
+/**
+ * Default fallback for \c dd_function_table::FlushMappedBufferRange().
+ * Called via glFlushMappedBufferRange().
+ */
+static void
+_mesa_buffer_flush_mapped_range( struct gl_context *ctx, GLenum target,
+ GLintptr offset, GLsizeiptr length,
+ struct gl_buffer_object *obj )
+{
+ (void) ctx;
+ (void) target;
+ (void) offset;
+ (void) length;
+ (void) obj;
+ /* no-op */
+}
+
+
+/**
+ * Default callback for \c dd_function_table::MapBuffer().
+ *
+ * The input parameters will have been already tested for errors.
+ *
+ * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
+ */
+GLboolean
+_mesa_buffer_unmap( struct gl_context *ctx, GLenum target,
+ struct gl_buffer_object *bufObj )
+{
+ (void) ctx;
+ (void) target;
+ /* XXX we might assert here that bufObj->Pointer is non-null */
+ bufObj->Pointer = NULL;
+ bufObj->Length = 0;
+ bufObj->Offset = 0;
+ bufObj->AccessFlags = 0x0;
+ return GL_TRUE;
+}
+
+
+/**
+ * Default fallback for \c dd_function_table::CopyBufferSubData().
+ * Called via glCopyBuffserSubData().
+ */
+static void
+_mesa_copy_buffer_subdata(struct gl_context *ctx,
+ struct gl_buffer_object *src,
+ struct gl_buffer_object *dst,
+ GLintptr readOffset, GLintptr writeOffset,
+ GLsizeiptr size)
+{
+ GLubyte *srcPtr, *dstPtr;
+
+ /* buffer should not already be mapped */
+ assert(!_mesa_bufferobj_mapped(src));
+ assert(!_mesa_bufferobj_mapped(dst));
+
+ srcPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_READ_BUFFER,
+ GL_READ_ONLY, src);
+ dstPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_WRITE_BUFFER,
+ GL_WRITE_ONLY, dst);
+
+ if (srcPtr && dstPtr)
+ memcpy(dstPtr + writeOffset, srcPtr + readOffset, size);
+
+ ctx->Driver.UnmapBuffer(ctx, GL_COPY_READ_BUFFER, src);
+ ctx->Driver.UnmapBuffer(ctx, GL_COPY_WRITE_BUFFER, dst);
+}
+
+
+
+/**
+ * Initialize the state associated with buffer objects
+ */
+void
+_mesa_init_buffer_objects( struct gl_context *ctx )
+{
+ memset(&DummyBufferObject, 0, sizeof(DummyBufferObject));
+ DummyBufferObject.RefCount = 1000*1000*1000; /* never delete */
+
+ _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj,
+ ctx->Shared->NullBufferObj);
+ _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj,
+ ctx->Shared->NullBufferObj);
+
+ _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer,
+ ctx->Shared->NullBufferObj);
+ _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer,
+ ctx->Shared->NullBufferObj);
+}
+
+
+void
+_mesa_free_buffer_objects( struct gl_context *ctx )
+{
+ _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
+ _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL);
+
+ _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL);
+ _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL);
+}
+
+
+/**
+ * Bind the specified target to buffer for the specified context.
+ * Called by glBindBuffer() and other functions.
+ */
+static void
+bind_buffer_object(struct gl_context *ctx, GLenum target, GLuint buffer)
+{
+ struct gl_buffer_object *oldBufObj;
+ struct gl_buffer_object *newBufObj = NULL;
+ struct gl_buffer_object **bindTarget = NULL;
+
+ bindTarget = get_buffer_target(ctx, target);
+ if (!bindTarget) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target);
+ return;
+ }
+
+ /* Get pointer to old buffer object (to be unbound) */
+ oldBufObj = *bindTarget;
+ if (oldBufObj && oldBufObj->Name == buffer)
+ return; /* rebinding the same buffer object- no change */
+
+ /*
+ * Get pointer to new buffer object (newBufObj)
+ */
+ if (buffer == 0) {
+ /* The spec says there's not a buffer object named 0, but we use
+ * one internally because it simplifies things.
+ */
+ newBufObj = ctx->Shared->NullBufferObj;
+ }
+ else {
+ /* non-default buffer object */
+ newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
+ if (!newBufObj || newBufObj == &DummyBufferObject) {
+ /* If this is a new buffer object id, or one which was generated but
+ * never used before, allocate a buffer object now.
+ */
+ ASSERT(ctx->Driver.NewBufferObject);
+ newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target);
+ if (!newBufObj) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB");
+ return;
+ }
+ _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj);
+ }
+ }
+
+ /* bind new buffer */
+ _mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
+
+ /* Pass BindBuffer call to device driver */
+ if (ctx->Driver.BindBuffer)
+ ctx->Driver.BindBuffer( ctx, target, newBufObj );
+}
+
+
+/**
+ * Update the default buffer objects in the given context to reference those
+ * specified in the shared state and release those referencing the old
+ * shared state.
+ */
+void
+_mesa_update_default_objects_buffer_objects(struct gl_context *ctx)
+{
+ /* Bind the NullBufferObj to remove references to those
+ * in the shared context hash table.
+ */
+ bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0);
+ bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+ bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0);
+ bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+}
+
+
+/**
+ * When we're about to read pixel data out of a PBO (via glDrawPixels,
+ * glTexImage, etc) or write data into a PBO (via glReadPixels,
+ * glGetTexImage, etc) we call this function to check that we're not
+ * going to read out of bounds.
+ *
+ * XXX This would also be a convenient time to check that the PBO isn't
+ * currently mapped. Whoever calls this function should check for that.
+ * Remember, we can't use a PBO when it's mapped!
+ *
+ * If we're not using a PBO, this is a no-op.
+ *
+ * \param width width of image to read/write
+ * \param height height of image to read/write
+ * \param depth depth of image to read/write
+ * \param format format of image to read/write
+ * \param type datatype of image to read/write
+ * \param ptr the user-provided pointer/offset
+ * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would
+ * go out of bounds.
+ */
+GLboolean
+_mesa_validate_pbo_access(GLuint dimensions,
+ const struct gl_pixelstore_attrib *pack,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type, const GLvoid *ptr)
+{
+ GLvoid *start, *end;
+ const GLubyte *sizeAddr; /* buffer size, cast to a pointer */
+
+ if (!_mesa_is_bufferobj(pack->BufferObj))
+ return GL_TRUE; /* no PBO, OK */
+
+ if (pack->BufferObj->Size == 0)
+ /* no buffer! */
+ return GL_FALSE;
+
+ /* get address of first pixel we'll read */
+ start = _mesa_image_address(dimensions, pack, ptr, width, height,
+ format, type, 0, 0, 0);
+
+ /* get address just past the last pixel we'll read */
+ end = _mesa_image_address(dimensions, pack, ptr, width, height,
+ format, type, depth-1, height-1, width);
+
+
+ sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size;
+
+ if ((const GLubyte *) start > sizeAddr) {
+ /* This will catch negative values / wrap-around */
+ return GL_FALSE;
+ }
+ if ((const GLubyte *) end > sizeAddr) {
+ /* Image read goes beyond end of buffer */
+ return GL_FALSE;
+ }
+
+ /* OK! */
+ return GL_TRUE;
+}
+
+
+/**
+ * For commands that read from a PBO (glDrawPixels, glTexImage,
+ * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
+ * and return the pointer into the PBO. If we're not reading from a
+ * PBO, return \p src as-is.
+ * If non-null return, must call _mesa_unmap_pbo_source() when done.
+ *
+ * \return NULL if error, else pointer to start of data
+ */
+const GLvoid *
+_mesa_map_pbo_source(struct gl_context *ctx,
+ const struct gl_pixelstore_attrib *unpack,
+ const GLvoid *src)
+{
+ const GLubyte *buf;
+
+ if (_mesa_is_bufferobj(unpack->BufferObj)) {
+ /* unpack from PBO */
+ buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
+ GL_READ_ONLY_ARB,
+ unpack->BufferObj);
+ if (!buf)
+ return NULL;
+
+ buf = ADD_POINTERS(buf, src);
+ }
+ else {
+ /* unpack from normal memory */
+ buf = src;
+ }
+
+ return buf;
+}
+
+
+/**
+ * Combine PBO-read validation and mapping.
+ * If any GL errors are detected, they'll be recorded and NULL returned.
+ * \sa _mesa_validate_pbo_access
+ * \sa _mesa_map_pbo_source
+ * A call to this function should have a matching call to
+ * _mesa_unmap_pbo_source().
+ */
+const GLvoid *
+_mesa_map_validate_pbo_source(struct gl_context *ctx,
+ GLuint dimensions,
+ const struct gl_pixelstore_attrib *unpack,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type, const GLvoid *ptr,
+ const char *where)
+{
+ ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
+
+ if (!_mesa_is_bufferobj(unpack->BufferObj)) {
+ /* non-PBO access: no validation to be done */
+ return ptr;
+ }
+
+ if (!_mesa_validate_pbo_access(dimensions, unpack,
+ width, height, depth, format, type, ptr)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(out of bounds PBO access)", where);
+ return NULL;
+ }
+
+ if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
+ /* buffer is already mapped - that's an error */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
+ return NULL;
+ }
+
+ ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
+ return ptr;
+}
+
+
+/**
+ * Counterpart to _mesa_map_pbo_source()
+ */
+void
+_mesa_unmap_pbo_source(struct gl_context *ctx,
+ const struct gl_pixelstore_attrib *unpack)
+{
+ ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
+ if (_mesa_is_bufferobj(unpack->BufferObj)) {
+ ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
+ unpack->BufferObj);
+ }
+}
+
+
+/**
+ * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
+ * if we're writing to a PBO, map it write-only and return the pointer
+ * into the PBO. If we're not writing to a PBO, return \p dst as-is.
+ * If non-null return, must call _mesa_unmap_pbo_dest() when done.
+ *
+ * \return NULL if error, else pointer to start of data
+ */
+void *
+_mesa_map_pbo_dest(struct gl_context *ctx,
+ const struct gl_pixelstore_attrib *pack,
+ GLvoid *dest)
+{
+ void *buf;
+
+ if (_mesa_is_bufferobj(pack->BufferObj)) {
+ /* pack into PBO */
+ buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
+ GL_WRITE_ONLY_ARB,
+ pack->BufferObj);
+ if (!buf)
+ return NULL;
+
+ buf = ADD_POINTERS(buf, dest);
+ }
+ else {
+ /* pack to normal memory */
+ buf = dest;
+ }
+
+ return buf;
+}
+
+
+/**
+ * Combine PBO-write validation and mapping.
+ * If any GL errors are detected, they'll be recorded and NULL returned.
+ * \sa _mesa_validate_pbo_access
+ * \sa _mesa_map_pbo_dest
+ * A call to this function should have a matching call to
+ * _mesa_unmap_pbo_dest().
+ */
+GLvoid *
+_mesa_map_validate_pbo_dest(struct gl_context *ctx,
+ GLuint dimensions,
+ const struct gl_pixelstore_attrib *unpack,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type, GLvoid *ptr,
+ const char *where)
+{
+ ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
+
+ if (!_mesa_is_bufferobj(unpack->BufferObj)) {
+ /* non-PBO access: no validation to be done */
+ return ptr;
+ }
+
+ if (!_mesa_validate_pbo_access(dimensions, unpack,
+ width, height, depth, format, type, ptr)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(out of bounds PBO access)", where);
+ return NULL;
+ }
+
+ if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
+ /* buffer is already mapped - that's an error */
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
+ return NULL;
+ }
+
+ ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
+ return ptr;
+}
+
+
+/**
+ * Counterpart to _mesa_map_pbo_dest()
+ */
+void
+_mesa_unmap_pbo_dest(struct gl_context *ctx,
+ const struct gl_pixelstore_attrib *pack)
+{
+ ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
+ if (_mesa_is_bufferobj(pack->BufferObj)) {
+ ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj);
+ }
+}
+
+
+
+/**
+ * Return the gl_buffer_object for the given ID.
+ * Always return NULL for ID 0.
+ */
+struct gl_buffer_object *
+_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer)
+{
+ if (buffer == 0)
+ return NULL;
+ else
+ return (struct gl_buffer_object *)
+ _mesa_HashLookup(ctx->Shared->BufferObjects, buffer);
+}
+
+
+/**
+ * If *ptr points to obj, set ptr = the Null/default buffer object.
+ * This is a helper for buffer object deletion.
+ * The GL spec says that deleting a buffer object causes it to get
+ * unbound from all arrays in the current context.
+ */
+static void
+unbind(struct gl_context *ctx,
+ struct gl_buffer_object **ptr,
+ struct gl_buffer_object *obj)
+{
+ if (*ptr == obj) {
+ _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj);
+ }
+}
+
+
+/**
+ * Plug default/fallback buffer object functions into the device
+ * driver hooks.
+ */
+void
+_mesa_init_buffer_object_functions(struct dd_function_table *driver)
+{
+ /* GL_ARB_vertex/pixel_buffer_object */
+ driver->NewBufferObject = _mesa_new_buffer_object;
+ driver->DeleteBuffer = _mesa_delete_buffer_object;
+ driver->BindBuffer = NULL;
+ driver->BufferData = _mesa_buffer_data;
+ driver->BufferSubData = _mesa_buffer_subdata;
+ driver->GetBufferSubData = _mesa_buffer_get_subdata;
+ driver->MapBuffer = _mesa_buffer_map;
+ driver->UnmapBuffer = _mesa_buffer_unmap;
+
+ /* GL_ARB_map_buffer_range */
+ driver->MapBufferRange = _mesa_buffer_map_range;
+ driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range;
+
+ /* GL_ARB_copy_buffer */
+ driver->CopyBufferSubData = _mesa_copy_buffer_subdata;
+}
+
+
+
+/**********************************************************************/
+/* API Functions */
+/**********************************************************************/
+
+void GLAPIENTRY
+_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);
+}
+
+
+/**
+ * Delete a set of buffer objects.
+ *
+ * \param n Number of buffer objects to delete.
+ * \param ids Array of \c n buffer object IDs.
+ */
+void GLAPIENTRY
+_mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLsizei i;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (n < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
+ return;
+ }
+
+ _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+
+ for (i = 0; i < n; i++) {
+ struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]);
+ if (bufObj) {
+ struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
+ GLuint j;
+
+ ASSERT(bufObj->Name == ids[i] || bufObj == &DummyBufferObject);
+
+ if (_mesa_bufferobj_mapped(bufObj)) {
+ /* if mapped, unmap it now */
+ ctx->Driver.UnmapBuffer(ctx, 0, bufObj);
+ bufObj->AccessFlags = DEFAULT_ACCESS;
+ bufObj->Pointer = NULL;
+ }
+
+ /* unbind any vertex pointers bound to this buffer */
+ unbind(ctx, &arrayObj->Vertex.BufferObj, bufObj);
+ unbind(ctx, &arrayObj->Weight.BufferObj, bufObj);
+ unbind(ctx, &arrayObj->Normal.BufferObj, bufObj);
+ unbind(ctx, &arrayObj->Color.BufferObj, bufObj);
+ unbind(ctx, &arrayObj->SecondaryColor.BufferObj, bufObj);
+ unbind(ctx, &arrayObj->FogCoord.BufferObj, bufObj);
+ unbind(ctx, &arrayObj->Index.BufferObj, bufObj);
+ unbind(ctx, &arrayObj->EdgeFlag.BufferObj, bufObj);
+ for (j = 0; j < Elements(arrayObj->TexCoord); j++) {
+ unbind(ctx, &arrayObj->TexCoord[j].BufferObj, bufObj);
+ }
+ for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) {
+ unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj);
+ }
+
+ if (ctx->Array.ArrayBufferObj == bufObj) {
+ _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
+ }
+ if (ctx->Array.ElementArrayBufferObj == bufObj) {
+ _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
+ }
+
+ /* unbind any pixel pack/unpack pointers bound to this buffer */
+ if (ctx->Pack.BufferObj == bufObj) {
+ _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 );
+ }
+ if (ctx->Unpack.BufferObj == bufObj) {
+ _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 );
+ }
+
+ /* The ID is immediately freed for re-use */
+ _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]);
+ _mesa_reference_buffer_object(ctx, &bufObj, NULL);
+ }
+ }
+
+ _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+}
+
+
+/**
+ * Generate a set of unique buffer object IDs and store them in \c buffer.
+ *
+ * \param n Number of IDs to generate.
+ * \param buffer Array of \c n locations to store the IDs.
+ */
+void GLAPIENTRY
+_mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLuint first;
+ 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;
+ }
+
+ if (!buffer) {
+ return;
+ }
+
+ /*
+ * This must be atomic (generation and allocation of buffer object IDs)
+ */
+ _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+
+ first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
+
+ /* Insert the ID and pointer to dummy buffer object into hash table */
+ for (i = 0; i < n; i++) {
+ _mesa_HashInsert(ctx->Shared->BufferObjects, first + i,
+ &DummyBufferObject);
+ buffer[i] = first + i;
+ }
+
+ _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+}
+
+
+/**
+ * Determine if ID is the name of a buffer object.
+ *
+ * \param id ID of the potential buffer object.
+ * \return \c GL_TRUE if \c id is the name of a buffer object,
+ * \c GL_FALSE otherwise.
+ */
+GLboolean GLAPIENTRY
+_mesa_IsBufferARB(GLuint id)
+{
+ struct gl_buffer_object *bufObj;
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
+
+ _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+ bufObj = _mesa_lookup_bufferobj(ctx, id);
+ _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+
+ return bufObj && bufObj != &DummyBufferObject;
+}
+
+
+void GLAPIENTRY
+_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
+ const GLvoid * data, GLenum usage)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ 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;
+ }
+
+ switch (usage) {
+ case GL_STREAM_DRAW_ARB:
+ case GL_STREAM_READ_ARB:
+ case GL_STREAM_COPY_ARB:
+ case GL_STATIC_DRAW_ARB:
+ case GL_STATIC_READ_ARB:
+ case GL_STATIC_COPY_ARB:
+ case GL_DYNAMIC_DRAW_ARB:
+ case GL_DYNAMIC_READ_ARB:
+ case GL_DYNAMIC_COPY_ARB:
+ /* OK */
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)");
+ return;
+ }
+
+ bufObj = get_buffer(ctx, target);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" );
+ return;
+ }
+ if (!_mesa_is_bufferobj(bufObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer 0)" );
+ return;
+ }
+
+ if (_mesa_bufferobj_mapped(bufObj)) {
+ /* Unmap the existing buffer. We'll replace it now. Not an error. */
+ ctx->Driver.UnmapBuffer(ctx, target, bufObj);
+ bufObj->AccessFlags = DEFAULT_ACCESS;
+ ASSERT(bufObj->Pointer == NULL);
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
+
+ bufObj->Written = GL_TRUE;
+
+#ifdef VBO_DEBUG
+ printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
+ bufObj->Name, size, data, usage);
+#endif
+
+#ifdef BOUNDS_CHECK
+ size += 100;
+#endif
+
+ ASSERT(ctx->Driver.BufferData);
+ if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()");
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
+ GLsizeiptrARB size, const GLvoid * data)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_buffer_object *bufObj;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
+ "glBufferSubDataARB" );
+ if (!bufObj) {
+ /* error already recorded */
+ return;
+ }
+
+ if (size == 0)
+ return;
+
+ bufObj->Written = GL_TRUE;
+
+ ASSERT(ctx->Driver.BufferSubData);
+ ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj );
+}
+
+
+void GLAPIENTRY
+_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
+ GLsizeiptrARB size, void * data)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_buffer_object *bufObj;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
+ "glGetBufferSubDataARB" );
+ if (!bufObj) {
+ /* error already recorded */
+ return;
+ }
+
+ ASSERT(ctx->Driver.GetBufferSubData);
+ ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj );
+}
+
+
+void * GLAPIENTRY
+_mesa_MapBufferARB(GLenum target, GLenum access)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_buffer_object * bufObj;
+ GLbitfield accessFlags;
+ void *map;
+
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
+
+ switch (access) {
+ case GL_READ_ONLY_ARB:
+ accessFlags = GL_MAP_READ_BIT;
+ break;
+ case GL_WRITE_ONLY_ARB:
+ accessFlags = GL_MAP_WRITE_BIT;
+ break;
+ case GL_READ_WRITE_ARB:
+ accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
+ return NULL;
+ }
+
+ bufObj = get_buffer(ctx, target);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" );
+ return NULL;
+ }
+ if (!_mesa_is_bufferobj(bufObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(buffer 0)" );
+ return NULL;
+ }
+ if (_mesa_bufferobj_mapped(bufObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
+ return NULL;
+ }
+
+ ASSERT(ctx->Driver.MapBuffer);
+ map = ctx->Driver.MapBuffer( ctx, target, access, bufObj );
+ if (!map) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
+ return NULL;
+ }
+ else {
+ /* The driver callback should have set these fields.
+ * This is important because other modules (like VBO) might call
+ * the driver function directly.
+ */
+ ASSERT(bufObj->Pointer == map);
+ ASSERT(bufObj->Length == bufObj->Size);
+ ASSERT(bufObj->Offset == 0);
+ bufObj->AccessFlags = accessFlags;
+ }
+
+ if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB)
+ bufObj->Written = GL_TRUE;
+
+#ifdef VBO_DEBUG
+ printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n",
+ bufObj->Name, bufObj->Size, access);
+ if (access == GL_WRITE_ONLY_ARB) {
+ GLuint i;
+ GLubyte *b = (GLubyte *) bufObj->Pointer;
+ for (i = 0; i < bufObj->Size; i++)
+ b[i] = i & 0xff;
+ }
+#endif
+
+#ifdef BOUNDS_CHECK
+ {
+ GLubyte *buf = (GLubyte *) bufObj->Pointer;
+ GLuint i;
+ /* buffer is 100 bytes larger than requested, fill with magic value */
+ for (i = 0; i < 100; i++) {
+ buf[bufObj->Size - i - 1] = 123;
+ }
+ }
+#endif
+
+ return bufObj->Pointer;
+}
+
+
+GLboolean GLAPIENTRY
+_mesa_UnmapBufferARB(GLenum target)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_buffer_object *bufObj;
+ GLboolean status = GL_TRUE;
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
+
+ bufObj = get_buffer(ctx, target);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" );
+ return GL_FALSE;
+ }
+ if (!_mesa_is_bufferobj(bufObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" );
+ return GL_FALSE;
+ }
+ if (!_mesa_bufferobj_mapped(bufObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
+ return GL_FALSE;
+ }
+
+#ifdef BOUNDS_CHECK
+ if (bufObj->Access != GL_READ_ONLY_ARB) {
+ GLubyte *buf = (GLubyte *) bufObj->Pointer;
+ GLuint i;
+ /* check that last 100 bytes are still = magic value */
+ for (i = 0; i < 100; i++) {
+ GLuint pos = bufObj->Size - i - 1;
+ if (buf[pos] != 123) {
+ _mesa_warning(ctx, "Out of bounds buffer object write detected"
+ " at position %d (value = %u)\n",
+ pos, buf[pos]);
+ }
+ }
+ }
+#endif
+
+#ifdef VBO_DEBUG
+ if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) {
+ GLuint i, unchanged = 0;
+ GLubyte *b = (GLubyte *) bufObj->Pointer;
+ GLint pos = -1;
+ /* check which bytes changed */
+ for (i = 0; i < bufObj->Size - 1; i++) {
+ if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) {
+ unchanged++;
+ if (pos == -1)
+ pos = i;
+ }
+ }
+ if (unchanged) {
+ printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
+ bufObj->Name, unchanged, bufObj->Size, pos);
+ }
+ }
+#endif
+
+ status = ctx->Driver.UnmapBuffer( ctx, target, bufObj );
+ bufObj->AccessFlags = DEFAULT_ACCESS;
+ ASSERT(bufObj->Pointer == NULL);
+ ASSERT(bufObj->Offset == 0);
+ ASSERT(bufObj->Length == 0);
+
+ return status;
+}
+
+
+void GLAPIENTRY
+_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_buffer_object *bufObj;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ bufObj = get_buffer(ctx, target);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(target)" );
+ return;
+ }
+ if (!_mesa_is_bufferobj(bufObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameterivARB" );
+ return;
+ }
+
+ switch (pname) {
+ case GL_BUFFER_SIZE_ARB:
+ *params = (GLint) bufObj->Size;
+ return;
+ case GL_BUFFER_USAGE_ARB:
+ *params = bufObj->Usage;
+ return;
+ case GL_BUFFER_ACCESS_ARB:
+ *params = simplified_access_mode(bufObj->AccessFlags);
+ return;
+ case GL_BUFFER_MAPPED_ARB:
+ *params = _mesa_bufferobj_mapped(bufObj);
+ return;
+ case GL_BUFFER_ACCESS_FLAGS:
+ if (ctx->VersionMajor < 3)
+ goto invalid_pname;
+ *params = bufObj->AccessFlags;
+ return;
+ case GL_BUFFER_MAP_OFFSET:
+ if (ctx->VersionMajor < 3)
+ goto invalid_pname;
+ *params = (GLint) bufObj->Offset;
+ return;
+ case GL_BUFFER_MAP_LENGTH:
+ if (ctx->VersionMajor < 3)
+ goto invalid_pname;
+ *params = (GLint) bufObj->Length;
+ return;
+ default:
+ ; /* fall-through */
+ }
+
+invalid_pname:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)",
+ _mesa_lookup_enum_by_nr(pname));
+}
+
+
+/**
+ * New in GL 3.2
+ * This is pretty much a duplicate of GetBufferParameteriv() but the
+ * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system.
+ */
+void GLAPIENTRY
+_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_buffer_object *bufObj;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ bufObj = get_buffer(ctx, target);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(target)" );
+ return;
+ }
+ if (!_mesa_is_bufferobj(bufObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameteri64v" );
+ return;
+ }
+
+ switch (pname) {
+ case GL_BUFFER_SIZE_ARB:
+ *params = bufObj->Size;
+ return;
+ case GL_BUFFER_USAGE_ARB:
+ *params = bufObj->Usage;
+ return;
+ case GL_BUFFER_ACCESS_ARB:
+ *params = simplified_access_mode(bufObj->AccessFlags);
+ return;
+ case GL_BUFFER_ACCESS_FLAGS:
+ if (ctx->VersionMajor < 3)
+ goto invalid_pname;
+ *params = bufObj->AccessFlags;
+ return;
+ case GL_BUFFER_MAPPED_ARB:
+ *params = _mesa_bufferobj_mapped(bufObj);
+ return;
+ case GL_BUFFER_MAP_OFFSET:
+ if (ctx->VersionMajor < 3)
+ goto invalid_pname;
+ *params = bufObj->Offset;
+ return;
+ case GL_BUFFER_MAP_LENGTH:
+ if (ctx->VersionMajor < 3)
+ goto invalid_pname;
+ *params = bufObj->Length;
+ return;
+ default:
+ ; /* fall-through */
+ }
+
+invalid_pname:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)",
+ _mesa_lookup_enum_by_nr(pname));
+}
+
+
+void GLAPIENTRY
+_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_buffer_object * bufObj;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (pname != GL_BUFFER_MAP_POINTER_ARB) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
+ return;
+ }
+
+ bufObj = get_buffer(ctx, target);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" );
+ return;
+ }
+ if (!_mesa_is_bufferobj(bufObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" );
+ return;
+ }
+
+ *params = bufObj->Pointer;
+}
+
+
+void GLAPIENTRY
+_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
+ GLintptr readOffset, GLintptr writeOffset,
+ GLsizeiptr size)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_buffer_object *src, *dst;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ src = get_buffer(ctx, readTarget);
+ if (!src || !_mesa_is_bufferobj(src)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glCopyBuffserSubData(readTarget = 0x%x)", readTarget);
+ return;
+ }
+
+ dst = get_buffer(ctx, writeTarget);
+ if (!dst || !_mesa_is_bufferobj(dst)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget);
+ return;
+ }
+
+ if (_mesa_bufferobj_mapped(src)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCopyBuffserSubData(readBuffer is mapped)");
+ return;
+ }
+
+ if (_mesa_bufferobj_mapped(dst)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCopyBuffserSubData(writeBuffer is mapped)");
+ return;
+ }
+
+ if (readOffset < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyBuffserSubData(readOffset = %d)", (int) readOffset);
+ return;
+ }
+
+ if (writeOffset < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyBuffserSubData(writeOffset = %d)", (int) writeOffset);
+ return;
+ }
+
+ if (readOffset + size > src->Size) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyBuffserSubData(readOffset + size = %d)",
+ (int) (readOffset + size));
+ return;
+ }
+
+ if (writeOffset + size > dst->Size) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyBuffserSubData(writeOffset + size = %d)",
+ (int) (writeOffset + size));
+ return;
+ }
+
+ if (src == dst) {
+ if (readOffset + size <= writeOffset) {
+ /* OK */
+ }
+ else if (writeOffset + size <= readOffset) {
+ /* OK */
+ }
+ else {
+ /* overlapping src/dst is illegal */
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyBuffserSubData(overlapping src/dst)");
+ return;
+ }
+ }
+
+ ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
+}
+
+
+/**
+ * See GL_ARB_map_buffer_range spec
+ */
+void * GLAPIENTRY
+_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
+ GLbitfield access)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_buffer_object *bufObj;
+ void *map;
+
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
+
+ if (!ctx->Extensions.ARB_map_buffer_range) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glMapBufferRange(extension not supported)");
+ return NULL;
+ }
+
+ if (offset < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glMapBufferRange(offset = %ld)", (long)offset);
+ return NULL;
+ }
+
+ if (length < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glMapBufferRange(length = %ld)", (long)length);
+ return NULL;
+ }
+
+ if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glMapBufferRange(access indicates neither read or write)");
+ return NULL;
+ }
+
+ if (access & GL_MAP_READ_BIT) {
+ if ((access & GL_MAP_INVALIDATE_RANGE_BIT) ||
+ (access & GL_MAP_INVALIDATE_BUFFER_BIT) ||
+ (access & GL_MAP_UNSYNCHRONIZED_BIT)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glMapBufferRange(invalid access flags)");
+ return NULL;
+ }
+ }
+
+ if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) &&
+ ((access & GL_MAP_WRITE_BIT) == 0)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glMapBufferRange(invalid access flags)");
+ return NULL;
+ }
+
+ bufObj = get_buffer(ctx, target);
+ if (!bufObj || !_mesa_is_bufferobj(bufObj)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glMapBufferRange(target = 0x%x)", target);
+ return NULL;
+ }
+
+ if (offset + length > bufObj->Size) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glMapBufferRange(offset + length > size)");
+ return NULL;
+ }
+
+ if (_mesa_bufferobj_mapped(bufObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glMapBufferRange(buffer already mapped)");
+ return NULL;
+ }
+
+ ASSERT(ctx->Driver.MapBufferRange);
+ map = ctx->Driver.MapBufferRange(ctx, target, offset, length,
+ access, bufObj);
+ if (!map) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
+ }
+ else {
+ /* The driver callback should have set all these fields.
+ * This is important because other modules (like VBO) might call
+ * the driver function directly.
+ */
+ ASSERT(bufObj->Pointer == map);
+ ASSERT(bufObj->Length == length);
+ ASSERT(bufObj->Offset == offset);
+ ASSERT(bufObj->AccessFlags == access);
+ }
+
+ return map;
+}
+
+
+/**
+ * See GL_ARB_map_buffer_range spec
+ */
+void GLAPIENTRY
+_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_buffer_object *bufObj;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (!ctx->Extensions.ARB_map_buffer_range) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glMapBufferRange(extension not supported)");
+ return;
+ }
+
+ if (offset < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glMapBufferRange(offset = %ld)", (long)offset);
+ return;
+ }
+
+ if (length < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glMapBufferRange(length = %ld)", (long)length);
+ return;
+ }
+
+ bufObj = get_buffer(ctx, target);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glMapBufferRange(target = 0x%x)", target);
+ return;
+ }
+
+ if (!_mesa_is_bufferobj(bufObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glMapBufferRange(current buffer is 0)");
+ return;
+ }
+
+ if (!_mesa_bufferobj_mapped(bufObj)) {
+ /* buffer is not mapped */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glMapBufferRange(buffer is not mapped)");
+ return;
+ }
+
+ if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glMapBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)");
+ return;
+ }
+
+ if (offset + length > bufObj->Length) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glMapBufferRange(offset %ld + length %ld > mapped length %ld)",
+ (long)offset, (long)length, (long)bufObj->Length);
+ return;
+ }
+
+ ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT);
+
+ if (ctx->Driver.FlushMappedBufferRange)
+ ctx->Driver.FlushMappedBufferRange(ctx, target, offset, length, bufObj);
+}
+
+
+#if FEATURE_APPLE_object_purgeable
+static GLenum
+_mesa_BufferObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option)
+{
+ struct gl_buffer_object *bufObj;
+ GLenum retval;
+
+ bufObj = _mesa_lookup_bufferobj(ctx, name);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glObjectPurgeable(name = 0x%x)", name);
+ return 0;
+ }
+ if (!_mesa_is_bufferobj(bufObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" );
+ return 0;
+ }
+
+ if (bufObj->Purgeable) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glObjectPurgeable(name = 0x%x) is already purgeable", name);
+ return GL_VOLATILE_APPLE;
+ }
+
+ bufObj->Purgeable = GL_TRUE;
+
+ retval = GL_VOLATILE_APPLE;
+ if (ctx->Driver.BufferObjectPurgeable)
+ retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option);
+
+ return retval;
+}
+
+
+static GLenum
+_mesa_RenderObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option)
+{
+ struct gl_renderbuffer *bufObj;
+ GLenum retval;
+
+ bufObj = _mesa_lookup_renderbuffer(ctx, name);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glObjectUnpurgeable(name = 0x%x)", name);
+ return 0;
+ }
+
+ if (bufObj->Purgeable) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glObjectPurgeable(name = 0x%x) is already purgeable", name);
+ return GL_VOLATILE_APPLE;
+ }
+
+ bufObj->Purgeable = GL_TRUE;
+
+ retval = GL_VOLATILE_APPLE;
+ if (ctx->Driver.RenderObjectPurgeable)
+ retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option);
+
+ return retval;
+}
+
+
+static GLenum
+_mesa_TextureObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option)
+{
+ struct gl_texture_object *bufObj;
+ GLenum retval;
+
+ bufObj = _mesa_lookup_texture(ctx, name);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glObjectPurgeable(name = 0x%x)", name);
+ return 0;
+ }
+
+ if (bufObj->Purgeable) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glObjectPurgeable(name = 0x%x) is already purgeable", name);
+ return GL_VOLATILE_APPLE;
+ }
+
+ bufObj->Purgeable = GL_TRUE;
+
+ retval = GL_VOLATILE_APPLE;
+ if (ctx->Driver.TextureObjectPurgeable)
+ retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option);
+
+ return retval;
+}
+
+
+GLenum GLAPIENTRY
+_mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
+{
+ GLenum retval;
+
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
+
+ if (name == 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glObjectPurgeable(name = 0x%x)", name);
+ return 0;
+ }
+
+ switch (option) {
+ case GL_VOLATILE_APPLE:
+ case GL_RELEASED_APPLE:
+ /* legal */
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glObjectPurgeable(name = 0x%x) invalid option: %d",
+ name, option);
+ return 0;
+ }
+
+ switch (objectType) {
+ case GL_TEXTURE:
+ retval = _mesa_TextureObjectPurgeable (ctx, name, option);
+ break;
+ case GL_RENDERBUFFER_EXT:
+ retval = _mesa_RenderObjectPurgeable (ctx, name, option);
+ break;
+ case GL_BUFFER_OBJECT_APPLE:
+ retval = _mesa_BufferObjectPurgeable (ctx, name, option);
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glObjectPurgeable(name = 0x%x) invalid type: %d",
+ name, objectType);
+ return 0;
+ }
+
+ /* In strict conformance to the spec, we must only return VOLATILE when
+ * when passed the VOLATILE option. Madness.
+ *
+ * XXX First fix the spec, then fix me.
+ */
+ return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval;
+}
+
+
+static GLenum
+_mesa_BufferObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
+{
+ struct gl_buffer_object *bufObj;
+ GLenum retval;
+
+ bufObj = _mesa_lookup_bufferobj(ctx, name);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glObjectUnpurgeable(name = 0x%x)", name);
+ return 0;
+ }
+
+ if (! bufObj->Purgeable) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glObjectUnpurgeable(name = 0x%x) object is "
+ " already \"unpurged\"", name);
+ return 0;
+ }
+
+ bufObj->Purgeable = GL_FALSE;
+
+ retval = option;
+ if (ctx->Driver.BufferObjectUnpurgeable)
+ retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option);
+
+ return retval;
+}
+
+
+static GLenum
+_mesa_RenderObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
+{
+ struct gl_renderbuffer *bufObj;
+ GLenum retval;
+
+ bufObj = _mesa_lookup_renderbuffer(ctx, name);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glObjectUnpurgeable(name = 0x%x)", name);
+ return 0;
+ }
+
+ if (! bufObj->Purgeable) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glObjectUnpurgeable(name = 0x%x) object is "
+ " already \"unpurged\"", name);
+ return 0;
+ }
+
+ bufObj->Purgeable = GL_FALSE;
+
+ retval = option;
+ if (ctx->Driver.RenderObjectUnpurgeable)
+ retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option);
+
+ return retval;
+}
+
+
+static GLenum
+_mesa_TextureObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
+{
+ struct gl_texture_object *bufObj;
+ GLenum retval;
+
+ bufObj = _mesa_lookup_texture(ctx, name);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glObjectUnpurgeable(name = 0x%x)", name);
+ return 0;
+ }
+
+ if (! bufObj->Purgeable) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glObjectUnpurgeable(name = 0x%x) object is"
+ " already \"unpurged\"", name);
+ return 0;
+ }
+
+ bufObj->Purgeable = GL_FALSE;
+
+ retval = option;
+ if (ctx->Driver.TextureObjectUnpurgeable)
+ retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option);
+
+ return retval;
+}
+
+
+GLenum GLAPIENTRY
+_mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
+
+ if (name == 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glObjectUnpurgeable(name = 0x%x)", name);
+ return 0;
+ }
+
+ switch (option) {
+ case GL_RETAINED_APPLE:
+ case GL_UNDEFINED_APPLE:
+ /* legal */
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glObjectUnpurgeable(name = 0x%x) invalid option: %d",
+ name, option);
+ return 0;
+ }
+
+ switch (objectType) {
+ case GL_BUFFER_OBJECT_APPLE:
+ return _mesa_BufferObjectUnpurgeable(ctx, name, option);
+ case GL_TEXTURE:
+ return _mesa_TextureObjectUnpurgeable(ctx, name, option);
+ case GL_RENDERBUFFER_EXT:
+ return _mesa_RenderObjectUnpurgeable(ctx, name, option);
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glObjectUnpurgeable(name = 0x%x) invalid type: %d",
+ name, objectType);
+ return 0;
+ }
+}
+
+
+static void
+_mesa_GetBufferObjectParameterivAPPLE(struct gl_context *ctx, GLuint name,
+ GLenum pname, GLint* params)
+{
+ struct gl_buffer_object *bufObj;
+
+ bufObj = _mesa_lookup_bufferobj(ctx, name);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetObjectParameteriv(name = 0x%x) invalid object", name);
+ return;
+ }
+
+ switch (pname) {
+ case GL_PURGEABLE_APPLE:
+ *params = bufObj->Purgeable;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
+ name, pname);
+ break;
+ }
+}
+
+
+static void
+_mesa_GetRenderObjectParameterivAPPLE(struct gl_context *ctx, GLuint name,
+ GLenum pname, GLint* params)
+{
+ struct gl_renderbuffer *bufObj;
+
+ bufObj = _mesa_lookup_renderbuffer(ctx, name);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glObjectUnpurgeable(name = 0x%x)", name);
+ return;
+ }
+
+ switch (pname) {
+ case GL_PURGEABLE_APPLE:
+ *params = bufObj->Purgeable;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
+ name, pname);
+ break;
+ }
+}
+
+
+static void
+_mesa_GetTextureObjectParameterivAPPLE(struct gl_context *ctx, GLuint name,
+ GLenum pname, GLint* params)
+{
+ struct gl_texture_object *bufObj;
+
+ bufObj = _mesa_lookup_texture(ctx, name);
+ if (!bufObj) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glObjectUnpurgeable(name = 0x%x)", name);
+ return;
+ }
+
+ switch (pname) {
+ case GL_PURGEABLE_APPLE:
+ *params = bufObj->Purgeable;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
+ name, pname);
+ break;
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname,
+ GLint* params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (name == 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetObjectParameteriv(name = 0x%x)", name);
+ return;
+ }
+
+ switch (objectType) {
+ case GL_TEXTURE:
+ _mesa_GetTextureObjectParameterivAPPLE (ctx, name, pname, params);
+ break;
+ case GL_BUFFER_OBJECT_APPLE:
+ _mesa_GetBufferObjectParameterivAPPLE (ctx, name, pname, params);
+ break;
+ case GL_RENDERBUFFER_EXT:
+ _mesa_GetRenderObjectParameterivAPPLE (ctx, name, pname, params);
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetObjectParameteriv(name = 0x%x) invalid type: %d",
+ name, objectType);
+ }
+}
+
+#endif /* FEATURE_APPLE_object_purgeable */
diff --git a/mesalib/src/mesa/main/compiler.h b/mesalib/src/mesa/main/compiler.h index 41cd48bc6..c1d773b18 100644 --- a/mesalib/src/mesa/main/compiler.h +++ b/mesalib/src/mesa/main/compiler.h @@ -60,29 +60,7 @@ extern "C" { /**
* Get standard integer types
*/
-#if defined(_MSC_VER)
- typedef __int8 int8_t;
- typedef unsigned __int8 uint8_t;
- typedef __int16 int16_t;
- typedef unsigned __int16 uint16_t;
- typedef __int32 int32_t;
- typedef unsigned __int32 uint32_t;
- typedef __int64 int64_t;
- typedef unsigned __int64 uint64_t;
-
-# if defined(_WIN64)
- typedef __int64 intptr_t;
- typedef unsigned __int64 uintptr_t;
-# else
- typedef __int32 intptr_t;
- typedef unsigned __int32 uintptr_t;
-# endif
-
-# define INT64_C(__val) __val##i64
-# define UINT64_C(__val) __val##ui64
-#else
-# include <stdint.h>
-#endif
+#include <stdint.h>
/**
diff --git a/mesalib/src/mesa/main/context.c b/mesalib/src/mesa/main/context.c index a94231455..cfb6b348b 100644 --- a/mesalib/src/mesa/main/context.c +++ b/mesalib/src/mesa/main/context.c @@ -1,1882 +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(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; -} - - -/*@}*/ +/*
+ * 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 4e391dde4..160e795f7 100644 --- a/mesalib/src/mesa/main/context.h +++ b/mesalib/src/mesa/main/context.h @@ -1,313 +1,313 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.1 - * - * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -/** - * \file context.h - * Mesa context and visual-related functions. - * - * There are three large Mesa data types/classes which are meant to be - * used by device drivers: - * - struct gl_context: this contains the Mesa rendering state - * - struct gl_config: this describes the color buffer (RGB vs. ci), whether or not - * there's a depth buffer, stencil buffer, etc. - * - struct gl_framebuffer: contains pointers to the depth buffer, stencil buffer, - * accum buffer and alpha buffers. - * - * These types should be encapsulated by corresponding device driver - * data types. See xmesa.h and xmesaP.h for an example. - * - * In OOP terms, struct gl_context, struct gl_config, and struct gl_framebuffer are base classes - * which the device driver must derive from. - * - * The following functions create and destroy these data types. - */ - - -#ifndef CONTEXT_H -#define CONTEXT_H - - -#include "imports.h" -#include "mtypes.h" - - -struct _glapi_table; - - -/** \name Visual-related functions */ -/*@{*/ - -extern 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 ); - -extern GLboolean -_mesa_initialize_visual( struct gl_config *v, - 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 ); - -extern void -_mesa_destroy_visual( struct gl_config *vis ); - -/*@}*/ - - -/** \name Context-related functions */ -/*@{*/ - -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(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 ); - -extern void -_mesa_destroy_context( struct gl_context *ctx ); - - -extern void -_mesa_copy_context(const struct gl_context *src, struct gl_context *dst, GLuint mask); - - -extern void -_mesa_check_init_viewport(struct gl_context *ctx, GLuint width, GLuint height); - -extern GLboolean -_mesa_make_current( struct gl_context *ctx, struct gl_framebuffer *drawBuffer, - struct gl_framebuffer *readBuffer ); - -extern GLboolean -_mesa_share_state(struct gl_context *ctx, struct gl_context *ctxToShare); - -extern struct gl_context * -_mesa_get_current_context(void); - -/*@}*/ - -extern void -_mesa_init_get_hash(struct gl_context *ctx); - -extern void -_mesa_notifySwapBuffers(struct gl_context *gc); - - -extern struct _glapi_table * -_mesa_get_dispatch(struct gl_context *ctx); - - -void -_mesa_set_mvp_with_dp4( struct gl_context *ctx, - GLboolean flag ); - - -extern GLboolean -_mesa_valid_to_render(struct gl_context *ctx, const char *where); - - - -/** \name Miscellaneous */ -/*@{*/ - -extern void -_mesa_record_error( struct gl_context *ctx, GLenum error ); - - -extern void -_mesa_finish(struct gl_context *ctx); - -extern void -_mesa_flush(struct gl_context *ctx); - - -extern void GLAPIENTRY -_mesa_Finish( void ); - -extern void GLAPIENTRY -_mesa_Flush( void ); - -/*@}*/ - - -/** - * \name Macros for flushing buffered rendering commands before state changes, - * checking if inside glBegin/glEnd, etc. - */ -/*@{*/ - -/** - * Flush vertices. - * - * \param ctx GL context. - * \param newstate new state. - * - * Checks if dd_function_table::NeedFlush is marked to flush stored vertices, - * and calls dd_function_table::FlushVertices if so. Marks - * __struct gl_contextRec::NewState with \p newstate. - */ -#define FLUSH_VERTICES(ctx, newstate) \ -do { \ - if (MESA_VERBOSE & VERBOSE_STATE) \ - _mesa_debug(ctx, "FLUSH_VERTICES in %s\n", MESA_FUNCTION);\ - if (ctx->Driver.NeedFlush & FLUSH_STORED_VERTICES) \ - ctx->Driver.FlushVertices(ctx, FLUSH_STORED_VERTICES); \ - ctx->NewState |= newstate; \ -} while (0) - -/** - * Flush current state. - * - * \param ctx GL context. - * \param newstate new state. - * - * Checks if dd_function_table::NeedFlush is marked to flush current state, - * and calls dd_function_table::FlushVertices if so. Marks - * __struct gl_contextRec::NewState with \p newstate. - */ -#define FLUSH_CURRENT(ctx, newstate) \ -do { \ - if (MESA_VERBOSE & VERBOSE_STATE) \ - _mesa_debug(ctx, "FLUSH_CURRENT in %s\n", MESA_FUNCTION); \ - if (ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) \ - ctx->Driver.FlushVertices(ctx, FLUSH_UPDATE_CURRENT); \ - ctx->NewState |= newstate; \ -} while (0) - -/** - * Macro to assert that the API call was made outside the - * glBegin()/glEnd() pair, with return value. - * - * \param ctx GL context. - * \param retval value to return value in case the assertion fails. - */ -#define ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, retval) \ -do { \ - if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { \ - _mesa_error(ctx, GL_INVALID_OPERATION, "Inside glBegin/glEnd"); \ - return retval; \ - } \ -} while (0) - -/** - * Macro to assert that the API call was made outside the - * glBegin()/glEnd() pair. - * - * \param ctx GL context. - */ -#define ASSERT_OUTSIDE_BEGIN_END(ctx) \ -do { \ - if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { \ - _mesa_error(ctx, GL_INVALID_OPERATION, "Inside glBegin/glEnd"); \ - return; \ - } \ -} while (0) - -/** - * Macro to assert that the API call was made outside the - * glBegin()/glEnd() pair and flush the vertices. - * - * \param ctx GL context. - */ -#define ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx) \ -do { \ - ASSERT_OUTSIDE_BEGIN_END(ctx); \ - FLUSH_VERTICES(ctx, 0); \ -} while (0) - -/** - * Macro to assert that the API call was made outside the - * glBegin()/glEnd() pair and flush the vertices, with return value. - * - * \param ctx GL context. - * \param retval value to return value in case the assertion fails. - */ -#define ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, retval) \ -do { \ - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, retval); \ - FLUSH_VERTICES(ctx, 0); \ -} while (0) - -/*@}*/ - - - -/** - * Is the secondary color needed? - */ -#define NEED_SECONDARY_COLOR(CTX) \ - (((CTX)->Light.Enabled && \ - (CTX)->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) \ - || (CTX)->Fog.ColorSumEnabled \ - || ((CTX)->VertexProgram._Current && \ - ((CTX)->VertexProgram._Current != (CTX)->VertexProgram._TnlProgram) && \ - ((CTX)->VertexProgram._Current->Base.InputsRead & VERT_BIT_COLOR1)) \ - || ((CTX)->FragmentProgram._Current && \ - ((CTX)->FragmentProgram._Current != (CTX)->FragmentProgram._TexEnvProgram) && \ - ((CTX)->FragmentProgram._Current->Base.InputsRead & FRAG_BIT_COL1)) \ - ) - - -/** - * Is RGBA LogicOp enabled? - */ -#define RGBA_LOGICOP_ENABLED(CTX) \ - ((CTX)->Color.ColorLogicOpEnabled || \ - ((CTX)->Color.BlendEnabled && (CTX)->Color.Blend[0].EquationRGB == GL_LOGIC_OP)) - - -#endif /* CONTEXT_H */ +/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.1
+ *
+ * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/**
+ * \file context.h
+ * Mesa context and visual-related functions.
+ *
+ * There are three large Mesa data types/classes which are meant to be
+ * used by device drivers:
+ * - struct gl_context: this contains the Mesa rendering state
+ * - struct gl_config: this describes the color buffer (RGB vs. ci), whether or not
+ * there's a depth buffer, stencil buffer, etc.
+ * - struct gl_framebuffer: contains pointers to the depth buffer, stencil buffer,
+ * accum buffer and alpha buffers.
+ *
+ * These types should be encapsulated by corresponding device driver
+ * data types. See xmesa.h and xmesaP.h for an example.
+ *
+ * In OOP terms, struct gl_context, struct gl_config, and struct gl_framebuffer are base classes
+ * which the device driver must derive from.
+ *
+ * The following functions create and destroy these data types.
+ */
+
+
+#ifndef CONTEXT_H
+#define CONTEXT_H
+
+
+#include "imports.h"
+#include "mtypes.h"
+
+
+struct _glapi_table;
+
+
+/** \name Visual-related functions */
+/*@{*/
+
+extern 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 );
+
+extern GLboolean
+_mesa_initialize_visual( struct gl_config *v,
+ 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 );
+
+extern void
+_mesa_destroy_visual( struct gl_config *vis );
+
+/*@}*/
+
+
+/** \name Context-related functions */
+/*@{*/
+
+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(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 );
+
+extern void
+_mesa_destroy_context( struct gl_context *ctx );
+
+
+extern void
+_mesa_copy_context(const struct gl_context *src, struct gl_context *dst, GLuint mask);
+
+
+extern void
+_mesa_check_init_viewport(struct gl_context *ctx, GLuint width, GLuint height);
+
+extern GLboolean
+_mesa_make_current( struct gl_context *ctx, struct gl_framebuffer *drawBuffer,
+ struct gl_framebuffer *readBuffer );
+
+extern GLboolean
+_mesa_share_state(struct gl_context *ctx, struct gl_context *ctxToShare);
+
+extern struct gl_context *
+_mesa_get_current_context(void);
+
+/*@}*/
+
+extern void
+_mesa_init_get_hash(struct gl_context *ctx);
+
+extern void
+_mesa_notifySwapBuffers(struct gl_context *gc);
+
+
+extern struct _glapi_table *
+_mesa_get_dispatch(struct gl_context *ctx);
+
+
+void
+_mesa_set_mvp_with_dp4( struct gl_context *ctx,
+ GLboolean flag );
+
+
+extern GLboolean
+_mesa_valid_to_render(struct gl_context *ctx, const char *where);
+
+
+
+/** \name Miscellaneous */
+/*@{*/
+
+extern void
+_mesa_record_error( struct gl_context *ctx, GLenum error );
+
+
+extern void
+_mesa_finish(struct gl_context *ctx);
+
+extern void
+_mesa_flush(struct gl_context *ctx);
+
+
+extern void GLAPIENTRY
+_mesa_Finish( void );
+
+extern void GLAPIENTRY
+_mesa_Flush( void );
+
+/*@}*/
+
+
+/**
+ * \name Macros for flushing buffered rendering commands before state changes,
+ * checking if inside glBegin/glEnd, etc.
+ */
+/*@{*/
+
+/**
+ * Flush vertices.
+ *
+ * \param ctx GL context.
+ * \param newstate new state.
+ *
+ * Checks if dd_function_table::NeedFlush is marked to flush stored vertices,
+ * and calls dd_function_table::FlushVertices if so. Marks
+ * __struct gl_contextRec::NewState with \p newstate.
+ */
+#define FLUSH_VERTICES(ctx, newstate) \
+do { \
+ if (MESA_VERBOSE & VERBOSE_STATE) \
+ _mesa_debug(ctx, "FLUSH_VERTICES in %s\n", MESA_FUNCTION);\
+ if (ctx->Driver.NeedFlush & FLUSH_STORED_VERTICES) \
+ ctx->Driver.FlushVertices(ctx, FLUSH_STORED_VERTICES); \
+ ctx->NewState |= newstate; \
+} while (0)
+
+/**
+ * Flush current state.
+ *
+ * \param ctx GL context.
+ * \param newstate new state.
+ *
+ * Checks if dd_function_table::NeedFlush is marked to flush current state,
+ * and calls dd_function_table::FlushVertices if so. Marks
+ * __struct gl_contextRec::NewState with \p newstate.
+ */
+#define FLUSH_CURRENT(ctx, newstate) \
+do { \
+ if (MESA_VERBOSE & VERBOSE_STATE) \
+ _mesa_debug(ctx, "FLUSH_CURRENT in %s\n", MESA_FUNCTION); \
+ if (ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) \
+ ctx->Driver.FlushVertices(ctx, FLUSH_UPDATE_CURRENT); \
+ ctx->NewState |= newstate; \
+} while (0)
+
+/**
+ * Macro to assert that the API call was made outside the
+ * glBegin()/glEnd() pair, with return value.
+ *
+ * \param ctx GL context.
+ * \param retval value to return value in case the assertion fails.
+ */
+#define ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, retval) \
+do { \
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { \
+ _mesa_error(ctx, GL_INVALID_OPERATION, "Inside glBegin/glEnd"); \
+ return retval; \
+ } \
+} while (0)
+
+/**
+ * Macro to assert that the API call was made outside the
+ * glBegin()/glEnd() pair.
+ *
+ * \param ctx GL context.
+ */
+#define ASSERT_OUTSIDE_BEGIN_END(ctx) \
+do { \
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { \
+ _mesa_error(ctx, GL_INVALID_OPERATION, "Inside glBegin/glEnd"); \
+ return; \
+ } \
+} while (0)
+
+/**
+ * Macro to assert that the API call was made outside the
+ * glBegin()/glEnd() pair and flush the vertices.
+ *
+ * \param ctx GL context.
+ */
+#define ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx) \
+do { \
+ ASSERT_OUTSIDE_BEGIN_END(ctx); \
+ FLUSH_VERTICES(ctx, 0); \
+} while (0)
+
+/**
+ * Macro to assert that the API call was made outside the
+ * glBegin()/glEnd() pair and flush the vertices, with return value.
+ *
+ * \param ctx GL context.
+ * \param retval value to return value in case the assertion fails.
+ */
+#define ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, retval) \
+do { \
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, retval); \
+ FLUSH_VERTICES(ctx, 0); \
+} while (0)
+
+/*@}*/
+
+
+
+/**
+ * Is the secondary color needed?
+ */
+#define NEED_SECONDARY_COLOR(CTX) \
+ (((CTX)->Light.Enabled && \
+ (CTX)->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) \
+ || (CTX)->Fog.ColorSumEnabled \
+ || ((CTX)->VertexProgram._Current && \
+ ((CTX)->VertexProgram._Current != (CTX)->VertexProgram._TnlProgram) && \
+ ((CTX)->VertexProgram._Current->Base.InputsRead & VERT_BIT_COLOR1)) \
+ || ((CTX)->FragmentProgram._Current && \
+ ((CTX)->FragmentProgram._Current != (CTX)->FragmentProgram._TexEnvProgram) && \
+ ((CTX)->FragmentProgram._Current->Base.InputsRead & FRAG_BIT_COL1)) \
+ )
+
+
+/**
+ * Is RGBA LogicOp enabled?
+ */
+#define RGBA_LOGICOP_ENABLED(CTX) \
+ ((CTX)->Color.ColorLogicOpEnabled || \
+ ((CTX)->Color.BlendEnabled && (CTX)->Color.Blend[0].EquationRGB == GL_LOGIC_OP))
+
+
+#endif /* CONTEXT_H */
diff --git a/mesalib/src/mesa/main/depth.c b/mesalib/src/mesa/main/depth.c index 52c69a6bc..d666ed5fe 100644 --- a/mesalib/src/mesa/main/depth.c +++ b/mesalib/src/mesa/main/depth.c @@ -1,174 +1,174 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#include "glheader.h" -#include "imports.h" -#include "context.h" -#include "depth.h" -#include "enums.h" -#include "macros.h" -#include "mtypes.h" - - -/**********************************************************************/ -/***** API Functions *****/ -/**********************************************************************/ - - - -void GLAPIENTRY -_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) - return; - - FLUSH_VERTICES(ctx, _NEW_DEPTH); - ctx->Depth.Clear = depth; - if (ctx->Driver.ClearDepth) - (*ctx->Driver.ClearDepth)( ctx, ctx->Depth.Clear ); -} - - -void GLAPIENTRY -_mesa_ClearDepthf( GLclampf depth ) -{ - _mesa_ClearDepth(depth); -} - - -void GLAPIENTRY -_mesa_DepthFunc( GLenum func ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glDepthFunc %s\n", _mesa_lookup_enum_by_nr(func)); - - switch (func) { - case GL_LESS: /* (default) pass if incoming z < stored z */ - case GL_GEQUAL: - case GL_LEQUAL: - case GL_GREATER: - case GL_NOTEQUAL: - case GL_EQUAL: - case GL_ALWAYS: - case GL_NEVER: - break; - default: - _mesa_error( ctx, GL_INVALID_ENUM, "glDepth.Func" ); - return; - } - - if (ctx->Depth.Func == func) - return; - - FLUSH_VERTICES(ctx, _NEW_DEPTH); - ctx->Depth.Func = func; - - if (ctx->Driver.DepthFunc) - ctx->Driver.DepthFunc( ctx, func ); -} - - - -void GLAPIENTRY -_mesa_DepthMask( GLboolean flag ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glDepthMask %d\n", flag); - - /* - * GL_TRUE indicates depth buffer writing is enabled (default) - * GL_FALSE indicates depth buffer writing is disabled - */ - if (ctx->Depth.Mask == flag) - return; - - FLUSH_VERTICES(ctx, _NEW_DEPTH); - ctx->Depth.Mask = flag; - - if (ctx->Driver.DepthMask) - ctx->Driver.DepthMask( ctx, flag ); -} - - - -/** - * Specified by the GL_EXT_depth_bounds_test extension. - */ -void GLAPIENTRY -_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; - } - - zmin = CLAMP(zmin, 0.0, 1.0); - zmax = CLAMP(zmax, 0.0, 1.0); - - if (ctx->Depth.BoundsMin == zmin && ctx->Depth.BoundsMax == zmax) - return; - - FLUSH_VERTICES(ctx, _NEW_DEPTH); - ctx->Depth.BoundsMin = (GLfloat) zmin; - ctx->Depth.BoundsMax = (GLfloat) zmax; -} - - -/**********************************************************************/ -/***** Initialization *****/ -/**********************************************************************/ - - -/** - * Initialize the depth buffer attribute group in the given context. - */ -void -_mesa_init_depth(struct gl_context *ctx) -{ - ctx->Depth.Test = GL_FALSE; - ctx->Depth.Clear = 1.0; - ctx->Depth.Func = GL_LESS; - ctx->Depth.Mask = GL_TRUE; -} +/*
+ * Mesa 3-D graphics library
+ * Version: 7.1
+ *
+ * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "imports.h"
+#include "context.h"
+#include "depth.h"
+#include "enums.h"
+#include "macros.h"
+#include "mtypes.h"
+
+
+/**********************************************************************/
+/***** API Functions *****/
+/**********************************************************************/
+
+
+
+void GLAPIENTRY
+_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)
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_DEPTH);
+ ctx->Depth.Clear = depth;
+ if (ctx->Driver.ClearDepth)
+ (*ctx->Driver.ClearDepth)( ctx, ctx->Depth.Clear );
+}
+
+
+void GLAPIENTRY
+_mesa_ClearDepthf( GLclampf depth )
+{
+ _mesa_ClearDepth(depth);
+}
+
+
+void GLAPIENTRY
+_mesa_DepthFunc( GLenum func )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glDepthFunc %s\n", _mesa_lookup_enum_by_nr(func));
+
+ switch (func) {
+ case GL_LESS: /* (default) pass if incoming z < stored z */
+ case GL_GEQUAL:
+ case GL_LEQUAL:
+ case GL_GREATER:
+ case GL_NOTEQUAL:
+ case GL_EQUAL:
+ case GL_ALWAYS:
+ case GL_NEVER:
+ break;
+ default:
+ _mesa_error( ctx, GL_INVALID_ENUM, "glDepth.Func" );
+ return;
+ }
+
+ if (ctx->Depth.Func == func)
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_DEPTH);
+ ctx->Depth.Func = func;
+
+ if (ctx->Driver.DepthFunc)
+ ctx->Driver.DepthFunc( ctx, func );
+}
+
+
+
+void GLAPIENTRY
+_mesa_DepthMask( GLboolean flag )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glDepthMask %d\n", flag);
+
+ /*
+ * GL_TRUE indicates depth buffer writing is enabled (default)
+ * GL_FALSE indicates depth buffer writing is disabled
+ */
+ if (ctx->Depth.Mask == flag)
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_DEPTH);
+ ctx->Depth.Mask = flag;
+
+ if (ctx->Driver.DepthMask)
+ ctx->Driver.DepthMask( ctx, flag );
+}
+
+
+
+/**
+ * Specified by the GL_EXT_depth_bounds_test extension.
+ */
+void GLAPIENTRY
+_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;
+ }
+
+ zmin = CLAMP(zmin, 0.0, 1.0);
+ zmax = CLAMP(zmax, 0.0, 1.0);
+
+ if (ctx->Depth.BoundsMin == zmin && ctx->Depth.BoundsMax == zmax)
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_DEPTH);
+ ctx->Depth.BoundsMin = (GLfloat) zmin;
+ ctx->Depth.BoundsMax = (GLfloat) zmax;
+}
+
+
+/**********************************************************************/
+/***** Initialization *****/
+/**********************************************************************/
+
+
+/**
+ * Initialize the depth buffer attribute group in the given context.
+ */
+void
+_mesa_init_depth(struct gl_context *ctx)
+{
+ ctx->Depth.Test = GL_FALSE;
+ ctx->Depth.Clear = 1.0;
+ ctx->Depth.Func = GL_LESS;
+ ctx->Depth.Mask = GL_TRUE;
+}
diff --git a/mesalib/src/mesa/main/dlopen.c b/mesalib/src/mesa/main/dlopen.c index 57a33292e..62d9023a9 100644 --- a/mesalib/src/mesa/main/dlopen.c +++ b/mesalib/src/mesa/main/dlopen.c @@ -51,7 +51,7 @@ _mesa_dlopen(const char *libname, int flags) #elif defined(_GNU_SOURCE) flags = RTLD_LAZY | RTLD_GLOBAL; /* Overriding flags at this time */ return dlopen(libname, flags); -#elif defined(__MINGW32__) +#elif defined(__MINGW32__) | defined(_MSC_VER) return LoadLibraryA(libname); #else return NULL; @@ -82,7 +82,7 @@ _mesa_dlsym(void *handle, const char *fname) u.v = dlsym(handle, fname2); #elif defined(_GNU_SOURCE) u.v = dlsym(handle, fname); -#elif defined(__MINGW32__) +#elif defined(__MINGW32__) | defined(_MSC_VER) u.v = (void *) GetProcAddress(handle, fname); #else u.v = NULL; @@ -101,7 +101,7 @@ _mesa_dlclose(void *handle) (void) handle; #elif defined(_GNU_SOURCE) dlclose(handle); -#elif defined(__MINGW32__) +#elif defined(__MINGW32__) | defined(_MSC_VER) FreeLibrary(handle); #else (void) handle; diff --git a/mesalib/src/mesa/main/hint.c b/mesalib/src/mesa/main/hint.c index ff8d88fff..aea0d7022 100644 --- a/mesalib/src/mesa/main/hint.c +++ b/mesalib/src/mesa/main/hint.c @@ -1,147 +1,147 @@ - -/* - * Mesa 3-D graphics library - * Version: 4.1 - * - * Copyright (C) 1999-2002 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#include "glheader.h" -#include "enums.h" -#include "context.h" -#include "hint.h" -#include "imports.h" -#include "mtypes.h" - - - -void GLAPIENTRY -_mesa_Hint( GLenum target, GLenum mode ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _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)"); - return; - } - - switch (target) { - case GL_FOG_HINT: - if (ctx->Hint.Fog == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.Fog = mode; - break; - case GL_LINE_SMOOTH_HINT: - if (ctx->Hint.LineSmooth == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.LineSmooth = mode; - break; - case GL_PERSPECTIVE_CORRECTION_HINT: - if (ctx->Hint.PerspectiveCorrection == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.PerspectiveCorrection = mode; - break; - case GL_POINT_SMOOTH_HINT: - if (ctx->Hint.PointSmooth == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.PointSmooth = mode; - break; - case GL_POLYGON_SMOOTH_HINT: - if (ctx->Hint.PolygonSmooth == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.PolygonSmooth = mode; - break; - - /* GL_EXT_clip_volume_hint */ - case GL_CLIP_VOLUME_CLIPPING_HINT_EXT: - if (ctx->Hint.ClipVolumeClipping == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.ClipVolumeClipping = mode; - break; - - /* GL_ARB_texture_compression */ - case GL_TEXTURE_COMPRESSION_HINT_ARB: - if (ctx->Hint.TextureCompression == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.TextureCompression = mode; - break; - - /* GL_SGIS_generate_mipmap */ - case GL_GENERATE_MIPMAP_HINT_SGIS: - if (ctx->Hint.GenerateMipmap == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.GenerateMipmap = mode; - break; - - /* GL_ARB_fragment_shader */ - case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB: - if (!ctx->Extensions.ARB_fragment_shader) { - _mesa_error(ctx, GL_INVALID_ENUM, "glHint(target)"); - return; - } - if (ctx->Hint.FragmentShaderDerivative == mode) - return; - FLUSH_VERTICES(ctx, _NEW_HINT); - ctx->Hint.FragmentShaderDerivative = mode; - break; - - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glHint(target)"); - return; - } - - if (ctx->Driver.Hint) { - (*ctx->Driver.Hint)( ctx, target, mode ); - } -} - - -/**********************************************************************/ -/***** Initialization *****/ -/**********************************************************************/ - -void _mesa_init_hint( struct gl_context * ctx ) -{ - /* Hint group */ - ctx->Hint.PerspectiveCorrection = GL_DONT_CARE; - ctx->Hint.PointSmooth = GL_DONT_CARE; - ctx->Hint.LineSmooth = GL_DONT_CARE; - ctx->Hint.PolygonSmooth = GL_DONT_CARE; - ctx->Hint.Fog = GL_DONT_CARE; - ctx->Hint.ClipVolumeClipping = GL_DONT_CARE; - ctx->Hint.TextureCompression = GL_DONT_CARE; - ctx->Hint.GenerateMipmap = GL_DONT_CARE; - ctx->Hint.FragmentShaderDerivative = GL_DONT_CARE; -} +
+/*
+ * Mesa 3-D graphics library
+ * Version: 4.1
+ *
+ * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "enums.h"
+#include "context.h"
+#include "hint.h"
+#include "imports.h"
+#include "mtypes.h"
+
+
+
+void GLAPIENTRY
+_mesa_Hint( GLenum target, GLenum mode )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _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)");
+ return;
+ }
+
+ switch (target) {
+ case GL_FOG_HINT:
+ if (ctx->Hint.Fog == mode)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_HINT);
+ ctx->Hint.Fog = mode;
+ break;
+ case GL_LINE_SMOOTH_HINT:
+ if (ctx->Hint.LineSmooth == mode)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_HINT);
+ ctx->Hint.LineSmooth = mode;
+ break;
+ case GL_PERSPECTIVE_CORRECTION_HINT:
+ if (ctx->Hint.PerspectiveCorrection == mode)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_HINT);
+ ctx->Hint.PerspectiveCorrection = mode;
+ break;
+ case GL_POINT_SMOOTH_HINT:
+ if (ctx->Hint.PointSmooth == mode)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_HINT);
+ ctx->Hint.PointSmooth = mode;
+ break;
+ case GL_POLYGON_SMOOTH_HINT:
+ if (ctx->Hint.PolygonSmooth == mode)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_HINT);
+ ctx->Hint.PolygonSmooth = mode;
+ break;
+
+ /* GL_EXT_clip_volume_hint */
+ case GL_CLIP_VOLUME_CLIPPING_HINT_EXT:
+ if (ctx->Hint.ClipVolumeClipping == mode)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_HINT);
+ ctx->Hint.ClipVolumeClipping = mode;
+ break;
+
+ /* GL_ARB_texture_compression */
+ case GL_TEXTURE_COMPRESSION_HINT_ARB:
+ if (ctx->Hint.TextureCompression == mode)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_HINT);
+ ctx->Hint.TextureCompression = mode;
+ break;
+
+ /* GL_SGIS_generate_mipmap */
+ case GL_GENERATE_MIPMAP_HINT_SGIS:
+ if (ctx->Hint.GenerateMipmap == mode)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_HINT);
+ ctx->Hint.GenerateMipmap = mode;
+ break;
+
+ /* GL_ARB_fragment_shader */
+ case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB:
+ if (!ctx->Extensions.ARB_fragment_shader) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glHint(target)");
+ return;
+ }
+ if (ctx->Hint.FragmentShaderDerivative == mode)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_HINT);
+ ctx->Hint.FragmentShaderDerivative = mode;
+ break;
+
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glHint(target)");
+ return;
+ }
+
+ if (ctx->Driver.Hint) {
+ (*ctx->Driver.Hint)( ctx, target, mode );
+ }
+}
+
+
+/**********************************************************************/
+/***** Initialization *****/
+/**********************************************************************/
+
+void _mesa_init_hint( struct gl_context * ctx )
+{
+ /* Hint group */
+ ctx->Hint.PerspectiveCorrection = GL_DONT_CARE;
+ ctx->Hint.PointSmooth = GL_DONT_CARE;
+ ctx->Hint.LineSmooth = GL_DONT_CARE;
+ ctx->Hint.PolygonSmooth = GL_DONT_CARE;
+ ctx->Hint.Fog = GL_DONT_CARE;
+ ctx->Hint.ClipVolumeClipping = GL_DONT_CARE;
+ ctx->Hint.TextureCompression = GL_DONT_CARE;
+ ctx->Hint.GenerateMipmap = GL_DONT_CARE;
+ ctx->Hint.FragmentShaderDerivative = GL_DONT_CARE;
+}
diff --git a/mesalib/src/mesa/main/lines.c b/mesalib/src/mesa/main/lines.c index 79bf5679d..1df409f45 100644 --- a/mesalib/src/mesa/main/lines.c +++ b/mesalib/src/mesa/main/lines.c @@ -1,117 +1,117 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#include "glheader.h" -#include "context.h" -#include "lines.h" -#include "macros.h" -#include "mtypes.h" - - -/** - * Set the line width. - * - * \param width line width in pixels. - * - * \sa glLineWidth(). - */ -void GLAPIENTRY -_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; - } - - if (ctx->Line.Width == width) - return; - - FLUSH_VERTICES(ctx, _NEW_LINE); - ctx->Line.Width = width; - - if (ctx->Driver.LineWidth) - ctx->Driver.LineWidth(ctx, width); -} - - -/** - * Set the line stipple pattern. - * - * \param factor pattern scale factor. - * \param pattern bit pattern. - * - * \sa glLineStipple(). - * - * Updates gl_line_attrib::StippleFactor and gl_line_attrib::StipplePattern. On - * change flushes the vertices and notifies the driver via - * the dd_function_table::LineStipple callback. - */ -void GLAPIENTRY -_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 && - ctx->Line.StipplePattern == pattern) - return; - - FLUSH_VERTICES(ctx, _NEW_LINE); - ctx->Line.StippleFactor = factor; - ctx->Line.StipplePattern = pattern; - - if (ctx->Driver.LineStipple) - ctx->Driver.LineStipple( ctx, factor, pattern ); -} - - -/** - * Initialize the context line state. - * - * \param ctx GL context. - * - * Initializes __struct gl_contextRec::Line and line related constants in - * __struct gl_contextRec::Const. - */ -void GLAPIENTRY -_mesa_init_line( struct gl_context * ctx ) -{ - ctx->Line.SmoothFlag = GL_FALSE; - ctx->Line.StippleFlag = GL_FALSE; - ctx->Line.Width = 1.0; - ctx->Line.StipplePattern = 0xffff; - ctx->Line.StippleFactor = 1; -} +/*
+ * Mesa 3-D graphics library
+ * Version: 6.5.3
+ *
+ * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "lines.h"
+#include "macros.h"
+#include "mtypes.h"
+
+
+/**
+ * Set the line width.
+ *
+ * \param width line width in pixels.
+ *
+ * \sa glLineWidth().
+ */
+void GLAPIENTRY
+_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;
+ }
+
+ if (ctx->Line.Width == width)
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_LINE);
+ ctx->Line.Width = width;
+
+ if (ctx->Driver.LineWidth)
+ ctx->Driver.LineWidth(ctx, width);
+}
+
+
+/**
+ * Set the line stipple pattern.
+ *
+ * \param factor pattern scale factor.
+ * \param pattern bit pattern.
+ *
+ * \sa glLineStipple().
+ *
+ * Updates gl_line_attrib::StippleFactor and gl_line_attrib::StipplePattern. On
+ * change flushes the vertices and notifies the driver via
+ * the dd_function_table::LineStipple callback.
+ */
+void GLAPIENTRY
+_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 &&
+ ctx->Line.StipplePattern == pattern)
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_LINE);
+ ctx->Line.StippleFactor = factor;
+ ctx->Line.StipplePattern = pattern;
+
+ if (ctx->Driver.LineStipple)
+ ctx->Driver.LineStipple( ctx, factor, pattern );
+}
+
+
+/**
+ * Initialize the context line state.
+ *
+ * \param ctx GL context.
+ *
+ * Initializes __struct gl_contextRec::Line and line related constants in
+ * __struct gl_contextRec::Const.
+ */
+void GLAPIENTRY
+_mesa_init_line( struct gl_context * ctx )
+{
+ ctx->Line.SmoothFlag = GL_FALSE;
+ ctx->Line.StippleFlag = GL_FALSE;
+ ctx->Line.Width = 1.0;
+ ctx->Line.StipplePattern = 0xffff;
+ ctx->Line.StippleFactor = 1;
+}
diff --git a/mesalib/src/mesa/main/queryobj.c b/mesalib/src/mesa/main/queryobj.c index fa35c6ce5..dc9f18a65 100644 --- a/mesalib/src/mesa/main/queryobj.c +++ b/mesalib/src/mesa/main/queryobj.c @@ -1,623 +1,623 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -#include "glheader.h" -#include "context.h" -#include "enums.h" -#include "hash.h" -#include "imports.h" -#include "queryobj.h" -#include "mfeatures.h" -#include "mtypes.h" -#include "main/dispatch.h" - - -#if FEATURE_queryobj - - -/** - * Allocate a new query object. This is a fallback routine called via - * ctx->Driver.NewQueryObject(). - * \param ctx - rendering context - * \param id - the new object's ID - * \return pointer to new query_object object or NULL if out of memory. - */ -static struct gl_query_object * -_mesa_new_query_object(struct gl_context *ctx, GLuint id) -{ - struct gl_query_object *q = MALLOC_STRUCT(gl_query_object); - (void) ctx; - if (q) { - q->Id = id; - q->Result = 0; - q->Active = GL_FALSE; - q->Ready = GL_TRUE; /* correct, see spec */ - } - return q; -} - - -/** - * Begin a query. Software driver fallback. - * Called via ctx->Driver.BeginQuery(). - */ -static void -_mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q) -{ - /* no-op */ -} - - -/** - * End a query. Software driver fallback. - * Called via ctx->Driver.EndQuery(). - */ -static void -_mesa_end_query(struct gl_context *ctx, struct gl_query_object *q) -{ - q->Ready = GL_TRUE; -} - - -/** - * Wait for query to complete. Software driver fallback. - * Called via ctx->Driver.WaitQuery(). - */ -static void -_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q) -{ - /* For software drivers, _mesa_end_query() should have completed the query. - * For real hardware, implement a proper WaitQuery() driver function, - * which may require issuing a flush. - */ - assert(q->Ready); -} - - -/** - * Check if a query results are ready. Software driver fallback. - * Called via ctx->Driver.CheckQuery(). - */ -static void -_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q) -{ - /* No-op for sw rendering. - * HW drivers may need to flush at this time. - */ -} - - -/** - * Delete a query object. Called via ctx->Driver.DeleteQuery(). - * Not removed from hash table here. - */ -static void -_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q) -{ - free(q); -} - - -void -_mesa_init_query_object_functions(struct dd_function_table *driver) -{ - driver->NewQueryObject = _mesa_new_query_object; - driver->DeleteQuery = _mesa_delete_query; - driver->BeginQuery = _mesa_begin_query; - driver->EndQuery = _mesa_end_query; - driver->WaitQuery = _mesa_wait_query; - driver->CheckQuery = _mesa_check_query; -} - - -/** - * Return pointer to the query object binding point for the given target. - * \return NULL if invalid target, else the address of binding point - */ -static struct gl_query_object ** -get_query_binding_point(struct gl_context *ctx, GLenum target) -{ - switch (target) { - case GL_SAMPLES_PASSED_ARB: - if (ctx->Extensions.ARB_occlusion_query) - return &ctx->Query.CurrentOcclusionObject; - else - return NULL; - case GL_ANY_SAMPLES_PASSED: - if (ctx->Extensions.ARB_occlusion_query2) - return &ctx->Query.CurrentOcclusionObject; - else - return NULL; - case GL_TIME_ELAPSED_EXT: - if (ctx->Extensions.EXT_timer_query) - return &ctx->Query.CurrentTimerObject; - else - return NULL; -#if FEATURE_EXT_transform_feedback - case GL_PRIMITIVES_GENERATED: - if (ctx->Extensions.EXT_transform_feedback) - return &ctx->Query.PrimitivesGenerated; - else - return NULL; - case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: - if (ctx->Extensions.EXT_transform_feedback) - return &ctx->Query.PrimitivesWritten; - else - return NULL; -#endif - default: - return NULL; - } -} - - -void GLAPIENTRY -_mesa_GenQueriesARB(GLsizei n, GLuint *ids) -{ - GLuint first; - 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; - } - - /* No query objects can be active at this time! */ - if (ctx->Query.CurrentOcclusionObject || - ctx->Query.CurrentTimerObject) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB"); - return; - } - - first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n); - if (first) { - GLsizei i; - for (i = 0; i < n; i++) { - struct gl_query_object *q - = ctx->Driver.NewQueryObject(ctx, first + i); - if (!q) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB"); - return; - } - ids[i] = first + i; - _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q); - } - } -} - - -void GLAPIENTRY -_mesa_DeleteQueriesARB(GLsizei n, const GLuint *ids) -{ - GLint i; - 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; - } - - /* No query objects can be active at this time! */ - if (ctx->Query.CurrentOcclusionObject || - ctx->Query.CurrentTimerObject) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteQueriesARB"); - return; - } - - for (i = 0; i < n; i++) { - if (ids[i] > 0) { - struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]); - if (q) { - ASSERT(!q->Active); /* should be caught earlier */ - _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]); - ctx->Driver.DeleteQuery(ctx, q); - } - } - } -} - - -GLboolean GLAPIENTRY -_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 - return GL_FALSE; -} - - -static void GLAPIENTRY -_mesa_BeginQueryARB(GLenum target, GLuint id) -{ - struct gl_query_object *q, **bindpt; - 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); - if (!bindpt) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)"); - return; - } - - if (id == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB(id==0)"); - return; - } - - q = _mesa_lookup_query_object(ctx, id); - if (!q) { - /* create new object */ - q = ctx->Driver.NewQueryObject(ctx, id); - if (!q) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQueryARB"); - return; - } - _mesa_HashInsert(ctx->Query.QueryObjects, id, q); - } - else { - /* pre-existing object */ - if (q->Active) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBeginQueryARB(query already active)"); - return; - } - } - - q->Target = target; - q->Active = GL_TRUE; - q->Result = 0; - q->Ready = GL_FALSE; - - /* XXX should probably refcount query objects */ - *bindpt = q; - - ctx->Driver.BeginQuery(ctx, q); -} - - -static void GLAPIENTRY -_mesa_EndQueryARB(GLenum target) -{ - struct gl_query_object *q, **bindpt; - 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); - if (!bindpt) { - _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)"); - return; - } - - /* XXX should probably refcount query objects */ - q = *bindpt; - *bindpt = NULL; - - if (!q || !q->Active) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glEndQueryARB(no matching glBeginQueryARB)"); - return; - } - - q->Active = GL_FALSE; - ctx->Driver.EndQuery(ctx, q); -} - - -void GLAPIENTRY -_mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params) -{ - struct gl_query_object *q, **bindpt; - 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)"); - return; - } - - q = *bindpt; - - switch (pname) { - case GL_QUERY_COUNTER_BITS_ARB: - *params = 8 * sizeof(q->Result); - break; - case GL_CURRENT_QUERY_ARB: - *params = q ? q->Id : 0; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(pname)"); - return; - } -} - - -void GLAPIENTRY -_mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params) -{ - struct gl_query_object *q = NULL; - 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); - - if (!q || q->Active) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetQueryObjectivARB(id=%d is invalid or active)", id); - return; - } - - switch (pname) { - case GL_QUERY_RESULT_ARB: - if (!q->Ready) - ctx->Driver.WaitQuery(ctx, q); - /* if result is too large for returned type, clamp to max value */ - if (q->Target == GL_ANY_SAMPLES_PASSED) { - if (q->Result) - *params = GL_TRUE; - else - *params = GL_FALSE; - } else { - if (q->Result > 0x7fffffff) { - *params = 0x7fffffff; - } - else { - *params = (GLint)q->Result; - } - } - break; - case GL_QUERY_RESULT_AVAILABLE_ARB: - if (!q->Ready) - ctx->Driver.CheckQuery( ctx, q ); - *params = q->Ready; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)"); - return; - } -} - - -void GLAPIENTRY -_mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params) -{ - struct gl_query_object *q = NULL; - 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); - - if (!q || q->Active) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetQueryObjectuivARB(id=%d is invalid or active)", id); - return; - } - - switch (pname) { - case GL_QUERY_RESULT_ARB: - if (!q->Ready) - ctx->Driver.WaitQuery(ctx, q); - /* if result is too large for returned type, clamp to max value */ - if (q->Target == GL_ANY_SAMPLES_PASSED) { - if (q->Result) - *params = GL_TRUE; - else - *params = GL_FALSE; - } else { - if (q->Result > 0xffffffff) { - *params = 0xffffffff; - } - else { - *params = (GLuint)q->Result; - } - } - break; - case GL_QUERY_RESULT_AVAILABLE_ARB: - if (!q->Ready) - ctx->Driver.CheckQuery( ctx, q ); - *params = q->Ready; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)"); - return; - } -} - - -/** - * New with GL_EXT_timer_query - */ -static void GLAPIENTRY -_mesa_GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params) -{ - struct gl_query_object *q = NULL; - 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); - - if (!q || q->Active) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetQueryObjectui64vARB(id=%d is invalid or active)", id); - return; - } - - switch (pname) { - case GL_QUERY_RESULT_ARB: - if (!q->Ready) - ctx->Driver.WaitQuery(ctx, q); - *params = q->Result; - break; - case GL_QUERY_RESULT_AVAILABLE_ARB: - if (!q->Ready) - ctx->Driver.CheckQuery( ctx, q ); - *params = q->Ready; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)"); - return; - } -} - - -/** - * New with GL_EXT_timer_query - */ -static void GLAPIENTRY -_mesa_GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params) -{ - struct gl_query_object *q = NULL; - 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); - - if (!q || q->Active) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id); - return; - } - - switch (pname) { - case GL_QUERY_RESULT_ARB: - if (!q->Ready) - ctx->Driver.WaitQuery(ctx, q); - *params = q->Result; - break; - case GL_QUERY_RESULT_AVAILABLE_ARB: - if (!q->Ready) - ctx->Driver.CheckQuery( ctx, q ); - *params = q->Ready; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)"); - return; - } -} - - -void -_mesa_init_queryobj_dispatch(struct _glapi_table *disp) -{ - SET_GenQueriesARB(disp, _mesa_GenQueriesARB); - SET_DeleteQueriesARB(disp, _mesa_DeleteQueriesARB); - SET_IsQueryARB(disp, _mesa_IsQueryARB); - SET_BeginQueryARB(disp, _mesa_BeginQueryARB); - SET_EndQueryARB(disp, _mesa_EndQueryARB); - SET_GetQueryivARB(disp, _mesa_GetQueryivARB); - SET_GetQueryObjectivARB(disp, _mesa_GetQueryObjectivARB); - SET_GetQueryObjectuivARB(disp, _mesa_GetQueryObjectuivARB); - - SET_GetQueryObjecti64vEXT(disp, _mesa_GetQueryObjecti64vEXT); - SET_GetQueryObjectui64vEXT(disp, _mesa_GetQueryObjectui64vEXT); -} - - -#endif /* FEATURE_queryobj */ - - -/** - * Allocate/init the context state related to query objects. - */ -void -_mesa_init_queryobj(struct gl_context *ctx) -{ - ctx->Query.QueryObjects = _mesa_NewHashTable(); - ctx->Query.CurrentOcclusionObject = NULL; -} - - -/** - * Callback for deleting a query object. Called by _mesa_HashDeleteAll(). - */ -static void -delete_queryobj_cb(GLuint id, void *data, void *userData) -{ - struct gl_query_object *q= (struct gl_query_object *) data; - struct gl_context *ctx = (struct gl_context *)userData; - ctx->Driver.DeleteQuery(ctx, q); -} - - -/** - * Free the context state related to query objects. - */ -void -_mesa_free_queryobj_data(struct gl_context *ctx) -{ - _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx); - _mesa_DeleteHashTable(ctx->Query.QueryObjects); -} +/*
+ * Mesa 3-D graphics library
+ * Version: 7.1
+ *
+ * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "enums.h"
+#include "hash.h"
+#include "imports.h"
+#include "queryobj.h"
+#include "mfeatures.h"
+#include "mtypes.h"
+#include "main/dispatch.h"
+
+
+#if FEATURE_queryobj
+
+
+/**
+ * Allocate a new query object. This is a fallback routine called via
+ * ctx->Driver.NewQueryObject().
+ * \param ctx - rendering context
+ * \param id - the new object's ID
+ * \return pointer to new query_object object or NULL if out of memory.
+ */
+struct gl_query_object *
+_mesa_new_query_object(struct gl_context *ctx, GLuint id)
+{
+ struct gl_query_object *q = MALLOC_STRUCT(gl_query_object);
+ (void) ctx;
+ if (q) {
+ q->Id = id;
+ q->Result = 0;
+ q->Active = GL_FALSE;
+ q->Ready = GL_TRUE; /* correct, see spec */
+ }
+ return q;
+}
+
+
+/**
+ * Begin a query. Software driver fallback.
+ * Called via ctx->Driver.BeginQuery().
+ */
+void
+_mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q)
+{
+ /* no-op */
+}
+
+
+/**
+ * End a query. Software driver fallback.
+ * Called via ctx->Driver.EndQuery().
+ */
+void
+_mesa_end_query(struct gl_context *ctx, struct gl_query_object *q)
+{
+ q->Ready = GL_TRUE;
+}
+
+
+/**
+ * Wait for query to complete. Software driver fallback.
+ * Called via ctx->Driver.WaitQuery().
+ */
+void
+_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q)
+{
+ /* For software drivers, _mesa_end_query() should have completed the query.
+ * For real hardware, implement a proper WaitQuery() driver function,
+ * which may require issuing a flush.
+ */
+ assert(q->Ready);
+}
+
+
+/**
+ * Check if a query results are ready. Software driver fallback.
+ * Called via ctx->Driver.CheckQuery().
+ */
+static void
+_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q)
+{
+ /* No-op for sw rendering.
+ * HW drivers may need to flush at this time.
+ */
+}
+
+
+/**
+ * Delete a query object. Called via ctx->Driver.DeleteQuery().
+ * Not removed from hash table here.
+ */
+void
+_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q)
+{
+ free(q);
+}
+
+
+void
+_mesa_init_query_object_functions(struct dd_function_table *driver)
+{
+ driver->NewQueryObject = _mesa_new_query_object;
+ driver->DeleteQuery = _mesa_delete_query;
+ driver->BeginQuery = _mesa_begin_query;
+ driver->EndQuery = _mesa_end_query;
+ driver->WaitQuery = _mesa_wait_query;
+ driver->CheckQuery = _mesa_check_query;
+}
+
+
+/**
+ * Return pointer to the query object binding point for the given target.
+ * \return NULL if invalid target, else the address of binding point
+ */
+static struct gl_query_object **
+get_query_binding_point(struct gl_context *ctx, GLenum target)
+{
+ switch (target) {
+ case GL_SAMPLES_PASSED_ARB:
+ if (ctx->Extensions.ARB_occlusion_query)
+ return &ctx->Query.CurrentOcclusionObject;
+ else
+ return NULL;
+ case GL_ANY_SAMPLES_PASSED:
+ if (ctx->Extensions.ARB_occlusion_query2)
+ return &ctx->Query.CurrentOcclusionObject;
+ else
+ return NULL;
+ case GL_TIME_ELAPSED_EXT:
+ if (ctx->Extensions.EXT_timer_query)
+ return &ctx->Query.CurrentTimerObject;
+ else
+ return NULL;
+#if FEATURE_EXT_transform_feedback
+ case GL_PRIMITIVES_GENERATED:
+ if (ctx->Extensions.EXT_transform_feedback)
+ return &ctx->Query.PrimitivesGenerated;
+ else
+ return NULL;
+ case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
+ if (ctx->Extensions.EXT_transform_feedback)
+ return &ctx->Query.PrimitivesWritten;
+ else
+ return NULL;
+#endif
+ default:
+ return NULL;
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GenQueriesARB(GLsizei n, GLuint *ids)
+{
+ GLuint first;
+ 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;
+ }
+
+ /* No query objects can be active at this time! */
+ if (ctx->Query.CurrentOcclusionObject ||
+ ctx->Query.CurrentTimerObject) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB");
+ return;
+ }
+
+ first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
+ if (first) {
+ GLsizei i;
+ for (i = 0; i < n; i++) {
+ struct gl_query_object *q
+ = ctx->Driver.NewQueryObject(ctx, first + i);
+ if (!q) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB");
+ return;
+ }
+ ids[i] = first + i;
+ _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q);
+ }
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_DeleteQueriesARB(GLsizei n, const GLuint *ids)
+{
+ GLint i;
+ 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;
+ }
+
+ /* No query objects can be active at this time! */
+ if (ctx->Query.CurrentOcclusionObject ||
+ ctx->Query.CurrentTimerObject) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteQueriesARB");
+ return;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (ids[i] > 0) {
+ struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
+ if (q) {
+ ASSERT(!q->Active); /* should be caught earlier */
+ _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]);
+ ctx->Driver.DeleteQuery(ctx, q);
+ }
+ }
+ }
+}
+
+
+GLboolean GLAPIENTRY
+_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
+ return GL_FALSE;
+}
+
+
+static void GLAPIENTRY
+_mesa_BeginQueryARB(GLenum target, GLuint id)
+{
+ struct gl_query_object *q, **bindpt;
+ 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);
+ if (!bindpt) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
+ return;
+ }
+
+ if (id == 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB(id==0)");
+ return;
+ }
+
+ q = _mesa_lookup_query_object(ctx, id);
+ if (!q) {
+ /* create new object */
+ q = ctx->Driver.NewQueryObject(ctx, id);
+ if (!q) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQueryARB");
+ return;
+ }
+ _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
+ }
+ else {
+ /* pre-existing object */
+ if (q->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBeginQueryARB(query already active)");
+ return;
+ }
+ }
+
+ q->Target = target;
+ q->Active = GL_TRUE;
+ q->Result = 0;
+ q->Ready = GL_FALSE;
+
+ /* XXX should probably refcount query objects */
+ *bindpt = q;
+
+ ctx->Driver.BeginQuery(ctx, q);
+}
+
+
+static void GLAPIENTRY
+_mesa_EndQueryARB(GLenum target)
+{
+ struct gl_query_object *q, **bindpt;
+ 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);
+ if (!bindpt) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
+ return;
+ }
+
+ /* XXX should probably refcount query objects */
+ q = *bindpt;
+ *bindpt = NULL;
+
+ if (!q || !q->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glEndQueryARB(no matching glBeginQueryARB)");
+ return;
+ }
+
+ q->Active = GL_FALSE;
+ ctx->Driver.EndQuery(ctx, q);
+}
+
+
+void GLAPIENTRY
+_mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params)
+{
+ struct gl_query_object *q, **bindpt;
+ 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)");
+ return;
+ }
+
+ q = *bindpt;
+
+ switch (pname) {
+ case GL_QUERY_COUNTER_BITS_ARB:
+ *params = 8 * sizeof(q->Result);
+ break;
+ case GL_CURRENT_QUERY_ARB:
+ *params = q ? q->Id : 0;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(pname)");
+ return;
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params)
+{
+ struct gl_query_object *q = NULL;
+ 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);
+
+ if (!q || q->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetQueryObjectivARB(id=%d is invalid or active)", id);
+ return;
+ }
+
+ switch (pname) {
+ case GL_QUERY_RESULT_ARB:
+ if (!q->Ready)
+ ctx->Driver.WaitQuery(ctx, q);
+ /* if result is too large for returned type, clamp to max value */
+ if (q->Target == GL_ANY_SAMPLES_PASSED) {
+ if (q->Result)
+ *params = GL_TRUE;
+ else
+ *params = GL_FALSE;
+ } else {
+ if (q->Result > 0x7fffffff) {
+ *params = 0x7fffffff;
+ }
+ else {
+ *params = (GLint)q->Result;
+ }
+ }
+ break;
+ case GL_QUERY_RESULT_AVAILABLE_ARB:
+ if (!q->Ready)
+ ctx->Driver.CheckQuery( ctx, q );
+ *params = q->Ready;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
+ return;
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params)
+{
+ struct gl_query_object *q = NULL;
+ 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);
+
+ if (!q || q->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
+ return;
+ }
+
+ switch (pname) {
+ case GL_QUERY_RESULT_ARB:
+ if (!q->Ready)
+ ctx->Driver.WaitQuery(ctx, q);
+ /* if result is too large for returned type, clamp to max value */
+ if (q->Target == GL_ANY_SAMPLES_PASSED) {
+ if (q->Result)
+ *params = GL_TRUE;
+ else
+ *params = GL_FALSE;
+ } else {
+ if (q->Result > 0xffffffff) {
+ *params = 0xffffffff;
+ }
+ else {
+ *params = (GLuint)q->Result;
+ }
+ }
+ break;
+ case GL_QUERY_RESULT_AVAILABLE_ARB:
+ if (!q->Ready)
+ ctx->Driver.CheckQuery( ctx, q );
+ *params = q->Ready;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
+ return;
+ }
+}
+
+
+/**
+ * New with GL_EXT_timer_query
+ */
+static void GLAPIENTRY
+_mesa_GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params)
+{
+ struct gl_query_object *q = NULL;
+ 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);
+
+ if (!q || q->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
+ return;
+ }
+
+ switch (pname) {
+ case GL_QUERY_RESULT_ARB:
+ if (!q->Ready)
+ ctx->Driver.WaitQuery(ctx, q);
+ *params = q->Result;
+ break;
+ case GL_QUERY_RESULT_AVAILABLE_ARB:
+ if (!q->Ready)
+ ctx->Driver.CheckQuery( ctx, q );
+ *params = q->Ready;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)");
+ return;
+ }
+}
+
+
+/**
+ * New with GL_EXT_timer_query
+ */
+static void GLAPIENTRY
+_mesa_GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params)
+{
+ struct gl_query_object *q = NULL;
+ 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);
+
+ if (!q || q->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id);
+ return;
+ }
+
+ switch (pname) {
+ case GL_QUERY_RESULT_ARB:
+ if (!q->Ready)
+ ctx->Driver.WaitQuery(ctx, q);
+ *params = q->Result;
+ break;
+ case GL_QUERY_RESULT_AVAILABLE_ARB:
+ if (!q->Ready)
+ ctx->Driver.CheckQuery( ctx, q );
+ *params = q->Ready;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)");
+ return;
+ }
+}
+
+
+void
+_mesa_init_queryobj_dispatch(struct _glapi_table *disp)
+{
+ SET_GenQueriesARB(disp, _mesa_GenQueriesARB);
+ SET_DeleteQueriesARB(disp, _mesa_DeleteQueriesARB);
+ SET_IsQueryARB(disp, _mesa_IsQueryARB);
+ SET_BeginQueryARB(disp, _mesa_BeginQueryARB);
+ SET_EndQueryARB(disp, _mesa_EndQueryARB);
+ SET_GetQueryivARB(disp, _mesa_GetQueryivARB);
+ SET_GetQueryObjectivARB(disp, _mesa_GetQueryObjectivARB);
+ SET_GetQueryObjectuivARB(disp, _mesa_GetQueryObjectuivARB);
+
+ SET_GetQueryObjecti64vEXT(disp, _mesa_GetQueryObjecti64vEXT);
+ SET_GetQueryObjectui64vEXT(disp, _mesa_GetQueryObjectui64vEXT);
+}
+
+
+#endif /* FEATURE_queryobj */
+
+
+/**
+ * Allocate/init the context state related to query objects.
+ */
+void
+_mesa_init_queryobj(struct gl_context *ctx)
+{
+ ctx->Query.QueryObjects = _mesa_NewHashTable();
+ ctx->Query.CurrentOcclusionObject = NULL;
+}
+
+
+/**
+ * Callback for deleting a query object. Called by _mesa_HashDeleteAll().
+ */
+static void
+delete_queryobj_cb(GLuint id, void *data, void *userData)
+{
+ struct gl_query_object *q= (struct gl_query_object *) data;
+ struct gl_context *ctx = (struct gl_context *)userData;
+ ctx->Driver.DeleteQuery(ctx, q);
+}
+
+
+/**
+ * Free the context state related to query objects.
+ */
+void
+_mesa_free_queryobj_data(struct gl_context *ctx)
+{
+ _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
+ _mesa_DeleteHashTable(ctx->Query.QueryObjects);
+}
diff --git a/mesalib/src/mesa/main/shaderapi.c b/mesalib/src/mesa/main/shaderapi.c index 11b0f884f..252cda845 100644 --- a/mesalib/src/mesa/main/shaderapi.c +++ b/mesalib/src/mesa/main/shaderapi.c @@ -1,1942 +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); - 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 */ -} - +/*
+ * 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 d898bf1d7..b49ddbdbb 100644 --- a/mesalib/src/mesa/main/stencil.c +++ b/mesalib/src/mesa/main/stencil.c @@ -1,614 +1,614 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -/** - * \file stencil.c - * Stencil operations. - * - * Note: There's some conflict between GL_EXT_stencil_two_side and - * OpenGL 2.0's two-sided stencil feature. - * - * With GL_EXT_stencil_two_side, calling glStencilOp/Func/Mask() only the - * front OR back face state (as set by glActiveStencilFaceEXT) is set. - * - * But with OpenGL 2.0, calling glStencilOp/Func/Mask() sets BOTH the - * front AND back state. - * - * Also, note that GL_ATI_separate_stencil is different as well: - * glStencilFuncSeparateATI(GLenum frontfunc, GLenum backfunc, ...) vs. - * glStencilFuncSeparate(GLenum face, GLenum func, ...). - * - * This problem is solved by keeping three sets of stencil state: - * state[0] = GL_FRONT state. - * state[1] = OpenGL 2.0 / GL_ATI_separate_stencil GL_BACK state. - * state[2] = GL_EXT_stencil_two_side GL_BACK state. - */ - - -#include "glheader.h" -#include "imports.h" -#include "context.h" -#include "macros.h" -#include "stencil.h" -#include "mtypes.h" - - -static GLboolean -validate_stencil_op(struct gl_context *ctx, GLenum op) -{ - switch (op) { - case GL_KEEP: - case GL_ZERO: - case GL_REPLACE: - case GL_INCR: - case GL_DECR: - case GL_INVERT: - return GL_TRUE; - case GL_INCR_WRAP_EXT: - case GL_DECR_WRAP_EXT: - if (ctx->Extensions.EXT_stencil_wrap) { - return GL_TRUE; - } - /* FALL-THROUGH */ - default: - return GL_FALSE; - } -} - - -static GLboolean -validate_stencil_func(struct gl_context *ctx, GLenum func) -{ - switch (func) { - case GL_NEVER: - case GL_LESS: - case GL_LEQUAL: - case GL_GREATER: - case GL_GEQUAL: - case GL_EQUAL: - case GL_NOTEQUAL: - case GL_ALWAYS: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Set the clear value for the stencil buffer. - * - * \param s clear value. - * - * \sa glClearStencil(). - * - * Updates gl_stencil_attrib::Clear. On change - * flushes the vertices and notifies the driver via - * the dd_function_table::ClearStencil callback. - */ -void GLAPIENTRY -_mesa_ClearStencil( GLint s ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (ctx->Stencil.Clear == (GLuint) s) - return; - - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.Clear = (GLuint) s; - - if (ctx->Driver.ClearStencil) { - ctx->Driver.ClearStencil( ctx, s ); - } -} - - -/** - * Set the function and reference value for stencil testing. - * - * \param frontfunc front test function. - * \param backfunc back test function. - * \param ref front and back reference value. - * \param mask front and back bitmask. - * - * \sa glStencilFunc(). - * - * Verifies the parameters and updates the respective values in - * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the - * driver via the dd_function_table::StencilFunc callback. - */ -void GLAPIENTRY -_mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask ) -{ - GET_CURRENT_CONTEXT(ctx); - 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)"); - return; - } - if (!validate_stencil_func(ctx, backfunc)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glStencilFuncSeparateATI(backfunc)"); - return; - } - - ref = CLAMP( ref, 0, stencilMax ); - - /* set both front and back state */ - if (ctx->Stencil.Function[0] == frontfunc && - ctx->Stencil.Function[1] == backfunc && - ctx->Stencil.ValueMask[0] == mask && - ctx->Stencil.ValueMask[1] == mask && - ctx->Stencil.Ref[0] == ref && - ctx->Stencil.Ref[1] == ref) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.Function[0] = frontfunc; - ctx->Stencil.Function[1] = backfunc; - ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; - ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; - if (ctx->Driver.StencilFuncSeparate) { - ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT, - frontfunc, ref, mask); - ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, - backfunc, ref, mask); - } -} - - -/** - * Set the function and reference value for stencil testing. - * - * \param func test function. - * \param ref reference value. - * \param mask bitmask. - * - * \sa glStencilFunc(). - * - * Verifies the parameters and updates the respective values in - * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the - * driver via the dd_function_table::StencilFunc callback. - */ -void GLAPIENTRY -_mesa_StencilFunc( GLenum func, GLint ref, GLuint mask ) -{ - GET_CURRENT_CONTEXT(ctx); - const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; - 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; - } - - ref = CLAMP( ref, 0, stencilMax ); - - if (face != 0) { - if (ctx->Stencil.Function[face] == func && - ctx->Stencil.ValueMask[face] == mask && - ctx->Stencil.Ref[face] == ref) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.Function[face] = func; - ctx->Stencil.Ref[face] = ref; - ctx->Stencil.ValueMask[face] = mask; - - /* Only propagate the change to the driver if EXT_stencil_two_side - * is enabled. - */ - if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) { - ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask); - } - } - else { - /* set both front and back state */ - if (ctx->Stencil.Function[0] == func && - ctx->Stencil.Function[1] == func && - ctx->Stencil.ValueMask[0] == mask && - ctx->Stencil.ValueMask[1] == mask && - ctx->Stencil.Ref[0] == ref && - ctx->Stencil.Ref[1] == ref) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.Function[0] = ctx->Stencil.Function[1] = func; - ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; - ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; - if (ctx->Driver.StencilFuncSeparate) { - ctx->Driver.StencilFuncSeparate(ctx, - ((ctx->Stencil.TestTwoSide) - ? GL_FRONT : GL_FRONT_AND_BACK), - func, ref, mask); - } - } -} - - -/** - * Set the stencil writing mask. - * - * \param mask bit-mask to enable/disable writing of individual bits in the - * stencil planes. - * - * \sa glStencilMask(). - * - * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and - * notifies the driver via the dd_function_table::StencilMask callback. - */ -void GLAPIENTRY -_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) { - /* Only modify the EXT_stencil_two_side back-face state. - */ - if (ctx->Stencil.WriteMask[face] == mask) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.WriteMask[face] = mask; - - /* Only propagate the change to the driver if EXT_stencil_two_side - * is enabled. - */ - if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) { - ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask); - } - } - else { - /* set both front and back state */ - if (ctx->Stencil.WriteMask[0] == mask && - ctx->Stencil.WriteMask[1] == mask) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask; - if (ctx->Driver.StencilMaskSeparate) { - ctx->Driver.StencilMaskSeparate(ctx, - ((ctx->Stencil.TestTwoSide) - ? GL_FRONT : GL_FRONT_AND_BACK), - mask); - } - } -} - - -/** - * Set the stencil test actions. - * - * \param fail action to take when stencil test fails. - * \param zfail action to take when stencil test passes, but depth test fails. - * \param zpass action to take when stencil test passes and the depth test - * passes (or depth testing is not enabled). - * - * \sa glStencilOp(). - * - * Verifies the parameters and updates the respective fields in - * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the - * driver via the dd_function_table::StencilOp callback. - */ -void GLAPIENTRY -_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)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)"); - return; - } - if (!validate_stencil_op(ctx, zfail)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)"); - return; - } - if (!validate_stencil_op(ctx, zpass)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)"); - return; - } - - if (face != 0) { - /* only set active face state */ - if (ctx->Stencil.ZFailFunc[face] == zfail && - ctx->Stencil.ZPassFunc[face] == zpass && - ctx->Stencil.FailFunc[face] == fail) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.ZFailFunc[face] = zfail; - ctx->Stencil.ZPassFunc[face] = zpass; - ctx->Stencil.FailFunc[face] = fail; - - /* Only propagate the change to the driver if EXT_stencil_two_side - * is enabled. - */ - if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) { - ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass); - } - } - else { - /* set both front and back state */ - if (ctx->Stencil.ZFailFunc[0] == zfail && - ctx->Stencil.ZFailFunc[1] == zfail && - ctx->Stencil.ZPassFunc[0] == zpass && - ctx->Stencil.ZPassFunc[1] == zpass && - ctx->Stencil.FailFunc[0] == fail && - ctx->Stencil.FailFunc[1] == fail) - return; - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail; - ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass; - ctx->Stencil.FailFunc[0] = ctx->Stencil.FailFunc[1] = fail; - if (ctx->Driver.StencilOpSeparate) { - ctx->Driver.StencilOpSeparate(ctx, - ((ctx->Stencil.TestTwoSide) - ? GL_FRONT : GL_FRONT_AND_BACK), - fail, zfail, zpass); - } - } -} - - - -#if _HAVE_FULL_GL -/* GL_EXT_stencil_two_side */ -void GLAPIENTRY -_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; - } - - if (face == GL_FRONT || face == GL_BACK) { - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)"); - } -} -#endif - - - -/** - * OpenGL 2.0 function. - * \todo Make StencilOp() call this function. And eventually remove the - * ctx->Driver.StencilOp function and use ctx->Driver.StencilOpSeparate - * instead. - */ -void GLAPIENTRY -_mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass) -{ - GLboolean set = GL_FALSE; - 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; - } - if (!validate_stencil_op(ctx, zfail)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)"); - return; - } - if (!validate_stencil_op(ctx, zpass)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)"); - return; - } - if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)"); - return; - } - - if (face != GL_BACK) { - /* set front */ - if (ctx->Stencil.ZFailFunc[0] != zfail || - ctx->Stencil.ZPassFunc[0] != zpass || - ctx->Stencil.FailFunc[0] != sfail){ - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.ZFailFunc[0] = zfail; - ctx->Stencil.ZPassFunc[0] = zpass; - ctx->Stencil.FailFunc[0] = sfail; - set = GL_TRUE; - } - } - if (face != GL_FRONT) { - /* set back */ - if (ctx->Stencil.ZFailFunc[1] != zfail || - ctx->Stencil.ZPassFunc[1] != zpass || - ctx->Stencil.FailFunc[1] != sfail) { - FLUSH_VERTICES(ctx, _NEW_STENCIL); - ctx->Stencil.ZFailFunc[1] = zfail; - ctx->Stencil.ZPassFunc[1] = zpass; - ctx->Stencil.FailFunc[1] = sfail; - set = GL_TRUE; - } - } - if (set && ctx->Driver.StencilOpSeparate) { - ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass); - } -} - - -/* OpenGL 2.0 */ -void GLAPIENTRY -_mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) -{ - GET_CURRENT_CONTEXT(ctx); - 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; - } - if (!validate_stencil_func(ctx, func)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)"); - return; - } - - ref = CLAMP(ref, 0, stencilMax); - - FLUSH_VERTICES(ctx, _NEW_STENCIL); - - if (face != GL_BACK) { - /* set front */ - ctx->Stencil.Function[0] = func; - ctx->Stencil.Ref[0] = ref; - ctx->Stencil.ValueMask[0] = mask; - } - if (face != GL_FRONT) { - /* set back */ - ctx->Stencil.Function[1] = func; - ctx->Stencil.Ref[1] = ref; - ctx->Stencil.ValueMask[1] = mask; - } - if (ctx->Driver.StencilFuncSeparate) { - ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask); - } -} - - -/* OpenGL 2.0 */ -void GLAPIENTRY -_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; - } - - FLUSH_VERTICES(ctx, _NEW_STENCIL); - - if (face != GL_BACK) { - ctx->Stencil.WriteMask[0] = mask; - } - if (face != GL_FRONT) { - ctx->Stencil.WriteMask[1] = mask; - } - if (ctx->Driver.StencilMaskSeparate) { - ctx->Driver.StencilMaskSeparate(ctx, face, mask); - } -} - - -/** - * Update derived stencil state. - */ -void -_mesa_update_stencil(struct gl_context *ctx) -{ - const GLint face = ctx->Stencil._BackFace; - - ctx->Stencil._Enabled = (ctx->Stencil.Enabled && - ctx->DrawBuffer->Visual.stencilBits > 0); - - ctx->Stencil._TestTwoSide = - ctx->Stencil._Enabled && - (ctx->Stencil.Function[0] != ctx->Stencil.Function[face] || - ctx->Stencil.FailFunc[0] != ctx->Stencil.FailFunc[face] || - ctx->Stencil.ZPassFunc[0] != ctx->Stencil.ZPassFunc[face] || - ctx->Stencil.ZFailFunc[0] != ctx->Stencil.ZFailFunc[face] || - ctx->Stencil.Ref[0] != ctx->Stencil.Ref[face] || - ctx->Stencil.ValueMask[0] != ctx->Stencil.ValueMask[face] || - ctx->Stencil.WriteMask[0] != ctx->Stencil.WriteMask[face]); -} - - -/** - * Initialize the context stipple state. - * - * \param ctx GL context. - * - * Initializes __struct gl_contextRec::Stencil attribute group. - */ -void -_mesa_init_stencil(struct gl_context *ctx) -{ - ctx->Stencil.Enabled = GL_FALSE; - ctx->Stencil.TestTwoSide = GL_FALSE; - ctx->Stencil.ActiveFace = 0; /* 0 = GL_FRONT, 2 = GL_BACK */ - ctx->Stencil.Function[0] = GL_ALWAYS; - ctx->Stencil.Function[1] = GL_ALWAYS; - ctx->Stencil.Function[2] = GL_ALWAYS; - ctx->Stencil.FailFunc[0] = GL_KEEP; - ctx->Stencil.FailFunc[1] = GL_KEEP; - ctx->Stencil.FailFunc[2] = GL_KEEP; - ctx->Stencil.ZPassFunc[0] = GL_KEEP; - ctx->Stencil.ZPassFunc[1] = GL_KEEP; - ctx->Stencil.ZPassFunc[2] = GL_KEEP; - ctx->Stencil.ZFailFunc[0] = GL_KEEP; - ctx->Stencil.ZFailFunc[1] = GL_KEEP; - ctx->Stencil.ZFailFunc[2] = GL_KEEP; - ctx->Stencil.Ref[0] = 0; - ctx->Stencil.Ref[1] = 0; - ctx->Stencil.Ref[2] = 0; - ctx->Stencil.ValueMask[0] = ~0U; - ctx->Stencil.ValueMask[1] = ~0U; - ctx->Stencil.ValueMask[2] = ~0U; - ctx->Stencil.WriteMask[0] = ~0U; - ctx->Stencil.WriteMask[1] = ~0U; - ctx->Stencil.WriteMask[2] = ~0U; - ctx->Stencil.Clear = 0; - ctx->Stencil._BackFace = 1; -} +/*
+ * Mesa 3-D graphics library
+ * Version: 7.1
+ *
+ * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/**
+ * \file stencil.c
+ * Stencil operations.
+ *
+ * Note: There's some conflict between GL_EXT_stencil_two_side and
+ * OpenGL 2.0's two-sided stencil feature.
+ *
+ * With GL_EXT_stencil_two_side, calling glStencilOp/Func/Mask() only the
+ * front OR back face state (as set by glActiveStencilFaceEXT) is set.
+ *
+ * But with OpenGL 2.0, calling glStencilOp/Func/Mask() sets BOTH the
+ * front AND back state.
+ *
+ * Also, note that GL_ATI_separate_stencil is different as well:
+ * glStencilFuncSeparateATI(GLenum frontfunc, GLenum backfunc, ...) vs.
+ * glStencilFuncSeparate(GLenum face, GLenum func, ...).
+ *
+ * This problem is solved by keeping three sets of stencil state:
+ * state[0] = GL_FRONT state.
+ * state[1] = OpenGL 2.0 / GL_ATI_separate_stencil GL_BACK state.
+ * state[2] = GL_EXT_stencil_two_side GL_BACK state.
+ */
+
+
+#include "glheader.h"
+#include "imports.h"
+#include "context.h"
+#include "macros.h"
+#include "stencil.h"
+#include "mtypes.h"
+
+
+static GLboolean
+validate_stencil_op(struct gl_context *ctx, GLenum op)
+{
+ switch (op) {
+ case GL_KEEP:
+ case GL_ZERO:
+ case GL_REPLACE:
+ case GL_INCR:
+ case GL_DECR:
+ case GL_INVERT:
+ return GL_TRUE;
+ case GL_INCR_WRAP_EXT:
+ case GL_DECR_WRAP_EXT:
+ if (ctx->Extensions.EXT_stencil_wrap) {
+ return GL_TRUE;
+ }
+ /* FALL-THROUGH */
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+static GLboolean
+validate_stencil_func(struct gl_context *ctx, GLenum func)
+{
+ switch (func) {
+ case GL_NEVER:
+ case GL_LESS:
+ case GL_LEQUAL:
+ case GL_GREATER:
+ case GL_GEQUAL:
+ case GL_EQUAL:
+ case GL_NOTEQUAL:
+ case GL_ALWAYS:
+ return GL_TRUE;
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Set the clear value for the stencil buffer.
+ *
+ * \param s clear value.
+ *
+ * \sa glClearStencil().
+ *
+ * Updates gl_stencil_attrib::Clear. On change
+ * flushes the vertices and notifies the driver via
+ * the dd_function_table::ClearStencil callback.
+ */
+void GLAPIENTRY
+_mesa_ClearStencil( GLint s )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (ctx->Stencil.Clear == (GLuint) s)
+ return;
+
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+ ctx->Stencil.Clear = (GLuint) s;
+
+ if (ctx->Driver.ClearStencil) {
+ ctx->Driver.ClearStencil( ctx, s );
+ }
+}
+
+
+/**
+ * Set the function and reference value for stencil testing.
+ *
+ * \param frontfunc front test function.
+ * \param backfunc back test function.
+ * \param ref front and back reference value.
+ * \param mask front and back bitmask.
+ *
+ * \sa glStencilFunc().
+ *
+ * Verifies the parameters and updates the respective values in
+ * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the
+ * driver via the dd_function_table::StencilFunc callback.
+ */
+void GLAPIENTRY
+_mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ 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)");
+ return;
+ }
+ if (!validate_stencil_func(ctx, backfunc)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glStencilFuncSeparateATI(backfunc)");
+ return;
+ }
+
+ ref = CLAMP( ref, 0, stencilMax );
+
+ /* set both front and back state */
+ if (ctx->Stencil.Function[0] == frontfunc &&
+ ctx->Stencil.Function[1] == backfunc &&
+ ctx->Stencil.ValueMask[0] == mask &&
+ ctx->Stencil.ValueMask[1] == mask &&
+ ctx->Stencil.Ref[0] == ref &&
+ ctx->Stencil.Ref[1] == ref)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+ ctx->Stencil.Function[0] = frontfunc;
+ ctx->Stencil.Function[1] = backfunc;
+ ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref;
+ ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
+ if (ctx->Driver.StencilFuncSeparate) {
+ ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT,
+ frontfunc, ref, mask);
+ ctx->Driver.StencilFuncSeparate(ctx, GL_BACK,
+ backfunc, ref, mask);
+ }
+}
+
+
+/**
+ * Set the function and reference value for stencil testing.
+ *
+ * \param func test function.
+ * \param ref reference value.
+ * \param mask bitmask.
+ *
+ * \sa glStencilFunc().
+ *
+ * Verifies the parameters and updates the respective values in
+ * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the
+ * driver via the dd_function_table::StencilFunc callback.
+ */
+void GLAPIENTRY
+_mesa_StencilFunc( GLenum func, GLint ref, GLuint mask )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
+ 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;
+ }
+
+ ref = CLAMP( ref, 0, stencilMax );
+
+ if (face != 0) {
+ if (ctx->Stencil.Function[face] == func &&
+ ctx->Stencil.ValueMask[face] == mask &&
+ ctx->Stencil.Ref[face] == ref)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+ ctx->Stencil.Function[face] = func;
+ ctx->Stencil.Ref[face] = ref;
+ ctx->Stencil.ValueMask[face] = mask;
+
+ /* Only propagate the change to the driver if EXT_stencil_two_side
+ * is enabled.
+ */
+ if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) {
+ ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask);
+ }
+ }
+ else {
+ /* set both front and back state */
+ if (ctx->Stencil.Function[0] == func &&
+ ctx->Stencil.Function[1] == func &&
+ ctx->Stencil.ValueMask[0] == mask &&
+ ctx->Stencil.ValueMask[1] == mask &&
+ ctx->Stencil.Ref[0] == ref &&
+ ctx->Stencil.Ref[1] == ref)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+ ctx->Stencil.Function[0] = ctx->Stencil.Function[1] = func;
+ ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref;
+ ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
+ if (ctx->Driver.StencilFuncSeparate) {
+ ctx->Driver.StencilFuncSeparate(ctx,
+ ((ctx->Stencil.TestTwoSide)
+ ? GL_FRONT : GL_FRONT_AND_BACK),
+ func, ref, mask);
+ }
+ }
+}
+
+
+/**
+ * Set the stencil writing mask.
+ *
+ * \param mask bit-mask to enable/disable writing of individual bits in the
+ * stencil planes.
+ *
+ * \sa glStencilMask().
+ *
+ * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and
+ * notifies the driver via the dd_function_table::StencilMask callback.
+ */
+void GLAPIENTRY
+_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) {
+ /* Only modify the EXT_stencil_two_side back-face state.
+ */
+ if (ctx->Stencil.WriteMask[face] == mask)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+ ctx->Stencil.WriteMask[face] = mask;
+
+ /* Only propagate the change to the driver if EXT_stencil_two_side
+ * is enabled.
+ */
+ if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) {
+ ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask);
+ }
+ }
+ else {
+ /* set both front and back state */
+ if (ctx->Stencil.WriteMask[0] == mask &&
+ ctx->Stencil.WriteMask[1] == mask)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+ ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask;
+ if (ctx->Driver.StencilMaskSeparate) {
+ ctx->Driver.StencilMaskSeparate(ctx,
+ ((ctx->Stencil.TestTwoSide)
+ ? GL_FRONT : GL_FRONT_AND_BACK),
+ mask);
+ }
+ }
+}
+
+
+/**
+ * Set the stencil test actions.
+ *
+ * \param fail action to take when stencil test fails.
+ * \param zfail action to take when stencil test passes, but depth test fails.
+ * \param zpass action to take when stencil test passes and the depth test
+ * passes (or depth testing is not enabled).
+ *
+ * \sa glStencilOp().
+ *
+ * Verifies the parameters and updates the respective fields in
+ * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the
+ * driver via the dd_function_table::StencilOp callback.
+ */
+void GLAPIENTRY
+_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)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)");
+ return;
+ }
+ if (!validate_stencil_op(ctx, zfail)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)");
+ return;
+ }
+ if (!validate_stencil_op(ctx, zpass)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)");
+ return;
+ }
+
+ if (face != 0) {
+ /* only set active face state */
+ if (ctx->Stencil.ZFailFunc[face] == zfail &&
+ ctx->Stencil.ZPassFunc[face] == zpass &&
+ ctx->Stencil.FailFunc[face] == fail)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+ ctx->Stencil.ZFailFunc[face] = zfail;
+ ctx->Stencil.ZPassFunc[face] = zpass;
+ ctx->Stencil.FailFunc[face] = fail;
+
+ /* Only propagate the change to the driver if EXT_stencil_two_side
+ * is enabled.
+ */
+ if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) {
+ ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass);
+ }
+ }
+ else {
+ /* set both front and back state */
+ if (ctx->Stencil.ZFailFunc[0] == zfail &&
+ ctx->Stencil.ZFailFunc[1] == zfail &&
+ ctx->Stencil.ZPassFunc[0] == zpass &&
+ ctx->Stencil.ZPassFunc[1] == zpass &&
+ ctx->Stencil.FailFunc[0] == fail &&
+ ctx->Stencil.FailFunc[1] == fail)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+ ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail;
+ ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass;
+ ctx->Stencil.FailFunc[0] = ctx->Stencil.FailFunc[1] = fail;
+ if (ctx->Driver.StencilOpSeparate) {
+ ctx->Driver.StencilOpSeparate(ctx,
+ ((ctx->Stencil.TestTwoSide)
+ ? GL_FRONT : GL_FRONT_AND_BACK),
+ fail, zfail, zpass);
+ }
+ }
+}
+
+
+
+#if _HAVE_FULL_GL
+/* GL_EXT_stencil_two_side */
+void GLAPIENTRY
+_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;
+ }
+
+ if (face == GL_FRONT || face == GL_BACK) {
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+ ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2;
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)");
+ }
+}
+#endif
+
+
+
+/**
+ * OpenGL 2.0 function.
+ * \todo Make StencilOp() call this function. And eventually remove the
+ * ctx->Driver.StencilOp function and use ctx->Driver.StencilOpSeparate
+ * instead.
+ */
+void GLAPIENTRY
+_mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass)
+{
+ GLboolean set = GL_FALSE;
+ 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;
+ }
+ if (!validate_stencil_op(ctx, zfail)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)");
+ return;
+ }
+ if (!validate_stencil_op(ctx, zpass)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)");
+ return;
+ }
+ if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)");
+ return;
+ }
+
+ if (face != GL_BACK) {
+ /* set front */
+ if (ctx->Stencil.ZFailFunc[0] != zfail ||
+ ctx->Stencil.ZPassFunc[0] != zpass ||
+ ctx->Stencil.FailFunc[0] != sfail){
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+ ctx->Stencil.ZFailFunc[0] = zfail;
+ ctx->Stencil.ZPassFunc[0] = zpass;
+ ctx->Stencil.FailFunc[0] = sfail;
+ set = GL_TRUE;
+ }
+ }
+ if (face != GL_FRONT) {
+ /* set back */
+ if (ctx->Stencil.ZFailFunc[1] != zfail ||
+ ctx->Stencil.ZPassFunc[1] != zpass ||
+ ctx->Stencil.FailFunc[1] != sfail) {
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+ ctx->Stencil.ZFailFunc[1] = zfail;
+ ctx->Stencil.ZPassFunc[1] = zpass;
+ ctx->Stencil.FailFunc[1] = sfail;
+ set = GL_TRUE;
+ }
+ }
+ if (set && ctx->Driver.StencilOpSeparate) {
+ ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass);
+ }
+}
+
+
+/* OpenGL 2.0 */
+void GLAPIENTRY
+_mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ 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;
+ }
+ if (!validate_stencil_func(ctx, func)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)");
+ return;
+ }
+
+ ref = CLAMP(ref, 0, stencilMax);
+
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+
+ if (face != GL_BACK) {
+ /* set front */
+ ctx->Stencil.Function[0] = func;
+ ctx->Stencil.Ref[0] = ref;
+ ctx->Stencil.ValueMask[0] = mask;
+ }
+ if (face != GL_FRONT) {
+ /* set back */
+ ctx->Stencil.Function[1] = func;
+ ctx->Stencil.Ref[1] = ref;
+ ctx->Stencil.ValueMask[1] = mask;
+ }
+ if (ctx->Driver.StencilFuncSeparate) {
+ ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask);
+ }
+}
+
+
+/* OpenGL 2.0 */
+void GLAPIENTRY
+_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;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_STENCIL);
+
+ if (face != GL_BACK) {
+ ctx->Stencil.WriteMask[0] = mask;
+ }
+ if (face != GL_FRONT) {
+ ctx->Stencil.WriteMask[1] = mask;
+ }
+ if (ctx->Driver.StencilMaskSeparate) {
+ ctx->Driver.StencilMaskSeparate(ctx, face, mask);
+ }
+}
+
+
+/**
+ * Update derived stencil state.
+ */
+void
+_mesa_update_stencil(struct gl_context *ctx)
+{
+ const GLint face = ctx->Stencil._BackFace;
+
+ ctx->Stencil._Enabled = (ctx->Stencil.Enabled &&
+ ctx->DrawBuffer->Visual.stencilBits > 0);
+
+ ctx->Stencil._TestTwoSide =
+ ctx->Stencil._Enabled &&
+ (ctx->Stencil.Function[0] != ctx->Stencil.Function[face] ||
+ ctx->Stencil.FailFunc[0] != ctx->Stencil.FailFunc[face] ||
+ ctx->Stencil.ZPassFunc[0] != ctx->Stencil.ZPassFunc[face] ||
+ ctx->Stencil.ZFailFunc[0] != ctx->Stencil.ZFailFunc[face] ||
+ ctx->Stencil.Ref[0] != ctx->Stencil.Ref[face] ||
+ ctx->Stencil.ValueMask[0] != ctx->Stencil.ValueMask[face] ||
+ ctx->Stencil.WriteMask[0] != ctx->Stencil.WriteMask[face]);
+}
+
+
+/**
+ * Initialize the context stipple state.
+ *
+ * \param ctx GL context.
+ *
+ * Initializes __struct gl_contextRec::Stencil attribute group.
+ */
+void
+_mesa_init_stencil(struct gl_context *ctx)
+{
+ ctx->Stencil.Enabled = GL_FALSE;
+ ctx->Stencil.TestTwoSide = GL_FALSE;
+ ctx->Stencil.ActiveFace = 0; /* 0 = GL_FRONT, 2 = GL_BACK */
+ ctx->Stencil.Function[0] = GL_ALWAYS;
+ ctx->Stencil.Function[1] = GL_ALWAYS;
+ ctx->Stencil.Function[2] = GL_ALWAYS;
+ ctx->Stencil.FailFunc[0] = GL_KEEP;
+ ctx->Stencil.FailFunc[1] = GL_KEEP;
+ ctx->Stencil.FailFunc[2] = GL_KEEP;
+ ctx->Stencil.ZPassFunc[0] = GL_KEEP;
+ ctx->Stencil.ZPassFunc[1] = GL_KEEP;
+ ctx->Stencil.ZPassFunc[2] = GL_KEEP;
+ ctx->Stencil.ZFailFunc[0] = GL_KEEP;
+ ctx->Stencil.ZFailFunc[1] = GL_KEEP;
+ ctx->Stencil.ZFailFunc[2] = GL_KEEP;
+ ctx->Stencil.Ref[0] = 0;
+ ctx->Stencil.Ref[1] = 0;
+ ctx->Stencil.Ref[2] = 0;
+ ctx->Stencil.ValueMask[0] = ~0U;
+ ctx->Stencil.ValueMask[1] = ~0U;
+ ctx->Stencil.ValueMask[2] = ~0U;
+ ctx->Stencil.WriteMask[0] = ~0U;
+ ctx->Stencil.WriteMask[1] = ~0U;
+ ctx->Stencil.WriteMask[2] = ~0U;
+ ctx->Stencil.Clear = 0;
+ ctx->Stencil._BackFace = 1;
+}
diff --git a/mesalib/src/mesa/main/syncobj.c b/mesalib/src/mesa/main/syncobj.c index 676038430..25307a17c 100644 --- a/mesalib/src/mesa/main/syncobj.c +++ b/mesalib/src/mesa/main/syncobj.c @@ -125,7 +125,7 @@ _mesa_wait_sync(struct gl_context *ctx, struct gl_sync_object *syncObj, }
-void
+void GLAPIENTRY
_mesa_init_sync_object_functions(struct dd_function_table *driver)
{
driver->NewSyncObject = _mesa_new_sync_object;
@@ -140,7 +140,7 @@ _mesa_init_sync_object_functions(struct dd_function_table *driver) }
-void
+void GLAPIENTRY
_mesa_init_sync_dispatch(struct _glapi_table *disp)
{
SET_IsSync(disp, _mesa_IsSync);
@@ -156,7 +156,7 @@ _mesa_init_sync_dispatch(struct _glapi_table *disp) /**
* Allocate/init the context state related to sync objects.
*/
-void
+void GLAPIENTRY
_mesa_init_sync(struct gl_context *ctx)
{
(void) ctx;
@@ -166,7 +166,7 @@ _mesa_init_sync(struct gl_context *ctx) /**
* Free the context state related to sync objects.
*/
-void
+void GLAPIENTRY
_mesa_free_sync_data(struct gl_context *ctx)
{
(void) ctx;
@@ -182,7 +182,7 @@ _mesa_validate_sync(struct gl_sync_object *syncObj) }
-void
+void GLAPIENTRY
_mesa_ref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj)
{
_glthread_LOCK_MUTEX(ctx->Shared->Mutex);
@@ -191,7 +191,7 @@ _mesa_ref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj) }
-void
+void GLAPIENTRY
_mesa_unref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj)
{
_glthread_LOCK_MUTEX(ctx->Shared->Mutex);
diff --git a/mesalib/src/mesa/main/syncobj.h b/mesalib/src/mesa/main/syncobj.h index ac1384f61..e83ac8b0e 100644 --- a/mesalib/src/mesa/main/syncobj.h +++ b/mesalib/src/mesa/main/syncobj.h @@ -41,22 +41,22 @@ struct gl_sync_object; #if FEATURE_ARB_sync
-extern void
+extern void GLAPIENTRY
_mesa_init_sync_object_functions(struct dd_function_table *driver);
-extern void
+extern void GLAPIENTRY
_mesa_init_sync_dispatch(struct _glapi_table *disp);
-extern void
+extern void GLAPIENTRY
_mesa_init_sync(struct gl_context *);
-extern void
+extern void GLAPIENTRY
_mesa_free_sync_data(struct gl_context *);
-extern void
+extern void GLAPIENTRY
_mesa_ref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj);
-extern void
+extern void GLAPIENTRY
_mesa_unref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj);
extern GLboolean GLAPIENTRY
diff --git a/mesalib/src/mesa/main/texcompress_s3tc.c b/mesalib/src/mesa/main/texcompress_s3tc.c index 90be6c0a8..479806eca 100644 --- a/mesalib/src/mesa/main/texcompress_s3tc.c +++ b/mesalib/src/mesa/main/texcompress_s3tc.c @@ -50,7 +50,11 @@ #if defined(_WIN32) || defined(WIN32)
+#ifdef _DEBUG
+#define DXTN_LIBNAME "dxtn_dbg.dll"
+#else
#define DXTN_LIBNAME "dxtn.dll"
+#endif
#define RTLD_LAZY 0
#define RTLD_GLOBAL 0
#elif defined(__DJGPP__)
diff --git a/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c b/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c index 76386fe01..678a270c7 100644 --- a/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c +++ b/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c @@ -1,182 +1,182 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - - /* - * Authors: - * Keith Whitwell <keith@tungstengraphics.com> - * Brian Paul - */ - -#include "st_context.h" -#include "st_atom.h" -#include "st_cb_fbo.h" -#include "st_texture.h" -#include "pipe/p_context.h" -#include "cso_cache/cso_context.h" -#include "util/u_math.h" -#include "util/u_inlines.h" -#include "util/u_format.h" - - -/** - * When doing GL render to texture, we have to be sure that finalize_texture() - * didn't yank out the pipe_resource that we earlier created a surface for. - * Check for that here and create a new surface if needed. - */ -static void -update_renderbuffer_surface(struct st_context *st, - struct st_renderbuffer *strb) -{ - struct pipe_context *pipe = st->pipe; - struct pipe_resource *resource = strb->rtt->pt; - int rtt_width = strb->Base.Width; - int rtt_height = strb->Base.Height; - enum pipe_format format = st->ctx->Color.sRGBEnabled ? resource->format : util_format_linear(resource->format); - - if (!strb->surface || - strb->surface->format != format || - strb->surface->texture != resource || - strb->surface->width != rtt_width || - strb->surface->height != rtt_height) { - GLuint level; - /* find matching mipmap level size */ - for (level = 0; level <= resource->last_level; level++) { - if (u_minify(resource->width0, level) == rtt_width && - u_minify(resource->height0, level) == rtt_height) { - struct pipe_surface surf_tmpl; - memset(&surf_tmpl, 0, sizeof(surf_tmpl)); - surf_tmpl.format = format; - surf_tmpl.usage = PIPE_BIND_RENDER_TARGET; - surf_tmpl.u.tex.level = level; - surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice; - surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice; - - pipe_surface_reference(&strb->surface, NULL); - - strb->surface = pipe->create_surface(pipe, - resource, - &surf_tmpl); -#if 0 - printf("-- alloc new surface %d x %d into tex %p\n", - strb->surface->width, strb->surface->height, - texture); -#endif - break; - } - } - } -} - - -/** - * Update framebuffer state (color, depth, stencil, etc. buffers) - */ -static void -update_framebuffer_state( struct st_context *st ) -{ - struct pipe_framebuffer_state *framebuffer = &st->state.framebuffer; - struct gl_framebuffer *fb = st->ctx->DrawBuffer; - struct st_renderbuffer *strb; - GLuint i; - - framebuffer->width = fb->Width; - framebuffer->height = fb->Height; - - /*printf("------ fb size %d x %d\n", fb->Width, fb->Height);*/ - - /* Examine Mesa's ctx->DrawBuffer->_ColorDrawBuffers state - * to determine which surfaces to draw to - */ - framebuffer->nr_cbufs = 0; - for (i = 0; i < fb->_NumColorDrawBuffers; i++) { - strb = st_renderbuffer(fb->_ColorDrawBuffers[i]); - - if (strb) { - /*printf("--------- framebuffer surface rtt %p\n", strb->rtt);*/ - if (strb->rtt) { - /* rendering to a GL texture, may have to update surface */ - update_renderbuffer_surface(st, strb); - } - - if (strb->surface) { - pipe_surface_reference(&framebuffer->cbufs[framebuffer->nr_cbufs], - strb->surface); - framebuffer->nr_cbufs++; - } - strb->defined = GL_TRUE; /* we'll be drawing something */ - } - } - for (i = framebuffer->nr_cbufs; i < PIPE_MAX_COLOR_BUFS; i++) { - pipe_surface_reference(&framebuffer->cbufs[i], NULL); - } - - /* - * Depth/Stencil renderbuffer/surface. - */ - strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer); - if (strb) { - strb = st_renderbuffer(strb->Base.Wrapped); - if (strb->rtt) { - /* rendering to a GL texture, may have to update surface */ - update_renderbuffer_surface(st, strb); - } - pipe_surface_reference(&framebuffer->zsbuf, strb->surface); - } - else { - strb = st_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer); - if (strb) { - strb = st_renderbuffer(strb->Base.Wrapped); - assert(strb->surface); - pipe_surface_reference(&framebuffer->zsbuf, strb->surface); - } - else - pipe_surface_reference(&framebuffer->zsbuf, NULL); - } - -#ifdef DEBUG - /* Make sure the resource binding flags were set properly */ - for (i = 0; i < framebuffer->nr_cbufs; i++) { - assert(framebuffer->cbufs[i]->texture->bind & PIPE_BIND_RENDER_TARGET); - } - if (framebuffer->zsbuf) { - assert(framebuffer->zsbuf->texture->bind & PIPE_BIND_DEPTH_STENCIL); - } -#endif - - cso_set_framebuffer(st->cso_context, framebuffer); -} - - -const struct st_tracked_state st_update_framebuffer = { - "st_update_framebuffer", /* name */ - { /* dirty */ - _NEW_BUFFERS, /* mesa */ - ST_NEW_FRAMEBUFFER, /* st */ - }, - update_framebuffer_state /* update */ -}; - +/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+ /*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ * Brian Paul
+ */
+
+#include "st_context.h"
+#include "st_atom.h"
+#include "st_cb_fbo.h"
+#include "st_texture.h"
+#include "pipe/p_context.h"
+#include "cso_cache/cso_context.h"
+#include "util/u_math.h"
+#include "util/u_inlines.h"
+#include "util/u_format.h"
+
+
+/**
+ * When doing GL render to texture, we have to be sure that finalize_texture()
+ * didn't yank out the pipe_resource that we earlier created a surface for.
+ * Check for that here and create a new surface if needed.
+ */
+static void
+update_renderbuffer_surface(struct st_context *st,
+ struct st_renderbuffer *strb)
+{
+ struct pipe_context *pipe = st->pipe;
+ struct pipe_resource *resource = strb->rtt->pt;
+ int rtt_width = strb->Base.Width;
+ int rtt_height = strb->Base.Height;
+ enum pipe_format format = st->ctx->Color.sRGBEnabled ? resource->format : util_format_linear(resource->format);
+
+ if (!strb->surface ||
+ strb->surface->format != format ||
+ strb->surface->texture != resource ||
+ strb->surface->width != rtt_width ||
+ strb->surface->height != rtt_height) {
+ GLuint level;
+ /* find matching mipmap level size */
+ for (level = 0; level <= resource->last_level; level++) {
+ if (u_minify(resource->width0, level) == rtt_width &&
+ u_minify(resource->height0, level) == rtt_height) {
+ struct pipe_surface surf_tmpl;
+ memset(&surf_tmpl, 0, sizeof(surf_tmpl));
+ surf_tmpl.format = format;
+ surf_tmpl.usage = PIPE_BIND_RENDER_TARGET;
+ surf_tmpl.u.tex.level = level;
+ surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice;
+ surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice;
+
+ pipe_surface_reference(&strb->surface, NULL);
+
+ strb->surface = pipe->create_surface(pipe,
+ resource,
+ &surf_tmpl);
+#if 0
+ printf("-- alloc new surface %d x %d into tex %p\n",
+ strb->surface->width, strb->surface->height,
+ texture);
+#endif
+ break;
+ }
+ }
+ }
+}
+
+
+/**
+ * Update framebuffer state (color, depth, stencil, etc. buffers)
+ */
+static void
+update_framebuffer_state( struct st_context *st )
+{
+ struct pipe_framebuffer_state *framebuffer = &st->state.framebuffer;
+ struct gl_framebuffer *fb = st->ctx->DrawBuffer;
+ struct st_renderbuffer *strb;
+ GLuint i;
+
+ framebuffer->width = fb->Width;
+ framebuffer->height = fb->Height;
+
+ /*printf("------ fb size %d x %d\n", fb->Width, fb->Height);*/
+
+ /* Examine Mesa's ctx->DrawBuffer->_ColorDrawBuffers state
+ * to determine which surfaces to draw to
+ */
+ framebuffer->nr_cbufs = 0;
+ for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
+ strb = st_renderbuffer(fb->_ColorDrawBuffers[i]);
+
+ if (strb) {
+ /*printf("--------- framebuffer surface rtt %p\n", strb->rtt);*/
+ if (strb->rtt) {
+ /* rendering to a GL texture, may have to update surface */
+ update_renderbuffer_surface(st, strb);
+ }
+
+ if (strb->surface) {
+ pipe_surface_reference(&framebuffer->cbufs[framebuffer->nr_cbufs],
+ strb->surface);
+ framebuffer->nr_cbufs++;
+ }
+ strb->defined = GL_TRUE; /* we'll be drawing something */
+ }
+ }
+ for (i = framebuffer->nr_cbufs; i < PIPE_MAX_COLOR_BUFS; i++) {
+ pipe_surface_reference(&framebuffer->cbufs[i], NULL);
+ }
+
+ /*
+ * Depth/Stencil renderbuffer/surface.
+ */
+ strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer);
+ if (strb) {
+ strb = st_renderbuffer(strb->Base.Wrapped);
+ if (strb->rtt) {
+ /* rendering to a GL texture, may have to update surface */
+ update_renderbuffer_surface(st, strb);
+ }
+ pipe_surface_reference(&framebuffer->zsbuf, strb->surface);
+ }
+ else {
+ strb = st_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer);
+ if (strb) {
+ strb = st_renderbuffer(strb->Base.Wrapped);
+ assert(strb->surface);
+ pipe_surface_reference(&framebuffer->zsbuf, strb->surface);
+ }
+ else
+ pipe_surface_reference(&framebuffer->zsbuf, NULL);
+ }
+
+#ifdef DEBUG
+ /* Make sure the resource binding flags were set properly */
+ for (i = 0; i < framebuffer->nr_cbufs; i++) {
+ assert(framebuffer->cbufs[i]->texture->bind & PIPE_BIND_RENDER_TARGET);
+ }
+ if (framebuffer->zsbuf) {
+ assert(framebuffer->zsbuf->texture->bind & PIPE_BIND_DEPTH_STENCIL);
+ }
+#endif
+
+ cso_set_framebuffer(st->cso_context, framebuffer);
+}
+
+
+const struct st_tracked_state st_update_framebuffer = {
+ "st_update_framebuffer", /* name */
+ { /* dirty */
+ _NEW_BUFFERS, /* mesa */
+ ST_NEW_FRAMEBUFFER, /* st */
+ },
+ update_framebuffer_state /* update */
+};
+
diff --git a/mesalib/src/mesa/state_tracker/st_context.c b/mesalib/src/mesa/state_tracker/st_context.c index dccbff3c1..b16d965f8 100644 --- a/mesalib/src/mesa/state_tracker/st_context.c +++ b/mesalib/src/mesa/state_tracker/st_context.c @@ -1,292 +1,292 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include "main/imports.h" -#include "main/context.h" -#include "main/shaderobj.h" -#include "program/prog_cache.h" -#include "vbo/vbo.h" -#include "glapi/glapi.h" -#include "st_context.h" -#include "st_debug.h" -#include "st_cb_accum.h" -#include "st_cb_bitmap.h" -#include "st_cb_blit.h" -#include "st_cb_bufferobjects.h" -#include "st_cb_clear.h" -#include "st_cb_condrender.h" -#include "st_cb_drawpixels.h" -#include "st_cb_rasterpos.h" -#include "st_cb_drawtex.h" -#include "st_cb_eglimage.h" -#include "st_cb_fbo.h" -#include "st_cb_feedback.h" -#include "st_cb_program.h" -#include "st_cb_queryobj.h" -#include "st_cb_readpixels.h" -#include "st_cb_texture.h" -#include "st_cb_xformfb.h" -#include "st_cb_flush.h" -#include "st_cb_strings.h" -#include "st_cb_viewport.h" -#include "st_atom.h" -#include "st_draw.h" -#include "st_extensions.h" -#include "st_gen_mipmap.h" -#include "st_program.h" -#include "pipe/p_context.h" -#include "util/u_inlines.h" -#include "cso_cache/cso_context.h" - - -DEBUG_GET_ONCE_BOOL_OPTION(mesa_mvp_dp4, "MESA_MVP_DP4", FALSE) - - -/** - * Called via ctx->Driver.UpdateState() - */ -void st_invalidate_state(struct gl_context * ctx, GLuint new_state) -{ - struct st_context *st = st_context(ctx); - - st->dirty.mesa |= new_state; - st->dirty.st |= ST_NEW_MESA; - - /* This is the only core Mesa module we depend upon. - * No longer use swrast, swsetup, tnl. - */ - _vbo_InvalidateState(ctx, new_state); -} - - -/** - * Check for multisample env var override. - */ -int -st_get_msaa(void) -{ - const char *msaa = _mesa_getenv("__GL_FSAA_MODE"); - if (msaa) - return atoi(msaa); - return 0; -} - - -static struct st_context * -st_create_context_priv( struct gl_context *ctx, struct pipe_context *pipe ) -{ - uint i; - struct st_context *st = ST_CALLOC_STRUCT( st_context ); - - ctx->st = st; - - st->ctx = ctx; - st->pipe = pipe; - - /* XXX: this is one-off, per-screen init: */ - st_debug_init(); - - /* state tracker needs the VBO module */ - _vbo_CreateContext(ctx); - - st->dirty.mesa = ~0; - st->dirty.st = ~0; - - st->cso_context = cso_create_context(pipe); - - st_init_atoms( st ); - st_init_bitmap(st); - st_init_clear(st); - st_init_draw( st ); - st_init_generate_mipmap(st); - st_init_blit(st); - - if(pipe->screen->get_param(pipe->screen, PIPE_CAP_NPOT_TEXTURES)) - st->internal_target = PIPE_TEXTURE_2D; - else - st->internal_target = PIPE_TEXTURE_RECT; - - for (i = 0; i < PIPE_MAX_SAMPLERS; i++) - st->state.sampler_list[i] = &st->state.samplers[i]; - - for (i = 0; i < 3; i++) { - memset(&st->velems_util_draw[i], 0, sizeof(struct pipe_vertex_element)); - st->velems_util_draw[i].src_offset = i * 4 * sizeof(float); - st->velems_util_draw[i].instance_divisor = 0; - st->velems_util_draw[i].vertex_buffer_index = 0; - st->velems_util_draw[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; - } - - /* we want all vertex data to be placed in buffer objects */ - vbo_use_buffer_objects(ctx); - - /* Need these flags: - */ - st->ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE; - - st->ctx->VertexProgram._MaintainTnlProgram = GL_TRUE; - - st->pixel_xfer.cache = _mesa_new_program_cache(); - - st->force_msaa = st_get_msaa(); - - /* GL limits and extensions */ - st_init_limits(st); - st_init_extensions(st); - - return st; -} - - -struct st_context *st_create_context(gl_api api, struct pipe_context *pipe, - const struct gl_config *visual, - struct st_context *share) -{ - struct gl_context *ctx; - struct gl_context *shareCtx = share ? share->ctx : NULL; - struct dd_function_table funcs; - - /* Sanity checks */ - assert(MESA_SHADER_VERTEX == PIPE_SHADER_VERTEX); - assert(MESA_SHADER_FRAGMENT == PIPE_SHADER_FRAGMENT); - assert(MESA_SHADER_GEOMETRY == PIPE_SHADER_GEOMETRY); - - memset(&funcs, 0, sizeof(funcs)); - st_init_driver_functions(&funcs); - - 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. - */ - if (debug_get_option_mesa_mvp_dp4()) - _mesa_set_mvp_with_dp4( ctx, GL_TRUE ); - - return st_create_context_priv(ctx, pipe); -} - - -static void st_destroy_context_priv( struct st_context *st ) -{ - uint i; - - st_destroy_atoms( st ); - st_destroy_draw( st ); - st_destroy_generate_mipmap(st); - st_destroy_blit(st); - st_destroy_clear(st); - st_destroy_bitmap(st); - st_destroy_drawpix(st); - st_destroy_drawtex(st); - - for (i = 0; i < Elements(st->state.sampler_views); i++) { - pipe_sampler_view_reference(&st->state.sampler_views[i], NULL); - } - - if (st->default_texture) { - st->ctx->Driver.DeleteTexture(st->ctx, st->default_texture); - st->default_texture = NULL; - } - - free( st ); -} - - -void st_destroy_context( struct st_context *st ) -{ - struct pipe_context *pipe = st->pipe; - struct cso_context *cso = st->cso_context; - struct gl_context *ctx = st->ctx; - GLuint i; - - /* need to unbind and destroy CSO objects before anything else */ - cso_release_all(st->cso_context); - - st_reference_fragprog(st, &st->fp, NULL); - st_reference_vertprog(st, &st->vp, NULL); - - /* release framebuffer surfaces */ - for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { - pipe_surface_reference(&st->state.framebuffer.cbufs[i], NULL); - } - pipe_surface_reference(&st->state.framebuffer.zsbuf, NULL); - - pipe->set_index_buffer(pipe, NULL); - - for (i = 0; i < PIPE_SHADER_TYPES; i++) { - pipe->set_constant_buffer(pipe, i, 0, NULL); - } - - _mesa_delete_program_cache(st->ctx, st->pixel_xfer.cache); - - _vbo_DestroyContext(st->ctx); - - st_destroy_program_variants(st); - - _mesa_free_context_data(ctx); - - st_destroy_context_priv(st); - - cso_destroy_context(cso); - - pipe->destroy( pipe ); - - free(ctx); -} - - -void st_init_driver_functions(struct dd_function_table *functions) -{ - _mesa_init_shader_object_functions(functions); - - st_init_accum_functions(functions); - st_init_blit_functions(functions); - st_init_bufferobject_functions(functions); - st_init_clear_functions(functions); - st_init_bitmap_functions(functions); - st_init_drawpixels_functions(functions); - st_init_rasterpos_functions(functions); - - st_init_drawtex_functions(functions); - - st_init_eglimage_functions(functions); - - st_init_fbo_functions(functions); - st_init_feedback_functions(functions); - st_init_program_functions(functions); - st_init_query_functions(functions); - st_init_cond_render_functions(functions); - st_init_readpixels_functions(functions); - st_init_texture_functions(functions); - st_init_flush_functions(functions); - st_init_string_functions(functions); - st_init_viewport_functions(functions); - - st_init_xformfb_functions(functions); - - functions->UpdateState = st_invalidate_state; -} +/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "main/imports.h"
+#include "main/context.h"
+#include "main/shaderobj.h"
+#include "program/prog_cache.h"
+#include "vbo/vbo.h"
+#include "glapi/glapi.h"
+#include "st_context.h"
+#include "st_debug.h"
+#include "st_cb_accum.h"
+#include "st_cb_bitmap.h"
+#include "st_cb_blit.h"
+#include "st_cb_bufferobjects.h"
+#include "st_cb_clear.h"
+#include "st_cb_condrender.h"
+#include "st_cb_drawpixels.h"
+#include "st_cb_rasterpos.h"
+#include "st_cb_drawtex.h"
+#include "st_cb_eglimage.h"
+#include "st_cb_fbo.h"
+#include "st_cb_feedback.h"
+#include "st_cb_program.h"
+#include "st_cb_queryobj.h"
+#include "st_cb_readpixels.h"
+#include "st_cb_texture.h"
+#include "st_cb_xformfb.h"
+#include "st_cb_flush.h"
+#include "st_cb_strings.h"
+#include "st_cb_viewport.h"
+#include "st_atom.h"
+#include "st_draw.h"
+#include "st_extensions.h"
+#include "st_gen_mipmap.h"
+#include "st_program.h"
+#include "pipe/p_context.h"
+#include "util/u_inlines.h"
+#include "cso_cache/cso_context.h"
+
+
+DEBUG_GET_ONCE_BOOL_OPTION(mesa_mvp_dp4, "MESA_MVP_DP4", FALSE)
+
+
+/**
+ * Called via ctx->Driver.UpdateState()
+ */
+void st_invalidate_state(struct gl_context * ctx, GLuint new_state)
+{
+ struct st_context *st = st_context(ctx);
+
+ st->dirty.mesa |= new_state;
+ st->dirty.st |= ST_NEW_MESA;
+
+ /* This is the only core Mesa module we depend upon.
+ * No longer use swrast, swsetup, tnl.
+ */
+ _vbo_InvalidateState(ctx, new_state);
+}
+
+
+/**
+ * Check for multisample env var override.
+ */
+int
+st_get_msaa(void)
+{
+ const char *msaa = _mesa_getenv("__GL_FSAA_MODE");
+ if (msaa)
+ return atoi(msaa);
+ return 0;
+}
+
+
+static struct st_context *
+st_create_context_priv( struct gl_context *ctx, struct pipe_context *pipe )
+{
+ uint i;
+ struct st_context *st = ST_CALLOC_STRUCT( st_context );
+
+ ctx->st = st;
+
+ st->ctx = ctx;
+ st->pipe = pipe;
+
+ /* XXX: this is one-off, per-screen init: */
+ st_debug_init();
+
+ /* state tracker needs the VBO module */
+ _vbo_CreateContext(ctx);
+
+ st->dirty.mesa = ~0;
+ st->dirty.st = ~0;
+
+ st->cso_context = cso_create_context(pipe);
+
+ st_init_atoms( st );
+ st_init_bitmap(st);
+ st_init_clear(st);
+ st_init_draw( st );
+ st_init_generate_mipmap(st);
+ st_init_blit(st);
+
+ if(pipe->screen->get_param(pipe->screen, PIPE_CAP_NPOT_TEXTURES))
+ st->internal_target = PIPE_TEXTURE_2D;
+ else
+ st->internal_target = PIPE_TEXTURE_RECT;
+
+ for (i = 0; i < PIPE_MAX_SAMPLERS; i++)
+ st->state.sampler_list[i] = &st->state.samplers[i];
+
+ for (i = 0; i < 3; i++) {
+ memset(&st->velems_util_draw[i], 0, sizeof(struct pipe_vertex_element));
+ st->velems_util_draw[i].src_offset = i * 4 * sizeof(float);
+ st->velems_util_draw[i].instance_divisor = 0;
+ st->velems_util_draw[i].vertex_buffer_index = 0;
+ st->velems_util_draw[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+ }
+
+ /* we want all vertex data to be placed in buffer objects */
+ vbo_use_buffer_objects(ctx);
+
+ /* Need these flags:
+ */
+ st->ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
+
+ st->ctx->VertexProgram._MaintainTnlProgram = GL_TRUE;
+
+ st->pixel_xfer.cache = _mesa_new_program_cache();
+
+ st->force_msaa = st_get_msaa();
+
+ /* GL limits and extensions */
+ st_init_limits(st);
+ st_init_extensions(st);
+
+ return st;
+}
+
+
+struct st_context *st_create_context(gl_api api, struct pipe_context *pipe,
+ const struct gl_config *visual,
+ struct st_context *share)
+{
+ struct gl_context *ctx;
+ struct gl_context *shareCtx = share ? share->ctx : NULL;
+ struct dd_function_table funcs;
+
+ /* Sanity checks */
+ assert(MESA_SHADER_VERTEX == PIPE_SHADER_VERTEX);
+ assert(MESA_SHADER_FRAGMENT == PIPE_SHADER_FRAGMENT);
+ assert(MESA_SHADER_GEOMETRY == PIPE_SHADER_GEOMETRY);
+
+ memset(&funcs, 0, sizeof(funcs));
+ st_init_driver_functions(&funcs);
+
+ 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.
+ */
+ if (debug_get_option_mesa_mvp_dp4())
+ _mesa_set_mvp_with_dp4( ctx, GL_TRUE );
+
+ return st_create_context_priv(ctx, pipe);
+}
+
+
+static void st_destroy_context_priv( struct st_context *st )
+{
+ uint i;
+
+ st_destroy_atoms( st );
+ st_destroy_draw( st );
+ st_destroy_generate_mipmap(st);
+ st_destroy_blit(st);
+ st_destroy_clear(st);
+ st_destroy_bitmap(st);
+ st_destroy_drawpix(st);
+ st_destroy_drawtex(st);
+
+ for (i = 0; i < Elements(st->state.sampler_views); i++) {
+ pipe_sampler_view_reference(&st->state.sampler_views[i], NULL);
+ }
+
+ if (st->default_texture) {
+ st->ctx->Driver.DeleteTexture(st->ctx, st->default_texture);
+ st->default_texture = NULL;
+ }
+
+ free( st );
+}
+
+
+void st_destroy_context( struct st_context *st )
+{
+ struct pipe_context *pipe = st->pipe;
+ struct cso_context *cso = st->cso_context;
+ struct gl_context *ctx = st->ctx;
+ GLuint i;
+
+ /* need to unbind and destroy CSO objects before anything else */
+ cso_release_all(st->cso_context);
+
+ st_reference_fragprog(st, &st->fp, NULL);
+ st_reference_vertprog(st, &st->vp, NULL);
+
+ /* release framebuffer surfaces */
+ for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
+ pipe_surface_reference(&st->state.framebuffer.cbufs[i], NULL);
+ }
+ pipe_surface_reference(&st->state.framebuffer.zsbuf, NULL);
+
+ pipe->set_index_buffer(pipe, NULL);
+
+ for (i = 0; i < PIPE_SHADER_TYPES; i++) {
+ pipe->set_constant_buffer(pipe, i, 0, NULL);
+ }
+
+ _mesa_delete_program_cache(st->ctx, st->pixel_xfer.cache);
+
+ _vbo_DestroyContext(st->ctx);
+
+ st_destroy_program_variants(st);
+
+ _mesa_free_context_data(ctx);
+
+ st_destroy_context_priv(st);
+
+ cso_destroy_context(cso);
+
+ pipe->destroy( pipe );
+
+ free(ctx);
+}
+
+
+void st_init_driver_functions(struct dd_function_table *functions)
+{
+ _mesa_init_shader_object_functions(functions);
+
+ st_init_accum_functions(functions);
+ st_init_blit_functions(functions);
+ st_init_bufferobject_functions(functions);
+ st_init_clear_functions(functions);
+ st_init_bitmap_functions(functions);
+ st_init_drawpixels_functions(functions);
+ st_init_rasterpos_functions(functions);
+
+ st_init_drawtex_functions(functions);
+
+ st_init_eglimage_functions(functions);
+
+ st_init_fbo_functions(functions);
+ st_init_feedback_functions(functions);
+ st_init_program_functions(functions);
+ st_init_query_functions(functions);
+ st_init_cond_render_functions(functions);
+ st_init_readpixels_functions(functions);
+ st_init_texture_functions(functions);
+ st_init_flush_functions(functions);
+ st_init_string_functions(functions);
+ st_init_viewport_functions(functions);
+
+ st_init_xformfb_functions(functions);
+
+ functions->UpdateState = st_invalidate_state;
+}
diff --git a/mesalib/src/mesa/state_tracker/st_draw_feedback.c b/mesalib/src/mesa/state_tracker/st_draw_feedback.c index 545b32d75..2ecb8e202 100644 --- a/mesalib/src/mesa/state_tracker/st_draw_feedback.c +++ b/mesalib/src/mesa/state_tracker/st_draw_feedback.c @@ -1,278 +1,278 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include "main/imports.h" -#include "main/image.h" -#include "main/macros.h" -#include "main/mfeatures.h" - -#include "vbo/vbo.h" - -#include "st_context.h" -#include "st_atom.h" -#include "st_cb_bufferobjects.h" -#include "st_draw.h" -#include "st_program.h" - -#include "pipe/p_context.h" -#include "pipe/p_defines.h" -#include "util/u_inlines.h" - -#include "draw/draw_private.h" -#include "draw/draw_context.h" - - -#if FEATURE_feedback || FEATURE_rastpos - -/** - * Set the (private) draw module's post-transformed vertex format when in - * GL_SELECT or GL_FEEDBACK mode or for glRasterPos. - */ -static void -set_feedback_vertex_format(struct gl_context *ctx) -{ -#if 0 - struct st_context *st = st_context(ctx); - struct vertex_info vinfo; - GLuint i; - - memset(&vinfo, 0, sizeof(vinfo)); - - if (ctx->RenderMode == GL_SELECT) { - assert(ctx->RenderMode == GL_SELECT); - vinfo.num_attribs = 1; - vinfo.format[0] = FORMAT_4F; - vinfo.interp_mode[0] = INTERP_LINEAR; - } - else { - /* GL_FEEDBACK, or glRasterPos */ - /* emit all attribs (pos, color, texcoord) as GLfloat[4] */ - vinfo.num_attribs = st->state.vs->cso->state.num_outputs; - for (i = 0; i < vinfo.num_attribs; i++) { - vinfo.format[i] = FORMAT_4F; - vinfo.interp_mode[i] = INTERP_LINEAR; - } - } - - draw_set_vertex_info(st->draw, &vinfo); -#endif -} - - -/** - * Called by VBO to draw arrays when in selection or feedback mode and - * to implement glRasterPos. - * This is very much like the normal draw_vbo() function above. - * Look at code refactoring some day. - * Might move this into the failover module some day. - */ -void -st_feedback_draw_vbo(struct gl_context *ctx, - const struct gl_client_array **arrays, - const struct _mesa_prim *prims, - GLuint nr_prims, - const struct _mesa_index_buffer *ib, - GLboolean index_bounds_valid, - GLuint min_index, - GLuint max_index) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - struct draw_context *draw = st->draw; - const struct st_vertex_program *vp; - const struct pipe_shader_state *vs; - struct pipe_vertex_buffer vbuffers[PIPE_MAX_SHADER_INPUTS]; - struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; - struct pipe_index_buffer ibuffer; - struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS]; - struct pipe_transfer *ib_transfer = NULL; - GLuint attr, i; - const void *mapped_indices = NULL; - - assert(draw); - - st_validate_state(st); - - if (!index_bounds_valid) - vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index); - - /* must get these after state validation! */ - vp = st->vp; - vs = &st->vp_variant->tgsi; - - if (!st->vp_variant->draw_shader) { - st->vp_variant->draw_shader = draw_create_vertex_shader(draw, vs); - } - - /* - * Set up the draw module's state. - * - * We'd like to do this less frequently, but the normal state-update - * code sends state updates to the pipe, not to our private draw module. - */ - assert(draw); - draw_set_viewport_state(draw, &st->state.viewport); - draw_set_clip_state(draw, &st->state.clip); - draw_set_rasterizer_state(draw, &st->state.rasterizer, NULL); - draw_bind_vertex_shader(draw, st->vp_variant->draw_shader); - set_feedback_vertex_format(ctx); - - /* loop over TGSI shader inputs to determine vertex buffer - * and attribute info - */ - for (attr = 0; attr < vp->num_inputs; attr++) { - const GLuint mesaAttr = vp->index_to_input[attr]; - struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; - void *map; - - if (bufobj && bufobj->Name) { - /* Attribute data is in a VBO. - * Recall that for VBOs, the gl_client_array->Ptr field is - * really an offset from the start of the VBO, not a pointer. - */ - struct st_buffer_object *stobj = st_buffer_object(bufobj); - assert(stobj->buffer); - - vbuffers[attr].buffer = NULL; - pipe_resource_reference(&vbuffers[attr].buffer, stobj->buffer); - vbuffers[attr].buffer_offset = pointer_to_offset(arrays[0]->Ptr); - velements[attr].src_offset = arrays[mesaAttr]->Ptr - arrays[0]->Ptr; - } - else { - /* attribute data is in user-space memory, not a VBO */ - uint bytes = (arrays[mesaAttr]->Size - * _mesa_sizeof_type(arrays[mesaAttr]->Type) - * (max_index + 1)); - - /* wrap user data */ - vbuffers[attr].buffer - = pipe_user_buffer_create(pipe->screen, (void *) arrays[mesaAttr]->Ptr, - bytes, - PIPE_BIND_VERTEX_BUFFER); - vbuffers[attr].buffer_offset = 0; - velements[attr].src_offset = 0; - } - - /* common-case setup */ - vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */ - vbuffers[attr].max_index = max_index; - velements[attr].instance_divisor = 0; - velements[attr].vertex_buffer_index = attr; - velements[attr].src_format = - st_pipe_vertex_format(arrays[mesaAttr]->Type, - arrays[mesaAttr]->Size, - arrays[mesaAttr]->Format, - arrays[mesaAttr]->Normalized); - assert(velements[attr].src_format); - - /* tell draw about this attribute */ -#if 0 - draw_set_vertex_buffer(draw, attr, &vbuffer[attr]); -#endif - - /* map the attrib buffer */ - map = pipe_buffer_map(pipe, vbuffers[attr].buffer, - PIPE_TRANSFER_READ, - &vb_transfer[attr]); - draw_set_mapped_vertex_buffer(draw, attr, map); - } - - draw_set_vertex_buffers(draw, vp->num_inputs, vbuffers); - draw_set_vertex_elements(draw, vp->num_inputs, velements); - - memset(&ibuffer, 0, sizeof(ibuffer)); - if (ib) { - struct gl_buffer_object *bufobj = ib->obj; - - switch (ib->type) { - case GL_UNSIGNED_INT: - ibuffer.index_size = 4; - break; - case GL_UNSIGNED_SHORT: - ibuffer.index_size = 2; - break; - case GL_UNSIGNED_BYTE: - ibuffer.index_size = 1; - break; - default: - assert(0); - goto out_unref_vertex; - } - - if (bufobj && bufobj->Name) { - struct st_buffer_object *stobj = st_buffer_object(bufobj); - - pipe_resource_reference(&ibuffer.buffer, stobj->buffer); - ibuffer.offset = pointer_to_offset(ib->ptr); - - mapped_indices = pipe_buffer_map(pipe, stobj->buffer, - PIPE_TRANSFER_READ, &ib_transfer); - } - else { - /* skip setting ibuffer.buffer as the draw module does not use it */ - mapped_indices = ib->ptr; - } - - draw_set_index_buffer(draw, &ibuffer); - draw_set_mapped_index_buffer(draw, mapped_indices); - } - - /* set the constant buffer */ - draw_set_mapped_constant_buffer(st->draw, PIPE_SHADER_VERTEX, 0, - st->state.constants[PIPE_SHADER_VERTEX].ptr, - st->state.constants[PIPE_SHADER_VERTEX].size); - - - /* draw here */ - for (i = 0; i < nr_prims; i++) { - draw_arrays(draw, prims[i].mode, prims[i].start, prims[i].count); - } - - - /* - * unmap vertex/index buffers - */ - if (ib) { - draw_set_mapped_index_buffer(draw, NULL); - draw_set_index_buffer(draw, NULL); - - if (ib_transfer) - pipe_buffer_unmap(pipe, ib_transfer); - pipe_resource_reference(&ibuffer.buffer, NULL); - } - - out_unref_vertex: - for (attr = 0; attr < vp->num_inputs; attr++) { - pipe_buffer_unmap(pipe, vb_transfer[attr]); - draw_set_mapped_vertex_buffer(draw, attr, NULL); - pipe_resource_reference(&vbuffers[attr].buffer, NULL); - } - draw_set_vertex_buffers(draw, 0, NULL); -} - -#endif /* FEATURE_feedback || FEATURE_rastpos */ - +/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "main/imports.h"
+#include "main/image.h"
+#include "main/macros.h"
+#include "main/mfeatures.h"
+
+#include "vbo/vbo.h"
+
+#include "st_context.h"
+#include "st_atom.h"
+#include "st_cb_bufferobjects.h"
+#include "st_draw.h"
+#include "st_program.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "util/u_inlines.h"
+
+#include "draw/draw_private.h"
+#include "draw/draw_context.h"
+
+
+#if FEATURE_feedback || FEATURE_rastpos
+
+/**
+ * Set the (private) draw module's post-transformed vertex format when in
+ * GL_SELECT or GL_FEEDBACK mode or for glRasterPos.
+ */
+static void
+set_feedback_vertex_format(struct gl_context *ctx)
+{
+#if 0
+ struct st_context *st = st_context(ctx);
+ struct vertex_info vinfo;
+ GLuint i;
+
+ memset(&vinfo, 0, sizeof(vinfo));
+
+ if (ctx->RenderMode == GL_SELECT) {
+ assert(ctx->RenderMode == GL_SELECT);
+ vinfo.num_attribs = 1;
+ vinfo.format[0] = FORMAT_4F;
+ vinfo.interp_mode[0] = INTERP_LINEAR;
+ }
+ else {
+ /* GL_FEEDBACK, or glRasterPos */
+ /* emit all attribs (pos, color, texcoord) as GLfloat[4] */
+ vinfo.num_attribs = st->state.vs->cso->state.num_outputs;
+ for (i = 0; i < vinfo.num_attribs; i++) {
+ vinfo.format[i] = FORMAT_4F;
+ vinfo.interp_mode[i] = INTERP_LINEAR;
+ }
+ }
+
+ draw_set_vertex_info(st->draw, &vinfo);
+#endif
+}
+
+
+/**
+ * Called by VBO to draw arrays when in selection or feedback mode and
+ * to implement glRasterPos.
+ * This is very much like the normal draw_vbo() function above.
+ * Look at code refactoring some day.
+ * Might move this into the failover module some day.
+ */
+void
+st_feedback_draw_vbo(struct gl_context *ctx,
+ const struct gl_client_array **arrays,
+ const struct _mesa_prim *prims,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ GLboolean index_bounds_valid,
+ GLuint min_index,
+ GLuint max_index)
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_context *pipe = st->pipe;
+ struct draw_context *draw = st->draw;
+ const struct st_vertex_program *vp;
+ const struct pipe_shader_state *vs;
+ struct pipe_vertex_buffer vbuffers[PIPE_MAX_SHADER_INPUTS];
+ struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
+ struct pipe_index_buffer ibuffer;
+ struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS];
+ struct pipe_transfer *ib_transfer = NULL;
+ GLuint attr, i;
+ const void *mapped_indices = NULL;
+
+ assert(draw);
+
+ st_validate_state(st);
+
+ if (!index_bounds_valid)
+ vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index);
+
+ /* must get these after state validation! */
+ vp = st->vp;
+ vs = &st->vp_variant->tgsi;
+
+ if (!st->vp_variant->draw_shader) {
+ st->vp_variant->draw_shader = draw_create_vertex_shader(draw, vs);
+ }
+
+ /*
+ * Set up the draw module's state.
+ *
+ * We'd like to do this less frequently, but the normal state-update
+ * code sends state updates to the pipe, not to our private draw module.
+ */
+ assert(draw);
+ draw_set_viewport_state(draw, &st->state.viewport);
+ draw_set_clip_state(draw, &st->state.clip);
+ draw_set_rasterizer_state(draw, &st->state.rasterizer, NULL);
+ draw_bind_vertex_shader(draw, st->vp_variant->draw_shader);
+ set_feedback_vertex_format(ctx);
+
+ /* loop over TGSI shader inputs to determine vertex buffer
+ * and attribute info
+ */
+ for (attr = 0; attr < vp->num_inputs; attr++) {
+ const GLuint mesaAttr = vp->index_to_input[attr];
+ struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj;
+ void *map;
+
+ if (bufobj && bufobj->Name) {
+ /* Attribute data is in a VBO.
+ * Recall that for VBOs, the gl_client_array->Ptr field is
+ * really an offset from the start of the VBO, not a pointer.
+ */
+ struct st_buffer_object *stobj = st_buffer_object(bufobj);
+ assert(stobj->buffer);
+
+ vbuffers[attr].buffer = NULL;
+ pipe_resource_reference(&vbuffers[attr].buffer, stobj->buffer);
+ vbuffers[attr].buffer_offset = pointer_to_offset(arrays[0]->Ptr);
+ velements[attr].src_offset = arrays[mesaAttr]->Ptr - arrays[0]->Ptr;
+ }
+ else {
+ /* attribute data is in user-space memory, not a VBO */
+ uint bytes = (arrays[mesaAttr]->Size
+ * _mesa_sizeof_type(arrays[mesaAttr]->Type)
+ * (max_index + 1));
+
+ /* wrap user data */
+ vbuffers[attr].buffer
+ = pipe_user_buffer_create(pipe->screen, (void *) arrays[mesaAttr]->Ptr,
+ bytes,
+ PIPE_BIND_VERTEX_BUFFER);
+ vbuffers[attr].buffer_offset = 0;
+ velements[attr].src_offset = 0;
+ }
+
+ /* common-case setup */
+ vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */
+ vbuffers[attr].max_index = max_index;
+ velements[attr].instance_divisor = 0;
+ velements[attr].vertex_buffer_index = attr;
+ velements[attr].src_format =
+ st_pipe_vertex_format(arrays[mesaAttr]->Type,
+ arrays[mesaAttr]->Size,
+ arrays[mesaAttr]->Format,
+ arrays[mesaAttr]->Normalized);
+ assert(velements[attr].src_format);
+
+ /* tell draw about this attribute */
+#if 0
+ draw_set_vertex_buffer(draw, attr, &vbuffer[attr]);
+#endif
+
+ /* map the attrib buffer */
+ map = pipe_buffer_map(pipe, vbuffers[attr].buffer,
+ PIPE_TRANSFER_READ,
+ &vb_transfer[attr]);
+ draw_set_mapped_vertex_buffer(draw, attr, map);
+ }
+
+ draw_set_vertex_buffers(draw, vp->num_inputs, vbuffers);
+ draw_set_vertex_elements(draw, vp->num_inputs, velements);
+
+ memset(&ibuffer, 0, sizeof(ibuffer));
+ if (ib) {
+ struct gl_buffer_object *bufobj = ib->obj;
+
+ switch (ib->type) {
+ case GL_UNSIGNED_INT:
+ ibuffer.index_size = 4;
+ break;
+ case GL_UNSIGNED_SHORT:
+ ibuffer.index_size = 2;
+ break;
+ case GL_UNSIGNED_BYTE:
+ ibuffer.index_size = 1;
+ break;
+ default:
+ assert(0);
+ goto out_unref_vertex;
+ }
+
+ if (bufobj && bufobj->Name) {
+ struct st_buffer_object *stobj = st_buffer_object(bufobj);
+
+ pipe_resource_reference(&ibuffer.buffer, stobj->buffer);
+ ibuffer.offset = pointer_to_offset(ib->ptr);
+
+ mapped_indices = pipe_buffer_map(pipe, stobj->buffer,
+ PIPE_TRANSFER_READ, &ib_transfer);
+ }
+ else {
+ /* skip setting ibuffer.buffer as the draw module does not use it */
+ mapped_indices = ib->ptr;
+ }
+
+ draw_set_index_buffer(draw, &ibuffer);
+ draw_set_mapped_index_buffer(draw, mapped_indices);
+ }
+
+ /* set the constant buffer */
+ draw_set_mapped_constant_buffer(st->draw, PIPE_SHADER_VERTEX, 0,
+ st->state.constants[PIPE_SHADER_VERTEX].ptr,
+ st->state.constants[PIPE_SHADER_VERTEX].size);
+
+
+ /* draw here */
+ for (i = 0; i < nr_prims; i++) {
+ draw_arrays(draw, prims[i].mode, prims[i].start, prims[i].count);
+ }
+
+
+ /*
+ * unmap vertex/index buffers
+ */
+ if (ib) {
+ draw_set_mapped_index_buffer(draw, NULL);
+ draw_set_index_buffer(draw, NULL);
+
+ if (ib_transfer)
+ pipe_buffer_unmap(pipe, ib_transfer);
+ pipe_resource_reference(&ibuffer.buffer, NULL);
+ }
+
+ out_unref_vertex:
+ for (attr = 0; attr < vp->num_inputs; attr++) {
+ pipe_buffer_unmap(pipe, vb_transfer[attr]);
+ draw_set_mapped_vertex_buffer(draw, attr, NULL);
+ pipe_resource_reference(&vbuffers[attr].buffer, NULL);
+ }
+ draw_set_vertex_buffers(draw, 0, NULL);
+}
+
+#endif /* FEATURE_feedback || FEATURE_rastpos */
+
diff --git a/mesalib/src/mesa/state_tracker/st_extensions.c b/mesalib/src/mesa/state_tracker/st_extensions.c index d600edc48..76bd42cf8 100644 --- a/mesalib/src/mesa/state_tracker/st_extensions.c +++ b/mesalib/src/mesa/state_tracker/st_extensions.c @@ -1,485 +1,485 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * 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, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include "main/imports.h" -#include "main/context.h" -#include "main/macros.h" -#include "main/mfeatures.h" - -#include "pipe/p_context.h" -#include "pipe/p_defines.h" -#include "pipe/p_screen.h" - -#include "st_context.h" -#include "st_extensions.h" - - -static int _min(int a, int b) -{ - return (a < b) ? a : b; -} - -static float _maxf(float a, float b) -{ - return (a > b) ? a : b; -} - -static int _clamp(int a, int min, int max) -{ - if (a < min) - return min; - else if (a > max) - return max; - else - return a; -} - - -/** - * Query driver to get implementation limits. - * Note that we have to limit/clamp against Mesa's internal limits too. - */ -void st_init_limits(struct st_context *st) -{ - struct pipe_screen *screen = st->pipe->screen; - struct gl_constants *c = &st->ctx->Const; - gl_shader_type sh; - - c->MaxTextureLevels - = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS), - MAX_TEXTURE_LEVELS); - - c->Max3DTextureLevels - = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_3D_LEVELS), - MAX_3D_TEXTURE_LEVELS); - - c->MaxCubeTextureLevels - = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS), - MAX_CUBE_TEXTURE_LEVELS); - - c->MaxTextureRectSize - = _min(1 << (c->MaxTextureLevels - 1), MAX_TEXTURE_RECT_SIZE); - - c->MaxTextureImageUnits - = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS), - MAX_TEXTURE_IMAGE_UNITS); - - c->MaxVertexTextureImageUnits - = _min(screen->get_param(screen, PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS), - MAX_VERTEX_TEXTURE_IMAGE_UNITS); - - c->MaxCombinedTextureImageUnits - = _min(screen->get_param(screen, PIPE_CAP_MAX_COMBINED_SAMPLERS), - MAX_COMBINED_TEXTURE_IMAGE_UNITS); - - c->MaxTextureCoordUnits - = _min(c->MaxTextureImageUnits, MAX_TEXTURE_COORD_UNITS); - - c->MaxTextureUnits = _min(c->MaxTextureImageUnits, c->MaxTextureCoordUnits); - - c->MaxDrawBuffers - = _clamp(screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS), - 1, MAX_DRAW_BUFFERS); - - c->MaxLineWidth - = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_LINE_WIDTH)); - c->MaxLineWidthAA - = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_LINE_WIDTH_AA)); - - c->MaxPointSize - = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_POINT_WIDTH)); - c->MaxPointSizeAA - = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_POINT_WIDTH_AA)); - /* called after _mesa_create_context/_mesa_init_point, fix default user - * settable max point size up - */ - st->ctx->Point.MaxSize = MAX2(c->MaxPointSize, c->MaxPointSizeAA); - /* these are not queryable. Note that GL basically mandates a 1.0 minimum - * for non-aa sizes, but we can go down to 0.0 for aa points. - */ - c->MinPointSize = 1.0f; - c->MinPointSizeAA = 0.0f; - - c->MaxTextureMaxAnisotropy - = _maxf(2.0f, screen->get_paramf(screen, PIPE_CAP_MAX_TEXTURE_ANISOTROPY)); - - c->MaxTextureLodBias - = screen->get_paramf(screen, PIPE_CAP_MAX_TEXTURE_LOD_BIAS); - - c->MaxDrawBuffers - = CLAMP(screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS), - 1, MAX_DRAW_BUFFERS); - - /* Quads always follow GL provoking rules. */ - c->QuadsFollowProvokingVertexConvention = GL_FALSE; - - for (sh = 0; sh < MESA_SHADER_TYPES; ++sh) { - struct gl_shader_compiler_options *options = - &st->ctx->ShaderCompilerOptions[sh]; - struct gl_program_constants *pc; - - switch (sh) { - case PIPE_SHADER_FRAGMENT: - pc = &c->FragmentProgram; - break; - case PIPE_SHADER_VERTEX: - pc = &c->VertexProgram; - break; - case PIPE_SHADER_GEOMETRY: - pc = &c->GeometryProgram; - break; - default: - assert(0); - continue; - } - - pc->MaxNativeInstructions = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_INSTRUCTIONS); - pc->MaxNativeAluInstructions = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS); - pc->MaxNativeTexInstructions = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS); - pc->MaxNativeTexIndirections = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS); - pc->MaxNativeAttribs = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_INPUTS); - pc->MaxNativeTemps = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_TEMPS); - pc->MaxNativeAddressRegs = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_ADDRS); - pc->MaxNativeParameters = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_CONSTS); - pc->MaxUniformComponents = 4 * MIN2(pc->MaxNativeParameters, MAX_UNIFORMS); - - options->EmitNoNoise = TRUE; - - /* TODO: make these more fine-grained if anyone needs it */ - options->EmitNoIfs = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH); - options->EmitNoLoops = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH); - options->EmitNoFunctions = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_SUBROUTINES); - options->EmitNoMainReturn = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_SUBROUTINES); - - options->EmitNoCont = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_TGSI_CONT_SUPPORTED); - - options->EmitNoIndirectInput = !screen->get_shader_param(screen, sh, - PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR); - options->EmitNoIndirectOutput = !screen->get_shader_param(screen, sh, - PIPE_SHADER_CAP_INDIRECT_OUTPUT_ADDR); - options->EmitNoIndirectTemp = !screen->get_shader_param(screen, sh, - PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR); - options->EmitNoIndirectUniform = !screen->get_shader_param(screen, sh, - PIPE_SHADER_CAP_INDIRECT_CONST_ADDR); - - if(options->EmitNoLoops) - options->MaxUnrollIterations = MIN2(screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_INSTRUCTIONS), 65536); - } - - /* PIPE_CAP_MAX_FS_INPUTS specifies the number of COLORn + GENERICn inputs - * and is set in MaxNativeAttribs. It's always 2 colors + N generic - * attributes. The GLSL compiler never uses COLORn for varyings, so we - * subtract the 2 colors to get the maximum number of varyings (generic - * attributes) supported by a driver. */ - c->MaxVarying = screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, PIPE_SHADER_CAP_MAX_INPUTS) - 2; - c->MaxVarying = MIN2(c->MaxVarying, MAX_VARYING); - - /* XXX we'll need a better query here someday */ - if (screen->get_param(screen, PIPE_CAP_GLSL)) { - c->GLSLVersion = 120; - } -} - - -/** - * Use pipe_screen::get_param() to query PIPE_CAP_ values to determine - * which GL extensions are supported. - * Quite a few extensions are always supported because they are standard - * features or can be built on top of other gallium features. - * Some fine tuning may still be needed. - */ -void st_init_extensions(struct st_context *st) -{ - struct pipe_screen *screen = st->pipe->screen; - struct gl_context *ctx = st->ctx; - - /* - * Extensions that are supported by all Gallium drivers: - */ - ctx->Extensions.ARB_copy_buffer = GL_TRUE; - ctx->Extensions.ARB_draw_elements_base_vertex = GL_TRUE; - ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE; - ctx->Extensions.ARB_fragment_program = GL_TRUE; - ctx->Extensions.ARB_half_float_pixel = GL_TRUE; - ctx->Extensions.ARB_map_buffer_range = GL_TRUE; - ctx->Extensions.ARB_multisample = GL_TRUE; - ctx->Extensions.ARB_texture_border_clamp = GL_TRUE; /* XXX temp */ - ctx->Extensions.ARB_texture_compression = GL_TRUE; - ctx->Extensions.ARB_texture_cube_map = GL_TRUE; - ctx->Extensions.ARB_texture_env_combine = GL_TRUE; - ctx->Extensions.ARB_texture_env_crossbar = GL_TRUE; - ctx->Extensions.ARB_texture_env_dot3 = GL_TRUE; - ctx->Extensions.ARB_vertex_array_object = GL_TRUE; - ctx->Extensions.ARB_vertex_buffer_object = GL_TRUE; - ctx->Extensions.ARB_vertex_program = GL_TRUE; - ctx->Extensions.ARB_window_pos = GL_TRUE; - - ctx->Extensions.EXT_blend_color = GL_TRUE; - ctx->Extensions.EXT_blend_func_separate = GL_TRUE; - ctx->Extensions.EXT_blend_logic_op = GL_TRUE; - ctx->Extensions.EXT_blend_minmax = GL_TRUE; - ctx->Extensions.EXT_blend_subtract = GL_TRUE; - ctx->Extensions.EXT_framebuffer_blit = GL_TRUE; - ctx->Extensions.EXT_framebuffer_object = GL_TRUE; - ctx->Extensions.EXT_framebuffer_multisample = GL_TRUE; - ctx->Extensions.EXT_fog_coord = GL_TRUE; - ctx->Extensions.EXT_gpu_program_parameters = GL_TRUE; - ctx->Extensions.EXT_multi_draw_arrays = GL_TRUE; - ctx->Extensions.EXT_pixel_buffer_object = GL_TRUE; - ctx->Extensions.EXT_point_parameters = GL_TRUE; - ctx->Extensions.EXT_provoking_vertex = GL_TRUE; - ctx->Extensions.EXT_secondary_color = GL_TRUE; - ctx->Extensions.EXT_stencil_wrap = GL_TRUE; - ctx->Extensions.EXT_texture_env_add = GL_TRUE; - ctx->Extensions.EXT_texture_env_combine = GL_TRUE; - ctx->Extensions.EXT_texture_env_dot3 = GL_TRUE; - ctx->Extensions.EXT_texture_lod_bias = GL_TRUE; - ctx->Extensions.EXT_vertex_array_bgra = GL_TRUE; - if (ctx->API == API_OPENGLES || ctx->API == API_OPENGLES2) - ctx->Extensions.EXT_texture_format_BGRA8888 = GL_TRUE; - - ctx->Extensions.APPLE_vertex_array_object = GL_TRUE; - - ctx->Extensions.ATI_texture_env_combine3 = GL_TRUE; - - ctx->Extensions.MESA_pack_invert = GL_TRUE; - - ctx->Extensions.NV_blend_square = GL_TRUE; - ctx->Extensions.NV_texgen_reflection = GL_TRUE; - ctx->Extensions.NV_texture_env_combine4 = GL_TRUE; - ctx->Extensions.NV_texture_rectangle = GL_TRUE; -#if 0 - /* possibly could support the following two */ - ctx->Extensions.NV_vertex_program = GL_TRUE; - ctx->Extensions.NV_vertex_program1_1 = GL_TRUE; -#endif - -#if FEATURE_OES_EGL_image - ctx->Extensions.OES_EGL_image = GL_TRUE; -#endif -#if FEATURE_OES_draw_texture - ctx->Extensions.OES_draw_texture = GL_TRUE; -#endif - - ctx->Extensions.SGIS_generate_mipmap = GL_TRUE; - - /* - * Extensions that depend on the driver/hardware: - */ - if (screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS) > 0) { - ctx->Extensions.ARB_draw_buffers = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_TEXTURE_SWIZZLE) > 0) { - ctx->Extensions.EXT_texture_swizzle = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_GLSL)) { - ctx->Extensions.ARB_fragment_shader = GL_TRUE; - ctx->Extensions.ARB_vertex_shader = GL_TRUE; - ctx->Extensions.ARB_shader_objects = GL_TRUE; - ctx->Extensions.ARB_shading_language_100 = GL_TRUE; - ctx->Extensions.ARB_explicit_attrib_location = GL_TRUE; - ctx->Extensions.EXT_separate_shader_objects = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_TEXTURE_MIRROR_REPEAT) > 0) { - ctx->Extensions.ARB_texture_mirrored_repeat = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_BLEND_EQUATION_SEPARATE)) { - ctx->Extensions.EXT_blend_equation_separate = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_TEXTURE_MIRROR_CLAMP) > 0) { - ctx->Extensions.EXT_texture_mirror_clamp = GL_TRUE; - ctx->Extensions.ATI_texture_mirror_once = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES)) { - ctx->Extensions.ARB_texture_non_power_of_two = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS) > 1) { - ctx->Extensions.ARB_multitexture = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) { - ctx->Extensions.ATI_separate_stencil = GL_TRUE; - ctx->Extensions.EXT_stencil_two_side = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_ANISOTROPIC_FILTER)) { - ctx->Extensions.EXT_texture_filter_anisotropic = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_POINT_SPRITE)) { - ctx->Extensions.ARB_point_sprite = GL_TRUE; - /* GL_NV_point_sprite is not supported by gallium because we don't - * support the GL_POINT_SPRITE_R_MODE_NV option. - */ - } - - if (screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY)) { - ctx->Extensions.ARB_occlusion_query = GL_TRUE; - ctx->Extensions.ARB_occlusion_query2 = GL_TRUE; - } - if (screen->get_param(screen, PIPE_CAP_TIMER_QUERY)) { - ctx->Extensions.EXT_timer_query = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_TEXTURE_SHADOW_MAP)) { - ctx->Extensions.ARB_depth_texture = GL_TRUE; - ctx->Extensions.ARB_fragment_program_shadow = GL_TRUE; - ctx->Extensions.ARB_shadow = GL_TRUE; - ctx->Extensions.EXT_shadow_funcs = GL_TRUE; - /*ctx->Extensions.ARB_shadow_ambient = GL_TRUE;*/ - } - - /* GL_EXT_packed_depth_stencil requires both the ability to render to - * a depth/stencil buffer and texture from depth/stencil source. - */ - if (screen->is_format_supported(screen, PIPE_FORMAT_S8_USCALED_Z24_UNORM, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_DEPTH_STENCIL, 0) && - screen->is_format_supported(screen, PIPE_FORMAT_S8_USCALED_Z24_UNORM, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_SAMPLER_VIEW, 0)) { - ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE; - } - else if (screen->is_format_supported(screen, PIPE_FORMAT_Z24_UNORM_S8_USCALED, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_DEPTH_STENCIL, 0) && - screen->is_format_supported(screen, PIPE_FORMAT_Z24_UNORM_S8_USCALED, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_SAMPLER_VIEW, 0)) { - ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE; - } - - /* sRGB support */ - if (screen->is_format_supported(screen, PIPE_FORMAT_A8B8G8R8_SRGB, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_SAMPLER_VIEW, 0) || - screen->is_format_supported(screen, PIPE_FORMAT_B8G8R8A8_SRGB, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_SAMPLER_VIEW, 0)) { - ctx->Extensions.EXT_texture_sRGB = GL_TRUE; - ctx->Extensions.EXT_texture_sRGB_decode = GL_TRUE; - if (screen->is_format_supported(screen, PIPE_FORMAT_A8B8G8R8_SRGB, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_RENDER_TARGET, 0) || - screen->is_format_supported(screen, PIPE_FORMAT_B8G8R8A8_SRGB, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_RENDER_TARGET, 0)) { - ctx->Extensions.EXT_framebuffer_sRGB = GL_TRUE; - ctx->Const.sRGBCapable = GL_TRUE; - } - } - - if (screen->is_format_supported(screen, PIPE_FORMAT_R8G8_UNORM, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_SAMPLER_VIEW, 0)) { - ctx->Extensions.ARB_texture_rg = GL_TRUE; - } - - /* s3tc support */ - if (screen->is_format_supported(screen, PIPE_FORMAT_DXT5_RGBA, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_SAMPLER_VIEW, 0) && - (ctx->Mesa_DXTn || - screen->is_format_supported(screen, PIPE_FORMAT_DXT5_RGBA, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_RENDER_TARGET, 0))) { - ctx->Extensions.EXT_texture_compression_s3tc = GL_TRUE; - ctx->Extensions.S3_s3tc = GL_TRUE; - } - - /* ycbcr support */ - if (screen->is_format_supported(screen, PIPE_FORMAT_UYVY, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_SAMPLER_VIEW, 0) || - screen->is_format_supported(screen, PIPE_FORMAT_YUYV, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_SAMPLER_VIEW, 0)) { - ctx->Extensions.MESA_ycbcr_texture = GL_TRUE; - } - - /* GL_EXT_texture_array */ - if (screen->get_param(screen, PIPE_CAP_ARRAY_TEXTURES)) { - ctx->Extensions.EXT_texture_array = GL_TRUE; - ctx->Extensions.MESA_texture_array = GL_TRUE; - } - - /* GL_ARB_framebuffer_object */ - if (ctx->Extensions.EXT_packed_depth_stencil) { - /* we support always support GL_EXT_framebuffer_blit */ - ctx->Extensions.ARB_framebuffer_object = GL_TRUE; - } - - if (st->pipe->render_condition) { - ctx->Extensions.NV_conditional_render = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_INDEP_BLEND_ENABLE)) { - ctx->Extensions.EXT_draw_buffers2 = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_INDEP_BLEND_FUNC)) { - ctx->Extensions.ARB_draw_buffers_blend = GL_TRUE; - } - - /* GL_ARB_half_float_vertex */ - if (screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_FLOAT, - PIPE_BUFFER, 0, - PIPE_BIND_VERTEX_BUFFER, 0)) { - ctx->Extensions.ARB_half_float_vertex = GL_TRUE; - } - - if (screen->get_shader_param(screen, PIPE_SHADER_GEOMETRY, PIPE_SHADER_CAP_MAX_INSTRUCTIONS) > 0) { -#if 0 /* XXX re-enable when GLSL compiler again supports geometry shaders */ - ctx->Extensions.ARB_geometry_shader4 = GL_TRUE; -#endif - } - - if (screen->get_param(screen, PIPE_CAP_PRIMITIVE_RESTART)) { - ctx->Extensions.NV_primitive_restart = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_DEPTH_CLAMP)) { - ctx->Extensions.ARB_depth_clamp = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) { - ctx->Extensions.ARB_shader_stencil_export = GL_TRUE; - } - - if (screen->get_param(screen, PIPE_CAP_INSTANCED_DRAWING)) { - ctx->Extensions.ARB_draw_instanced = GL_TRUE; - ctx->Extensions.ARB_instanced_arrays = GL_TRUE; - } -} +/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "main/imports.h"
+#include "main/context.h"
+#include "main/macros.h"
+#include "main/mfeatures.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_screen.h"
+
+#include "st_context.h"
+#include "st_extensions.h"
+
+
+static int _min(int a, int b)
+{
+ return (a < b) ? a : b;
+}
+
+static float _maxf(float a, float b)
+{
+ return (a > b) ? a : b;
+}
+
+static int _clamp(int a, int min, int max)
+{
+ if (a < min)
+ return min;
+ else if (a > max)
+ return max;
+ else
+ return a;
+}
+
+
+/**
+ * Query driver to get implementation limits.
+ * Note that we have to limit/clamp against Mesa's internal limits too.
+ */
+void st_init_limits(struct st_context *st)
+{
+ struct pipe_screen *screen = st->pipe->screen;
+ struct gl_constants *c = &st->ctx->Const;
+ gl_shader_type sh;
+
+ c->MaxTextureLevels
+ = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS),
+ MAX_TEXTURE_LEVELS);
+
+ c->Max3DTextureLevels
+ = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_3D_LEVELS),
+ MAX_3D_TEXTURE_LEVELS);
+
+ c->MaxCubeTextureLevels
+ = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS),
+ MAX_CUBE_TEXTURE_LEVELS);
+
+ c->MaxTextureRectSize
+ = _min(1 << (c->MaxTextureLevels - 1), MAX_TEXTURE_RECT_SIZE);
+
+ c->MaxTextureImageUnits
+ = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS),
+ MAX_TEXTURE_IMAGE_UNITS);
+
+ c->MaxVertexTextureImageUnits
+ = _min(screen->get_param(screen, PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS),
+ MAX_VERTEX_TEXTURE_IMAGE_UNITS);
+
+ c->MaxCombinedTextureImageUnits
+ = _min(screen->get_param(screen, PIPE_CAP_MAX_COMBINED_SAMPLERS),
+ MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+
+ c->MaxTextureCoordUnits
+ = _min(c->MaxTextureImageUnits, MAX_TEXTURE_COORD_UNITS);
+
+ c->MaxTextureUnits = _min(c->MaxTextureImageUnits, c->MaxTextureCoordUnits);
+
+ c->MaxDrawBuffers
+ = _clamp(screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS),
+ 1, MAX_DRAW_BUFFERS);
+
+ c->MaxLineWidth
+ = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_LINE_WIDTH));
+ c->MaxLineWidthAA
+ = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_LINE_WIDTH_AA));
+
+ c->MaxPointSize
+ = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_POINT_WIDTH));
+ c->MaxPointSizeAA
+ = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_POINT_WIDTH_AA));
+ /* called after _mesa_create_context/_mesa_init_point, fix default user
+ * settable max point size up
+ */
+ st->ctx->Point.MaxSize = MAX2(c->MaxPointSize, c->MaxPointSizeAA);
+ /* these are not queryable. Note that GL basically mandates a 1.0 minimum
+ * for non-aa sizes, but we can go down to 0.0 for aa points.
+ */
+ c->MinPointSize = 1.0f;
+ c->MinPointSizeAA = 0.0f;
+
+ c->MaxTextureMaxAnisotropy
+ = _maxf(2.0f, screen->get_paramf(screen, PIPE_CAP_MAX_TEXTURE_ANISOTROPY));
+
+ c->MaxTextureLodBias
+ = screen->get_paramf(screen, PIPE_CAP_MAX_TEXTURE_LOD_BIAS);
+
+ c->MaxDrawBuffers
+ = CLAMP(screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS),
+ 1, MAX_DRAW_BUFFERS);
+
+ /* Quads always follow GL provoking rules. */
+ c->QuadsFollowProvokingVertexConvention = GL_FALSE;
+
+ for (sh = 0; sh < MESA_SHADER_TYPES; ++sh) {
+ struct gl_shader_compiler_options *options =
+ &st->ctx->ShaderCompilerOptions[sh];
+ struct gl_program_constants *pc;
+
+ switch (sh) {
+ case PIPE_SHADER_FRAGMENT:
+ pc = &c->FragmentProgram;
+ break;
+ case PIPE_SHADER_VERTEX:
+ pc = &c->VertexProgram;
+ break;
+ case PIPE_SHADER_GEOMETRY:
+ pc = &c->GeometryProgram;
+ break;
+ default:
+ assert(0);
+ continue;
+ }
+
+ pc->MaxNativeInstructions = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_INSTRUCTIONS);
+ pc->MaxNativeAluInstructions = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS);
+ pc->MaxNativeTexInstructions = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS);
+ pc->MaxNativeTexIndirections = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS);
+ pc->MaxNativeAttribs = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_INPUTS);
+ pc->MaxNativeTemps = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_TEMPS);
+ pc->MaxNativeAddressRegs = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_ADDRS);
+ pc->MaxNativeParameters = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_CONSTS);
+ pc->MaxUniformComponents = 4 * MIN2(pc->MaxNativeParameters, MAX_UNIFORMS);
+
+ options->EmitNoNoise = TRUE;
+
+ /* TODO: make these more fine-grained if anyone needs it */
+ options->EmitNoIfs = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH);
+ options->EmitNoLoops = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH);
+ options->EmitNoFunctions = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_SUBROUTINES);
+ options->EmitNoMainReturn = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_SUBROUTINES);
+
+ options->EmitNoCont = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_TGSI_CONT_SUPPORTED);
+
+ options->EmitNoIndirectInput = !screen->get_shader_param(screen, sh,
+ PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR);
+ options->EmitNoIndirectOutput = !screen->get_shader_param(screen, sh,
+ PIPE_SHADER_CAP_INDIRECT_OUTPUT_ADDR);
+ options->EmitNoIndirectTemp = !screen->get_shader_param(screen, sh,
+ PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR);
+ options->EmitNoIndirectUniform = !screen->get_shader_param(screen, sh,
+ PIPE_SHADER_CAP_INDIRECT_CONST_ADDR);
+
+ if(options->EmitNoLoops)
+ options->MaxUnrollIterations = MIN2(screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_INSTRUCTIONS), 65536);
+ }
+
+ /* PIPE_CAP_MAX_FS_INPUTS specifies the number of COLORn + GENERICn inputs
+ * and is set in MaxNativeAttribs. It's always 2 colors + N generic
+ * attributes. The GLSL compiler never uses COLORn for varyings, so we
+ * subtract the 2 colors to get the maximum number of varyings (generic
+ * attributes) supported by a driver. */
+ c->MaxVarying = screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, PIPE_SHADER_CAP_MAX_INPUTS) - 2;
+ c->MaxVarying = MIN2(c->MaxVarying, MAX_VARYING);
+
+ /* XXX we'll need a better query here someday */
+ if (screen->get_param(screen, PIPE_CAP_GLSL)) {
+ c->GLSLVersion = 120;
+ }
+}
+
+
+/**
+ * Use pipe_screen::get_param() to query PIPE_CAP_ values to determine
+ * which GL extensions are supported.
+ * Quite a few extensions are always supported because they are standard
+ * features or can be built on top of other gallium features.
+ * Some fine tuning may still be needed.
+ */
+void st_init_extensions(struct st_context *st)
+{
+ struct pipe_screen *screen = st->pipe->screen;
+ struct gl_context *ctx = st->ctx;
+
+ /*
+ * Extensions that are supported by all Gallium drivers:
+ */
+ ctx->Extensions.ARB_copy_buffer = GL_TRUE;
+ ctx->Extensions.ARB_draw_elements_base_vertex = GL_TRUE;
+ ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE;
+ ctx->Extensions.ARB_fragment_program = GL_TRUE;
+ ctx->Extensions.ARB_half_float_pixel = GL_TRUE;
+ ctx->Extensions.ARB_map_buffer_range = GL_TRUE;
+ ctx->Extensions.ARB_multisample = GL_TRUE;
+ ctx->Extensions.ARB_texture_border_clamp = GL_TRUE; /* XXX temp */
+ ctx->Extensions.ARB_texture_compression = GL_TRUE;
+ ctx->Extensions.ARB_texture_cube_map = GL_TRUE;
+ ctx->Extensions.ARB_texture_env_combine = GL_TRUE;
+ ctx->Extensions.ARB_texture_env_crossbar = GL_TRUE;
+ ctx->Extensions.ARB_texture_env_dot3 = GL_TRUE;
+ ctx->Extensions.ARB_vertex_array_object = GL_TRUE;
+ ctx->Extensions.ARB_vertex_buffer_object = GL_TRUE;
+ ctx->Extensions.ARB_vertex_program = GL_TRUE;
+ ctx->Extensions.ARB_window_pos = GL_TRUE;
+
+ ctx->Extensions.EXT_blend_color = GL_TRUE;
+ ctx->Extensions.EXT_blend_func_separate = GL_TRUE;
+ ctx->Extensions.EXT_blend_logic_op = GL_TRUE;
+ ctx->Extensions.EXT_blend_minmax = GL_TRUE;
+ ctx->Extensions.EXT_blend_subtract = GL_TRUE;
+ ctx->Extensions.EXT_framebuffer_blit = GL_TRUE;
+ ctx->Extensions.EXT_framebuffer_object = GL_TRUE;
+ ctx->Extensions.EXT_framebuffer_multisample = GL_TRUE;
+ ctx->Extensions.EXT_fog_coord = GL_TRUE;
+ ctx->Extensions.EXT_gpu_program_parameters = GL_TRUE;
+ ctx->Extensions.EXT_multi_draw_arrays = GL_TRUE;
+ ctx->Extensions.EXT_pixel_buffer_object = GL_TRUE;
+ ctx->Extensions.EXT_point_parameters = GL_TRUE;
+ ctx->Extensions.EXT_provoking_vertex = GL_TRUE;
+ ctx->Extensions.EXT_secondary_color = GL_TRUE;
+ ctx->Extensions.EXT_stencil_wrap = GL_TRUE;
+ ctx->Extensions.EXT_texture_env_add = GL_TRUE;
+ ctx->Extensions.EXT_texture_env_combine = GL_TRUE;
+ ctx->Extensions.EXT_texture_env_dot3 = GL_TRUE;
+ ctx->Extensions.EXT_texture_lod_bias = GL_TRUE;
+ ctx->Extensions.EXT_vertex_array_bgra = GL_TRUE;
+ if (ctx->API == API_OPENGLES || ctx->API == API_OPENGLES2)
+ ctx->Extensions.EXT_texture_format_BGRA8888 = GL_TRUE;
+
+ ctx->Extensions.APPLE_vertex_array_object = GL_TRUE;
+
+ ctx->Extensions.ATI_texture_env_combine3 = GL_TRUE;
+
+ ctx->Extensions.MESA_pack_invert = GL_TRUE;
+
+ ctx->Extensions.NV_blend_square = GL_TRUE;
+ ctx->Extensions.NV_texgen_reflection = GL_TRUE;
+ ctx->Extensions.NV_texture_env_combine4 = GL_TRUE;
+ ctx->Extensions.NV_texture_rectangle = GL_TRUE;
+#if 0
+ /* possibly could support the following two */
+ ctx->Extensions.NV_vertex_program = GL_TRUE;
+ ctx->Extensions.NV_vertex_program1_1 = GL_TRUE;
+#endif
+
+#if FEATURE_OES_EGL_image
+ ctx->Extensions.OES_EGL_image = GL_TRUE;
+#endif
+#if FEATURE_OES_draw_texture
+ ctx->Extensions.OES_draw_texture = GL_TRUE;
+#endif
+
+ ctx->Extensions.SGIS_generate_mipmap = GL_TRUE;
+
+ /*
+ * Extensions that depend on the driver/hardware:
+ */
+ if (screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS) > 0) {
+ ctx->Extensions.ARB_draw_buffers = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_TEXTURE_SWIZZLE) > 0) {
+ ctx->Extensions.EXT_texture_swizzle = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_GLSL)) {
+ ctx->Extensions.ARB_fragment_shader = GL_TRUE;
+ ctx->Extensions.ARB_vertex_shader = GL_TRUE;
+ ctx->Extensions.ARB_shader_objects = GL_TRUE;
+ ctx->Extensions.ARB_shading_language_100 = GL_TRUE;
+ ctx->Extensions.ARB_explicit_attrib_location = GL_TRUE;
+ ctx->Extensions.EXT_separate_shader_objects = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_TEXTURE_MIRROR_REPEAT) > 0) {
+ ctx->Extensions.ARB_texture_mirrored_repeat = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_BLEND_EQUATION_SEPARATE)) {
+ ctx->Extensions.EXT_blend_equation_separate = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_TEXTURE_MIRROR_CLAMP) > 0) {
+ ctx->Extensions.EXT_texture_mirror_clamp = GL_TRUE;
+ ctx->Extensions.ATI_texture_mirror_once = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES)) {
+ ctx->Extensions.ARB_texture_non_power_of_two = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS) > 1) {
+ ctx->Extensions.ARB_multitexture = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) {
+ ctx->Extensions.ATI_separate_stencil = GL_TRUE;
+ ctx->Extensions.EXT_stencil_two_side = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_ANISOTROPIC_FILTER)) {
+ ctx->Extensions.EXT_texture_filter_anisotropic = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_POINT_SPRITE)) {
+ ctx->Extensions.ARB_point_sprite = GL_TRUE;
+ /* GL_NV_point_sprite is not supported by gallium because we don't
+ * support the GL_POINT_SPRITE_R_MODE_NV option.
+ */
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY)) {
+ ctx->Extensions.ARB_occlusion_query = GL_TRUE;
+ ctx->Extensions.ARB_occlusion_query2 = GL_TRUE;
+ }
+ if (screen->get_param(screen, PIPE_CAP_TIMER_QUERY)) {
+ ctx->Extensions.EXT_timer_query = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_TEXTURE_SHADOW_MAP)) {
+ ctx->Extensions.ARB_depth_texture = GL_TRUE;
+ ctx->Extensions.ARB_fragment_program_shadow = GL_TRUE;
+ ctx->Extensions.ARB_shadow = GL_TRUE;
+ ctx->Extensions.EXT_shadow_funcs = GL_TRUE;
+ /*ctx->Extensions.ARB_shadow_ambient = GL_TRUE;*/
+ }
+
+ /* GL_EXT_packed_depth_stencil requires both the ability to render to
+ * a depth/stencil buffer and texture from depth/stencil source.
+ */
+ if (screen->is_format_supported(screen, PIPE_FORMAT_S8_USCALED_Z24_UNORM,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_DEPTH_STENCIL, 0) &&
+ screen->is_format_supported(screen, PIPE_FORMAT_S8_USCALED_Z24_UNORM,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0)) {
+ ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE;
+ }
+ else if (screen->is_format_supported(screen, PIPE_FORMAT_Z24_UNORM_S8_USCALED,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_DEPTH_STENCIL, 0) &&
+ screen->is_format_supported(screen, PIPE_FORMAT_Z24_UNORM_S8_USCALED,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0)) {
+ ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE;
+ }
+
+ /* sRGB support */
+ if (screen->is_format_supported(screen, PIPE_FORMAT_A8B8G8R8_SRGB,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0) ||
+ screen->is_format_supported(screen, PIPE_FORMAT_B8G8R8A8_SRGB,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0)) {
+ ctx->Extensions.EXT_texture_sRGB = GL_TRUE;
+ ctx->Extensions.EXT_texture_sRGB_decode = GL_TRUE;
+ if (screen->is_format_supported(screen, PIPE_FORMAT_A8B8G8R8_SRGB,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_RENDER_TARGET, 0) ||
+ screen->is_format_supported(screen, PIPE_FORMAT_B8G8R8A8_SRGB,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_RENDER_TARGET, 0)) {
+ ctx->Extensions.EXT_framebuffer_sRGB = GL_TRUE;
+ ctx->Const.sRGBCapable = GL_TRUE;
+ }
+ }
+
+ if (screen->is_format_supported(screen, PIPE_FORMAT_R8G8_UNORM,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0)) {
+ ctx->Extensions.ARB_texture_rg = GL_TRUE;
+ }
+
+ /* s3tc support */
+ if (screen->is_format_supported(screen, PIPE_FORMAT_DXT5_RGBA,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0) &&
+ (ctx->Mesa_DXTn ||
+ screen->is_format_supported(screen, PIPE_FORMAT_DXT5_RGBA,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_RENDER_TARGET, 0))) {
+ ctx->Extensions.EXT_texture_compression_s3tc = GL_TRUE;
+ ctx->Extensions.S3_s3tc = GL_TRUE;
+ }
+
+ /* ycbcr support */
+ if (screen->is_format_supported(screen, PIPE_FORMAT_UYVY,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0) ||
+ screen->is_format_supported(screen, PIPE_FORMAT_YUYV,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0)) {
+ ctx->Extensions.MESA_ycbcr_texture = GL_TRUE;
+ }
+
+ /* GL_EXT_texture_array */
+ if (screen->get_param(screen, PIPE_CAP_ARRAY_TEXTURES)) {
+ ctx->Extensions.EXT_texture_array = GL_TRUE;
+ ctx->Extensions.MESA_texture_array = GL_TRUE;
+ }
+
+ /* GL_ARB_framebuffer_object */
+ if (ctx->Extensions.EXT_packed_depth_stencil) {
+ /* we support always support GL_EXT_framebuffer_blit */
+ ctx->Extensions.ARB_framebuffer_object = GL_TRUE;
+ }
+
+ if (st->pipe->render_condition) {
+ ctx->Extensions.NV_conditional_render = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_INDEP_BLEND_ENABLE)) {
+ ctx->Extensions.EXT_draw_buffers2 = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_INDEP_BLEND_FUNC)) {
+ ctx->Extensions.ARB_draw_buffers_blend = GL_TRUE;
+ }
+
+ /* GL_ARB_half_float_vertex */
+ if (screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_FLOAT,
+ PIPE_BUFFER, 0,
+ PIPE_BIND_VERTEX_BUFFER, 0)) {
+ ctx->Extensions.ARB_half_float_vertex = GL_TRUE;
+ }
+
+ if (screen->get_shader_param(screen, PIPE_SHADER_GEOMETRY, PIPE_SHADER_CAP_MAX_INSTRUCTIONS) > 0) {
+#if 0 /* XXX re-enable when GLSL compiler again supports geometry shaders */
+ ctx->Extensions.ARB_geometry_shader4 = GL_TRUE;
+#endif
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_PRIMITIVE_RESTART)) {
+ ctx->Extensions.NV_primitive_restart = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_DEPTH_CLAMP)) {
+ ctx->Extensions.ARB_depth_clamp = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) {
+ ctx->Extensions.ARB_shader_stencil_export = GL_TRUE;
+ }
+
+ if (screen->get_param(screen, PIPE_CAP_INSTANCED_DRAWING)) {
+ ctx->Extensions.ARB_draw_instanced = GL_TRUE;
+ ctx->Extensions.ARB_instanced_arrays = GL_TRUE;
+ }
+}
diff --git a/mesalib/src/mesa/state_tracker/st_program.c b/mesalib/src/mesa/state_tracker/st_program.c index fc1dfb3ef..e5c26c563 100644 --- a/mesalib/src/mesa/state_tracker/st_program.c +++ b/mesalib/src/mesa/state_tracker/st_program.c @@ -1,1165 +1,1165 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - /* - * Authors: - * Keith Whitwell <keith@tungstengraphics.com> - * Brian Paul - */ - - -#include "main/imports.h" -#include "main/hash.h" -#include "main/mfeatures.h" -#include "main/mtypes.h" -#include "program/prog_parameter.h" -#include "program/prog_print.h" -#include "program/programopt.h" - -#include "pipe/p_context.h" -#include "pipe/p_defines.h" -#include "pipe/p_shader_tokens.h" -#include "draw/draw_context.h" -#include "tgsi/tgsi_dump.h" -#include "tgsi/tgsi_ureg.h" - -#include "st_debug.h" -#include "st_cb_bitmap.h" -#include "st_cb_drawpixels.h" -#include "st_context.h" -#include "st_program.h" -#include "st_mesa_to_tgsi.h" -#include "cso_cache/cso_context.h" - - - -/** - * Delete a vertex program variant. Note the caller must unlink - * the variant from the linked list. - */ -static void -delete_vp_variant(struct st_context *st, struct st_vp_variant *vpv) -{ - if (vpv->driver_shader) - cso_delete_vertex_shader(st->cso_context, vpv->driver_shader); - -#if FEATURE_feedback || FEATURE_rastpos - if (vpv->draw_shader) - draw_delete_vertex_shader( st->draw, vpv->draw_shader ); -#endif - - if (vpv->tgsi.tokens) - st_free_tokens(vpv->tgsi.tokens); - - FREE( vpv ); -} - - - -/** - * Clean out any old compilations: - */ -void -st_release_vp_variants( struct st_context *st, - struct st_vertex_program *stvp ) -{ - struct st_vp_variant *vpv; - - for (vpv = stvp->variants; vpv; ) { - struct st_vp_variant *next = vpv->next; - delete_vp_variant(st, vpv); - vpv = next; - } - - stvp->variants = NULL; -} - - - -/** - * Delete a fragment program variant. Note the caller must unlink - * the variant from the linked list. - */ -static void -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); -} - - -/** - * Free all variants of a fragment program. - */ -void -st_release_fp_variants(struct st_context *st, struct st_fragment_program *stfp) -{ - struct st_fp_variant *fpv; - - for (fpv = stfp->variants; fpv; ) { - struct st_fp_variant *next = fpv->next; - delete_fp_variant(st, fpv); - fpv = next; - } - - stfp->variants = NULL; -} - - -/** - * Delete a geometry program variant. Note the caller must unlink - * the variant from the linked list. - */ -static void -delete_gp_variant(struct st_context *st, struct st_gp_variant *gpv) -{ - if (gpv->driver_shader) - cso_delete_geometry_shader(st->cso_context, gpv->driver_shader); - - FREE(gpv); -} - - -/** - * Free all variants of a geometry program. - */ -void -st_release_gp_variants(struct st_context *st, struct st_geometry_program *stgp) -{ - struct st_gp_variant *gpv; - - for (gpv = stgp->variants; gpv; ) { - struct st_gp_variant *next = gpv->next; - delete_gp_variant(st, gpv); - gpv = next; - } - - stgp->variants = NULL; -} - - - - -/** - * Translate a Mesa vertex shader into a TGSI shader. - * \param outputMapping to map vertex program output registers (VERT_RESULT_x) - * to TGSI output slots - * \param tokensOut destination for TGSI tokens - * \return pointer to cached pipe_shader object. - */ -static void -st_prepare_vertex_program(struct st_context *st, - struct st_vertex_program *stvp) -{ - GLuint attr; - - stvp->num_inputs = 0; - stvp->num_outputs = 0; - - if (stvp->Base.IsPositionInvariant) - _mesa_insert_mvp_code(st->ctx, &stvp->Base); - - assert(stvp->Base.Base.NumInstructions > 1); - - /* - * Determine number of inputs, the mappings between VERT_ATTRIB_x - * and TGSI generic input indexes, plus input attrib semantic info. - */ - for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { - if (stvp->Base.Base.InputsRead & (1 << attr)) { - stvp->input_to_index[attr] = stvp->num_inputs; - stvp->index_to_input[stvp->num_inputs] = attr; - stvp->num_inputs++; - } - } - /* bit of a hack, presetup potentially unused edgeflag input */ - stvp->input_to_index[VERT_ATTRIB_EDGEFLAG] = stvp->num_inputs; - stvp->index_to_input[stvp->num_inputs] = VERT_ATTRIB_EDGEFLAG; - - /* Compute mapping of vertex program outputs to slots. - */ - for (attr = 0; attr < VERT_RESULT_MAX; attr++) { - if ((stvp->Base.Base.OutputsWritten & BITFIELD64_BIT(attr)) == 0) { - stvp->result_to_output[attr] = ~0; - } - else { - unsigned slot = stvp->num_outputs++; - - stvp->result_to_output[attr] = slot; - - switch (attr) { - case VERT_RESULT_HPOS: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_COL0: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_COL1: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stvp->output_semantic_index[slot] = 1; - break; - case VERT_RESULT_BFC0: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_BFC1: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - stvp->output_semantic_index[slot] = 1; - break; - case VERT_RESULT_FOGC: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_FOG; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_PSIZ: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; - stvp->output_semantic_index[slot] = 0; - break; - case VERT_RESULT_EDGE: - assert(0); - break; - - case VERT_RESULT_TEX0: - case VERT_RESULT_TEX1: - case VERT_RESULT_TEX2: - case VERT_RESULT_TEX3: - case VERT_RESULT_TEX4: - case VERT_RESULT_TEX5: - case VERT_RESULT_TEX6: - case VERT_RESULT_TEX7: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stvp->output_semantic_index[slot] = attr - VERT_RESULT_TEX0; - break; - - case VERT_RESULT_VAR0: - default: - assert(attr < VERT_RESULT_MAX); - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stvp->output_semantic_index[slot] = (FRAG_ATTRIB_VAR0 - - FRAG_ATTRIB_TEX0 + - attr - - VERT_RESULT_VAR0); - break; - } - } - } - /* similar hack to above, presetup potentially unused edgeflag output */ - stvp->result_to_output[VERT_RESULT_EDGE] = stvp->num_outputs; - stvp->output_semantic_name[stvp->num_outputs] = TGSI_SEMANTIC_EDGEFLAG; - stvp->output_semantic_index[stvp->num_outputs] = 0; -} - - -/** - * Translate a vertex program to create a new variant. - */ -static struct st_vp_variant * -st_translate_vertex_program(struct st_context *st, - struct st_vertex_program *stvp, - const struct st_vp_variant_key *key) -{ - struct st_vp_variant *vpv = CALLOC_STRUCT(st_vp_variant); - struct pipe_context *pipe = st->pipe; - struct ureg_program *ureg; - enum pipe_error error; - unsigned num_outputs; - - st_prepare_vertex_program( st, stvp ); - - _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_OUTPUT); - _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_VARYING); - - ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); - if (ureg == NULL) { - FREE(vpv); - return NULL; - } - - vpv->key = *key; - - vpv->num_inputs = stvp->num_inputs; - num_outputs = stvp->num_outputs; - if (key->passthrough_edgeflags) { - vpv->num_inputs++; - num_outputs++; - } - - if (ST_DEBUG & DEBUG_MESA) { - _mesa_print_program(&stvp->Base.Base); - _mesa_print_program_parameters(st->ctx, &stvp->Base.Base); - debug_printf("\n"); - } - - error = st_translate_mesa_program(st->ctx, - TGSI_PROCESSOR_VERTEX, - ureg, - &stvp->Base.Base, - /* inputs */ - vpv->num_inputs, - stvp->input_to_index, - NULL, /* input semantic name */ - NULL, /* input semantic index */ - NULL, - /* outputs */ - num_outputs, - stvp->result_to_output, - stvp->output_semantic_name, - stvp->output_semantic_index, - key->passthrough_edgeflags ); - - if (error) - goto fail; - - vpv->tgsi.tokens = ureg_get_tokens( ureg, NULL ); - if (!vpv->tgsi.tokens) - goto fail; - - ureg_destroy( ureg ); - - vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->tgsi); - - if (ST_DEBUG & DEBUG_TGSI) { - tgsi_dump( vpv->tgsi.tokens, 0 ); - debug_printf("\n"); - } - - return vpv; - -fail: - debug_printf("%s: failed to translate Mesa program:\n", __FUNCTION__); - _mesa_print_program(&stvp->Base.Base); - debug_assert(0); - - ureg_destroy( ureg ); - return NULL; -} - - -/** - * Find/create a vertex program variant. - */ -struct st_vp_variant * -st_get_vp_variant(struct st_context *st, - struct st_vertex_program *stvp, - const struct st_vp_variant_key *key) -{ - struct st_vp_variant *vpv; - - /* Search for existing variant */ - for (vpv = stvp->variants; vpv; vpv = vpv->next) { - if (memcmp(&vpv->key, key, sizeof(*key)) == 0) { - break; - } - } - - if (!vpv) { - /* create now */ - vpv = st_translate_vertex_program(st, stvp, key); - if (vpv) { - /* insert into list */ - vpv->next = stvp->variants; - stvp->variants = vpv; - } - } - - return vpv; -} - - -/** - * Translate a Mesa fragment shader into a TGSI shader using extra info in - * the key. - * \return new fragment program variant - */ -static struct st_fp_variant * -st_translate_fragment_program(struct st_context *st, - struct st_fragment_program *stfp, - const struct st_fp_variant_key *key) -{ - struct pipe_context *pipe = st->pipe; - struct st_fp_variant *variant = CALLOC_STRUCT(st_fp_variant); - GLboolean deleteFP = GL_FALSE; - - if (!variant) - return NULL; - - assert(!(key->bitmap && key->drawpixels)); - -#if FEATURE_drawpix - if (key->bitmap) { - /* glBitmap drawing */ - 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; /* we free this temp program below */ - - if (key->drawpixels_z || key->drawpixels_stencil) { - fp = st_make_drawpix_z_stencil_program(st, key->drawpixels_z, - key->drawpixels_stencil); - } - else { - /* 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); - } -#endif - - if (!stfp->tgsi.tokens) { - /* need to translate Mesa instructions to TGSI now */ - GLuint outputMapping[FRAG_RESULT_MAX]; - GLuint inputMapping[FRAG_ATTRIB_MAX]; - GLuint interpMode[PIPE_MAX_SHADER_INPUTS]; /* XXX size? */ - GLuint attr; - enum pipe_error error; - const GLbitfield inputsRead = stfp->Base.Base.InputsRead; - struct ureg_program *ureg; - GLboolean write_all = GL_FALSE; - - ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; - ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS]; - uint fs_num_inputs = 0; - - ubyte fs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; - ubyte fs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; - uint fs_num_outputs = 0; - - - _mesa_remove_output_reads(&stfp->Base.Base, PROGRAM_OUTPUT); - - /* - * Convert Mesa program inputs to TGSI input register semantics. - */ - for (attr = 0; attr < FRAG_ATTRIB_MAX; attr++) { - if (inputsRead & (1 << attr)) { - const GLuint slot = fs_num_inputs++; - - inputMapping[attr] = slot; - - switch (attr) { - case FRAG_ATTRIB_WPOS: - input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - input_semantic_index[slot] = 0; - interpMode[slot] = TGSI_INTERPOLATE_LINEAR; - break; - case FRAG_ATTRIB_COL0: - input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - input_semantic_index[slot] = 0; - interpMode[slot] = TGSI_INTERPOLATE_LINEAR; - break; - case FRAG_ATTRIB_COL1: - input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - input_semantic_index[slot] = 1; - interpMode[slot] = TGSI_INTERPOLATE_LINEAR; - break; - case FRAG_ATTRIB_FOGC: - input_semantic_name[slot] = TGSI_SEMANTIC_FOG; - input_semantic_index[slot] = 0; - interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; - break; - case FRAG_ATTRIB_FACE: - input_semantic_name[slot] = TGSI_SEMANTIC_FACE; - input_semantic_index[slot] = 0; - interpMode[slot] = TGSI_INTERPOLATE_CONSTANT; - break; - /* In most cases, there is nothing special about these - * inputs, so adopt a convention to use the generic - * semantic name and the mesa FRAG_ATTRIB_ number as the - * index. - * - * All that is required is that the vertex shader labels - * its own outputs similarly, and that the vertex shader - * generates at least every output required by the - * fragment shader plus fixed-function hardware (such as - * BFC). - * - * There is no requirement that semantic indexes start at - * zero or be restricted to a particular range -- nobody - * should be building tables based on semantic index. - */ - case FRAG_ATTRIB_PNTC: - case FRAG_ATTRIB_TEX0: - case FRAG_ATTRIB_TEX1: - case FRAG_ATTRIB_TEX2: - case FRAG_ATTRIB_TEX3: - case FRAG_ATTRIB_TEX4: - case FRAG_ATTRIB_TEX5: - case FRAG_ATTRIB_TEX6: - case FRAG_ATTRIB_TEX7: - case FRAG_ATTRIB_VAR0: - default: - /* Actually, let's try and zero-base this just for - * readability of the generated TGSI. - */ - assert(attr >= FRAG_ATTRIB_TEX0); - input_semantic_index[slot] = (attr - FRAG_ATTRIB_TEX0); - input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - if (attr == FRAG_ATTRIB_PNTC) - interpMode[slot] = TGSI_INTERPOLATE_LINEAR; - else - interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; - break; - } - } - else { - inputMapping[attr] = -1; - } - } - - /* - * Semantics and mapping for outputs - */ - { - uint numColors = 0; - GLbitfield64 outputsWritten = stfp->Base.Base.OutputsWritten; - - /* if z is written, emit that first */ - if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) { - fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_POSITION; - fs_output_semantic_index[fs_num_outputs] = 0; - outputMapping[FRAG_RESULT_DEPTH] = fs_num_outputs; - fs_num_outputs++; - outputsWritten &= ~(1 << FRAG_RESULT_DEPTH); - } - - if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_STENCIL)) { - fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_STENCIL; - fs_output_semantic_index[fs_num_outputs] = 0; - outputMapping[FRAG_RESULT_STENCIL] = fs_num_outputs; - fs_num_outputs++; - outputsWritten &= ~(1 << FRAG_RESULT_STENCIL); - } - - /* handle remaning outputs (color) */ - for (attr = 0; attr < FRAG_RESULT_MAX; attr++) { - if (outputsWritten & BITFIELD64_BIT(attr)) { - switch (attr) { - case FRAG_RESULT_DEPTH: - case FRAG_RESULT_STENCIL: - /* handled above */ - assert(0); - break; - case FRAG_RESULT_COLOR: - write_all = GL_TRUE; /* fallthrough */ - default: - assert(attr == FRAG_RESULT_COLOR || - (FRAG_RESULT_DATA0 <= attr && attr < FRAG_RESULT_MAX)); - fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_COLOR; - fs_output_semantic_index[fs_num_outputs] = numColors; - outputMapping[attr] = fs_num_outputs; - numColors++; - break; - } - - fs_num_outputs++; - } - } - } - - ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); - if (ureg == NULL) - return NULL; - - if (ST_DEBUG & DEBUG_MESA) { - _mesa_print_program(&stfp->Base.Base); - _mesa_print_program_parameters(st->ctx, &stfp->Base.Base); - debug_printf("\n"); - } - if (write_all == GL_TRUE) - ureg_property_fs_color0_writes_all_cbufs(ureg, 1); - - error = st_translate_mesa_program(st->ctx, - TGSI_PROCESSOR_FRAGMENT, - ureg, - &stfp->Base.Base, - /* inputs */ - fs_num_inputs, - inputMapping, - input_semantic_name, - input_semantic_index, - interpMode, - /* outputs */ - fs_num_outputs, - outputMapping, - fs_output_semantic_name, - fs_output_semantic_index, FALSE ); - - stfp->tgsi.tokens = ureg_get_tokens( ureg, NULL ); - ureg_destroy( ureg ); - } - - /* fill in variant */ - variant->driver_shader = pipe->create_fs_state(pipe, &stfp->tgsi); - variant->key = *key; - - if (ST_DEBUG & DEBUG_TGSI) { - tgsi_dump( stfp->tgsi.tokens, 0/*TGSI_DUMP_VERBOSE*/ ); - 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; -} - - -/** - * Translate fragment program if needed. - */ -struct st_fp_variant * -st_get_fp_variant(struct st_context *st, - struct st_fragment_program *stfp, - const struct st_fp_variant_key *key) -{ - struct st_fp_variant *fpv; - - /* Search for existing variant */ - for (fpv = stfp->variants; fpv; fpv = fpv->next) { - if (memcmp(&fpv->key, key, sizeof(*key)) == 0) { - break; - } - } - - if (!fpv) { - /* create new */ - fpv = st_translate_fragment_program(st, stfp, key); - if (fpv) { - /* insert into list */ - fpv->next = stfp->variants; - stfp->variants = fpv; - } - } - - return fpv; -} - - -/** - * Translate a geometry program to create a new variant. - */ -static struct st_gp_variant * -st_translate_geometry_program(struct st_context *st, - struct st_geometry_program *stgp, - const struct st_gp_variant_key *key) -{ - GLuint inputMapping[GEOM_ATTRIB_MAX]; - GLuint outputMapping[GEOM_RESULT_MAX]; - struct pipe_context *pipe = st->pipe; - enum pipe_error error; - GLuint attr; - const GLbitfield inputsRead = stgp->Base.Base.InputsRead; - GLuint vslot = 0; - GLuint num_generic = 0; - - uint gs_num_inputs = 0; - uint gs_builtin_inputs = 0; - uint gs_array_offset = 0; - - ubyte gs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; - ubyte gs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; - uint gs_num_outputs = 0; - - GLint i; - GLuint maxSlot = 0; - struct ureg_program *ureg; - - struct st_gp_variant *gpv; - - gpv = CALLOC_STRUCT(st_gp_variant); - if (!gpv) - return NULL; - - _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_OUTPUT); - _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_VARYING); - - ureg = ureg_create( TGSI_PROCESSOR_GEOMETRY ); - if (ureg == NULL) { - FREE(gpv); - return NULL; - } - - /* which vertex output goes to the first geometry input */ - vslot = 0; - - memset(inputMapping, 0, sizeof(inputMapping)); - memset(outputMapping, 0, sizeof(outputMapping)); - - /* - * Convert Mesa program inputs to TGSI input register semantics. - */ - for (attr = 0; attr < GEOM_ATTRIB_MAX; attr++) { - if (inputsRead & (1 << attr)) { - const GLuint slot = gs_num_inputs; - - gs_num_inputs++; - - inputMapping[attr] = slot; - - stgp->input_map[slot + gs_array_offset] = vslot - gs_builtin_inputs; - stgp->input_to_index[attr] = vslot; - stgp->index_to_input[vslot] = attr; - ++vslot; - - if (attr != GEOM_ATTRIB_PRIMITIVE_ID) { - gs_array_offset += 2; - } else - ++gs_builtin_inputs; - -#if 0 - debug_printf("input map at %d = %d\n", - slot + gs_array_offset, stgp->input_map[slot + gs_array_offset]); -#endif - - switch (attr) { - case GEOM_ATTRIB_PRIMITIVE_ID: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_PRIMID; - stgp->input_semantic_index[slot] = 0; - break; - case GEOM_ATTRIB_POSITION: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - stgp->input_semantic_index[slot] = 0; - break; - case GEOM_ATTRIB_COLOR0: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stgp->input_semantic_index[slot] = 0; - break; - case GEOM_ATTRIB_COLOR1: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stgp->input_semantic_index[slot] = 1; - break; - case GEOM_ATTRIB_FOG_FRAG_COORD: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_FOG; - stgp->input_semantic_index[slot] = 0; - break; - case GEOM_ATTRIB_TEX_COORD: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stgp->input_semantic_index[slot] = num_generic++; - break; - case GEOM_ATTRIB_VAR0: - /* fall-through */ - default: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stgp->input_semantic_index[slot] = num_generic++; - } - } - } - - /* initialize output semantics to defaults */ - for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) { - gs_output_semantic_name[i] = TGSI_SEMANTIC_GENERIC; - gs_output_semantic_index[i] = 0; - } - - num_generic = 0; - /* - * Determine number of outputs, the (default) output register - * mapping and the semantic information for each output. - */ - for (attr = 0; attr < GEOM_RESULT_MAX; attr++) { - if (stgp->Base.Base.OutputsWritten & (1 << attr)) { - GLuint slot; - - slot = gs_num_outputs; - gs_num_outputs++; - outputMapping[attr] = slot; - - switch (attr) { - case GEOM_RESULT_POS: - assert(slot == 0); - gs_output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_COL0: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_COL1: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - gs_output_semantic_index[slot] = 1; - break; - case GEOM_RESULT_SCOL0: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_SCOL1: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - gs_output_semantic_index[slot] = 1; - break; - case GEOM_RESULT_FOGC: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_FOG; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_PSIZ: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; - gs_output_semantic_index[slot] = 0; - break; - case GEOM_RESULT_TEX0: - case GEOM_RESULT_TEX1: - case GEOM_RESULT_TEX2: - case GEOM_RESULT_TEX3: - case GEOM_RESULT_TEX4: - case GEOM_RESULT_TEX5: - case GEOM_RESULT_TEX6: - case GEOM_RESULT_TEX7: - /* fall-through */ - case GEOM_RESULT_VAR0: - /* fall-through */ - default: - assert(slot < Elements(gs_output_semantic_name)); - /* use default semantic info */ - gs_output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - gs_output_semantic_index[slot] = num_generic++; - } - } - } - - assert(gs_output_semantic_name[0] == TGSI_SEMANTIC_POSITION); - - /* find max output slot referenced to compute gs_num_outputs */ - for (attr = 0; attr < GEOM_RESULT_MAX; attr++) { - if (outputMapping[attr] != ~0 && outputMapping[attr] > maxSlot) - maxSlot = outputMapping[attr]; - } - gs_num_outputs = maxSlot + 1; - -#if 0 /* debug */ - { - GLuint i; - printf("outputMapping? %d\n", outputMapping ? 1 : 0); - if (outputMapping) { - printf("attr -> slot\n"); - for (i = 0; i < 16; i++) { - printf(" %2d %3d\n", i, outputMapping[i]); - } - } - printf("slot sem_name sem_index\n"); - for (i = 0; i < gs_num_outputs; i++) { - printf(" %2d %d %d\n", - i, - gs_output_semantic_name[i], - gs_output_semantic_index[i]); - } - } -#endif - - /* free old shader state, if any */ - if (stgp->tgsi.tokens) { - st_free_tokens(stgp->tgsi.tokens); - stgp->tgsi.tokens = NULL; - } - - ureg_property_gs_input_prim(ureg, stgp->Base.InputType); - ureg_property_gs_output_prim(ureg, stgp->Base.OutputType); - ureg_property_gs_max_vertices(ureg, stgp->Base.VerticesOut); - - error = st_translate_mesa_program(st->ctx, - TGSI_PROCESSOR_GEOMETRY, - ureg, - &stgp->Base.Base, - /* inputs */ - gs_num_inputs, - inputMapping, - stgp->input_semantic_name, - stgp->input_semantic_index, - NULL, - /* outputs */ - gs_num_outputs, - outputMapping, - gs_output_semantic_name, - gs_output_semantic_index, - FALSE); - - stgp->num_inputs = gs_num_inputs; - stgp->tgsi.tokens = ureg_get_tokens( ureg, NULL ); - ureg_destroy( ureg ); - - /* fill in new variant */ - gpv->driver_shader = pipe->create_gs_state(pipe, &stgp->tgsi); - gpv->key = *key; - - if ((ST_DEBUG & DEBUG_TGSI) && (ST_DEBUG & DEBUG_MESA)) { - _mesa_print_program(&stgp->Base.Base); - debug_printf("\n"); - } - - if (ST_DEBUG & DEBUG_TGSI) { - tgsi_dump(stgp->tgsi.tokens, 0); - debug_printf("\n"); - } - - return gpv; -} - - -/** - * Get/create geometry program variant. - */ -struct st_gp_variant * -st_get_gp_variant(struct st_context *st, - struct st_geometry_program *stgp, - const struct st_gp_variant_key *key) -{ - struct st_gp_variant *gpv; - - /* Search for existing variant */ - for (gpv = stgp->variants; gpv; gpv = gpv->next) { - if (memcmp(&gpv->key, key, sizeof(*key)) == 0) { - break; - } - } - - if (!gpv) { - /* create new */ - gpv = st_translate_geometry_program(st, stgp, key); - if (gpv) { - /* insert into list */ - gpv->next = stgp->variants; - stgp->variants = gpv; - } - } - - return gpv; -} - - - - -/** - * Debug- print current shader text - */ -void -st_print_shaders(struct gl_context *ctx) -{ - struct gl_shader_program *shProg[3] = { - ctx->Shader.CurrentVertexProgram, - ctx->Shader.CurrentGeometryProgram, - ctx->Shader.CurrentFragmentProgram, - }; - unsigned j; - - for (j = 0; j < 3; j++) { - unsigned i; - - if (shProg[j] == NULL) - continue; - - for (i = 0; i < shProg[j]->NumShaders; i++) { - struct gl_shader *sh; - - switch (shProg[j]->Shaders[i]->Type) { - case GL_VERTEX_SHADER: - sh = (i != 0) ? NULL : shProg[j]->Shaders[i]; - break; - case GL_GEOMETRY_SHADER_ARB: - sh = (i != 1) ? NULL : shProg[j]->Shaders[i]; - break; - case GL_FRAGMENT_SHADER: - sh = (i != 2) ? NULL : shProg[j]->Shaders[i]; - break; - default: - assert(0); - sh = NULL; - break; - } - - if (sh != NULL) { - printf("GLSL shader %u of %u:\n", i, shProg[j]->NumShaders); - printf("%s\n", sh->Source); - } - } - } -} - - -/** - * Vert/Geom/Frag programs have per-context variants. Free all the - * variants attached to the given program which match the given context. - */ -static void -destroy_program_variants(struct st_context *st, struct gl_program *program) -{ - if (!program) - return; - - switch (program->Target) { - case GL_VERTEX_PROGRAM_ARB: - { - struct st_vertex_program *stvp = (struct st_vertex_program *) program; - struct st_vp_variant *vpv, **prevPtr = &stvp->variants; - - for (vpv = stvp->variants; vpv; ) { - struct st_vp_variant *next = vpv->next; - if (vpv->key.st == st) { - /* unlink from list */ - *prevPtr = next; - /* destroy this variant */ - delete_vp_variant(st, vpv); - } - else { - prevPtr = &vpv->next; - } - vpv = next; - } - } - break; - case GL_FRAGMENT_PROGRAM_ARB: - { - struct st_fragment_program *stfp = - (struct st_fragment_program *) program; - struct st_fp_variant *fpv, **prevPtr = &stfp->variants; - - for (fpv = stfp->variants; fpv; ) { - struct st_fp_variant *next = fpv->next; - if (fpv->key.st == st) { - /* unlink from list */ - *prevPtr = next; - /* destroy this variant */ - delete_fp_variant(st, fpv); - } - else { - prevPtr = &fpv->next; - } - fpv = next; - } - } - break; - case MESA_GEOMETRY_PROGRAM: - { - struct st_geometry_program *stgp = - (struct st_geometry_program *) program; - struct st_gp_variant *gpv, **prevPtr = &stgp->variants; - - for (gpv = stgp->variants; gpv; ) { - struct st_gp_variant *next = gpv->next; - if (gpv->key.st == st) { - /* unlink from list */ - *prevPtr = next; - /* destroy this variant */ - delete_gp_variant(st, gpv); - } - else { - prevPtr = &gpv->next; - } - gpv = next; - } - } - break; - default: - _mesa_problem(NULL, "Unexpected program target in " - "destroy_program_variants_cb()"); - } -} - - -/** - * Callback for _mesa_HashWalk. Free all the shader's program variants - * which match the given context. - */ -static void -destroy_shader_program_variants_cb(GLuint key, void *data, void *userData) -{ - struct st_context *st = (struct st_context *) userData; - struct gl_shader *shader = (struct gl_shader *) data; - - switch (shader->Type) { - case GL_SHADER_PROGRAM_MESA: - { - struct gl_shader_program *shProg = (struct gl_shader_program *) data; - GLuint i; - - for (i = 0; i < shProg->NumShaders; i++) { - destroy_program_variants(st, shProg->Shaders[i]->Program); - } - - destroy_program_variants(st, (struct gl_program *) - shProg->VertexProgram); - destroy_program_variants(st, (struct gl_program *) - shProg->FragmentProgram); - destroy_program_variants(st, (struct gl_program *) - shProg->GeometryProgram); - } - break; - case GL_VERTEX_SHADER: - case GL_FRAGMENT_SHADER: - case GL_GEOMETRY_SHADER: - { - destroy_program_variants(st, shader->Program); - } - break; - default: - assert(0); - } -} - - -/** - * Callback for _mesa_HashWalk. Free all the program variants which match - * the given context. - */ -static void -destroy_program_variants_cb(GLuint key, void *data, void *userData) -{ - struct st_context *st = (struct st_context *) userData; - struct gl_program *program = (struct gl_program *) data; - destroy_program_variants(st, program); -} - - -/** - * Walk over all shaders and programs to delete any variants which - * belong to the given context. - * This is called during context tear-down. - */ -void -st_destroy_program_variants(struct st_context *st) -{ - /* ARB vert/frag program */ - _mesa_HashWalk(st->ctx->Shared->Programs, - destroy_program_variants_cb, st); - - /* GLSL vert/frag/geom shaders */ - _mesa_HashWalk(st->ctx->Shared->ShaderObjects, - destroy_shader_program_variants_cb, st); -} +/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+ /*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ * Brian Paul
+ */
+
+
+#include "main/imports.h"
+#include "main/hash.h"
+#include "main/mfeatures.h"
+#include "main/mtypes.h"
+#include "program/prog_parameter.h"
+#include "program/prog_print.h"
+#include "program/programopt.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_shader_tokens.h"
+#include "draw/draw_context.h"
+#include "tgsi/tgsi_dump.h"
+#include "tgsi/tgsi_ureg.h"
+
+#include "st_debug.h"
+#include "st_cb_bitmap.h"
+#include "st_cb_drawpixels.h"
+#include "st_context.h"
+#include "st_program.h"
+#include "st_mesa_to_tgsi.h"
+#include "cso_cache/cso_context.h"
+
+
+
+/**
+ * Delete a vertex program variant. Note the caller must unlink
+ * the variant from the linked list.
+ */
+static void
+delete_vp_variant(struct st_context *st, struct st_vp_variant *vpv)
+{
+ if (vpv->driver_shader)
+ cso_delete_vertex_shader(st->cso_context, vpv->driver_shader);
+
+#if FEATURE_feedback || FEATURE_rastpos
+ if (vpv->draw_shader)
+ draw_delete_vertex_shader( st->draw, vpv->draw_shader );
+#endif
+
+ if (vpv->tgsi.tokens)
+ st_free_tokens(vpv->tgsi.tokens);
+
+ FREE( vpv );
+}
+
+
+
+/**
+ * Clean out any old compilations:
+ */
+void
+st_release_vp_variants( struct st_context *st,
+ struct st_vertex_program *stvp )
+{
+ struct st_vp_variant *vpv;
+
+ for (vpv = stvp->variants; vpv; ) {
+ struct st_vp_variant *next = vpv->next;
+ delete_vp_variant(st, vpv);
+ vpv = next;
+ }
+
+ stvp->variants = NULL;
+}
+
+
+
+/**
+ * Delete a fragment program variant. Note the caller must unlink
+ * the variant from the linked list.
+ */
+static void
+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);
+}
+
+
+/**
+ * Free all variants of a fragment program.
+ */
+void
+st_release_fp_variants(struct st_context *st, struct st_fragment_program *stfp)
+{
+ struct st_fp_variant *fpv;
+
+ for (fpv = stfp->variants; fpv; ) {
+ struct st_fp_variant *next = fpv->next;
+ delete_fp_variant(st, fpv);
+ fpv = next;
+ }
+
+ stfp->variants = NULL;
+}
+
+
+/**
+ * Delete a geometry program variant. Note the caller must unlink
+ * the variant from the linked list.
+ */
+static void
+delete_gp_variant(struct st_context *st, struct st_gp_variant *gpv)
+{
+ if (gpv->driver_shader)
+ cso_delete_geometry_shader(st->cso_context, gpv->driver_shader);
+
+ FREE(gpv);
+}
+
+
+/**
+ * Free all variants of a geometry program.
+ */
+void
+st_release_gp_variants(struct st_context *st, struct st_geometry_program *stgp)
+{
+ struct st_gp_variant *gpv;
+
+ for (gpv = stgp->variants; gpv; ) {
+ struct st_gp_variant *next = gpv->next;
+ delete_gp_variant(st, gpv);
+ gpv = next;
+ }
+
+ stgp->variants = NULL;
+}
+
+
+
+
+/**
+ * Translate a Mesa vertex shader into a TGSI shader.
+ * \param outputMapping to map vertex program output registers (VERT_RESULT_x)
+ * to TGSI output slots
+ * \param tokensOut destination for TGSI tokens
+ * \return pointer to cached pipe_shader object.
+ */
+static void
+st_prepare_vertex_program(struct st_context *st,
+ struct st_vertex_program *stvp)
+{
+ GLuint attr;
+
+ stvp->num_inputs = 0;
+ stvp->num_outputs = 0;
+
+ if (stvp->Base.IsPositionInvariant)
+ _mesa_insert_mvp_code(st->ctx, &stvp->Base);
+
+ assert(stvp->Base.Base.NumInstructions > 1);
+
+ /*
+ * Determine number of inputs, the mappings between VERT_ATTRIB_x
+ * and TGSI generic input indexes, plus input attrib semantic info.
+ */
+ for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
+ if (stvp->Base.Base.InputsRead & (1 << attr)) {
+ stvp->input_to_index[attr] = stvp->num_inputs;
+ stvp->index_to_input[stvp->num_inputs] = attr;
+ stvp->num_inputs++;
+ }
+ }
+ /* bit of a hack, presetup potentially unused edgeflag input */
+ stvp->input_to_index[VERT_ATTRIB_EDGEFLAG] = stvp->num_inputs;
+ stvp->index_to_input[stvp->num_inputs] = VERT_ATTRIB_EDGEFLAG;
+
+ /* Compute mapping of vertex program outputs to slots.
+ */
+ for (attr = 0; attr < VERT_RESULT_MAX; attr++) {
+ if ((stvp->Base.Base.OutputsWritten & BITFIELD64_BIT(attr)) == 0) {
+ stvp->result_to_output[attr] = ~0;
+ }
+ else {
+ unsigned slot = stvp->num_outputs++;
+
+ stvp->result_to_output[attr] = slot;
+
+ switch (attr) {
+ case VERT_RESULT_HPOS:
+ stvp->output_semantic_name[slot] = TGSI_SEMANTIC_POSITION;
+ stvp->output_semantic_index[slot] = 0;
+ break;
+ case VERT_RESULT_COL0:
+ stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
+ stvp->output_semantic_index[slot] = 0;
+ break;
+ case VERT_RESULT_COL1:
+ stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
+ stvp->output_semantic_index[slot] = 1;
+ break;
+ case VERT_RESULT_BFC0:
+ stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR;
+ stvp->output_semantic_index[slot] = 0;
+ break;
+ case VERT_RESULT_BFC1:
+ stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR;
+ stvp->output_semantic_index[slot] = 1;
+ break;
+ case VERT_RESULT_FOGC:
+ stvp->output_semantic_name[slot] = TGSI_SEMANTIC_FOG;
+ stvp->output_semantic_index[slot] = 0;
+ break;
+ case VERT_RESULT_PSIZ:
+ stvp->output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE;
+ stvp->output_semantic_index[slot] = 0;
+ break;
+ case VERT_RESULT_EDGE:
+ assert(0);
+ break;
+
+ case VERT_RESULT_TEX0:
+ case VERT_RESULT_TEX1:
+ case VERT_RESULT_TEX2:
+ case VERT_RESULT_TEX3:
+ case VERT_RESULT_TEX4:
+ case VERT_RESULT_TEX5:
+ case VERT_RESULT_TEX6:
+ case VERT_RESULT_TEX7:
+ stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
+ stvp->output_semantic_index[slot] = attr - VERT_RESULT_TEX0;
+ break;
+
+ case VERT_RESULT_VAR0:
+ default:
+ assert(attr < VERT_RESULT_MAX);
+ stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
+ stvp->output_semantic_index[slot] = (FRAG_ATTRIB_VAR0 -
+ FRAG_ATTRIB_TEX0 +
+ attr -
+ VERT_RESULT_VAR0);
+ break;
+ }
+ }
+ }
+ /* similar hack to above, presetup potentially unused edgeflag output */
+ stvp->result_to_output[VERT_RESULT_EDGE] = stvp->num_outputs;
+ stvp->output_semantic_name[stvp->num_outputs] = TGSI_SEMANTIC_EDGEFLAG;
+ stvp->output_semantic_index[stvp->num_outputs] = 0;
+}
+
+
+/**
+ * Translate a vertex program to create a new variant.
+ */
+static struct st_vp_variant *
+st_translate_vertex_program(struct st_context *st,
+ struct st_vertex_program *stvp,
+ const struct st_vp_variant_key *key)
+{
+ struct st_vp_variant *vpv = CALLOC_STRUCT(st_vp_variant);
+ struct pipe_context *pipe = st->pipe;
+ struct ureg_program *ureg;
+ enum pipe_error error;
+ unsigned num_outputs;
+
+ st_prepare_vertex_program( st, stvp );
+
+ _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_OUTPUT);
+ _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_VARYING);
+
+ ureg = ureg_create( TGSI_PROCESSOR_VERTEX );
+ if (ureg == NULL) {
+ FREE(vpv);
+ return NULL;
+ }
+
+ vpv->key = *key;
+
+ vpv->num_inputs = stvp->num_inputs;
+ num_outputs = stvp->num_outputs;
+ if (key->passthrough_edgeflags) {
+ vpv->num_inputs++;
+ num_outputs++;
+ }
+
+ if (ST_DEBUG & DEBUG_MESA) {
+ _mesa_print_program(&stvp->Base.Base);
+ _mesa_print_program_parameters(st->ctx, &stvp->Base.Base);
+ debug_printf("\n");
+ }
+
+ error = st_translate_mesa_program(st->ctx,
+ TGSI_PROCESSOR_VERTEX,
+ ureg,
+ &stvp->Base.Base,
+ /* inputs */
+ vpv->num_inputs,
+ stvp->input_to_index,
+ NULL, /* input semantic name */
+ NULL, /* input semantic index */
+ NULL,
+ /* outputs */
+ num_outputs,
+ stvp->result_to_output,
+ stvp->output_semantic_name,
+ stvp->output_semantic_index,
+ key->passthrough_edgeflags );
+
+ if (error)
+ goto fail;
+
+ vpv->tgsi.tokens = ureg_get_tokens( ureg, NULL );
+ if (!vpv->tgsi.tokens)
+ goto fail;
+
+ ureg_destroy( ureg );
+
+ vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->tgsi);
+
+ if (ST_DEBUG & DEBUG_TGSI) {
+ tgsi_dump( vpv->tgsi.tokens, 0 );
+ debug_printf("\n");
+ }
+
+ return vpv;
+
+fail:
+ debug_printf("%s: failed to translate Mesa program:\n", __FUNCTION__);
+ _mesa_print_program(&stvp->Base.Base);
+ debug_assert(0);
+
+ ureg_destroy( ureg );
+ return NULL;
+}
+
+
+/**
+ * Find/create a vertex program variant.
+ */
+struct st_vp_variant *
+st_get_vp_variant(struct st_context *st,
+ struct st_vertex_program *stvp,
+ const struct st_vp_variant_key *key)
+{
+ struct st_vp_variant *vpv;
+
+ /* Search for existing variant */
+ for (vpv = stvp->variants; vpv; vpv = vpv->next) {
+ if (memcmp(&vpv->key, key, sizeof(*key)) == 0) {
+ break;
+ }
+ }
+
+ if (!vpv) {
+ /* create now */
+ vpv = st_translate_vertex_program(st, stvp, key);
+ if (vpv) {
+ /* insert into list */
+ vpv->next = stvp->variants;
+ stvp->variants = vpv;
+ }
+ }
+
+ return vpv;
+}
+
+
+/**
+ * Translate a Mesa fragment shader into a TGSI shader using extra info in
+ * the key.
+ * \return new fragment program variant
+ */
+static struct st_fp_variant *
+st_translate_fragment_program(struct st_context *st,
+ struct st_fragment_program *stfp,
+ const struct st_fp_variant_key *key)
+{
+ struct pipe_context *pipe = st->pipe;
+ struct st_fp_variant *variant = CALLOC_STRUCT(st_fp_variant);
+ GLboolean deleteFP = GL_FALSE;
+
+ if (!variant)
+ return NULL;
+
+ assert(!(key->bitmap && key->drawpixels));
+
+#if FEATURE_drawpix
+ if (key->bitmap) {
+ /* glBitmap drawing */
+ 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; /* we free this temp program below */
+
+ if (key->drawpixels_z || key->drawpixels_stencil) {
+ fp = st_make_drawpix_z_stencil_program(st, key->drawpixels_z,
+ key->drawpixels_stencil);
+ }
+ else {
+ /* 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);
+ }
+#endif
+
+ if (!stfp->tgsi.tokens) {
+ /* need to translate Mesa instructions to TGSI now */
+ GLuint outputMapping[FRAG_RESULT_MAX];
+ GLuint inputMapping[FRAG_ATTRIB_MAX];
+ GLuint interpMode[PIPE_MAX_SHADER_INPUTS]; /* XXX size? */
+ GLuint attr;
+ enum pipe_error error;
+ const GLbitfield inputsRead = stfp->Base.Base.InputsRead;
+ struct ureg_program *ureg;
+ GLboolean write_all = GL_FALSE;
+
+ ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS];
+ ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS];
+ uint fs_num_inputs = 0;
+
+ ubyte fs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS];
+ ubyte fs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS];
+ uint fs_num_outputs = 0;
+
+
+ _mesa_remove_output_reads(&stfp->Base.Base, PROGRAM_OUTPUT);
+
+ /*
+ * Convert Mesa program inputs to TGSI input register semantics.
+ */
+ for (attr = 0; attr < FRAG_ATTRIB_MAX; attr++) {
+ if (inputsRead & (1 << attr)) {
+ const GLuint slot = fs_num_inputs++;
+
+ inputMapping[attr] = slot;
+
+ switch (attr) {
+ case FRAG_ATTRIB_WPOS:
+ input_semantic_name[slot] = TGSI_SEMANTIC_POSITION;
+ input_semantic_index[slot] = 0;
+ interpMode[slot] = TGSI_INTERPOLATE_LINEAR;
+ break;
+ case FRAG_ATTRIB_COL0:
+ input_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
+ input_semantic_index[slot] = 0;
+ interpMode[slot] = TGSI_INTERPOLATE_LINEAR;
+ break;
+ case FRAG_ATTRIB_COL1:
+ input_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
+ input_semantic_index[slot] = 1;
+ interpMode[slot] = TGSI_INTERPOLATE_LINEAR;
+ break;
+ case FRAG_ATTRIB_FOGC:
+ input_semantic_name[slot] = TGSI_SEMANTIC_FOG;
+ input_semantic_index[slot] = 0;
+ interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE;
+ break;
+ case FRAG_ATTRIB_FACE:
+ input_semantic_name[slot] = TGSI_SEMANTIC_FACE;
+ input_semantic_index[slot] = 0;
+ interpMode[slot] = TGSI_INTERPOLATE_CONSTANT;
+ break;
+ /* In most cases, there is nothing special about these
+ * inputs, so adopt a convention to use the generic
+ * semantic name and the mesa FRAG_ATTRIB_ number as the
+ * index.
+ *
+ * All that is required is that the vertex shader labels
+ * its own outputs similarly, and that the vertex shader
+ * generates at least every output required by the
+ * fragment shader plus fixed-function hardware (such as
+ * BFC).
+ *
+ * There is no requirement that semantic indexes start at
+ * zero or be restricted to a particular range -- nobody
+ * should be building tables based on semantic index.
+ */
+ case FRAG_ATTRIB_PNTC:
+ case FRAG_ATTRIB_TEX0:
+ case FRAG_ATTRIB_TEX1:
+ case FRAG_ATTRIB_TEX2:
+ case FRAG_ATTRIB_TEX3:
+ case FRAG_ATTRIB_TEX4:
+ case FRAG_ATTRIB_TEX5:
+ case FRAG_ATTRIB_TEX6:
+ case FRAG_ATTRIB_TEX7:
+ case FRAG_ATTRIB_VAR0:
+ default:
+ /* Actually, let's try and zero-base this just for
+ * readability of the generated TGSI.
+ */
+ assert(attr >= FRAG_ATTRIB_TEX0);
+ input_semantic_index[slot] = (attr - FRAG_ATTRIB_TEX0);
+ input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
+ if (attr == FRAG_ATTRIB_PNTC)
+ interpMode[slot] = TGSI_INTERPOLATE_LINEAR;
+ else
+ interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE;
+ break;
+ }
+ }
+ else {
+ inputMapping[attr] = -1;
+ }
+ }
+
+ /*
+ * Semantics and mapping for outputs
+ */
+ {
+ uint numColors = 0;
+ GLbitfield64 outputsWritten = stfp->Base.Base.OutputsWritten;
+
+ /* if z is written, emit that first */
+ if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) {
+ fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_POSITION;
+ fs_output_semantic_index[fs_num_outputs] = 0;
+ outputMapping[FRAG_RESULT_DEPTH] = fs_num_outputs;
+ fs_num_outputs++;
+ outputsWritten &= ~(1 << FRAG_RESULT_DEPTH);
+ }
+
+ if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_STENCIL)) {
+ fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_STENCIL;
+ fs_output_semantic_index[fs_num_outputs] = 0;
+ outputMapping[FRAG_RESULT_STENCIL] = fs_num_outputs;
+ fs_num_outputs++;
+ outputsWritten &= ~(1 << FRAG_RESULT_STENCIL);
+ }
+
+ /* handle remaning outputs (color) */
+ for (attr = 0; attr < FRAG_RESULT_MAX; attr++) {
+ if (outputsWritten & BITFIELD64_BIT(attr)) {
+ switch (attr) {
+ case FRAG_RESULT_DEPTH:
+ case FRAG_RESULT_STENCIL:
+ /* handled above */
+ assert(0);
+ break;
+ case FRAG_RESULT_COLOR:
+ write_all = GL_TRUE; /* fallthrough */
+ default:
+ assert(attr == FRAG_RESULT_COLOR ||
+ (FRAG_RESULT_DATA0 <= attr && attr < FRAG_RESULT_MAX));
+ fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_COLOR;
+ fs_output_semantic_index[fs_num_outputs] = numColors;
+ outputMapping[attr] = fs_num_outputs;
+ numColors++;
+ break;
+ }
+
+ fs_num_outputs++;
+ }
+ }
+ }
+
+ ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
+ if (ureg == NULL)
+ return NULL;
+
+ if (ST_DEBUG & DEBUG_MESA) {
+ _mesa_print_program(&stfp->Base.Base);
+ _mesa_print_program_parameters(st->ctx, &stfp->Base.Base);
+ debug_printf("\n");
+ }
+ if (write_all == GL_TRUE)
+ ureg_property_fs_color0_writes_all_cbufs(ureg, 1);
+
+ error = st_translate_mesa_program(st->ctx,
+ TGSI_PROCESSOR_FRAGMENT,
+ ureg,
+ &stfp->Base.Base,
+ /* inputs */
+ fs_num_inputs,
+ inputMapping,
+ input_semantic_name,
+ input_semantic_index,
+ interpMode,
+ /* outputs */
+ fs_num_outputs,
+ outputMapping,
+ fs_output_semantic_name,
+ fs_output_semantic_index, FALSE );
+
+ stfp->tgsi.tokens = ureg_get_tokens( ureg, NULL );
+ ureg_destroy( ureg );
+ }
+
+ /* fill in variant */
+ variant->driver_shader = pipe->create_fs_state(pipe, &stfp->tgsi);
+ variant->key = *key;
+
+ if (ST_DEBUG & DEBUG_TGSI) {
+ tgsi_dump( stfp->tgsi.tokens, 0/*TGSI_DUMP_VERBOSE*/ );
+ 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;
+}
+
+
+/**
+ * Translate fragment program if needed.
+ */
+struct st_fp_variant *
+st_get_fp_variant(struct st_context *st,
+ struct st_fragment_program *stfp,
+ const struct st_fp_variant_key *key)
+{
+ struct st_fp_variant *fpv;
+
+ /* Search for existing variant */
+ for (fpv = stfp->variants; fpv; fpv = fpv->next) {
+ if (memcmp(&fpv->key, key, sizeof(*key)) == 0) {
+ break;
+ }
+ }
+
+ if (!fpv) {
+ /* create new */
+ fpv = st_translate_fragment_program(st, stfp, key);
+ if (fpv) {
+ /* insert into list */
+ fpv->next = stfp->variants;
+ stfp->variants = fpv;
+ }
+ }
+
+ return fpv;
+}
+
+
+/**
+ * Translate a geometry program to create a new variant.
+ */
+static struct st_gp_variant *
+st_translate_geometry_program(struct st_context *st,
+ struct st_geometry_program *stgp,
+ const struct st_gp_variant_key *key)
+{
+ GLuint inputMapping[GEOM_ATTRIB_MAX];
+ GLuint outputMapping[GEOM_RESULT_MAX];
+ struct pipe_context *pipe = st->pipe;
+ enum pipe_error error;
+ GLuint attr;
+ const GLbitfield inputsRead = stgp->Base.Base.InputsRead;
+ GLuint vslot = 0;
+ GLuint num_generic = 0;
+
+ uint gs_num_inputs = 0;
+ uint gs_builtin_inputs = 0;
+ uint gs_array_offset = 0;
+
+ ubyte gs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS];
+ ubyte gs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS];
+ uint gs_num_outputs = 0;
+
+ GLint i;
+ GLuint maxSlot = 0;
+ struct ureg_program *ureg;
+
+ struct st_gp_variant *gpv;
+
+ gpv = CALLOC_STRUCT(st_gp_variant);
+ if (!gpv)
+ return NULL;
+
+ _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_OUTPUT);
+ _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_VARYING);
+
+ ureg = ureg_create( TGSI_PROCESSOR_GEOMETRY );
+ if (ureg == NULL) {
+ FREE(gpv);
+ return NULL;
+ }
+
+ /* which vertex output goes to the first geometry input */
+ vslot = 0;
+
+ memset(inputMapping, 0, sizeof(inputMapping));
+ memset(outputMapping, 0, sizeof(outputMapping));
+
+ /*
+ * Convert Mesa program inputs to TGSI input register semantics.
+ */
+ for (attr = 0; attr < GEOM_ATTRIB_MAX; attr++) {
+ if (inputsRead & (1 << attr)) {
+ const GLuint slot = gs_num_inputs;
+
+ gs_num_inputs++;
+
+ inputMapping[attr] = slot;
+
+ stgp->input_map[slot + gs_array_offset] = vslot - gs_builtin_inputs;
+ stgp->input_to_index[attr] = vslot;
+ stgp->index_to_input[vslot] = attr;
+ ++vslot;
+
+ if (attr != GEOM_ATTRIB_PRIMITIVE_ID) {
+ gs_array_offset += 2;
+ } else
+ ++gs_builtin_inputs;
+
+#if 0
+ debug_printf("input map at %d = %d\n",
+ slot + gs_array_offset, stgp->input_map[slot + gs_array_offset]);
+#endif
+
+ switch (attr) {
+ case GEOM_ATTRIB_PRIMITIVE_ID:
+ stgp->input_semantic_name[slot] = TGSI_SEMANTIC_PRIMID;
+ stgp->input_semantic_index[slot] = 0;
+ break;
+ case GEOM_ATTRIB_POSITION:
+ stgp->input_semantic_name[slot] = TGSI_SEMANTIC_POSITION;
+ stgp->input_semantic_index[slot] = 0;
+ break;
+ case GEOM_ATTRIB_COLOR0:
+ stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
+ stgp->input_semantic_index[slot] = 0;
+ break;
+ case GEOM_ATTRIB_COLOR1:
+ stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
+ stgp->input_semantic_index[slot] = 1;
+ break;
+ case GEOM_ATTRIB_FOG_FRAG_COORD:
+ stgp->input_semantic_name[slot] = TGSI_SEMANTIC_FOG;
+ stgp->input_semantic_index[slot] = 0;
+ break;
+ case GEOM_ATTRIB_TEX_COORD:
+ stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
+ stgp->input_semantic_index[slot] = num_generic++;
+ break;
+ case GEOM_ATTRIB_VAR0:
+ /* fall-through */
+ default:
+ stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
+ stgp->input_semantic_index[slot] = num_generic++;
+ }
+ }
+ }
+
+ /* initialize output semantics to defaults */
+ for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) {
+ gs_output_semantic_name[i] = TGSI_SEMANTIC_GENERIC;
+ gs_output_semantic_index[i] = 0;
+ }
+
+ num_generic = 0;
+ /*
+ * Determine number of outputs, the (default) output register
+ * mapping and the semantic information for each output.
+ */
+ for (attr = 0; attr < GEOM_RESULT_MAX; attr++) {
+ if (stgp->Base.Base.OutputsWritten & (1 << attr)) {
+ GLuint slot;
+
+ slot = gs_num_outputs;
+ gs_num_outputs++;
+ outputMapping[attr] = slot;
+
+ switch (attr) {
+ case GEOM_RESULT_POS:
+ assert(slot == 0);
+ gs_output_semantic_name[slot] = TGSI_SEMANTIC_POSITION;
+ gs_output_semantic_index[slot] = 0;
+ break;
+ case GEOM_RESULT_COL0:
+ gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
+ gs_output_semantic_index[slot] = 0;
+ break;
+ case GEOM_RESULT_COL1:
+ gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
+ gs_output_semantic_index[slot] = 1;
+ break;
+ case GEOM_RESULT_SCOL0:
+ gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR;
+ gs_output_semantic_index[slot] = 0;
+ break;
+ case GEOM_RESULT_SCOL1:
+ gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR;
+ gs_output_semantic_index[slot] = 1;
+ break;
+ case GEOM_RESULT_FOGC:
+ gs_output_semantic_name[slot] = TGSI_SEMANTIC_FOG;
+ gs_output_semantic_index[slot] = 0;
+ break;
+ case GEOM_RESULT_PSIZ:
+ gs_output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE;
+ gs_output_semantic_index[slot] = 0;
+ break;
+ case GEOM_RESULT_TEX0:
+ case GEOM_RESULT_TEX1:
+ case GEOM_RESULT_TEX2:
+ case GEOM_RESULT_TEX3:
+ case GEOM_RESULT_TEX4:
+ case GEOM_RESULT_TEX5:
+ case GEOM_RESULT_TEX6:
+ case GEOM_RESULT_TEX7:
+ /* fall-through */
+ case GEOM_RESULT_VAR0:
+ /* fall-through */
+ default:
+ assert(slot < Elements(gs_output_semantic_name));
+ /* use default semantic info */
+ gs_output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
+ gs_output_semantic_index[slot] = num_generic++;
+ }
+ }
+ }
+
+ assert(gs_output_semantic_name[0] == TGSI_SEMANTIC_POSITION);
+
+ /* find max output slot referenced to compute gs_num_outputs */
+ for (attr = 0; attr < GEOM_RESULT_MAX; attr++) {
+ if (outputMapping[attr] != ~0 && outputMapping[attr] > maxSlot)
+ maxSlot = outputMapping[attr];
+ }
+ gs_num_outputs = maxSlot + 1;
+
+#if 0 /* debug */
+ {
+ GLuint i;
+ printf("outputMapping? %d\n", outputMapping ? 1 : 0);
+ if (outputMapping) {
+ printf("attr -> slot\n");
+ for (i = 0; i < 16; i++) {
+ printf(" %2d %3d\n", i, outputMapping[i]);
+ }
+ }
+ printf("slot sem_name sem_index\n");
+ for (i = 0; i < gs_num_outputs; i++) {
+ printf(" %2d %d %d\n",
+ i,
+ gs_output_semantic_name[i],
+ gs_output_semantic_index[i]);
+ }
+ }
+#endif
+
+ /* free old shader state, if any */
+ if (stgp->tgsi.tokens) {
+ st_free_tokens(stgp->tgsi.tokens);
+ stgp->tgsi.tokens = NULL;
+ }
+
+ ureg_property_gs_input_prim(ureg, stgp->Base.InputType);
+ ureg_property_gs_output_prim(ureg, stgp->Base.OutputType);
+ ureg_property_gs_max_vertices(ureg, stgp->Base.VerticesOut);
+
+ error = st_translate_mesa_program(st->ctx,
+ TGSI_PROCESSOR_GEOMETRY,
+ ureg,
+ &stgp->Base.Base,
+ /* inputs */
+ gs_num_inputs,
+ inputMapping,
+ stgp->input_semantic_name,
+ stgp->input_semantic_index,
+ NULL,
+ /* outputs */
+ gs_num_outputs,
+ outputMapping,
+ gs_output_semantic_name,
+ gs_output_semantic_index,
+ FALSE);
+
+ stgp->num_inputs = gs_num_inputs;
+ stgp->tgsi.tokens = ureg_get_tokens( ureg, NULL );
+ ureg_destroy( ureg );
+
+ /* fill in new variant */
+ gpv->driver_shader = pipe->create_gs_state(pipe, &stgp->tgsi);
+ gpv->key = *key;
+
+ if ((ST_DEBUG & DEBUG_TGSI) && (ST_DEBUG & DEBUG_MESA)) {
+ _mesa_print_program(&stgp->Base.Base);
+ debug_printf("\n");
+ }
+
+ if (ST_DEBUG & DEBUG_TGSI) {
+ tgsi_dump(stgp->tgsi.tokens, 0);
+ debug_printf("\n");
+ }
+
+ return gpv;
+}
+
+
+/**
+ * Get/create geometry program variant.
+ */
+struct st_gp_variant *
+st_get_gp_variant(struct st_context *st,
+ struct st_geometry_program *stgp,
+ const struct st_gp_variant_key *key)
+{
+ struct st_gp_variant *gpv;
+
+ /* Search for existing variant */
+ for (gpv = stgp->variants; gpv; gpv = gpv->next) {
+ if (memcmp(&gpv->key, key, sizeof(*key)) == 0) {
+ break;
+ }
+ }
+
+ if (!gpv) {
+ /* create new */
+ gpv = st_translate_geometry_program(st, stgp, key);
+ if (gpv) {
+ /* insert into list */
+ gpv->next = stgp->variants;
+ stgp->variants = gpv;
+ }
+ }
+
+ return gpv;
+}
+
+
+
+
+/**
+ * Debug- print current shader text
+ */
+void
+st_print_shaders(struct gl_context *ctx)
+{
+ struct gl_shader_program *shProg[3] = {
+ ctx->Shader.CurrentVertexProgram,
+ ctx->Shader.CurrentGeometryProgram,
+ ctx->Shader.CurrentFragmentProgram,
+ };
+ unsigned j;
+
+ for (j = 0; j < 3; j++) {
+ unsigned i;
+
+ if (shProg[j] == NULL)
+ continue;
+
+ for (i = 0; i < shProg[j]->NumShaders; i++) {
+ struct gl_shader *sh;
+
+ switch (shProg[j]->Shaders[i]->Type) {
+ case GL_VERTEX_SHADER:
+ sh = (i != 0) ? NULL : shProg[j]->Shaders[i];
+ break;
+ case GL_GEOMETRY_SHADER_ARB:
+ sh = (i != 1) ? NULL : shProg[j]->Shaders[i];
+ break;
+ case GL_FRAGMENT_SHADER:
+ sh = (i != 2) ? NULL : shProg[j]->Shaders[i];
+ break;
+ default:
+ assert(0);
+ sh = NULL;
+ break;
+ }
+
+ if (sh != NULL) {
+ printf("GLSL shader %u of %u:\n", i, shProg[j]->NumShaders);
+ printf("%s\n", sh->Source);
+ }
+ }
+ }
+}
+
+
+/**
+ * Vert/Geom/Frag programs have per-context variants. Free all the
+ * variants attached to the given program which match the given context.
+ */
+static void
+destroy_program_variants(struct st_context *st, struct gl_program *program)
+{
+ if (!program)
+ return;
+
+ switch (program->Target) {
+ case GL_VERTEX_PROGRAM_ARB:
+ {
+ struct st_vertex_program *stvp = (struct st_vertex_program *) program;
+ struct st_vp_variant *vpv, **prevPtr = &stvp->variants;
+
+ for (vpv = stvp->variants; vpv; ) {
+ struct st_vp_variant *next = vpv->next;
+ if (vpv->key.st == st) {
+ /* unlink from list */
+ *prevPtr = next;
+ /* destroy this variant */
+ delete_vp_variant(st, vpv);
+ }
+ else {
+ prevPtr = &vpv->next;
+ }
+ vpv = next;
+ }
+ }
+ break;
+ case GL_FRAGMENT_PROGRAM_ARB:
+ {
+ struct st_fragment_program *stfp =
+ (struct st_fragment_program *) program;
+ struct st_fp_variant *fpv, **prevPtr = &stfp->variants;
+
+ for (fpv = stfp->variants; fpv; ) {
+ struct st_fp_variant *next = fpv->next;
+ if (fpv->key.st == st) {
+ /* unlink from list */
+ *prevPtr = next;
+ /* destroy this variant */
+ delete_fp_variant(st, fpv);
+ }
+ else {
+ prevPtr = &fpv->next;
+ }
+ fpv = next;
+ }
+ }
+ break;
+ case MESA_GEOMETRY_PROGRAM:
+ {
+ struct st_geometry_program *stgp =
+ (struct st_geometry_program *) program;
+ struct st_gp_variant *gpv, **prevPtr = &stgp->variants;
+
+ for (gpv = stgp->variants; gpv; ) {
+ struct st_gp_variant *next = gpv->next;
+ if (gpv->key.st == st) {
+ /* unlink from list */
+ *prevPtr = next;
+ /* destroy this variant */
+ delete_gp_variant(st, gpv);
+ }
+ else {
+ prevPtr = &gpv->next;
+ }
+ gpv = next;
+ }
+ }
+ break;
+ default:
+ _mesa_problem(NULL, "Unexpected program target in "
+ "destroy_program_variants_cb()");
+ }
+}
+
+
+/**
+ * Callback for _mesa_HashWalk. Free all the shader's program variants
+ * which match the given context.
+ */
+static void
+destroy_shader_program_variants_cb(GLuint key, void *data, void *userData)
+{
+ struct st_context *st = (struct st_context *) userData;
+ struct gl_shader *shader = (struct gl_shader *) data;
+
+ switch (shader->Type) {
+ case GL_SHADER_PROGRAM_MESA:
+ {
+ struct gl_shader_program *shProg = (struct gl_shader_program *) data;
+ GLuint i;
+
+ for (i = 0; i < shProg->NumShaders; i++) {
+ destroy_program_variants(st, shProg->Shaders[i]->Program);
+ }
+
+ destroy_program_variants(st, (struct gl_program *)
+ shProg->VertexProgram);
+ destroy_program_variants(st, (struct gl_program *)
+ shProg->FragmentProgram);
+ destroy_program_variants(st, (struct gl_program *)
+ shProg->GeometryProgram);
+ }
+ break;
+ case GL_VERTEX_SHADER:
+ case GL_FRAGMENT_SHADER:
+ case GL_GEOMETRY_SHADER:
+ {
+ destroy_program_variants(st, shader->Program);
+ }
+ break;
+ default:
+ assert(0);
+ }
+}
+
+
+/**
+ * Callback for _mesa_HashWalk. Free all the program variants which match
+ * the given context.
+ */
+static void
+destroy_program_variants_cb(GLuint key, void *data, void *userData)
+{
+ struct st_context *st = (struct st_context *) userData;
+ struct gl_program *program = (struct gl_program *) data;
+ destroy_program_variants(st, program);
+}
+
+
+/**
+ * Walk over all shaders and programs to delete any variants which
+ * belong to the given context.
+ * This is called during context tear-down.
+ */
+void
+st_destroy_program_variants(struct st_context *st)
+{
+ /* ARB vert/frag program */
+ _mesa_HashWalk(st->ctx->Shared->Programs,
+ destroy_program_variants_cb, st);
+
+ /* GLSL vert/frag/geom shaders */
+ _mesa_HashWalk(st->ctx->Shared->ShaderObjects,
+ destroy_shader_program_variants_cb, st);
+}
|