1
0
mirror of synced 2025-02-16 10:32:35 +01:00

impr: Run data processor in a worker task

This commit is contained in:
WerWolv 2024-07-11 23:30:54 +02:00
parent 7975edade4
commit 8422965d0b
6 changed files with 136 additions and 75 deletions

View File

@ -12,6 +12,7 @@
#include <nlohmann/json_fwd.hpp>
#include <imgui.h>
#include <hex/providers/provider_data.hpp>
namespace hex::prv {
class Provider;
@ -42,8 +43,9 @@ namespace hex::dp {
m_overlay = overlay;
}
virtual void drawNode() { }
void draw();
virtual void process() = 0;
virtual void reset() { }
virtual void store(nlohmann::json &j) const { hex::unused(j); }
virtual void load(const nlohmann::json &j) { hex::unused(j); }
@ -80,6 +82,11 @@ namespace hex::dp {
void setIntegerOnOutput(u32 index, i128 integer);
void setFloatOnOutput(u32 index, double floatingPoint);
static void interrupt();
protected:
virtual void drawNode() { }
private:
int m_id;
UnlocalizedString m_unlocalizedTitle, m_unlocalizedName;
@ -90,45 +97,16 @@ namespace hex::dp {
static int s_idCounter;
Attribute& getAttribute(u32 index) {
if (index >= this->getAttributes().size())
throw std::runtime_error("Attribute index out of bounds!");
return this->getAttributes()[index];
}
Attribute *getConnectedInputAttribute(u32 index) {
const auto &connectedAttribute = this->getAttribute(index).getConnectedAttributes();
if (connectedAttribute.empty())
return nullptr;
return connectedAttribute.begin()->second;
}
void markInputProcessed(u32 index) {
const auto &[iter, inserted] = m_processedInputs.insert(index);
if (!inserted)
throwNodeError("Recursion detected!");
}
void unmarkInputProcessed(u32 index) {
m_processedInputs.erase(index);
}
Attribute& getAttribute(u32 index);
Attribute *getConnectedInputAttribute(u32 index);
void markInputProcessed(u32 index);
void unmarkInputProcessed(u32 index);
protected:
[[noreturn]] void throwNodeError(const std::string &message) {
throw NodeError { this, message };
}
[[noreturn]] void throwNodeError(const std::string &message);
void setOverlayData(u64 address, const std::vector<u8> &data);
void setAttributes(std::vector<Attribute> attributes) {
m_attributes = std::move(attributes);
for (auto &attr : m_attributes)
attr.setParentNode(this);
}
void setAttributes(std::vector<Attribute> attributes);
};
}

View File

@ -8,12 +8,18 @@
namespace hex::dp {
int Node::s_idCounter = 1;
static std::atomic_bool s_interrupted;
Node::Node(UnlocalizedString unlocalizedTitle, std::vector<Attribute> attributes) : m_id(s_idCounter++), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_attributes(std::move(attributes)) {
for (auto &attr : m_attributes)
attr.setParentNode(this);
}
void Node::draw() {
this->drawNode();
}
const std::vector<u8>& Node::getBufferOnInput(u32 index) {
auto attribute = this->getConnectedInputAttribute(index);
@ -148,9 +154,56 @@ namespace hex::dp {
m_overlay->getData() = data;
}
[[noreturn]] void Node::throwNodeError(const std::string &message) {
throw NodeError { this, message };
}
void Node::setAttributes(std::vector<Attribute> attributes) {
m_attributes = std::move(attributes);
for (auto &attr : m_attributes)
attr.setParentNode(this);
}
void Node::setIdCounter(int id) {
if (id > s_idCounter)
s_idCounter = id;
}
Attribute& Node::getAttribute(u32 index) {
if (index >= this->getAttributes().size())
throw std::runtime_error("Attribute index out of bounds!");
return this->getAttributes()[index];
}
Attribute *Node::getConnectedInputAttribute(u32 index) {
const auto &connectedAttribute = this->getAttribute(index).getConnectedAttributes();
if (connectedAttribute.empty())
return nullptr;
return connectedAttribute.begin()->second;
}
void Node::markInputProcessed(u32 index) {
const auto &[iter, inserted] = m_processedInputs.insert(index);
if (!inserted)
throwNodeError("Recursion detected!");
if (s_interrupted) {
s_interrupted = false;
throwNodeError("Execution interrupted!");
}
}
void Node::unmarkInputProcessed(u32 index) {
m_processedInputs.erase(index);
}
void Node::interrupt() {
s_interrupted = true;
}
}

View File

@ -8,6 +8,7 @@
#include <imnodes_internal.h>
#include <string>
#include <hex/api/task_manager.hpp>
#include <nlohmann/json.hpp>
namespace hex::plugin::builtin {
@ -17,6 +18,8 @@ namespace hex::plugin::builtin {
struct Workspace {
Workspace() = default;
std::unique_ptr<ImNodesContext, void(*)(ImNodesContext*)> context = { []{
ImNodesContext *ctx = ImNodes::CreateContext();
ctx->Style = ImNodes::GetStyle();
@ -47,7 +50,7 @@ namespace hex::plugin::builtin {
static void eraseLink(Workspace &workspace, int id);
static void eraseNodes(Workspace &workspace, const std::vector<int> &ids);
static void processNodes(Workspace &workspace);
void processNodes(Workspace &workspace);
void reloadCustomNodes();
void updateNodePositions();
@ -74,6 +77,7 @@ namespace hex::plugin::builtin {
PerProvider<Workspace> m_mainWorkspace;
PerProvider<std::vector<Workspace*>> m_workspaceStack;
TaskHolder m_evaluationTask;
};
}

View File

@ -138,6 +138,10 @@ namespace hex::plugin::builtin {
this->setIntegerOnOutput(4, m_value);
}
void reset() override {
m_started = false;
}
private:
bool m_started = false;
i128 m_value = 0;

View File

@ -28,10 +28,7 @@ namespace hex::plugin::builtin {
}
void process() override {
m_value.reset();
const auto &input = this->getIntegerOnInput(0);
m_value = input;
m_value = this->getIntegerOnInput(0);
}
private:

View File

@ -390,10 +390,6 @@ namespace hex::plugin::builtin {
m_updateNodePositions = true;
});
EventDataChanged::subscribe(this, [this](prv::Provider *provider) {
ViewDataProcessor::processNodes(*m_workspaceStack.get(provider).back());
});
/* Import Nodes */
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.import", "hex.builtin.menu.file.import.data_processor" }, ICON_VS_CHIP, 4050, Shortcut::None, [this]{
fs::openFileBrowser(fs::DialogMode::Open, { {"hex.builtin.view.data_processor.name"_lang, "hexnode" } },
@ -532,36 +528,49 @@ namespace hex::plugin::builtin {
// Reset any potential node errors
workspace.currNodeError.reset();
// Process all nodes in the workspace
try {
for (auto &endNode : workspace.endNodes) {
// Reset the output data of the end node
endNode->resetOutputData();
m_evaluationTask = TaskManager::createTask("Evaluating Nodes...", 0, [this, workspace = &workspace](Task& task) {
task.setInterruptCallback([]{
dp::Node::interrupt();
});
do {
// Reset processed inputs of all nodes
for (auto &node : workspace.nodes)
node->resetProcessedInputs();
// Process all nodes in the workspace
try {
for (auto &endNode : workspace->endNodes) {
// Reset the output data of the end node
endNode->resetOutputData();
// Process the end node
endNode->process();
}
} catch (const dp::Node::NodeError &e) {
// Handle user errors
// Reset processed inputs of all nodes
for (auto &node : workspace->nodes) {
node->reset();
node->resetProcessedInputs();
}
// Add the node error to the current workspace, so it can be displayed
workspace.currNodeError = e;
// Process the end node
endNode->process();
}
} catch (const dp::Node::NodeError &e) {
// Handle user errors
// Add the node error to the current workspace, so it can be displayed
workspace->currNodeError = e;
// Delete all overlays
for (auto overlay : workspace->dataOverlays)
ImHexApi::Provider::get()->deleteOverlay(overlay);
workspace->dataOverlays.clear();
} catch (const std::runtime_error &e) {
// Handle internal errors
log::fatal("Data processor node implementation bug! {}", e.what());
} catch (const std::exception &e) {
// Handle other fatal errors
log::fatal("Unhandled exception thrown in data processor node! {}", e.what());
}
task.update();
} while (m_continuousEvaluation);
});
// Delete all overlays
for (auto overlay : workspace.dataOverlays)
ImHexApi::Provider::get()->deleteOverlay(overlay);
workspace.dataOverlays.clear();
} catch (const std::runtime_error &e) {
// Handle internal errors
log::fatal("Data processor node implementation bug! {}", e.what());
} catch (const std::exception &e) {
// Handle other fatal errors
log::fatal("Unhandled exception thrown in data processor node! {}", e.what());
}
}
void ViewDataProcessor::reloadCustomNodes() {
@ -774,7 +783,9 @@ namespace hex::plugin::builtin {
// Draw the node's body
ImGui::PopStyleVar();
node.drawNode();
if (!m_evaluationTask.isRunning()) {
node.draw();
}
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(1.0F, 1.0F));
// Draw all attributes of the node
@ -851,6 +862,8 @@ namespace hex::plugin::builtin {
void ViewDataProcessor::drawContent() {
auto &workspace = *m_workspaceStack->back();
ImGui::BeginDisabled(m_evaluationTask.isRunning());
bool popWorkspace = false;
// Set the ImNodes context to the current workspace context
ImNodes::SetCurrentContext(workspace.context.get());
@ -873,6 +886,9 @@ namespace hex::plugin::builtin {
if (ImGui::BeginChild("##node_editor", ImGui::GetContentRegionAvail() - ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 1.3F))) {
ImNodes::BeginNodeEditor();
if (m_evaluationTask.isRunning())
ImNodes::GetCurrentContext()->MousePos = { FLT_MAX, FLT_MAX };
// Loop over all nodes that have been placed in the workspace
bool stillUpdating = m_updateNodePositions;
for (auto &node : workspace.nodes) {
@ -933,10 +949,19 @@ namespace hex::plugin::builtin {
}
ImGui::EndChild();
ImGui::EndDisabled();
// Draw the control bar at the bottom
{
if (ImGuiExt::IconButton(ICON_VS_DEBUG_START, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen)) || m_continuousEvaluation)
this->processNodes(workspace);
if (!m_evaluationTask.isRunning()) {
if (ImGuiExt::IconButton(ICON_VS_DEBUG_START, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen))) {
this->processNodes(workspace);
}
} else {
if (ImGuiExt::IconButton(ICON_VS_DEBUG_STOP, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) {
m_evaluationTask.interrupt();
}
}
ImGui::SameLine();
@ -944,7 +969,7 @@ namespace hex::plugin::builtin {
}
// Erase links that have been distroyed
// Erase links that have been destroyed
{
int linkId;
if (ImNodes::IsLinkDestroyed(&linkId)) {