Use GDExtensionInstanceBindingCallbacks properly #1
Labels
No labels
blocked
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Depends on
#3 Implement gdxx::GodotExternClass
queertherians.org/gdxx
Reference
queertherians.org/gdxx#1
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A
GDExtensionInstanceBindingCallbacksstruct is handed as an argument to the API callgdxx::API::object_set_instance_binding(...), and its meaning is very unclear based on the documentation I have been able to review so far.Starting at line 65 in
include/GodotClass.hpp:These callback pointers are left blank in the example documentation. Do we know if these callbacks need to be assigned to anything, and what might need to happen when these functions are called?
Open to comments/suggestions/assistance, either on the BarkVR matrix or in this thread.
Did some quick web searching. It seems to be a mechanism that actually helps define how the lifetime of objects is managed across the Godot/Native memory boundary. According to some Google AI slop summaries (urgh) that I've tried to verify with external sources (take it with a grain of salt; I've got no other accessible documentation to work off of, so sadly this is my only route currently), rewritten in my own words:
API::object_get_instance_binding(...)specifically calls.create_callbackfor an existing copy of an object (for class types that we haven't registered ourselves) IF we do not have a native version of the object already. This allows us to quickly create or fetch a wrapper instance for Godot-initialized objects (gdxx:GodotExternClass? #3). It avoids calling.create_callbackand returns a cached reference to a native wrapper if one was already set. Probably does nothing forobject_set_instance_binding, since there we're already assigning an instance binding..free_callbackis called by the engine when.queue_free()on a wrapped object was called. We destruct/free the wrapper, but keep the internal Godot object pointer alive for Godot to free on its own. (We should probably keep this asnullptrfor when we're setting the instance binding withinClassCreationInfo.create_instance_func, since we're presumably already deleting the native object in ClassCreationInfo.free_instance_func).reference_callbackis used for RefCounted (Resource) objects (custom or not), as opposed to objects in the Scene Tree whose lifetime is determined by the Tree. If the provided boolean argument istrue, the ref-count is non-zero on the Godot side, so the object shall not be freed (we probably returntrue). If the provided boolean isfalse, the Godot-side ref-count (probably?) reached zero, which should exclude Godot from the Native-side ref-count1. If, at that point, the ref-count hits zero on our end too, we returntrue. Otherwise, we returnfalse, as we still have alive references on our end. We do not do any freeing here, as that is subsequently done in.free_callback(wrapped after make) orClassCreationInfo.free_instance_func(Native representation only) appropriately if it's called for.I'm writing all this out here mainly for my own reference, so I can attempt the implementation of this. Despite being figured from AI slop, it seems reasonable based on what I can tell, but I'll still maintain some healthy skepticism. Hopefully upon its successful implementation, this issue should close. This should also solve some of the confusion and future speculation in other issues currently open.
NOT
shared_ptrper-se, but a native ref-countedlongwith a Godot flag. If native ref-count later hits zero with Godot flag false (i.e. outside of.reference_callback), we should probably call for deletion of the object. If Godot flag is true, however, we never free it ourselves, since Godot maintains ownership. ↩︎Godot Class constructors/destructors cannot be public, because Godot native objects/wrappers need to always initialize/destroy through the proper utility (
ClassCreationInfo.create_instance_funcorAPI::object_get_instance_binding(...)->.create_callback) (always heap allocated; lifetime cannot be restrained to stack-scope).Static methods for creation and queue_free will be defined for convenience, utilizing the StringNames for the class name (all to be shared within
gdxx::GodotClass).We now depend on ClassDB (to be wrapped in
gdxx::GodotExternClass) for detecting whether we are refcounted or not.