diff --git a/src/fmri/RenderingState.cpp b/src/fmri/RenderingState.cpp index 8cb5bc7..44d2cba 100644 --- a/src/fmri/RenderingState.cpp +++ b/src/fmri/RenderingState.cpp @@ -6,6 +6,7 @@ #include "visualisations.hpp" #include "Range.hpp" #include "glutils.hpp" +#include "Simulator.hpp" using namespace fmri; @@ -228,25 +229,17 @@ void RenderingState::handleMouseAt(int x, int y) glutPostRedisplay(); } -void RenderingState::loadSimulationData(const std::map &info, vector> &&data) -{ - layerInfo = std::move(info); - layerData = std::move(data); - currentData = layerData.begin(); - - queueUpdate(); -} - void RenderingState::queueUpdate() { // Make sure that visualisations are cleared in the current thread layerVisualisations.clear(); interactionAnimations.clear(); - loadingFuture = std::async(std::launch::async, []() { + visualisationFuture = std::async(std::launch::async, []() { RenderingState::instance().updateVisualisers(); + + return true; }); - isLoading = true; } void RenderingState::updateVisualisers() @@ -278,7 +271,7 @@ void RenderingState::render(float time) const // Clear Color and Depth Buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - if (!isLoading) { + if (!isLoading()) { renderVisualisation(time); } else { renderLoadingScreen(); @@ -418,6 +411,8 @@ void RenderingState::loadOptions(const Options &programOptions) options.pathColor = programOptions.pathColor(); options.layerAlpha = programOptions.layerTransparancy(); options.interactionAlpha = programOptions.interactionTransparancy(); + + simulationFuture = std::async(std::launch::async, Simulator::loadSimulationData, programOptions); } const Color &RenderingState::pathColor() const @@ -454,24 +449,47 @@ float RenderingState::layerAlpha() const return options.layerAlpha; } +/** + * Attempt to wait for completion of a future, for less than a frame. + * + * @tparam T + * @param f The future to wait for + * @return The result of the computation, or an empty optional if it hasn't finished. + */ +template +static std::optional awaitCompletion(std::future& f) +{ + constexpr auto waitTime = std::chrono::milliseconds(10); + switch (f.wait_for(waitTime)) { + case std::future_status::timeout: + return std::nullopt; + + case std::future_status::ready: + return f.get(); + + default: + LOG(ERROR) << "loading status was deferred, invalid state!"; + abort(); + } +} + + void RenderingState::idleFunc() { - if (isLoading && loadingFuture.valid()) { - auto result = loadingFuture.wait_for(std::chrono::milliseconds(16)); - switch (result) { - case std::future_status::deferred: - LOG(ERROR) << "loading status was deferred, invalid state!"; - abort(); - - case std::future_status::timeout: - // Still loading - break; - - case std::future_status::ready: - loadingFuture.get(); + if (isLoading()) { + if (visualisationFuture.valid()) { + auto result = awaitCompletion(visualisationFuture); + if (result) { loadGLItems(); - isLoading = false; - break; + return; + } + } else if (simulationFuture.valid()) { + auto result = awaitCompletion(simulationFuture); + if (result) { + tie(layerInfo, layerData) = std::move(*result); + currentData = layerData.begin(); + queueUpdate(); + } } } else { if (options.mouse_1_pressed) { @@ -490,3 +508,8 @@ void RenderingState::loadGLItems() std::for_each(layerVisualisations.begin(), layerVisualisations.end(), [](auto& x) { x->glLoad(); }); std::for_each(interactionAnimations.begin(), interactionAnimations.end(), [](auto& x) { if (x) x->glLoad(); }); } + +bool RenderingState::isLoading() const +{ + return visualisationFuture.valid() || simulationFuture.valid(); +} diff --git a/src/fmri/RenderingState.hpp b/src/fmri/RenderingState.hpp index 0d4a081..d5ba27f 100644 --- a/src/fmri/RenderingState.hpp +++ b/src/fmri/RenderingState.hpp @@ -40,7 +40,6 @@ namespace fmri void handleSpecialKey(int key); void render(float time) const; - void loadSimulationData(const std::map &info, std::vector> &&data); /** * Load rendering-specific options from the given options object. * @@ -79,8 +78,8 @@ namespace fmri std::vector>::iterator currentData; std::vector> layerVisualisations; std::vector> interactionAnimations; - bool isLoading = false; - std::future loadingFuture; + std::future visualisationFuture; + std::future> simulationFuture; RenderingState() noexcept; @@ -102,5 +101,7 @@ namespace fmri void renderVisualisation(float time) const; void loadGLItems(); + + bool isLoading() const; }; } diff --git a/src/fmri/Simulator.cpp b/src/fmri/Simulator.cpp index 86e2735..5dbf1fa 100644 --- a/src/fmri/Simulator.cpp +++ b/src/fmri/Simulator.cpp @@ -231,3 +231,34 @@ const map & Simulator::layerInfo() const { return pImpl->layerInfo(); } + +std::pair, std::vector>> +fmri::Simulator::loadSimulationData(const Options &options) +{ + Simulator simulator(options.model(), options.weights(), options.means()); + + std::vector> results; + transform(options.inputs().begin(), options.inputs().end(), back_inserter(results), [&simulator] (auto& x) { + return simulator.simulate(x); + }); + + auto dumper = options.imageDumper(); + if (dumper) { + for (auto &layer : *results.begin()) { + dumper->dump(layer); + } + } + + const auto optLabels = options.labels(); + + if (optLabels) { + auto& labels = *optLabels; + for (const auto& result : results) { + auto &last = *result.rbegin(); + auto bestIndex = std::distance(last.data(), max_element(last.data(), last.data() + last.numEntries())); + LOG(INFO) << "Got answer: " << labels[bestIndex] << endl; + } + } + + return make_pair(simulator.layerInfo(), std::move(results)); +} diff --git a/src/fmri/Simulator.hpp b/src/fmri/Simulator.hpp index 48dfc52..a6c7cc4 100644 --- a/src/fmri/Simulator.hpp +++ b/src/fmri/Simulator.hpp @@ -5,6 +5,7 @@ #include #include "LayerData.hpp" #include "LayerInfo.hpp" +#include "Options.hpp" namespace fmri { using std::string; @@ -18,6 +19,8 @@ namespace fmri { vector simulate(const string &input_file); const std::map& layerInfo() const; + static std::pair, std::vector>> loadSimulationData(const Options &options); + private: struct Impl; std::unique_ptr pImpl; diff --git a/src/fmri/main.cpp b/src/fmri/main.cpp index 97e0c8d..ec4c9da 100644 --- a/src/fmri/main.cpp +++ b/src/fmri/main.cpp @@ -17,39 +17,6 @@ using namespace std; using namespace fmri; -static void loadSimulationData(const Options &options) -{ - vector> results; - - auto dumper = options.imageDumper(); - Simulator simulator(options.model(), options.weights(), options.means()); - - for (const auto &image : options.inputs()) { - results.emplace_back(simulator.simulate(image)); - } - - CHECK_GT(results.size(), 0) << "Should have some results" << endl; - - if (dumper) { - for (auto &layer : *results.begin()) { - dumper->dump(layer); - } - } - - const auto optLabels = options.labels(); - - if (optLabels) { - auto& labels = *optLabels; - for (const auto& result : results) { - auto &last = *result.rbegin(); - auto bestIndex = std::distance(last.data(), max_element(last.data(), last.data() + last.numEntries())); - LOG(INFO) << "Got answer: " << labels[bestIndex] << endl; - } - } - - RenderingState::instance().loadSimulationData(simulator.layerInfo(), std::move(results)); -} - int main(int argc, char *argv[]) { google::InitGoogleLogging(argv[0]); @@ -64,7 +31,6 @@ int main(int argc, char *argv[]) // Prepare data for simulations Options options(argc, argv); RenderingState::instance().loadOptions(options); - loadSimulationData(options); // Register callbacks glutReshapeFunc(changeWindowSize);