include_directories(${CMAKE_CURRENT_BINARY_DIR})
link_directories(${CMAKE_ARCHIVE_OUTPUT_DIRECTORY})
-flex_target(GLESv2 ${CMAKE_CURRENT_SOURCE_DIR}/yagl_glsl_lexer.l ${CMAKE_CURRENT_BINARY_DIR}/yagl_glsl_lexer.c)
-bison_target(GLESv2 ${CMAKE_CURRENT_SOURCE_DIR}/yagl_glsl_parser.y ${CMAKE_CURRENT_BINARY_DIR}/yagl_glsl_parser.c
+flex_target(GLSL_lexer ${CMAKE_CURRENT_SOURCE_DIR}/yagl_glsl_lexer.l ${CMAKE_CURRENT_BINARY_DIR}/yagl_glsl_lexer.c)
+bison_target(GLSL_parser ${CMAKE_CURRENT_SOURCE_DIR}/yagl_glsl_parser.y ${CMAKE_CURRENT_BINARY_DIR}/yagl_glsl_parser.c
VERBOSE)
+add_flex_bison_dependency(GLSL_lexer GLSL_parser)
-add_library(GLESv2 SHARED ${SOURCES} ${FLEX_GLESv2_OUTPUTS} ${BISON_GLESv2_OUTPUTS})
+add_library(GLESv2 SHARED ${SOURCES} ${FLEX_GLSL_lexer_OUTPUTS} ${BISON_GLSL_parser_OUTPUTS})
set_target_properties(GLESv2 PROPERTIES VERSION 2.0 SOVERSION 2)
target_link_libraries(GLESv2 "-Wl,-whole-archive" GLES_common "-Wl,-no-whole-archive")
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_TRACE(" -> %s: at %d unit %d", samplers[i].name, samplers[i].location, samplers[i].value);
+ YAGL_LOG_TRACE(" -> %s: at %d unit %d count %d",
+ samplers[i].name, samplers[i].location, samplers[i].value, samplers[i].count);
}
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_LOG_TRACE(" -> %s: at %d unit %d count %d",
+ samplers[i].name, samplers[i].location, samplers[i].value, samplers[i].count);
}
yagl_gles2_shader_source(shader_obj,
return TOK_PP_IF_EOL;
}
+<PP_IF>\] {
+ // for handling expression resolution in-code
+ struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner);
+ BEGIN(UNIFORM);
+ yagl_glsl_state_new_character_token(state, yylval, *yytext);
+ return TOK_ARR_PAREN_CLOSE;
+}
+
<PP_IF>\/\/[^\n]* {
struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner);
yagl_glsl_state_new_comment(state, strlen(yytext));
<UNIFORM>\[ {
struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner);
+ BEGIN(PP_IF);
yagl_glsl_state_new_character_token(state, yylval, *yytext);
return TOK_ARR_PAREN_OPEN;
}
-<UNIFORM>\] {
- struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner);
- yagl_glsl_state_new_character_token(state, yylval, *yytext);
- return TOK_ARR_PAREN_CLOSE;
-}
-
-<UNIFORM>[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;
-}
-
<UNIFORM>{STRING} {
struct yagl_glsl_state *state = yagl_glsl_lexer_get_extra(yyscanner);
yagl_glsl_state_new_str_token(state, yylval, yytext);
state->es3_supported = es3_supported;
state->scanner = scanner;
state->token_index = 1;
+ state->last_declared_sampler_externaloes = -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;
yagl_glsl_state_append_output_char(state, $1.c);
if (state->pp_condition_parse_started) {
- yagl_glsl_pp_condition_status status = yagl_glsl_state_pp_condition_resolve(state);
+ yagl_glsl_pp_condition_status status = yagl_glsl_state_pp_condition_resolve(state, NULL);
if (status == yagl_glsl_pp_condition_error) {
yyerror(state, "GLSL preprocessor condition resolution failure");
} else {
yagl_glsl_state_append_output(state, $1.value);
}
}
-| TOK_UNIFORM TOK_STRING TOK_STRING TOK_STRING TOK_ARR_PAREN_OPEN TOK_INTEGER TOK_ARR_PAREN_CLOSE TOK_EOI
+| TOK_UNIFORM TOK_STRING TOK_STRING TOK_STRING TOK_EOI
{
- 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, $4.value);
yagl_glsl_state_flush_pending(state, $5.index);
yagl_glsl_state_append_output_char(state, $5.c);
- yagl_glsl_state_flush_pending(state, $6.index);
- snprintf(s, 100, "%d", $6.value);
- yagl_glsl_state_append_output(state, s);
- yagl_glsl_state_flush_pending(state, $7.index);
- yagl_glsl_state_append_output_char(state, $7.c);
- yagl_glsl_state_flush_pending(state, $8.index);
- yagl_glsl_state_append_output_char(state, $8.c);
- // TODO this should also take into account TOK_INTEGER, because it could be an array of samplers
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
yagl_glsl_state_add_sampler_2D(state, $4.value);
}
+ yagl_glsl_state_set_last_sampler_array_count(state, 1);
free(type_resolved);
}
}
}
-| TOK_UNIFORM TOK_STRING TOK_STRING TOK_ARR_PAREN_OPEN TOK_INTEGER TOK_ARR_PAREN_CLOSE TOK_EOI
+| TOK_UNIFORM TOK_STRING TOK_STRING TOK_EOI
{
- 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, $3.value);
yagl_glsl_state_flush_pending(state, $4.index);
yagl_glsl_state_append_output_char(state, $4.c);
- yagl_glsl_state_flush_pending(state, $5.index);
- snprintf(s, 100, "%d", $5.value);
- yagl_glsl_state_append_output(state, s);
- yagl_glsl_state_flush_pending(state, $6.index);
- yagl_glsl_state_append_output_char(state, $6.c);
- yagl_glsl_state_flush_pending(state, $7.index);
- yagl_glsl_state_append_output_char(state, $7.c);
- // TODO this should also take into account TOK_INTEGER, because it is an array of samplers (not a single sampler)
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
yagl_glsl_state_add_sampler_2D(state, $3.value);
}
+ yagl_glsl_state_set_last_sampler_array_count(state, 1);
free(type_resolved);
}
}
}
-| TOK_UNIFORM TOK_STRING TOK_STRING TOK_STRING TOK_EOI
+| TOK_UNIFORM TOK_STRING TOK_STRING TOK_STRING TOK_ARR_PAREN_OPEN
{
yagl_glsl_state_flush_pending(state, $1.index);
yagl_glsl_state_append_output(state, $1.value);
state->have_samplerexternaloes = 1;
}
+ // TODO add how many samplers are added too - check resolution_value
yagl_glsl_state_add_sampler_ExternalOES(state, $4.value);
+ yagl_glsl_state_pp_condition_parse_start(state);
} else if (strcmp(type_resolved, "sampler2D") == 0) {
yagl_glsl_state_add_sampler_2D(state, $4.value);
+ yagl_glsl_state_pp_condition_parse_start(state);
}
free(type_resolved);
}
}
}
-| TOK_UNIFORM TOK_STRING TOK_STRING TOK_EOI
+| TOK_UNIFORM TOK_STRING TOK_STRING TOK_ARR_PAREN_OPEN
{
yagl_glsl_state_flush_pending(state, $1.index);
yagl_glsl_state_append_output(state, $1.value);
}
yagl_glsl_state_add_sampler_ExternalOES(state, $3.value);
+ yagl_glsl_state_pp_condition_parse_start(state);
} else if (strcmp(type_resolved, "sampler2D") == 0) {
yagl_glsl_state_add_sampler_2D(state, $3.value);
+ yagl_glsl_state_pp_condition_parse_start(state);
}
free(type_resolved);
}
}
}
+| TOK_ARR_PAREN_CLOSE TOK_EOI
+{
+ yagl_glsl_state_flush_pending(state, $1.index);
+ yagl_glsl_state_append_output_char(state, $1.c);
+ yagl_glsl_state_flush_pending(state, $2.index);
+ yagl_glsl_state_append_output_char(state, $2.c);
+
+ // check our expression resolution result to know how many array items we have
+ if (state->pp_condition_parse_started) {
+ int resolution_value = 0;
+ yagl_glsl_pp_condition_status status = yagl_glsl_state_pp_condition_resolve(state, &resolution_value);
+ if (yagl_glsl_state_pp_is_condition_met(state)) {
+ if (status == yagl_glsl_pp_condition_error) {
+ yyerror(state, "GLSL preprocessor expression resolution failure");
+ }
+
+ if (resolution_value <= 0) {
+ yyerror(state, "GLSL declared uniform array of size less than (or equal) to 0");
+ }
+
+ // TODO sampler array is rarely used, but it still has to be properly processed
+ // at samplerExternalOES -> sampler2D substitution stage
+ yagl_glsl_state_set_last_sampler_array_count(state, resolution_value);
+ }
+ }
+}
| TOK_TEXTURE1D
{
yagl_glsl_state_flush_pending(state, $1.index);
sampler.name = strdup(str);
sampler.location = YAGL_GLSL_SAMPLER_LOCATION_UNKNOWN;
sampler.value = 0; // GL spec predefines uniform value as 0
+ sampler.count = YAGL_GLSL_SAMPLER_DEFAULT_COUNT; // real count provided by yagl_glsl_state_set_last_sampler_array_count
sampler.replaced_tex2d = YAGL_GLSL_SAMPLER_VALUE_UNKNOWN;
yagl_vector_push_back(&state->samplers_ExternalOES, &sampler);
+
+ state->last_declared_sampler_externaloes = 1;
}
void yagl_glsl_state_add_sampler_2D(struct yagl_glsl_state *state,
sampler.name = strdup(str);
sampler.location = YAGL_GLSL_SAMPLER_LOCATION_UNKNOWN;
sampler.value = 0; // GL spec predefines uniform value as 0
+ sampler.count = YAGL_GLSL_SAMPLER_DEFAULT_COUNT; // real count provided by yagl_glsl_state_set_last_sampler_array_count
sampler.replaced_tex2d = YAGL_GLSL_SAMPLER_VALUE_UNKNOWN;
yagl_vector_push_back(&state->samplers_2D, &sampler);
+
+ state->last_declared_sampler_externaloes = 0;
+}
+
+void yagl_glsl_state_set_last_sampler_array_count(struct yagl_glsl_state *state, int count)
+{
+ assert(state->last_declared_sampler_externaloes != -1);
+
+ struct yagl_vector *samplers = NULL;
+ if (state->last_declared_sampler_externaloes) {
+ samplers = &state->samplers_ExternalOES;
+ } else {
+ samplers = &state->samplers_2D;
+ }
+
+ int samplers_size = yagl_vector_size(samplers);
+ assert(samplers_size > 0);
+ struct yagl_glsl_sampler *samplers_data = (struct yagl_glsl_sampler *)yagl_vector_data(samplers);
+ samplers_data += samplers_size - 1;
+ samplers_data->count = count;
+
+ state->last_declared_sampler_externaloes = -1;
}
void yagl_glsl_state_pp_add_define_string(struct yagl_glsl_state *state,
void yagl_glsl_state_pp_condition_parse_start(struct yagl_glsl_state *state)
{
+ assert(!state->pp_condition_parse_started);
+
// 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;
}
}
-yagl_glsl_pp_condition_status yagl_glsl_state_pp_condition_resolve(struct yagl_glsl_state *state)
+yagl_glsl_pp_condition_status yagl_glsl_state_pp_condition_resolve(struct yagl_glsl_state *state,
+ int *resolution_value)
{
struct yagl_glsl_pp_token res_stack[YAGL_GLSL_PP_EXPRESSION_STACK_SIZE];
int res_cur = 0;
yagl_glsl_pp_condition_status result = yagl_glsl_pp_condition_not_met;
YAGL_LOG_FUNC_SET(yagl_glsl_state_pp_condition_resolve);
+ assert(state->pp_condition_parse_started);
+
// empty op stack into expression stack
while (state->pp_current_op > 0) {
assert(state->pp_current_expr < YAGL_GLSL_PP_EXPRESSION_STACK_SIZE);
// there should be only one resolution on stack remaining - the result
assert(res_cur == 1);
- result = (res_stack[res_cur - 1].value > 0 ? yagl_glsl_pp_condition_met : yagl_glsl_pp_condition_not_met);
+
+ // in some cases resolution can be just a preprocessor macro - try resolving it
+ int result_value = 0;
+ if (res_stack[res_cur - 1].macro != NULL) {
+ char* define_resolution = NULL; // should stay null, but if it doesn't it's syntax error
+ yagl_glsl_state_pp_resolve_define(state, res_stack[res_cur - 1].macro, &define_resolution, &result_value);
+ if (define_resolution != NULL) {
+ // error - macro did not become a constant, cannot evaluate result
+ YAGL_LOG_ERROR("Expression resolution error - macro %s did not evaluate to integer constant", res_stack[res_cur - 1].macro);
+ result = yagl_glsl_pp_condition_error;
+ yagl_free(define_resolution);
+ goto clean;
+ }
+ } else {
+ result_value = res_stack[res_cur - 1].value;
+ }
+
+ // determine final result (and pass the value if it's needed)
+ result = (result_value > 0 ? yagl_glsl_pp_condition_met : yagl_glsl_pp_condition_not_met);
+ if (resolution_value != NULL) {
+ *resolution_value = result_value;
+ YAGL_LOG_TRACE("Expression resolution value: %d", *resolution_value);
+ }
clean:
// cleanup
#define YAGL_GLSL_SAMPLER_LOCATION_UNKNOWN (-1)
#define YAGL_GLSL_SAMPLER_VALUE_UNKNOWN (-1)
+#define YAGL_GLSL_SAMPLER_DEFAULT_COUNT (0)
#define YAGL_GLSL_PP_CONDITION_STACK_SIZE 32
#define YAGL_GLSL_PP_EXPRESSION_STACK_SIZE 128
#define YAGL_GLSL_PP_OPERATION_STACK_SIZE 64
char* name;
int location;
int value;
+ int count; // for uniform array support
int replaced_tex2d; // only used in samplerExternalOES handling
};
int texturecube_declared;
int texturecubelod_declared;
+ // used for determining which sampler group was used last
+ int last_declared_sampler_externaloes;
+
// Each token is assigned an index.
int token_index;
void yagl_glsl_state_add_sampler_2D(struct yagl_glsl_state *state,
const char *str);
+// Reaches last added sampler (ExternalOES or 2D) and adds information on how many samplers there are
+// count can be 1 for singular samplers and more for sampler arrays
+void yagl_glsl_state_set_last_sampler_array_count(struct yagl_glsl_state *state, int count);
+
/*
* GLSL Preprocessor control functions
* @{
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
-yagl_glsl_pp_condition_status yagl_glsl_state_pp_condition_resolve(struct yagl_glsl_state *state);
+// detailed information on resolution value can be optionally acquired via resolution_value param
+yagl_glsl_pp_condition_status yagl_glsl_state_pp_condition_resolve(struct yagl_glsl_state *state, int *resolution_value);
/*
* @}
*/