#include <boost/lexical_cast.hpp>\r
\r
#include <tbb/parallel_for.h>\r
-#include <tbb/spin_mutex.h>\r
+#include <tbb/mutex.h>\r
\r
#include <array>\r
#include <memory>\r
\r
std::vector<layer> layers_; \r
\r
- tbb::spin_mutex output_mutex_;\r
output_func output_;\r
\r
const safe_ptr<frame_factory> factory_;\r
\r
mutable executor executor_;\r
-\r
public:\r
implementation(const printer& parent_printer, const safe_ptr<frame_factory>& factory, const output_func& output) \r
: parent_printer_(parent_printer)\r
void tick()\r
{ \r
auto frames = draw();\r
- output_func output;\r
- {\r
- tbb::spin_mutex::scoped_lock lock(output_mutex_);\r
- output = output_;\r
- }\r
- output(frames);\r
+ output_(draw());\r
executor_.begin_invoke([=]{tick();});\r
}\r
\r
\r
void swap_layer(size_t index, size_t other_index)\r
{\r
- layers_.at(index).swap(layers_[other_index]);\r
+ executor_.invoke([&]\r
+ {\r
+ layers_.at(index).swap(layers_[other_index]);\r
+ });\r
}\r
\r
void swap_layer(size_t index, size_t other_index, frame_producer_device& other)\r
{\r
- layers_.at(index).swap(other.impl_->layers_.at(other_index));\r
+ if(other.impl_.get() == this) // Avoid deadlock.\r
+ swap_layer(index, other_index);\r
+ else\r
+ {\r
+ auto func = [&]\r
+ {\r
+ layers_.at(index).swap(other.impl_->layers_.at(other_index)); \r
+ };\r
+ \r
+ executor_.invoke([&]{other.impl_->executor_.invoke(func);});\r
+ }\r
}\r
\r
- void swap_output(frame_producer_device& other)\r
+ void swap(frame_producer_device& other)\r
{\r
if(other.impl_.get() == this) // Avoid deadlock.\r
return;\r
\r
- tbb::spin_mutex::scoped_lock lock1(output_mutex_);\r
- tbb::spin_mutex::scoped_lock lock2(other.impl_->output_mutex_);\r
- output_.swap(other.impl_->output_);\r
+ auto func = [&]\r
+ {\r
+ for(size_t n = 0; n < frame_producer_device::MAX_LAYER+1; ++n)\r
+ layers_[n].swap(other.impl_->layers_[n]);\r
+ };\r
+ \r
+ executor_.invoke([&]{other.impl_->executor_.invoke(func);});\r
}\r
\r
boost::unique_future<safe_ptr<frame_producer>> foreground(size_t index) const\r
\r
frame_producer_device::frame_producer_device(const printer& parent_printer, const safe_ptr<frame_factory>& factory, const output_func& output) : impl_(new implementation(parent_printer, factory, output)){}\r
frame_producer_device::frame_producer_device(frame_producer_device&& other) : impl_(std::move(other.impl_)){}\r
+void frame_producer_device::swap(frame_producer_device& other){impl_->swap(other);}\r
void frame_producer_device::load(size_t index, const safe_ptr<frame_producer>& producer, bool play_on_load){impl_->load(index, producer, play_on_load);}\r
void frame_producer_device::preview(size_t index, const safe_ptr<frame_producer>& producer){impl_->preview(index, producer);}\r
void frame_producer_device::pause(size_t index){impl_->pause(index);}\r
void frame_producer_device::clear(){impl_->clear();}\r
void frame_producer_device::swap_layer(size_t index, size_t other_index){impl_->swap_layer(index, other_index);}\r
void frame_producer_device::swap_layer(size_t index, size_t other_index, frame_producer_device& other){impl_->swap_layer(index, other_index, other);}\r
-void frame_producer_device::swap_output(frame_producer_device& other){impl_->swap_output(other);}\r
boost::unique_future<safe_ptr<frame_producer>> frame_producer_device::foreground(size_t index) const{ return impl_->foreground(index);}\r
}}
\ No newline at end of file
\r
explicit frame_producer_device(const printer& parent_printer, const safe_ptr<frame_factory>& factory, const output_func& output);\r
frame_producer_device(frame_producer_device&& other);\r
+ void swap(frame_producer_device& other);\r
\r
void load(size_t index, const safe_ptr<frame_producer>& producer, bool play_on_load = false);\r
void preview(size_t index, const safe_ptr<frame_producer>& producer);\r
void clear(); \r
void swap_layer(size_t index, size_t other_index);\r
void swap_layer(size_t index, size_t other_index, frame_producer_device& other);\r
- void swap_output(frame_producer_device& other);\r
boost::unique_future<safe_ptr<frame_producer>> foreground(size_t index) const;\r
\r
private:\r
\r
struct layer::implementation : boost::noncopyable\r
{ \r
- mutable tbb::spin_mutex printer_mutex_;\r
printer parent_printer_;\r
int index_;\r
\r
\r
std::wstring print() const\r
{\r
- tbb::spin_mutex::scoped_lock lock(printer_mutex_);\r
return (parent_printer_ ? parent_printer_() + L"/" : L"") + L"layer[" + boost::lexical_cast<std::wstring>(index_) + L"]";\r
}\r
-};\r
\r
-layer::layer(int index, const printer& parent_printer)\r
-{\r
- impl_ = new implementation(index, parent_printer);\r
-}\r
-layer::~layer()\r
-{\r
- if(!impl_)\r
- return;\r
+ void swap(implementation& other)\r
+ {\r
+ std::swap(foreground_, other.foreground_);\r
+ std::swap(background_, other.background_);\r
+ std::swap(last_frame_, other.last_frame_);\r
+ std::swap(is_paused_, other.is_paused_);\r
+ }\r
+};\r
\r
- impl_->clear();\r
- delete impl_.fetch_and_store(nullptr);\r
-}\r
-layer::layer(layer&& other)\r
-{\r
- impl_ = other.impl_.fetch_and_store(nullptr);\r
-}\r
+layer::layer(int index, const printer& parent_printer) : impl_(new implementation(index, parent_printer)){}\r
+layer::layer(layer&& other) : impl_(std::move(other.impl_)){}\r
layer& layer::operator=(layer&& other)\r
{\r
- impl_ = other.impl_.fetch_and_store(nullptr);\r
+ impl_ = std::move(other.impl_);\r
return *this;\r
}\r
void layer::swap(layer& other)\r
{\r
- impl_ = other.impl_.compare_and_swap(impl_, other.impl_);\r
- tbb::spin_mutex::scoped_lock lock(other.impl_->printer_mutex_);\r
- std::swap(impl_->index_, other.impl_->index_);\r
- std::swap(impl_->parent_printer_, other.impl_->parent_printer_);\r
+ impl_->swap(*other.impl_);\r
}\r
void layer::load(const safe_ptr<frame_producer>& frame_producer, bool play_on_load){return impl_->load(frame_producer, play_on_load);} \r
void layer::preview(const safe_ptr<frame_producer>& frame_producer){return impl_->preview(frame_producer);} \r
{\r
public:\r
layer(int index, const printer& parent_printer = nullptr); // nothrow\r
- ~layer();\r
layer(layer&& other); // nothrow\r
layer& operator=(layer&& other); // nothrow\r
\r
- // Swap is thread-safe on "other".\r
void swap(layer& other); // nothrow \r
\r
void load(const safe_ptr<frame_producer>& producer, bool play_on_load = false); // nothrow\r
std::wstring print() const;\r
private:\r
struct implementation;\r
- tbb::atomic<implementation*> impl_;\r
+ std::shared_ptr<implementation> impl_;\r
};\r
\r
}}
\ No newline at end of file
{\r
auto ch1 = GetChannel();\r
auto ch2 = GetChannels().at(boost::lexical_cast<int>(_parameters[0])-1);\r
- ch1->producer().swap_output(ch2->producer());\r
+ ch1->producer().swap(ch2->producer());\r
}\r
\r
CASPAR_LOG(info) << "Swapped successfully";\r