Replace vertex shader external textures & fix some issues 12/252012/1
authorLukasz Kostyra <l.kostyra@samsung.com>
Thu, 21 Jan 2021 17:49:50 +0000 (18:49 +0100)
committerLukasz Kostyra <l.kostyra@samsung.com>
Thu, 21 Jan 2021 17:52:27 +0000 (18:52 +0100)
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

GLESv2/yagl_gles2_context.c
GLESv2/yagl_gles2_context.h
GLESv2/yagl_gles2_program.c
GLESv2/yagl_glsl_state.c
GLESv2/yagl_glsl_state.h

index 1ff5f80c58651e668a22edbfa91a49bf1118bfb5..64fedad3309287cc2c13c3ca344f58993426962a 100644 (file)
@@ -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;
     }
 }
 
index cf127ba1a7604e3d5af48e6877514f77f2edecc0..d306223bb874ce5b8b6a4db513ed3068cb6238ae 100644 (file)
@@ -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;
 };
 
 /*
index 3e0f88878a2b1444e345be5ed5a14d65fb4fc57b..9fe3966d5bc9865d04a97ffe47ba277b02d5edbd 100644 (file)
@@ -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;
             }
         }
index 6c12f684e1df6a08cfc3fbf1516dc119f7e87cac..74def144bf0c808be24423dd924c3f8f3caa7dca 100644 (file)
@@ -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++;
index 99dabb50e66354d223a14fdd77f46b6786013efd..7e4a87b276cff07e8c6c52000e74a9c317f51d12 100644 (file)
@@ -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