Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions include/rive/lua/rive_lua_libs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,8 @@ class ScriptedRenderer
class ScriptReffedArtboard : public RefCnt<ScriptReffedArtboard>
{
public:
ScriptReffedArtboard(rcp<File> file,
ScriptReffedArtboard(lua_State* L,
rcp<File> file,
std::unique_ptr<ArtboardInstance>&& artboardInstance,
rcp<ViewModelInstance> viewModelInstance,
rcp<DataContext> parentDataContext);
Expand All @@ -582,12 +583,18 @@ class ScriptReffedArtboard : public RefCnt<ScriptReffedArtboard>
Artboard* artboard();
StateMachineInstance* stateMachine();
rcp<ViewModelInstance> viewModelInstance() { return m_viewModelInstance; }
void releaseReferences();
static void releaseAll(lua_State* state);

private:
rcp<File> m_file;
std::unique_ptr<ArtboardInstance> m_artboard;
std::unique_ptr<StateMachineInstance> m_stateMachine;
rcp<ViewModelInstance> m_viewModelInstance;
lua_State* m_luaState = nullptr;
ScriptReffedArtboard* m_trackNext = nullptr;
ScriptReffedArtboard* m_trackPrev = nullptr;
static ScriptReffedArtboard* s_head;
};

class ScriptedArtboard
Expand Down Expand Up @@ -630,7 +637,6 @@ class ScriptedArtboard
private:
lua_State* m_state = nullptr;
rcp<ScriptReffedArtboard> m_scriptReffedArtboard = nullptr;
rcp<DataContext> m_dataContext = nullptr;
int m_dataRef = 0;
};

Expand Down Expand Up @@ -704,11 +710,17 @@ class ScriptedViewModel
return m_viewModelInstance;
}

void releaseReferences();
static void releaseAll(lua_State* state);

private:
lua_State* m_state;
rcp<ViewModel> m_viewModel;
rcp<ViewModelInstance> m_viewModelInstance;
std::unordered_map<std::string, int> m_propertyRefs;
ScriptedViewModel* m_trackNext = nullptr;
ScriptedViewModel* m_trackPrev = nullptr;
static ScriptedViewModel* s_head;
};

class ScriptedPropertyViewModel : public ScriptedProperty
Expand Down
3 changes: 3 additions & 0 deletions include/rive/scripted/scripted_object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ class ScriptedObject : public FileAssetReferencer,
lua_State* state() const { return m_vm ? m_vm->state() : nullptr; }
#endif
void scriptDispose();
#ifdef WITH_RIVE_SCRIPTING
static void collectLuaGarbage(lua_State* state);
#endif
virtual bool addScriptedDirt(ComponentDirt value, bool recurse = false) = 0;
void setAsset(rcp<FileAsset> asset) override;
static ScriptedObject* from(Core* object);
Expand Down
10 changes: 10 additions & 0 deletions src/artboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ Artboard::~Artboard()
return vmObjects.count(object) != 0;
};

#ifdef WITH_RIVE_SCRIPTING
lua_State* luaState = nullptr;
if (!m_ScriptedObjects.empty())
{
luaState = m_ScriptedObjects[0]->state();
}
#endif
// Second pass: delete non-VM objects.
for (auto object : m_Objects)
{
Expand All @@ -154,6 +161,9 @@ Artboard::~Artboard()
}
delete object;
}
#ifdef WITH_RIVE_SCRIPTING
ScriptedObject::collectLuaGarbage(luaState);
#endif
for (auto object : m_invalidObjects)
{
if (object == nullptr)
Expand Down
60 changes: 52 additions & 8 deletions src/lua/lua_artboards.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@

using namespace rive;

ScriptReffedArtboard* ScriptReffedArtboard::s_head = nullptr;

ScriptReffedArtboard::ScriptReffedArtboard(
lua_State* L,
rcp<File> file,
std::unique_ptr<ArtboardInstance>&& artboardInstance,
rcp<ViewModelInstance> viewModelInstance,
rcp<DataContext> parentDataContext) :
m_file(file),
m_artboard(std::move(artboardInstance)),
m_stateMachine(m_artboard->defaultStateMachine())
m_stateMachine(m_artboard->defaultStateMachine()),
m_luaState(L)
{
if (viewModelInstance)
{
Expand All @@ -45,18 +49,58 @@ ScriptReffedArtboard::ScriptReffedArtboard(
m_stateMachine->bindViewModelInstance(m_viewModelInstance);
}
}
// Track this instance for cleanup during artboard destruction
m_trackNext = s_head;
m_trackPrev = nullptr;
if (s_head)
{
s_head->m_trackPrev = this;
}
s_head = this;
}

ScriptReffedArtboard::~ScriptReffedArtboard()
{
// Make sure state machine is deleted before artboard since
// StateMachineInstance destructor accesses the artboard.
// Remove from tracking list
if (m_trackPrev)
{
m_trackPrev->m_trackNext = m_trackNext;
}
else if (s_head == this)
{
s_head = m_trackNext;
}
if (m_trackNext)
{
m_trackNext->m_trackPrev = m_trackPrev;
}
releaseReferences();
}

void ScriptReffedArtboard::releaseReferences()
{
// StateMachine must be deleted before artboard since its destructor
// accesses the artboard.
m_stateMachine = nullptr;
// Make sure artboard is deleted before file.
m_artboard = nullptr;
m_viewModelInstance = nullptr;
m_file = nullptr;
}

void ScriptReffedArtboard::releaseAll(lua_State* state)
{
ScriptReffedArtboard* current = s_head;
while (current)
{
ScriptReffedArtboard* next = current->m_trackNext;
if (current->m_luaState == state)
{
current->releaseReferences();
}
current = next;
}
}

rive::rcp<rive::File> ScriptReffedArtboard::file() { return m_file; }

Artboard* ScriptReffedArtboard::artboard() { return m_artboard.get(); }
Expand Down Expand Up @@ -264,7 +308,7 @@ int ScriptedArtboard::instance(lua_State* L,
m_scriptReffedArtboard->file(),
std::move(artboardInstance),
viewModelInstance,
m_dataContext);
artboard()->dataContext());
return 1;
}

Expand Down Expand Up @@ -384,11 +428,11 @@ ScriptedArtboard::ScriptedArtboard(
rcp<DataContext> dataContext) :
m_state(L),
m_scriptReffedArtboard(
make_rcp<ScriptReffedArtboard>(file,
make_rcp<ScriptReffedArtboard>(L,
file,
std::move(artboardInstance),
viewModelInstance,
dataContext)),
m_dataContext(dataContext)
dataContext))
{}

ScriptedArtboard::~ScriptedArtboard()
Expand Down
45 changes: 44 additions & 1 deletion src/lua/lua_properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,18 +245,61 @@ void ScriptedPropertyViewModel::setValue(ScriptedViewModel* scriptedViewModel)
}
}

ScriptedViewModel* ScriptedViewModel::s_head = nullptr;

ScriptedViewModel::ScriptedViewModel(lua_State* L,
rcp<ViewModel> viewModel,
rcp<ViewModelInstance> viewModelInstance) :
m_state(L), m_viewModel(viewModel), m_viewModelInstance(viewModelInstance)
{}
{
m_trackNext = s_head;
m_trackPrev = nullptr;
if (s_head)
{
s_head->m_trackPrev = this;
}
s_head = this;
}

ScriptedViewModel::~ScriptedViewModel()
{
if (m_trackPrev)
{
m_trackPrev->m_trackNext = m_trackNext;
}
else if (s_head == this)
{
s_head = m_trackNext;
}
if (m_trackNext)
{
m_trackNext->m_trackPrev = m_trackPrev;
}
for (auto itr : m_propertyRefs)
{
lua_unref(m_state, itr.second);
}
releaseReferences();
}

void ScriptedViewModel::releaseReferences()
{
m_viewModel = nullptr;
m_viewModelInstance = nullptr;
}

void ScriptedViewModel::releaseAll(lua_State* state)
{
ScriptedViewModel* current = s_head;
while (current)
{
ScriptedViewModel* next = current->m_trackNext;
if (current->m_state == state)
{
current->releaseReferences();
}
current = next;
}
}

int ScriptedViewModel::instance(lua_State* L)
Expand Down
17 changes: 15 additions & 2 deletions src/scripted/scripted_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,14 +355,27 @@ void ScriptedObject::scriptDispose()
lua_unref(L, m_self);
disposeScriptedContext();
#ifdef TESTING
// Force GC to collect any ScriptedArtboard instances created via
// instance()
lua_gc(L, LUA_GCCOLLECT, 0);
#endif
}
m_vm = nullptr;
m_self = 0;
}

void ScriptedObject::collectLuaGarbage(lua_State* state)
{
if (state != nullptr)
{
// Null C++ pointers on all ScriptReffedArtboard and ScriptedViewModel
// instances for this lua_State. Sub-artboard scripts store orphaned
// registry refs (m_context, m_dataRef, m_propertyRefs) that keep C++
// objects alive. Rather than walk the registry, we null the C++ side
// directly — the Lua userdata become harmless empty shells.
ScriptReffedArtboard::releaseAll(state);
ScriptedViewModel::releaseAll(state);
lua_gc(state, LUA_GCCOLLECT, 0);
}
}
#else
void ScriptedObject::setArtboardInput(std::string name, Artboard* artboard) {}

Expand Down
Binary file added tests/unit_tests/assets/blinko.riv
Binary file not shown.
Loading