aboutsummaryrefslogtreecommitdiff
path: root/mesalib
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2011-11-09 17:05:56 +0100
committermarha <marha@users.sourceforge.net>2011-11-09 17:05:56 +0100
commit72d7f8d5af476f12dc75eab4fa9d59364cbec190 (patch)
tree1efac13a52811bfd28ae51538b15f87cbfaf8939 /mesalib
parenta3d796bcc7de83fd88b42e09c6a82a8df4f9b836 (diff)
parenta8e5f06fe01732fbd643bc435dd3b8eaa602defe (diff)
downloadvcxsrv-72d7f8d5af476f12dc75eab4fa9d59364cbec190.tar.gz
vcxsrv-72d7f8d5af476f12dc75eab4fa9d59364cbec190.tar.bz2
vcxsrv-72d7f8d5af476f12dc75eab4fa9d59364cbec190.zip
Merge remote-tracking branch 'origin/released'
Conflicts: mesalib/src/mapi/glapi/glapi.h
Diffstat (limited to 'mesalib')
-rw-r--r--mesalib/scons/gallium.py1
-rw-r--r--mesalib/src/gallium/auxiliary/util/u_math.h11
-rw-r--r--mesalib/src/glsl/ast.h83
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp310
-rw-r--r--mesalib/src/glsl/glsl_parser.yy87
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.cpp103
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.h10
-rw-r--r--mesalib/src/glsl/glsl_types.h19
-rw-r--r--mesalib/src/glsl/ir_uniform.h128
-rw-r--r--mesalib/src/glsl/link_uniforms.cpp249
-rw-r--r--mesalib/src/glsl/linker.cpp180
-rw-r--r--mesalib/src/glsl/linker.h7
-rw-r--r--mesalib/src/glu/sgi/libnurbs/internals/bin.cc2
-rw-r--r--mesalib/src/glu/sgi/libnurbs/internals/bin.h2
-rw-r--r--mesalib/src/mapi/glapi/glapi.h6
-rw-r--r--mesalib/src/mapi/glapi/glthread.h8
-rw-r--r--mesalib/src/mapi/mapi/u_thread.h22
-rw-r--r--mesalib/src/mesa/SConscript6
-rw-r--r--mesalib/src/mesa/main/clear.c84
-rw-r--r--mesalib/src/mesa/main/context.h9
-rw-r--r--mesalib/src/mesa/main/core.h119
-rw-r--r--mesalib/src/mesa/main/formats.h11
-rw-r--r--mesalib/src/mesa/main/glheader.h10
-rw-r--r--mesalib/src/mesa/main/mtypes.h44
-rw-r--r--mesalib/src/mesa/main/renderbuffer.c40
-rw-r--r--mesalib/src/mesa/main/shader_query.cpp93
-rw-r--r--mesalib/src/mesa/main/shaderapi.c61
-rw-r--r--mesalib/src/mesa/main/shaderapi.h11
-rw-r--r--mesalib/src/mesa/main/shaderobj.c19
-rw-r--r--mesalib/src/mesa/main/simple_list.h8
-rw-r--r--mesalib/src/mesa/main/texobj.c13
-rw-r--r--mesalib/src/mesa/main/uniform_query.cpp885
-rw-r--r--mesalib/src/mesa/main/uniforms.c1014
-rw-r--r--mesalib/src/mesa/main/uniforms.h86
-rw-r--r--mesalib/src/mesa/main/version.c5
-rw-r--r--mesalib/src/mesa/math/m_matrix.h9
-rw-r--r--mesalib/src/mesa/program/hash_table.h17
-rw-r--r--mesalib/src/mesa/program/ir_to_mesa.cpp115
-rw-r--r--mesalib/src/mesa/program/ir_to_mesa.h20
-rw-r--r--mesalib/src/mesa/program/prog_parameter.h9
-rw-r--r--mesalib/src/mesa/program/prog_statevars.h11
-rw-r--r--mesalib/src/mesa/program/prog_uniform.c103
-rw-r--r--mesalib/src/mesa/program/prog_uniform.h85
-rw-r--r--mesalib/src/mesa/program/sampler.cpp12
-rw-r--r--mesalib/src/mesa/sources.mak1
-rw-r--r--mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c12
-rw-r--r--mesalib/src/mesa/state_tracker/st_cb_clear.c5
-rw-r--r--mesalib/src/mesa/state_tracker/st_cb_drawpixels.c10
-rw-r--r--mesalib/src/mesa/state_tracker/st_cb_fbo.c59
-rw-r--r--mesalib/src/mesa/state_tracker/st_cb_fbo.h2
-rw-r--r--mesalib/src/mesa/state_tracker/st_draw.c65
-rw-r--r--mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp14
-rw-r--r--mesalib/src/mesa/state_tracker/st_program.c14
-rw-r--r--mesalib/src/mesa/swrast/s_context.c4
54 files changed, 2713 insertions, 1600 deletions
diff --git a/mesalib/scons/gallium.py b/mesalib/scons/gallium.py
index 18be73f76..9651925a4 100644
--- a/mesalib/scons/gallium.py
+++ b/mesalib/scons/gallium.py
@@ -453,6 +453,7 @@ def generate(env):
'/fp:fast', # fast floating point
'/W3', # warning level
#'/Wp64', # enable 64 bit porting warnings
+ '/wd4996', # disable deprecated POSIX name warnings
]
if env['machine'] == 'x86':
ccflags += [
diff --git a/mesalib/src/gallium/auxiliary/util/u_math.h b/mesalib/src/gallium/auxiliary/util/u_math.h
index b9295f4f8..551463f75 100644
--- a/mesalib/src/gallium/auxiliary/util/u_math.h
+++ b/mesalib/src/gallium/auxiliary/util/u_math.h
@@ -207,6 +207,17 @@ double log2(double d)
return log(d) * (1.0 / M_LN2);
}
+/* workaround a conflict with main/imports.h */
+#ifdef log2f
+#undef log2f
+#endif
+
+static INLINE
+float log2f(float f)
+{
+ return logf(f) * (float) (1.0 / M_LN2);
+}
+
#endif
diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h
index eb40a75b0..79054be86 100644
--- a/mesalib/src/glsl/ast.h
+++ b/mesalib/src/glsl/ast.h
@@ -633,13 +633,78 @@ public:
class ast_case_label : public ast_node {
public:
+ ast_case_label(ast_expression *test_value);
+ virtual void print(void) const;
+
+ virtual ir_rvalue *hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state);
/**
- * An expression of NULL means 'default'.
+ * An test value of NULL means 'default'.
*/
- ast_expression *expression;
+ ast_expression *test_value;
+};
+
+
+class ast_case_label_list : public ast_node {
+public:
+ ast_case_label_list(void);
+ virtual void print(void) const;
+
+ virtual ir_rvalue *hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state);
+
+ /**
+ * A list of case labels.
+ */
+ exec_list labels;
};
+
+class ast_case_statement : public ast_node {
+public:
+ ast_case_statement(ast_case_label_list *labels);
+ virtual void print(void) const;
+
+ virtual ir_rvalue *hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state);
+
+ ast_case_label_list *labels;
+
+ /**
+ * A list of statements.
+ */
+ exec_list stmts;
+};
+
+
+class ast_case_statement_list : public ast_node {
+public:
+ ast_case_statement_list(void);
+ virtual void print(void) const;
+
+ virtual ir_rvalue *hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state);
+
+ /**
+ * A list of cases.
+ */
+ exec_list cases;
+};
+
+
+class ast_switch_body : public ast_node {
+public:
+ ast_switch_body(ast_case_statement_list *stmts);
+ virtual void print(void) const;
+
+ virtual ir_rvalue *hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state);
+
+ ast_case_statement_list *stmts;
+};
+
+
class ast_selection_statement : public ast_node {
public:
ast_selection_statement(ast_expression *condition,
@@ -658,8 +723,18 @@ public:
class ast_switch_statement : public ast_node {
public:
- ast_expression *expression;
- exec_list statements;
+ ast_switch_statement(ast_expression *test_expression,
+ ast_node *body);
+ virtual void print(void) const;
+
+ virtual ir_rvalue *hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state);
+
+ ast_expression *test_expression;
+ ast_node *body;
+
+protected:
+ void test_to_hir(exec_list *, struct _mesa_glsl_parse_state *);
};
class ast_iteration_statement : public ast_node {
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp
index ed6abdc70..ac090c315 100644
--- a/mesalib/src/glsl/ast_to_hir.cpp
+++ b/mesalib/src/glsl/ast_to_hir.cpp
@@ -3355,34 +3355,49 @@ ast_jump_statement::hir(exec_list *instructions,
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) {
+ if (mode == ast_continue &&
+ state->loop_nesting_ast == 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();
+ "continue may only appear in a loop");
+ } else if (mode == ast_break &&
+ state->loop_nesting_ast == NULL &&
+ state->switch_nesting_ast == NULL) {
+ YYLTYPE loc = this->get_location();
- /* Inline the for loop expression again, since we don't know
- * where near the end of the loop body the normal copy of it
+ _mesa_glsl_error(& loc, state,
+ "break may only appear in a loop or a switch");
+ } else {
+ /* For a 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 (state->loop_nesting_ast != NULL &&
+ mode == ast_continue &&
+ state->loop_nesting_ast->rest_expression) {
+ state->loop_nesting_ast->rest_expression->hir(instructions,
+ state);
}
- if (loop != NULL) {
- ir_loop_jump *const jump =
+ if (state->is_switch_innermost &&
+ mode == ast_break) {
+ /* Force break out of switch by setting is_break switch state.
+ */
+ ir_variable *const is_break_var = state->is_break_var;
+ ir_dereference_variable *const deref_is_break_var =
+ new(ctx) ir_dereference_variable(is_break_var);
+ ir_constant *const true_val = new(ctx) ir_constant(true);
+ ir_assignment *const set_break_var =
+ new(ctx) ir_assignment(deref_is_break_var,
+ true_val,
+ NULL);
+
+ instructions->push_tail(set_break_var);
+ }
+ else {
+ ir_loop_jump *const jump =
new(ctx) ir_loop_jump((mode == ast_break)
? ir_loop_jump::jump_break
: ir_loop_jump::jump_continue);
@@ -3445,6 +3460,243 @@ ast_selection_statement::hir(exec_list *instructions,
}
+ir_rvalue *
+ast_switch_statement::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ ir_rvalue *const test_expression =
+ this->test_expression->hir(instructions, state);
+
+ /* From page 66 (page 55 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "The type of init-expression in a switch statement must be a
+ * scalar integer."
+ *
+ * The checks are separated so that higher quality diagnostics can be
+ * generated for cases where the rule is violated.
+ */
+ if (!test_expression->type->is_integer()) {
+ YYLTYPE loc = this->test_expression->get_location();
+
+ _mesa_glsl_error(& loc,
+ state,
+ "switch-statement expression must be scalar "
+ "integer");
+ }
+
+ /* Track the switch-statement nesting in a stack-like manner.
+ */
+ ir_variable *saved_test_var = state->test_var;
+ ir_variable *saved_is_fallthru_var = state->is_fallthru_var;
+
+ bool save_is_switch_innermost = state->is_switch_innermost;
+ ast_switch_statement *saved_nesting_ast = state->switch_nesting_ast;
+
+ state->is_switch_innermost = true;
+ state->switch_nesting_ast = this;
+
+ /* Initalize is_fallthru state to false.
+ */
+ ir_rvalue *const is_fallthru_val = new (ctx) ir_constant(false);
+ state->is_fallthru_var = new(ctx) ir_variable(glsl_type::bool_type,
+ "switch_is_fallthru_tmp",
+ ir_var_temporary);
+ instructions->push_tail(state->is_fallthru_var);
+
+ ir_dereference_variable *deref_is_fallthru_var =
+ new(ctx) ir_dereference_variable(state->is_fallthru_var);
+ instructions->push_tail(new(ctx) ir_assignment(deref_is_fallthru_var,
+ is_fallthru_val,
+ NULL));
+
+ /* Initalize is_break state to false.
+ */
+ ir_rvalue *const is_break_val = new (ctx) ir_constant(false);
+ state->is_break_var = new(ctx) ir_variable(glsl_type::bool_type,
+ "switch_is_break_tmp",
+ ir_var_temporary);
+ instructions->push_tail(state->is_break_var);
+
+ ir_dereference_variable *deref_is_break_var =
+ new(ctx) ir_dereference_variable(state->is_break_var);
+ instructions->push_tail(new(ctx) ir_assignment(deref_is_break_var,
+ is_break_val,
+ NULL));
+
+ /* Cache test expression.
+ */
+ test_to_hir(instructions, state);
+
+ /* Emit code for body of switch stmt.
+ */
+ body->hir(instructions, state);
+
+ /* Restore previous nesting before returning.
+ */
+ state->switch_nesting_ast = saved_nesting_ast;
+ state->is_switch_innermost = save_is_switch_innermost;
+
+ state->test_var = saved_test_var;
+ state->is_fallthru_var = saved_is_fallthru_var;
+
+ /* Switch statements do not have r-values.
+ */
+ return NULL;
+}
+
+
+void
+ast_switch_statement::test_to_hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ /* Cache value of test expression.
+ */
+ ir_rvalue *const test_val =
+ test_expression->hir(instructions,
+ state);
+
+ state->test_var = new(ctx) ir_variable(glsl_type::int_type,
+ "switch_test_tmp",
+ ir_var_temporary);
+ ir_dereference_variable *deref_test_var =
+ new(ctx) ir_dereference_variable(state->test_var);
+
+ instructions->push_tail(state->test_var);
+ instructions->push_tail(new(ctx) ir_assignment(deref_test_var,
+ test_val,
+ NULL));
+}
+
+
+ir_rvalue *
+ast_switch_body::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ if (stmts != NULL)
+ stmts->hir(instructions, state);
+
+ /* Switch bodies do not have r-values.
+ */
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_case_statement_list::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ foreach_list_typed (ast_case_statement, case_stmt, link, & this->cases)
+ case_stmt->hir(instructions, state);
+
+ /* Case statements do not have r-values.
+ */
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_case_statement::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ labels->hir(instructions, state);
+
+ /* Conditionally set fallthru state based on break state.
+ */
+ ir_constant *const false_val = new(state) ir_constant(false);
+ ir_dereference_variable *const deref_is_fallthru_var =
+ new(state) ir_dereference_variable(state->is_fallthru_var);
+ ir_dereference_variable *const deref_is_break_var =
+ new(state) ir_dereference_variable(state->is_break_var);
+ ir_assignment *const reset_fallthru_on_break =
+ new(state) ir_assignment(deref_is_fallthru_var,
+ false_val,
+ deref_is_break_var);
+ instructions->push_tail(reset_fallthru_on_break);
+
+ /* Guard case statements depending on fallthru state.
+ */
+ ir_dereference_variable *const deref_fallthru_guard =
+ new(state) ir_dereference_variable(state->is_fallthru_var);
+ ir_if *const test_fallthru = new(state) ir_if(deref_fallthru_guard);
+
+ foreach_list_typed (ast_node, stmt, link, & this->stmts)
+ stmt->hir(& test_fallthru->then_instructions, state);
+
+ instructions->push_tail(test_fallthru);
+
+ /* Case statements do not have r-values.
+ */
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_case_label_list::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ foreach_list_typed (ast_case_label, label, link, & this->labels)
+ label->hir(instructions, state);
+
+ /* Case labels do not have r-values.
+ */
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_case_label::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ ir_dereference_variable *deref_fallthru_var =
+ new(ctx) ir_dereference_variable(state->is_fallthru_var);
+
+ ir_rvalue *const true_val = new(ctx) ir_constant(true);
+
+ /* If not default case, ...
+ */
+ if (this->test_value != NULL) {
+ /* Conditionally set fallthru state based on
+ * comparison of cached test expression value to case label.
+ */
+ ir_rvalue *const test_val = this->test_value->hir(instructions, state);
+
+ ir_dereference_variable *deref_test_var =
+ new(ctx) ir_dereference_variable(state->test_var);
+
+ ir_rvalue *const test_cond = new(ctx) ir_expression(ir_binop_all_equal,
+ glsl_type::bool_type,
+ test_val,
+ deref_test_var);
+
+ ir_assignment *set_fallthru_on_test =
+ new(ctx) ir_assignment(deref_fallthru_var,
+ true_val,
+ test_cond);
+
+ instructions->push_tail(set_fallthru_on_test);
+ } else { /* default case */
+ /* Set falltrhu state.
+ */
+ ir_assignment *set_fallthru =
+ new(ctx) ir_assignment(deref_fallthru_var,
+ true_val,
+ NULL);
+
+ instructions->push_tail(set_fallthru);
+ }
+
+ /* Case statements do not have r-values.
+ */
+ return NULL;
+}
+
+
void
ast_iteration_statement::condition_to_hir(ir_loop *stmt,
struct _mesa_glsl_parse_state *state)
@@ -3498,13 +3750,17 @@ ast_iteration_statement::hir(exec_list *instructions,
ir_loop *const stmt = new(ctx) ir_loop();
instructions->push_tail(stmt);
- /* Track the current loop and / or switch-statement nesting.
+ /* Track the current loop nesting.
*/
- ir_instruction *const nesting = state->loop_or_switch_nesting;
- ast_iteration_statement *nesting_ast = state->loop_or_switch_nesting_ast;
+ ast_iteration_statement *nesting_ast = state->loop_nesting_ast;
+
+ state->loop_nesting_ast = this;
- state->loop_or_switch_nesting = stmt;
- state->loop_or_switch_nesting_ast = this;
+ /* Likewise, indicate that following code is closest to a loop,
+ * NOT closest to a switch.
+ */
+ bool saved_is_switch_innermost = state->is_switch_innermost;
+ state->is_switch_innermost = false;
if (mode != ast_do_while)
condition_to_hir(stmt, state);
@@ -3523,8 +3779,8 @@ ast_iteration_statement::hir(exec_list *instructions,
/* Restore previous nesting before returning.
*/
- state->loop_or_switch_nesting = nesting;
- state->loop_or_switch_nesting_ast = nesting_ast;
+ state->loop_nesting_ast = nesting_ast;
+ state->is_switch_innermost = saved_is_switch_innermost;
/* Loops do not have r-values.
*/
diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy
index d32d6e4e1..f3e873800 100644
--- a/mesalib/src/glsl/glsl_parser.yy
+++ b/mesalib/src/glsl/glsl_parser.yy
@@ -67,6 +67,11 @@
ast_declarator_list *declarator_list;
ast_struct_specifier *struct_specifier;
ast_declaration *declaration;
+ ast_switch_body *switch_body;
+ ast_case_label *case_label;
+ ast_case_label_list *case_label_list;
+ ast_case_statement *case_statement;
+ ast_case_statement_list *case_statement_list;
struct {
ast_node *cond;
@@ -207,6 +212,12 @@
%type <declaration> struct_declarator_list
%type <node> selection_statement
%type <selection_rest_statement> selection_rest_statement
+%type <node> switch_statement
+%type <switch_body> switch_body
+%type <case_label_list> case_label_list
+%type <case_label> case_label
+%type <case_statement> case_statement
+%type <case_statement_list> case_statement_list
%type <node> iteration_statement
%type <node> condition
%type <node> conditionopt
@@ -1517,8 +1528,7 @@ simple_statement:
declaration_statement
| expression_statement
| selection_statement
- | switch_statement { $$ = NULL; }
- | case_label { $$ = NULL; }
+ | switch_statement
| iteration_statement
| jump_statement
;
@@ -1640,13 +1650,84 @@ condition:
}
;
+/*
+ * siwtch_statement grammar is based on the syntax described in the body
+ * of the GLSL spec, not in it's appendix!!!
+ */
switch_statement:
- SWITCH '(' expression ')' compound_statement
+ SWITCH '(' expression ')' switch_body
+ {
+ $$ = new(state) ast_switch_statement($3, $5);
+ }
+ ;
+
+switch_body:
+ '{' '}'
+ {
+ $$ = new(state) ast_switch_body(NULL);
+ $$->set_location(yylloc);
+ }
+ | '{' case_statement_list '}'
+ {
+ $$ = new(state) ast_switch_body($2);
+ $$->set_location(yylloc);
+ }
;
case_label:
CASE expression ':'
+ {
+ $$ = new(state) ast_case_label($2);
+ }
| DEFAULT ':'
+ {
+ $$ = new(state) ast_case_label(NULL);
+ }
+ ;
+
+case_label_list:
+ case_label
+ {
+ ast_case_label_list *labels = new(state) ast_case_label_list();
+
+ labels->labels.push_tail(& $1->link);
+ $$ = labels;
+ }
+ | case_label_list case_label
+ {
+ $$ = $1;
+ $$->labels.push_tail(& $2->link);
+ }
+ ;
+
+case_statement:
+ case_label_list statement
+ {
+ ast_case_statement *stmts = new(state) ast_case_statement($1);
+
+ stmts->stmts.push_tail(& $2->link);
+ $$ = stmts
+ }
+ | case_statement statement
+ {
+ $$ = $1;
+ $$->stmts.push_tail(& $2->link);
+ }
+ ;
+
+case_statement_list:
+ case_statement
+ {
+ ast_case_statement_list *cases= new(state) ast_case_statement_list();
+
+ cases->cases.push_tail(& $1->link);
+ $$ = cases;
+ }
+ | case_statement_list case_statement
+ {
+ $$ = $1;
+ $$->cases.push_tail(& $2->link);
+ }
;
iteration_statement:
diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp
index e627dabf7..23aadb143 100644
--- a/mesalib/src/glsl/glsl_parser_extras.cpp
+++ b/mesalib/src/glsl/glsl_parser_extras.cpp
@@ -50,7 +50,8 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *ctx,
this->symbols = new(mem_ctx) glsl_symbol_table;
this->info_log = ralloc_strdup(mem_ctx, "");
this->error = false;
- this->loop_or_switch_nesting = NULL;
+ this->loop_nesting_ast = NULL;
+ this->switch_nesting_ast = NULL;
this->num_builtins_to_link = 0;
@@ -806,6 +807,106 @@ ast_selection_statement::ast_selection_statement(ast_expression *condition,
void
+ast_switch_statement::print(void) const
+{
+ printf("switch ( ");
+ test_expression->print();
+ printf(") ");
+
+ body->print();
+}
+
+
+ast_switch_statement::ast_switch_statement(ast_expression *test_expression,
+ ast_node *body)
+{
+ this->test_expression = test_expression;
+ this->body = body;
+}
+
+
+void
+ast_switch_body::print(void) const
+{
+ printf("{\n");
+ if (stmts != NULL) {
+ stmts->print();
+ }
+ printf("}\n");
+}
+
+
+ast_switch_body::ast_switch_body(ast_case_statement_list *stmts)
+{
+ this->stmts = stmts;
+}
+
+
+void ast_case_label::print(void) const
+{
+ if (test_value != NULL) {
+ printf("case ");
+ test_value->print();
+ printf(": ");
+ } else {
+ printf("default: ");
+ }
+}
+
+
+ast_case_label::ast_case_label(ast_expression *test_value)
+{
+ this->test_value = test_value;
+}
+
+
+void ast_case_label_list::print(void) const
+{
+ foreach_list_const(n, & this->labels) {
+ ast_node *ast = exec_node_data(ast_node, n, link);
+ ast->print();
+ }
+ printf("\n");
+}
+
+
+ast_case_label_list::ast_case_label_list(void)
+{
+}
+
+
+void ast_case_statement::print(void) const
+{
+ labels->print();
+ foreach_list_const(n, & this->stmts) {
+ ast_node *ast = exec_node_data(ast_node, n, link);
+ ast->print();
+ printf("\n");
+ }
+}
+
+
+ast_case_statement::ast_case_statement(ast_case_label_list *labels)
+{
+ this->labels = labels;
+}
+
+
+void ast_case_statement_list::print(void) const
+{
+ foreach_list_const(n, & this->cases) {
+ ast_node *ast = exec_node_data(ast_node, n, link);
+ ast->print();
+ }
+}
+
+
+ast_case_statement_list::ast_case_statement_list(void)
+{
+}
+
+
+void
ast_iteration_statement::print(void) const
{
switch (mode) {
diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h
index 7c7ed7f75..ee714637d 100644
--- a/mesalib/src/glsl/glsl_parser_extras.h
+++ b/mesalib/src/glsl/glsl_parser_extras.h
@@ -153,8 +153,14 @@ struct _mesa_glsl_parse_state {
bool all_invariant;
/** Loop or switch statement containing the current instructions. */
- class ir_instruction *loop_or_switch_nesting;
- class ast_iteration_statement *loop_or_switch_nesting_ast;
+ class ast_iteration_statement *loop_nesting_ast;
+ class ast_switch_statement *switch_nesting_ast;
+ bool is_switch_innermost; // if switch stmt is closest to break, ...
+
+ /** Temporary variables needed for switch statement. */
+ ir_variable *test_var;
+ ir_variable *is_fallthru_var;
+ ir_variable *is_break_var;
/** List of structures defined in user code. */
const glsl_type **user_structures;
diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h
index 56b8efe7b..4ac90118b 100644
--- a/mesalib/src/glsl/glsl_types.h
+++ b/mesalib/src/glsl/glsl_types.h
@@ -29,21 +29,23 @@
#include <string.h>
#include <assert.h>
+#ifdef __cplusplus
extern "C" {
-#include "GL/gl.h"
-}
-
-#include "ralloc.h"
+#endif
struct _mesa_glsl_parse_state;
struct glsl_symbol_table;
-extern "C" void
+extern void
_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state);
-extern "C" void
+extern void
_mesa_glsl_release_types(void);
+#ifdef __cplusplus
+}
+#endif
+
enum glsl_base_type {
GLSL_TYPE_UINT = 0,
GLSL_TYPE_INT,
@@ -66,6 +68,9 @@ enum glsl_sampler_dim {
GLSL_SAMPLER_DIM_EXTERNAL
};
+#ifdef __cplusplus
+#include "GL/gl.h"
+#include "ralloc.h"
struct glsl_type {
GLenum gl_type;
@@ -530,4 +535,6 @@ struct glsl_struct_field {
const char *name;
};
+#endif /* __cplusplus */
+
#endif /* GLSL_TYPES_H */
diff --git a/mesalib/src/glsl/ir_uniform.h b/mesalib/src/glsl/ir_uniform.h
new file mode 100644
index 000000000..225da3fc5
--- /dev/null
+++ b/mesalib/src/glsl/ir_uniform.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright © 2011 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.
+ */
+
+#pragma once
+#ifndef IR_UNIFORM_H
+#define IR_UNIFORM_H
+
+
+/* stdbool.h is necessary because this file is included in both C and C++ code.
+ */
+#include <stdbool.h>
+
+#include "program/prog_parameter.h" /* For union gl_constant_value. */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum gl_uniform_driver_format {
+ uniform_native = 0, /**< Store data in the native format. */
+ uniform_int_float, /**< Store integer data as floats. */
+ uniform_bool_float, /**< Store boolean data as floats. */
+
+ /**
+ * Store boolean data as integer using 1 for \c true.
+ */
+ uniform_bool_int_0_1,
+
+ /**
+ * Store boolean data as integer using ~0 for \c true.
+ */
+ uniform_bool_int_0_not0
+};
+
+struct gl_uniform_driver_storage {
+ /**
+ * Number of bytes from one array element to the next.
+ */
+ uint8_t element_stride;
+
+ /**
+ * Number of bytes from one vector in a matrix to the next.
+ */
+ uint8_t vector_stride;
+
+ /**
+ * Base format of the stored data.
+ *
+ * This field must have a value from \c GLSL_TYPE_UINT through \c
+ * GLSL_TYPE_SAMPLER.
+ */
+ uint8_t format;
+
+ /**
+ * Pointer to the base of the data.
+ */
+ void *data;
+};
+
+struct gl_uniform_storage {
+ char *name;
+ const struct glsl_type *type;
+
+ /**
+ * The number of elements in this uniform.
+ *
+ * For non-arrays, this is always 0. For arrays, the value is the size of
+ * the array.
+ */
+ unsigned array_elements;
+
+ /**
+ * Has this uniform ever been set?
+ */
+ bool initialized;
+
+ /**
+ * Base sampler index
+ *
+ * If \c ::base_type is \c GLSL_TYPE_SAMPLER, this represents the index of
+ * this sampler. If \c ::array_elements is not zero, the array will use
+ * sampler indexes \c ::sampler through \c ::sampler + \c ::array_elements
+ * - 1, inclusive.
+ */
+ uint8_t sampler;
+
+ /**
+ * Storage used by the driver for the uniform
+ */
+ unsigned num_driver_storage;
+ struct gl_uniform_driver_storage *driver_storage;
+
+ /**
+ * Storage used by Mesa for the uniform
+ *
+ * This form of the uniform is used by Mesa's implementation of \c
+ * glGetUniform. It can also be used by drivers to obtain the value of the
+ * uniform if the \c ::driver_storage interface is not used.
+ */
+ union gl_constant_value *storage;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IR_UNIFORM_H */
diff --git a/mesalib/src/glsl/link_uniforms.cpp b/mesalib/src/glsl/link_uniforms.cpp
index 6dd1f5354..b9d5361b0 100644
--- a/mesalib/src/glsl/link_uniforms.cpp
+++ b/mesalib/src/glsl/link_uniforms.cpp
@@ -24,6 +24,7 @@
#include "main/core.h"
#include "ir.h"
#include "linker.h"
+#include "ir_uniform.h"
#include "glsl_symbol_table.h"
#include "program/hash_table.h"
@@ -34,6 +35,21 @@
* \author Ian Romanick <ian.d.romanick@intel.com>
*/
+/**
+ * Count the backing storage requirements for a type
+ */
+static unsigned
+values_for_type(const glsl_type *type)
+{
+ if (type->is_sampler()) {
+ return 1;
+ } else if (type->is_array() && type->fields.array->is_sampler()) {
+ return type->array_size();
+ } else {
+ return type->component_slots();
+ }
+}
+
void
uniform_field_visitor::process(ir_variable *var)
{
@@ -83,3 +99,236 @@ uniform_field_visitor::recursion(const glsl_type *t, char **name,
this->visit_field(t, *name);
}
}
+
+/**
+ * Class to help calculate the storage requirements for a set of uniforms
+ *
+ * As uniforms are added to the active set the number of active uniforms and
+ * the storage requirements for those uniforms are accumulated. The active
+ * uniforms are added the the hash table supplied to the constructor.
+ *
+ * If the same uniform is added multiple times (i.e., once for each shader
+ * target), it will only be accounted once.
+ */
+class count_uniform_size : public uniform_field_visitor {
+public:
+ count_uniform_size(struct string_to_uint_map *map)
+ : num_active_uniforms(0), num_values(0), map(map)
+ {
+ /* empty */
+ }
+
+ /**
+ * Total number of active uniforms counted
+ */
+ unsigned num_active_uniforms;
+
+ /**
+ * Number of data values required to back the storage for the active uniforms
+ */
+ unsigned num_values;
+
+private:
+ virtual void visit_field(const glsl_type *type, const char *name)
+ {
+ assert(!type->is_record());
+ assert(!(type->is_array() && type->fields.array->is_record()));
+
+ /* If the uniform is already in the map, there's nothing more to do.
+ */
+ unsigned id;
+ if (this->map->get(id, name))
+ return;
+
+ char *key = strdup(name);
+ this->map->put(this->num_active_uniforms, key);
+
+ /* Each leaf uniform occupies one entry in the list of active
+ * uniforms.
+ */
+ this->num_active_uniforms++;
+ this->num_values += values_for_type(type);
+ }
+
+ struct string_to_uint_map *map;
+};
+
+/**
+ * Class to help parcel out pieces of backing storage to uniforms
+ *
+ * Each uniform processed has some range of the \c gl_constant_value
+ * structures associated with it. The association is done by finding
+ * the uniform in the \c string_to_uint_map and using the value from
+ * the map to connect that slot in the \c gl_uniform_storage table
+ * with the next available slot in the \c gl_constant_value array.
+ *
+ * \warning
+ * This class assumes that every uniform that will be processed is
+ * already in the \c string_to_uint_map. In addition, it assumes that
+ * the \c gl_uniform_storage and \c gl_constant_value arrays are "big
+ * enough."
+ */
+class parcel_out_uniform_storage : public uniform_field_visitor {
+public:
+ parcel_out_uniform_storage(struct string_to_uint_map *map,
+ struct gl_uniform_storage *uniforms,
+ union gl_constant_value *values)
+ : map(map), uniforms(uniforms), next_sampler(0), values(values)
+ {
+ /* empty */
+ }
+
+private:
+ virtual void visit_field(const glsl_type *type, const char *name)
+ {
+ assert(!type->is_record());
+ assert(!(type->is_array() && type->fields.array->is_record()));
+
+ unsigned id;
+ bool found = this->map->get(id, name);
+ assert(found);
+
+ if (!found)
+ return;
+
+ /* If there is already storage associated with this uniform, it means
+ * that it was set while processing an earlier shader stage. For
+ * example, we may be processing the uniform in the fragment shader, but
+ * the uniform was already processed in the vertex shader.
+ */
+ if (this->uniforms[id].storage != NULL)
+ return;
+
+ const glsl_type *base_type;
+ if (type->is_array()) {
+ this->uniforms[id].array_elements = type->length;
+ base_type = type->fields.array;
+ } else {
+ this->uniforms[id].array_elements = 0;
+ base_type = type;
+ }
+
+ if (base_type->is_sampler()) {
+ this->uniforms[id].sampler = this->next_sampler;
+
+ /* Increment the sampler by 1 for non-arrays and by the number of
+ * array elements for arrays.
+ */
+ this->next_sampler += MAX2(1, this->uniforms[id].array_elements);
+ } else {
+ this->uniforms[id].sampler = ~0;
+ }
+
+ this->uniforms[id].name = strdup(name);
+ this->uniforms[id].type = base_type;
+ this->uniforms[id].initialized = 0;
+ this->uniforms[id].num_driver_storage = 0;
+ this->uniforms[id].driver_storage = NULL;
+ this->uniforms[id].storage = this->values;
+
+ this->values += values_for_type(type);
+ }
+
+ struct string_to_uint_map *map;
+
+ struct gl_uniform_storage *uniforms;
+ unsigned next_sampler;
+
+public:
+ union gl_constant_value *values;
+};
+
+void
+link_assign_uniform_locations(struct gl_shader_program *prog)
+{
+ ralloc_free(prog->UniformStorage);
+ prog->UniformStorage = NULL;
+ prog->NumUserUniformStorage = 0;
+
+ if (prog->UniformHash != NULL) {
+ prog->UniformHash->clear();
+ } else {
+ prog->UniformHash = new string_to_uint_map;
+ }
+
+ for (unsigned i = 0; i < Elements(prog->SamplerUnits); i++) {
+ prog->SamplerUnits[i] = i;
+ }
+
+ /* First pass: Count the uniform resources used by the user-defined
+ * uniforms. While this happens, each active uniform will have an index
+ * assigned to it.
+ *
+ * Note: this is *NOT* the index that is returned to the application by
+ * glGetUniformLocation.
+ */
+ count_uniform_size uniform_size(prog->UniformHash);
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ if (prog->_LinkedShaders[i] == NULL)
+ continue;
+
+ foreach_list(node, prog->_LinkedShaders[i]->ir) {
+ ir_variable *const var = ((ir_instruction *) node)->as_variable();
+
+ if ((var == NULL) || (var->mode != ir_var_uniform))
+ continue;
+
+ /* FINISHME: Update code to process built-in uniforms!
+ */
+ if (strncmp("gl_", var->name, 3) == 0)
+ continue;
+
+ uniform_size.process(var);
+ }
+ }
+
+ const unsigned num_user_uniforms = uniform_size.num_active_uniforms;
+ const unsigned num_data_slots = uniform_size.num_values;
+
+ /* On the outside chance that there were no uniforms, bail out.
+ */
+ if (num_user_uniforms == 0)
+ return;
+
+ struct gl_uniform_storage *uniforms =
+ rzalloc_array(prog, struct gl_uniform_storage, num_user_uniforms);
+ union gl_constant_value *data =
+ rzalloc_array(uniforms, union gl_constant_value, num_data_slots);
+#ifndef NDEBUG
+ union gl_constant_value *data_end = &data[num_data_slots];
+#endif
+
+ parcel_out_uniform_storage parcel(prog->UniformHash, uniforms, data);
+
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ if (prog->_LinkedShaders[i] == NULL)
+ continue;
+
+ foreach_list(node, prog->_LinkedShaders[i]->ir) {
+ ir_variable *const var = ((ir_instruction *) node)->as_variable();
+
+ if ((var == NULL) || (var->mode != ir_var_uniform))
+ continue;
+
+ /* FINISHME: Update code to process built-in uniforms!
+ */
+ if (strncmp("gl_", var->name, 3) == 0)
+ continue;
+
+ parcel.process(var);
+ }
+ }
+
+#ifndef NDEBUG
+ for (unsigned i = 0; i < num_user_uniforms; i++) {
+ assert(uniforms[i].storage != NULL);
+ }
+#endif
+
+ assert(parcel.values == data_end);
+
+ prog->NumUserUniformStorage = num_user_uniforms;
+ prog->UniformStorage = uniforms;
+
+ return;
+}
diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp
index 915d5bbcf..0306b7a1b 100644
--- a/mesalib/src/glsl/linker.cpp
+++ b/mesalib/src/glsl/linker.cpp
@@ -191,8 +191,8 @@ linker_warning(gl_shader_program *prog, const char *fmt, ...)
void
-invalidate_variable_locations(gl_shader *sh, enum ir_variable_mode mode,
- int generic_base)
+link_invalidate_variable_locations(gl_shader *sh, enum ir_variable_mode mode,
+ int generic_base)
{
foreach_list(node, sh->ir) {
ir_variable *const var = ((ir_instruction *) node)->as_variable();
@@ -1021,13 +1021,6 @@ link_intrastage_shaders(void *mem_ctx,
return linked;
}
-
-struct uniform_node {
- exec_node link;
- struct gl_uniform *u;
- unsigned slots;
-};
-
/**
* Update the sizes of linked shader uniform arrays to the maximum
* array index used.
@@ -1100,151 +1093,6 @@ update_array_sizes(struct gl_shader_program *prog)
}
}
-static void
-add_uniform(void *mem_ctx, exec_list *uniforms, struct hash_table *ht,
- const char *name, const glsl_type *type, GLenum shader_type,
- unsigned *next_shader_pos, unsigned *total_uniforms)
-{
- if (type->is_record()) {
- for (unsigned int i = 0; i < type->length; i++) {
- const glsl_type *field_type = type->fields.structure[i].type;
- char *field_name = ralloc_asprintf(mem_ctx, "%s.%s", name,
- type->fields.structure[i].name);
-
- add_uniform(mem_ctx, uniforms, ht, field_name, field_type,
- shader_type, next_shader_pos, total_uniforms);
- }
- } else {
- uniform_node *n = (uniform_node *) hash_table_find(ht, name);
- unsigned int vec4_slots;
- const glsl_type *array_elem_type = NULL;
-
- if (type->is_array()) {
- array_elem_type = type->fields.array;
- /* Array of structures. */
- if (array_elem_type->is_record()) {
- for (unsigned int i = 0; i < type->length; i++) {
- char *elem_name = ralloc_asprintf(mem_ctx, "%s[%d]", name, i);
- add_uniform(mem_ctx, uniforms, ht, elem_name, array_elem_type,
- shader_type, next_shader_pos, total_uniforms);
- }
- return;
- }
- }
-
- /* Fix the storage size of samplers at 1 vec4 each. Be sure to pad out
- * vectors to vec4 slots.
- */
- if (type->is_array()) {
- if (array_elem_type->is_sampler())
- vec4_slots = type->length;
- else
- vec4_slots = type->length * array_elem_type->matrix_columns;
- } else if (type->is_sampler()) {
- vec4_slots = 1;
- } else {
- vec4_slots = type->matrix_columns;
- }
-
- if (n == NULL) {
- n = (uniform_node *) calloc(1, sizeof(struct uniform_node));
- n->u = (gl_uniform *) calloc(1, sizeof(struct gl_uniform));
- n->slots = vec4_slots;
-
- n->u->Name = strdup(name);
- n->u->Type = type;
- n->u->VertPos = -1;
- n->u->FragPos = -1;
- n->u->GeomPos = -1;
- (*total_uniforms)++;
-
- hash_table_insert(ht, n, name);
- uniforms->push_tail(& n->link);
- }
-
- switch (shader_type) {
- case GL_VERTEX_SHADER:
- n->u->VertPos = *next_shader_pos;
- break;
- case GL_FRAGMENT_SHADER:
- n->u->FragPos = *next_shader_pos;
- break;
- case GL_GEOMETRY_SHADER:
- n->u->GeomPos = *next_shader_pos;
- break;
- }
-
- (*next_shader_pos) += vec4_slots;
- }
-}
-
-void
-assign_uniform_locations(struct gl_shader_program *prog)
-{
- /* */
- exec_list uniforms;
- unsigned total_uniforms = 0;
- hash_table *ht = hash_table_ctor(32, hash_table_string_hash,
- hash_table_string_compare);
- void *mem_ctx = ralloc_context(NULL);
-
- for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
- if (prog->_LinkedShaders[i] == NULL)
- continue;
-
- unsigned next_position = 0;
-
- foreach_list(node, prog->_LinkedShaders[i]->ir) {
- ir_variable *const var = ((ir_instruction *) node)->as_variable();
-
- if ((var == NULL) || (var->mode != ir_var_uniform))
- continue;
-
- if (strncmp(var->name, "gl_", 3) == 0) {
- /* At the moment, we don't allocate uniform locations for
- * builtin uniforms. It's permitted by spec, and we'll
- * likely switch to doing that at some point, but not yet.
- */
- continue;
- }
-
- var->location = next_position;
- add_uniform(mem_ctx, &uniforms, ht, var->name, var->type,
- prog->_LinkedShaders[i]->Type,
- &next_position, &total_uniforms);
- }
- }
-
- ralloc_free(mem_ctx);
-
- gl_uniform_list *ul = (gl_uniform_list *)
- calloc(1, sizeof(gl_uniform_list));
-
- ul->Size = total_uniforms;
- ul->NumUniforms = total_uniforms;
- ul->Uniforms = (gl_uniform *) calloc(total_uniforms, sizeof(gl_uniform));
-
- unsigned idx = 0;
- uniform_node *next;
- for (uniform_node *node = (uniform_node *) uniforms.head
- ; node->link.next != NULL
- ; node = next) {
- next = (uniform_node *) node->link.next;
-
- node->link.remove();
- memcpy(&ul->Uniforms[idx], node->u, sizeof(gl_uniform));
- idx++;
-
- free(node->u);
- free(node);
- }
-
- hash_table_dtor(ht);
-
- prog->Uniforms = ul;
-}
-
-
/**
* Find a contiguous set of available bits in a bitmask.
*
@@ -1291,12 +1139,6 @@ find_available_slots(unsigned used_mask, unsigned needed_count)
* \return
* If locations are successfully assigned, true is returned. Otherwise an
* error is emitted to the shader link log and false is returned.
- *
- * \bug
- * Locations set via \c glBindFragDataLocation are not currently supported.
- * Only locations assigned automatically by the linker, explicitly set by a
- * layout qualifier, or explicitly set by a built-in variable (e.g., \c
- * gl_FragColor) are supported for fragment shaders.
*/
bool
assign_attribute_or_color_locations(gl_shader_program *prog,
@@ -1320,7 +1162,8 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
* 1. Invalidate the location assignments for all vertex shader inputs.
*
* 2. Assign locations for inputs that have user-defined (via
- * glBindVertexAttribLocation) locations.
+ * glBindVertexAttribLocation) locations and outputs that have
+ * user-defined locations (via glBindFragDataLocation).
*
* 3. Sort the attributes without assigned locations by number of slots
* required in decreasing order. Fragmentation caused by attribute
@@ -1337,7 +1180,7 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
(target_index == MESA_SHADER_VERTEX) ? ir_var_in : ir_var_out;
- invalidate_variable_locations(sh, direction, generic_base);
+ link_invalidate_variable_locations(sh, direction, generic_base);
/* Temporary storage for the set of attributes that need locations assigned.
*/
@@ -1381,6 +1224,13 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
assert(binding >= VERT_ATTRIB_GENERIC0);
var->location = binding;
}
+ } else if (target_index == MESA_SHADER_FRAGMENT) {
+ unsigned binding;
+
+ if (prog->FragDataBindings->get(binding, var->name)) {
+ assert(binding >= FRAG_RESULT_DATA0);
+ var->location = binding;
+ }
}
/* If the variable is not a built-in and has a location statically
@@ -1539,8 +1389,8 @@ assign_varying_locations(struct gl_context *ctx,
* not being inputs. This lets the optimizer eliminate them.
*/
- invalidate_variable_locations(producer, ir_var_out, VERT_RESULT_VAR0);
- invalidate_variable_locations(consumer, ir_var_in, FRAG_ATTRIB_VAR0);
+ link_invalidate_variable_locations(producer, ir_var_out, VERT_RESULT_VAR0);
+ link_invalidate_variable_locations(consumer, ir_var_in, FRAG_ATTRIB_VAR0);
foreach_list(node, producer->ir) {
ir_variable *const output_var = ((ir_instruction *) node)->as_variable();
@@ -1858,7 +1708,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
}
update_array_sizes(prog);
- assign_uniform_locations(prog);
+ link_assign_uniform_locations(prog);
/* OpenGL ES requires that a vertex shader and a fragment shader both be
* present in a linked program. By checking for use of shading language
diff --git a/mesalib/src/glsl/linker.h b/mesalib/src/glsl/linker.h
index 78c632961..433c63be2 100644
--- a/mesalib/src/glsl/linker.h
+++ b/mesalib/src/glsl/linker.h
@@ -30,6 +30,13 @@ extern bool
link_function_calls(gl_shader_program *prog, gl_shader *main,
gl_shader **shader_list, unsigned num_shaders);
+extern void
+link_invalidate_variable_locations(gl_shader *sh, enum ir_variable_mode mode,
+ int generic_base);
+
+extern void
+link_assign_uniform_locations(struct gl_shader_program *prog);
+
/**
* Class for processing all of the leaf fields of an uniform
*
diff --git a/mesalib/src/glu/sgi/libnurbs/internals/bin.cc b/mesalib/src/glu/sgi/libnurbs/internals/bin.cc
index ff75b86be..d85bd80dc 100644
--- a/mesalib/src/glu/sgi/libnurbs/internals/bin.cc
+++ b/mesalib/src/glu/sgi/libnurbs/internals/bin.cc
@@ -119,7 +119,7 @@ Bin::adopt()
*/
void
-Bin::show( char *name )
+Bin::show( const char *name )
{
#ifndef NDEBUG
_glu_dprintf( "%s\n", name );
diff --git a/mesalib/src/glu/sgi/libnurbs/internals/bin.h b/mesalib/src/glu/sgi/libnurbs/internals/bin.h
index 2f976eb9b..dd0f878f6 100644
--- a/mesalib/src/glu/sgi/libnurbs/internals/bin.h
+++ b/mesalib/src/glu/sgi/libnurbs/internals/bin.h
@@ -57,7 +57,7 @@ public:
int numarcs( void );
void adopt( void );
void markall( void );
- void show( char * );
+ void show( const char * );
void listBezier( void );
};
diff --git a/mesalib/src/mapi/glapi/glapi.h b/mesalib/src/mapi/glapi/glapi.h
index 8ef654636..f0955fce4 100644
--- a/mesalib/src/mapi/glapi/glapi.h
+++ b/mesalib/src/mapi/glapi/glapi.h
@@ -44,9 +44,13 @@
#ifndef _GLAPI_H
#define _GLAPI_H
+#include "glapi/glthread.h"
+
+
#ifdef __cplusplus
extern "C" {
#endif
+
#ifdef _GLAPI_NO_EXPORTS
# define _GLAPI_EXPORT
#else /* _GLAPI_NO_EXPORTS */
@@ -84,7 +88,6 @@ typedef void (*_glapi_warning_func)(void *ctx, const char *str, ...);
#define _glapi_Dispatch _mglapi_Dispatch
#endif
-
/*
* Number of extension functions which we can dynamically add at runtime.
*/
@@ -181,6 +184,7 @@ extern struct _glapi_table *
_glapi_create_table_from_handle(void *handle, const char *symbol_prefix);
#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/mesalib/src/mapi/glapi/glthread.h b/mesalib/src/mapi/glapi/glthread.h
index fc4ece7c3..1c3f4e2bf 100644
--- a/mesalib/src/mapi/glapi/glthread.h
+++ b/mesalib/src/mapi/glapi/glthread.h
@@ -3,6 +3,10 @@
#include "mapi/u_thread.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define _glthread_DECLARE_STATIC_MUTEX(name) u_mutex_declare_static(name)
#define _glthread_INIT_MUTEX(name) u_mutex_init(name)
#define _glthread_DESTROY_MUTEX(name) u_mutex_destroy(name)
@@ -17,4 +21,8 @@
typedef struct u_tsd _glthread_TSD;
typedef u_mutex _glthread_Mutex;
+#ifdef __cplusplus
+}
+#endif
+
#endif /* GLTHREAD_H */
diff --git a/mesalib/src/mapi/mapi/u_thread.h b/mesalib/src/mapi/mapi/u_thread.h
index 4405ec9c5..7db22b793 100644
--- a/mesalib/src/mapi/mapi/u_thread.h
+++ b/mesalib/src/mapi/mapi/u_thread.h
@@ -44,12 +44,25 @@
#include "u_compiler.h"
-#if defined(PTHREADS) || defined(WIN32)
+#if defined(PTHREADS)
+#include <pthread.h> /* POSIX threads headers */
+#endif
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#if defined(PTHREADS) || defined(_WIN32)
#ifndef THREADS
#define THREADS
#endif
#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
/*
* POSIX threads. This should be your choice in the Unix world
* whenever possible. When building with POSIX threads, be sure
@@ -60,7 +73,6 @@
* proper compiling for MT-safe libc etc.
*/
#if defined(PTHREADS)
-#include <pthread.h> /* POSIX threads headers */
struct u_tsd {
pthread_key_t key;
@@ -86,7 +98,6 @@ typedef pthread_mutex_t u_mutex;
* used!
*/
#ifdef WIN32
-#include <windows.h>
struct u_tsd {
DWORD key;
@@ -142,4 +153,9 @@ u_tsd_get(struct u_tsd *tsd);
void
u_tsd_set(struct u_tsd *tsd, void *ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _U_THREAD_H_ */
diff --git a/mesalib/src/mesa/SConscript b/mesalib/src/mesa/SConscript
index 7688ce941..8f978097c 100644
--- a/mesalib/src/mesa/SConscript
+++ b/mesalib/src/mesa/SConscript
@@ -149,10 +149,6 @@ math_sources = [
'math/m_xform.c',
]
-math_xform_sources = [
- 'math/m_xform.c'
-]
-
swrast_sources = [
'swrast/s_aaline.c',
'swrast/s_aatriangle.c',
@@ -306,7 +302,6 @@ program_sources = [
'program/prog_parameter_layout.c',
'program/prog_print.c',
'program/prog_statevars.c',
- 'program/prog_uniform.c',
'program/programopt.c',
'program/sampler.cpp',
'program/symbol_table.c',
@@ -323,7 +318,6 @@ common_driver_sources = [
mesa_sources = (
main_sources +
math_sources +
- math_xform_sources +
program_sources +
vbo_sources +
tnl_sources +
diff --git a/mesalib/src/mesa/main/clear.c b/mesalib/src/mesa/main/clear.c
index c35675fb4..2e27c951b 100644
--- a/mesalib/src/mesa/main/clear.c
+++ b/mesalib/src/mesa/main/clear.c
@@ -326,6 +326,13 @@ _mesa_ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value)
switch (buffer) {
case GL_STENCIL:
+ /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
+ *
+ * "ClearBuffer generates an INVALID VALUE error if buffer is
+ * COLOR and drawbuffer is less than zero, or greater than the
+ * value of MAX DRAW BUFFERS minus one; or if buffer is DEPTH,
+ * STENCIL, or DEPTH STENCIL and drawbuffer is not zero."
+ */
if (drawbuffer != 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferiv(drawbuffer=%d)",
drawbuffer);
@@ -373,6 +380,25 @@ _mesa_ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value)
}
}
break;
+ case GL_DEPTH:
+ /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
+ *
+ * "The result of ClearBuffer is undefined if no conversion between
+ * the type of the specified value and the type of the buffer being
+ * cleared is defined (for example, if ClearBufferiv is called for a
+ * fixed- or floating-point buffer, or if ClearBufferfv is called
+ * for a signed or unsigned integer buffer). This is not an error."
+ *
+ * In this case we take "undefined" and "not an error" to mean "ignore."
+ * Note that we still need to generate an error for the invalid
+ * drawbuffer case (see the GL_STENCIL case above).
+ */
+ if (drawbuffer != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferiv(drawbuffer=%d)",
+ drawbuffer);
+ return;
+ }
+ return;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferiv(buffer=%s)",
_mesa_lookup_enum_by_nr(buffer));
@@ -424,6 +450,31 @@ _mesa_ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value)
}
}
break;
+ case GL_DEPTH:
+ case GL_STENCIL:
+ /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
+ *
+ * "The result of ClearBuffer is undefined if no conversion between
+ * the type of the specified value and the type of the buffer being
+ * cleared is defined (for example, if ClearBufferiv is called for a
+ * fixed- or floating-point buffer, or if ClearBufferfv is called
+ * for a signed or unsigned integer buffer). This is not an error."
+ *
+ * In this case we take "undefined" and "not an error" to mean "ignore."
+ * Even though we could do something sensible for GL_STENCIL, page 263
+ * (page 279 of the PDF) says:
+ *
+ * "Only ClearBufferiv should be used to clear stencil buffers."
+ *
+ * Note that we still need to generate an error for the invalid
+ * drawbuffer case (see the GL_STENCIL case in _mesa_ClearBufferiv).
+ */
+ if (drawbuffer != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferuiv(drawbuffer=%d)",
+ drawbuffer);
+ return;
+ }
+ return;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferuiv(buffer=%s)",
_mesa_lookup_enum_by_nr(buffer));
@@ -450,6 +501,13 @@ _mesa_ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value)
switch (buffer) {
case GL_DEPTH:
+ /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
+ *
+ * "ClearBuffer generates an INVALID VALUE error if buffer is
+ * COLOR and drawbuffer is less than zero, or greater than the
+ * value of MAX DRAW BUFFERS minus one; or if buffer is DEPTH,
+ * STENCIL, or DEPTH STENCIL and drawbuffer is not zero."
+ */
if (drawbuffer != 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)",
drawbuffer);
@@ -498,6 +556,25 @@ _mesa_ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value)
}
}
break;
+ case GL_STENCIL:
+ /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
+ *
+ * "The result of ClearBuffer is undefined if no conversion between
+ * the type of the specified value and the type of the buffer being
+ * cleared is defined (for example, if ClearBufferiv is called for a
+ * fixed- or floating-point buffer, or if ClearBufferfv is called
+ * for a signed or unsigned integer buffer). This is not an error."
+ *
+ * In this case we take "undefined" and "not an error" to mean "ignore."
+ * Note that we still need to generate an error for the invalid
+ * drawbuffer case (see the GL_DEPTH case above).
+ */
+ if (drawbuffer != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)",
+ drawbuffer);
+ return;
+ }
+ return;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfv(buffer=%s)",
_mesa_lookup_enum_by_nr(buffer));
@@ -525,6 +602,13 @@ _mesa_ClearBufferfi(GLenum buffer, GLint drawbuffer,
return;
}
+ /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
+ *
+ * "ClearBuffer generates an INVALID VALUE error if buffer is
+ * COLOR and drawbuffer is less than zero, or greater than the
+ * value of MAX DRAW BUFFERS minus one; or if buffer is DEPTH,
+ * STENCIL, or DEPTH STENCIL and drawbuffer is not zero."
+ */
if (drawbuffer != 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfi(drawbuffer=%d)",
drawbuffer);
diff --git a/mesalib/src/mesa/main/context.h b/mesalib/src/mesa/main/context.h
index a9df0a866..a66dd5076 100644
--- a/mesalib/src/mesa/main/context.h
+++ b/mesalib/src/mesa/main/context.h
@@ -53,6 +53,11 @@
#include "mtypes.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
struct _glapi_table;
@@ -285,5 +290,9 @@ do { \
/*@}*/
+#ifdef __cplusplus
+}
+#endif
+
#endif /* CONTEXT_H */
diff --git a/mesalib/src/mesa/main/core.h b/mesalib/src/mesa/main/core.h
index ee3e91593..c28a8af53 100644
--- a/mesalib/src/mesa/main/core.h
+++ b/mesalib/src/mesa/main/core.h
@@ -1,64 +1,55 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.9
- *
- * Copyright (C) 2010 LunarG Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * 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.
- *
- * Authors:
- * Chia-I Wu <olv@lunarg.com>
- */
-
-
-/**
- * \file core.h
- * The public header of core mesa.
- *
- * This file is the (only) public header of core mesa. It is supposed to be
- * used by GLX, WGL, and GLSL. It is important that headers directly or
- * indirectly included here do not perform feature tests (#if FEATURE_xxx).
- */
-
-
-#ifndef CORE_H
-#define CORE_H
-
-
-#include "main/glheader.h"
-#include "main/compiler.h"
-#include "main/imports.h"
-#include "main/macros.h"
-
-#include "main/mtypes.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* for GLSL */
-#include "program/prog_parameter.h"
-#include "program/prog_uniform.h"
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* CORE_H */
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * 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.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+
+/**
+ * \file core.h
+ * The public header of core mesa.
+ *
+ * This file is the (only) public header of core mesa. It is supposed to be
+ * used by GLX, WGL, and GLSL. It is important that headers directly or
+ * indirectly included here do not perform feature tests (#if FEATURE_xxx).
+ */
+
+
+#ifndef CORE_H
+#define CORE_H
+
+
+#include "main/glheader.h"
+#include "main/compiler.h"
+#include "main/imports.h"
+#include "main/macros.h"
+
+#include "main/mtypes.h"
+
+/* for GLSL */
+#include "program/prog_parameter.h"
+
+
+#endif /* CORE_H */
diff --git a/mesalib/src/mesa/main/formats.h b/mesalib/src/mesa/main/formats.h
index f24d52548..b2cb750aa 100644
--- a/mesalib/src/mesa/main/formats.h
+++ b/mesalib/src/mesa/main/formats.h
@@ -35,6 +35,12 @@
#include <GL/gl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
/* OpenGL doesn't have GL_UNSIGNED_BYTE_4_4, so we must define our own type
* for GL_LUMINANCE4_ALPHA4. */
#define MESA_UNSIGNED_BYTE_4_4 (GL_UNSIGNED_BYTE<<1)
@@ -322,4 +328,9 @@ GLboolean
_mesa_format_matches_format_and_type(gl_format gl_format,
GLenum format, GLenum type);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* FORMATS_H */
diff --git a/mesalib/src/mesa/main/glheader.h b/mesalib/src/mesa/main/glheader.h
index c4fb1570d..7980111b5 100644
--- a/mesalib/src/mesa/main/glheader.h
+++ b/mesalib/src/mesa/main/glheader.h
@@ -54,6 +54,11 @@
#include "GL/glext.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
/**
* GL_FIXED is defined in glext.h version 64 but these typedefs aren't (yet).
*/
@@ -172,4 +177,9 @@ typedef void *GLeglImageOES;
#define GLX_DONT_CARE 0xFFFFFFFF
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* GLHEADER_H */
diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h
index 61909727d..58dc9af0f 100644
--- a/mesalib/src/mesa/main/mtypes.h
+++ b/mesalib/src/mesa/main/mtypes.h
@@ -43,6 +43,11 @@
#include "main/formats.h" /* MESA_FORMAT_COUNT */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
/**
* Stencil buffer data type.
*/
@@ -77,6 +82,7 @@ struct gl_program_cache;
struct gl_texture_object;
struct gl_context;
struct st_context;
+struct gl_uniform_storage;
/*@}*/
@@ -2184,6 +2190,15 @@ struct gl_shader_program
*/
struct string_to_uint_map *AttributeBindings;
+ /**
+ * User-defined fragment data bindings
+ *
+ * These are set via \c glBindFragDataLocation and are used to direct the
+ * GLSL linker. These are \b not the values used in the compiled shader,
+ * and they are \b not the values returned by \c glGetFragDataLocation.
+ */
+ struct string_to_uint_map *FragDataBindings;
+
/** Transform feedback varyings */
struct {
GLenum BufferMode;
@@ -2205,7 +2220,30 @@ struct gl_shader_program
} Vert;
/* post-link info: */
- struct gl_uniform_list *Uniforms;
+ unsigned NumUserUniformStorage;
+ struct gl_uniform_storage *UniformStorage;
+
+ /**
+ * Map of active uniform names to locations
+ *
+ * Maps any active uniform that is not an array element to a location.
+ * Each active uniform, including individual structure members will appear
+ * in this map. This roughly corresponds to the set of names that would be
+ * enumerated by \c glGetActiveUniform.
+ */
+ struct string_to_uint_map *UniformHash;
+
+ /**
+ * Map from sampler unit to texture unit (set by glUniform1i())
+ *
+ * A sampler unit is associated with each sampler uniform by the linker.
+ * The sampler unit associated with each uniform is stored in the
+ * \c gl_uniform_storage::sampler field.
+ */
+ GLubyte SamplerUnits[MAX_SAMPLERS];
+ /** Which texture target is being sampled (TEXTURE_1D/2D/3D/etc_INDEX) */
+ gl_texture_index SamplerTargets[MAX_SAMPLERS];
+
struct gl_program_parameter_list *Varying;
GLboolean LinkStatus; /**< GL_LINK_STATUS */
GLboolean Validated;
@@ -3421,4 +3459,8 @@ enum _debug
+#ifdef __cplusplus
+}
+#endif
+
#endif /* MTYPES_H */
diff --git a/mesalib/src/mesa/main/renderbuffer.c b/mesalib/src/mesa/main/renderbuffer.c
index 33bec42d9..4415dbd4f 100644
--- a/mesalib/src/mesa/main/renderbuffer.c
+++ b/mesalib/src/mesa/main/renderbuffer.c
@@ -720,7 +720,8 @@ get_values_ubyte4(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint cou
GLuint *dst = (GLuint *) values;
GLuint i;
ASSERT(rb->DataType == GL_UNSIGNED_BYTE);
- ASSERT(rb->Format == MESA_FORMAT_RGBA8888);
+ ASSERT(rb->Format == MESA_FORMAT_RGBA8888 ||
+ rb->Format == MESA_FORMAT_RGBA8888_REV);
for (i = 0; i < count; i++) {
const GLuint *src = (GLuint *) rb->Data + (y[i] * rb->RowStride + x[i]);
dst[i] = *src;
@@ -736,7 +737,8 @@ put_row_ubyte4(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
const GLuint *src = (const GLuint *) values;
GLuint *dst = (GLuint *) rb->Data + (y * rb->RowStride + x);
ASSERT(rb->DataType == GL_UNSIGNED_BYTE);
- ASSERT(rb->Format == MESA_FORMAT_RGBA8888);
+ ASSERT(rb->Format == MESA_FORMAT_RGBA8888 ||
+ rb->Format == MESA_FORMAT_RGBA8888_REV);
if (mask) {
GLuint i;
for (i = 0; i < count; i++) {
@@ -760,7 +762,8 @@ put_row_rgb_ubyte4(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint co
GLubyte *dst = (GLubyte *) rb->Data + 4 * (y * rb->RowStride + x);
GLuint i;
ASSERT(rb->DataType == GL_UNSIGNED_BYTE);
- ASSERT(rb->Format == MESA_FORMAT_RGBA8888);
+ ASSERT(rb->Format == MESA_FORMAT_RGBA8888 ||
+ rb->Format == MESA_FORMAT_RGBA8888_REV);
for (i = 0; i < count; i++) {
if (!mask || mask[i]) {
dst[i * 4 + 0] = src[i * 3 + 0];
@@ -780,7 +783,8 @@ put_mono_row_ubyte4(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint c
const GLuint val = *((const GLuint *) value);
GLuint *dst = (GLuint *) rb->Data + (y * rb->RowStride + x);
ASSERT(rb->DataType == GL_UNSIGNED_BYTE);
- ASSERT(rb->Format == MESA_FORMAT_RGBA8888);
+ ASSERT(rb->Format == MESA_FORMAT_RGBA8888 ||
+ rb->Format == MESA_FORMAT_RGBA8888_REV);
if (!mask && val == 0) {
/* common case */
memset(dst, 0, count * 4 * sizeof(GLubyte));
@@ -814,7 +818,8 @@ put_values_ubyte4(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint cou
const GLuint *src = (const GLuint *) values;
GLuint i;
ASSERT(rb->DataType == GL_UNSIGNED_BYTE);
- ASSERT(rb->Format == MESA_FORMAT_RGBA8888);
+ ASSERT(rb->Format == MESA_FORMAT_RGBA8888 ||
+ rb->Format == MESA_FORMAT_RGBA8888_REV);
for (i = 0; i < count; i++) {
if (!mask || mask[i]) {
GLuint *dst = (GLuint *) rb->Data + (y[i] * rb->RowStride + x[i]);
@@ -833,7 +838,8 @@ put_mono_values_ubyte4(struct gl_context *ctx, struct gl_renderbuffer *rb,
const GLuint val = *((const GLuint *) value);
GLuint i;
ASSERT(rb->DataType == GL_UNSIGNED_BYTE);
- ASSERT(rb->Format == MESA_FORMAT_RGBA8888);
+ ASSERT(rb->Format == MESA_FORMAT_RGBA8888 ||
+ rb->Format == MESA_FORMAT_RGBA8888_REV);
for (i = 0; i < count; i++) {
if (!mask || mask[i]) {
GLuint *dst = (GLuint *) rb->Data + (y[i] * rb->RowStride + x[i]);
@@ -1400,6 +1406,7 @@ _mesa_set_renderbuffer_accessors(struct gl_renderbuffer *rb)
break;
case MESA_FORMAT_RGBA8888:
+ case MESA_FORMAT_RGBA8888_REV:
rb->DataType = GL_UNSIGNED_BYTE;
rb->GetValues = get_values_ubyte4;
rb->PutRow = put_row_ubyte4;
@@ -1622,7 +1629,10 @@ _mesa_soft_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *
case GL_RGB10_A2:
case GL_RGBA12:
#endif
- rb->Format = MESA_FORMAT_RGBA8888;
+ if (_mesa_little_endian())
+ rb->Format = MESA_FORMAT_RGBA8888_REV;
+ else
+ rb->Format = MESA_FORMAT_RGBA8888;
break;
case GL_RGBA16:
case GL_RGBA16_SNORM:
@@ -2127,16 +2137,6 @@ _mesa_add_color_renderbuffers(struct gl_context *ctx, struct gl_framebuffer *fb,
return GL_FALSE;
}
- if (rgbBits <= 8) {
- if (alphaBits)
- rb->Format = MESA_FORMAT_RGBA8888;
- else
- rb->Format = MESA_FORMAT_RGB888;
- }
- else {
- assert(rgbBits <= 16);
- rb->Format = MESA_FORMAT_NONE; /*XXX RGBA16;*/
- }
rb->InternalFormat = GL_RGBA;
rb->AllocStorage = _mesa_soft_renderbuffer_storage;
@@ -2284,15 +2284,12 @@ _mesa_add_depth_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
}
if (depthBits <= 16) {
- rb->Format = MESA_FORMAT_Z16;
rb->InternalFormat = GL_DEPTH_COMPONENT16;
}
else if (depthBits <= 24) {
- rb->Format = MESA_FORMAT_X8_Z24;
rb->InternalFormat = GL_DEPTH_COMPONENT24;
}
else {
- rb->Format = MESA_FORMAT_Z32;
rb->InternalFormat = GL_DEPTH_COMPONENT32;
}
@@ -2332,7 +2329,6 @@ _mesa_add_stencil_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb
}
assert(stencilBits <= 8);
- rb->Format = MESA_FORMAT_S8;
rb->InternalFormat = GL_STENCIL_INDEX8;
rb->AllocStorage = _mesa_soft_renderbuffer_storage;
@@ -2371,7 +2367,6 @@ _mesa_add_accum_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
return GL_FALSE;
}
- rb->Format = MESA_FORMAT_SIGNED_RGBA_16;
rb->InternalFormat = GL_RGBA16_SNORM;
rb->AllocStorage = _mesa_soft_renderbuffer_storage;
_mesa_add_renderbuffer(fb, BUFFER_ACCUM, rb);
@@ -2416,7 +2411,6 @@ _mesa_add_aux_renderbuffers(struct gl_context *ctx, struct gl_framebuffer *fb,
}
assert (colorBits <= 8);
- rb->Format = MESA_FORMAT_RGBA8888;
rb->InternalFormat = GL_RGBA;
rb->AllocStorage = _mesa_soft_renderbuffer_storage;
diff --git a/mesalib/src/mesa/main/shader_query.cpp b/mesalib/src/mesa/main/shader_query.cpp
index bd873a491..38bacdb74 100644
--- a/mesalib/src/mesa/main/shader_query.cpp
+++ b/mesalib/src/mesa/main/shader_query.cpp
@@ -237,3 +237,96 @@ _mesa_longest_attribute_name_length(struct gl_shader_program *shProg)
return longest;
}
+
+void GLAPIENTRY
+_mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
+ const GLchar *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ struct gl_shader_program *const shProg =
+ _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocation");
+ if (!shProg)
+ return;
+
+ if (!name)
+ return;
+
+ if (strncmp(name, "gl_", 3) == 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindFragDataLocation(illegal name)");
+ return;
+ }
+
+ if (colorNumber >= ctx->Const.MaxDrawBuffers) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocation(index)");
+ return;
+ }
+
+ /* Replace the current value if it's already in the list. Add
+ * FRAG_RESULT_DATA0 because that's how the linker differentiates
+ * between built-in attributes and user-defined attributes.
+ */
+ shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name);
+
+ /*
+ * Note that this binding won't go into effect until
+ * glLinkProgram is called again.
+ */
+}
+
+GLint GLAPIENTRY
+_mesa_GetFragDataLocation(GLuint program, const GLchar *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_shader_program *const shProg =
+ _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataLocation");
+
+ if (!shProg) {
+ return -1;
+ }
+
+ if (!shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetFragDataLocation(program not linked)");
+ return -1;
+ }
+
+ if (!name)
+ return -1;
+
+ if (strncmp(name, "gl_", 3) == 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetFragDataLocation(illegal name)");
+ return -1;
+ }
+
+ /* Not having a fragment shader is not an error.
+ */
+ if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
+ return -1;
+
+ exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
+ foreach_list(node, ir) {
+ const ir_variable *const var = ((ir_instruction *) node)->as_variable();
+
+ /* The extra check against FRAG_RESULT_DATA0 is because
+ * glGetFragDataLocation cannot be used on "conventional" attributes.
+ *
+ * From page 95 of the OpenGL 3.0 spec:
+ *
+ * "If name is not an active attribute, if name is a conventional
+ * attribute, or if an error occurs, -1 will be returned."
+ */
+ if (var == NULL
+ || var->mode != ir_var_out
+ || var->location == -1
+ || var->location < FRAG_RESULT_DATA0)
+ continue;
+
+ if (strcmp(var->name, name) == 0)
+ return var->location - FRAG_RESULT_DATA0;
+ }
+
+ return -1;
+}
diff --git a/mesalib/src/mesa/main/shaderapi.c b/mesalib/src/mesa/main/shaderapi.c
index 56d955c53..c4d01abc7 100644
--- a/mesalib/src/mesa/main/shaderapi.c
+++ b/mesalib/src/mesa/main/shaderapi.c
@@ -47,10 +47,10 @@
#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"
+#include "../glsl/ir_uniform.h"
/** Define this to enable shader substitution (see below) */
#define SHADER_SUBST 0
@@ -325,14 +325,6 @@ attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
}
-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)
{
@@ -504,16 +496,6 @@ get_attached_shaders(struct gl_context *ctx, GLuint program, GLsizei maxCount,
}
-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.
*/
@@ -572,13 +554,24 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param
*params = _mesa_longest_attribute_name_length(shProg);
break;
case GL_ACTIVE_UNIFORMS:
- *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
+ *params = shProg->NumUserUniformStorage;
break;
- case GL_ACTIVE_UNIFORM_MAX_LENGTH:
- *params = _mesa_longest_uniform_name(shProg->Uniforms);
- if (*params > 0)
- (*params)++; /* add one for terminating zero */
+ case GL_ACTIVE_UNIFORM_MAX_LENGTH: {
+ unsigned i;
+ GLint max_len = 0;
+
+ for (i = 0; i < shProg->NumUserUniformStorage; i++) {
+ /* Add one for the terminating NUL character.
+ */
+ const GLint len = strlen(shProg->UniformStorage[i].name) + 1;
+
+ if (len > max_len)
+ max_len = len;
+ }
+
+ *params = max_len;
break;
+ }
case GL_PROGRAM_BINARY_LENGTH_OES:
*params = 0;
break;
@@ -1049,16 +1042,6 @@ _mesa_AttachShader(GLuint program, GLuint shader)
}
-/* 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)
{
@@ -1185,16 +1168,6 @@ _mesa_GetAttachedShaders(GLuint program, GLsizei maxCount,
}
-/* 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)
diff --git a/mesalib/src/mesa/main/shaderapi.h b/mesalib/src/mesa/main/shaderapi.h
index bec448dee..0ffebdb07 100644
--- a/mesalib/src/mesa/main/shaderapi.h
+++ b/mesalib/src/mesa/main/shaderapi.h
@@ -29,6 +29,12 @@
#include "glheader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
struct _glapi_table;
struct gl_context;
struct gl_shader_program;
@@ -194,4 +200,9 @@ _mesa_ActiveProgramEXT(GLuint program);
extern GLuint GLAPIENTRY
_mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* SHADERAPI_H */
diff --git a/mesalib/src/mesa/main/shaderobj.c b/mesalib/src/mesa/main/shaderobj.c
index ccf7efddb..454007f83 100644
--- a/mesalib/src/mesa/main/shaderobj.c
+++ b/mesalib/src/mesa/main/shaderobj.c
@@ -37,7 +37,6 @@
#include "main/shaderobj.h"
#include "program/program.h"
#include "program/prog_parameter.h"
-#include "program/prog_uniform.h"
#include "program/hash_table.h"
#include "ralloc.h"
@@ -241,6 +240,7 @@ _mesa_init_shader_program(struct gl_context *ctx, struct gl_shader_program *prog
prog->RefCount = 1;
prog->AttributeBindings = string_to_uint_map_ctor();
+ prog->FragDataBindings = string_to_uint_map_ctor();
#if FEATURE_ARB_geometry_shader4
prog->Geom.VerticesOut = 0;
@@ -275,9 +275,15 @@ void
_mesa_clear_shader_program_data(struct gl_context *ctx,
struct gl_shader_program *shProg)
{
- if (shProg->Uniforms) {
- _mesa_free_uniform_list(shProg->Uniforms);
- shProg->Uniforms = NULL;
+ if (shProg->UniformStorage) {
+ ralloc_free(shProg->UniformStorage);
+ shProg->NumUserUniformStorage = 0;
+ shProg->UniformStorage = NULL;
+ }
+
+ if (shProg->UniformHash) {
+ string_to_uint_map_dtor(shProg->UniformHash);
+ shProg->UniformHash = NULL;
}
if (shProg->Varying) {
@@ -311,6 +317,11 @@ _mesa_free_shader_program_data(struct gl_context *ctx,
shProg->AttributeBindings = NULL;
}
+ if (shProg->FragDataBindings) {
+ string_to_uint_map_dtor(shProg->FragDataBindings);
+ shProg->FragDataBindings = NULL;
+ }
+
/* detach shaders */
for (i = 0; i < shProg->NumShaders; i++) {
_mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
diff --git a/mesalib/src/mesa/main/simple_list.h b/mesalib/src/mesa/main/simple_list.h
index ff7f88823..9417108a0 100644
--- a/mesalib/src/mesa/main/simple_list.h
+++ b/mesalib/src/mesa/main/simple_list.h
@@ -37,6 +37,10 @@
#ifndef _SIMPLE_LIST_H
#define _SIMPLE_LIST_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct simple_node {
struct simple_node *next;
struct simple_node *prev;
@@ -199,4 +203,8 @@ do { \
#define foreach_s(ptr, t, list) \
for(ptr=(list)->next,t=(ptr)->next; list != ptr; ptr=t, t=(t)->next)
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/mesalib/src/mesa/main/texobj.c b/mesalib/src/mesa/main/texobj.c
index e2f0dc8b6..17c78ce3e 100644
--- a/mesalib/src/mesa/main/texobj.c
+++ b/mesalib/src/mesa/main/texobj.c
@@ -415,10 +415,6 @@ incomplete(struct gl_texture_object *t, const char *fmt, ...)
* The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE
* accordingly.
*
- * XXX TODO: For immutable textures (GL_ARB_texture_storage) we can skip
- * many of the checks below since we know the mipmap images will have
- * consistent sizes.
- *
* \param ctx GL context.
* \param t texture object.
*
@@ -504,6 +500,15 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
/* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */
t->_MaxLambda = (GLfloat) (t->_MaxLevel - t->BaseLevel);
+ if (t->Immutable) {
+ /* This texture object was created with glTexStorage1/2/3D() so we
+ * know that all the mipmap levels are the right size and all cube
+ * map faces are the same size.
+ * We don't need to do any of the additional checks below.
+ */
+ return;
+ }
+
if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
/* make sure that all six cube map level 0 images are the same size */
const GLuint w = t->Image[0][baseLevel]->Width2;
diff --git a/mesalib/src/mesa/main/uniform_query.cpp b/mesalib/src/mesa/main/uniform_query.cpp
index ba7d7591f..39aa5570e 100644
--- a/mesalib/src/mesa/main/uniform_query.cpp
+++ b/mesalib/src/mesa/main/uniform_query.cpp
@@ -22,15 +22,20 @@
* 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 <stdlib.h>
+
#include "main/core.h"
+#include "main/context.h"
#include "ir.h"
+#include "ir_uniform.h"
+#include "program/hash_table.h"
#include "../glsl/program.h"
-
-extern "C" {
+#include "../glsl/ir_uniform.h"
#include "main/shaderapi.h"
#include "main/shaderobj.h"
#include "uniforms.h"
-}
+
extern "C" void GLAPIENTRY
_mesa_GetActiveUniformARB(GLhandleARB program, GLuint index,
@@ -40,41 +45,875 @@ _mesa_GetActiveUniformARB(GLhandleARB program, GLuint index,
GET_CURRENT_CONTEXT(ctx);
struct gl_shader_program *shProg =
_mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
- const struct gl_program_parameter *param;
if (!shProg)
return;
- if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
+ if (index >= shProg->NumUserUniformStorage) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
return;
}
- param = get_uniform_parameter(shProg, index);
- if (!param)
- return;
-
- const struct gl_uniform *const uni = &shProg->Uniforms->Uniforms[index];
+ const struct gl_uniform_storage *const uni = &shProg->UniformStorage[index];
if (nameOut) {
- _mesa_copy_string(nameOut, maxLength, length, param->Name);
+ _mesa_copy_string(nameOut, maxLength, length, uni->name);
}
if (size) {
- GLint typeSize = _mesa_sizeof_glsl_type(uni->Type->gl_type);
- if ((GLint) param->Size > typeSize) {
- /* This is an array.
- * Array elements are placed on vector[4] boundaries so they're
- * a multiple of four floats. We round typeSize up to next multiple
- * of four to get the right size below.
- */
- typeSize = (typeSize + 3) & ~3;
- }
- /* Note that the returned size is in units of the <type>, not bytes */
- *size = param->Size / typeSize;
+ /* array_elements is zero for non-arrays, but the API requires that 1 be
+ * returned.
+ */
+ *size = MAX2(1, uni->array_elements);
}
if (type) {
- *type = uni->Type->gl_type;
+ *type = uni->type->gl_type;
+ }
+}
+
+static bool
+validate_uniform_parameters(struct gl_context *ctx,
+ struct gl_shader_program *shProg,
+ GLint location, GLsizei count,
+ unsigned *loc,
+ unsigned *array_index,
+ const char *caller,
+ bool negative_one_is_not_valid)
+{
+ if (!shProg || !shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", caller);
+ return false;
}
+
+ if (location == -1) {
+ /* For glGetUniform, page 264 (page 278 of the PDF) of the OpenGL 2.1
+ * spec says:
+ *
+ * "The error INVALID_OPERATION is generated if program has not been
+ * linked successfully, or if location is not a valid location for
+ * program."
+ *
+ * For glUniform, page 82 (page 96 of the PDF) of the OpenGL 2.1 spec
+ * says:
+ *
+ * "If the value of location is -1, the Uniform* commands will
+ * silently ignore the data passed in, and the current uniform
+ * values will not be changed."
+ *
+ * Allowing -1 for the location parameter of glUniform allows
+ * applications to avoid error paths in the case that, for example, some
+ * uniform variable is removed by the compiler / linker after
+ * optimization. In this case, the new value of the uniform is dropped
+ * on the floor. For the case of glGetUniform, there is nothing
+ * sensible to do for a location of -1.
+ *
+ * The negative_one_is_not_valid flag selects between the two behaviors.
+ */
+ if (negative_one_is_not_valid) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
+ caller, location);
+ }
+
+ return false;
+ }
+
+ /* From page 12 (page 26 of the PDF) of the OpenGL 2.1 spec:
+ *
+ * "If a negative number is provided where an argument of type sizei or
+ * sizeiptr is specified, the error INVALID_VALUE is generated."
+ */
+ if (count < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(count < 0)", caller);
+ return false;
+ }
+
+ /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
+ *
+ * "If any of the following conditions occur, an INVALID_OPERATION
+ * error is generated by the Uniform* commands, and no uniform values
+ * are changed:
+ *
+ * ...
+ *
+ * - if no variable with a location of location exists in the
+ * program object currently in use and location is not -1,
+ * - if count is greater than one, and the uniform declared in the
+ * shader is not an array variable,
+ */
+ if (location < -1) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
+ caller, location);
+ return false;
+ }
+
+ _mesa_uniform_split_location_offset(location, loc, array_index);
+
+ if (*loc >= shProg->NumUserUniformStorage) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
+ caller, location);
+ return false;
+ }
+
+ if (shProg->UniformStorage[*loc].array_elements == 0 && count > 1) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(count > 1 for non-array, location=%d)",
+ caller, location);
+ return false;
+ }
+
+ /* This case should be impossible. The implication is that a call like
+ * glGetUniformLocation(prog, "foo[8]") was successful but "foo" is not an
+ * array.
+ */
+ if (*array_index != 0 && shProg->UniformStorage[*loc].array_elements == 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
+ caller, location);
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Called via glGetUniform[fiui]v() to get the current value of a uniform.
+ */
+extern "C" void
+_mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location,
+ GLsizei bufSize, enum glsl_base_type returnType,
+ GLvoid *paramsOut)
+{
+ struct gl_shader_program *shProg =
+ _mesa_lookup_shader_program_err(ctx, program, "glGetUniformfv");
+ struct gl_uniform_storage *uni;
+ unsigned loc, offset;
+
+ if (!validate_uniform_parameters(ctx, shProg, location, 1,
+ &loc, &offset, "glGetUniform", true))
+ return;
+
+ uni = &shProg->UniformStorage[loc];
+
+ {
+ unsigned elements = (uni->type->is_sampler())
+ ? 1 : uni->type->components();
+
+ /* Calculate the source base address *BEFORE* modifying elements to
+ * account for the size of the user's buffer.
+ */
+ const union gl_constant_value *const src =
+ &uni->storage[offset * elements];
+
+ unsigned bytes = sizeof(uni->storage[0]) * elements;
+ if (bytes > (unsigned) bufSize) {
+ elements = bufSize / sizeof(uni->storage[0]);
+ bytes = bufSize;
+ }
+
+ /* If the return type and the uniform's native type are "compatible,"
+ * just memcpy the data. If the types are not compatible, perform a
+ * slower convert-and-copy process.
+ */
+ if (returnType == uni->type->base_type
+ || ((returnType == GLSL_TYPE_INT
+ || returnType == GLSL_TYPE_UINT
+ || returnType == GLSL_TYPE_SAMPLER)
+ &&
+ (uni->type->base_type == GLSL_TYPE_INT
+ || uni->type->base_type == GLSL_TYPE_UINT
+ || uni->type->base_type == GLSL_TYPE_SAMPLER))) {
+ memcpy(paramsOut, src, bytes);
+ } else {
+ union gl_constant_value *const dst =
+ (union gl_constant_value *) paramsOut;
+
+ /* This code could be optimized by putting the loop inside the switch
+ * statements. However, this is not expected to be
+ * performance-critical code.
+ */
+ for (unsigned i = 0; i < elements; i++) {
+ switch (returnType) {
+ case GLSL_TYPE_FLOAT:
+ switch (uni->type->base_type) {
+ case GLSL_TYPE_UINT:
+ dst[i].f = (float) src[i].u;
+ break;
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_SAMPLER:
+ dst[i].f = (float) src[i].i;
+ break;
+ case GLSL_TYPE_BOOL:
+ dst[i].f = src[i].i ? 1.0f : 0.0f;
+ break;
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ break;
+
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_UINT:
+ switch (uni->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ /* While the GL 3.2 core spec doesn't explicitly
+ * state how conversion of float uniforms to integer
+ * values works, in section 6.2 "State Tables" on
+ * page 267 it says:
+ *
+ * "Unless otherwise specified, when floating
+ * point state is returned as integer values or
+ * integer state is returned as floating-point
+ * values it is converted in the fashion
+ * described in section 6.1.2"
+ *
+ * That section, on page 248, says:
+ *
+ * "If GetIntegerv or GetInteger64v are called,
+ * a floating-point value is rounded to the
+ * nearest integer..."
+ */
+ dst[i].i = IROUND(src[i].f);
+ break;
+ case GLSL_TYPE_BOOL:
+ dst[i].i = src[i].i ? 1 : 0;
+ break;
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ break;
+
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void
+log_uniform(const void *values, enum glsl_base_type basicType,
+ unsigned rows, unsigned cols, unsigned count,
+ bool transpose,
+ const struct gl_shader_program *shProg,
+ GLint location,
+ const struct gl_uniform_storage *uni)
+{
+
+ const union gl_constant_value *v = (const union gl_constant_value *) values;
+ const unsigned elems = rows * cols * count;
+ const char *const extra = (cols == 1) ? "uniform" : "uniform matrix";
+
+ printf("Mesa: set program %u %s \"%s\" (loc %d, type \"%s\", "
+ "transpose = %s) to: ",
+ shProg->Name, extra, uni->name, location, uni->type->name,
+ transpose ? "true" : "false");
+ for (unsigned i = 0; i < elems; i++) {
+ if (i != 0 && ((i % rows) == 0))
+ printf(", ");
+
+ switch (basicType) {
+ case GLSL_TYPE_UINT:
+ printf("%u ", v[i].u);
+ break;
+ case GLSL_TYPE_INT:
+ printf("%d ", v[i].i);
+ break;
+ case GLSL_TYPE_FLOAT:
+ printf("%g ", v[i].f);
+ break;
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ }
+ printf("\n");
+ fflush(stdout);
+}
+
+#if 0
+static void
+log_program_parameters(const struct gl_shader_program *shProg)
+{
+ static const char *stages[] = {
+ "vertex", "fragment", "geometry"
+ };
+
+ assert(Elements(stages) == MESA_SHADER_TYPES);
+
+ for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+ if (shProg->_LinkedShaders[i] == NULL)
+ continue;
+
+ const struct gl_program *const prog = shProg->_LinkedShaders[i]->Program;
+
+ printf("Program %d %s shader parameters:\n",
+ shProg->Name, stages[i]);
+ for (unsigned j = 0; j < prog->Parameters->NumParameters; j++) {
+ printf("%s: %p %f %f %f %f\n",
+ prog->Parameters->Parameters[j].Name,
+ prog->Parameters->ParameterValues[j],
+ prog->Parameters->ParameterValues[j][0].f,
+ prog->Parameters->ParameterValues[j][1].f,
+ prog->Parameters->ParameterValues[j][2].f,
+ prog->Parameters->ParameterValues[j][3].f);
+ }
+ }
+ fflush(stdout);
+}
+#endif
+
+/**
+ * Propagate some values from uniform backing storage to driver storage
+ *
+ * Values propagated from uniform backing storage to driver storage
+ * have all format / type conversions previously requested by the
+ * driver applied. This function is most often called by the
+ * implementations of \c glUniform1f, etc. and \c glUniformMatrix2f,
+ * etc.
+ *
+ * \param uni Uniform whose data is to be propagated to driver storage
+ * \param array_index If \c uni is an array, this is the element of
+ * the array to be propagated.
+ * \param count Number of array elements to propagate.
+ */
+extern "C" void
+_mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni,
+ unsigned array_index,
+ unsigned count)
+{
+ unsigned i;
+
+ /* vector_elements and matrix_columns can be 0 for samplers.
+ */
+ const unsigned components = MAX2(1, uni->type->vector_elements);
+ const unsigned vectors = MAX2(1, uni->type->matrix_columns);
+
+ /* Store the data in the driver's requested type in the driver's storage
+ * areas.
+ */
+ unsigned src_vector_byte_stride = components * 4;
+
+ for (i = 0; i < uni->num_driver_storage; i++) {
+ struct gl_uniform_driver_storage *const store = &uni->driver_storage[i];
+ uint8_t *dst = (uint8_t *) store->data;
+ const unsigned extra_stride =
+ store->element_stride - (vectors * store->vector_stride);
+ const uint8_t *src =
+ (uint8_t *) (&uni->storage[array_index * (components * vectors)].i);
+
+#if 0
+ printf("%s: %p[%d] components=%u vectors=%u count=%u vector_stride=%u "
+ "extra_stride=%u\n",
+ __func__, dst, array_index, components,
+ vectors, count, store->vector_stride, extra_stride);
+#endif
+
+ dst += array_index * store->element_stride;
+
+ switch (store->format) {
+ case uniform_native:
+ case uniform_bool_int_0_1: {
+ unsigned j;
+ unsigned v;
+
+ for (j = 0; j < count; j++) {
+ for (v = 0; v < vectors; v++) {
+ memcpy(dst, src, src_vector_byte_stride);
+ src += src_vector_byte_stride;
+ dst += store->vector_stride;
+ }
+
+ dst += extra_stride;
+ }
+ break;
+ }
+
+ case uniform_int_float:
+ case uniform_bool_float: {
+ const int *isrc = (const int *) src;
+ unsigned j;
+ unsigned v;
+ unsigned c;
+
+ for (j = 0; j < count; j++) {
+ for (v = 0; v < vectors; v++) {
+ for (c = 0; c < components; c++) {
+ ((float *) dst)[c] = (float) *isrc;
+ isrc++;
+ }
+
+ dst += store->vector_stride;
+ }
+
+ dst += extra_stride;
+ }
+ break;
+ }
+
+ case uniform_bool_int_0_not0: {
+ const int *isrc = (const int *) src;
+ unsigned j;
+ unsigned v;
+ unsigned c;
+
+ for (j = 0; j < count; j++) {
+ for (v = 0; v < vectors; v++) {
+ for (c = 0; c < components; c++) {
+ ((int *) dst)[c] = *isrc == 0 ? 0 : ~0;
+ isrc++;
+ }
+
+ dst += store->vector_stride;
+ }
+
+ dst += extra_stride;
+ }
+ break;
+ }
+
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ }
+}
+
+/**
+ * Called via glUniform*() functions.
+ */
+extern "C" void
+_mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg,
+ GLint location, GLsizei count,
+ const GLvoid *values, GLenum type)
+{
+ unsigned loc, offset;
+ unsigned components;
+ unsigned src_components;
+ enum glsl_base_type basicType;
+ struct gl_uniform_storage *uni;
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (!validate_uniform_parameters(ctx, shProg, location, count,
+ &loc, &offset, "glUniform", false))
+ return;
+
+ uni = &shProg->UniformStorage[loc];
+
+ /* Verify that the types are compatible.
+ */
+ switch (type) {
+ case GL_FLOAT:
+ basicType = GLSL_TYPE_FLOAT;
+ src_components = 1;
+ break;
+ case GL_FLOAT_VEC2:
+ basicType = GLSL_TYPE_FLOAT;
+ src_components = 2;
+ break;
+ case GL_FLOAT_VEC3:
+ basicType = GLSL_TYPE_FLOAT;
+ src_components = 3;
+ break;
+ case GL_FLOAT_VEC4:
+ basicType = GLSL_TYPE_FLOAT;
+ src_components = 4;
+ break;
+ case GL_UNSIGNED_INT:
+ basicType = GLSL_TYPE_UINT;
+ src_components = 1;
+ break;
+ case GL_UNSIGNED_INT_VEC2:
+ basicType = GLSL_TYPE_UINT;
+ src_components = 2;
+ break;
+ case GL_UNSIGNED_INT_VEC3:
+ basicType = GLSL_TYPE_UINT;
+ src_components = 3;
+ break;
+ case GL_UNSIGNED_INT_VEC4:
+ basicType = GLSL_TYPE_UINT;
+ src_components = 4;
+ break;
+ case GL_INT:
+ basicType = GLSL_TYPE_INT;
+ src_components = 1;
+ break;
+ case GL_INT_VEC2:
+ basicType = GLSL_TYPE_INT;
+ src_components = 2;
+ break;
+ case GL_INT_VEC3:
+ basicType = GLSL_TYPE_INT;
+ src_components = 3;
+ break;
+ case GL_INT_VEC4:
+ basicType = GLSL_TYPE_INT;
+ src_components = 4;
+ break;
+ case GL_BOOL:
+ case GL_BOOL_VEC2:
+ case GL_BOOL_VEC3:
+ case GL_BOOL_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT2x4:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT3x4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ case GL_FLOAT_MAT4:
+ default:
+ _mesa_problem(NULL, "Invalid type in %s", __func__);
+ return;
+ }
+
+ if (uni->type->is_sampler()) {
+ components = 1;
+ } else {
+ components = uni->type->vector_elements;
+ }
+
+ bool match;
+ switch (uni->type->base_type) {
+ case GLSL_TYPE_BOOL:
+ match = true;
+ break;
+ case GLSL_TYPE_SAMPLER:
+ match = (basicType == GLSL_TYPE_INT);
+ break;
+ default:
+ match = (basicType == uni->type->base_type);
+ break;
+ }
+
+ if (uni->type->is_matrix() || components != src_components || !match) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
+ return;
+ }
+
+ if (ctx->Shader.Flags & GLSL_UNIFORMS) {
+ log_uniform(values, basicType, components, 1, count,
+ false, shProg, location, uni);
+ }
+
+ /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says:
+ *
+ * "Setting a sampler's value to i selects texture image unit number
+ * i. The values of i range from zero to the implementation- dependent
+ * maximum supported number of texture image units."
+ *
+ * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of
+ * the PDF) says:
+ *
+ * "Error Description Offending command
+ * ignored?
+ * ...
+ * INVALID_VALUE Numeric argument out of range Yes"
+ *
+ * Based on that, when an invalid sampler is specified, we generate a
+ * GL_INVALID_VALUE error and ignore the command.
+ */
+ if (uni->type->is_sampler()) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ const unsigned texUnit = ((unsigned *) values)[i];
+
+ /* check that the sampler (tex unit index) is legal */
+ if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glUniform1i(invalid sampler/tex unit index for "
+ "uniform %d)",
+ location);
+ return;
+ }
+ }
+ }
+
+ /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
+ *
+ * "When loading N elements starting at an arbitrary position k in a
+ * uniform declared as an array, elements k through k + N - 1 in the
+ * array will be replaced with the new values. Values for any array
+ * element that exceeds the highest array element index used, as
+ * reported by GetActiveUniform, will be ignored by the GL."
+ *
+ * Clamp 'count' to a valid value. Note that for non-arrays a count > 1
+ * will have already generated an error.
+ */
+ if (uni->array_elements != 0) {
+ if (offset >= uni->array_elements)
+ return;
+
+ count = MIN2(count, (uni->array_elements - offset));
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
+
+ /* Store the data in the "actual type" backing storage for the uniform.
+ */
+ if (!uni->type->is_boolean()) {
+ memcpy(&uni->storage[components * offset], values,
+ sizeof(uni->storage[0]) * components * count);
+ } else {
+ const union gl_constant_value *src =
+ (const union gl_constant_value *) values;
+ union gl_constant_value *dst = &uni->storage[components * offset];
+ const unsigned elems = components * count;
+ unsigned i;
+
+ for (i = 0; i < elems; i++) {
+ if (basicType == GLSL_TYPE_FLOAT) {
+ dst[i].i = src[i].f != 0.0f ? 1 : 0;
+ } else {
+ dst[i].i = src[i].i != 0 ? 1 : 0;
+ }
+ }
+ }
+
+ uni->initialized = true;
+
+ _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
+
+ /* If the uniform is a sampler, do the extra magic necessary to propagate
+ * the changes through.
+ */
+ if (uni->type->is_sampler()) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ shProg->SamplerUnits[uni->sampler + offset + i] =
+ ((unsigned *) values)[i];
+ }
+
+ bool flushed = false;
+ for (i = 0; i < MESA_SHADER_TYPES; i++) {
+ struct gl_program *prog;
+
+ if (shProg->_LinkedShaders[i] == NULL)
+ continue;
+
+ prog = shProg->_LinkedShaders[i]->Program;
+
+ assert(sizeof(prog->SamplerUnits) == sizeof(shProg->SamplerUnits));
+
+ if (memcmp(prog->SamplerUnits,
+ shProg->SamplerUnits,
+ sizeof(shProg->SamplerUnits)) != 0) {
+ if (!flushed) {
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
+ flushed = true;
+ }
+
+ memcpy(prog->SamplerUnits,
+ shProg->SamplerUnits,
+ sizeof(shProg->SamplerUnits));
+
+ _mesa_update_shader_textures_used(prog);
+ (void) ctx->Driver.ProgramStringNotify(ctx, prog->Target, prog);
+ }
+ }
+ }
+}
+
+/**
+ * Called by glUniformMatrix*() functions.
+ * Note: cols=2, rows=4 ==> array[2] of vec4
+ */
+extern "C" void
+_mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg,
+ GLuint cols, GLuint rows,
+ GLint location, GLsizei count,
+ GLboolean transpose, const GLfloat *values)
+{
+ unsigned loc, offset;
+ unsigned vectors;
+ unsigned components;
+ unsigned elements;
+ struct gl_uniform_storage *uni;
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (!validate_uniform_parameters(ctx, shProg, location, count,
+ &loc, &offset, "glUniformMatrix", false))
+ return;
+
+ uni = &shProg->UniformStorage[loc];
+ if (!uni->type->is_matrix()) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUniformMatrix(non-matrix uniform)");
+ return;
+ }
+
+ assert(!uni->type->is_sampler());
+ vectors = uni->type->matrix_columns;
+ components = uni->type->vector_elements;
+
+ /* Verify that the types are compatible. This is greatly simplified for
+ * matrices because they can only have a float base type.
+ */
+ if (vectors != cols || components != rows) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUniformMatrix(matrix size mismatch)");
+ return;
+ }
+
+ if (ctx->Shader.Flags & GLSL_UNIFORMS) {
+ log_uniform(values, GLSL_TYPE_FLOAT, components, vectors, count,
+ bool(transpose), shProg, location, uni);
+ }
+
+ /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
+ *
+ * "When loading N elements starting at an arbitrary position k in a
+ * uniform declared as an array, elements k through k + N - 1 in the
+ * array will be replaced with the new values. Values for any array
+ * element that exceeds the highest array element index used, as
+ * reported by GetActiveUniform, will be ignored by the GL."
+ *
+ * Clamp 'count' to a valid value. Note that for non-arrays a count > 1
+ * will have already generated an error.
+ */
+ if (uni->array_elements != 0) {
+ if (offset >= uni->array_elements)
+ return;
+
+ count = MIN2(count, (uni->array_elements - offset));
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
+
+ /* Store the data in the "actual type" backing storage for the uniform.
+ */
+ elements = components * vectors;
+
+ if (!transpose) {
+ memcpy(&uni->storage[elements * offset], values,
+ sizeof(uni->storage[0]) * elements * count);
+ } else {
+ /* Copy and transpose the matrix.
+ */
+ const float *src = values;
+ float *dst = &uni->storage[elements * offset].f;
+
+ for (int i = 0; i < count; i++) {
+ for (unsigned r = 0; r < rows; r++) {
+ for (unsigned c = 0; c < cols; c++) {
+ dst[(c * components) + r] = src[c + (r * vectors)];
+ }
+ }
+
+ dst += elements;
+ src += elements;
+ }
+ }
+
+ uni->initialized = true;
+
+ _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
+}
+
+/**
+ * Called via glGetUniformLocation().
+ *
+ * The return value will encode two values, the uniform location and an
+ * offset (used for arrays, structs).
+ */
+extern "C" GLint
+_mesa_get_uniform_location(struct gl_context *ctx,
+ struct gl_shader_program *shProg,
+ const GLchar *name)
+{
+ const size_t len = strlen(name);
+ long offset;
+ bool array_lookup;
+ char *name_copy;
+
+ /* If the name ends with a ']', assume that it refers to some element of an
+ * array. Malformed array references will fail the hash table look up
+ * below, so it doesn't matter that they are not caught here. This code
+ * only wants to catch the "leaf" array references so that arrays of
+ * structures containing arrays will be handled correctly.
+ */
+ if (name[len-1] == ']') {
+ unsigned i;
+
+ /* Walk backwards over the string looking for a non-digit character.
+ * This had better be the opening bracket for an array index.
+ *
+ * Initially, i specifies the location of the ']'. Since the string may
+ * contain only the ']' charcater, walk backwards very carefully.
+ */
+ for (i = len - 1; (i > 0) && isdigit(name[i-1]); --i)
+ /* empty */ ;
+
+ /* Page 80 (page 94 of the PDF) of the OpenGL 2.1 spec says:
+ *
+ * "The first element of a uniform array is identified using the
+ * name of the uniform array appended with "[0]". Except if the last
+ * part of the string name indicates a uniform array, then the
+ * location of the first element of that array can be retrieved by
+ * either using the name of the uniform array, or the name of the
+ * uniform array appended with "[0]"."
+ *
+ * Page 79 (page 93 of the PDF) of the OpenGL 2.1 spec says:
+ *
+ * "name must be a null terminated string, without white space."
+ *
+ * Return an error if there is no opening '[' to match the closing ']'.
+ * An error will also be returned if there is intervening white space
+ * (or other non-digit characters) before the opening '['.
+ */
+ if ((i == 0) || name[i-1] != '[')
+ return -1;
+
+ /* Return an error if there are no digits between the opening '[' to
+ * match the closing ']'.
+ */
+ if (i == (len - 1))
+ return -1;
+
+ /* Make a new string that is a copy of the old string up to (but not
+ * including) the '[' character.
+ */
+ name_copy = (char *) malloc(i);
+ memcpy(name_copy, name, i - 1);
+ name_copy[i-1] = '\0';
+
+ offset = strtol(&name[i], NULL, 10);
+ if (offset < 0)
+ return -1;
+
+ array_lookup = true;
+ } else {
+ name_copy = (char *) name;
+ offset = 0;
+ array_lookup = false;
+ }
+
+ unsigned location;
+ const bool found = shProg->UniformHash->get(location, name_copy);
+
+ assert(!found
+ || strcmp(name_copy, shProg->UniformStorage[location].name) == 0);
+
+ /* Free the temporary buffer *before* possibly returning an error.
+ */
+ if (name_copy != name)
+ free(name_copy);
+
+ if (!found)
+ return -1;
+
+ /* Since array_elements is 0 for non-arrays, this causes look-ups of 'a[0]'
+ * to (correctly) fail if 'a' is not an array.
+ */
+ if (array_lookup && shProg->UniformStorage[location].array_elements == 0) {
+ return -1;
+ }
+
+ return _mesa_uniform_merge_location_offset(location, offset);
}
diff --git a/mesalib/src/mesa/main/uniforms.c b/mesalib/src/mesa/main/uniforms.c
index 68e44b272..685c0f13f 100644
--- a/mesalib/src/mesa/main/uniforms.c
+++ b/mesalib/src/mesa/main/uniforms.c
@@ -35,522 +35,14 @@
* 2. Insert FLUSH_VERTICES calls in various places
*/
-
#include "main/glheader.h"
#include "main/context.h"
#include "main/dispatch.h"
-#include "main/image.h"
-#include "main/mfeatures.h"
-#include "main/mtypes.h"
#include "main/shaderapi.h"
#include "main/shaderobj.h"
#include "main/uniforms.h"
-#include "program/prog_parameter.h"
-#include "program/prog_statevars.h"
-#include "program/prog_uniform.h"
-#include "program/prog_instruction.h"
-
-
-static GLenum
-base_uniform_type(GLenum type)
-{
- switch (type) {
- case GL_BOOL:
- case GL_BOOL_VEC2:
- case GL_BOOL_VEC3:
- case GL_BOOL_VEC4:
- return GL_BOOL;
- case GL_FLOAT:
- case GL_FLOAT_VEC2:
- case GL_FLOAT_VEC3:
- case GL_FLOAT_VEC4:
- case GL_FLOAT_MAT2:
- case GL_FLOAT_MAT2x3:
- case GL_FLOAT_MAT2x4:
- case GL_FLOAT_MAT3x2:
- case GL_FLOAT_MAT3:
- case GL_FLOAT_MAT3x4:
- case GL_FLOAT_MAT4x2:
- case GL_FLOAT_MAT4x3:
- case GL_FLOAT_MAT4:
- return GL_FLOAT;
- case GL_UNSIGNED_INT:
- case GL_UNSIGNED_INT_VEC2:
- case GL_UNSIGNED_INT_VEC3:
- case GL_UNSIGNED_INT_VEC4:
- return GL_UNSIGNED_INT;
- case GL_INT:
- case GL_INT_VEC2:
- case GL_INT_VEC3:
- case GL_INT_VEC4:
- return GL_INT;
- default:
- _mesa_problem(NULL, "Invalid type in base_uniform_type()");
- return GL_FLOAT;
- }
-}
-
-
-static GLboolean
-is_boolean_type(GLenum type)
-{
- switch (type) {
- case GL_BOOL:
- case GL_BOOL_VEC2:
- case GL_BOOL_VEC3:
- case GL_BOOL_VEC4:
- return GL_TRUE;
- default:
- return GL_FALSE;
- }
-}
-
-
-static GLboolean
-is_sampler_type(GLenum type)
-{
- switch (type) {
- case GL_SAMPLER_1D:
- case GL_INT_SAMPLER_1D:
- case GL_UNSIGNED_INT_SAMPLER_1D:
- case GL_SAMPLER_2D:
- case GL_INT_SAMPLER_2D:
- case GL_UNSIGNED_INT_SAMPLER_2D:
- case GL_SAMPLER_3D:
- case GL_INT_SAMPLER_3D:
- case GL_UNSIGNED_INT_SAMPLER_3D:
- case GL_SAMPLER_CUBE:
- case GL_INT_SAMPLER_CUBE:
- case GL_UNSIGNED_INT_SAMPLER_CUBE:
- case GL_SAMPLER_1D_SHADOW:
- case GL_SAMPLER_2D_SHADOW:
- case GL_SAMPLER_CUBE_SHADOW:
- case GL_SAMPLER_2D_RECT_ARB:
- case GL_INT_SAMPLER_2D_RECT:
- case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
- case GL_SAMPLER_2D_RECT_SHADOW_ARB:
- case GL_SAMPLER_1D_ARRAY_EXT:
- case GL_INT_SAMPLER_1D_ARRAY:
- case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
- case GL_SAMPLER_2D_ARRAY_EXT:
- case GL_INT_SAMPLER_2D_ARRAY:
- case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
- case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
- case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
- case GL_SAMPLER_CUBE_MAP_ARRAY:
- case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
- case GL_SAMPLER_BUFFER:
- case GL_INT_SAMPLER_BUFFER:
- case GL_UNSIGNED_INT_SAMPLER_BUFFER:
- case GL_SAMPLER_2D_MULTISAMPLE:
- case GL_INT_SAMPLER_2D_MULTISAMPLE:
- case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
- case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
- case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
- case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
- case GL_SAMPLER_EXTERNAL_OES:
- return GL_TRUE;
- default:
- return GL_FALSE;
- }
-}
-
-
-/**
- * Given a uniform index, return the vertex/geometry/fragment program
- * that has that parameter, plus the position of the parameter in the
- * parameter/constant buffer.
- * \param shProg the shader program
- * \param index the uniform index in [0, NumUniforms-1]
- * \param progOut returns containing program
- * \param posOut returns position of the uniform in the param/const buffer
- * \return GL_TRUE for success, GL_FALSE for invalid index
- */
-static GLboolean
-find_uniform_parameter_pos(struct gl_shader_program *shProg, GLint index,
- struct gl_program **progOut, GLint *posOut)
-{
- struct gl_program *prog = NULL;
- GLint pos;
-
- if (!shProg->Uniforms ||
- index < 0 ||
- index >= (GLint) shProg->Uniforms->NumUniforms) {
- return GL_FALSE;
- }
-
- pos = shProg->Uniforms->Uniforms[index].VertPos;
- if (pos >= 0) {
- prog = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->Program;
- }
- else {
- pos = shProg->Uniforms->Uniforms[index].FragPos;
- if (pos >= 0) {
- prog = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program;
- }
- else {
- pos = shProg->Uniforms->Uniforms[index].GeomPos;
- if (pos >= 0) {
- prog = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program;
- }
- }
- }
-
- if (!prog || pos < 0)
- return GL_FALSE; /* should really never happen */
-
- *progOut = prog;
- *posOut = pos;
-
- return GL_TRUE;
-}
-
-
-/**
- * Return pointer to a gl_program_parameter which corresponds to a uniform.
- * \param shProg the shader program
- * \param index the uniform index in [0, NumUniforms-1]
- * \return gl_program_parameter point or NULL if index is invalid
- */
-const struct gl_program_parameter *
-get_uniform_parameter(struct gl_shader_program *shProg, GLint index)
-{
- struct gl_program *prog;
- GLint progPos;
-
- if (find_uniform_parameter_pos(shProg, index, &prog, &progPos))
- return &prog->Parameters->Parameters[progPos];
- else
- return NULL;
-}
-
-
-static unsigned
-get_vector_elements(GLenum type)
-{
- switch (type) {
- case GL_FLOAT:
- case GL_INT:
- case GL_BOOL:
- case GL_UNSIGNED_INT:
- default: /* Catch all the various sampler types. */
- return 1;
-
- case GL_FLOAT_VEC2:
- case GL_INT_VEC2:
- case GL_BOOL_VEC2:
- case GL_UNSIGNED_INT_VEC2:
- return 2;
-
- case GL_FLOAT_VEC3:
- case GL_INT_VEC3:
- case GL_BOOL_VEC3:
- case GL_UNSIGNED_INT_VEC3:
- return 3;
-
- case GL_FLOAT_VEC4:
- case GL_INT_VEC4:
- case GL_BOOL_VEC4:
- case GL_UNSIGNED_INT_VEC4:
- return 4;
- }
-}
-
-static void
-get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
-{
- switch (type) {
- case GL_FLOAT_MAT2:
- *rows = *cols = 2;
- break;
- case GL_FLOAT_MAT2x3:
- *rows = 3;
- *cols = 2;
- break;
- case GL_FLOAT_MAT2x4:
- *rows = 4;
- *cols = 2;
- break;
- case GL_FLOAT_MAT3:
- *rows = 3;
- *cols = 3;
- break;
- case GL_FLOAT_MAT3x2:
- *rows = 2;
- *cols = 3;
- break;
- case GL_FLOAT_MAT3x4:
- *rows = 4;
- *cols = 3;
- break;
- case GL_FLOAT_MAT4:
- *rows = 4;
- *cols = 4;
- break;
- case GL_FLOAT_MAT4x2:
- *rows = 2;
- *cols = 4;
- break;
- case GL_FLOAT_MAT4x3:
- *rows = 3;
- *cols = 4;
- break;
- default:
- *rows = *cols = 0;
- }
-}
-
-
-/**
- * Determine the number of rows and columns occupied by a uniform
- * according to its datatype. For non-matrix types (such as GL_FLOAT_VEC4),
- * the number of rows = 1 and cols = number of elements in the vector.
- */
-static void
-get_uniform_rows_cols(const struct gl_program_parameter *p,
- GLint *rows, GLint *cols)
-{
- get_matrix_dims(p->DataType, rows, cols);
- if (*rows == 0 && *cols == 0) {
- /* not a matrix type, probably a float or vector */
- *rows = 1;
- *cols = get_vector_elements(p->DataType);
- }
-}
-
-
-/**
- * GLSL uniform arrays and structs require special handling.
- *
- * The GL_ARB_shader_objects spec says that if you use
- * glGetUniformLocation to get the location of an array, you CANNOT
- * access other elements of the array by adding an offset to the
- * returned location. For example, you must call
- * glGetUniformLocation("foo[16]") if you want to set the 16th element
- * of the array with glUniform().
- *
- * HOWEVER, some other OpenGL drivers allow accessing array elements
- * by adding an offset to the returned array location. And some apps
- * seem to depend on that behaviour.
- *
- * Mesa's gl_uniform_list doesn't directly support this since each
- * entry in the list describes one uniform variable, not one uniform
- * element. We could insert dummy entries in the list for each array
- * element after [0] but that causes complications elsewhere.
- *
- * We solve this problem by encoding two values in the location that's
- * returned by glGetUniformLocation():
- * a) index into gl_uniform_list::Uniforms[] for the uniform
- * b) an array/field offset (0 for simple types)
- *
- * These two values are encoded in the high and low halves of a GLint.
- * By putting the uniform number in the high part and the offset in the
- * low part, we can support the unofficial ability to index into arrays
- * by adding offsets to the location value.
- */
-static void
-merge_location_offset(GLint *location, GLint offset)
-{
- *location = (*location << 16) | offset;
-}
-
-
-/**
- * Separate the uniform location and parameter offset. See above.
- */
-static void
-split_location_offset(GLint *location, GLint *offset)
-{
- *offset = *location & 0xffff;
- *location = *location >> 16;
-}
-
-
-
-/**
- * Called via glGetUniform[fiui]v() to get the current value of a uniform.
- */
-static void
-get_uniform(struct gl_context *ctx, GLuint program, GLint location,
- GLsizei bufSize, GLenum returnType, GLvoid *paramsOut)
-{
- struct gl_shader_program *shProg =
- _mesa_lookup_shader_program_err(ctx, program, "glGetUniformfv");
- struct gl_program *prog;
- GLint paramPos, offset;
-
- if (!shProg)
- return;
-
- split_location_offset(&location, &offset);
-
- if (!find_uniform_parameter_pos(shProg, location, &prog, &paramPos)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
- }
- else {
- const struct gl_program_parameter *p =
- &prog->Parameters->Parameters[paramPos];
- gl_constant_value (*values)[4];
- GLint rows, cols, i, j, k;
- GLsizei numBytes;
- GLenum storage_type;
-
- values = prog->Parameters->ParameterValues + paramPos + offset;
-
- get_uniform_rows_cols(p, &rows, &cols);
-
- numBytes = rows * cols * _mesa_sizeof_type(returnType);
- if (bufSize < numBytes) {
- _mesa_error( ctx, GL_INVALID_OPERATION,
- "glGetnUniformfvARB(out of bounds: bufSize is %d,"
- " but %d bytes are required)", bufSize, numBytes );
- return;
- }
-
- if (ctx->Const.NativeIntegers) {
- storage_type = base_uniform_type(p->DataType);
- } else {
- storage_type = GL_FLOAT;
- }
-
- k = 0;
- for (i = 0; i < rows; i++) {
- for (j = 0; j < cols; j++ ) {
- void *out = (char *)paramsOut + 4 * k;
-
- switch (returnType) {
- case GL_FLOAT:
- switch (storage_type) {
- case GL_FLOAT:
- *(float *)out = values[i][j].f;
- break;
- case GL_INT:
- case GL_BOOL: /* boolean is just an integer 1 or 0. */
- *(float *)out = values[i][j].i;
- break;
- case GL_UNSIGNED_INT:
- *(float *)out = values[i][j].u;
- break;
- }
- break;
-
- case GL_INT:
- case GL_UNSIGNED_INT:
- switch (storage_type) {
- case GL_FLOAT:
- /* While the GL 3.2 core spec doesn't explicitly
- * state how conversion of float uniforms to integer
- * values works, in section 6.2 "State Tables" on
- * page 267 it says:
- *
- * "Unless otherwise specified, when floating
- * point state is returned as integer values or
- * integer state is returned as floating-point
- * values it is converted in the fashion
- * described in section 6.1.2"
- *
- * That section, on page 248, says:
- *
- * "If GetIntegerv or GetInteger64v are called,
- * a floating-point value is rounded to the
- * nearest integer..."
- */
- *(int *)out = IROUND(values[i][j].f);
- break;
-
- case GL_INT:
- case GL_UNSIGNED_INT:
- case GL_BOOL:
- /* type conversions for these to int/uint are just
- * copying the data.
- */
- *(int *)out = values[i][j].i;
- break;
- break;
- }
- break;
- }
-
- k++;
- }
- }
- }
-}
-
-
-/**
- * Called via glGetUniformLocation().
- *
- * The return value will encode two values, the uniform location and an
- * offset (used for arrays, structs).
- */
-GLint
-_mesa_get_uniform_location(struct gl_context *ctx,
- struct gl_shader_program *shProg,
- const GLchar *name)
-{
- GLint offset = 0, location = -1;
-
- if (shProg->LinkStatus == GL_FALSE) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
- return -1;
- }
-
- /* XXX we should return -1 if the uniform was declared, but not
- * actually used.
- */
-
- /* XXX we need to be able to parse uniform names for structs and arrays
- * such as:
- * mymatrix[1]
- * mystruct.field1
- */
-
- {
- /* handle 1-dimension arrays here... */
- char *c = strchr(name, '[');
- if (c) {
- /* truncate name at [ */
- const GLint len = c - name;
- GLchar *newName = malloc(len + 1);
- if (!newName)
- return -1; /* out of mem */
- memcpy(newName, name, len);
- newName[len] = 0;
-
- location = _mesa_lookup_uniform(shProg->Uniforms, newName);
- if (location >= 0) {
- const GLint element = atoi(c + 1);
- if (element > 0) {
- /* get type of the uniform array element */
- const struct gl_program_parameter *p =
- get_uniform_parameter(shProg, location);
- if (p) {
- GLint rows, cols;
- get_matrix_dims(p->DataType, &rows, &cols);
- if (rows < 1)
- rows = 1;
- offset = element * rows;
- }
- }
- }
-
- free(newName);
- }
- }
-
- if (location < 0) {
- location = _mesa_lookup_uniform(shProg->Uniforms, name);
- }
-
- if (location >= 0) {
- merge_location_offset(&location, offset);
- }
-
- return location;
-}
-
-
+#include "ir_uniform.h"
+#include "glsl_types.h"
/**
* Update the vertex/fragment program's TexturesUsed array.
@@ -585,470 +77,53 @@ _mesa_update_shader_textures_used(struct gl_program *prog)
}
}
-
/**
- * Check if the type given by userType is allowed to set a uniform of the
- * target type. Generally, equivalence is required, but setting Boolean
- * uniforms can be done with glUniformiv or glUniformfv.
- */
-static GLboolean
-compatible_types(GLenum userType, GLenum targetType)
-{
- if (userType == targetType)
- return GL_TRUE;
-
- if (targetType == GL_BOOL && (userType == GL_FLOAT ||
- userType == GL_UNSIGNED_INT ||
- userType == GL_INT))
- return GL_TRUE;
-
- if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
- userType == GL_UNSIGNED_INT_VEC2 ||
- userType == GL_INT_VEC2))
- return GL_TRUE;
-
- if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
- userType == GL_UNSIGNED_INT_VEC3 ||
- userType == GL_INT_VEC3))
- return GL_TRUE;
-
- if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
- userType == GL_UNSIGNED_INT_VEC4 ||
- userType == GL_INT_VEC4))
- return GL_TRUE;
-
- if (is_sampler_type(targetType) && userType == GL_INT)
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-/**
- * Set the value of a program's uniform variable.
- * \param program the program whose uniform to update
- * \param index the index of the program parameter for the uniform
- * \param offset additional parameter slot offset (for arrays)
- * \param type the incoming datatype of 'values'
- * \param count the number of uniforms to set
- * \param elems number of elements per uniform (1, 2, 3 or 4)
- * \param values the new values, of datatype 'type'
- */
-static void
-set_program_uniform(struct gl_context *ctx, struct gl_program *program,
- GLint index, GLint offset,
- GLenum type, GLsizei count, GLint elems,
- const void *values)
-{
- const struct gl_program_parameter *param =
- &program->Parameters->Parameters[index];
-
- assert(offset >= 0);
- assert(elems >= 1);
- assert(elems <= 4);
-
- if (!compatible_types(type, param->DataType)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
- return;
- }
-
- if (index + offset > (GLint) program->Parameters->Size) {
- /* out of bounds! */
- return;
- }
-
- if (param->Type == PROGRAM_SAMPLER) {
- /* This controls which texture unit which is used by a sampler */
- GLboolean changed = GL_FALSE;
- GLint i;
-
- /* this should have been caught by the compatible_types() check */
- ASSERT(type == GL_INT);
-
- /* loop over number of samplers to change */
- for (i = 0; i < count; i++) {
- GLuint sampler = (GLuint)
- program->Parameters->ParameterValues[index+offset + i][0].f;
- GLuint texUnit = ((GLuint *) values)[i];
-
- /* check that the sampler (tex unit index) is legal */
- if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glUniform1(invalid sampler/tex unit index for '%s')",
- param->Name);
- return;
- }
-
- /* This maps a sampler to a texture unit: */
- if (sampler < MAX_SAMPLERS) {
-#if 0
- printf("Set program %p sampler %d '%s' to unit %u\n",
- program, sampler, param->Name, texUnit);
-#endif
- if (program->SamplerUnits[sampler] != texUnit) {
- program->SamplerUnits[sampler] = texUnit;
- changed = GL_TRUE;
- }
- }
- }
-
- if (changed) {
- /* When a sampler's value changes it usually requires rewriting
- * a GPU program's TEX instructions since there may not be a
- * sampler->texture lookup table. We signal this with the
- * ProgramStringNotify() callback.
- */
- FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
- _mesa_update_shader_textures_used(program);
- /* Do we need to care about the return value here?
- * This should not be the first time the driver was notified of
- * this program.
- */
- (void) ctx->Driver.ProgramStringNotify(ctx, program->Target, program);
- }
- }
- else {
- /* ordinary uniform variable */
- const GLboolean isUniformBool = is_boolean_type(param->DataType);
- const GLenum basicType = base_uniform_type(type);
- const GLint slots = (param->Size + 3) / 4;
- const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
- GLsizei k, i;
-
- if ((GLint) param->Size > typeSize) {
- /* an array */
- /* we'll ignore extra data below */
- }
- else {
- /* non-array: count must be at most one; count == 0 is handled
- * by the loop below
- */
- if (count > 1) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUniform(uniform '%s' is not an array)",
- param->Name);
- return;
- }
- }
-
- /* loop over number of array elements */
- for (k = 0; k < count; k++) {
- gl_constant_value *uniformVal;
-
- if (offset + k >= slots) {
- /* Extra array data is ignored */
- break;
- }
-
- /* uniformVal (the destination) is always gl_constant_value[4] */
- uniformVal = program->Parameters->ParameterValues[index + offset + k];
-
- if (basicType == GL_INT) {
- const GLint *iValues = ((const GLint *) values) + k * elems;
- for (i = 0; i < elems; i++) {
- if (!ctx->Const.NativeIntegers)
- uniformVal[i].f = (GLfloat) iValues[i];
- else
- uniformVal[i].i = iValues[i];
- }
- }
- else if (basicType == GL_UNSIGNED_INT) {
- const GLuint *iValues = ((const GLuint *) values) + k * elems;
- for (i = 0; i < elems; i++) {
- if (!ctx->Const.NativeIntegers)
- uniformVal[i].f = (GLfloat)(GLuint) iValues[i];
- else
- uniformVal[i].u = iValues[i];
- }
- }
- else {
- const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
- assert(basicType == GL_FLOAT);
- for (i = 0; i < elems; i++) {
- uniformVal[i].f = fValues[i];
- }
- }
-
- /* if the uniform is bool-valued, convert to 1 or 0 */
- if (isUniformBool) {
- for (i = 0; i < elems; i++) {
- if (basicType == GL_FLOAT)
- uniformVal[i].b = uniformVal[i].f != 0.0f ? 1 : 0;
- else
- uniformVal[i].b = uniformVal[i].u ? 1 : 0;
-
- if (ctx->Const.NativeIntegers)
- uniformVal[i].u =
- uniformVal[i].b ? ctx->Const.UniformBooleanTrue : 0;
- else
- uniformVal[i].f = uniformVal[i].b ? 1.0f : 0.0f;
- }
- }
- }
- }
-}
-
-
-/**
- * Called via glUniform*() functions.
+ * Connect a piece of driver storage with a part of a uniform
+ *
+ * \param uni The uniform with which the storage will be associated
+ * \param element_stride Byte-stride between array elements.
+ * \sa gl_uniform_driver_storage::element_stride.
+ * \param vector_stride Byte-stride between vectors (in a matrix).
+ * \sa gl_uniform_driver_storage::vector_stride.
+ * \param format Conversion from native format to driver format
+ * required by the driver.
+ * \param data Location to dump the data.
*/
void
-_mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg,
- GLint location, GLsizei count,
- const GLvoid *values, GLenum type)
-{
- struct gl_uniform *uniform;
- GLint elems, offset;
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (!shProg || !shProg->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
- return;
- }
-
- if (location == -1)
- return; /* The standard specifies this as a no-op */
-
- if (location < -1) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location=%d)",
- location);
- return;
- }
-
- split_location_offset(&location, &offset);
-
- if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location=%d)", location);
- return;
- }
-
- if (count < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
- return;
- }
-
- elems = _mesa_sizeof_glsl_type(type);
-
- FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
-
- uniform = &shProg->Uniforms->Uniforms[location];
-
- if (ctx->Shader.Flags & GLSL_UNIFORMS) {
- const GLenum basicType = base_uniform_type(type);
- GLint i;
- printf("Mesa: set program %u uniform %s (loc %d) to: ",
- shProg->Name, uniform->Name, location);
- if (basicType == GL_INT) {
- const GLint *v = (const GLint *) values;
- for (i = 0; i < count * elems; i++) {
- printf("%d ", v[i]);
- }
- }
- else if (basicType == GL_UNSIGNED_INT) {
- const GLuint *v = (const GLuint *) values;
- for (i = 0; i < count * elems; i++) {
- printf("%u ", v[i]);
- }
- }
- else {
- const GLfloat *v = (const GLfloat *) values;
- assert(basicType == GL_FLOAT);
- for (i = 0; i < count * elems; i++) {
- printf("%g ", v[i]);
- }
- }
- printf("\n");
- }
-
- /* A uniform var may be used by both a vertex shader and a fragment
- * shader. We may need to update one or both shader's uniform here:
- */
- if (shProg->_LinkedShaders[MESA_SHADER_VERTEX]) {
- /* convert uniform location to program parameter index */
- GLint index = uniform->VertPos;
- if (index >= 0) {
- set_program_uniform(ctx,
- shProg->_LinkedShaders[MESA_SHADER_VERTEX]->Program,
- index, offset, type, count, elems, values);
- }
- }
-
- if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]) {
- /* convert uniform location to program parameter index */
- GLint index = uniform->FragPos;
- if (index >= 0) {
- set_program_uniform(ctx,
- shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program,
- index, offset, type, count, elems, values);
- }
- }
-
- if (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]) {
- /* convert uniform location to program parameter index */
- GLint index = uniform->GeomPos;
- if (index >= 0) {
- set_program_uniform(ctx,
- shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program,
- index, offset, type, count, elems, values);
- }
- }
-
- uniform->Initialized = GL_TRUE;
-}
-
-
-/**
- * Set a matrix-valued program parameter.
- */
-static void
-set_program_uniform_matrix(struct gl_context *ctx, struct gl_program *program,
- GLuint index, GLuint offset,
- GLuint count, GLuint rows, GLuint cols,
- GLboolean transpose, const GLfloat *values)
+_mesa_uniform_attach_driver_storage(struct gl_uniform_storage *uni,
+ unsigned element_stride,
+ unsigned vector_stride,
+ enum gl_uniform_driver_format format,
+ void *data)
{
- GLuint mat, row, col;
- GLuint src = 0;
- const struct gl_program_parameter *param =
- &program->Parameters->Parameters[index];
- const GLuint slots = (param->Size + 3) / 4;
- const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
- GLint nr, nc;
-
- /* check that the number of rows, columns is correct */
- get_matrix_dims(param->DataType, &nr, &nc);
- if (rows != nr || cols != nc) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUniformMatrix(matrix size mismatch)");
- return;
- }
-
- if ((GLint) param->Size <= typeSize) {
- /* non-array: count must be at most one; count == 0 is handled
- * by the loop below
- */
- if (count > 1) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUniformMatrix(uniform is not an array)");
- return;
- }
- }
-
- /*
- * Note: the _columns_ of a matrix are stored in program registers, not
- * the rows. So, the loops below look a little funny.
- * XXX could optimize this a bit...
- */
+ uni->driver_storage = (struct gl_uniform_driver_storage*)
+ realloc(uni->driver_storage,
+ sizeof(struct gl_uniform_driver_storage)
+ * (uni->num_driver_storage + 1));
- /* loop over matrices */
- for (mat = 0; mat < count; mat++) {
-
- /* each matrix: */
- for (col = 0; col < cols; col++) {
- GLfloat *v;
- if (offset >= slots) {
- /* Ignore writes beyond the end of (the used part of) an array */
- return;
- }
- v = (GLfloat *) program->Parameters->ParameterValues[index + offset];
- for (row = 0; row < rows; row++) {
- if (transpose) {
- v[row] = values[src + row * cols + col];
- }
- else {
- v[row] = values[src + col * rows + row];
- }
- }
-
- offset++;
- }
+ uni->driver_storage[uni->num_driver_storage].element_stride = element_stride;
+ uni->driver_storage[uni->num_driver_storage].vector_stride = vector_stride;
+ uni->driver_storage[uni->num_driver_storage].format = (uint8_t) format;
+ uni->driver_storage[uni->num_driver_storage].data = data;
- src += rows * cols; /* next matrix */
- }
+ uni->num_driver_storage++;
}
-
/**
- * Called by glUniformMatrix*() functions.
- * Note: cols=2, rows=4 ==> array[2] of vec4
+ * Sever all connections with all pieces of driver storage for all uniforms
+ *
+ * \warning
+ * This function does \b not release any of the \c data pointers
+ * previously passed in to \c _mesa_uniform_attach_driver_stoarge.
*/
void
-_mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg,
- GLint cols, GLint rows,
- GLint location, GLsizei count,
- GLboolean transpose, const GLfloat *values)
+_mesa_uniform_detach_all_driver_storage(struct gl_uniform_storage *uni)
{
- struct gl_uniform *uniform;
- GLint offset;
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (!shProg || !shProg->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUniformMatrix(program not linked)");
- return;
- }
-
- if (location == -1)
- return; /* The standard specifies this as a no-op */
-
- if (location < -1) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
- return;
- }
-
- split_location_offset(&location, &offset);
-
- if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
- return;
- }
- if (values == NULL) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
- return;
- }
-
- FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
-
- uniform = &shProg->Uniforms->Uniforms[location];
-
- if (shProg->_LinkedShaders[MESA_SHADER_VERTEX]) {
- /* convert uniform location to program parameter index */
- GLint index = uniform->VertPos;
- if (index >= 0) {
- set_program_uniform_matrix(ctx,
- shProg->_LinkedShaders[MESA_SHADER_VERTEX]->Program,
- index, offset,
- count, rows, cols, transpose, values);
- }
- }
-
- if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]) {
- /* convert uniform location to program parameter index */
- GLint index = uniform->FragPos;
- if (index >= 0) {
- set_program_uniform_matrix(ctx,
- shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program,
- index, offset,
- count, rows, cols, transpose, values);
- }
- }
-
- if (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]) {
- /* convert uniform location to program parameter index */
- GLint index = uniform->GeomPos;
- if (index >= 0) {
- set_program_uniform_matrix(ctx,
- shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program,
- index, offset,
- count, rows, cols, transpose, values);
- }
- }
-
- uniform->Initialized = GL_TRUE;
+ free(uni->driver_storage);
+ uni->driver_storage = NULL;
+ uni->num_driver_storage = 0;
}
-
void GLAPIENTRY
_mesa_Uniform1fARB(GLint location, GLfloat v0)
{
@@ -1349,7 +424,7 @@ _mesa_GetnUniformfvARB(GLhandleARB program, GLint location,
GLsizei bufSize, GLfloat *params)
{
GET_CURRENT_CONTEXT(ctx);
- get_uniform(ctx, program, location, bufSize, GL_FLOAT, params);
+ _mesa_get_uniform(ctx, program, location, bufSize, GLSL_TYPE_FLOAT, params);
}
void GLAPIENTRY
@@ -1364,7 +439,7 @@ _mesa_GetnUniformivARB(GLhandleARB program, GLint location,
GLsizei bufSize, GLint *params)
{
GET_CURRENT_CONTEXT(ctx);
- get_uniform(ctx, program, location, bufSize, GL_INT, params);
+ _mesa_get_uniform(ctx, program, location, bufSize, GLSL_TYPE_INT, params);
}
void GLAPIENTRY
@@ -1380,7 +455,7 @@ _mesa_GetnUniformuivARB(GLhandleARB program, GLint location,
GLsizei bufSize, GLuint *params)
{
GET_CURRENT_CONTEXT(ctx);
- get_uniform(ctx, program, location, bufSize, GL_UNSIGNED_INT, params);
+ _mesa_get_uniform(ctx, program, location, bufSize, GLSL_TYPE_UINT, params);
}
void GLAPIENTRY
@@ -1403,7 +478,7 @@ _mesa_GetnUniformdvARB(GLhandleARB program, GLint location,
(void) params;
/*
- get_uniform(ctx, program, location, bufSize, GL_DOUBLE, params);
+ _mesa_get_uniform(ctx, program, location, bufSize, GL_DOUBLE, params);
*/
_mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformdvARB"
"(GL_ARB_gpu_shader_fp64 not implemented)");
@@ -1428,6 +503,17 @@ _mesa_GetUniformLocationARB(GLhandleARB programObj, const GLcharARB *name)
if (!shProg)
return -1;
+ /* Page 80 (page 94 of the PDF) of the OpenGL 2.1 spec says:
+ *
+ * "If program has not been successfully linked, the error
+ * INVALID_OPERATION is generated."
+ */
+ if (shProg->LinkStatus == GL_FALSE) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetUniformLocation(program not linked)");
+ return -1;
+ }
+
return _mesa_get_uniform_location(ctx, shProg, name);
}
diff --git a/mesalib/src/mesa/main/uniforms.h b/mesalib/src/mesa/main/uniforms.h
index 77f55d47d..123d7b954 100644
--- a/mesalib/src/mesa/main/uniforms.h
+++ b/mesalib/src/mesa/main/uniforms.h
@@ -27,6 +27,13 @@
#include "glheader.h"
#include "program/prog_parameter.h"
+#include "../glsl/glsl_types.h"
+#include "../glsl/ir_uniform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct gl_program;
struct _glapi_table;
@@ -180,10 +187,30 @@ _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shader_program,
void
_mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg,
- GLint cols, GLint rows,
+ GLuint cols, GLuint rows,
GLint location, GLsizei count,
GLboolean transpose, const GLfloat *values);
+void
+_mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location,
+ GLsizei bufSize, enum glsl_base_type returnType,
+ GLvoid *paramsOut);
+
+extern void
+_mesa_uniform_attach_driver_storage(struct gl_uniform_storage *,
+ unsigned element_stride,
+ unsigned vector_stride,
+ enum gl_uniform_driver_format format,
+ void *data);
+
+extern void
+_mesa_uniform_detach_all_driver_storage(struct gl_uniform_storage *uni);
+
+extern void
+_mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni,
+ unsigned array_index,
+ unsigned count);
+
extern void
_mesa_update_shader_textures_used(struct gl_program *prog);
@@ -208,4 +235,61 @@ struct gl_builtin_uniform_desc {
extern const struct gl_builtin_uniform_desc _mesa_builtin_uniform_desc[];
+/**
+ * \name GLSL uniform arrays and structs require special handling.
+ *
+ * The GL_ARB_shader_objects spec says that if you use
+ * glGetUniformLocation to get the location of an array, you CANNOT
+ * access other elements of the array by adding an offset to the
+ * returned location. For example, you must call
+ * glGetUniformLocation("foo[16]") if you want to set the 16th element
+ * of the array with glUniform().
+ *
+ * HOWEVER, some other OpenGL drivers allow accessing array elements
+ * by adding an offset to the returned array location. And some apps
+ * seem to depend on that behaviour.
+ *
+ * Mesa's gl_uniform_list doesn't directly support this since each
+ * entry in the list describes one uniform variable, not one uniform
+ * element. We could insert dummy entries in the list for each array
+ * element after [0] but that causes complications elsewhere.
+ *
+ * We solve this problem by encoding two values in the location that's
+ * returned by glGetUniformLocation():
+ * a) index into gl_uniform_list::Uniforms[] for the uniform
+ * b) an array/field offset (0 for simple types)
+ *
+ * These two values are encoded in the high and low halves of a GLint.
+ * By putting the uniform number in the high part and the offset in the
+ * low part, we can support the unofficial ability to index into arrays
+ * by adding offsets to the location value.
+ */
+/*@{*/
+/**
+ * Combine the uniform's base location and the offset
+ */
+static inline GLint
+_mesa_uniform_merge_location_offset(unsigned base_location, unsigned offset)
+{
+ return (base_location << 16) | offset;
+}
+
+/**
+ * Separate the uniform base location and parameter offset
+ */
+static inline void
+_mesa_uniform_split_location_offset(GLint location, unsigned *base_location,
+ unsigned *offset)
+{
+ *offset = location & 0xffff;
+ *base_location = location >> 16;
+}
+/*@}*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
#endif /* UNIFORMS_H */
diff --git a/mesalib/src/mesa/main/version.c b/mesalib/src/mesa/main/version.c
index fbe211182..b4d462103 100644
--- a/mesalib/src/mesa/main/version.c
+++ b/mesalib/src/mesa/main/version.c
@@ -124,9 +124,11 @@ compute_version(struct gl_context *ctx)
ctx->Extensions.EXT_pixel_buffer_object &&
ctx->Extensions.EXT_texture_sRGB);
const GLboolean ver_3_0 = (ver_2_1 &&
+ ctx->Const.GLSLVersion >= 130 &&
ctx->Extensions.ARB_color_buffer_float &&
ctx->Extensions.ARB_depth_buffer_float &&
ctx->Extensions.ARB_half_float_pixel &&
+ ctx->Extensions.ARB_half_float_vertex &&
ctx->Extensions.ARB_map_buffer_range &&
ctx->Extensions.ARB_texture_float &&
ctx->Extensions.ARB_texture_rg &&
@@ -145,6 +147,7 @@ compute_version(struct gl_context *ctx)
ctx->Extensions.EXT_transform_feedback &&
ctx->Extensions.NV_conditional_render);
const GLboolean ver_3_1 = (ver_3_0 &&
+ ctx->Const.GLSLVersion >= 140 &&
ctx->Extensions.ARB_copy_buffer &&
ctx->Extensions.ARB_draw_instanced &&
ctx->Extensions.ARB_texture_buffer_object &&
@@ -154,6 +157,7 @@ compute_version(struct gl_context *ctx)
ctx->Extensions.NV_texture_rectangle &&
ctx->Const.MaxVertexTextureImageUnits >= 16);
const GLboolean ver_3_2 = (ver_3_1 &&
+ ctx->Const.GLSLVersion >= 150 &&
ctx->Extensions.ARB_depth_clamp &&
ctx->Extensions.ARB_draw_elements_base_vertex &&
ctx->Extensions.ARB_fragment_coord_conventions &&
@@ -164,6 +168,7 @@ compute_version(struct gl_context *ctx)
ctx->Extensions.ARB_texture_multisample &&
ctx->Extensions.EXT_vertex_array_bgra);
const GLboolean ver_3_3 = (ver_3_2 &&
+ ctx->Const.GLSLVersion >= 330 &&
ctx->Extensions.ARB_blend_func_extended &&
ctx->Extensions.ARB_explicit_attrib_location &&
ctx->Extensions.ARB_instanced_arrays &&
diff --git a/mesalib/src/mesa/math/m_matrix.h b/mesalib/src/mesa/math/m_matrix.h
index a69afb858..e8e48aab7 100644
--- a/mesalib/src/mesa/math/m_matrix.h
+++ b/mesalib/src/mesa/math/m_matrix.h
@@ -35,6 +35,11 @@
#include "main/glheader.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
/**
* \name Symbolic names to some of the entries in the matrix
*
@@ -209,4 +214,8 @@ _mesa_transform_vector(GLfloat u[4], const GLfloat v[4], const GLfloat m[16]);
/*@}*/
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/mesalib/src/mesa/program/hash_table.h b/mesalib/src/mesa/program/hash_table.h
index 9ec4e40e8..e1c234ea4 100644
--- a/mesalib/src/mesa/program/hash_table.h
+++ b/mesalib/src/mesa/program/hash_table.h
@@ -38,16 +38,17 @@
#include <assert.h>
#include <unistd.h>
-struct hash_table;
struct string_to_uint_map;
-typedef unsigned (*hash_func_t)(const void *key);
-typedef int (*hash_compare_func_t)(const void *key1, const void *key2);
-
#ifdef __cplusplus
extern "C" {
#endif
+struct hash_table;
+
+typedef unsigned (*hash_func_t)(const void *key);
+typedef int (*hash_compare_func_t)(const void *key1, const void *key2);
+
/**
* Hash table constructor
*
@@ -215,6 +216,14 @@ public:
}
/**
+ * Remove all mappings from this map.
+ */
+ void clear()
+ {
+ hash_table_clear(this->ht);
+ }
+
+ /**
* Get the value associated with a particular key
*
* \return
diff --git a/mesalib/src/mesa/program/ir_to_mesa.cpp b/mesalib/src/mesa/program/ir_to_mesa.cpp
index 3c2eb5707..1b8b48e53 100644
--- a/mesalib/src/mesa/program/ir_to_mesa.cpp
+++ b/mesalib/src/mesa/program/ir_to_mesa.cpp
@@ -35,6 +35,7 @@
#include "ir_visitor.h"
#include "ir_print_visitor.h"
#include "ir_expression_flattening.h"
+#include "ir_uniform.h"
#include "glsl_types.h"
#include "glsl_parser_extras.h"
#include "../glsl/program.h"
@@ -53,7 +54,6 @@ extern "C" {
#include "program/prog_optimize.h"
#include "program/prog_print.h"
#include "program/program.h"
-#include "program/prog_uniform.h"
#include "program/prog_parameter.h"
#include "program/sampler.h"
}
@@ -2597,17 +2597,17 @@ class add_uniform_to_shader : public uniform_field_visitor {
public:
add_uniform_to_shader(struct gl_shader_program *shader_program,
struct gl_program_parameter_list *params)
- : shader_program(shader_program), params(params), next_sampler(0)
+ : shader_program(shader_program), params(params)
{
/* empty */
}
- int process(ir_variable *var)
+ void process(ir_variable *var)
{
this->idx = -1;
this->uniform_field_visitor::process(var);
- return this->idx;
+ var->location = this->idx;
}
private:
@@ -2615,7 +2615,6 @@ private:
struct gl_shader_program *shader_program;
struct gl_program_parameter_list *params;
- int next_sampler;
int idx;
};
@@ -2648,8 +2647,20 @@ add_uniform_to_shader::visit_field(const glsl_type *type, const char *name)
* store in ParameterValues[].
*/
if (file == PROGRAM_SAMPLER) {
+ unsigned location;
+ const bool found =
+ this->shader_program->UniformHash->get(location,
+ params->Parameters[index].Name);
+ assert(found);
+
+ if (!found)
+ return;
+
+ struct gl_uniform_storage *storage =
+ &this->shader_program->UniformStorage[location];
+
for (unsigned int j = 0; j < size / 4; j++)
- params->ParameterValues[index + j][0].f = this->next_sampler++;
+ params->ParameterValues[index + j][0].f = storage->sampler + j;
}
}
@@ -2684,16 +2695,77 @@ _mesa_generate_parameters_list_for_uniforms(struct gl_shader_program
|| (strncmp(var->name, "gl_", 3) == 0))
continue;
- int loc = add.process(var);
+ add.process(var);
+ }
+}
- /* The location chosen in the Parameters list here (returned from
- * _mesa_add_parameter) has to match what the linker chose.
- */
- if (var->location != loc) {
- linker_error(shader_program,
- "Allocation of uniform `%s' to target failed "
- "(%d vs %d)\n",
- var->name, loc, var->location);
+void
+_mesa_associate_uniform_storage(struct gl_context *ctx,
+ struct gl_shader_program *shader_program,
+ struct gl_program_parameter_list *params)
+{
+ /* After adding each uniform to the parameter list, connect the storage for
+ * the parameter with the tracking structure used by the API for the
+ * uniform.
+ */
+ unsigned last_location = unsigned(~0);
+ for (unsigned i = 0; i < params->NumParameters; i++) {
+ if (params->Parameters[i].Type != PROGRAM_UNIFORM)
+ continue;
+
+ unsigned location;
+ const bool found =
+ shader_program->UniformHash->get(location, params->Parameters[i].Name);
+ assert(found);
+
+ if (!found)
+ continue;
+
+ if (location != last_location) {
+ struct gl_uniform_storage *storage =
+ &shader_program->UniformStorage[location];
+ enum gl_uniform_driver_format format = uniform_native;
+
+ unsigned columns = 0;
+ switch (storage->type->base_type) {
+ case GLSL_TYPE_UINT:
+ assert(ctx->Const.NativeIntegers);
+ format = uniform_native;
+ columns = 1;
+ break;
+ case GLSL_TYPE_INT:
+ format =
+ (ctx->Const.NativeIntegers) ? uniform_native : uniform_int_float;
+ columns = 1;
+ break;
+ case GLSL_TYPE_FLOAT:
+ format = uniform_native;
+ columns = storage->type->matrix_columns;
+ break;
+ case GLSL_TYPE_BOOL:
+ if (ctx->Const.NativeIntegers) {
+ format = (ctx->Const.UniformBooleanTrue == 1)
+ ? uniform_bool_int_0_1 : uniform_bool_int_0_not0;
+ } else {
+ format = uniform_bool_float;
+ }
+ columns = 1;
+ break;
+ case GLSL_TYPE_SAMPLER:
+ format = uniform_native;
+ columns = 1;
+ break;
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+
+ _mesa_uniform_attach_driver_storage(storage,
+ 4 * sizeof(float) * columns,
+ 4 * sizeof(float),
+ format,
+ &params->ParameterValues[i]);
+ last_location = location;
}
}
}
@@ -2759,12 +2831,12 @@ set_uniform_initializer(struct gl_context *ctx, void *mem_ctx,
element_type->matrix_columns,
element_type->vector_elements,
loc, 1, GL_FALSE, (GLfloat *)values);
- loc += element_type->matrix_columns;
} else {
_mesa_uniform(ctx, shader_program, loc, element_type->matrix_columns,
values, element_type->gl_type);
- loc += type_size(element_type);
}
+
+ loc++;
}
}
@@ -3211,6 +3283,15 @@ get_mesa_program(struct gl_context *ctx,
_mesa_optimize_program(ctx, prog);
}
+ /* This has to be done last. Any operation that can cause
+ * prog->ParameterValues to get reallocated (e.g., anything that adds a
+ * program constant) has to happen before creating this linkage.
+ */
+ _mesa_associate_uniform_storage(ctx, shader_program, prog->Parameters);
+ if (!shader_program->LinkStatus) {
+ goto fail_exit;
+ }
+
return prog;
fail_exit:
diff --git a/mesalib/src/mesa/program/ir_to_mesa.h b/mesalib/src/mesa/program/ir_to_mesa.h
index d046b0fcf..aa053d9c8 100644
--- a/mesalib/src/mesa/program/ir_to_mesa.h
+++ b/mesalib/src/mesa/program/ir_to_mesa.h
@@ -21,28 +21,34 @@
* DEALINGS IN THE SOFTWARE.
*/
-#include "main/glheader.h"
+#pragma once
-struct gl_context;
-struct gl_shader;
-struct gl_shader_program;
+#include "main/glheader.h"
#ifdef __cplusplus
extern "C" {
#endif
+struct gl_context;
+struct gl_shader;
+struct gl_shader_program;
+
void _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *sh);
void _mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog);
GLboolean _mesa_ir_compile_shader(struct gl_context *ctx, struct gl_shader *shader);
GLboolean _mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog);
-#ifdef __cplusplus
-}
-
void
_mesa_generate_parameters_list_for_uniforms(struct gl_shader_program
*shader_program,
struct gl_shader *sh,
struct gl_program_parameter_list
*params);
+void
+_mesa_associate_uniform_storage(struct gl_context *ctx,
+ struct gl_shader_program *shader_program,
+ struct gl_program_parameter_list *params);
+
+#ifdef __cplusplus
+}
#endif
diff --git a/mesalib/src/mesa/program/prog_parameter.h b/mesalib/src/mesa/program/prog_parameter.h
index a6793d0d8..3c6dc8cf9 100644
--- a/mesalib/src/mesa/program/prog_parameter.h
+++ b/mesalib/src/mesa/program/prog_parameter.h
@@ -35,6 +35,11 @@
#include "prog_statevars.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
/**
* Program parameter flags
*/
@@ -178,4 +183,8 @@ _mesa_num_parameters_of_type(const struct gl_program_parameter_list *list,
gl_register_file type);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* PROG_PARAMETER_H */
diff --git a/mesalib/src/mesa/program/prog_statevars.h b/mesalib/src/mesa/program/prog_statevars.h
index 04af3f4cf..8b731e12b 100644
--- a/mesalib/src/mesa/program/prog_statevars.h
+++ b/mesalib/src/mesa/program/prog_statevars.h
@@ -25,8 +25,15 @@
#ifndef PROG_STATEVARS_H
#define PROG_STATEVARS_H
+
#include "main/glheader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
struct gl_context;
struct gl_program_parameter_list;
@@ -145,4 +152,8 @@ extern void
_mesa_load_tracked_matrices(struct gl_context *ctx);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* PROG_STATEVARS_H */
diff --git a/mesalib/src/mesa/program/prog_uniform.c b/mesalib/src/mesa/program/prog_uniform.c
deleted file mode 100644
index d0b25e5c5..000000000
--- a/mesalib/src/mesa/program/prog_uniform.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.1
- *
- * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file prog_uniform.c
- * Shader uniform functions.
- * \author Brian Paul
- */
-
-#include "main/imports.h"
-#include "main/mtypes.h"
-#include "prog_uniform.h"
-
-
-struct gl_uniform_list *
-_mesa_new_uniform_list(void)
-{
- return CALLOC_STRUCT(gl_uniform_list);
-}
-
-
-void
-_mesa_free_uniform_list(struct gl_uniform_list *list)
-{
- GLuint i;
-
- if (!list)
- return;
-
- for (i = 0; i < list->NumUniforms; i++) {
- free((void *) list->Uniforms[i].Name);
- }
- free(list->Uniforms);
- free(list);
-}
-
-
-/**
- * Return the location/index of the named uniform in the uniform list,
- * or -1 if not found.
- */
-GLint
-_mesa_lookup_uniform(const struct gl_uniform_list *list, const char *name)
-{
- GLuint i;
- for (i = 0; list && i < list->NumUniforms; i++) {
- if (!strcmp(list->Uniforms[i].Name, name)) {
- return i;
- }
- }
- return -1;
-}
-
-
-GLint
-_mesa_longest_uniform_name(const struct gl_uniform_list *list)
-{
- GLint max = 0;
- GLuint i;
- for (i = 0; list && i < list->NumUniforms; i++) {
- GLint len = (GLint) strlen(list->Uniforms[i].Name);
- if (len > max)
- max = len;
- }
- return max;
-}
-
-
-void
-_mesa_print_uniforms(const struct gl_uniform_list *list)
-{
- GLuint i;
- printf("Uniform list %p:\n", (void *) list);
- for (i = 0; i < list->NumUniforms; i++) {
- printf("%d: %s %d %d %d\n",
- i,
- list->Uniforms[i].Name,
- list->Uniforms[i].VertPos,
- list->Uniforms[i].FragPos,
- list->Uniforms[i].GeomPos);
- }
-}
diff --git a/mesalib/src/mesa/program/prog_uniform.h b/mesalib/src/mesa/program/prog_uniform.h
deleted file mode 100644
index 83cd30780..000000000
--- a/mesalib/src/mesa/program/prog_uniform.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.1
- *
- * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file prog_uniform.c
- * Shader uniform functions.
- * \author Brian Paul
- */
-
-#ifndef PROG_UNIFORM_H
-#define PROG_UNIFORM_H
-
-#include "main/glheader.h"
-
-
-/**
- * Shader program uniform variable.
- * The glGetUniformLocation() and glUniform() commands will use this
- * information.
- * Note that a uniform such as "binormal" might be used in both the
- * vertex shader and the fragment shader. When glUniform() is called to
- * set the uniform's value, it must be updated in both the vertex and
- * fragment shaders. The uniform may be in different locations in the
- * two shaders so we keep track of that here.
- */
-struct gl_uniform
-{
- const char *Name; /**< Null-terminated string */
- GLint VertPos;
- GLint FragPos;
- GLint GeomPos;
- GLboolean Initialized; /**< For debug. Has this uniform been set? */
- const struct glsl_type *Type;
-};
-
-
-/**
- * List of gl_uniforms
- */
-struct gl_uniform_list
-{
- GLuint Size; /**< allocated size of Uniforms array */
- GLuint NumUniforms; /**< number of uniforms in the array */
- struct gl_uniform *Uniforms; /**< Array [Size] */
-};
-
-
-extern struct gl_uniform_list *
-_mesa_new_uniform_list(void);
-
-extern void
-_mesa_free_uniform_list(struct gl_uniform_list *list);
-
-extern GLint
-_mesa_lookup_uniform(const struct gl_uniform_list *list, const char *name);
-
-extern GLint
-_mesa_longest_uniform_name(const struct gl_uniform_list *list);
-
-extern void
-_mesa_print_uniforms(const struct gl_uniform_list *list);
-
-
-#endif /* PROG_UNIFORM_H */
diff --git a/mesalib/src/mesa/program/sampler.cpp b/mesalib/src/mesa/program/sampler.cpp
index 3b459d59c..e3641aaa9 100644
--- a/mesalib/src/mesa/program/sampler.cpp
+++ b/mesalib/src/mesa/program/sampler.cpp
@@ -27,6 +27,8 @@
#include "glsl_types.h"
#include "ir_visitor.h"
#include "../glsl/program.h"
+#include "program/hash_table.h"
+#include "ir_uniform.h"
extern "C" {
#include "main/compiler.h"
@@ -110,17 +112,13 @@ _mesa_get_sampler_uniform_value(class ir_dereference *sampler,
sampler->accept(&getname);
- GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1,
- getname.name);
-
- if (index < 0) {
+ unsigned location;
+ if (!shader_program->UniformHash->get(location, getname.name)) {
linker_error(shader_program,
"failed to find sampler named %s.\n", getname.name);
return 0;
}
- index += getname.offset;
-
- return prog->Parameters->ParameterValues[index][0].f;
+ return shader_program->UniformStorage[location].sampler + getname.offset;
}
}
diff --git a/mesalib/src/mesa/sources.mak b/mesalib/src/mesa/sources.mak
index 6e327a472..b804a95cc 100644
--- a/mesalib/src/mesa/sources.mak
+++ b/mesalib/src/mesa/sources.mak
@@ -261,7 +261,6 @@ PROGRAM_SOURCES = \
program/prog_parameter_layout.c \
program/prog_print.c \
program/prog_statevars.c \
- program/prog_uniform.c \
program/programopt.c \
program/register_allocate.c \
program/symbol_table.c
diff --git a/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c b/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c
index aab7444e2..adac92f2c 100644
--- a/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c
+++ b/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c
@@ -115,6 +115,11 @@ st_bufferobj_subdata(struct gl_context *ctx,
if (!data)
return;
+ if (!st_obj->buffer) {
+ /* we probably ran out of memory during buffer allocation */
+ return;
+ }
+
/* Now that transfers are per-context, we don't have to figure out
* flushing here. Usually drivers won't need to flush in this case
* even if the buffer is currently referenced by hardware - they
@@ -146,6 +151,11 @@ st_bufferobj_get_subdata(struct gl_context *ctx,
if (!size)
return;
+ if (!st_obj->buffer) {
+ /* we probably ran out of memory during buffer allocation */
+ return;
+ }
+
pipe_buffer_read(st_context(ctx)->pipe, st_obj->buffer,
offset, size, data);
}
@@ -216,6 +226,8 @@ st_bufferobj_data(struct gl_context *ctx,
pipe_usage, size);
if (!st_obj->buffer) {
+ /* out of memory */
+ st_obj->Base.Size = 0;
return GL_FALSE;
}
diff --git a/mesalib/src/mesa/state_tracker/st_cb_clear.c b/mesalib/src/mesa/state_tracker/st_cb_clear.c
index 19a87aae2..89273e28e 100644
--- a/mesalib/src/mesa/state_tracker/st_cb_clear.c
+++ b/mesalib/src/mesa/state_tracker/st_cb_clear.c
@@ -165,6 +165,11 @@ draw_quad(struct st_context *st,
max_slots * sizeof(st->clear.vertices));
}
+ if (!st->clear.vbuf) {
+ /* ran out of memory */
+ return;
+ }
+
/* positions */
st->clear.vertices[0][0][0] = x0;
st->clear.vertices[0][0][1] = y0;
diff --git a/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c b/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c
index 1c44d0d87..5714d343d 100644
--- a/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c
+++ b/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c
@@ -1135,10 +1135,10 @@ st_DrawPixels(struct gl_context *ctx, GLint x, GLint y,
assert(0);
}
- sv[1] = st_create_texture_sampler_view_format(st->pipe, pt,
+ sv[1] = st_create_texture_sampler_view_format(st->pipe, pt,
stencil_format);
- num_sampler_view++;
- }
+ num_sampler_view++;
+ }
draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
width, height,
@@ -1638,9 +1638,9 @@ st_destroy_drawpix(struct st_context *st)
st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL);
if (st->drawpix.vert_shaders[0])
- ureg_free_tokens(st->drawpix.vert_shaders[0]);
+ cso_delete_vertex_shader(st->cso_context, st->drawpix.vert_shaders[0]);
if (st->drawpix.vert_shaders[1])
- ureg_free_tokens(st->drawpix.vert_shaders[1]);
+ cso_delete_vertex_shader(st->cso_context, st->drawpix.vert_shaders[1]);
}
#endif /* FEATURE_drawpix */
diff --git a/mesalib/src/mesa/state_tracker/st_cb_fbo.c b/mesalib/src/mesa/state_tracker/st_cb_fbo.c
index 6da65d7b9..e04cb4406 100644
--- a/mesalib/src/mesa/state_tracker/st_cb_fbo.c
+++ b/mesalib/src/mesa/state_tracker/st_cb_fbo.c
@@ -630,6 +630,62 @@ st_ReadBuffer(struct gl_context *ctx, GLenum buffer)
}
+
+/**
+ * Called via ctx->Driver.MapRenderbuffer.
+ */
+static void
+st_MapRenderbuffer(struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint x, GLuint y, GLuint w, GLuint h,
+ GLbitfield mode,
+ GLubyte **mapOut, GLint *rowStrideOut)
+{
+ struct st_context *st = st_context(ctx);
+ struct st_renderbuffer *strb = st_renderbuffer(rb);
+ struct pipe_context *pipe = st->pipe;
+ unsigned usage;
+
+ usage = 0x0;
+ if (mode & GL_MAP_READ_BIT)
+ usage |= PIPE_TRANSFER_READ;
+ if (mode & GL_MAP_WRITE_BIT)
+ usage |= PIPE_TRANSFER_WRITE;
+
+ strb->transfer = pipe_get_transfer(pipe,
+ strb->texture,
+ strb->rtt_level,
+ strb->rtt_face + strb->rtt_slice,
+ usage, x, y, w, h);
+ if (strb->transfer) {
+ *mapOut = pipe_transfer_map(pipe, strb->transfer);
+ *rowStrideOut = strb->transfer->stride;
+ }
+ else {
+ *mapOut = NULL;
+ *rowStrideOut = 0;
+ }
+}
+
+
+/**
+ * Called via ctx->Driver.UnmapRenderbuffer.
+ */
+static void
+st_UnmapRenderbuffer(struct gl_context *ctx,
+ struct gl_renderbuffer *rb)
+{
+ struct st_context *st = st_context(ctx);
+ struct st_renderbuffer *strb = st_renderbuffer(rb);
+ struct pipe_context *pipe = st->pipe;
+
+ pipe_transfer_unmap(pipe, strb->transfer);
+ pipe->transfer_destroy(pipe, strb->transfer);
+ strb->transfer = NULL;
+}
+
+
+
void st_init_fbo_functions(struct dd_function_table *functions)
{
#if FEATURE_EXT_framebuffer_object
@@ -647,6 +703,9 @@ void st_init_fbo_functions(struct dd_function_table *functions)
functions->DrawBuffers = st_DrawBuffers;
functions->ReadBuffer = st_ReadBuffer;
+
+ functions->MapRenderbuffer = st_MapRenderbuffer;
+ functions->UnmapRenderbuffer = st_UnmapRenderbuffer;
}
diff --git a/mesalib/src/mesa/state_tracker/st_cb_fbo.h b/mesalib/src/mesa/state_tracker/st_cb_fbo.h
index 1afa3fe6e..1be017314 100644
--- a/mesalib/src/mesa/state_tracker/st_cb_fbo.h
+++ b/mesalib/src/mesa/state_tracker/st_cb_fbo.h
@@ -51,6 +51,8 @@ struct st_renderbuffer
enum pipe_format format; /** preferred format, or PIPE_FORMAT_NONE */
GLboolean defined; /**< defined contents? */
+ struct pipe_transfer *transfer; /**< only used when mapping the resource */
+
/**
* Used only when hardware accumulation buffers are not supported.
*/
diff --git a/mesalib/src/mesa/state_tracker/st_draw.c b/mesalib/src/mesa/state_tracker/st_draw.c
index ff3008a5f..f2fbf4836 100644
--- a/mesalib/src/mesa/state_tracker/st_draw.c
+++ b/mesalib/src/mesa/state_tracker/st_draw.c
@@ -45,7 +45,6 @@
#include "main/bufferobj.h"
#include "main/macros.h"
#include "main/mfeatures.h"
-#include "program/prog_uniform.h"
#include "vbo/vbo.h"
@@ -64,6 +63,8 @@
#include "draw/draw_context.h"
#include "cso_cache/cso_context.h"
+#include "../glsl/ir_uniform.h"
+
static GLuint double_types[4] = {
PIPE_FORMAT_R64_FLOAT,
@@ -338,8 +339,9 @@ is_interleaved_arrays(const struct st_vertex_program *vp,
* or all live in user space.
* \param vbuffer returns vertex buffer info
* \param velements returns vertex element info
+ * \return GL_TRUE for success, GL_FALSE otherwise (probably out of memory)
*/
-static void
+static GLboolean
setup_interleaved_attribs(struct gl_context *ctx,
const struct st_vertex_program *vp,
const struct st_vp_variant *vpv,
@@ -434,6 +436,11 @@ setup_interleaved_attribs(struct gl_context *ctx,
/* all interleaved arrays in a VBO */
struct st_buffer_object *stobj = st_buffer_object(bufobj);
+ if (!stobj) {
+ /* probably out of memory */
+ return GL_FALSE;
+ }
+
vbuffer->buffer = NULL;
pipe_resource_reference(&vbuffer->buffer, stobj->buffer);
vbuffer->buffer_offset = pointer_to_offset(low_addr);
@@ -455,6 +462,8 @@ setup_interleaved_attribs(struct gl_context *ctx,
st->user_attrib[0].stride = stride;
st->num_user_attribs = 1;
}
+
+ return GL_TRUE;
}
@@ -463,8 +472,9 @@ setup_interleaved_attribs(struct gl_context *ctx,
* vertex attribute.
* \param vbuffer returns vertex buffer info
* \param velements returns vertex element info
+ * \return GL_TRUE for success, GL_FALSE otherwise (probably out of memory)
*/
-static void
+static GLboolean
setup_non_interleaved_attribs(struct gl_context *ctx,
const struct st_vertex_program *vp,
const struct st_vp_variant *vpv,
@@ -493,7 +503,11 @@ setup_non_interleaved_attribs(struct gl_context *ctx,
* really an offset from the start of the VBO, not a pointer.
*/
struct st_buffer_object *stobj = st_buffer_object(bufobj);
- assert(stobj->buffer);
+
+ if (!stobj || !stobj->buffer) {
+ /* probably ran out of memory */
+ return GL_FALSE;
+ }
vbuffer[attr].buffer = NULL;
pipe_resource_reference(&vbuffer[attr].buffer, stobj->buffer);
@@ -533,6 +547,11 @@ setup_non_interleaved_attribs(struct gl_context *ctx,
st->user_attrib[attr].element_size = element_size;
st->user_attrib[attr].stride = stride;
st->num_user_attribs = MAX2(st->num_user_attribs, attr + 1);
+
+ if (!vbuffer[attr].buffer) {
+ /* probably ran out of memory */
+ return GL_FALSE;
+ }
}
/* common-case setup */
@@ -547,6 +566,8 @@ setup_non_interleaved_attribs(struct gl_context *ctx,
array->Normalized);
assert(velements[attr].src_format);
}
+
+ return GL_TRUE;
}
@@ -616,12 +637,12 @@ check_uniforms(struct gl_context *ctx)
if (shProg[j] == NULL || !shProg[j]->LinkStatus)
continue;
- for (i = 0; i < shProg[j]->Uniforms->NumUniforms; i++) {
- const struct gl_uniform *u = &shProg[j]->Uniforms->Uniforms[i];
- if (!u->Initialized) {
+ for (i = 0; i < shProg[j]->NumUserUniformStorage; i++) {
+ const struct gl_uniform_storage *u = &shProg[j]->UniformStorage[i];
+ if (!u->initialized) {
_mesa_warning(ctx,
"Using shader with uninitialized uniform: %s",
- u->Name);
+ u->name);
}
}
}
@@ -775,7 +796,11 @@ translate_prim(const struct gl_context *ctx, unsigned prim)
}
-static void
+/**
+ * Setup vertex arrays and buffers prior to drawing.
+ * \return GL_TRUE for success, GL_FALSE otherwise (probably out of memory)
+ */
+static GLboolean
st_validate_varrays(struct gl_context *ctx,
const struct gl_client_array **arrays,
unsigned max_index,
@@ -806,8 +831,10 @@ st_validate_varrays(struct gl_context *ctx,
* Setup the vbuffer[] and velements[] arrays.
*/
if (is_interleaved_arrays(vp, vpv, arrays)) {
- setup_interleaved_attribs(ctx, vp, vpv, arrays, vbuffer, velements,
- max_index, num_instances);
+ if (!setup_interleaved_attribs(ctx, vp, vpv, arrays, vbuffer, velements,
+ max_index, num_instances)) {
+ return GL_FALSE;
+ }
num_vbuffers = 1;
num_velements = vpv->num_inputs;
@@ -815,9 +842,12 @@ st_validate_varrays(struct gl_context *ctx,
num_vbuffers = 0;
}
else {
- setup_non_interleaved_attribs(ctx, vp, vpv, arrays,
- vbuffer, velements, max_index,
- num_instances);
+ if (!setup_non_interleaved_attribs(ctx, vp, vpv, arrays,
+ vbuffer, velements, max_index,
+ num_instances)) {
+ return GL_FALSE;
+ }
+
num_vbuffers = vpv->num_inputs;
num_velements = vpv->num_inputs;
}
@@ -832,6 +862,8 @@ st_validate_varrays(struct gl_context *ctx,
pipe_resource_reference(&vbuffer[attr].buffer, NULL);
assert(!vbuffer[attr].buffer);
}
+
+ return GL_TRUE;
}
@@ -901,7 +933,10 @@ st_draw_vbo(struct gl_context *ctx,
st_validate_state(st);
if (new_array) {
- st_validate_varrays(ctx, arrays, max_index, num_instances);
+ if (!st_validate_varrays(ctx, arrays, max_index, num_instances)) {
+ /* probably out of memory, no-op the draw call */
+ return;
+ }
}
#if 0
diff --git a/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
index 529f5f64a..b133164c3 100644
--- a/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
+++ b/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
@@ -53,7 +53,6 @@ extern "C" {
#include "program/prog_optimize.h"
#include "program/prog_print.h"
#include "program/program.h"
-#include "program/prog_uniform.h"
#include "program/prog_parameter.h"
#include "program/sampler.h"
@@ -2984,12 +2983,12 @@ set_uniform_initializer(struct gl_context *ctx, void *mem_ctx,
element_type->matrix_columns,
element_type->vector_elements,
loc, 1, GL_FALSE, (GLfloat *)values);
- loc += element_type->matrix_columns;
} else {
_mesa_uniform(ctx, shader_program, loc, element_type->matrix_columns,
values, element_type->gl_type);
- loc += type_size(element_type);
}
+
+ loc++;
}
}
@@ -5004,6 +5003,15 @@ get_mesa_program(struct gl_context *ctx,
_mesa_reference_program(ctx, &shader->Program, prog);
+ /* This has to be done last. Any operation the can cause
+ * prog->ParameterValues to get reallocated (e.g., anything that adds a
+ * program constant) has to happen before creating this linkage.
+ */
+ _mesa_associate_uniform_storage(ctx, shader_program, prog->Parameters);
+ if (!shader_program->LinkStatus) {
+ return NULL;
+ }
+
struct st_vertex_program *stvp;
struct st_fragment_program *stfp;
struct st_geometry_program *stgp;
diff --git a/mesalib/src/mesa/state_tracker/st_program.c b/mesalib/src/mesa/state_tracker/st_program.c
index 146e77f9d..e03157940 100644
--- a/mesalib/src/mesa/state_tracker/st_program.c
+++ b/mesalib/src/mesa/state_tracker/st_program.c
@@ -416,7 +416,9 @@ st_get_vp_variant(struct st_context *st,
return vpv;
}
-static int st_translate_interp(enum glsl_interp_qualifier glsl_qual)
+
+static unsigned
+st_translate_interp(enum glsl_interp_qualifier glsl_qual)
{
switch (glsl_qual) {
case INTERP_QUALIFIER_NONE:
@@ -426,11 +428,13 @@ static int st_translate_interp(enum glsl_interp_qualifier glsl_qual)
return TGSI_INTERPOLATE_CONSTANT;
case INTERP_QUALIFIER_NOPERSPECTIVE:
return TGSI_INTERPOLATE_LINEAR;
+ default:
+ assert(0 && "unexpected interp mode in st_translate_interp()");
+ return TGSI_INTERPOLATE_PERSPECTIVE;
}
- assert(0);
- return TGSI_INTERPOLATE_PERSPECTIVE;
}
+
/**
* Translate a Mesa fragment shader into a TGSI shader using extra info in
* the key.
@@ -632,8 +636,10 @@ st_translate_fragment_program(struct st_context *st,
}
ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
- if (ureg == NULL)
+ if (ureg == NULL) {
+ FREE(variant);
return NULL;
+ }
if (ST_DEBUG & DEBUG_MESA) {
_mesa_print_program(&stfp->Base.Base);
diff --git a/mesalib/src/mesa/swrast/s_context.c b/mesalib/src/mesa/swrast/s_context.c
index 9112cf30d..98702f068 100644
--- a/mesalib/src/mesa/swrast/s_context.c
+++ b/mesalib/src/mesa/swrast/s_context.c
@@ -249,7 +249,9 @@ _swrast_update_fog_state( struct gl_context *ctx )
SWcontext *swrast = SWRAST_CONTEXT(ctx);
const struct gl_fragment_program *fp = ctx->FragmentProgram._Current;
- assert((fp == NULL) || (fp->Base.Target == GL_FRAGMENT_PROGRAM_ARB));
+ assert((fp == NULL) ||
+ (fp->Base.Target == GL_FRAGMENT_PROGRAM_ARB) ||
+ (fp->Base.Target == GL_FRAGMENT_PROGRAM_NV));
/* determine if fog is needed, and if so, which fog mode */
swrast->_FogEnabled = (fp == NULL && ctx->Fog.Enabled);