-
-
Notifications
You must be signed in to change notification settings - Fork 691
Description
Background Info:
Working on adding GDExtension support for Video playback.
One part of the VideoStream is Ref<VideoStreamPlayback> VideoStream::instance_playback()
For the VideoStreamExtension class this is implemented as
Ref<VideoStreamPlayback> VideoStreamExtension::instance_playback() {
Ref<VideoStreamPlaybackExtension> ref;
if (GDVIRTUAL_CALL(_instance_playback, ref)) {
ERR_FAIL_COND_V_MSG(ref.is_null(), nullptr, "Plugin returned null playback");
// open_file() is an unregistered private method in VideoStreamPlaybackExtension
ref->open_file(file);
// set_audio_track() is a virtual method implemented with GDVIRTUAL_CALL
ref->set_audio_track(audio_track);
return ref;
}
return nullptr;
}On the GDExtension plugin side:
godot::Ref<godot::VideoStreamPlaybackExtension> godot::VideoStreamReference::_instance_playback() {
Ref<VideoStreamPlaybackReference> ref;
ref.instantiate();
// will add the temp fix here.
return ref;
}The Issue:
The above implementation crashes with:
Exception thrown: read access violation.
**VideoStreamPlayback::set_audio_track[virtual]** was 0xFFFFFFFFFFFFFFFF.
Stepping through in the debugger shows the VideoStreamPlaybackReference::_cleanup (Destructor) is called on return from
// binder_common.hpp
void call_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const GDNativeTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}As the Ref counts to 0.
If one stores the Ref in the plugin: Godot and the Plugin both has separate 'ownership' of the object. As such after cleanup on one end - the other Ref dangles.
Temporary Solution:
RefCounted* r = static_cast<RefCounted*>(ref.ptr());
r->reference();Adding this increments the refcount and prevents the deletion after encode.
The Ref quietly deletes and reduces refcount to 1 which is copied and owned by Godot
Works for this particular case since it's an ownership transfer. But it will not work in Shared ownership case as RefCounted object seems to not be shared across the boundary.
Related: #417