+ set_frame_specific_data( service, frame, "_movit effect input", input_service, 0, NULL, NULL );
+}
+
+void GlslManager::get_effect_secondary_input( mlt_service service, mlt_frame frame, mlt_service *input_service, mlt_frame *input_frame)
+{
+ *input_service = (mlt_service) get_frame_specific_data( service, frame, "_movit effect secondary input", NULL );
+ *input_frame = (mlt_frame) get_frame_specific_data( service, frame, "_movit effect secondary input frame", NULL );
+}
+
+void GlslManager::set_effect_secondary_input( mlt_service service, mlt_frame frame, mlt_service input_service, mlt_frame input_frame )
+{
+ set_frame_specific_data( service, frame, "_movit effect secondary input", input_service, 0, NULL, NULL );
+ set_frame_specific_data( service, frame, "_movit effect secondary input frame", input_frame, 0, NULL, NULL );
+}
+
+int GlslManager::render_frame_texture(EffectChain *chain, mlt_frame frame, int width, int height, uint8_t **image)
+{
+ glsl_texture texture = get_texture( width, height, GL_RGBA8 );
+ if (!texture) {
+ return 1;
+ }
+
+ GLuint fbo;
+ glGenFramebuffers( 1, &fbo );
+ check_error();
+ glBindFramebuffer( GL_FRAMEBUFFER, fbo );
+ check_error();
+ glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0 );
+ check_error();
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+ check_error();
+
+ lock();
+ while (syncs_to_delete.count() > 0) {
+ GLsync sync = (GLsync) syncs_to_delete.pop_front();
+ glDeleteSync( sync );
+ }
+ unlock();
+
+ // Make sure we never have more than one frame pending at any time.
+ // This ensures we do not swamp the GPU with so much work
+ // that we cannot actually display the frames we generate.
+ if (prev_sync != NULL) {
+ glFlush();
+ glClientWaitSync( prev_sync, 0, GL_TIMEOUT_IGNORED );
+ glDeleteSync( prev_sync );
+ }
+ chain->render_to_fbo( fbo, width, height );
+ prev_sync = glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 );
+ GLsync sync = glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 );
+
+ check_error();
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+ check_error();
+ glDeleteFramebuffers( 1, &fbo );
+ check_error();
+
+ *image = (uint8_t*) &texture->texture;
+ mlt_frame_set_image( frame, *image, 0, NULL );
+ mlt_properties_set_data( MLT_FRAME_PROPERTIES(frame), "movit.convert.texture", texture, 0,
+ (mlt_destructor) GlslManager::release_texture, NULL );
+ mlt_properties_set_data( MLT_FRAME_PROPERTIES(frame), "movit.convert.fence", sync, 0,
+ (mlt_destructor) GlslManager::delete_sync, NULL );
+
+ return 0;
+}
+
+int GlslManager::render_frame_rgba(EffectChain *chain, mlt_frame frame, int width, int height, uint8_t **image)
+{
+ glsl_texture texture = get_texture( width, height, GL_RGBA8 );
+ if (!texture) {
+ return 1;