diff options
author | Lukasz Kostyra <l.kostyra@samsung.com> | 2021-01-07 13:56:41 +0100 |
---|---|---|
committer | Lukasz Kostyra <l.kostyra@samsung.com> | 2021-01-07 17:43:22 +0100 |
commit | e95a38294313e2cfdb8ca456f77eca219ac93055 (patch) | |
tree | 17105cbefb89318c0fb4ab48f7a1840fa479e3a0 | |
parent | 2c7783b1fef54254001594636906eb27baeebd2e (diff) | |
download | emulator-yagl-e95a38294313e2cfdb8ca456f77eca219ac93055.tar.gz emulator-yagl-e95a38294313e2cfdb8ca456f77eca219ac93055.tar.bz2 emulator-yagl-e95a38294313e2cfdb8ca456f77eca219ac93055.zip |
Implement parsing of preprocessor condition directives
Some #define statements could be hidden beneath #if/#elif/#else/#endif
blocks. In order to properly recognize them YaGL shader parser now
recognizes and evaluates these blocks.
Change-Id: I1c9c0d4237b9796dbad9e9d6ef0cad9e4b3196ae
-rw-r--r-- | GLESv2/yagl_gles2_calls.c | 22 | ||||
-rw-r--r-- | GLESv2/yagl_gles2_context.c | 12 | ||||
-rw-r--r-- | GLESv2/yagl_glsl_lexer.l | 290 | ||||
-rw-r--r-- | GLESv2/yagl_glsl_parser.y | 346 | ||||
-rw-r--r-- | GLESv2/yagl_glsl_state.c | 447 | ||||
-rw-r--r-- | GLESv2/yagl_glsl_state.h | 128 |
6 files changed, 1192 insertions, 53 deletions
diff --git a/GLESv2/yagl_gles2_calls.c b/GLESv2/yagl_gles2_calls.c index 029a680..6346fc8 100644 --- a/GLESv2/yagl_gles2_calls.c +++ b/GLESv2/yagl_gles2_calls.c @@ -1404,8 +1404,6 @@ YAGL_API void glShaderSource(GLuint shader, GLsizei count, const GLchar * const } } - YAGL_LOG_INFO("have_strings is %d string is %p", have_strings, string); - if (have_strings) { uint8_t *tmp_buff; int ret; @@ -1447,19 +1445,29 @@ YAGL_API void glShaderSource(GLuint shader, GLsizei count, const GLchar * const YAGL_LOG_TRACE("patched source = %s", patched_source); - YAGL_LOG_DEBUG("extract summary:"); - YAGL_LOG_DEBUG(" defines extracted from source:"); + YAGL_LOG_TRACE("Macro and sampler extract summary:"); + YAGL_LOG_TRACE(" Macros:"); defines = yagl_vector_data(&shader_obj->state.defines); size = yagl_vector_size(&shader_obj->state.defines); for (i = 0; i < size; ++i) { - YAGL_LOG_DEBUG(" -> %s => %s", defines[i].name_orig, defines[i].name_new); + if (defines[i].name_new) + YAGL_LOG_TRACE(" -> %s => %s", defines[i].name_orig, defines[i].name_new); + else + YAGL_LOG_TRACE(" -> %s => %i", defines[i].name_orig, defines[i].value); } - YAGL_LOG_DEBUG(" samplersExternalOES extracted from source:"); + YAGL_LOG_TRACE(" samplerExternalOES uniforms:"); samplers = yagl_vector_data(&shader_obj->state.samplers_ExternalOES); size = yagl_vector_size(&shader_obj->state.samplers_ExternalOES); for (i = 0; i < size; ++i) { - YAGL_LOG_DEBUG(" -> %s: at %d unit %d", samplers[i].name, samplers[i].location, samplers[i].value); + YAGL_LOG_TRACE(" -> %s: at %d unit %d", samplers[i].name, samplers[i].location, samplers[i].value); + } + + YAGL_LOG_TRACE(" sampler2D uniforms:"); + samplers = yagl_vector_data(&shader_obj->state.samplers_2D); + size = yagl_vector_size(&shader_obj->state.samplers_2D); + for (i = 0; i < size; ++i) { + YAGL_LOG_TRACE(" -> %s: at %d unit %d", samplers[i].name, samplers[i].location, samplers[i].value); } yagl_gles2_shader_source(shader_obj, diff --git a/GLESv2/yagl_gles2_context.c b/GLESv2/yagl_gles2_context.c index 928d900..ad54510 100644 --- a/GLESv2/yagl_gles2_context.c +++ b/GLESv2/yagl_gles2_context.c @@ -641,15 +641,9 @@ void yagl_gles2_context_pre_draw(struct yagl_gles2_context *ctx, struct yagl_glsl_sampler *samplers = NULL; int i = 0, samplers_size = 0; - YAGL_LOG_DEBUG("samplersExternalOES extracted from source:"); - samplers = yagl_vector_data(&fragment_shader->state.samplers_ExternalOES); - samplers_size = yagl_vector_size(&fragment_shader->state.samplers_ExternalOES); - for (i = 0; i < samplers_size; ++i) { - YAGL_LOG_DEBUG(" -> %s: at %d unit %d", samplers[i].name, samplers[i].location, samplers[i].value); - } - ctx->base.have_externaloes_rebinds = 1; + YAGL_LOG_TRACE("Binding samplerExternalOES units into GL_TEXTURE_2D slots:"); // FIXME for now assume user is always right and there is no error cases. // Errors to consider: // * samplerExternalOES and sampler2D attempting to access same unit @@ -665,13 +659,13 @@ void yagl_gles2_context_pre_draw(struct yagl_gles2_context *ctx, &ctx->base.texture_units[samplers[i].value].target_states[yagl_gles_texture_target_external_oes]; if (texture_external_state->texture == texture_external_state->texture_zero) { - YAGL_LOG_WARN("Trying to rebind unbound external texture at unit %d", samplers[i].value); + YAGL_LOG_WARN(" #d: Trying to rebind unbound external texture at unit %d", i, samplers[i].value); continue; // TODO error GL_INVALID_OPERATION? } if (samplers[i].location == YAGL_GLSL_SAMPLER_LOCATION_UNKNOWN || samplers[i].value == YAGL_GLSL_SAMPLER_VALUE_UNKNOWN) { - YAGL_LOG_WARN("Unknown location/value of uniform %s - skipping", samplers[i].name); + YAGL_LOG_WARN(" #d: Unknown location/value of uniform %s - skipping", i, samplers[i].name); continue; } diff --git a/GLESv2/yagl_glsl_lexer.l b/GLESv2/yagl_glsl_lexer.l index 8ec6599..c5ee31a 100644 --- a/GLESv2/yagl_glsl_lexer.l +++ b/GLESv2/yagl_glsl_lexer.l @@ -17,7 +17,7 @@ static yy_size_t string_input(char *buf, yy_size_t max_size, yyscan_t yyscanner) %option prefix="yagl_glsl_lexer_" %option extra-type="struct yagl_glsl_state *" -%x COMMENT PP UNIFORM +%x COMMENT PP PP_IFDEF PP_IF PP_DEFINE PP_UNDEF UNIFORM WS [ \r\t\v\f] PRECISION "lowp"|"mediump"|"highp"|"precision"[^;\n]+;? @@ -46,17 +46,64 @@ STRING [^ \r\t\v\f\n()\[\]{},;?:/%*&|^!+\-=<>\.]+ ^{WS}*#{WS}*define { struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); - BEGIN(PP); + BEGIN(PP_DEFINE); yagl_glsl_state_new_str_token(state, yylval, yytext); return TOK_DEFINE; } +^{WS}*#{WS}*undef { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + BEGIN(PP_UNDEF); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_UNDEF; +} + ^{WS}*#{WS}*extension[^\n]* { struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); yagl_glsl_state_new_str_token(state, yylval, yytext); return TOK_EXTENSION; } +^{WS}*#{WS}*if { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + BEGIN(PP_IF); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_IF; +} + +^{WS}*#{WS}*elif { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + BEGIN(PP_IF); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_ELIF; +} + +^{WS}*#{WS}*else { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_ELSE; +} + +^{WS}*#{WS}*ifdef { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + BEGIN(PP_IFDEF); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_IFDEF; +} + +^{WS}*#{WS}*ifndef { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + BEGIN(PP_IFDEF); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_IFNDEF; +} + +^{WS}*#{WS}*endif { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_ENDIF; +} + [\n]+ { struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); yagl_glsl_state_new_pending(state, yytext); @@ -264,6 +311,220 @@ STRING [^ \r\t\v\f\n()\[\]{},;?:/%*&|^!+\-=<>\.]+ return TOK_STRING; } +<PP_DEFINE>{WS}+ { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_pending(state, yytext); +} + +<PP_DEFINE>\n { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + BEGIN(INITIAL); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_EOL; +} + +<PP_DEFINE>\/\/[^\n]* { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_comment(state, strlen(yytext)); +} + +<PP_DEFINE>[0-9]+ { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_integer_token(state, yylval, strtol(yytext, NULL, 10)); + return TOK_INTEGER; +} + +<PP_DEFINE>{STRING} { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_STRING; +} + +<PP_UNDEF>{WS}+ { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_pending(state, yytext); +} + +<PP_UNDEF>{STRING} { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + BEGIN(INITIAL); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_STRING; +} + +<PP_IF>{WS}+ { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_pending(state, yytext); +} + +<PP_IF>\n { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + BEGIN(INITIAL); + yagl_glsl_state_new_character_token(state, yylval, *yytext); + return TOK_PP_IF_EOL; +} + +<PP_IF>\/\/[^\n]* { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_comment(state, strlen(yytext)); +} + +<PP_IF>\( { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_character_token(state, yylval, *yytext); + return TOK_PP_PAREN_OPEN; +} + +<PP_IF>\) { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_character_token(state, yylval, *yytext); + return TOK_PP_PAREN_CLOSE; +} + +<PP_IF>"defined" { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_DEFINED; +} + +<PP_IF>\! { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_character_token(state, yylval, *yytext); + return TOK_PP_OP_NOT; +} + +<PP_IF>\* { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_character_token(state, yylval, *yytext); + return TOK_PP_OP_MUL; +} + +<PP_IF>\/ { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_character_token(state, yylval, *yytext); + return TOK_PP_OP_DIV; +} + +<PP_IF>\% { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_character_token(state, yylval, *yytext); + return TOK_PP_OP_MOD; +} + +<PP_IF>\+ { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_character_token(state, yylval, *yytext); + return TOK_PP_OP_ADD; +} + +<PP_IF>\- { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_character_token(state, yylval, *yytext); + return TOK_PP_OP_SUB; +} + +<PP_IF>"<<" { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_OP_SL; +} + +<PP_IF>">>" { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_OP_SR; +} + +<PP_IF>\< { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_character_token(state, yylval, *yytext); + return TOK_PP_OP_LESS; +} + +<PP_IF>\> { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_character_token(state, yylval, *yytext); + return TOK_PP_OP_GREATER; +} + +<PP_IF>"<=" { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_OP_LEQ; +} + +<PP_IF>">=" { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_OP_GEQ; +} + +<PP_IF>"==" { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_OP_EQ; +} + +<PP_IF>"!=" { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_OP_NEQ; +} + +<PP_IF>\& { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_character_token(state, yylval, *yytext); + return TOK_PP_OP_BIT_AND; +} + +<PP_IF>\^ { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_character_token(state, yylval, *yytext); + return TOK_PP_OP_BIT_XOR; +} + +<PP_IF>\| { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_character_token(state, yylval, *yytext); + return TOK_PP_OP_BIT_OR; +} + +<PP_IF>"&&" { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_OP_AND; +} + +<PP_IF>"||" { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_OP_OR; +} + +<PP_IF>[0-9]+ { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_integer_token(state, yylval, strtol(yytext, NULL, 10)); + return TOK_PP_INTEGER; +} + +<PP_IF>{STRING} { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_PP_STRING; +} + +<PP_IFDEF>{WS}+ { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + yagl_glsl_state_new_pending(state, yytext); +} + +<PP_IFDEF>{STRING} { + struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); + BEGIN(INITIAL); + yagl_glsl_state_new_str_token(state, yylval, yytext); + return TOK_STRING; +} + <UNIFORM>{WS}*; { struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner); BEGIN(INITIAL); @@ -325,7 +586,7 @@ static yy_size_t string_input(char *buf, yy_size_t max_size, yyscan_t yyscanner) return num_read; } -extern int yagl_glsl_debug; +//extern int yagl_glsl_debug; int yagl_glsl_state_init(struct yagl_glsl_state *state, GLenum shader_type, @@ -337,7 +598,7 @@ int yagl_glsl_state_init(struct yagl_glsl_state *state, memset(state, 0, sizeof(*state)); - yagl_glsl_debug = 1; + //yagl_glsl_debug = 1; if (yagl_glsl_lexer_lex_init_extra(state, &scanner)) { return 0; @@ -349,6 +610,10 @@ int yagl_glsl_state_init(struct yagl_glsl_state *state, state->es3_supported = es3_supported; state->scanner = scanner; state->token_index = 1; + memset(&state->pp_conditions, 0, sizeof(int) * YAGL_GLSL_PP_CONDITION_STACK_SIZE); + state->pp_current_condition = 0; + state->pp_condition_parse_started = 0; + state->pp_elif_check = 0; yagl_glsl_state_set_version(state, 120, 0); @@ -361,6 +626,9 @@ int yagl_glsl_state_init(struct yagl_glsl_state *state, yagl_vector_init(&state->samplers_2D, sizeof(struct yagl_glsl_sampler), 0); yagl_vector_init(&state->defines, sizeof(struct yagl_glsl_define), 0); + // we are in OpenGL ES mode - GL_ES must be defined always + yagl_glsl_state_pp_add_define_int(state, "GL_ES", 1); + return 1; } @@ -371,6 +639,7 @@ void yagl_glsl_state_cleanup(struct yagl_glsl_state *state) char **tmp; struct yagl_glsl_pending *it, *tmp_it; struct yagl_glsl_sampler *sampler_tmp; + struct yagl_glsl_define *defines_tmp; tmp = yagl_vector_data(&state->strings); @@ -396,16 +665,25 @@ void yagl_glsl_state_cleanup(struct yagl_glsl_state *state) sampler_tmp = yagl_vector_data(&state->samplers_ExternalOES); for (i = 0; i < yagl_vector_size(&state->samplers_ExternalOES); ++i) { - free((sampler_tmp + i)->name); + free(sampler_tmp[i].name); } sampler_tmp = yagl_vector_data(&state->samplers_2D); for (i = 0; i < yagl_vector_size(&state->samplers_2D); ++i) { - free((sampler_tmp + i)->name); + free(sampler_tmp[i].name); } yagl_vector_cleanup(&state->samplers_ExternalOES); yagl_vector_cleanup(&state->samplers_2D); + defines_tmp = yagl_vector_data(&state->defines); + for (i = 0; i < yagl_vector_size(&state->defines); ++i) { + if (defines_tmp[i].name_orig) + free(defines_tmp[i].name_orig); + if (defines_tmp[i].name_new) + free(defines_tmp[i].name_new); + } + yagl_vector_cleanup(&state->defines); + yagl_glsl_lexer_lex_destroy(scanner); } diff --git a/GLESv2/yagl_glsl_parser.y b/GLESv2/yagl_glsl_parser.y index d6ae2b1..f50022f 100644 --- a/GLESv2/yagl_glsl_parser.y +++ b/GLESv2/yagl_glsl_parser.y @@ -38,12 +38,50 @@ static int yagl_glsl_lex(union YYSTYPE *val, struct yagl_glsl_state *state) int index; const char *value; } str; + + struct + { + int index; + char c; + } character; } %token <str> TOK_EOL %token <str> TOK_EOI %token <str> TOK_VERSION %token <str> TOK_DEFINE +%token <str> TOK_UNDEF +%token <str> TOK_PP_IF +%token <character> TOK_PP_IF_EOL +%token <str> TOK_PP_ELIF +%token <str> TOK_PP_ELSE +%token <str> TOK_PP_IFDEF +%token <str> TOK_PP_IFNDEF +%token <str> TOK_PP_ENDIF +%token <str> TOK_PP_DEFINED +%token <character> TOK_PP_PAREN_OPEN +%token <character> TOK_PP_PAREN_CLOSE +%token <character> TOK_PP_OP_NOT +%token <character> TOK_PP_OP_MUL +%token <character> TOK_PP_OP_DIV +%token <character> TOK_PP_OP_MOD +%token <character> TOK_PP_OP_ADD +%token <character> TOK_PP_OP_SUB +%token <str> TOK_PP_OP_SL +%token <str> TOK_PP_OP_SR +%token <character> TOK_PP_OP_LESS +%token <character> TOK_PP_OP_GREATER +%token <str> TOK_PP_OP_LEQ +%token <str> TOK_PP_OP_GEQ +%token <str> TOK_PP_OP_EQ +%token <str> TOK_PP_OP_NEQ +%token <character> TOK_PP_OP_BIT_AND +%token <character> TOK_PP_OP_BIT_XOR +%token <character> TOK_PP_OP_BIT_OR +%token <str> TOK_PP_OP_AND +%token <str> TOK_PP_OP_OR +%token <str> TOK_PP_STRING +%token <integer> TOK_PP_INTEGER %token <str> TOK_EXTENSION %token <str> TOK_STRING %token <integer> TOK_INTEGER @@ -186,7 +224,7 @@ expression yagl_glsl_state_flush_pending(state, $2.index); yagl_glsl_state_append_output(state, $2.value); } -| TOK_DEFINE TOK_STRING TOK_STRING TOK_EOL +| TOK_DEFINE TOK_STRING TOK_STRING { yagl_glsl_state_flush_pending(state, $1.index); yagl_glsl_state_append_output(state, $1.value); @@ -194,16 +232,283 @@ expression yagl_glsl_state_append_output(state, $2.value); yagl_glsl_state_flush_pending(state, $3.index); yagl_glsl_state_append_output(state, $3.value); - yagl_glsl_state_flush_pending(state, $4.index); - yagl_glsl_state_append_output(state, $4.value); - yagl_glsl_state_add_define(state, $2.value, $3.value); + if (yagl_glsl_state_pp_is_condition_met(state)) + yagl_glsl_state_pp_add_define_string(state, $2.value, $3.value); +} +| TOK_DEFINE TOK_STRING TOK_INTEGER +{ + char s[100]; + + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + yagl_glsl_state_flush_pending(state, $2.index); + yagl_glsl_state_append_output(state, $2.value); + yagl_glsl_state_flush_pending(state, $3.index); + sprintf(s, "%d", $3.value); + yagl_glsl_state_append_output(state, s); + + if (yagl_glsl_state_pp_is_condition_met(state)) + yagl_glsl_state_pp_add_define_int(state, $2.value, $3.value); +} +| TOK_DEFINE TOK_STRING +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + yagl_glsl_state_flush_pending(state, $2.index); + yagl_glsl_state_append_output(state, $2.value); + + if (yagl_glsl_state_pp_is_condition_met(state)) + yagl_glsl_state_pp_add_define_int(state, $2.value, 1); +} +| TOK_UNDEF TOK_STRING +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + yagl_glsl_state_flush_pending(state, $2.index); + yagl_glsl_state_append_output(state, $2.value); + + if (yagl_glsl_state_pp_is_condition_met(state)) + yagl_glsl_state_pp_undef(state, $2.value); } | TOK_DEFINE { yagl_glsl_state_flush_pending(state, $1.index); yagl_glsl_state_append_output(state, $1.value); } +| TOK_PP_IF +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + + yagl_glsl_state_pp_condition_parse_start(state); +} +| TOK_PP_ELIF +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + + if (!yagl_glsl_state_pp_is_condition_completed(state)) { + if (yagl_glsl_state_pp_is_condition_met(state)) { + yagl_glsl_state_pp_set_condition_status(state, yagl_glsl_pp_condition_completed); + } else { + // previous condition was not met, begin evaluation of current condition + yagl_glsl_state_pp_condition_parse_start(state); + state->pp_elif_check = 1; + } + } +} +| TOK_PP_ELSE +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + + if (!yagl_glsl_state_pp_is_condition_completed(state)) { + int met = yagl_glsl_state_pp_is_condition_met(state); + yagl_glsl_state_pp_set_condition_status(state, met ? yagl_glsl_pp_condition_not_met : yagl_glsl_pp_condition_met); + } +} +| TOK_PP_IF_EOL +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output_char(state, $1.c); + + if (state->pp_condition_parse_started) { + int condition_result = yagl_glsl_state_pp_condition_resolve(state); + if (condition_result < 0) { + yyerror(state, "GLSL preprocessor condition resolution failure"); + } else { + if (state->pp_elif_check) { + yagl_glsl_state_pp_set_condition_status(state, + (condition_result > 0) ? yagl_glsl_pp_condition_met : yagl_glsl_pp_condition_not_met); + state->pp_elif_check = 0; + } else { + yagl_glsl_state_pp_start_condition(state, + (condition_result > 0) ? yagl_glsl_pp_condition_met : yagl_glsl_pp_condition_not_met); + } + } + } +} +| TOK_PP_IFDEF TOK_STRING +{ + int defined = 0; + + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + yagl_glsl_state_flush_pending(state, $2.index); + yagl_glsl_state_append_output(state, $2.value); + + defined = yagl_glsl_state_pp_is_defined(state, $2.value); + yagl_glsl_state_pp_start_condition(state, (defined > 0) ? yagl_glsl_pp_condition_met : yagl_glsl_pp_condition_not_met); +} +| TOK_PP_IFNDEF TOK_STRING +{ + int defined = 0; + + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + yagl_glsl_state_flush_pending(state, $2.index); + yagl_glsl_state_append_output(state, $2.value); + + defined = yagl_glsl_state_pp_is_defined(state, $2.value); + yagl_glsl_state_pp_start_condition(state, (defined == 0) ? yagl_glsl_pp_condition_met : yagl_glsl_pp_condition_not_met); +} +| TOK_PP_ENDIF +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + + yagl_glsl_state_pp_end_condition(state); +} +| TOK_PP_PAREN_OPEN +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output_char(state, $1.c); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_par_open); +} +| TOK_PP_PAREN_CLOSE +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output_char(state, $1.c); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_par_close); +} +| TOK_PP_DEFINED +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_defined); +} +| TOK_PP_OP_NOT +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output_char(state, $1.c); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_not); +} +| TOK_PP_OP_MUL +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output_char(state, $1.c); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_mul); +} +| TOK_PP_OP_DIV +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output_char(state, $1.c); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_div); +} +| TOK_PP_OP_MOD +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output_char(state, $1.c); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_mod); +} +| TOK_PP_OP_ADD +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output_char(state, $1.c); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_add); +} +| TOK_PP_OP_SUB +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output_char(state, $1.c); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_sub); +} +| TOK_PP_OP_SL +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_sl); +} +| TOK_PP_OP_SR +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_sr); +} +| TOK_PP_OP_LESS +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output_char(state, $1.c); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_less); +} +| TOK_PP_OP_GREATER +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output_char(state, $1.c); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_greater); +} +| TOK_PP_OP_LEQ +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_leq); +} +| TOK_PP_OP_GEQ +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_geq); +} +| TOK_PP_OP_EQ +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_eq); +} +| TOK_PP_OP_NEQ +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_neq); +} +| TOK_PP_OP_BIT_AND +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output_char(state, $1.c); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_bit_and); +} +| TOK_PP_OP_BIT_XOR +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output_char(state, $1.c); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_bit_xor); +} +| TOK_PP_OP_BIT_OR +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output_char(state, $1.c); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_bit_or); +} +| TOK_PP_OP_AND +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_and); +} +| TOK_PP_OP_OR +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + yagl_glsl_state_pp_condition_parse_add_op(state, yagl_glsl_pp_op_or); +} +| TOK_PP_INTEGER +{ + char s[100]; + + yagl_glsl_state_flush_pending(state, $1.index); + sprintf(s, "%d", $1.value); + yagl_glsl_state_append_output(state, s); + + yagl_glsl_state_pp_condition_parse_add_expr(state, NULL, $1.value); +} +| TOK_PP_STRING +{ + yagl_glsl_state_flush_pending(state, $1.index); + yagl_glsl_state_append_output(state, $1.value); + + yagl_glsl_state_pp_condition_parse_add_expr(state, $1.value, 0); +} | TOK_EXTENSION { /* @@ -353,23 +658,28 @@ expression yagl_glsl_state_flush_pending(state, $4.index); yagl_glsl_state_append_output(state, $4.value); - // locally try to resolve the define based on current knowledge - // it won't matter if our type is not a macro but an actual sampler type - char* type_resolved; - yagl_glsl_state_resolve_define(state, $2.value, &type_resolved); + if (yagl_glsl_state_pp_is_condition_met(state)) { + // locally try to resolve the define based on current knowledge + // it won't matter if our type is not a macro but an actual sampler type + char* type_resolved; + int int_resolved; + yagl_glsl_state_pp_resolve_define(state, $2.value, &type_resolved, &int_resolved); + + if (type_resolved != NULL) { + if (strcmp(type_resolved, "samplerExternalOES") == 0) { + if (!state->have_samplerexternaloes) { + yagl_glsl_state_append_header(state, "#define samplerExternalOES sampler2D\n"); + state->have_samplerexternaloes = 1; + } + + yagl_glsl_state_add_sampler_ExternalOES(state, $3.value); + } else if (strcmp(type_resolved, "sampler2D") == 0) { + yagl_glsl_state_add_sampler_2D(state, $3.value); + } - if (strcmp(type_resolved, "samplerExternalOES") == 0) { - if (!state->have_samplerexternaloes) { - yagl_glsl_state_append_header(state, "#define samplerExternalOES sampler2D\n"); - state->have_samplerexternaloes = 1; + free(type_resolved); } - - yagl_glsl_state_add_sampler_ExternalOES(state, $3.value); - } else if (strcmp(type_resolved, "sampler2D") == 0) { - yagl_glsl_state_add_sampler_2D(state, $3.value); } - - free(type_resolved); } | TOK_TEXTURE1D { diff --git a/GLESv2/yagl_glsl_state.c b/GLESv2/yagl_glsl_state.c index ee7f33f..544b30d 100644 --- a/GLESv2/yagl_glsl_state.c +++ b/GLESv2/yagl_glsl_state.c @@ -40,6 +40,68 @@ #include <stdio.h> #include <assert.h> +// LUT for operator priorities +// these follow GLSL specification but reversed - higher priority is higher number +const int glsl_pp_op_prio[] = { + 0, // yagl_glsl_pp_op_error + 0, // yagl_glsl_pp_op_token + 1, // yagl_glsl_pp_op_or + 2, // yagl_glsl_pp_op_and + 3, // yagl_glsl_pp_op_bit_or + 4, // yagl_glsl_pp_op_bit_xor + 5, // yagl_glsl_pp_op_bit_and + 6, // yagl_glsl_pp_op_neq + 6, // yagl_glsl_pp_op_eq + 7, // yagl_glsl_pp_op_geq + 7, // yagl_glsl_pp_op_leq + 7, // yagl_glsl_pp_op_greater + 7, // yagl_glsl_pp_op_less + 8, // yagl_glsl_pp_op_sr + 8, // yagl_glsl_pp_op_sl + 9, // yagl_glsl_pp_op_sub + 9, // yagl_glsl_pp_op_add + 10, // yagl_glsl_pp_op_mod + 10, // yagl_glsl_pp_op_div + 10, // yagl_glsl_pp_op_mul + 11, // yagl_glsl_pp_op_not + 11, // yagl_glsl_pp_op_bit_not + 11, // yagl_glsl_pp_op_negative + 11, // yagl_glsl_pp_op_positive + 11, // yagl_glsl_pp_op_defined + 0, // yagl_glsl_pp_op_par_open - lowest priority because of special handling + 0, // yagl_glsl_pp_op_par_close - lowest priority because of special handling +}; + +const char *glsl_pp_op_dbgstr[] = { + "op_error", + "op_token", + "op_or", + "op_and", + "op_bit_or", + "op_bit_xor", + "op_bit_and", + "op_neq", + "op_eq", + "op_geq", + "op_leq", + "op_greater", + "op_less", + "op_sr", + "op_sl", + "op_sub", + "op_add", + "op_mod", + "op_div", + "op_mul", + "op_not", + "op_bit_not", + "op_negative", + "op_positive", + "op_defined", + "op_par_open", + "op_par_close", +}; + static void yagl_glsl_state_flush_version(struct yagl_glsl_state *state) { int have_version = state->have_version; @@ -226,6 +288,18 @@ void yagl_glsl_state_new_integer_token(struct yagl_glsl_state *state, ++state->token_index; } +void yagl_glsl_state_new_character_token(struct yagl_glsl_state *state, + YYSTYPE *yylval, + char c) +{ + yagl_glsl_state_move_pending(state); + + yylval->character.index = state->token_index; + yylval->character.c = c; + + ++state->token_index; +} + void yagl_glsl_state_flush_pending(struct yagl_glsl_state *state, int token_index) { @@ -272,6 +346,19 @@ void yagl_glsl_state_append_output(struct yagl_glsl_state *state, memcpy(yagl_vector_data(&state->output) + size, str, str_len); } +void yagl_glsl_state_append_output_char(struct yagl_glsl_state *state, + char c) +{ + int size; + char* data; + + size = yagl_vector_size(&state->output); + + yagl_vector_resize(&state->output, size + 1); + data = (char*)yagl_vector_data(&state->output); + data[size] = c; +} + void yagl_glsl_state_output_to_header(struct yagl_glsl_state *state) { int header_size, output_size; @@ -326,31 +413,52 @@ void yagl_glsl_state_add_sampler_2D(struct yagl_glsl_state *state, yagl_vector_push_back(&state->samplers_2D, &sampler); } -void yagl_glsl_state_add_define(struct yagl_glsl_state *state, - const char *tok_orig, const char *tok_new) +void yagl_glsl_state_pp_add_define_string(struct yagl_glsl_state *state, + const char *tok_orig, const char *tok_new) { struct yagl_glsl_define define; define.name_orig = strdup(tok_orig); define.name_new = strdup(tok_new); + define.value = 0; + yagl_vector_push_back(&state->defines, &define); +} + +void yagl_glsl_state_pp_add_define_int(struct yagl_glsl_state *state, + const char *tok_orig, int value) +{ + struct yagl_glsl_define define; + define.name_orig = strdup(tok_orig); + define.name_new = NULL; + define.value = value; yagl_vector_push_back(&state->defines, &define); } -void yagl_glsl_state_resolve_define(struct yagl_glsl_state *state, - const char *token, char **resolved) +void yagl_glsl_state_pp_undef(struct yagl_glsl_state *state, + const char *macro) +{ + // TODO + // Might require switching state->defines into yagl_list +} + +void yagl_glsl_state_pp_resolve_define(struct yagl_glsl_state *state, + const char *token, char **resolved, int *resolved_int) { struct yagl_glsl_define *defines = yagl_vector_data(&state->defines); int i = 0, defines_size = yagl_vector_size(&state->defines); const char* to_resolve = token; - YAGL_LOG_FUNC_SET(yagl_glsl_state_resolve_define); assert(resolved != NULL); + assert(resolved_int != NULL); - YAGL_LOG_DEBUG("LKDEBUG resolving define %s", to_resolve); while (1) { for (i = 0; i < defines_size; ++i) { if (strcmp(to_resolve, defines[i].name_orig) == 0) { - YAGL_LOG_DEBUG(" * %s -> %s", to_resolve, defines[i].name_new); - to_resolve = defines[i].name_new; + if (defines[i].name_new == NULL) { + *resolved_int = defines[i].value; + return; + } else { + to_resolve = defines[i].name_new; + } break; } } @@ -362,5 +470,326 @@ void yagl_glsl_state_resolve_define(struct yagl_glsl_state *state, } *resolved = strdup(to_resolve); - YAGL_LOG_DEBUG("resolved as %s", *resolved); +} + +int yagl_glsl_state_pp_is_defined(struct yagl_glsl_state *state, const char *macro) +{ + struct yagl_glsl_define *defines = yagl_vector_data(&state->defines); + int i = 0, defines_size = yagl_vector_size(&state->defines); + + for (i = 0; i < defines_size; ++i) { + if (strcmp(macro, defines[i].name_orig) == 0) { + return 1; + } + } + + return 0; +} + +void yagl_glsl_state_pp_start_condition(struct yagl_glsl_state *state, yagl_glsl_pp_condition_status condition_met) +{ + assert(state->pp_current_condition < YAGL_GLSL_PP_CONDITION_STACK_SIZE); + + state->pp_conditions[state->pp_current_condition] = condition_met; + state->pp_current_condition++; +} + +void yagl_glsl_state_pp_end_condition(struct yagl_glsl_state *state) +{ + assert(state->pp_current_condition > 0); + + state->pp_current_condition--; +} + +void yagl_glsl_state_pp_set_condition_status(struct yagl_glsl_state *state, yagl_glsl_pp_condition_status condition_met) +{ + assert(state->pp_current_condition > 0); + + state->pp_conditions[state->pp_current_condition - 1] = condition_met; +} + +int yagl_glsl_state_pp_is_condition_met(struct yagl_glsl_state *state) +{ + if (state->pp_current_condition) + // we are in a condition scope, check if it's met + return (state->pp_conditions[state->pp_current_condition - 1] == yagl_glsl_pp_condition_met); + else + // outside of any condition scope, we don't need to exclude any preprocessor code + // so assume preprocessor condition is met anyway + return 1; +} + +int yagl_glsl_state_pp_is_condition_completed(struct yagl_glsl_state *state) +{ + if (state->pp_current_condition) + return (state->pp_conditions[state->pp_current_condition - 1] == yagl_glsl_pp_condition_completed); + else + return 1; +} + +void yagl_glsl_state_pp_condition_parse_start(struct yagl_glsl_state *state) +{ + // initialize expression stack and operation stack for RPN + memset(state->pp_exprs, 0, sizeof(struct yagl_glsl_pp_expr) * YAGL_GLSL_PP_EXPRESSION_STACK_SIZE); + state->pp_current_expr = 0; + + memset(state->pp_ops, 0, sizeof(yagl_glsl_pp_expr_op) * YAGL_GLSL_PP_OPERATION_STACK_SIZE); + state->pp_current_op = 0; + + state->pp_condition_parse_started = 1; +} + +void yagl_glsl_state_pp_condition_parse_add_expr(struct yagl_glsl_state *state, const char* token, int value) +{ + if (!state->pp_condition_parse_started) + return; + + assert(state->pp_current_expr < YAGL_GLSL_PP_EXPRESSION_STACK_SIZE); + + state->pp_exprs[state->pp_current_expr].op = yagl_glsl_pp_op_token; + state->pp_exprs[state->pp_current_expr].token.macro = token ? strdup(token) : NULL; + state->pp_exprs[state->pp_current_expr].token.value = value; + state->pp_current_expr++; +} + +void yagl_glsl_state_pp_condition_parse_add_op(struct yagl_glsl_state *state, yagl_glsl_pp_expr_op op) +{ + if (!state->pp_condition_parse_started) + return; + + assert(state->pp_current_op < YAGL_GLSL_PP_OPERATION_STACK_SIZE); + assert(state->pp_current_expr < YAGL_GLSL_PP_EXPRESSION_STACK_SIZE); + + // if stack is empty or we encounter an open parenthesis, just add op and return + if ((state->pp_current_op == 0) || (op == yagl_glsl_pp_op_par_open)) { + state->pp_ops[state->pp_current_op] = op; + state->pp_current_op++; + return; + } + + // if we encounter a closed parenthesis + if (op == yagl_glsl_pp_op_par_close) { + // move ops from op stack to expr stack until we hit open parenthesis + while (state->pp_ops[state->pp_current_op - 1] != yagl_glsl_pp_op_par_open) { + assert(state->pp_current_op > 0 && state->pp_curent_expr < YAGL_GLSL_PP_EXPRESSION_STACK_SIZE); + state->pp_current_op--; + state->pp_exprs[state->pp_current_expr].op = state->pp_ops[state->pp_current_op]; + state->pp_current_expr++; + } + + // remove open parenthesis from stack but without writing it + assert(state->pp_current_op > 0); + state->pp_current_op--; + return; + } + + // move higher or equal priority operations to expression stack + while (glsl_pp_op_prio[op] <= glsl_pp_op_prio[state->pp_ops[state->pp_current_op - 1]]) { + assert(state->pp_current_op > 0 && state->pp_curent_expr < YAGL_GLSL_PP_EXPRESSION_STACK_SIZE); + state->pp_current_op--; + state->pp_exprs[state->pp_current_expr].op = state->pp_ops[state->pp_current_op]; + state->pp_current_expr++; + } + + // store op + state->pp_ops[state->pp_current_op] = op; + state->pp_current_op++; +} + +static int yagl_glsl_state_pp_solve_unary(struct yagl_glsl_state *state, + yagl_glsl_pp_expr_op op, + struct yagl_glsl_pp_token token, + int *result) +{ + char* tmp; + int v; + + assert(result != NULL); + + // special case for "defined" function + if (op == yagl_glsl_pp_op_defined) { + if (token.macro == NULL) { + return 0; // error + } + + *result = yagl_glsl_state_pp_is_defined(state, token.macro); + return 1; + } + + if (token.macro != NULL) { + yagl_glsl_state_pp_resolve_define(state, token.macro, &tmp, &v); + if (tmp != NULL) { + return 0; + } + } else { + v = token.value; + } + + switch (op) { + case yagl_glsl_pp_op_not: *result = !v; break; + case yagl_glsl_pp_op_bit_not: *result = ~v; break; + case yagl_glsl_pp_op_negative: *result = -v; break; + case yagl_glsl_pp_op_positive: *result = +v; break; + default: + return 0; + } + + return 1; +} + +static int yagl_glsl_state_pp_solve_binary(struct yagl_glsl_state *state, + yagl_glsl_pp_expr_op op, + struct yagl_glsl_pp_token tok_a, + struct yagl_glsl_pp_token tok_b, + int *result) +{ + char *tmp; + int a, b; + + assert(result != NULL); + + // resolve first macro + if (tok_a.macro != NULL) { + yagl_glsl_state_pp_resolve_define(state, tok_a.macro, &tmp, &a); + if (tmp != NULL) { + return 0; + } + } else { + a = tok_a.value; + } + + // resolve second macro + if (tok_b.macro != NULL) { + yagl_glsl_state_pp_resolve_define(state, tok_b.macro, &tmp, &b); + if (tmp != NULL) { + return 0; + } + } else { + b = tok_b.value; + } + + switch (op) { + case yagl_glsl_pp_op_or: *result = (a || b); break; + case yagl_glsl_pp_op_and: *result = (a && b); break; + case yagl_glsl_pp_op_bit_or: *result = (a | b); break; + case yagl_glsl_pp_op_bit_xor: *result = (a ^ b); break; + case yagl_glsl_pp_op_bit_and: *result = (a & b); break; + case yagl_glsl_pp_op_neq: *result = (a != b); break; + case yagl_glsl_pp_op_eq: *result = (a == b); break; + case yagl_glsl_pp_op_geq: *result = (a >= b); break; + case yagl_glsl_pp_op_leq: *result = (a <= b); break; + case yagl_glsl_pp_op_greater: *result = (a > b); break; + case yagl_glsl_pp_op_less: *result = (a < b); break; + case yagl_glsl_pp_op_sr: *result = (a >> b); break; + case yagl_glsl_pp_op_sl: *result = (a << b); break; + case yagl_glsl_pp_op_sub: *result = (a - b); break; + case yagl_glsl_pp_op_add: *result = (a + b); break; + case yagl_glsl_pp_op_mod: *result = (a % b); break; + case yagl_glsl_pp_op_div: *result = (a / b); break; + case yagl_glsl_pp_op_mul: *result = (a * b); break; + default: + return 0; + } + + return 1; +} + +static inline int yagl_glsl_pp_expr_op_is_unary(yagl_glsl_pp_expr_op op) +{ + switch (op) { + case yagl_glsl_pp_op_not: + case yagl_glsl_pp_op_bit_not: + case yagl_glsl_pp_op_negative: + case yagl_glsl_pp_op_positive: + case yagl_glsl_pp_op_defined: + return 1; + case yagl_glsl_pp_op_or: + case yagl_glsl_pp_op_and: + case yagl_glsl_pp_op_bit_or: + case yagl_glsl_pp_op_bit_xor: + case yagl_glsl_pp_op_bit_and: + case yagl_glsl_pp_op_neq: + case yagl_glsl_pp_op_eq: + case yagl_glsl_pp_op_geq: + case yagl_glsl_pp_op_leq: + case yagl_glsl_pp_op_greater: + case yagl_glsl_pp_op_less: + case yagl_glsl_pp_op_sr: + case yagl_glsl_pp_op_sl: + case yagl_glsl_pp_op_sub: + case yagl_glsl_pp_op_add: + case yagl_glsl_pp_op_mod: + case yagl_glsl_pp_op_div: + case yagl_glsl_pp_op_mul: + return 0; + default: + assert(0); // illegal operators, shouldn't happen + return -1; + } +} + +int yagl_glsl_state_pp_condition_resolve(struct yagl_glsl_state *state) +{ + struct yagl_glsl_pp_token res_stack[YAGL_GLSL_PP_EXPRESSION_STACK_SIZE]; + int res_cur = 0; + struct yagl_glsl_pp_token tok_a, tok_b; + int i, tmp_result; + int result = 0; + + // empty op stack into expression stack + while (state->pp_current_op > 0) { + assert(state->pp_current_op > 0 && state->pp_curent_expr < YAGL_GLSL_PP_EXPRESSION_STACK_SIZE); + state->pp_current_op--; + state->pp_exprs[state->pp_current_expr].op = state->pp_ops[state->pp_current_op]; + state->pp_current_expr++; + } + + // go through expressions and solve them + for (i = 0; i < state->pp_current_expr; i++) { + if (state->pp_exprs[i].op == yagl_glsl_pp_op_token) { + res_stack[res_cur] = state->pp_exprs[i].token; + res_cur++; + } else { + if (yagl_glsl_pp_expr_op_is_unary(state->pp_exprs[i].op)) { + assert(res_cur > 0); + + if (!yagl_glsl_state_pp_solve_unary(state, state->pp_exprs[i].op, res_stack[res_cur - 1], &tmp_result)) { + result = -1; + goto clean; + } + } else { + assert(res_cur >= 2); + + tok_a = res_stack[res_cur - 2]; + tok_b = res_stack[res_cur - 1]; + res_cur--; + + if (!yagl_glsl_state_pp_solve_binary(state, state->pp_exprs[i].op, tok_a, tok_b, &tmp_result)) { + result = -1; + goto clean; + } + } + + res_stack[res_cur - 1].value = tmp_result; + res_stack[res_cur - 1].macro = NULL; // any possible macro string is still owned by state->pp_exprs + } + } + + // there should be only one resolution on stack remaining - the result + assert(res_cur == 1); + result = res_stack[res_cur - 1].value; + +clean: + // cleanup + for (i = 0; i < state->pp_current_expr; ++i) { + if (state->pp_exprs[i].token.macro != NULL) { + yagl_free(state->pp_exprs[i].token.macro); + } + } + + state->pp_current_expr = 0; + state->pp_current_op = 0; + state->pp_condition_parse_started = 0; + + return result; } diff --git a/GLESv2/yagl_glsl_state.h b/GLESv2/yagl_glsl_state.h index 4091339..9f3ef59 100644 --- a/GLESv2/yagl_glsl_state.h +++ b/GLESv2/yagl_glsl_state.h @@ -51,11 +51,15 @@ struct yagl_glsl_pending #define YAGL_GLSL_SAMPLER_LOCATION_UNKNOWN (-1) #define YAGL_GLSL_SAMPLER_VALUE_UNKNOWN (-1) +#define YAGL_GLSL_PP_CONDITION_STACK_SIZE 16 +#define YAGL_GLSL_PP_EXPRESSION_STACK_SIZE 128 +#define YAGL_GLSL_PP_OPERATION_STACK_SIZE 64 struct yagl_glsl_define { char* name_orig; char* name_new; + int value; }; struct yagl_glsl_sampler @@ -68,6 +72,58 @@ struct yagl_glsl_sampler typedef enum { + yagl_glsl_pp_condition_not_met = 0, + yagl_glsl_pp_condition_met, + yagl_glsl_pp_condition_completed, +} yagl_glsl_pp_condition_status; + +// operations processed in preprocessor condition resolving +// order is defined according to priorities in GLSL specification +typedef enum +{ + yagl_glsl_pp_op_error = 0, + yagl_glsl_pp_op_token, + yagl_glsl_pp_op_or, + yagl_glsl_pp_op_and, + yagl_glsl_pp_op_bit_or, + yagl_glsl_pp_op_bit_xor, + yagl_glsl_pp_op_bit_and, + yagl_glsl_pp_op_neq, + yagl_glsl_pp_op_eq, + yagl_glsl_pp_op_geq, + yagl_glsl_pp_op_leq, + yagl_glsl_pp_op_greater, + yagl_glsl_pp_op_less, + yagl_glsl_pp_op_sr, + yagl_glsl_pp_op_sl, + yagl_glsl_pp_op_sub, + yagl_glsl_pp_op_add, + yagl_glsl_pp_op_mod, + yagl_glsl_pp_op_div, + yagl_glsl_pp_op_mul, + yagl_glsl_pp_op_not, + yagl_glsl_pp_op_bit_not, + yagl_glsl_pp_op_negative, + yagl_glsl_pp_op_positive, + yagl_glsl_pp_op_defined, + yagl_glsl_pp_op_par_open, + yagl_glsl_pp_op_par_close, +} yagl_glsl_pp_expr_op; + +struct yagl_glsl_pp_token +{ + char* macro; + int value; +}; + +struct yagl_glsl_pp_expr +{ + yagl_glsl_pp_expr_op op; + struct yagl_glsl_pp_token token; +}; + +typedef enum +{ yagl_glsl_asis, yagl_glsl_120, yagl_glsl_140, @@ -149,6 +205,23 @@ struct yagl_glsl_state // names of sampler2D uniforms struct yagl_vector samplers_2D; + // stack of conditions currently in scope; 0 is not met, 1 is met, 2 is completed + // 2 is used to pass through #elif/#else blocks when we satisfied the condition already + yagl_glsl_pp_condition_status pp_conditions[YAGL_GLSL_PP_CONDITION_STACK_SIZE]; // TODO make dynamic + int pp_current_condition; + + // flags for parsing conditions + int pp_condition_parse_started; + int pp_elif_check; + + // stack of expressions for preprocessor condition parsing + struct yagl_glsl_pp_expr pp_exprs[YAGL_GLSL_PP_EXPRESSION_STACK_SIZE]; // TODO make dynamic + int pp_current_expr; + + // helper stack of operations for preprocessor condition parsing + yagl_glsl_pp_expr_op pp_ops[YAGL_GLSL_PP_OPERATION_STACK_SIZE]; // TODO make dynamic + int pp_current_op; + /* * @} */ @@ -183,6 +256,10 @@ void yagl_glsl_state_new_integer_token(struct yagl_glsl_state *state, YYSTYPE *yylval, int value); +void yagl_glsl_state_new_character_token(struct yagl_glsl_state *state, + YYSTYPE *yylval, + char c); + void yagl_glsl_state_flush_pending(struct yagl_glsl_state *state, int token_index); @@ -192,6 +269,9 @@ void yagl_glsl_state_append_header(struct yagl_glsl_state *state, void yagl_glsl_state_append_output(struct yagl_glsl_state *state, const char *str); +void yagl_glsl_state_append_output_char(struct yagl_glsl_state *state, + char c); + void yagl_glsl_state_output_to_header(struct yagl_glsl_state *state); /* @@ -205,11 +285,51 @@ void yagl_glsl_state_add_sampler_ExternalOES(struct yagl_glsl_state *state, void yagl_glsl_state_add_sampler_2D(struct yagl_glsl_state *state, const char *str); -void yagl_glsl_state_add_define(struct yagl_glsl_state *state, - const char *tok_orig, const char *tok_new); +/* + * GLSL Preprocessor control functions + * @{ + */ +void yagl_glsl_state_pp_add_define_string(struct yagl_glsl_state *state, + const char *tok_orig, const char *tok_new); + +void yagl_glsl_state_pp_add_define_int(struct yagl_glsl_state *state, + const char *tok_orig, int value); + +void yagl_glsl_state_pp_undef(struct yagl_glsl_state *state, + const char *macro); + +// resolved will be NULL if the result of our resolution is an integer +void yagl_glsl_state_pp_resolve_define(struct yagl_glsl_state *state, + const char *token, char **resolved, int *resolved_int); + +// >0 if defined, 0 if not +int yagl_glsl_state_pp_is_defined(struct yagl_glsl_state *state, const char *macro); -void yagl_glsl_state_resolve_define(struct yagl_glsl_state *state, - const char *token, char **resolved); +// mark if current preprocessor condition is met, we +void yagl_glsl_state_pp_start_condition(struct yagl_glsl_state *state, yagl_glsl_pp_condition_status condition_met); + +// end current preprocessor condition +void yagl_glsl_state_pp_end_condition(struct yagl_glsl_state *state); + +// edit current condition - useful for #elif/#else directives +void yagl_glsl_state_pp_set_condition_status(struct yagl_glsl_state *state, yagl_glsl_pp_condition_status condition_met); + +// check if recently parsed preprocessor condition was met; 1 if met, 0 if not met +int yagl_glsl_state_pp_is_condition_met(struct yagl_glsl_state *state); +int yagl_glsl_state_pp_is_condition_completed(struct yagl_glsl_state *state); + +// initialize parsing stack for preprocessor condition parsing +void yagl_glsl_state_pp_condition_parse_start(struct yagl_glsl_state *state); + +// add tokens to preprocessor condition parser +void yagl_glsl_state_pp_condition_parse_add_expr(struct yagl_glsl_state *state, const char* token, int value); +void yagl_glsl_state_pp_condition_parse_add_op(struct yagl_glsl_state *state, yagl_glsl_pp_expr_op op); + +// resolve preprocessor condition parser; 1 if met, 0 if not met, -1 on error +int yagl_glsl_state_pp_condition_resolve(struct yagl_glsl_state *state); +/* + * @} + */ int yagl_glsl_parse(struct yagl_glsl_state *state); |