diff options
76 files changed, 3756 insertions, 2668 deletions
diff --git a/libX11/include/X11/Xlibint.h b/libX11/include/X11/Xlibint.h index 2ce356d15..80edeec9a 100644 --- a/libX11/include/X11/Xlibint.h +++ b/libX11/include/X11/Xlibint.h @@ -420,6 +420,30 @@ extern LockInfoPtr _Xglobal_lock; #define WORD64ALIGN #endif /* WORD64 */ +/** + * Return a len-sized request buffer for the request type. This function may + * flush the output queue. + * + * @param dpy The display connection + * @param type The request type + * @param len Length of the request in bytes + * + * @returns A pointer to the request buffer with a few default values + * initialized. + */ +extern void *_XGetRequest(Display *dpy, CARD8 type, size_t len); + +/* GetReqSized is the same as GetReq but allows the caller to specify the + * size in bytes. 'sz' must be a multiple of 4! */ + +#if !defined(UNIXCPP) || defined(ANSICPP) +#define GetReqSized(name, sz, req) \ + req = (x##name##Req *) _XGetRequest(dpy, X_##name, sz) +#else +#define GetReqSized(name, sz, req) \ + req = (x/**/name/**/Req *) _XGetRequest(dpy, X_/**/name, sz) +#endif + /* * GetReq - Get the next available X request packet in the buffer and @@ -432,25 +456,10 @@ extern LockInfoPtr _Xglobal_lock; #if !defined(UNIXCPP) || defined(ANSICPP) #define GetReq(name, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(x##name##Req)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (x##name##Req *)(dpy->last_req = dpy->bufptr);\ - req->reqType = X_##name;\ - req->length = (SIZEOF(x##name##Req))>>2;\ - dpy->bufptr += SIZEOF(x##name##Req);\ - dpy->request++ - + GetReqSized(name, SIZEOF(x##name##Req), req) #else /* non-ANSI C uses empty comment instead of "##" for token concatenation */ #define GetReq(name, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(x/**/name/**/Req)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (x/**/name/**/Req *)(dpy->last_req = dpy->bufptr);\ - req->reqType = X_/**/name;\ - req->length = (SIZEOF(x/**/name/**/Req))>>2;\ - dpy->bufptr += SIZEOF(x/**/name/**/Req);\ - dpy->request++ + GetReqSized(name, SIZEOF(x/**/name/**/Req), req) #endif /* GetReqExtra is the same as GetReq, but allocates "n" additional @@ -458,24 +467,10 @@ extern LockInfoPtr _Xglobal_lock; #if !defined(UNIXCPP) || defined(ANSICPP) #define GetReqExtra(name, n, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(x##name##Req) + n) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (x##name##Req *)(dpy->last_req = dpy->bufptr);\ - req->reqType = X_##name;\ - req->length = (SIZEOF(x##name##Req) + n)>>2;\ - dpy->bufptr += SIZEOF(x##name##Req) + n;\ - dpy->request++ + GetReqSized(name, SIZEOF(x##name##Req) + n, req) #else #define GetReqExtra(name, n, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(x/**/name/**/Req) + n) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (x/**/name/**/Req *)(dpy->last_req = dpy->bufptr);\ - req->reqType = X_/**/name;\ - req->length = (SIZEOF(x/**/name/**/Req) + n)>>2;\ - dpy->bufptr += SIZEOF(x/**/name/**/Req) + n;\ - dpy->request++ + GetReqSized(name, SIZEOF(x/**/name/**/Req) + n, req) #endif @@ -487,26 +482,12 @@ extern LockInfoPtr _Xglobal_lock; #if !defined(UNIXCPP) || defined(ANSICPP) #define GetResReq(name, rid, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(xResourceReq)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (xResourceReq *) (dpy->last_req = dpy->bufptr);\ - req->reqType = X_##name;\ - req->length = 2;\ - req->id = (rid);\ - dpy->bufptr += SIZEOF(xResourceReq);\ - dpy->request++ + req = (xResourceReq *) _XGetRequest(dpy, X_##name, SIZEOF(xResourceReq)); \ + req->id = (rid) #else #define GetResReq(name, rid, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(xResourceReq)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (xResourceReq *) (dpy->last_req = dpy->bufptr);\ - req->reqType = X_/**/name;\ - req->length = 2;\ - req->id = (rid);\ - dpy->bufptr += SIZEOF(xResourceReq);\ - dpy->request++ + req = (xResourceReq *) _XGetRequest(dpy, X_/**/name, SIZEOF(xResourceReq)); \ + req->id = (rid) #endif /* @@ -515,24 +496,10 @@ extern LockInfoPtr _Xglobal_lock; */ #if !defined(UNIXCPP) || defined(ANSICPP) #define GetEmptyReq(name, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(xReq)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (xReq *) (dpy->last_req = dpy->bufptr);\ - req->reqType = X_##name;\ - req->length = 1;\ - dpy->bufptr += SIZEOF(xReq);\ - dpy->request++ + req = (xReq *) _XGetRequest(dpy, X_##name, SIZEOF(xReq)) #else #define GetEmptyReq(name, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(xReq)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (xReq *) (dpy->last_req = dpy->bufptr);\ - req->reqType = X_/**/name;\ - req->length = 1;\ - dpy->bufptr += SIZEOF(xReq);\ - dpy->request++ + req = (xReq *) _XGetRequest(dpy, X_/**/name, SIZEOF(xReq)) #endif #ifdef WORD64 diff --git a/libX11/src/XlibInt.c b/libX11/src/XlibInt.c index 3db151e29..a8f5d0844 100644 --- a/libX11/src/XlibInt.c +++ b/libX11/src/XlibInt.c @@ -1956,6 +1956,37 @@ Screen *_XScreenOfWindow(Display *dpy, Window w) } +/* + * WARNING: This implementation's pre-conditions and post-conditions + * must remain compatible with the old macro-based implementations of + * GetReq, GetReqExtra, GetResReq, and GetEmptyReq. The portions of the + * Display structure affected by those macros are part of libX11's + * ABI. + */ +void *_XGetRequest(Display *dpy, CARD8 type, size_t len) +{ + xReq *req; + + WORD64ALIGN + + if (dpy->bufptr + len > dpy->bufmax) + _XFlush(dpy); + + if (len % 4) + fprintf(stderr, + "Xlib: request %d length %zd not a multiple of 4.\n", + type, len); + + dpy->last_req = dpy->bufptr; + + req = (xReq*)dpy->bufptr; + req->reqType = type; + req->length = len / 4; + dpy->bufptr += len; + dpy->request++; + return req; +} + #if defined(WIN32) /* 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 9fe6c4125..d899bc62a 100644 --- a/mesalib/src/glsl/ast.h +++ b/mesalib/src/glsl/ast.h @@ -629,13 +629,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, @@ -654,8 +719,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 1f3404c9d..dd932951f 100644 --- a/mesalib/src/glsl/glsl_parser_extras.h +++ b/mesalib/src/glsl/glsl_parser_extras.h @@ -149,8 +149,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 b9351d146..f6854754b 100644 --- a/mesalib/src/mapi/glapi/glapi.h +++ b/mesalib/src/mapi/glapi/glapi.h @@ -44,10 +44,14 @@ #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 */ @@ -75,8 +79,6 @@ extern "C" { #define _glapi_Context _mglapi_Context #endif -#include "glapi/glthread.h" - typedef void (*_glapi_proc)(void); struct _glapi_table; @@ -180,6 +182,7 @@ _glapi_noop_enable_warnings(unsigned char enable); _GLAPI_EXPORT void _glapi_set_warning_func(_glapi_proc func); + #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, ¶mPos)) { - _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 17c060059..49cdc3088 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 941d28a4c..bcf65df7d 100644 --- a/mesalib/src/mesa/program/hash_table.h +++ b/mesalib/src/mesa/program/hash_table.h @@ -37,16 +37,17 @@ #include <limits.h> #include <assert.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 * @@ -214,6 +215,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, + ¶ms->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); diff --git a/pixman/demos/composite-test.c b/pixman/demos/composite-test.c index 79d5d5eac..bba90c522 100644 --- a/pixman/demos/composite-test.c +++ b/pixman/demos/composite-test.c @@ -1,191 +1,191 @@ -#include <gtk/gtk.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "pixman.h"
-#include "gtk-utils.h"
-
-#define WIDTH 60
-#define HEIGHT 60
-
-typedef struct {
- const char *name;
- pixman_op_t op;
-} operator_t;
-
-static const operator_t operators[] = {
- { "CLEAR", PIXMAN_OP_CLEAR },
- { "SRC", PIXMAN_OP_SRC },
- { "DST", PIXMAN_OP_DST },
- { "OVER", PIXMAN_OP_OVER },
- { "OVER_REVERSE", PIXMAN_OP_OVER_REVERSE },
- { "IN", PIXMAN_OP_IN },
- { "IN_REVERSE", PIXMAN_OP_IN_REVERSE },
- { "OUT", PIXMAN_OP_OUT },
- { "OUT_REVERSE", PIXMAN_OP_OUT_REVERSE },
- { "ATOP", PIXMAN_OP_ATOP },
- { "ATOP_REVERSE", PIXMAN_OP_ATOP_REVERSE },
- { "XOR", PIXMAN_OP_XOR },
- { "ADD", PIXMAN_OP_ADD },
- { "SATURATE", PIXMAN_OP_SATURATE },
-
- { "MULTIPLY", PIXMAN_OP_MULTIPLY },
- { "SCREEN", PIXMAN_OP_SCREEN },
- { "OVERLAY", PIXMAN_OP_OVERLAY },
- { "DARKEN", PIXMAN_OP_DARKEN },
- { "LIGHTEN", PIXMAN_OP_LIGHTEN },
- { "COLOR_DODGE", PIXMAN_OP_COLOR_DODGE },
- { "COLOR_BURN", PIXMAN_OP_COLOR_BURN },
- { "HARD_LIGHT", PIXMAN_OP_HARD_LIGHT },
- { "SOFT_LIGHT", PIXMAN_OP_SOFT_LIGHT },
- { "DIFFERENCE", PIXMAN_OP_DIFFERENCE },
- { "EXCLUSION", PIXMAN_OP_EXCLUSION },
- { "HSL_HUE", PIXMAN_OP_HSL_HUE },
- { "HSL_SATURATION", PIXMAN_OP_HSL_SATURATION },
- { "HSL_COLOR", PIXMAN_OP_HSL_COLOR },
- { "HSL_LUMINOSITY", PIXMAN_OP_HSL_LUMINOSITY },
-};
-
-static uint32_t
-reader (const void *src, int size)
-{
- switch (size)
- {
- case 1:
- return *(uint8_t *)src;
- case 2:
- return *(uint16_t *)src;
- case 4:
- return *(uint32_t *)src;
- default:
- g_assert_not_reached();
- }
-}
-
-static void
-writer (void *src, uint32_t value, int size)
-{
- switch (size)
- {
- case 1:
- *(uint8_t *)src = value;
- break;
-
- case 2:
- *(uint16_t *)src = value;
- break;
-
- case 4:
- *(uint32_t *)src = value;
- break;
-
- default:
- break;
- }
-}
-
-int
-main (int argc, char **argv)
-{
-#define d2f pixman_double_to_fixed
-
- GtkWidget *window, *swindow;
- GtkWidget *table;
- uint32_t *dest = malloc (WIDTH * HEIGHT * 4);
- uint32_t *src = malloc (WIDTH * HEIGHT * 4);
- pixman_image_t *src_img;
- pixman_image_t *dest_img;
- pixman_point_fixed_t p1 = { -10 << 0, 0 };
- pixman_point_fixed_t p2 = { WIDTH << 16, (HEIGHT - 10) << 16 };
- uint16_t full = 0xcfff;
- uint16_t low = 0x5000;
- uint16_t alpha = 0xffff;
- pixman_gradient_stop_t stops[6] =
- {
- { d2f (0.0), { full, low, low, alpha } },
- { d2f (0.25), { full, full, low, alpha } },
- { d2f (0.4), { low, full, low, alpha } },
- { d2f (0.6), { low, full, full, alpha } },
- { d2f (0.8), { low, low, full, alpha } },
- { d2f (1.0), { full, low, full, alpha } },
- };
-
- int i;
-
- gtk_init (&argc, &argv);
-
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-
- gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
-
- g_signal_connect (window, "delete-event",
- G_CALLBACK (gtk_main_quit),
- NULL);
- table = gtk_table_new (G_N_ELEMENTS (operators) / 6, 6, TRUE);
-
- src_img = pixman_image_create_linear_gradient (&p1, &p2, stops,
- sizeof (stops) / sizeof (stops[0]));
-
- pixman_image_set_repeat (src_img, PIXMAN_REPEAT_PAD);
-
- dest_img = pixman_image_create_bits (PIXMAN_a8r8g8b8,
- WIDTH, HEIGHT,
- dest,
- WIDTH * 4);
- pixman_image_set_accessors (dest_img, reader, writer);
-
- for (i = 0; i < G_N_ELEMENTS (operators); ++i)
- {
- GtkWidget *image;
- GdkPixbuf *pixbuf;
- GtkWidget *vbox;
- GtkWidget *label;
- int j, k;
-
- vbox = gtk_vbox_new (FALSE, 0);
-
- label = gtk_label_new (operators[i].name);
- gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 6);
- gtk_widget_show (label);
-
- for (j = 0; j < HEIGHT; ++j)
- {
- for (k = 0; k < WIDTH; ++k)
- dest[j * WIDTH + k] = 0x7f6f6f00;
- }
- pixman_image_composite (operators[i].op, src_img, NULL, dest_img,
- 0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
- pixbuf = pixbuf_from_argb32 (pixman_image_get_data (dest_img), TRUE,
- WIDTH, HEIGHT, WIDTH * 4);
- image = gtk_image_new_from_pixbuf (pixbuf);
- gtk_box_pack_start (GTK_BOX (vbox), image, FALSE, FALSE, 0);
- gtk_widget_show (image);
-
- gtk_table_attach_defaults (GTK_TABLE (table), vbox,
- i % 6, (i % 6) + 1, i / 6, (i / 6) + 1);
- gtk_widget_show (vbox);
-
- g_object_unref (pixbuf);
- }
-
- pixman_image_unref (src_img);
- free (src);
- pixman_image_unref (dest_img);
- free (dest);
-
- swindow = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC);
-
- gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (swindow), table);
- gtk_widget_show (table);
-
- gtk_container_add (GTK_CONTAINER (window), swindow);
- gtk_widget_show (swindow);
-
- gtk_widget_show (window);
-
- gtk_main ();
-
- return 0;
-}
+#include <gtk/gtk.h> +#include <stdlib.h> +#include <stdio.h> +#include "pixman.h" +#include "gtk-utils.h" + +#define WIDTH 60 +#define HEIGHT 60 + +typedef struct { + const char *name; + pixman_op_t op; +} operator_t; + +static const operator_t operators[] = { + { "CLEAR", PIXMAN_OP_CLEAR }, + { "SRC", PIXMAN_OP_SRC }, + { "DST", PIXMAN_OP_DST }, + { "OVER", PIXMAN_OP_OVER }, + { "OVER_REVERSE", PIXMAN_OP_OVER_REVERSE }, + { "IN", PIXMAN_OP_IN }, + { "IN_REVERSE", PIXMAN_OP_IN_REVERSE }, + { "OUT", PIXMAN_OP_OUT }, + { "OUT_REVERSE", PIXMAN_OP_OUT_REVERSE }, + { "ATOP", PIXMAN_OP_ATOP }, + { "ATOP_REVERSE", PIXMAN_OP_ATOP_REVERSE }, + { "XOR", PIXMAN_OP_XOR }, + { "ADD", PIXMAN_OP_ADD }, + { "SATURATE", PIXMAN_OP_SATURATE }, + + { "MULTIPLY", PIXMAN_OP_MULTIPLY }, + { "SCREEN", PIXMAN_OP_SCREEN }, + { "OVERLAY", PIXMAN_OP_OVERLAY }, + { "DARKEN", PIXMAN_OP_DARKEN }, + { "LIGHTEN", PIXMAN_OP_LIGHTEN }, + { "COLOR_DODGE", PIXMAN_OP_COLOR_DODGE }, + { "COLOR_BURN", PIXMAN_OP_COLOR_BURN }, + { "HARD_LIGHT", PIXMAN_OP_HARD_LIGHT }, + { "SOFT_LIGHT", PIXMAN_OP_SOFT_LIGHT }, + { "DIFFERENCE", PIXMAN_OP_DIFFERENCE }, + { "EXCLUSION", PIXMAN_OP_EXCLUSION }, + { "HSL_HUE", PIXMAN_OP_HSL_HUE }, + { "HSL_SATURATION", PIXMAN_OP_HSL_SATURATION }, + { "HSL_COLOR", PIXMAN_OP_HSL_COLOR }, + { "HSL_LUMINOSITY", PIXMAN_OP_HSL_LUMINOSITY }, +}; + +static uint32_t +reader (const void *src, int size) +{ + switch (size) + { + case 1: + return *(uint8_t *)src; + case 2: + return *(uint16_t *)src; + case 4: + return *(uint32_t *)src; + default: + g_assert_not_reached(); + } +} + +static void +writer (void *src, uint32_t value, int size) +{ + switch (size) + { + case 1: + *(uint8_t *)src = value; + break; + + case 2: + *(uint16_t *)src = value; + break; + + case 4: + *(uint32_t *)src = value; + break; + + default: + break; + } +} + +int +main (int argc, char **argv) +{ +#define d2f pixman_double_to_fixed + + GtkWidget *window, *swindow; + GtkWidget *table; + uint32_t *dest = malloc (WIDTH * HEIGHT * 4); + uint32_t *src = malloc (WIDTH * HEIGHT * 4); + pixman_image_t *src_img; + pixman_image_t *dest_img; + pixman_point_fixed_t p1 = { -10 << 0, 0 }; + pixman_point_fixed_t p2 = { WIDTH << 16, (HEIGHT - 10) << 16 }; + uint16_t full = 0xcfff; + uint16_t low = 0x5000; + uint16_t alpha = 0xffff; + pixman_gradient_stop_t stops[6] = + { + { d2f (0.0), { full, low, low, alpha } }, + { d2f (0.25), { full, full, low, alpha } }, + { d2f (0.4), { low, full, low, alpha } }, + { d2f (0.6), { low, full, full, alpha } }, + { d2f (0.8), { low, low, full, alpha } }, + { d2f (1.0), { full, low, full, alpha } }, + }; + + int i; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_window_set_default_size (GTK_WINDOW (window), 800, 600); + + g_signal_connect (window, "delete-event", + G_CALLBACK (gtk_main_quit), + NULL); + table = gtk_table_new (G_N_ELEMENTS (operators) / 6, 6, TRUE); + + src_img = pixman_image_create_linear_gradient (&p1, &p2, stops, + G_N_ELEMENTS (stops)); + + pixman_image_set_repeat (src_img, PIXMAN_REPEAT_PAD); + + dest_img = pixman_image_create_bits (PIXMAN_a8r8g8b8, + WIDTH, HEIGHT, + dest, + WIDTH * 4); + pixman_image_set_accessors (dest_img, reader, writer); + + for (i = 0; i < G_N_ELEMENTS (operators); ++i) + { + GtkWidget *image; + GdkPixbuf *pixbuf; + GtkWidget *vbox; + GtkWidget *label; + int j, k; + + vbox = gtk_vbox_new (FALSE, 0); + + label = gtk_label_new (operators[i].name); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 6); + gtk_widget_show (label); + + for (j = 0; j < HEIGHT; ++j) + { + for (k = 0; k < WIDTH; ++k) + dest[j * WIDTH + k] = 0x7f6f6f00; + } + pixman_image_composite (operators[i].op, src_img, NULL, dest_img, + 0, 0, 0, 0, 0, 0, WIDTH, HEIGHT); + pixbuf = pixbuf_from_argb32 (pixman_image_get_data (dest_img), TRUE, + WIDTH, HEIGHT, WIDTH * 4); + image = gtk_image_new_from_pixbuf (pixbuf); + gtk_box_pack_start (GTK_BOX (vbox), image, FALSE, FALSE, 0); + gtk_widget_show (image); + + gtk_table_attach_defaults (GTK_TABLE (table), vbox, + i % 6, (i % 6) + 1, i / 6, (i / 6) + 1); + gtk_widget_show (vbox); + + g_object_unref (pixbuf); + } + + pixman_image_unref (src_img); + free (src); + pixman_image_unref (dest_img); + free (dest); + + swindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (swindow), table); + gtk_widget_show (table); + + gtk_container_add (GTK_CONTAINER (window), swindow); + gtk_widget_show (swindow); + + gtk_widget_show (window); + + gtk_main (); + + return 0; +} diff --git a/pixman/pixman/pixman-image.c b/pixman/pixman/pixman-image.c index 09d7cbc4e..913853ceb 100644 --- a/pixman/pixman/pixman-image.c +++ b/pixman/pixman/pixman-image.c @@ -145,11 +145,8 @@ _pixman_image_fini (pixman_image_t *image) pixman_region32_fini (&common->clip_region); - if (common->transform) - free (common->transform); - - if (common->filter_params) - free (common->filter_params); + free (common->transform); + free (common->filter_params); if (common->alpha_map) pixman_image_unref ((pixman_image_t *)common->alpha_map); diff --git a/pixman/pixman/pixman-region.c b/pixman/pixman/pixman-region.c index 47beb5238..80219c6ec 100644 --- a/pixman/pixman/pixman-region.c +++ b/pixman/pixman/pixman-region.c @@ -828,8 +828,7 @@ pixman_op (region_type_t * new_reg, /* Place to store result { if (!pixman_rect_alloc (new_reg, new_size)) { - if (old_data) - free (old_data); + free (old_data); return FALSE; } } @@ -1005,8 +1004,7 @@ pixman_op (region_type_t * new_reg, /* Place to store result APPEND_REGIONS (new_reg, r2_band_end, r2_end); } - if (old_data) - free (old_data); + free (old_data); if (!(numRects = new_reg->data->numRects)) { @@ -1027,8 +1025,7 @@ pixman_op (region_type_t * new_reg, /* Place to store result return TRUE; bail: - if (old_data) - free (old_data); + free (old_data); return pixman_break (new_reg); } diff --git a/pixman/test/a1-trap-test.c b/pixman/test/a1-trap-test.c index 6163e7c61..93c6caa14 100644 --- a/pixman/test/a1-trap-test.c +++ b/pixman/test/a1-trap-test.c @@ -2,7 +2,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include "pixman.h" +#include "utils.h" int main (int argc, char **argv) diff --git a/pixman/test/alphamap.c b/pixman/test/alphamap.c index 554b309fb..24a350ed7 100644 --- a/pixman/test/alphamap.c +++ b/pixman/test/alphamap.c @@ -139,8 +139,6 @@ get_alpha (pixman_image_t *image, int x, int y, int orig_x, int orig_y) return r; } -#define ARRAY_LENGTH(A) ((int) (sizeof (A) / sizeof ((A) [0]))) - static int run_test (int s, int d, int sa, int da, int soff, int doff) { diff --git a/pixman/test/blitters-test.c b/pixman/test/blitters-test.c index 4f931c440..55b6c735c 100644 --- a/pixman/test/blitters-test.c +++ b/pixman/test/blitters-test.c @@ -5,7 +5,6 @@ * Script 'fuzzer-find-diff.pl' can be used to narrow down the problem in * the case of test failure. */ -#include <assert.h> #include <stdlib.h> #include <stdio.h> #include "utils.h" @@ -281,7 +280,7 @@ test_composite (int testnum, int verbose) lcg_srand (testnum); - op = op_list[lcg_rand_n (sizeof (op_list) / sizeof (op_list[0]))]; + op = op_list[lcg_rand_n (ARRAY_LENGTH (op_list))]; if (lcg_rand_n (8)) { diff --git a/pixman/test/composite-traps-test.c b/pixman/test/composite-traps-test.c index fa6d8a988..ff03b50d9 100644 --- a/pixman/test/composite-traps-test.c +++ b/pixman/test/composite-traps-test.c @@ -1,6 +1,5 @@ /* Based loosely on scaling-test */ -#include <assert.h> #include <stdlib.h> #include <stdio.h> #include "utils.h" diff --git a/pixman/test/composite.c b/pixman/test/composite.c index 408c363a3..fe59eae3c 100644 --- a/pixman/test/composite.c +++ b/pixman/test/composite.c @@ -22,8 +22,6 @@ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ -#define PIXMAN_USE_INTERNAL_API -#include <pixman.h> #include <stdio.h> #include <stdlib.h> /* abort() */ #include <math.h> diff --git a/pixman/test/fetch-test.c b/pixman/test/fetch-test.c index 9f80eec1b..04e8cc583 100644 --- a/pixman/test/fetch-test.c +++ b/pixman/test/fetch-test.c @@ -1,11 +1,7 @@ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #include <assert.h> #include <stdlib.h> #include <stdio.h> -#include "pixman.h" +#include "utils.h" #define SIZE 1024 @@ -107,7 +103,7 @@ static testcase_t testcases[] = }, }; -int n_test_cases = sizeof(testcases)/sizeof(testcases[0]); +int n_test_cases = ARRAY_LENGTH (testcases); static uint32_t diff --git a/pixman/test/gradient-crash-test.c b/pixman/test/gradient-crash-test.c index 35b25b2cb..73e5bbcd5 100644 --- a/pixman/test/gradient-crash-test.c +++ b/pixman/test/gradient-crash-test.c @@ -1,158 +1,158 @@ -#include <stdio.h>
-#include <stdlib.h>
-#include "utils.h"
-
-int
-main (int argc, char **argv)
-{
-#define WIDTH 400
-#define HEIGHT 200
-
- uint32_t *dest = malloc (WIDTH * HEIGHT * 4);
- pixman_image_t *src_img;
- pixman_image_t *dest_img;
- int i, j, k, p;
-
- typedef struct
- {
- pixman_point_fixed_t p0;
- pixman_point_fixed_t p1;
- } point_pair_t;
-
- pixman_gradient_stop_t onestop[1] =
- {
- { pixman_int_to_fixed (1), { 0xffff, 0xeeee, 0xeeee, 0xeeee } },
- };
-
- pixman_gradient_stop_t subsetstops[2] =
- {
- { pixman_int_to_fixed (1), { 0xffff, 0xeeee, 0xeeee, 0xeeee } },
- { pixman_int_to_fixed (1), { 0xffff, 0xeeee, 0xeeee, 0xeeee } },
- };
-
- pixman_gradient_stop_t stops01[2] =
- {
- { pixman_int_to_fixed (0), { 0xffff, 0xeeee, 0xeeee, 0xeeee } },
- { pixman_int_to_fixed (1), { 0xffff, 0x1111, 0x1111, 0x1111 } }
- };
-
- point_pair_t point_pairs [] =
- { { { pixman_double_to_fixed (0), 0 },
- { pixman_double_to_fixed (WIDTH / 8.), pixman_int_to_fixed (0) } },
- { { pixman_double_to_fixed (WIDTH / 2.0), pixman_double_to_fixed (HEIGHT / 2.0) },
- { pixman_double_to_fixed (WIDTH / 2.0), pixman_double_to_fixed (HEIGHT / 2.0) } }
- };
-
- pixman_transform_t transformations[] = {
- {
- { { pixman_double_to_fixed (2), pixman_double_to_fixed (0.5), pixman_double_to_fixed (-100), },
- { pixman_double_to_fixed (0), pixman_double_to_fixed (3), pixman_double_to_fixed (0), },
- { pixman_double_to_fixed (0), pixman_double_to_fixed (0.000), pixman_double_to_fixed (1.0) }
- }
- },
- {
- { { pixman_double_to_fixed (1), pixman_double_to_fixed (0), pixman_double_to_fixed (0), },
- { pixman_double_to_fixed (0), pixman_double_to_fixed (1), pixman_double_to_fixed (0), },
- { pixman_double_to_fixed (0), pixman_double_to_fixed (0.000), pixman_double_to_fixed (1.0) }
- }
- },
- {
- { { pixman_double_to_fixed (2), pixman_double_to_fixed (1), pixman_double_to_fixed (0), },
- { pixman_double_to_fixed (1), pixman_double_to_fixed (1), pixman_double_to_fixed (0), },
- { pixman_double_to_fixed (2), pixman_double_to_fixed (1.000), pixman_double_to_fixed (1.0) }
- }
- },
- {
- { { pixman_double_to_fixed (2), pixman_double_to_fixed (1), pixman_double_to_fixed (0), },
- { pixman_double_to_fixed (1), pixman_double_to_fixed (1), pixman_double_to_fixed (0), },
- { pixman_double_to_fixed (0), pixman_double_to_fixed (0), pixman_double_to_fixed (0) }
- }
- },
- {
- { { pixman_double_to_fixed (2), pixman_double_to_fixed (1), pixman_double_to_fixed (0), },
- { pixman_double_to_fixed (1), pixman_double_to_fixed (1), pixman_double_to_fixed (0), },
- { pixman_double_to_fixed (2), pixman_double_to_fixed (-1), pixman_double_to_fixed (0) }
- }
- },
- {
- { { pixman_double_to_fixed (2), pixman_double_to_fixed (1), pixman_double_to_fixed (3), },
- { pixman_double_to_fixed (1), pixman_double_to_fixed (1), pixman_double_to_fixed (0), },
- { pixman_double_to_fixed (2), pixman_double_to_fixed (-1), pixman_double_to_fixed (0) }
- }
- },
- };
-
- pixman_fixed_t r_inner;
- pixman_fixed_t r_outer;
-
- enable_fp_exceptions();
-
- for (i = 0; i < WIDTH * HEIGHT; ++i)
- dest[i] = 0x4f00004f; /* pale blue */
-
- dest_img = pixman_image_create_bits (PIXMAN_a8r8g8b8,
- WIDTH, HEIGHT,
- dest,
- WIDTH * 4);
-
- r_inner = 0;
- r_outer = pixman_double_to_fixed (50.0);
-
- for (i = 0; i < 3; ++i)
- {
- pixman_gradient_stop_t *stops;
- int num_stops;
-
- if (i == 0)
- {
- stops = onestop;
- num_stops = sizeof(onestop) / sizeof(onestop[0]);
- }
- else if (i == 1)
- {
- stops = subsetstops;
- num_stops = sizeof(subsetstops) / sizeof(subsetstops[0]);
- }
- else
- {
- stops = stops01;
- num_stops = sizeof(stops01) / sizeof(stops01[0]);
- }
-
- for (j = 0; j < 3; ++j)
- {
- for (p = 0; p < ARRAY_LENGTH (point_pairs); ++p)
- {
- point_pair_t *pair = &(point_pairs[p]);
-
- if (j == 0)
- src_img = pixman_image_create_conical_gradient (&(pair->p0), r_inner,
- stops, num_stops);
- else if (j == 1)
- src_img = pixman_image_create_radial_gradient (&(pair->p0), &(pair->p1),
- r_inner, r_outer,
- stops, num_stops);
- else
- src_img = pixman_image_create_linear_gradient (&(pair->p0), &(pair->p1),
- stops, num_stops);
-
- for (k = 0; k < ARRAY_LENGTH (transformations); ++k)
- {
- pixman_image_set_transform (src_img, &transformations[k]);
-
- pixman_image_set_repeat (src_img, PIXMAN_REPEAT_NONE);
- pixman_image_composite (PIXMAN_OP_OVER, src_img, NULL, dest_img,
- 0, 0, 0, 0, 0, 0, 10 * WIDTH, HEIGHT);
- }
-
- pixman_image_unref (src_img);
- }
-
- }
- }
-
- pixman_image_unref (dest_img);
- free (dest);
-
- return 0;
-}
+#include <stdio.h> +#include <stdlib.h> +#include "utils.h" + +int +main (int argc, char **argv) +{ +#define WIDTH 400 +#define HEIGHT 200 + + uint32_t *dest = malloc (WIDTH * HEIGHT * 4); + pixman_image_t *src_img; + pixman_image_t *dest_img; + int i, j, k, p; + + typedef struct + { + pixman_point_fixed_t p0; + pixman_point_fixed_t p1; + } point_pair_t; + + pixman_gradient_stop_t onestop[1] = + { + { pixman_int_to_fixed (1), { 0xffff, 0xeeee, 0xeeee, 0xeeee } }, + }; + + pixman_gradient_stop_t subsetstops[2] = + { + { pixman_int_to_fixed (1), { 0xffff, 0xeeee, 0xeeee, 0xeeee } }, + { pixman_int_to_fixed (1), { 0xffff, 0xeeee, 0xeeee, 0xeeee } }, + }; + + pixman_gradient_stop_t stops01[2] = + { + { pixman_int_to_fixed (0), { 0xffff, 0xeeee, 0xeeee, 0xeeee } }, + { pixman_int_to_fixed (1), { 0xffff, 0x1111, 0x1111, 0x1111 } } + }; + + point_pair_t point_pairs [] = + { { { pixman_double_to_fixed (0), 0 }, + { pixman_double_to_fixed (WIDTH / 8.), pixman_int_to_fixed (0) } }, + { { pixman_double_to_fixed (WIDTH / 2.0), pixman_double_to_fixed (HEIGHT / 2.0) }, + { pixman_double_to_fixed (WIDTH / 2.0), pixman_double_to_fixed (HEIGHT / 2.0) } } + }; + + pixman_transform_t transformations[] = { + { + { { pixman_double_to_fixed (2), pixman_double_to_fixed (0.5), pixman_double_to_fixed (-100), }, + { pixman_double_to_fixed (0), pixman_double_to_fixed (3), pixman_double_to_fixed (0), }, + { pixman_double_to_fixed (0), pixman_double_to_fixed (0.000), pixman_double_to_fixed (1.0) } + } + }, + { + { { pixman_double_to_fixed (1), pixman_double_to_fixed (0), pixman_double_to_fixed (0), }, + { pixman_double_to_fixed (0), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, + { pixman_double_to_fixed (0), pixman_double_to_fixed (0.000), pixman_double_to_fixed (1.0) } + } + }, + { + { { pixman_double_to_fixed (2), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, + { pixman_double_to_fixed (1), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, + { pixman_double_to_fixed (2), pixman_double_to_fixed (1.000), pixman_double_to_fixed (1.0) } + } + }, + { + { { pixman_double_to_fixed (2), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, + { pixman_double_to_fixed (1), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, + { pixman_double_to_fixed (0), pixman_double_to_fixed (0), pixman_double_to_fixed (0) } + } + }, + { + { { pixman_double_to_fixed (2), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, + { pixman_double_to_fixed (1), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, + { pixman_double_to_fixed (2), pixman_double_to_fixed (-1), pixman_double_to_fixed (0) } + } + }, + { + { { pixman_double_to_fixed (2), pixman_double_to_fixed (1), pixman_double_to_fixed (3), }, + { pixman_double_to_fixed (1), pixman_double_to_fixed (1), pixman_double_to_fixed (0), }, + { pixman_double_to_fixed (2), pixman_double_to_fixed (-1), pixman_double_to_fixed (0) } + } + }, + }; + + pixman_fixed_t r_inner; + pixman_fixed_t r_outer; + + enable_fp_exceptions(); + + for (i = 0; i < WIDTH * HEIGHT; ++i) + dest[i] = 0x4f00004f; /* pale blue */ + + dest_img = pixman_image_create_bits (PIXMAN_a8r8g8b8, + WIDTH, HEIGHT, + dest, + WIDTH * 4); + + r_inner = 0; + r_outer = pixman_double_to_fixed (50.0); + + for (i = 0; i < 3; ++i) + { + pixman_gradient_stop_t *stops; + int num_stops; + + if (i == 0) + { + stops = onestop; + num_stops = ARRAY_LENGTH (onestop); + } + else if (i == 1) + { + stops = subsetstops; + num_stops = ARRAY_LENGTH (subsetstops); + } + else + { + stops = stops01; + num_stops = ARRAY_LENGTH (stops01); + } + + for (j = 0; j < 3; ++j) + { + for (p = 0; p < ARRAY_LENGTH (point_pairs); ++p) + { + point_pair_t *pair = &(point_pairs[p]); + + if (j == 0) + src_img = pixman_image_create_conical_gradient (&(pair->p0), r_inner, + stops, num_stops); + else if (j == 1) + src_img = pixman_image_create_radial_gradient (&(pair->p0), &(pair->p1), + r_inner, r_outer, + stops, num_stops); + else + src_img = pixman_image_create_linear_gradient (&(pair->p0), &(pair->p1), + stops, num_stops); + + for (k = 0; k < ARRAY_LENGTH (transformations); ++k) + { + pixman_image_set_transform (src_img, &transformations[k]); + + pixman_image_set_repeat (src_img, PIXMAN_REPEAT_NONE); + pixman_image_composite (PIXMAN_OP_OVER, src_img, NULL, dest_img, + 0, 0, 0, 0, 0, 0, 10 * WIDTH, HEIGHT); + } + + pixman_image_unref (src_img); + } + + } + } + + pixman_image_unref (dest_img); + free (dest); + + return 0; +} diff --git a/pixman/test/lowlevel-blt-bench.c b/pixman/test/lowlevel-blt-bench.c index bdafb3592..ba7f30716 100644 --- a/pixman/test/lowlevel-blt-bench.c +++ b/pixman/test/lowlevel-blt-bench.c @@ -25,10 +25,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> - -#define PIXMAN_USE_INTERNAL_API -#include <pixman.h> - #include "utils.h" #define SOLID_FLAG 1 @@ -707,7 +703,7 @@ main (int argc, char *argv[]) x / 1000000., x / 4000000); printf ("---\n"); - for (i = 0; i < sizeof(tests_tbl) / sizeof(tests_tbl[0]); i++) + for (i = 0; i < ARRAY_LENGTH (tests_tbl); i++) { if (strcmp (pattern, "all") == 0 || strstr (tests_tbl[i].testname, pattern)) { diff --git a/pixman/test/oob-test.c b/pixman/test/oob-test.c index 4f9e5a244..0d19b504a 100644 --- a/pixman/test/oob-test.c +++ b/pixman/test/oob-test.c @@ -1,6 +1,6 @@ #include <stdio.h> #include <stdlib.h> -#include "pixman.h" +#include "utils.h" typedef struct { @@ -94,7 +94,7 @@ main (int argc, char **argv) { int i; - for (i = 0; i < sizeof (info) / sizeof (info[0]); ++i) + for (i = 0; i < ARRAY_LENGTH (info); ++i) test_composite (&info[i]); return 0; diff --git a/pixman/test/region-contains-test.c b/pixman/test/region-contains-test.c index b660fdf0b..2372686fc 100644 --- a/pixman/test/region-contains-test.c +++ b/pixman/test/region-contains-test.c @@ -1,4 +1,3 @@ -#include <assert.h> #include <stdlib.h> #include <stdio.h> #include "utils.h" diff --git a/pixman/test/region-translate-test.c b/pixman/test/region-translate-test.c index 7c63df966..5a03027e8 100644 --- a/pixman/test/region-translate-test.c +++ b/pixman/test/region-translate-test.c @@ -1,30 +1,30 @@ -#include <pixman.h>
-#include <assert.h>
-
-/* Pixman had a bug where 32bit regions where clipped to 16bit sizes when
- * pixman_region32_translate() was called. This test exercises that bug.
- */
-
-#define LARGE 32000
-
-int
-main (int argc, char **argv)
-{
- pixman_box32_t rect = { -LARGE, -LARGE, LARGE, LARGE };
- pixman_region32_t r1, r2;
-
- pixman_region32_init_rects (&r1, &rect, 1);
- pixman_region32_init_rect (&r2, rect.x1, rect.y1, rect.x2 - rect.x1, rect.y2 - rect.y1);
-
- assert (pixman_region32_equal (&r1, &r2));
-
- pixman_region32_translate (&r1, -LARGE, LARGE);
- pixman_region32_translate (&r1, LARGE, -LARGE);
-
- assert (pixman_region32_equal (&r1, &r2));
-
- pixman_region32_fini (&r1);
- pixman_region32_fini (&r2);
-
- return 0;
-}
+#include <assert.h> +#include "utils.h" + +/* Pixman had a bug where 32bit regions where clipped to 16bit sizes when + * pixman_region32_translate() was called. This test exercises that bug. + */ + +#define LARGE 32000 + +int +main (int argc, char **argv) +{ + pixman_box32_t rect = { -LARGE, -LARGE, LARGE, LARGE }; + pixman_region32_t r1, r2; + + pixman_region32_init_rects (&r1, &rect, 1); + pixman_region32_init_rect (&r2, rect.x1, rect.y1, rect.x2 - rect.x1, rect.y2 - rect.y1); + + assert (pixman_region32_equal (&r1, &r2)); + + pixman_region32_translate (&r1, -LARGE, LARGE); + pixman_region32_translate (&r1, LARGE, -LARGE); + + assert (pixman_region32_equal (&r1, &r2)); + + pixman_region32_fini (&r1); + pixman_region32_fini (&r2); + + return 0; +} diff --git a/pixman/test/scaling-crash-test.c b/pixman/test/scaling-crash-test.c index 23ee8c6be..ed57ae024 100644 --- a/pixman/test/scaling-crash-test.c +++ b/pixman/test/scaling-crash-test.c @@ -1,217 +1,216 @@ -#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "pixman.h"
-
-/*
- * We have a source image filled with solid color, set NORMAL or PAD repeat,
- * and some transform which results in nearest neighbour scaling.
- *
- * The expected result is either that the destination image filled with this solid
- * color or, if the transformation is such that we can't composite anything at
- * all, that nothing has changed in the destination.
- *
- * The surrounding memory of the source image is a different solid color so that
- * we are sure to get failures if we access it.
- */
-static int
-run_test (int32_t dst_width,
- int32_t dst_height,
- int32_t src_width,
- int32_t src_height,
- int32_t src_x,
- int32_t src_y,
- int32_t scale_x,
- int32_t scale_y,
- pixman_filter_t filter,
- pixman_repeat_t repeat)
-{
- pixman_image_t * src_img;
- pixman_image_t * dst_img;
- pixman_transform_t transform;
- uint32_t * srcbuf;
- uint32_t * dstbuf;
- pixman_box32_t box = { 0, 0, src_width, src_height };
- pixman_color_t color_cc = { 0xcccc, 0xcccc, 0xcccc, 0xcccc };
- int result;
- int i;
-
- static const pixman_fixed_t kernel[] =
- {
-#define D(f) (pixman_double_to_fixed (f) + 0x0001)
-
- pixman_int_to_fixed (5),
- pixman_int_to_fixed (5),
- D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0),
- D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0),
- D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0),
- D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0),
- D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0)
- };
-
- result = 0;
-
- srcbuf = (uint32_t *)malloc ((src_width + 10) * (src_height + 10) * 4);
- dstbuf = (uint32_t *)malloc (dst_width * dst_height * 4);
-
- memset (srcbuf, 0x88, src_width * src_height * 4);
- memset (dstbuf, 0x33, dst_width * dst_height * 4);
-
- src_img = pixman_image_create_bits (
- PIXMAN_a8r8g8b8, src_width, src_height,
- srcbuf + (src_width + 10) * 5 + 5, (src_width + 10) * 4);
-
- pixman_image_fill_boxes (PIXMAN_OP_SRC, src_img, &color_cc, 1, &box);
-
- dst_img = pixman_image_create_bits (
- PIXMAN_a8r8g8b8, dst_width, dst_height, dstbuf, dst_width * 4);
-
- pixman_transform_init_scale (&transform, scale_x, scale_y);
- pixman_image_set_transform (src_img, &transform);
- pixman_image_set_repeat (src_img, repeat);
- if (filter == PIXMAN_FILTER_CONVOLUTION)
- pixman_image_set_filter (src_img, filter, kernel, 27);
- else
- pixman_image_set_filter (src_img, filter, NULL, 0);
-
- pixman_image_composite (PIXMAN_OP_SRC, src_img, NULL, dst_img,
- src_x, src_y, 0, 0, 0, 0, dst_width, dst_height);
-
- pixman_image_unref (src_img);
- pixman_image_unref (dst_img);
-
- for (i = 0; i < dst_width * dst_height; i++)
- {
- if (dstbuf[i] != 0xCCCCCCCC && dstbuf[i] != 0x33333333)
- {
- result = 1;
- break;
- }
- }
-
- free (srcbuf);
- free (dstbuf);
- return result;
-}
-
-typedef struct filter_info_t filter_info_t;
-struct filter_info_t
-{
- pixman_filter_t value;
- char name[28];
-};
-
-static const filter_info_t filters[] =
-{
- { PIXMAN_FILTER_NEAREST, "NEAREST" },
- { PIXMAN_FILTER_BILINEAR, "BILINEAR" },
- { PIXMAN_FILTER_CONVOLUTION, "CONVOLUTION" },
-};
-
-typedef struct repeat_info_t repeat_info_t;
-struct repeat_info_t
-{
- pixman_repeat_t value;
- char name[28];
-};
-
-
-static const repeat_info_t repeats[] =
-{
- { PIXMAN_REPEAT_PAD, "PAD" },
- { PIXMAN_REPEAT_REFLECT, "REFLECT" },
- { PIXMAN_REPEAT_NORMAL, "NORMAL" }
-};
-
-static int
-do_test (int32_t dst_size,
- int32_t src_size,
- int32_t src_offs,
- int32_t scale_factor)
-{
-#define N_ELEMENTS(a) (sizeof (a) / sizeof ((a)[0]))
- int i, j;
-
- for (i = 0; i < N_ELEMENTS(filters); ++i)
- {
- for (j = 0; j < N_ELEMENTS (repeats); ++j)
- {
- /* horizontal test */
- if (run_test (dst_size, 1,
- src_size, 1,
- src_offs, 0,
- scale_factor, 65536,
- filters[i].value,
- repeats[j].value) != 0)
- {
- printf ("Vertical test failed with %s filter and repeat mode %s\n",
- filters[i].name, repeats[j].name);
-
- return 1;
- }
-
- /* vertical test */
- if (run_test (1, dst_size,
- 1, src_size,
- 0, src_offs,
- 65536, scale_factor,
- filters[i].value,
- repeats[j].value) != 0)
- {
- printf ("Vertical test failed with %s filter and repeat mode %s\n",
- filters[i].name, repeats[j].name);
-
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-int
-main (int argc, char *argv[])
-{
- int i;
-
- pixman_disable_out_of_bounds_workaround ();
-
- /* can potentially crash */
- assert (do_test (
- 48000, 32767, 1, 65536 * 128) == 0);
-
- /* can potentially get into a deadloop */
- assert (do_test (
- 16384, 65536, 32, 32768) == 0);
-
- /* can potentially access memory outside source image buffer */
- assert (do_test (
- 10, 10, 0, 1) == 0);
- assert (do_test (
- 10, 10, 0, 0) == 0);
-
- for (i = 0; i < 100; ++i)
- {
- pixman_fixed_t one_seventh =
- (((pixman_fixed_48_16_t)pixman_fixed_1) << 16) / (7 << 16);
-
- assert (do_test (
- 1, 7, 3, one_seventh + i - 50) == 0);
- }
-
- for (i = 0; i < 100; ++i)
- {
- pixman_fixed_t scale =
- (((pixman_fixed_48_16_t)pixman_fixed_1) << 16) / (32767 << 16);
-
- assert (do_test (
- 1, 32767, 16383, scale + i - 50) == 0);
- }
-
- /* can potentially provide invalid results (out of range matrix stuff) */
- assert (do_test (
- 48000, 32767, 16384, 65536 * 128) == 0);
-
- return 0;
-}
+#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "utils.h" + +/* + * We have a source image filled with solid color, set NORMAL or PAD repeat, + * and some transform which results in nearest neighbour scaling. + * + * The expected result is either that the destination image filled with this solid + * color or, if the transformation is such that we can't composite anything at + * all, that nothing has changed in the destination. + * + * The surrounding memory of the source image is a different solid color so that + * we are sure to get failures if we access it. + */ +static int +run_test (int32_t dst_width, + int32_t dst_height, + int32_t src_width, + int32_t src_height, + int32_t src_x, + int32_t src_y, + int32_t scale_x, + int32_t scale_y, + pixman_filter_t filter, + pixman_repeat_t repeat) +{ + pixman_image_t * src_img; + pixman_image_t * dst_img; + pixman_transform_t transform; + uint32_t * srcbuf; + uint32_t * dstbuf; + pixman_box32_t box = { 0, 0, src_width, src_height }; + pixman_color_t color_cc = { 0xcccc, 0xcccc, 0xcccc, 0xcccc }; + int result; + int i; + + static const pixman_fixed_t kernel[] = + { +#define D(f) (pixman_double_to_fixed (f) + 0x0001) + + pixman_int_to_fixed (5), + pixman_int_to_fixed (5), + D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), + D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), + D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), + D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), + D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0), D(1/25.0) + }; + + result = 0; + + srcbuf = (uint32_t *)malloc ((src_width + 10) * (src_height + 10) * 4); + dstbuf = (uint32_t *)malloc (dst_width * dst_height * 4); + + memset (srcbuf, 0x88, src_width * src_height * 4); + memset (dstbuf, 0x33, dst_width * dst_height * 4); + + src_img = pixman_image_create_bits ( + PIXMAN_a8r8g8b8, src_width, src_height, + srcbuf + (src_width + 10) * 5 + 5, (src_width + 10) * 4); + + pixman_image_fill_boxes (PIXMAN_OP_SRC, src_img, &color_cc, 1, &box); + + dst_img = pixman_image_create_bits ( + PIXMAN_a8r8g8b8, dst_width, dst_height, dstbuf, dst_width * 4); + + pixman_transform_init_scale (&transform, scale_x, scale_y); + pixman_image_set_transform (src_img, &transform); + pixman_image_set_repeat (src_img, repeat); + if (filter == PIXMAN_FILTER_CONVOLUTION) + pixman_image_set_filter (src_img, filter, kernel, 27); + else + pixman_image_set_filter (src_img, filter, NULL, 0); + + pixman_image_composite (PIXMAN_OP_SRC, src_img, NULL, dst_img, + src_x, src_y, 0, 0, 0, 0, dst_width, dst_height); + + pixman_image_unref (src_img); + pixman_image_unref (dst_img); + + for (i = 0; i < dst_width * dst_height; i++) + { + if (dstbuf[i] != 0xCCCCCCCC && dstbuf[i] != 0x33333333) + { + result = 1; + break; + } + } + + free (srcbuf); + free (dstbuf); + return result; +} + +typedef struct filter_info_t filter_info_t; +struct filter_info_t +{ + pixman_filter_t value; + char name[28]; +}; + +static const filter_info_t filters[] = +{ + { PIXMAN_FILTER_NEAREST, "NEAREST" }, + { PIXMAN_FILTER_BILINEAR, "BILINEAR" }, + { PIXMAN_FILTER_CONVOLUTION, "CONVOLUTION" }, +}; + +typedef struct repeat_info_t repeat_info_t; +struct repeat_info_t +{ + pixman_repeat_t value; + char name[28]; +}; + + +static const repeat_info_t repeats[] = +{ + { PIXMAN_REPEAT_PAD, "PAD" }, + { PIXMAN_REPEAT_REFLECT, "REFLECT" }, + { PIXMAN_REPEAT_NORMAL, "NORMAL" } +}; + +static int +do_test (int32_t dst_size, + int32_t src_size, + int32_t src_offs, + int32_t scale_factor) +{ + int i, j; + + for (i = 0; i < ARRAY_LENGTH (filters); ++i) + { + for (j = 0; j < ARRAY_LENGTH (repeats); ++j) + { + /* horizontal test */ + if (run_test (dst_size, 1, + src_size, 1, + src_offs, 0, + scale_factor, 65536, + filters[i].value, + repeats[j].value) != 0) + { + printf ("Vertical test failed with %s filter and repeat mode %s\n", + filters[i].name, repeats[j].name); + + return 1; + } + + /* vertical test */ + if (run_test (1, dst_size, + 1, src_size, + 0, src_offs, + 65536, scale_factor, + filters[i].value, + repeats[j].value) != 0) + { + printf ("Vertical test failed with %s filter and repeat mode %s\n", + filters[i].name, repeats[j].name); + + return 1; + } + } + } + + return 0; +} + +int +main (int argc, char *argv[]) +{ + int i; + + pixman_disable_out_of_bounds_workaround (); + + /* can potentially crash */ + assert (do_test ( + 48000, 32767, 1, 65536 * 128) == 0); + + /* can potentially get into a deadloop */ + assert (do_test ( + 16384, 65536, 32, 32768) == 0); + + /* can potentially access memory outside source image buffer */ + assert (do_test ( + 10, 10, 0, 1) == 0); + assert (do_test ( + 10, 10, 0, 0) == 0); + + for (i = 0; i < 100; ++i) + { + pixman_fixed_t one_seventh = + (((pixman_fixed_48_16_t)pixman_fixed_1) << 16) / (7 << 16); + + assert (do_test ( + 1, 7, 3, one_seventh + i - 50) == 0); + } + + for (i = 0; i < 100; ++i) + { + pixman_fixed_t scale = + (((pixman_fixed_48_16_t)pixman_fixed_1) << 16) / (32767 << 16); + + assert (do_test ( + 1, 32767, 16383, scale + i - 50) == 0); + } + + /* can potentially provide invalid results (out of range matrix stuff) */ + assert (do_test ( + 48000, 32767, 16384, 65536 * 128) == 0); + + return 0; +} diff --git a/pixman/test/scaling-test.c b/pixman/test/scaling-test.c index f247e1e9a..6f2da1432 100644 --- a/pixman/test/scaling-test.c +++ b/pixman/test/scaling-test.c @@ -1,368 +1,367 @@ -/*
- * Test program, which can detect some problems with nearest neighbour
- * and bilinear scaling in pixman. Testing is done by running lots
- * of random SRC and OVER compositing operations a8r8g8b8, x8a8r8g8b8
- * and r5g6b5 color formats.
- *
- * Script 'fuzzer-find-diff.pl' can be used to narrow down the problem in
- * the case of test failure.
- */
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "utils.h"
-
-#define MAX_SRC_WIDTH 48
-#define MAX_SRC_HEIGHT 8
-#define MAX_DST_WIDTH 48
-#define MAX_DST_HEIGHT 8
-#define MAX_STRIDE 4
-
-/*
- * Composite operation with pseudorandom images
- */
-uint32_t
-test_composite (int testnum,
- int verbose)
-{
- int i;
- pixman_image_t * src_img;
- pixman_image_t * mask_img;
- pixman_image_t * dst_img;
- pixman_transform_t transform;
- pixman_region16_t clip;
- int src_width, src_height;
- int mask_width, mask_height;
- int dst_width, dst_height;
- int src_stride, mask_stride, dst_stride;
- int src_x, src_y;
- int mask_x, mask_y;
- int dst_x, dst_y;
- int src_bpp;
- int mask_bpp = 1;
- int dst_bpp;
- int w, h;
- pixman_fixed_t scale_x = 65536, scale_y = 65536;
- pixman_fixed_t translate_x = 0, translate_y = 0;
- pixman_fixed_t mask_scale_x = 65536, mask_scale_y = 65536;
- pixman_fixed_t mask_translate_x = 0, mask_translate_y = 0;
- pixman_op_t op;
- pixman_repeat_t repeat = PIXMAN_REPEAT_NONE;
- pixman_repeat_t mask_repeat = PIXMAN_REPEAT_NONE;
- pixman_format_code_t src_fmt, dst_fmt;
- uint32_t * srcbuf;
- uint32_t * dstbuf;
- uint32_t * maskbuf;
- uint32_t crc32;
- FLOAT_REGS_CORRUPTION_DETECTOR_START ();
-
- lcg_srand (testnum);
-
- src_bpp = (lcg_rand_n (2) == 0) ? 2 : 4;
- dst_bpp = (lcg_rand_n (2) == 0) ? 2 : 4;
- switch (lcg_rand_n (3))
- {
- case 0:
- op = PIXMAN_OP_SRC;
- break;
- case 1:
- op = PIXMAN_OP_OVER;
- break;
- default:
- op = PIXMAN_OP_ADD;
- break;
- }
-
- src_width = lcg_rand_n (MAX_SRC_WIDTH) + 1;
- src_height = lcg_rand_n (MAX_SRC_HEIGHT) + 1;
-
- if (lcg_rand_n (2))
- {
- mask_width = lcg_rand_n (MAX_SRC_WIDTH) + 1;
- mask_height = lcg_rand_n (MAX_SRC_HEIGHT) + 1;
- }
- else
- {
- mask_width = mask_height = 1;
- }
-
- dst_width = lcg_rand_n (MAX_DST_WIDTH) + 1;
- dst_height = lcg_rand_n (MAX_DST_HEIGHT) + 1;
- src_stride = src_width * src_bpp + lcg_rand_n (MAX_STRIDE) * src_bpp;
- mask_stride = mask_width * mask_bpp + lcg_rand_n (MAX_STRIDE) * mask_bpp;
- dst_stride = dst_width * dst_bpp + lcg_rand_n (MAX_STRIDE) * dst_bpp;
-
- if (src_stride & 3)
- src_stride += 2;
-
- if (mask_stride & 1)
- mask_stride += 1;
- if (mask_stride & 2)
- mask_stride += 2;
-
- if (dst_stride & 3)
- dst_stride += 2;
-
- src_x = -(src_width / 4) + lcg_rand_n (src_width * 3 / 2);
- src_y = -(src_height / 4) + lcg_rand_n (src_height * 3 / 2);
- mask_x = -(mask_width / 4) + lcg_rand_n (mask_width * 3 / 2);
- mask_y = -(mask_height / 4) + lcg_rand_n (mask_height * 3 / 2);
- dst_x = -(dst_width / 4) + lcg_rand_n (dst_width * 3 / 2);
- dst_y = -(dst_height / 4) + lcg_rand_n (dst_height * 3 / 2);
- w = lcg_rand_n (dst_width * 3 / 2 - dst_x);
- h = lcg_rand_n (dst_height * 3 / 2 - dst_y);
-
- srcbuf = (uint32_t *)malloc (src_stride * src_height);
- maskbuf = (uint32_t *)malloc (mask_stride * mask_height);
- dstbuf = (uint32_t *)malloc (dst_stride * dst_height);
-
- for (i = 0; i < src_stride * src_height; i++)
- *((uint8_t *)srcbuf + i) = lcg_rand_n (256);
-
- for (i = 0; i < mask_stride * mask_height; i++)
- *((uint8_t *)maskbuf + i) = lcg_rand_n (256);
-
- for (i = 0; i < dst_stride * dst_height; i++)
- *((uint8_t *)dstbuf + i) = lcg_rand_n (256);
-
- src_fmt = src_bpp == 4 ? (lcg_rand_n (2) == 0 ?
- PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8) : PIXMAN_r5g6b5;
-
- dst_fmt = dst_bpp == 4 ? (lcg_rand_n (2) == 0 ?
- PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8) : PIXMAN_r5g6b5;
-
- src_img = pixman_image_create_bits (
- src_fmt, src_width, src_height, srcbuf, src_stride);
-
- mask_img = pixman_image_create_bits (
- PIXMAN_a8, mask_width, mask_height, maskbuf, mask_stride);
-
- dst_img = pixman_image_create_bits (
- dst_fmt, dst_width, dst_height, dstbuf, dst_stride);
-
- image_endian_swap (src_img);
- image_endian_swap (dst_img);
-
- if (lcg_rand_n (4) > 0)
- {
- scale_x = -32768 * 3 + lcg_rand_N (65536 * 5);
- scale_y = -32768 * 3 + lcg_rand_N (65536 * 5);
- translate_x = lcg_rand_N (65536);
- translate_y = lcg_rand_N (65536);
- pixman_transform_init_scale (&transform, scale_x, scale_y);
- pixman_transform_translate (&transform, NULL, translate_x, translate_y);
- pixman_image_set_transform (src_img, &transform);
- }
-
- if (lcg_rand_n (2) > 0)
- {
- mask_scale_x = -32768 * 3 + lcg_rand_N (65536 * 5);
- mask_scale_y = -32768 * 3 + lcg_rand_N (65536 * 5);
- mask_translate_x = lcg_rand_N (65536);
- mask_translate_y = lcg_rand_N (65536);
- pixman_transform_init_scale (&transform, mask_scale_x, mask_scale_y);
- pixman_transform_translate (&transform, NULL, mask_translate_x, mask_translate_y);
- pixman_image_set_transform (mask_img, &transform);
- }
-
- switch (lcg_rand_n (4))
- {
- case 0:
- mask_repeat = PIXMAN_REPEAT_NONE;
- break;
-
- case 1:
- mask_repeat = PIXMAN_REPEAT_NORMAL;
- break;
-
- case 2:
- mask_repeat = PIXMAN_REPEAT_PAD;
- break;
-
- case 3:
- mask_repeat = PIXMAN_REPEAT_REFLECT;
- break;
-
- default:
- break;
- }
- pixman_image_set_repeat (mask_img, mask_repeat);
-
- switch (lcg_rand_n (4))
- {
- case 0:
- repeat = PIXMAN_REPEAT_NONE;
- break;
-
- case 1:
- repeat = PIXMAN_REPEAT_NORMAL;
- break;
-
- case 2:
- repeat = PIXMAN_REPEAT_PAD;
- break;
-
- case 3:
- repeat = PIXMAN_REPEAT_REFLECT;
- break;
-
- default:
- break;
- }
- pixman_image_set_repeat (src_img, repeat);
-
- if (lcg_rand_n (2))
- pixman_image_set_filter (src_img, PIXMAN_FILTER_NEAREST, NULL, 0);
- else
- pixman_image_set_filter (src_img, PIXMAN_FILTER_BILINEAR, NULL, 0);
-
- if (lcg_rand_n (2))
- pixman_image_set_filter (mask_img, PIXMAN_FILTER_NEAREST, NULL, 0);
- else
- pixman_image_set_filter (mask_img, PIXMAN_FILTER_BILINEAR, NULL, 0);
-
- if (verbose)
- {
- printf ("src_fmt=%08X, dst_fmt=%08X\n", src_fmt, dst_fmt);
- printf ("op=%d, scale_x=%d, scale_y=%d, repeat=%d\n",
- op, scale_x, scale_y, repeat);
- printf ("translate_x=%d, translate_y=%d\n",
- translate_x, translate_y);
- printf ("src_width=%d, src_height=%d, dst_width=%d, dst_height=%d\n",
- src_width, src_height, dst_width, dst_height);
- printf ("src_x=%d, src_y=%d, dst_x=%d, dst_y=%d\n",
- src_x, src_y, dst_x, dst_y);
- printf ("w=%d, h=%d\n", w, h);
- }
-
- if (lcg_rand_n (8) == 0)
- {
- pixman_box16_t clip_boxes[2];
- int n = lcg_rand_n (2) + 1;
-
- for (i = 0; i < n; i++)
- {
- clip_boxes[i].x1 = lcg_rand_n (src_width);
- clip_boxes[i].y1 = lcg_rand_n (src_height);
- clip_boxes[i].x2 =
- clip_boxes[i].x1 + lcg_rand_n (src_width - clip_boxes[i].x1);
- clip_boxes[i].y2 =
- clip_boxes[i].y1 + lcg_rand_n (src_height - clip_boxes[i].y1);
-
- if (verbose)
- {
- printf ("source clip box: [%d,%d-%d,%d]\n",
- clip_boxes[i].x1, clip_boxes[i].y1,
- clip_boxes[i].x2, clip_boxes[i].y2);
- }
- }
-
- pixman_region_init_rects (&clip, clip_boxes, n);
- pixman_image_set_clip_region (src_img, &clip);
- pixman_image_set_source_clipping (src_img, 1);
- pixman_region_fini (&clip);
- }
-
- if (lcg_rand_n (8) == 0)
- {
- pixman_box16_t clip_boxes[2];
- int n = lcg_rand_n (2) + 1;
-
- for (i = 0; i < n; i++)
- {
- clip_boxes[i].x1 = lcg_rand_n (mask_width);
- clip_boxes[i].y1 = lcg_rand_n (mask_height);
- clip_boxes[i].x2 =
- clip_boxes[i].x1 + lcg_rand_n (mask_width - clip_boxes[i].x1);
- clip_boxes[i].y2 =
- clip_boxes[i].y1 + lcg_rand_n (mask_height - clip_boxes[i].y1);
-
- if (verbose)
- {
- printf ("mask clip box: [%d,%d-%d,%d]\n",
- clip_boxes[i].x1, clip_boxes[i].y1,
- clip_boxes[i].x2, clip_boxes[i].y2);
- }
- }
-
- pixman_region_init_rects (&clip, clip_boxes, n);
- pixman_image_set_clip_region (mask_img, &clip);
- pixman_image_set_source_clipping (mask_img, 1);
- pixman_region_fini (&clip);
- }
-
- if (lcg_rand_n (8) == 0)
- {
- pixman_box16_t clip_boxes[2];
- int n = lcg_rand_n (2) + 1;
- for (i = 0; i < n; i++)
- {
- clip_boxes[i].x1 = lcg_rand_n (dst_width);
- clip_boxes[i].y1 = lcg_rand_n (dst_height);
- clip_boxes[i].x2 =
- clip_boxes[i].x1 + lcg_rand_n (dst_width - clip_boxes[i].x1);
- clip_boxes[i].y2 =
- clip_boxes[i].y1 + lcg_rand_n (dst_height - clip_boxes[i].y1);
-
- if (verbose)
- {
- printf ("destination clip box: [%d,%d-%d,%d]\n",
- clip_boxes[i].x1, clip_boxes[i].y1,
- clip_boxes[i].x2, clip_boxes[i].y2);
- }
- }
- pixman_region_init_rects (&clip, clip_boxes, n);
- pixman_image_set_clip_region (dst_img, &clip);
- pixman_region_fini (&clip);
- }
-
- if (lcg_rand_n (2) == 0)
- pixman_image_composite (op, src_img, NULL, dst_img,
- src_x, src_y, 0, 0, dst_x, dst_y, w, h);
- else
- pixman_image_composite (op, src_img, mask_img, dst_img,
- src_x, src_y, mask_x, mask_y, dst_x, dst_y, w, h);
-
- if (dst_fmt == PIXMAN_x8r8g8b8)
- {
- /* ignore unused part */
- for (i = 0; i < dst_stride * dst_height / 4; i++)
- dstbuf[i] &= 0xFFFFFF;
- }
-
- image_endian_swap (dst_img);
-
- if (verbose)
- {
- int j;
-
- for (i = 0; i < dst_height; i++)
- {
- for (j = 0; j < dst_stride; j++)
- printf ("%02X ", *((uint8_t *)dstbuf + i * dst_stride + j));
-
- printf ("\n");
- }
- }
-
- pixman_image_unref (src_img);
- pixman_image_unref (mask_img);
- pixman_image_unref (dst_img);
-
- crc32 = compute_crc32 (0, dstbuf, dst_stride * dst_height);
- free (srcbuf);
- free (maskbuf);
- free (dstbuf);
-
- FLOAT_REGS_CORRUPTION_DETECTOR_FINISH ();
- return crc32;
-}
-
-int
-main (int argc, const char *argv[])
-{
- pixman_disable_out_of_bounds_workaround ();
-
- return fuzzer_test_main("scaling", 8000000, 0x80DF1CB2,
- test_composite, argc, argv);
-}
+/* + * Test program, which can detect some problems with nearest neighbour + * and bilinear scaling in pixman. Testing is done by running lots + * of random SRC and OVER compositing operations a8r8g8b8, x8a8r8g8b8 + * and r5g6b5 color formats. + * + * Script 'fuzzer-find-diff.pl' can be used to narrow down the problem in + * the case of test failure. + */ +#include <stdlib.h> +#include <stdio.h> +#include "utils.h" + +#define MAX_SRC_WIDTH 48 +#define MAX_SRC_HEIGHT 8 +#define MAX_DST_WIDTH 48 +#define MAX_DST_HEIGHT 8 +#define MAX_STRIDE 4 + +/* + * Composite operation with pseudorandom images + */ +uint32_t +test_composite (int testnum, + int verbose) +{ + int i; + pixman_image_t * src_img; + pixman_image_t * mask_img; + pixman_image_t * dst_img; + pixman_transform_t transform; + pixman_region16_t clip; + int src_width, src_height; + int mask_width, mask_height; + int dst_width, dst_height; + int src_stride, mask_stride, dst_stride; + int src_x, src_y; + int mask_x, mask_y; + int dst_x, dst_y; + int src_bpp; + int mask_bpp = 1; + int dst_bpp; + int w, h; + pixman_fixed_t scale_x = 65536, scale_y = 65536; + pixman_fixed_t translate_x = 0, translate_y = 0; + pixman_fixed_t mask_scale_x = 65536, mask_scale_y = 65536; + pixman_fixed_t mask_translate_x = 0, mask_translate_y = 0; + pixman_op_t op; + pixman_repeat_t repeat = PIXMAN_REPEAT_NONE; + pixman_repeat_t mask_repeat = PIXMAN_REPEAT_NONE; + pixman_format_code_t src_fmt, dst_fmt; + uint32_t * srcbuf; + uint32_t * dstbuf; + uint32_t * maskbuf; + uint32_t crc32; + FLOAT_REGS_CORRUPTION_DETECTOR_START (); + + lcg_srand (testnum); + + src_bpp = (lcg_rand_n (2) == 0) ? 2 : 4; + dst_bpp = (lcg_rand_n (2) == 0) ? 2 : 4; + switch (lcg_rand_n (3)) + { + case 0: + op = PIXMAN_OP_SRC; + break; + case 1: + op = PIXMAN_OP_OVER; + break; + default: + op = PIXMAN_OP_ADD; + break; + } + + src_width = lcg_rand_n (MAX_SRC_WIDTH) + 1; + src_height = lcg_rand_n (MAX_SRC_HEIGHT) + 1; + + if (lcg_rand_n (2)) + { + mask_width = lcg_rand_n (MAX_SRC_WIDTH) + 1; + mask_height = lcg_rand_n (MAX_SRC_HEIGHT) + 1; + } + else + { + mask_width = mask_height = 1; + } + + dst_width = lcg_rand_n (MAX_DST_WIDTH) + 1; + dst_height = lcg_rand_n (MAX_DST_HEIGHT) + 1; + src_stride = src_width * src_bpp + lcg_rand_n (MAX_STRIDE) * src_bpp; + mask_stride = mask_width * mask_bpp + lcg_rand_n (MAX_STRIDE) * mask_bpp; + dst_stride = dst_width * dst_bpp + lcg_rand_n (MAX_STRIDE) * dst_bpp; + + if (src_stride & 3) + src_stride += 2; + + if (mask_stride & 1) + mask_stride += 1; + if (mask_stride & 2) + mask_stride += 2; + + if (dst_stride & 3) + dst_stride += 2; + + src_x = -(src_width / 4) + lcg_rand_n (src_width * 3 / 2); + src_y = -(src_height / 4) + lcg_rand_n (src_height * 3 / 2); + mask_x = -(mask_width / 4) + lcg_rand_n (mask_width * 3 / 2); + mask_y = -(mask_height / 4) + lcg_rand_n (mask_height * 3 / 2); + dst_x = -(dst_width / 4) + lcg_rand_n (dst_width * 3 / 2); + dst_y = -(dst_height / 4) + lcg_rand_n (dst_height * 3 / 2); + w = lcg_rand_n (dst_width * 3 / 2 - dst_x); + h = lcg_rand_n (dst_height * 3 / 2 - dst_y); + + srcbuf = (uint32_t *)malloc (src_stride * src_height); + maskbuf = (uint32_t *)malloc (mask_stride * mask_height); + dstbuf = (uint32_t *)malloc (dst_stride * dst_height); + + for (i = 0; i < src_stride * src_height; i++) + *((uint8_t *)srcbuf + i) = lcg_rand_n (256); + + for (i = 0; i < mask_stride * mask_height; i++) + *((uint8_t *)maskbuf + i) = lcg_rand_n (256); + + for (i = 0; i < dst_stride * dst_height; i++) + *((uint8_t *)dstbuf + i) = lcg_rand_n (256); + + src_fmt = src_bpp == 4 ? (lcg_rand_n (2) == 0 ? + PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8) : PIXMAN_r5g6b5; + + dst_fmt = dst_bpp == 4 ? (lcg_rand_n (2) == 0 ? + PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8) : PIXMAN_r5g6b5; + + src_img = pixman_image_create_bits ( + src_fmt, src_width, src_height, srcbuf, src_stride); + + mask_img = pixman_image_create_bits ( + PIXMAN_a8, mask_width, mask_height, maskbuf, mask_stride); + + dst_img = pixman_image_create_bits ( + dst_fmt, dst_width, dst_height, dstbuf, dst_stride); + + image_endian_swap (src_img); + image_endian_swap (dst_img); + + if (lcg_rand_n (4) > 0) + { + scale_x = -32768 * 3 + lcg_rand_N (65536 * 5); + scale_y = -32768 * 3 + lcg_rand_N (65536 * 5); + translate_x = lcg_rand_N (65536); + translate_y = lcg_rand_N (65536); + pixman_transform_init_scale (&transform, scale_x, scale_y); + pixman_transform_translate (&transform, NULL, translate_x, translate_y); + pixman_image_set_transform (src_img, &transform); + } + + if (lcg_rand_n (2) > 0) + { + mask_scale_x = -32768 * 3 + lcg_rand_N (65536 * 5); + mask_scale_y = -32768 * 3 + lcg_rand_N (65536 * 5); + mask_translate_x = lcg_rand_N (65536); + mask_translate_y = lcg_rand_N (65536); + pixman_transform_init_scale (&transform, mask_scale_x, mask_scale_y); + pixman_transform_translate (&transform, NULL, mask_translate_x, mask_translate_y); + pixman_image_set_transform (mask_img, &transform); + } + + switch (lcg_rand_n (4)) + { + case 0: + mask_repeat = PIXMAN_REPEAT_NONE; + break; + + case 1: + mask_repeat = PIXMAN_REPEAT_NORMAL; + break; + + case 2: + mask_repeat = PIXMAN_REPEAT_PAD; + break; + + case 3: + mask_repeat = PIXMAN_REPEAT_REFLECT; + break; + + default: + break; + } + pixman_image_set_repeat (mask_img, mask_repeat); + + switch (lcg_rand_n (4)) + { + case 0: + repeat = PIXMAN_REPEAT_NONE; + break; + + case 1: + repeat = PIXMAN_REPEAT_NORMAL; + break; + + case 2: + repeat = PIXMAN_REPEAT_PAD; + break; + + case 3: + repeat = PIXMAN_REPEAT_REFLECT; + break; + + default: + break; + } + pixman_image_set_repeat (src_img, repeat); + + if (lcg_rand_n (2)) + pixman_image_set_filter (src_img, PIXMAN_FILTER_NEAREST, NULL, 0); + else + pixman_image_set_filter (src_img, PIXMAN_FILTER_BILINEAR, NULL, 0); + + if (lcg_rand_n (2)) + pixman_image_set_filter (mask_img, PIXMAN_FILTER_NEAREST, NULL, 0); + else + pixman_image_set_filter (mask_img, PIXMAN_FILTER_BILINEAR, NULL, 0); + + if (verbose) + { + printf ("src_fmt=%08X, dst_fmt=%08X\n", src_fmt, dst_fmt); + printf ("op=%d, scale_x=%d, scale_y=%d, repeat=%d\n", + op, scale_x, scale_y, repeat); + printf ("translate_x=%d, translate_y=%d\n", + translate_x, translate_y); + printf ("src_width=%d, src_height=%d, dst_width=%d, dst_height=%d\n", + src_width, src_height, dst_width, dst_height); + printf ("src_x=%d, src_y=%d, dst_x=%d, dst_y=%d\n", + src_x, src_y, dst_x, dst_y); + printf ("w=%d, h=%d\n", w, h); + } + + if (lcg_rand_n (8) == 0) + { + pixman_box16_t clip_boxes[2]; + int n = lcg_rand_n (2) + 1; + + for (i = 0; i < n; i++) + { + clip_boxes[i].x1 = lcg_rand_n (src_width); + clip_boxes[i].y1 = lcg_rand_n (src_height); + clip_boxes[i].x2 = + clip_boxes[i].x1 + lcg_rand_n (src_width - clip_boxes[i].x1); + clip_boxes[i].y2 = + clip_boxes[i].y1 + lcg_rand_n (src_height - clip_boxes[i].y1); + + if (verbose) + { + printf ("source clip box: [%d,%d-%d,%d]\n", + clip_boxes[i].x1, clip_boxes[i].y1, + clip_boxes[i].x2, clip_boxes[i].y2); + } + } + + pixman_region_init_rects (&clip, clip_boxes, n); + pixman_image_set_clip_region (src_img, &clip); + pixman_image_set_source_clipping (src_img, 1); + pixman_region_fini (&clip); + } + + if (lcg_rand_n (8) == 0) + { + pixman_box16_t clip_boxes[2]; + int n = lcg_rand_n (2) + 1; + + for (i = 0; i < n; i++) + { + clip_boxes[i].x1 = lcg_rand_n (mask_width); + clip_boxes[i].y1 = lcg_rand_n (mask_height); + clip_boxes[i].x2 = + clip_boxes[i].x1 + lcg_rand_n (mask_width - clip_boxes[i].x1); + clip_boxes[i].y2 = + clip_boxes[i].y1 + lcg_rand_n (mask_height - clip_boxes[i].y1); + + if (verbose) + { + printf ("mask clip box: [%d,%d-%d,%d]\n", + clip_boxes[i].x1, clip_boxes[i].y1, + clip_boxes[i].x2, clip_boxes[i].y2); + } + } + + pixman_region_init_rects (&clip, clip_boxes, n); + pixman_image_set_clip_region (mask_img, &clip); + pixman_image_set_source_clipping (mask_img, 1); + pixman_region_fini (&clip); + } + + if (lcg_rand_n (8) == 0) + { + pixman_box16_t clip_boxes[2]; + int n = lcg_rand_n (2) + 1; + for (i = 0; i < n; i++) + { + clip_boxes[i].x1 = lcg_rand_n (dst_width); + clip_boxes[i].y1 = lcg_rand_n (dst_height); + clip_boxes[i].x2 = + clip_boxes[i].x1 + lcg_rand_n (dst_width - clip_boxes[i].x1); + clip_boxes[i].y2 = + clip_boxes[i].y1 + lcg_rand_n (dst_height - clip_boxes[i].y1); + + if (verbose) + { + printf ("destination clip box: [%d,%d-%d,%d]\n", + clip_boxes[i].x1, clip_boxes[i].y1, + clip_boxes[i].x2, clip_boxes[i].y2); + } + } + pixman_region_init_rects (&clip, clip_boxes, n); + pixman_image_set_clip_region (dst_img, &clip); + pixman_region_fini (&clip); + } + + if (lcg_rand_n (2) == 0) + pixman_image_composite (op, src_img, NULL, dst_img, + src_x, src_y, 0, 0, dst_x, dst_y, w, h); + else + pixman_image_composite (op, src_img, mask_img, dst_img, + src_x, src_y, mask_x, mask_y, dst_x, dst_y, w, h); + + if (dst_fmt == PIXMAN_x8r8g8b8) + { + /* ignore unused part */ + for (i = 0; i < dst_stride * dst_height / 4; i++) + dstbuf[i] &= 0xFFFFFF; + } + + image_endian_swap (dst_img); + + if (verbose) + { + int j; + + for (i = 0; i < dst_height; i++) + { + for (j = 0; j < dst_stride; j++) + printf ("%02X ", *((uint8_t *)dstbuf + i * dst_stride + j)); + + printf ("\n"); + } + } + + pixman_image_unref (src_img); + pixman_image_unref (mask_img); + pixman_image_unref (dst_img); + + crc32 = compute_crc32 (0, dstbuf, dst_stride * dst_height); + free (srcbuf); + free (maskbuf); + free (dstbuf); + + FLOAT_REGS_CORRUPTION_DETECTOR_FINISH (); + return crc32; +} + +int +main (int argc, const char *argv[]) +{ + pixman_disable_out_of_bounds_workaround (); + + return fuzzer_test_main("scaling", 8000000, 0x80DF1CB2, + test_composite, argc, argv); +} diff --git a/pixman/test/stress-test.c b/pixman/test/stress-test.c index 571420ab0..08bf1d4df 100644 --- a/pixman/test/stress-test.c +++ b/pixman/test/stress-test.c @@ -1,4 +1,5 @@ #include <stdio.h> +#include <stdlib.h> #include "utils.h" #include <sys/types.h> diff --git a/pixman/test/trap-crasher.c b/pixman/test/trap-crasher.c index 7485e62fd..4e4cac297 100644 --- a/pixman/test/trap-crasher.c +++ b/pixman/test/trap-crasher.c @@ -1,5 +1,5 @@ #include <stdlib.h> -#include <pixman.h> +#include "utils.h" int main() @@ -22,6 +22,6 @@ main() dst = pixman_image_create_bits (PIXMAN_a8, 1, 1, NULL, -1); - pixman_add_trapezoids (dst, 0, 0, sizeof (traps)/sizeof (traps[0]), traps); + pixman_add_trapezoids (dst, 0, 0, ARRAY_LENGTH (traps), traps); return (0); } diff --git a/pixman/test/utils.c b/pixman/test/utils.c index adabd75dd..204066f9b 100644 --- a/pixman/test/utils.c +++ b/pixman/test/utils.c @@ -2,6 +2,7 @@ #include "utils.h" #include <signal.h> +#include <stdlib.h> #ifdef HAVE_GETTIMEOFDAY #include <sys/time.h> diff --git a/pixman/test/utils.h b/pixman/test/utils.h index b23925c4a..3bff78e76 100644 --- a/pixman/test/utils.h +++ b/pixman/test/utils.h @@ -2,7 +2,6 @@ #include <config.h> #endif -#include <stdlib.h> #include <assert.h> #include "pixman-private.h" /* For 'inline' definition */ |