summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukasz Kostyra <l.kostyra@samsung.com>2021-01-21 18:49:50 +0100
committerLukasz Kostyra <l.kostyra@samsung.com>2021-01-21 18:52:27 +0100
commitfc6b56c5fb1ed811faf62c89689aa9ac4a813de9 (patch)
tree4650c246a3ec44a1c48748e5238f72f7a25a9bc5
parent1022a5686113a5e6a46348ed305b3fa12e86e762 (diff)
downloademulator-yagl-fc6b56c5fb1ed811faf62c89689aa9ac4a813de9.tar.gz
emulator-yagl-fc6b56c5fb1ed811faf62c89689aa9ac4a813de9.tar.bz2
emulator-yagl-fc6b56c5fb1ed811faf62c89689aa9ac4a813de9.zip
Replace vertex shader external textures & fix some issues
Vertex shader, just like fragment shader, has access to samplers. This patch enables rebinding textures used in vertex shader, which could be of type samplerExternalOES. Additional issues fixed: * Shader Program could be vertex-only. This caused crashes, which are now fixed. * Condition resolution in GLSL parser was incorrect and has been fixed Change-Id: I2c30b1c30ae9d75467e2c6dd4f4e128adc630320
-rw-r--r--GLESv2/yagl_gles2_context.c165
-rw-r--r--GLESv2/yagl_gles2_context.h6
-rw-r--r--GLESv2/yagl_gles2_program.c52
-rw-r--r--GLESv2/yagl_glsl_state.c77
-rw-r--r--GLESv2/yagl_glsl_state.h2
5 files changed, 207 insertions, 95 deletions
diff --git a/GLESv2/yagl_gles2_context.c b/GLESv2/yagl_gles2_context.c
index 1ff5f80..64fedad 100644
--- a/GLESv2/yagl_gles2_context.c
+++ b/GLESv2/yagl_gles2_context.c
@@ -473,6 +473,79 @@ struct yagl_gles_array
return arrays;
}
+static void yagl_gles2_context_bind_externaloes(struct yagl_gles2_context *ctx,
+ struct yagl_gles2_shader *shader)
+{
+ struct yagl_glsl_sampler *samplers;
+ int i = 0, samplers_size = 0;
+ YAGL_LOG_FUNC_SET(yagl_gles2_context_bind_externaloes);
+
+ YAGL_LOG_DEBUG("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
+ // * samplerExternalOES points at unit having no texture bound
+ samplers = yagl_vector_data(&shader->state.samplers_ExternalOES);
+ samplers_size = yagl_vector_size(&shader->state.samplers_ExternalOES);
+ for (i = 0; i < samplers_size; ++i) {
+ struct yagl_gles_texture_target_state *texture_2d_state, *texture_external_state;
+
+ texture_2d_state =
+ &ctx->base.texture_units[samplers[i].value].target_states[yagl_gles_texture_target_2d];
+ texture_external_state =
+ &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(" #%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(" #%d: Unknown location/value of uniform %s - skipping", i, samplers[i].name);
+ continue;
+ }
+
+ // we could have currently bound either an actual texture 2d or a "zero texture" (for binding = 0)
+ // store whatever is bound from cached info, we'll restore it post-draw
+ if (texture_2d_state->texture != texture_2d_state->texture_zero) {
+ samplers[i].replaced_tex2d = texture_2d_state->texture->global_name;
+ YAGL_LOG_DEBUG(" -> Binding in place of existing texture");
+ } else {
+ samplers[i].replaced_tex2d = texture_2d_state->texture_zero->global_name;
+ YAGL_LOG_DEBUG(" -> Binding in place of zero texture");
+ }
+ YAGL_LOG_DEBUG(" #%d: slot %d texture2D %d => textureExternal %d", i, samplers[i].value, samplers[i].replaced_tex2d,
+ texture_external_state->texture->global_name);
+
+ // samplers[i].value is unit requested by app from shader - replace it
+ yagl_host_glActiveTexture(GL_TEXTURE0 + samplers[i].value);
+ yagl_host_glBindTexture(GL_TEXTURE_2D, texture_external_state->texture->global_name);
+ }
+}
+
+static void yagl_gles2_context_restore_externaloes_binds(struct yagl_gles2_shader *shader)
+{
+ struct yagl_glsl_sampler *samplers;
+ int i = 0, samplers_size = 0;
+ YAGL_LOG_FUNC_SET(yagl_gles2_context_restore_externaloes_binds);
+
+ YAGL_LOG_DEBUG("Restoring TEXTURE_2D bindings:");
+ samplers = yagl_vector_data(&shader->state.samplers_ExternalOES);
+ samplers_size = yagl_vector_size(&shader->state.samplers_ExternalOES);
+ for (i = 0; i < samplers_size; ++i) {
+ if (samplers[i].location == YAGL_GLSL_SAMPLER_LOCATION_UNKNOWN ||
+ samplers[i].value == YAGL_GLSL_SAMPLER_VALUE_UNKNOWN) {
+ continue;
+ }
+
+ YAGL_LOG_DEBUG(" #%d: %d unit => %d texture", i, samplers[i].value, samplers[i].replaced_tex2d);
+ yagl_host_glActiveTexture(GL_TEXTURE0 + samplers[i].value);
+ yagl_host_glBindTexture(GL_TEXTURE_2D, samplers[i].replaced_tex2d);
+ samplers[i].replaced_tex2d = YAGL_GLSL_SAMPLER_VALUE_UNKNOWN;
+ }
+}
+
void yagl_gles2_context_pre_draw(struct yagl_gles2_context *ctx,
GLenum mode,
GLint count)
@@ -636,53 +709,18 @@ void yagl_gles2_context_pre_draw(struct yagl_gles2_context *ctx,
* Check for currently bound shaders if any samplers are of samplerExternalOES type.
* If they are, do some extra checks and bind some textures temporarily.
*/
- struct yagl_gles2_shader *fragment_shader = ctx->program->fragment_shader;
- if (fragment_shader->state.have_samplerexternaloes) {
- struct yagl_glsl_sampler *samplers = NULL;
- int i = 0, samplers_size = 0;
-
- 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
- // * samplerExternalOES points at unit having no texture bound
- 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) {
- struct yagl_gles_texture_target_state *texture_2d_state, *texture_external_state;
-
- texture_2d_state =
- &ctx->base.texture_units[samplers[i].value].target_states[yagl_gles_texture_target_2d];
- texture_external_state =
- &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(" #%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(" #%d: Unknown location/value of uniform %s - skipping", i, samplers[i].name);
- continue;
- }
-
- // we could have currently bound either an actual texture 2d or a "zero texture" (for binding = 0)
- // store whatever is bound from cached info, we'll restore it post-draw
- if (texture_2d_state->texture != texture_2d_state->texture_zero) {
- samplers[i].replaced_tex2d = texture_2d_state->texture->global_name;
- } else {
- samplers[i].replaced_tex2d = texture_2d_state->texture_zero->global_name;
- }
- YAGL_LOG_TRACE(" #%d: slot %d texture2D %d => textureExternal %d", i, samplers[i].value, samplers[i].replaced_tex2d,
- texture_external_state->texture->global_name);
+ struct yagl_gles2_shader *vertex_shader = ctx->program->vertex_shader;
+ if (vertex_shader && vertex_shader->state.have_samplerexternaloes) {
+ ctx->have_externaloes_rebinds_vs = 1;
+ YAGL_LOG_DEBUG("======= Vertex shader has samplerExternalOES ========");
+ yagl_gles2_context_bind_externaloes(ctx, vertex_shader);
+ }
- // samplers[i].value is unit requested by app from shader - replace it
- yagl_host_glActiveTexture(GL_TEXTURE0 + samplers[i].value);
- yagl_host_glBindTexture(GL_TEXTURE_2D, texture_external_state->texture->global_name);
- }
+ struct yagl_gles2_shader *fragment_shader = ctx->program->fragment_shader;
+ if (fragment_shader && fragment_shader->state.have_samplerexternaloes) {
+ ctx->have_externaloes_rebinds_fs = 1;
+ YAGL_LOG_DEBUG("======= Fragment shader has samplerExternalOES ========");
+ yagl_gles2_context_bind_externaloes(ctx, fragment_shader);
}
}
@@ -690,8 +728,6 @@ void yagl_gles2_context_post_draw(struct yagl_gles2_context *ctx,
GLenum mode,
GLint count)
{
- YAGL_LOG_FUNC_SET(yagl_gles2_context_post_draw);
-
if (mode == GL_POINTS) {
yagl_host_glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
if (yagl_get_host_gl_version() <= yagl_gl_3_2) {
@@ -721,28 +757,21 @@ void yagl_gles2_context_post_draw(struct yagl_gles2_context *ctx,
/*
* Restore original TEXTURE_2D bindings
*/
- if (ctx->base.have_externaloes_rebinds) {
- struct yagl_gles2_shader *fragment_shader = ctx->program->fragment_shader;
- struct yagl_glsl_sampler *samplers;
- int i = 0, samplers_size = 0;
-
- YAGL_LOG_TRACE("Restoring TEXTURE_2D bindings:");
- 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) {
- if (samplers[i].location == YAGL_GLSL_SAMPLER_LOCATION_UNKNOWN ||
- samplers[i].value == YAGL_GLSL_SAMPLER_VALUE_UNKNOWN) {
- continue;
- }
+ if (ctx->have_externaloes_rebinds_vs) {
+ yagl_gles2_context_restore_externaloes_binds(ctx->program->vertex_shader);
+ }
- YAGL_LOG_TRACE(" #%d: %d unit => %d texture", i, samplers[i].value, samplers[i].replaced_tex2d);
- yagl_host_glActiveTexture(GL_TEXTURE0 + samplers[i].value);
- yagl_host_glBindTexture(GL_TEXTURE_2D, samplers[i].replaced_tex2d);
- samplers[i].replaced_tex2d = YAGL_GLSL_SAMPLER_VALUE_UNKNOWN;
- }
+ if (ctx->have_externaloes_rebinds_fs) {
+ yagl_gles2_context_restore_externaloes_binds(ctx->program->fragment_shader);
+ }
- yagl_host_glActiveTexture(ctx->base.active_texture_unit);
- ctx->base.have_externaloes_rebinds = 0;
+ /*
+ * Reactivate texture unit which was active before draw and zero flags
+ */
+ if (ctx->have_externaloes_rebinds_vs || ctx->have_externaloes_rebinds_fs) {
+ yagl_host_glActiveTexture(GL_TEXTURE0 + ctx->base.active_texture_unit);
+ ctx->have_externaloes_rebinds_vs = 0;
+ ctx->have_externaloes_rebinds_fs = 0;
}
}
diff --git a/GLESv2/yagl_gles2_context.h b/GLESv2/yagl_gles2_context.h
index cf127ba..d306223 100644
--- a/GLESv2/yagl_gles2_context.h
+++ b/GLESv2/yagl_gles2_context.h
@@ -141,6 +141,12 @@ struct yagl_gles2_context
GLint max_vertex_uniform_components;
GLclampf blend_color[4];
+
+ /*
+ * Like for yagl_gles_context, but per-shader
+ */
+ int have_externaloes_rebinds_vs;
+ int have_externaloes_rebinds_fs;
};
/*
diff --git a/GLESv2/yagl_gles2_program.c b/GLESv2/yagl_gles2_program.c
index 3e0f888..9fe3966 100644
--- a/GLESv2/yagl_gles2_program.c
+++ b/GLESv2/yagl_gles2_program.c
@@ -417,16 +417,31 @@ int yagl_gles2_program_get_uniform_location(struct yagl_gles2_program *program,
* Luckily, uniform location does not change so it has to be done
* only once.
*/
- if (program->fragment_shader->state.have_samplerexternaloes) {
- struct yagl_glsl_sampler *data = NULL, *it = NULL;
+ if (program->vertex_shader &&
+ program->vertex_shader->state.have_samplerexternaloes) {
+ struct yagl_glsl_sampler *data = NULL;
+ int i = 0, data_size = 0;
+
+ data = yagl_vector_data(&program->vertex_shader->state.samplers_ExternalOES);
+ data_size = yagl_vector_size(&program->vertex_shader->state.samplers_ExternalOES);
+ for (i = 0; i < data_size; ++i) {
+ if (strcmp(data[i].name, name) == 0) {
+ data[i].location = ret;
+ break;
+ }
+ }
+ }
+
+ if (program->fragment_shader &&
+ program->fragment_shader->state.have_samplerexternaloes) {
+ struct yagl_glsl_sampler *data = NULL;
int i = 0, data_size = 0;
data = yagl_vector_data(&program->fragment_shader->state.samplers_ExternalOES);
data_size = yagl_vector_size(&program->fragment_shader->state.samplers_ExternalOES);
for (i = 0; i < data_size; ++i) {
- it = data + i;
- if (strcmp(it->name, name) == 0) {
- it->location = ret;
+ if (strcmp(data[i].name, name) == 0) {
+ data[i].location = ret;
break;
}
}
@@ -681,18 +696,33 @@ int yagl_gles2_program_uniform1i(struct yagl_gles2_program *program,
yagl_host_glUniform1i(program->gen_locations, global_location, x);
/*
- * Update fragment shader state for pre_draw/post_draw analysis
+ * Update shader state for pre_draw/post_draw analysis
*/
- if (program->fragment_shader->state.have_samplerexternaloes) {
- struct yagl_glsl_sampler *data = NULL, *it = NULL;
+ if (program->vertex_shader &&
+ program->vertex_shader->state.have_samplerexternaloes) {
+ struct yagl_glsl_sampler *data = NULL;
+ int i = 0, data_size = 0;
+
+ data = yagl_vector_data(&program->vertex_shader->state.samplers_ExternalOES);
+ data_size = yagl_vector_size(&program->vertex_shader->state.samplers_ExternalOES);
+ for (i = 0; i < data_size; ++i) {
+ if (data[i].location == location) {
+ data[i].value = x;
+ break;
+ }
+ }
+ }
+
+ if (program->fragment_shader &&
+ program->fragment_shader->state.have_samplerexternaloes) {
+ struct yagl_glsl_sampler *data = NULL;
int i = 0, data_size = 0;
data = yagl_vector_data(&program->fragment_shader->state.samplers_ExternalOES);
data_size = yagl_vector_size(&program->fragment_shader->state.samplers_ExternalOES);
for (i = 0; i < data_size; ++i) {
- it = data + i;
- if (it->location == location) {
- it->value = x;
+ if (data[i].location == location) {
+ data[i].value = x;
break;
}
}
diff --git a/GLESv2/yagl_glsl_state.c b/GLESv2/yagl_glsl_state.c
index 6c12f68..74def14 100644
--- a/GLESv2/yagl_glsl_state.c
+++ b/GLESv2/yagl_glsl_state.c
@@ -439,7 +439,50 @@ void yagl_glsl_state_pp_undef(struct yagl_glsl_state *state,
// TODO
// Might require switching state->defines into yagl_list
}
+/*
+static void yagl_glsl_state_pp_dbg_print_expr_stack(struct yagl_glsl_state *state, const char* func_name)
+{
+ int i = 0;
+ const char* _yagl_log_current_func = func_name ? func_name : "yagl_glsl_state_pp_dbg_print_expr_stack";
+ pid_t _yagl_log_current_pid = getpid();
+ pid_t _yagl_log_current_tid = syscall(SYS_gettid);
+
+
+ YAGL_LOG_TRACE(" Expression stack state:");
+ for (i = state->pp_current_expr - 1; i >= 0; --i) {
+ if (state->pp_exprs[i].op == yagl_glsl_pp_op_token) {
+ if (state->pp_exprs[i].token.macro) {
+ YAGL_LOG_TRACE(" #%d: macro %s", i, state->pp_exprs[i].token.macro);
+ } else {
+ YAGL_LOG_TRACE(" #%d: const %d", i, state->pp_exprs[i].token.value);
+ }
+ } else {
+ YAGL_LOG_TRACE(" #%d: oper %d (%s) prio %d", i,
+ state->pp_exprs[i].op, glsl_pp_op_dbgstr[state->pp_exprs[i].op],
+ glsl_pp_op_prio[state->pp_exprs[i].op]
+ );
+ }
+ }
+ YAGL_LOG_TRACE(" ");
+}
+static void yagl_glsl_state_pp_dbg_print_op_stack(struct yagl_glsl_state *state, const char* func_name)
+{
+ int i = 0;
+ const char* _yagl_log_current_func = func_name ? func_name : "yagl_glsl_state_pp_dbg_print_op_stack";
+ pid_t _yagl_log_current_pid = getpid();
+ pid_t _yagl_log_current_tid = syscall(SYS_gettid);
+
+ YAGL_LOG_TRACE(" Operation stack state:");
+ for (i = state->pp_current_op - 1; i >= 0; --i) {
+ YAGL_LOG_TRACE(" #%d: op %d (%s) prio %d", i,
+ state->pp_ops[i], glsl_pp_op_dbgstr[state->pp_ops[i]],
+ glsl_pp_op_prio[state->pp_ops[i]]
+ );
+ }
+ YAGL_LOG_TRACE(" ");
+}
+*/
void yagl_glsl_state_pp_resolve_define(struct yagl_glsl_state *state,
const char *token, char **resolved, int *resolved_int)
{
@@ -510,21 +553,22 @@ void yagl_glsl_state_pp_set_condition_status(struct yagl_glsl_state *state, yagl
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 result = 1;
+ int i = 0;
+
+ // for current condition to be met all conditions on the stack must be met
+ // if there is no conditions on stack, result is always true (we're not in condition scope)
+ for (i = 0; i < state->pp_current_condition; ++i) {
+ result &= (state->pp_conditions[i] == yagl_glsl_pp_condition_met);
+ }
+
+ return result;
}
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;
+ assert(state->pp_current_condition > 0);
+ return (state->pp_conditions[state->pp_current_condition - 1] == yagl_glsl_pp_condition_completed);
}
void yagl_glsl_state_pp_condition_parse_start(struct yagl_glsl_state *state)
@@ -545,7 +589,6 @@ void yagl_glsl_state_pp_condition_parse_add_expr(struct yagl_glsl_state *state,
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;
@@ -584,8 +627,9 @@ void yagl_glsl_state_pp_condition_parse_add_op(struct yagl_glsl_state *state, ya
}
// 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_current_expr < YAGL_GLSL_PP_EXPRESSION_STACK_SIZE);
+ while (glsl_pp_op_prio[op] <= glsl_pp_op_prio[state->pp_ops[state->pp_current_op - 1]] &&
+ state->pp_current_op > 0) {
+ assert(state->pp_current_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++;
@@ -619,6 +663,7 @@ static int yagl_glsl_state_pp_solve_unary(struct yagl_glsl_state *state,
if (token.macro != NULL) {
yagl_glsl_state_pp_resolve_define(state, token.macro, &tmp, &v);
if (tmp != NULL) {
+ yagl_free(tmp);
return 0;
}
} else {
@@ -652,6 +697,7 @@ static int yagl_glsl_state_pp_solve_binary(struct yagl_glsl_state *state,
if (tok_a.macro != NULL) {
yagl_glsl_state_pp_resolve_define(state, tok_a.macro, &tmp, &a);
if (tmp != NULL) {
+ yagl_free(tmp);
return 0;
}
} else {
@@ -662,6 +708,7 @@ static int yagl_glsl_state_pp_solve_binary(struct yagl_glsl_state *state,
if (tok_b.macro != NULL) {
yagl_glsl_state_pp_resolve_define(state, tok_b.macro, &tmp, &b);
if (tmp != NULL) {
+ yagl_free(tmp);
return 0;
}
} else {
@@ -739,7 +786,7 @@ yagl_glsl_pp_condition_status yagl_glsl_state_pp_condition_resolve(struct yagl_g
// empty op stack into expression stack
while (state->pp_current_op > 0) {
- assert(state->pp_current_op > 0 && state->pp_current_expr < YAGL_GLSL_PP_EXPRESSION_STACK_SIZE);
+ assert(state->pp_current_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++;
diff --git a/GLESv2/yagl_glsl_state.h b/GLESv2/yagl_glsl_state.h
index 99dabb5..7e4a87b 100644
--- a/GLESv2/yagl_glsl_state.h
+++ b/GLESv2/yagl_glsl_state.h
@@ -51,7 +51,7 @@ 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_CONDITION_STACK_SIZE 32
#define YAGL_GLSL_PP_EXPRESSION_STACK_SIZE 128
#define YAGL_GLSL_PP_OPERATION_STACK_SIZE 64