parent
df33e5e3a7
commit
23a83adb23
72 changed files with 1423 additions and 1220 deletions
After Width: | Height: | Size: 463 KiB |
@ -1,381 +0,0 @@ |
|||||||
// cxxpool is a header-only thread pool for C++
|
|
||||||
// Repository: https://github.com/bloomen/cxxpool
|
|
||||||
// Copyright: 2022 Christian Blume
|
|
||||||
// License: http://www.opensource.org/licenses/mit-license.php
|
|
||||||
#pragma once |
|
||||||
#include <thread> |
|
||||||
#include <mutex> |
|
||||||
#include <future> |
|
||||||
#include <stdexcept> |
|
||||||
#include <queue> |
|
||||||
#include <utility> |
|
||||||
#include <functional> |
|
||||||
#include <vector> |
|
||||||
#include <chrono> |
|
||||||
#include <cstddef> |
|
||||||
|
|
||||||
|
|
||||||
namespace cxxpool { |
|
||||||
namespace detail { |
|
||||||
|
|
||||||
|
|
||||||
template<typename Iterator> |
|
||||||
struct future_info { |
|
||||||
typedef typename std::iterator_traits<Iterator>::value_type future_type; |
|
||||||
typedef decltype(std::declval<future_type>().get()) value_type; |
|
||||||
static constexpr bool is_void = std::is_void<value_type>::value; |
|
||||||
}; |
|
||||||
|
|
||||||
|
|
||||||
} // detail
|
|
||||||
|
|
||||||
|
|
||||||
// Waits until all futures contain results
|
|
||||||
template<typename Iterator> |
|
||||||
inline |
|
||||||
void wait(Iterator first, Iterator last) { |
|
||||||
for (; first != last; ++first) |
|
||||||
first->wait(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// Waits until all futures contain results with a given timeout duration and
|
|
||||||
// returns a container of std::future::status
|
|
||||||
template<typename Result, typename Iterator, typename Rep, typename Period> |
|
||||||
inline |
|
||||||
Result wait_for(Iterator first, Iterator last, |
|
||||||
const std::chrono::duration<Rep, Period>& timeout_duration, |
|
||||||
Result result) { |
|
||||||
for (; first != last; ++first) |
|
||||||
result.push_back(first->wait_for(timeout_duration)); |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// Waits until all futures contain results with a given timeout duration and
|
|
||||||
// returns a vector of std::future::status
|
|
||||||
template<typename Iterator, typename Rep, typename Period> |
|
||||||
inline |
|
||||||
std::vector<std::future_status> wait_for(Iterator first, Iterator last, |
|
||||||
const std::chrono::duration<Rep, Period>& timeout_duration) { |
|
||||||
return wait_for(first, last, timeout_duration, std::vector<std::future_status>{}); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// Waits until all futures contain results with a given timeout time and
|
|
||||||
// returns a container of std::future::status
|
|
||||||
template<typename Result, typename Iterator, typename Clock, typename Duration> |
|
||||||
inline |
|
||||||
Result wait_until(Iterator first, Iterator last, |
|
||||||
const std::chrono::time_point<Clock, Duration>& timeout_time, |
|
||||||
Result result) { |
|
||||||
for (; first != last; ++first) |
|
||||||
result.push_back(first->wait_until(timeout_time)); |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// Waits until all futures contain results with a given timeout time and
|
|
||||||
// returns a vector of std::future::status
|
|
||||||
template<typename Iterator, typename Clock, typename Duration> |
|
||||||
inline |
|
||||||
std::vector<std::future_status> wait_until(Iterator first, Iterator last, |
|
||||||
const std::chrono::time_point<Clock, Duration>& timeout_time) { |
|
||||||
return wait_until(first, last, timeout_time, std::vector<std::future_status>{}); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// Calls get() on all futures
|
|
||||||
template<typename Iterator, |
|
||||||
typename = typename std::enable_if<cxxpool::detail::future_info<Iterator>::is_void>::type> |
|
||||||
inline |
|
||||||
void get(Iterator first, Iterator last) { |
|
||||||
for (; first != last; ++first) |
|
||||||
first->get(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// Calls get() on all futures and stores the results in the returned container
|
|
||||||
template<typename Result, typename Iterator, |
|
||||||
typename = typename std::enable_if<!cxxpool::detail::future_info<Iterator>::is_void>::type> |
|
||||||
inline |
|
||||||
Result get(Iterator first, Iterator last, Result result) { |
|
||||||
for (; first != last; ++first) |
|
||||||
result.push_back(first->get()); |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// Calls get() on all futures and stores the results in the returned vector
|
|
||||||
template<typename Iterator, |
|
||||||
typename = typename std::enable_if<!detail::future_info<Iterator>::is_void>::type> |
|
||||||
inline |
|
||||||
std::vector<typename detail::future_info<Iterator>::value_type> |
|
||||||
get(Iterator first, Iterator last) { |
|
||||||
return cxxpool::get(first, last, std::vector<typename cxxpool::detail::future_info<Iterator>::value_type>{}); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
namespace detail { |
|
||||||
|
|
||||||
|
|
||||||
template<typename Index, Index max = std::numeric_limits<Index>::max()> |
|
||||||
class infinite_counter { |
|
||||||
public: |
|
||||||
|
|
||||||
infinite_counter() |
|
||||||
: count_{0} |
|
||||||
{} |
|
||||||
|
|
||||||
infinite_counter& operator++() { |
|
||||||
if (count_.back() == max) |
|
||||||
count_.push_back(0); |
|
||||||
else |
|
||||||
++count_.back(); |
|
||||||
return *this; |
|
||||||
} |
|
||||||
|
|
||||||
bool operator>(const infinite_counter& other) const { |
|
||||||
if (count_.size() == other.count_.size()) { |
|
||||||
return count_.back() > other.count_.back(); |
|
||||||
} else { |
|
||||||
return count_.size() > other.count_.size(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private: |
|
||||||
std::vector<Index> count_; |
|
||||||
}; |
|
||||||
|
|
||||||
|
|
||||||
class priority_task { |
|
||||||
public: |
|
||||||
typedef std::size_t counter_elem_t; |
|
||||||
|
|
||||||
priority_task() |
|
||||||
: callback_{}, priority_{}, order_{} |
|
||||||
{} |
|
||||||
|
|
||||||
// cppcheck-suppress passedByValue
|
|
||||||
priority_task(std::function<void()> callback, std::size_t priority, cxxpool::detail::infinite_counter<counter_elem_t> order) |
|
||||||
: callback_{std::move(callback)}, priority_(priority), order_{std::move(order)} |
|
||||||
{} |
|
||||||
|
|
||||||
bool operator<(const priority_task& other) const { |
|
||||||
if (priority_ == other.priority_) { |
|
||||||
return order_ > other.order_; |
|
||||||
} else { |
|
||||||
return priority_ < other.priority_; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void operator()() const { |
|
||||||
return callback_(); |
|
||||||
} |
|
||||||
|
|
||||||
private: |
|
||||||
std::function<void()> callback_; |
|
||||||
std::size_t priority_; |
|
||||||
cxxpool::detail::infinite_counter<counter_elem_t> order_; |
|
||||||
}; |
|
||||||
|
|
||||||
|
|
||||||
} // detail
|
|
||||||
|
|
||||||
|
|
||||||
// Exception thrown by the thread_pool class
|
|
||||||
class thread_pool_error : public std::runtime_error { |
|
||||||
public: |
|
||||||
explicit thread_pool_error(const std::string& message) |
|
||||||
: std::runtime_error{message} |
|
||||||
{} |
|
||||||
}; |
|
||||||
|
|
||||||
|
|
||||||
// A thread pool for C++
|
|
||||||
//
|
|
||||||
// Constructing the thread pool launches the worker threads while
|
|
||||||
// destructing it joins them. The threads will be alive for as long as the
|
|
||||||
// thread pool is not destructed. One may call add_threads() to add more
|
|
||||||
// threads to the thread pool.
|
|
||||||
//
|
|
||||||
// Tasks can be pushed into the pool with and w/o providing a priority >= 0.
|
|
||||||
// Not providing a priority is equivalent to providing a priority of 0.
|
|
||||||
// Those tasks are processed first that have the highest priority.
|
|
||||||
// If priorities are equal those tasks are processed first that were pushed
|
|
||||||
// first into the pool (FIFO).
|
|
||||||
class thread_pool { |
|
||||||
public: |
|
||||||
|
|
||||||
// Constructor. No threads are launched
|
|
||||||
thread_pool() |
|
||||||
: done_{false}, paused_{false}, threads_{}, tasks_{}, task_counter_{}, |
|
||||||
task_cond_var_{}, task_mutex_{}, thread_mutex_{} |
|
||||||
{} |
|
||||||
|
|
||||||
// Constructor. Launches the desired number of threads. Passing 0 is
|
|
||||||
// equivalent to calling the no-argument constructor
|
|
||||||
explicit thread_pool(std::size_t n_threads) |
|
||||||
: thread_pool{} |
|
||||||
{ |
|
||||||
if (n_threads > 0) { |
|
||||||
std::lock_guard<std::mutex> thread_lock(thread_mutex_); |
|
||||||
const auto n_target = threads_.size() + n_threads; |
|
||||||
while (threads_.size() < n_target) { |
|
||||||
std::thread thread; |
|
||||||
try { |
|
||||||
thread = std::thread{&thread_pool::worker, this}; |
|
||||||
} catch (...) { |
|
||||||
shutdown(); |
|
||||||
throw; |
|
||||||
} |
|
||||||
try { |
|
||||||
threads_.push_back(std::move(thread)); |
|
||||||
} catch (...) { |
|
||||||
shutdown(); |
|
||||||
thread.join(); |
|
||||||
throw; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Destructor. Joins all threads launched. Waits for all running tasks
|
|
||||||
// to complete
|
|
||||||
~thread_pool() { |
|
||||||
shutdown(); |
|
||||||
} |
|
||||||
|
|
||||||
// deleting copy/move semantics
|
|
||||||
thread_pool(const thread_pool&) = delete; |
|
||||||
thread_pool& operator=(const thread_pool&) = delete; |
|
||||||
thread_pool(thread_pool&&) = delete; |
|
||||||
thread_pool& operator=(thread_pool&&) = delete; |
|
||||||
|
|
||||||
// Adds new threads to the pool and launches them
|
|
||||||
void add_threads(std::size_t n_threads) { |
|
||||||
if (n_threads > 0) { |
|
||||||
{ |
|
||||||
std::lock_guard<std::mutex> task_lock(task_mutex_); |
|
||||||
if (done_) |
|
||||||
throw thread_pool_error{"add_threads called while pool is shutting down"}; |
|
||||||
} |
|
||||||
std::lock_guard<std::mutex> thread_lock(thread_mutex_); |
|
||||||
const auto n_target = threads_.size() + n_threads; |
|
||||||
while (threads_.size() < n_target) { |
|
||||||
std::thread thread(&thread_pool::worker, this); |
|
||||||
try { |
|
||||||
threads_.push_back(std::move(thread)); |
|
||||||
} catch (...) { |
|
||||||
shutdown(); |
|
||||||
thread.join(); |
|
||||||
throw; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Returns the number of threads launched
|
|
||||||
std::size_t n_threads() const { |
|
||||||
{ |
|
||||||
std::lock_guard<std::mutex> task_lock(task_mutex_); |
|
||||||
if (done_) |
|
||||||
throw thread_pool_error{"n_threads called while pool is shutting down"}; |
|
||||||
} |
|
||||||
std::lock_guard<std::mutex> thread_lock(thread_mutex_); |
|
||||||
return threads_.size(); |
|
||||||
} |
|
||||||
|
|
||||||
// Pushes a new task into the thread pool and returns the associated future.
|
|
||||||
// The task will have a priority of 0
|
|
||||||
template<typename Functor, typename... Args> |
|
||||||
auto push(Functor&& functor, Args&&... args) -> std::future<decltype(functor(args...))> { |
|
||||||
return push(0, std::forward<Functor>(functor), std::forward<Args>(args)...); |
|
||||||
} |
|
||||||
|
|
||||||
// Pushes a new task into the thread pool while providing a priority and
|
|
||||||
// returns the associated future. Higher priorities are processed first
|
|
||||||
template<typename Functor, typename... Args> |
|
||||||
auto push(std::size_t priority, Functor&& functor, Args&&... args) -> std::future<decltype(functor(args...))> { |
|
||||||
typedef decltype(functor(args...)) result_type; |
|
||||||
auto pack_task = std::make_shared<std::packaged_task<result_type()>>( |
|
||||||
std::bind(std::forward<Functor>(functor), std::forward<Args>(args)...)); |
|
||||||
auto future = pack_task->get_future(); |
|
||||||
{ |
|
||||||
std::lock_guard<std::mutex> task_lock(task_mutex_); |
|
||||||
if (done_) |
|
||||||
throw cxxpool::thread_pool_error{"push called while pool is shutting down"}; |
|
||||||
tasks_.emplace([pack_task]{ (*pack_task)(); }, priority, ++task_counter_); |
|
||||||
} |
|
||||||
task_cond_var_.notify_one(); |
|
||||||
return future; |
|
||||||
} |
|
||||||
|
|
||||||
// Returns the current number of queued tasks
|
|
||||||
std::size_t n_tasks() const { |
|
||||||
std::lock_guard<std::mutex> task_lock(task_mutex_); |
|
||||||
return tasks_.size(); |
|
||||||
} |
|
||||||
|
|
||||||
// Clears all queued tasks, not affecting currently running tasks
|
|
||||||
void clear() { |
|
||||||
std::lock_guard<std::mutex> task_lock(task_mutex_); |
|
||||||
decltype(tasks_) empty; |
|
||||||
tasks_.swap(empty); |
|
||||||
} |
|
||||||
|
|
||||||
// If enabled then pauses the processing of tasks, not affecting currently
|
|
||||||
// running tasks. Disabling it will resume the processing of tasks
|
|
||||||
void set_pause(bool enabled) { |
|
||||||
{ |
|
||||||
std::lock_guard<std::mutex> task_lock(task_mutex_); |
|
||||||
paused_ = enabled; |
|
||||||
} |
|
||||||
if (!paused_) |
|
||||||
task_cond_var_.notify_all(); |
|
||||||
} |
|
||||||
|
|
||||||
private: |
|
||||||
|
|
||||||
void worker() { |
|
||||||
for (;;) { |
|
||||||
cxxpool::detail::priority_task task; |
|
||||||
{ |
|
||||||
std::unique_lock<std::mutex> task_lock(task_mutex_); |
|
||||||
task_cond_var_.wait(task_lock, [this]{ |
|
||||||
return !paused_ && (done_ || !tasks_.empty()); |
|
||||||
}); |
|
||||||
if (done_ && tasks_.empty()) |
|
||||||
break; |
|
||||||
task = tasks_.top(); |
|
||||||
tasks_.pop(); |
|
||||||
} |
|
||||||
task(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void shutdown() { |
|
||||||
{ |
|
||||||
std::lock_guard<std::mutex> task_lock(task_mutex_); |
|
||||||
done_ = true; |
|
||||||
paused_ = false; |
|
||||||
} |
|
||||||
task_cond_var_.notify_all(); |
|
||||||
std::lock_guard<std::mutex> thread_lock(thread_mutex_); |
|
||||||
for (auto& thread : threads_) |
|
||||||
thread.join(); |
|
||||||
} |
|
||||||
|
|
||||||
bool done_; |
|
||||||
bool paused_; |
|
||||||
std::vector<std::thread> threads_; |
|
||||||
std::priority_queue<cxxpool::detail::priority_task> tasks_; |
|
||||||
cxxpool::detail::infinite_counter< |
|
||||||
typename detail::priority_task::counter_elem_t> task_counter_; |
|
||||||
std::condition_variable task_cond_var_; |
|
||||||
mutable std::mutex task_mutex_; |
|
||||||
mutable std::mutex thread_mutex_; |
|
||||||
}; |
|
||||||
|
|
||||||
|
|
||||||
} // cxxpool
|
|
@ -0,0 +1,132 @@ |
|||||||
|
/*
|
||||||
|
* Simple header-only thread pool implementation in modern C++. |
||||||
|
* |
||||||
|
* Created: Aug 9, 2020. |
||||||
|
* Repository: https://github.com/leiless/threadpool.hpp
|
||||||
|
* LICENSE: BSD-2-Clause |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef THE_THREADPOOL_HPP |
||||||
|
#define THE_THREADPOOL_HPP |
||||||
|
|
||||||
|
#include <functional> |
||||||
|
#include <mutex> |
||||||
|
#include <condition_variable> |
||||||
|
#include <queue> |
||||||
|
#include <thread> |
||||||
|
#include <future> |
||||||
|
|
||||||
|
#define THE_NAMESPACE_BEGIN(name) namespace name { |
||||||
|
#define THE_NAMESPACE_END() } |
||||||
|
|
||||||
|
THE_NAMESPACE_BEGIN(concurrent) |
||||||
|
|
||||||
|
class threadpool { |
||||||
|
public: |
||||||
|
explicit threadpool(size_t threads) : alive(true) { |
||||||
|
if (threads == 0) { |
||||||
|
throw std::runtime_error("thread pool size cannot be zero"); |
||||||
|
} |
||||||
|
|
||||||
|
for (auto i = 0llu; i < threads; i++) { |
||||||
|
std::cerr << "work" << std::endl; |
||||||
|
workers.emplace_back([this] { worker_main(); }); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// see: https://stackoverflow.com/a/23771245/13600780
|
||||||
|
threadpool(const threadpool &) = delete; |
||||||
|
threadpool & operator=(const threadpool &) = delete; |
||||||
|
|
||||||
|
~threadpool() noexcept { |
||||||
|
{ |
||||||
|
std::lock_guard<decltype(mtx)> lock(mtx); |
||||||
|
alive = false; |
||||||
|
} |
||||||
|
|
||||||
|
cv.notify_all(); |
||||||
|
|
||||||
|
for (auto & worker : workers) { |
||||||
|
worker.join(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
template<typename Fn, typename... Args> |
||||||
|
decltype(auto) enqueue(Fn && fn, Args &&... args) { |
||||||
|
return enqueue(false, fn, args...); |
||||||
|
} |
||||||
|
|
||||||
|
template<typename Fn, typename... Args> |
||||||
|
decltype(auto) enqueue_r(Fn && fn, Args &&... args) { |
||||||
|
return enqueue(true, fn, args...); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
template<typename Fn, typename... Args> |
||||||
|
decltype(auto) enqueue(bool block_on_shutdown, Fn && fn, Args &&... args) { |
||||||
|
using return_type = std::invoke_result_t<Fn, Args...>; |
||||||
|
using pack_task = std::packaged_task<return_type()>; |
||||||
|
|
||||||
|
auto t = std::make_shared<pack_task>( |
||||||
|
std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...) |
||||||
|
); |
||||||
|
auto future = t->get_future(); |
||||||
|
|
||||||
|
{ |
||||||
|
std::lock_guard<decltype(mtx)> lock(mtx); |
||||||
|
if (!alive) { |
||||||
|
throw std::runtime_error("enqueue on stopped thread pool"); |
||||||
|
} |
||||||
|
tasks.emplace([t = std::move(t)] { (*t)(); }, block_on_shutdown); |
||||||
|
} |
||||||
|
|
||||||
|
cv.notify_one(); |
||||||
|
return future; |
||||||
|
} |
||||||
|
|
||||||
|
using task = std::pair<std::function<void()>, bool>; |
||||||
|
|
||||||
|
[[nodiscard]] inline task poll_task() noexcept { |
||||||
|
task t; |
||||||
|
|
||||||
|
std::unique_lock<decltype(mtx)> lock(mtx); |
||||||
|
cv.wait(lock, [this] { return !tasks.empty() || !alive; }); |
||||||
|
|
||||||
|
while (!tasks.empty()) { |
||||||
|
if (!alive && !tasks.front().second) { |
||||||
|
tasks.pop(); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
t = std::move(tasks.front()); |
||||||
|
tasks.pop(); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
return t; |
||||||
|
} |
||||||
|
|
||||||
|
void worker_main() { |
||||||
|
while (true) { |
||||||
|
std::cerr << "I" << std::endl; |
||||||
|
task t = poll_task(); |
||||||
|
std::cerr << "II" << std::endl; |
||||||
|
// The thread pool is going to shutdown
|
||||||
|
if (t.first == nullptr) break; |
||||||
|
std::cerr << "III" << std::endl; |
||||||
|
t.first(); |
||||||
|
std::cerr << "IIII" << std::endl; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool alive; |
||||||
|
std::mutex mtx; |
||||||
|
std::condition_variable cv; |
||||||
|
std::queue<task> tasks; |
||||||
|
std::vector<std::thread> workers; |
||||||
|
}; |
||||||
|
|
||||||
|
THE_NAMESPACE_END() |
||||||
|
|
||||||
|
#endif |
||||||
|
|
@ -0,0 +1,45 @@ |
|||||||
|
// This file is part of OpenCV project.
|
||||||
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||||
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
|
// Copyright Amir Hassan (kallaballa) <amir@viel-zu.org>
|
||||||
|
|
||||||
|
#include "nanoguicontext.hpp" |
||||||
|
|
||||||
|
namespace cv { |
||||||
|
namespace v4d { |
||||||
|
namespace detail { |
||||||
|
NanoguiContext::NanoguiContext(V4D& v4d, FrameBufferContext& fbContext) : |
||||||
|
mainFbContext_(fbContext), nguiFbContext_(v4d, "NanoGUI", fbContext) { |
||||||
|
fbCtx().makeCurrent(); |
||||||
|
screen_ = new nanogui::Screen(); |
||||||
|
screen_->initialize(nguiFbContext_.getGLFWWindow(), false); |
||||||
|
form_ = new cv::v4d::FormHelper(screen_); |
||||||
|
fbCtx().resizeWindow(fbCtx().getSize()); |
||||||
|
fbCtx().makeNoneCurrent(); |
||||||
|
} |
||||||
|
|
||||||
|
void NanoguiContext::render() { |
||||||
|
screen().draw_widgets(); |
||||||
|
} |
||||||
|
|
||||||
|
void NanoguiContext::build(std::function<void(cv::v4d::FormHelper&)> fn) { |
||||||
|
fbCtx().makeCurrent(); |
||||||
|
fn(form()); |
||||||
|
screen().perform_layout(); |
||||||
|
fbCtx().makeNoneCurrent(); |
||||||
|
} |
||||||
|
|
||||||
|
nanogui::Screen& NanoguiContext::screen() { |
||||||
|
return *screen_; |
||||||
|
} |
||||||
|
|
||||||
|
cv::v4d::FormHelper& NanoguiContext::form() { |
||||||
|
return *form_; |
||||||
|
} |
||||||
|
|
||||||
|
FrameBufferContext& NanoguiContext::fbCtx() { |
||||||
|
return nguiFbContext_; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
// This file is part of OpenCV project.
|
||||||
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||||
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
|
// Copyright Amir Hassan (kallaballa) <amir@viel-zu.org>
|
||||||
|
|
||||||
|
#ifndef SRC_OPENCV_NANOGUICONTEXT_HPP_ |
||||||
|
#define SRC_OPENCV_NANOGUICONTEXT_HPP_ |
||||||
|
|
||||||
|
#include "framebuffercontext.hpp" |
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__ |
||||||
|
#include <emscripten.h> |
||||||
|
#endif |
||||||
|
|
||||||
|
#include <opencv2/v4d/formhelper.hpp> |
||||||
|
|
||||||
|
namespace cv { |
||||||
|
namespace v4d { |
||||||
|
namespace detail { |
||||||
|
/*!
|
||||||
|
* Used to setup a nanogui context |
||||||
|
*/ |
||||||
|
class NanoguiContext { |
||||||
|
nanogui::Screen* screen_; |
||||||
|
cv::v4d::FormHelper* form_; |
||||||
|
FrameBufferContext& mainFbContext_; |
||||||
|
FrameBufferContext nguiFbContext_; |
||||||
|
cv::UMat preFB_; |
||||||
|
cv::UMat fb_; |
||||||
|
cv::UMat postFB_; |
||||||
|
public: |
||||||
|
NanoguiContext(V4D& v4d, FrameBufferContext& fbContext); |
||||||
|
void render(); |
||||||
|
void build(std::function<void(cv::v4d::FormHelper&)> fn); |
||||||
|
nanogui::Screen& screen(); |
||||||
|
cv::v4d::FormHelper& form(); |
||||||
|
|
||||||
|
FrameBufferContext& fbCtx(); |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#endif /* SRC_OPENCV_NANOGUICONTEXT_HPP_ */ |
@ -0,0 +1,16 @@ |
|||||||
|
# Display an image using direct framebuffer access {#v4d_display_image_fb} |
||||||
|
|
||||||
|
@prev_tutorial{v4d_display_image_pipeline} |
||||||
|
@next_tutorial{v4d_vector_graphics} |
||||||
|
|
||||||
|
| | | |
||||||
|
| -: | :- | |
||||||
|
| Original author | Amir Hassan (kallaballa) <amir@viel-zu.org> | |
||||||
|
| Compatibility | OpenCV >= 4.7 | |
||||||
|
|
||||||
|
## Using direct framebuffer access |
||||||
|
Instead of feeding to the video pipeline we can request the framebuffer in a ```fb``` context and copy the image to it. But first we must manually resize and color convert the image. |
||||||
|
|
||||||
|
\htmlinclude "../samples/example_v4d_display_image_fb.html" |
||||||
|
|
||||||
|
@include samples/display_image_fb.cpp |
@ -0,0 +1,16 @@ |
|||||||
|
# Render vector graphics {#v4d_vector_graphics} |
||||||
|
|
||||||
|
@prev_tutorial{v4d_display_image_fb} |
||||||
|
@next_tutorial{v4d_vector_graphics_and_fb} |
||||||
|
|
||||||
|
| | | |
||||||
|
| -: | :- | |
||||||
|
| Original author | Amir Hassan (kallaballa) <amir@viel-zu.org> | |
||||||
|
| Compatibility | OpenCV >= 4.7 | |
||||||
|
|
||||||
|
## Vector graphics |
||||||
|
Through the nvg context javascript-canvas-like rendering is possible. |
||||||
|
|
||||||
|
\htmlinclude "../samples/example_v4d_vector_graphics.html" |
||||||
|
|
||||||
|
@include samples/vector_graphics.cpp |
Loading…
Reference in new issue