ctx->polygon_offset_units = 0.0f;
ctx->dither_enabled = GL_TRUE;
+
+ ctx->have_externaloes_rebinds = 0;
}
void yagl_gles_context_prepare(struct yagl_gles_context *ctx,
texture = texture_target_state->texture_zero;
}
- if (!yagl_gles_texture_bind(texture, target)) {
- YAGL_SET_ERR(GL_INVALID_OPERATION);
- return;
+ // TEXTURE_EXTERNAL_OES is late bound, before drawing
+ if (target != GL_TEXTURE_EXTERNAL_OES) {
+ if (!yagl_gles_texture_bind(texture, target)) {
+ YAGL_SET_ERR(GL_INVALID_OPERATION);
+ return;
+ }
}
yagl_gles_texture_acquire(texture);
GLboolean sample_coverage_enabled;
GLboolean scissor_test_enabled;
GLboolean stencil_test_enabled;
+
+ /*
+ * Texture information to restore post-draw. Updated only by pre/post-draw
+ */
+ int have_externaloes_rebinds;
};
void yagl_gles_context_init(struct yagl_gles_context *ctx,
return 0;
}
- yagl_host_glBindTexture(target == GL_TEXTURE_EXTERNAL_OES ? GL_TEXTURE_2D : target,
- texture->global_name);
+ // To support TEXTURE_EXTERNAL_OES we need to use TEXTURE_2D target
+ // on host side. In order to not collide with what is bound there we'll
+ // store the texture for later on guest side and do the temporary bind
+ // on-demand, whenever app modifies TEXTURE_EXTERNAL_OES
+ // target via other GL APIs.
+ assert(target != GL_TEXTURE_EXTERNAL_OES);
+
+ yagl_host_glBindTexture(target, texture->global_name);
texture->target = target;
texture->binding = NULL;
}
- /*
- * FIXME We still need to update the host binding when using external
- * textures even if that same image is already set. E.g. consider the bellow
- * scenario:
- * glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
- * glBindTexture(GL_TEXTURE_2D, 0);
- * glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, img);
- * External textures are handled as GL_TEXTURE_2D thus the corresponding
- * host binding will be zero in this case.
- */
if (texture->image == image) {
goto bind;
}
texture->internalformat = GL_RGBA;
bind:
- yagl_host_glBindTexture(texture->target == GL_TEXTURE_EXTERNAL_OES ? GL_TEXTURE_2D : texture->target,
- texture->global_name);
+ if (texture->target != GL_TEXTURE_EXTERNAL_OES) {
+ yagl_host_glBindTexture(texture->target, texture->global_name);
+ }
}
void yagl_gles_texture_unset_image(struct yagl_gles_texture *texture)
texture->global_name = yagl_get_global_name();
yagl_host_glGenTextures(&texture->global_name, 1);
- yagl_host_glBindTexture(texture->target == GL_TEXTURE_EXTERNAL_OES ? GL_TEXTURE_2D : texture->target,
- texture->global_name);
+ if (texture->target != GL_TEXTURE_EXTERNAL_OES) {
+ yagl_host_glBindTexture(texture->target, texture->global_name);
+ }
}
}
texture->image = image;
texture->binding = binding;
- yagl_host_glBindTexture(texture->target == GL_TEXTURE_EXTERNAL_OES ? GL_TEXTURE_2D : texture->target,
- texture->global_name);
+ if (texture->target != GL_TEXTURE_EXTERNAL_OES) {
+ yagl_host_glBindTexture(texture->target, texture->global_name);
+ }
}
/*
yagl_object_acquire(sg->texture_zero[i]);
}
- yagl_gles_texture_bind(texture_unit->target_states[i].texture_zero,
- target_map[i]);
+ // TEXTURE_EXTERNAL_OES is manually late-bound, before drawing
+ if (target_map[i] != GL_TEXTURE_EXTERNAL_OES) {
+ yagl_gles_texture_bind(texture_unit->target_states[i].texture_zero,
+ target_map[i]);
+ }
yagl_gles_texture_acquire(texture_unit->target_states[i].texture_zero);
texture_unit->target_states[i].texture =
}
}
+// Below pre-draw and post-draw are GLESv1-exclusive
+// Fixed-funciton GLES needs a bit different handling than programmable GLES
+static void yagl_gles1_context_pre_draw(struct yagl_gles_context *ctx)
+{
+ // In GLESv1 there is a set priority of used texture targets.
+ // TEXTURE_EXTERNAL_OES takes over TEXTURE_2D - we must rebind if that's the case
+ // luckily switching textures
+ GLboolean is_externaloes_enabled = 0;
+ ctx->is_enabled(ctx, GL_TEXTURE_EXTERNAL_OES, &is_externaloes_enabled);
+ if (is_externaloes_enabled) {
+ struct yagl_gles_texture_target_state *texture_external_state;
+
+ texture_external_state =
+ &ctx->texture_units[ctx->active_texture_unit].target_states[yagl_gles_texture_target_external_oes];
+
+ if (texture_external_state->texture != texture_external_state->texture_zero) {
+ yagl_host_glBindTexture(GL_TEXTURE_2D, texture_external_state->texture->global_name);
+ ctx->have_externaloes_rebinds = 1;
+ }
+ }
+}
+
+static void yagl_gles1_context_post_draw(struct yagl_gles_context *ctx)
+{
+ // Return to previous binding to keep consistency for other functions
+ if (ctx->have_externaloes_rebinds) {
+ struct yagl_gles_texture_target_state *texture_2d_state;
+
+ texture_2d_state =
+ &ctx->texture_units[ctx->active_texture_unit].target_states[yagl_gles_texture_target_2d];
+
+ yagl_host_glBindTexture(GL_TEXTURE_2D, texture_2d_state->texture->global_name);
+ ctx->have_externaloes_rebinds = 0;
+ }
+}
+
static void yagl_gles1_context_draw_arrays(struct yagl_gles_context *ctx,
GLenum mode,
GLint first,
return;
}
+ yagl_gles1_context_pre_draw(ctx);
+
if ((mode == GL_POINTS) && ctx->vao->arrays[yagl_gles1_array_pointsize].enabled) {
yagl_gles1_draw_arrays_psize(ctx, first, count);
} else {
yagl_host_glDrawArrays(mode, first, count);
}
+
+ yagl_gles1_context_post_draw(ctx);
}
static void yagl_gles1_context_draw_elements(struct yagl_gles_context *ctx,
return;
}
+ yagl_gles1_context_pre_draw(ctx);
+
if ((mode == GL_POINTS) && ctx->vao->arrays[yagl_gles1_array_pointsize].enabled) {
yagl_gles1_draw_elem_psize(ctx, count, type, indices, indices_count);
} else {
yagl_host_glDrawElements(mode, count, type, indices, indices_count);
}
+
+ yagl_gles1_context_post_draw(ctx);
}
static int yagl_gles1_context_bind_buffer(struct yagl_gles_context *ctx,
}
}
+ YAGL_LOG_INFO("have_strings is %d string is %p", have_strings, string);
+
if (have_strings) {
uint8_t *tmp_buff;
int ret;
*/
struct yagl_gles2_shader *fragment_shader = ctx->program->fragment_shader;
if (fragment_shader->state.have_samplerexternaloes) {
- struct yagl_glsl_sampler *data = NULL, *it = NULL;
- int i = 0;
+ struct yagl_glsl_sampler *samplers = NULL;
+ int i = 0, samplers_size = 0;
+
+ ctx->base.have_externaloes_rebinds = 1;
+
+ // 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("Trying to rebind unbound external texture at unit %d", samplers[i].value);
+ continue; // TODO error GL_INVALID_OPERATION?
+ }
- YAGL_LOG_INFO("LKDEBUG We have samplerExternalOES to handle");
+ 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);
+ continue;
+ }
- // LKDEBUG
- data = yagl_vector_data(&fragment_shader->state.samplers_ExternalOES);
- for (i = 0; i < yagl_vector_size(&fragment_shader->state.samplers_ExternalOES); ++i) {
- it = data + i;
- YAGL_LOG_INFO("LKDEBUG externaloes sampler %s location %d value %d", it->name, it->location, it->value);
- }
+ // 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 bound texture2D ID %d", i, samplers[i].value, samplers[i].replaced_tex2d);
- data = yagl_vector_data(&fragment_shader->state.samplers_2D);
- for (i = 0; i < yagl_vector_size(&fragment_shader->state.samplers_2D); ++i) {
- it = data + i;
- YAGL_LOG_INFO("LKDEBUG 2d sampler %s location %d value %d", it->name, it->location, it->value);
+ // 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);
}
}
}
*/
yagl_host_glDisableVertexAttribArray(0);
}
+
+ /*
+ * 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;
+
+ 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;
+ }
+
+ 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;
+ }
+
+ yagl_host_glActiveTexture(ctx->base.active_texture_unit);
+ ctx->base.have_externaloes_rebinds = 0;
+ }
}
void yagl_gles2_context_compressed_tex_image_2d(struct yagl_gles_context *gles_ctx,
yagl_list_add_tail(&program->uniform_locations_l, &location->list);
}
+
+ /*
+ * We need to perform an extra search and go through our samplers.
+ * This will come in handy on pre_draw/post_draw logic later on.
+ * 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;
+ 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;
+ break;
+ }
+ }
+ }
+
return ret;
}
yagl_host_glUniform1i(program->gen_locations, global_location, x);
+ /*
+ * Update fragment shader state for pre_draw/post_draw analysis
+ */
+ if (program->fragment_shader->state.have_samplerexternaloes) {
+ struct yagl_glsl_sampler *data = NULL, *it = 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;
+ break;
+ }
+ }
+ }
+
return 1;
}
sampler.name = strdup(str);
sampler.location = YAGL_GLSL_SAMPLER_LOCATION_UNKNOWN;
sampler.value = YAGL_GLSL_SAMPLER_VALUE_UNKNOWN;
+ sampler.replaced_tex2d = YAGL_GLSL_SAMPLER_VALUE_UNKNOWN;
yagl_vector_push_back(&state->samplers_ExternalOES, &sampler);
}
sampler.name = strdup(str);
sampler.location = YAGL_GLSL_SAMPLER_LOCATION_UNKNOWN;
sampler.value = YAGL_GLSL_SAMPLER_VALUE_UNKNOWN;
+ sampler.replaced_tex2d = YAGL_GLSL_SAMPLER_VALUE_UNKNOWN;
yagl_vector_push_back(&state->samplers_2D, &sampler);
}
char* name;
int location;
int value;
+ int replaced_tex2d; // only used in samplerExternalOES handling
};
typedef enum