summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukasz Kostyra <l.kostyra@samsung.com>2021-01-07 13:56:41 +0100
committerLukasz Kostyra <l.kostyra@samsung.com>2021-01-07 17:43:22 +0100
commite95a38294313e2cfdb8ca456f77eca219ac93055 (patch)
tree17105cbefb89318c0fb4ab48f7a1840fa479e3a0
parent2c7783b1fef54254001594636906eb27baeebd2e (diff)
downloademulator-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.c22
-rw-r--r--GLESv2/yagl_gles2_context.c12
-rw-r--r--GLESv2/yagl_glsl_lexer.l290
-rw-r--r--GLESv2/yagl_glsl_parser.y346
-rw-r--r--GLESv2/yagl_glsl_state.c447
-rw-r--r--GLESv2/yagl_glsl_state.h128
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);