From d62349fd118e89b16adfc5478c73cd8e10136364 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Wed, 6 Jan 2016 00:26:52 +0100 Subject: [PATCH] Clean up resources in the global ResourcePool on exit, in order to avoid some assert failures. --- glwidget.cpp | 13 +++++++++++- glwidget.h | 10 +++++++++- main.cpp | 1 + mainwindow.cpp | 9 +++++++++ mainwindow.h | 4 ++++ theme.cpp | 54 +++++++++++++++++++++++++++++++++++++++++--------- theme.h | 1 + 7 files changed, 81 insertions(+), 11 deletions(-) diff --git a/glwidget.cpp b/glwidget.cpp index 06675f3..01d372f 100644 --- a/glwidget.cpp +++ b/glwidget.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "glwidget.h" @@ -36,8 +37,12 @@ GLWidget::GLWidget(QWidget *parent) { } -GLWidget::~GLWidget() +void GLWidget::clean_context() { + if (resource_pool != nullptr) { + makeCurrent(); + resource_pool->clean_context(); + } } void GLWidget::initializeGL() @@ -82,6 +87,12 @@ void GLWidget::paintGL() check_error(); frame.chain->render_to_screen(); check_error(); + + if (resource_pool == nullptr) { + resource_pool = frame.chain->get_resource_pool(); + } else { + assert(resource_pool == frame.chain->get_resource_pool()); + } } void GLWidget::mousePressEvent(QMouseEvent *event) diff --git a/glwidget.h b/glwidget.h index ae4902c..857d733 100644 --- a/glwidget.h +++ b/glwidget.h @@ -13,6 +13,12 @@ class QMouseEvent; class QWidget; +namespace movit { + +class ResourcePool; + +} // namespace movit + // Note: We use the older QGLWidget instead of QOpenGLWidget as it is // much faster (does not go through a separate offscreen rendering step). // @@ -23,13 +29,14 @@ class GLWidget : public QGLWidget public: GLWidget(QWidget *parent = 0); - ~GLWidget(); void set_output(Mixer::Output output) { this->output = output; } + void clean_context(); + protected: void initializeGL() override; void resizeGL(int width, int height) override; @@ -45,6 +52,7 @@ private: Mixer::Output output; GLuint vao, program_num; GLuint position_vbo, texcoord_vbo; + movit::ResourcePool *resource_pool = nullptr; }; #endif diff --git a/main.cpp b/main.cpp index b7679f9..f28b859 100644 --- a/main.cpp +++ b/main.cpp @@ -47,6 +47,7 @@ int main(int argc, char *argv[]) int rc = app.exec(); global_mixer->quit(); + mainWindow.mixer_shutting_down(); delete global_mixer; return rc; } diff --git a/mainwindow.cpp b/mainwindow.cpp index 9f29334..ede1fb6 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -117,6 +117,15 @@ void MainWindow::mixer_created(Mixer *mixer) mixer->set_audio_level_callback(bind(&MainWindow::audio_level_callback, this, _1, _2, _3, _4, _5, _6)); } +void MainWindow::mixer_shutting_down() +{ + ui->me_live->clean_context(); + ui->me_preview->clean_context(); + for (Ui::Display *display : previews) { + display->display->clean_context(); + } +} + void MainWindow::cutoff_knob_changed(int value) { float octaves = value * 0.1f; diff --git a/mainwindow.h b/mainwindow.h index 8faa812..f768aaa 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -27,6 +27,10 @@ public: void resizeEvent(QResizeEvent *event) override; void mixer_created(Mixer *mixer); + // Used to release FBOs on the global ResourcePool. Call after the + // mixer has been shut down but not destroyed yet. + void mixer_shutting_down(); + public slots: void transition_clicked(int transition_number); void channel_clicked(int channel_number); diff --git a/theme.cpp b/theme.cpp index 7bfe6cf..0019300 100644 --- a/theme.cpp +++ b/theme.cpp @@ -98,6 +98,28 @@ int wrap_lua_object(lua_State* L, const char *class_name, Args&&... args) return 1; } +// Like wrap_lua_object, but the object is not owned by Lua; ie. it's not freed +// by Lua GC. This is typically the case for Effects, which are owned by EffectChain +// and expected to be destructed by it. The object will be of type T** instead of T* +// when exposed to Lua. +// +// Note that we currently leak if you allocate an Effect in this way and never call +// add_effect. We should see if there's a way to e.g. set __gc on it at construction time +// and then release that once add_effect() takes ownership. +template +int wrap_lua_object_nonowned(lua_State* L, const char *class_name, Args&&... args) +{ + // Construct the pointer ot the C++ object and put it on the stack. + T **obj = (T **)lua_newuserdata(L, sizeof(T *)); + *obj = new T(std::forward(args)...); + + // Look up the metatable named , and set it on the new object. + luaL_getmetatable(L, class_name); + lua_setmetatable(L, -2); + + return 1; +} + Theme *get_theme_updata(lua_State* L) { luaL_checktype(L, lua_upvalueindex(1), LUA_TLIGHTUSERDATA); @@ -114,7 +136,7 @@ Effect *get_effect(lua_State *L, int idx) luaL_testudata(L, idx, "ResizeEffect") || luaL_testudata(L, idx, "MixEffect") || luaL_testudata(L, idx, "ImageInput")) { - return (Effect *)lua_touserdata(L, idx); + return *(Effect **)lua_touserdata(L, idx); } luaL_error(L, "Error: Index #%d was not an Effect type\n", idx); return nullptr; @@ -152,6 +174,14 @@ int EffectChain_new(lua_State* L) return wrap_lua_object(L, "EffectChain", aspect_w, aspect_h, theme->get_resource_pool()); } +int EffectChain_gc(lua_State* L) +{ + assert(lua_gettop(L) == 1); + EffectChain *chain = (EffectChain *)luaL_checkudata(L, 1, "EffectChain"); + chain->~EffectChain(); + return 0; +} + int EffectChain_add_live_input(lua_State* L) { assert(lua_gettop(L) == 3); @@ -255,49 +285,49 @@ int ImageInput_new(lua_State* L) { assert(lua_gettop(L) == 1); std::string filename = checkstdstring(L, 1); - return wrap_lua_object(L, "ImageInput", filename); + return wrap_lua_object_nonowned(L, "ImageInput", filename); } int WhiteBalanceEffect_new(lua_State* L) { assert(lua_gettop(L) == 0); - return wrap_lua_object(L, "WhiteBalanceEffect"); + return wrap_lua_object_nonowned(L, "WhiteBalanceEffect"); } int ResampleEffect_new(lua_State* L) { assert(lua_gettop(L) == 0); - return wrap_lua_object(L, "ResampleEffect"); + return wrap_lua_object_nonowned(L, "ResampleEffect"); } int PaddingEffect_new(lua_State* L) { assert(lua_gettop(L) == 0); - return wrap_lua_object(L, "PaddingEffect"); + return wrap_lua_object_nonowned(L, "PaddingEffect"); } int IntegralPaddingEffect_new(lua_State* L) { assert(lua_gettop(L) == 0); - return wrap_lua_object(L, "IntegralPaddingEffect"); + return wrap_lua_object_nonowned(L, "IntegralPaddingEffect"); } int OverlayEffect_new(lua_State* L) { assert(lua_gettop(L) == 0); - return wrap_lua_object(L, "OverlayEffect"); + return wrap_lua_object_nonowned(L, "OverlayEffect"); } int ResizeEffect_new(lua_State* L) { assert(lua_gettop(L) == 0); - return wrap_lua_object(L, "ResizeEffect"); + return wrap_lua_object_nonowned(L, "ResizeEffect"); } int MixEffect_new(lua_State* L) { assert(lua_gettop(L) == 0); - return wrap_lua_object(L, "MixEffect"); + return wrap_lua_object_nonowned(L, "MixEffect"); } int InputStateInfo_get_width(lua_State* L) @@ -409,6 +439,7 @@ int Effect_set_vec4(lua_State *L) const luaL_Reg EffectChain_funcs[] = { { "new", EffectChain_new }, + { "__gc", EffectChain_gc }, { "add_live_input", EffectChain_add_live_input }, { "add_effect", EffectChain_add_effect }, { "finalize", EffectChain_finalize }, @@ -655,6 +686,11 @@ Theme::Theme(const char *filename, ResourcePool *resource_pool, unsigned num_car assert(lua_gettop(L) == 0); } +Theme::~Theme() +{ + lua_close(L); +} + void Theme::register_class(const char *class_name, const luaL_Reg *funcs) { assert(lua_gettop(L) == 0); diff --git a/theme.h b/theme.h index 1f4f429..4803973 100644 --- a/theme.h +++ b/theme.h @@ -40,6 +40,7 @@ public: class Theme { public: Theme(const char *filename, movit::ResourcePool *resource_pool, unsigned num_cards); + ~Theme(); struct Chain { movit::EffectChain *chain; -- 2.39.2