Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deferred Lua Execution #1180

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
4 changes: 0 additions & 4 deletions core/src/MegaMolGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,6 @@ bool megamol::core::MegaMolGraph::SetParameter(std::string const& paramName, std

bool success = param_ptr->ParseValue(value);

// param changes are queued in the graphs parameter changes queue
// and get passed to graph subscribers at beginning of each frame by the Lua Service
// using MegaMolGraph::Broadcast_graph_subscribers_parameter_changes()

if (!success)
return false;

Expand Down
322 changes: 138 additions & 184 deletions frontend/main/src/CLIConfigParsing.cpp

Large diffs are not rendered by default.

65 changes: 43 additions & 22 deletions frontend/main/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "mmcore/MegaMolGraph.h"
#include "mmcore/factories/PluginRegister.h"

#include "FrontendResourcesMap.h"
#include "GlobalValueStore.h"
#include "RuntimeConfig.h"

Expand Down Expand Up @@ -124,10 +125,12 @@ int main(const int argc, const char** argv) {
luaConfig.host_address = config.lua_host_address;
luaConfig.retry_socket_port = config.lua_host_port_retry;
luaConfig.show_version_notification = config.show_version_note;
luaConfig.interactive = config.interactive;
lua_service_wrapper.setPriority(0);

megamol::frontend::ProjectLoader_Service projectloader_service;
megamol::frontend::ProjectLoader_Service::Config projectloaderConfig;
projectloaderConfig.interactive = config.interactive;
projectloader_service.setPriority(1);

megamol::frontend::ImagePresentation_Service imagepresentation_service;
Expand Down Expand Up @@ -261,6 +264,10 @@ int main(const int argc, const char** argv) {
// e.g. graph updates, module and call creation via lua and GUI happen here
services.digestChangedRequestedResources();

// before rendering, flush lua commands coming from services
lua_service_wrapper.run_lua_queue();
graph.Broadcast_graph_subscribers_parameter_changes();

// services tell us whether we should shut down megamol
if (services.shouldShutdown())
return false;
Expand Down Expand Up @@ -316,35 +323,49 @@ int main(const int argc, const char** argv) {
ret += 2;
}

// load project files via lua
if (run_megamol && graph_resources_ok)
for (auto& file : config.project_files) {
if (!projectloader_service.load_file(file)) {
log_error("Project file \"" + file + "\" did not execute correctly");
run_megamol = false;
ret += 4;
// queue CLI project files and raw lua
if (run_megamol && graph_resources_ok) {
const auto& frontend_resources_map = megamol::frontend_resources::FrontendResourcesMap{frontend_resources};
const auto& execute_lua_deferred =
frontend_resources_map.get<megamol::frontend_resources::LuaScriptExecution>().execute_deferred_callback;
auto raw_lua_callback = [&](auto const& result) {
const bool cli_lua_ok = std::get<0>(result);
const std::string lua_result = std::get<1>(result);

// if interactive, continue to run MegaMol
if (config.interactive) {
log_warning("Interactive mode: start MegaMol anyway");
run_megamol = true;
if (!cli_lua_ok)
log_error("Error in CLI Lua command: " + lua_result);
};
for (auto& request : config.cli_execute_lua_commands) {
switch (request.source) {
case RuntimeConfig::CliLuaRequest::Type::File: {
// attention: the project files are only _queued_ for later lua execution here
// if a project file leads to errors on the file-level, we exit here, if not in interactive mode
auto& file = request.contents;
if (!projectloader_service.load_file(file)) {
log_error("Loading project file \"" + file + "\" produced error");
run_megamol = false;
ret += 8;
}
}
}

// execute Lua commands passed via CLI
if (graph_resources_ok)
if (!config.cli_execute_lua_commands.empty()) {
std::string lua_result;
bool cli_lua_ok = lua_api.RunString(config.cli_execute_lua_commands, lua_result);
if (!cli_lua_ok) {
} break;
case RuntimeConfig::CliLuaRequest::Type::Raw:
// queue Lua commands passed via CLI. this also include CLI param changes.
execute_lua_deferred(request.contents, "", raw_lua_callback);
break;
default:
log_warning("CLI Lua Commands: unknown type: " + std::to_string(static_cast<int>(request.source)));
run_megamol = false;
ret += 8;
log_error("Error in CLI Lua command: " + lua_result);
ret += 4;
break;
}
}
// if interactive, continuing to run MegaMol is ensured by the Project or Lua service itself
}

while (run_megamol) {
// we run the lua queue here as a starting point to evaluate CLI-related lua inputs
// during rendering of the frame there is another execution of the lua queue
// but it is meant to flush lua commands issued by services during a frame
lua_service_wrapper.run_lua_queue();
run_megamol = render_next_frame();
}

Expand Down
4 changes: 1 addition & 3 deletions frontend/resources/include/CommonTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

namespace megamol::frontend_resources {

struct common_types {
using lua_func_type = std::function<std::tuple<bool, std::string>(std::string const&)>;
};
struct common_types {};

} // namespace megamol::frontend_resources
79 changes: 79 additions & 0 deletions frontend/resources/include/LuaScriptExecution.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* LuaScriptExecution.h
*
* Copyright (C) 2022 by VISUS (Universitaet Stuttgart).
* Alle Rechte vorbehalten.
*/

#pragma once

#include "LuaScriptExecution.h"

#include <chrono>
#include <functional>
#include <future>
#include <list>
#include <string>

namespace megamol {
namespace frontend_resources {

static std::string LuaScriptExecution_Req_Name = "LuaScriptExecution";

using LuaExecutionResult = std::tuple<bool, std::string>;
using LuaFutureExecutionResult = std::future<LuaExecutionResult>;
using LuaExecutionResultCallback = std::function<void(LuaExecutionResult const&)>;

using lua_execution_func = std::function<LuaExecutionResult(std::string const&)>;
using lua_deferred_execution_func =
std::function<LuaFutureExecutionResult(std::string const& /*script*/, std::string const& /*script path*/)>;
using lua_deferred_execution_callback_func = std::function<void(
std::string const& /*script*/, std::string const& /*script path*/, LuaExecutionResultCallback const&)>;

// one may execute lua script immediately or at the start of the next frame (deferred)
struct LuaScriptExecution {
// calls the lua interpreter immediately. this is only safe when not inside the rendering of a frame, i.e. inside megamol graph execution.
lua_execution_func execute_immediate;

// queues lua script execution for beginning of next frame, executed by lua service at beginning of next frame cycle (but after network lua requests)
// this is safe to execute from inside megamol graph execution as it will not immediately alter graph state from lua.
lua_deferred_execution_func execute_deferred;

// queues lua script for execution, along with a callback function which gets called after execution of the lua script
lua_deferred_execution_callback_func execute_deferred_callback;
};

// holds a set of futures of LuaFutureExecutionResult, helping you to check the futures for newly available results
struct LuaFutureExecutionResult_Helper {
std::list<LuaFutureExecutionResult> futures;

// adds a future to list of pending future results
void add(LuaFutureExecutionResult& future) {
futures.push_back(std::move(future));
}

// calls 'callback' function providing the LuaExecutionResult of futures containing a result
// futures which provided a result will be removed from the list of pending future results
void check_all(LuaExecutionResultCallback const& callback) {
using namespace std::chrono_literals;

auto first = futures.begin();
while (first != futures.end()) {
auto& future = *first;
if (future.wait_for(0ms) == std::future_status::ready) {
callback(future.get());
auto old = first++;
futures.erase(old);
} else {
first++;
}
}
}

void clear() {
futures.clear();
}
};

} /* end namespace frontend_resources */
} /* end namespace megamol */
27 changes: 27 additions & 0 deletions frontend/resources/include/LuaScriptPaths.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* LuaScriptPaths.h
*
* Copyright (C) 2020 by VISUS (Universitaet Stuttgart).
* Alle Rechte vorbehalten.
*/

#pragma once

#include <functional>
#include <string>
#include <vector>

namespace megamol {
namespace frontend_resources {

static std::string LuaScriptPaths_Req_Name = "LuaScriptPaths";
static std::string SetLuaScriptPath_Req_Name = "SetLuaScriptPath";

using set_lua_script_path_func = std::function<void(std::string const&)>;

struct LuaScriptPaths {
std::vector<std::string> lua_script_paths;
};

} /* end namespace frontend_resources */
} /* end namespace megamol */
16 changes: 13 additions & 3 deletions frontend/resources/include/RuntimeConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,19 @@ struct RuntimeConfig {
megamol::core::utility::log::Log::log_level::info; // mmSetLogLevel
megamol::core::utility::log::Log::log_level echo_level =
megamol::core::utility::log::Log::log_level::info; // mmSetEchoLevel
std::vector<Path> project_files = {}; // NEW: mmLoadProject - project files are loaded after services are up
std::vector<StringPair> global_values = {}; // use GlobalValueStore resource for access to global values!
std::string cli_execute_lua_commands;
std::vector<StringPair> global_values = {}; // use GlobalValueStore resource for access to global values!
std::vector<Path> project_files = {}; // mmLoadProject

struct CliLuaRequest {
enum class Type {
File,
Raw,
};
Type source;
std::string contents;
};
// CLI project files and raw lua scripts, in the order as provided via CLI
std::vector<CliLuaRequest> cli_execute_lua_commands;

// detailed and service-specific configurations
// every CLI option can be set via the config file using mmSetConfigValue
Expand Down
20 changes: 0 additions & 20 deletions frontend/resources/include/ScriptPaths.h

This file was deleted.

7 changes: 4 additions & 3 deletions frontend/services/gui/src/GUIManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,12 +248,13 @@ class GUIManager {
*/
void RegisterHotkeys(megamol::core::view::CommandRegistry& cmdregistry, megamol::core::MegaMolGraph& megamol_graph);

void SetLuaFunc(megamol::frontend_resources::common_types::lua_func_type* lua_func) {
void SetLuaFunc(megamol::frontend_resources::LuaScriptExecution const& lua_func) {
auto cons = win_collection.GetWindow<LogConsole>();
auto& func = const_cast<megamol::frontend_resources::LuaScriptExecution&>(lua_func);
if (cons) {
cons->SetLuaFunc(lua_func);
cons->SetLuaFunc(&func);
}
this->win_configurator_ptr->GetGraphCollection().SetLuaFunc(lua_func);
this->win_configurator_ptr->GetGraphCollection().SetLuaFunc(&func);
}

#ifdef MEGAMOL_USE_PROFILING
Expand Down
14 changes: 7 additions & 7 deletions frontend/services/gui/src/GUI_Service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@
#include "GUIManager.h"
#include "ImagePresentationEntryPoints.h"
#include "KeyboardMouse_Events.h"
#include "LuaScriptExecution.h"
#include "LuaScriptPaths.h"
#include "ModuleGraphSubscription.h"
#include "OpenGL_Context.h"
#include "PluginsResource.h"
#include "ProjectLoader.h"
#include "RuntimeConfig.h"
#include "ScriptPaths.h"
#include "WindowManipulation.h"
#include "Window_Events.h"

Expand Down Expand Up @@ -55,14 +56,14 @@ bool GUI_Service::init(const Config& config) {
"optional<OpenGL_Context>", // 4 - graphics api for imgui context
"FramebufferEvents", // 5 - viewport size
"GLFrontbufferToPNG_ScreenshotTrigger", // 6 - trigger screenshot
"LuaScriptPaths", // 7 - current project path
frontend_resources::LuaScriptPaths_Req_Name, // 7 - current project path
"ProjectLoader", // 8 - trigger loading of new running project
"FrameStatistics", // 9 - current fps and ms value
"RuntimeConfig", // 10 - resource paths
"optional<WindowManipulation>", // 11 - GLFW window pointer
frontend_resources::CommandRegistry_Req_Name, // 12 - Command registry
"ImagePresentationEntryPoints", // 13 - Entry point
"ExecuteLuaScript", // 14 - Execute Lua Scripts (from Console)
frontend_resources::LuaScriptExecution_Req_Name, // 14 - Execute Lua Scripts (from Console)
frontend_resources::MegaMolGraph_SubscriptionRegistry_Req_Name, // 15 MegaMol Graph subscription
"PluginsResource", // 16 - Plugins
#ifdef MEGAMOL_USE_PROFILING
Expand Down Expand Up @@ -240,7 +241,7 @@ void GUI_Service::digestChangedRequestedResources() {
}

/// Pipe lua script paths to gui = resource index 7
auto& script_paths = frontend_resources->get<megamol::frontend_resources::ScriptPaths>();
auto& script_paths = frontend_resources->get<megamol::frontend_resources::LuaScriptPaths>();
this->m_gui->SetProjectScriptPaths(script_paths.lua_script_paths);

/// Pipe project loading request from GUI to project loader = resource index 8
Expand Down Expand Up @@ -366,9 +367,8 @@ void GUI_Service::setRequestedResources(std::vector<FrontendResource> resources)
"GUI_Service: error adding graph entry point ... image presentation service rejected GUI Service.");
}

m_exec_lua = const_cast<megamol::frontend_resources::common_types::lua_func_type*>(
&frontend_resources->get<frontend_resources::common_types::lua_func_type>());
m_gui->SetLuaFunc(m_exec_lua);
auto& execute_lua = frontend_resources->get<frontend_resources::LuaScriptExecution>();
m_gui->SetLuaFunc(execute_lua);

// MegaMol Graph Subscription
auto& megamolgraph_subscription = const_cast<frontend_resources::MegaMolGraph_SubscriptionRegistry&>(
Expand Down
2 changes: 0 additions & 2 deletions frontend/services/gui/src/GUI_Service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@


#include "AbstractFrontendService.hpp"
#include "CommonTypes.h"
#include "GUIRegisterWindow.h"
#include "GUIState.h"
#include "PerformanceManager.h"
Expand Down Expand Up @@ -87,7 +86,6 @@ class GUI_Service final : public AbstractFrontendService {

megamol::frontend_resources::GUIState m_providedStateResource;
megamol::frontend_resources::GUIRegisterWindow m_providedRegisterWindowResource;
megamol::frontend_resources::common_types::lua_func_type* m_exec_lua;

std::string resource_request_gui_state(bool as_lua);
bool resource_request_gui_visibility();
Expand Down
Loading