From: Ronag Date: Wed, 24 Aug 2011 21:17:27 +0000 (+0000) Subject: 2.0 image_mixer: Refactored, core: Fixed destruction proxy usage. X-Git-Tag: 2.0.1~65 X-Git-Url: https://git.sesse.net/?p=casparcg;a=commitdiff_plain;h=a486c25d5e6ce0ebe08e9a2d793a447ff3cb797a 2.0 image_mixer: Refactored, core: Fixed destruction proxy usage. git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@1278 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- diff --git a/common/common.vcxproj b/common/common.vcxproj index 7fada92e2..3a7700691 100644 --- a/common/common.vcxproj +++ b/common/common.vcxproj @@ -226,6 +226,7 @@ + diff --git a/common/common.vcxproj.filters b/common/common.vcxproj.filters index 4ebf73f0d..54cce3a53 100644 --- a/common/common.vcxproj.filters +++ b/common/common.vcxproj.filters @@ -124,5 +124,8 @@ source + + source\utility + \ No newline at end of file diff --git a/common/concurrency/executor.h b/common/concurrency/executor.h index c4ba4008f..0687889a1 100644 --- a/common/concurrency/executor.h +++ b/common/concurrency/executor.h @@ -21,6 +21,7 @@ #include "../exception/win32_exception.h" #include "../utility/string.h" +#include "../utility/move_on_copy.h" #include "../log/log.h" #include @@ -76,23 +77,6 @@ enum thread_priority below_normal_priority_class }; -namespace internal -{ - template - struct move_on_copy - { - move_on_copy(const move_on_copy& other) : value(std::move(other.value)){} - move_on_copy(T&& value) : value(std::move(value)){} - mutable T value; - }; - - template - move_on_copy make_move_on_copy(T&& value) - { - return move_on_copy(std::move(value)); - } -} - class executor : boost::noncopyable { const std::string name_; @@ -133,6 +117,7 @@ public: virtual ~executor() // noexcept { stop(); + execution_queue_[normal_priority].try_push([]{}); // Wake the execution thread. join(); } @@ -159,7 +144,6 @@ public: void stop() // noexcept { is_running_ = false; - execution_queue_[normal_priority].try_push([]{}); // Wake the execution thread. } void wait() // noexcept @@ -177,7 +161,7 @@ public: auto begin_invoke(Func&& func, task_priority priority = normal_priority) -> boost::unique_future // noexcept { // Create a move on copy adaptor to avoid copying the functor into the queue, tbb::concurrent_queue does not support move semantics. - auto task_adaptor = internal::make_move_on_copy(create_task(func)); + auto task_adaptor = make_move_on_copy(create_task(func)); auto future = task_adaptor.value.get_future(); @@ -198,7 +182,7 @@ public: auto try_begin_invoke(Func&& func, task_priority priority = normal_priority) -> boost::unique_future // noexcept { // Create a move on copy adaptor to avoid copying the functor into the queue, tbb::concurrent_queue does not support move semantics. - auto task_adaptor = internal::make_move_on_copy(create_task(func)); + auto task_adaptor = make_move_on_copy(create_task(func)); auto future = task_adaptor.value.get_future(); diff --git a/common/utility/move_on_copy.h b/common/utility/move_on_copy.h new file mode 100644 index 000000000..99774d192 --- /dev/null +++ b/common/utility/move_on_copy.h @@ -0,0 +1,19 @@ +#pragma once + +namespace caspar { + +template +struct move_on_copy +{ + move_on_copy(const move_on_copy& other) : value(std::move(other.value)){} + move_on_copy(T&& value) : value(std::move(value)){} + mutable T value; +}; + +template +move_on_copy make_move_on_copy(T&& value) +{ + return move_on_copy(std::move(value)); +} + +} \ No newline at end of file diff --git a/core/mixer/image/image_kernel.h b/core/mixer/image/image_kernel.h index 2e6051fef..2af0d5bcf 100644 --- a/core/mixer/image/image_kernel.h +++ b/core/mixer/image/image_kernel.h @@ -39,6 +39,8 @@ struct render_item std::vector> textures; frame_transform transform; blend_mode::type blend_mode; + + render_item() : blend_mode(blend_mode::normal){} }; bool operator==(const render_item& lhs, const render_item& rhs); diff --git a/core/mixer/image/image_mixer.cpp b/core/mixer/image/image_mixer.cpp index eda73da2f..941e28d6c 100644 --- a/core/mixer/image/image_mixer.cpp +++ b/core/mixer/image/image_mixer.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -46,7 +47,15 @@ using namespace boost::assign; namespace caspar { namespace core { -typedef std::deque layer; +struct layer +{ + std::vector items; + blend_mode::type blend_mode; + + layer(blend_mode::type blend_mode) : blend_mode(blend_mode) + { + } +}; class image_renderer { @@ -59,17 +68,17 @@ public: { } - boost::unique_future> render(std::deque&& layers) + boost::unique_future> render(std::vector&& layers) { - auto layers2 = std::move(layers); - return channel_.ogl().begin_invoke([=]() mutable + auto layers2 = make_move_on_copy(std::move(layers)); + return channel_.ogl().begin_invoke([=] { - return do_render(std::move(layers2)); + return do_render(std::move(layers2.value)); }); } private: - safe_ptr do_render(std::deque&& layers) + safe_ptr do_render(std::vector&& layers) { std::shared_ptr layer_key_buffer; @@ -91,34 +100,30 @@ private: void draw_layer(layer&& layer, const safe_ptr& draw_buffer, std::shared_ptr& layer_key_buffer) { - if(layer.empty()) + if(layer.items.empty()) return; std::pair> local_key_buffer = std::make_pair(0, nullptr); // int is fields flag - if(layer.front().blend_mode != blend_mode::normal && has_overlapping_items(layer)) + if(layer.blend_mode != blend_mode::normal && has_overlapping_items(layer)) { auto layer_draw_buffer = create_device_buffer(4); // int is fields flag - auto layer_blend_mode = layer.front().blend_mode; - BOOST_FOREACH(auto& item, layer) - { - item.blend_mode = blend_mode::normal; // Disable blending and just merge. + BOOST_FOREACH(auto& item, layer.items) draw_item(std::move(item), *layer_draw_buffer, local_key_buffer, layer_key_buffer); - } - + render_item item; item.pix_desc.pix_fmt = pixel_format::bgra; item.pix_desc.planes = list_of(pixel_format_desc::plane(channel_.get_format_desc().width, channel_.get_format_desc().height, 4)); item.textures = list_of(layer_draw_buffer); item.transform = frame_transform(); - item.blend_mode = layer_blend_mode; + item.blend_mode = layer.blend_mode; kernel_.draw(channel_.ogl(), std::move(item), *draw_buffer, nullptr, nullptr); } else // fast path { - BOOST_FOREACH(auto& item, layer) + BOOST_FOREACH(auto& item, layer.items) draw_item(std::move(item), *draw_buffer, local_key_buffer, layer_key_buffer); } @@ -158,12 +163,12 @@ private: bool has_overlapping_items(const layer& layer) { - auto upper_count = boost::range::count_if(layer, [&](const render_item& item) + auto upper_count = boost::range::count_if(layer.items, [&](const render_item& item) { return !item.transform.is_key && (item.transform.field_mode & field_mode::upper); }); - auto lower_count = boost::range::count_if(layer, [&](const render_item& item) + auto lower_count = boost::range::count_if(layer.items, [&](const render_item& item) { return !item.transform.is_key && (item.transform.field_mode & field_mode::lower); }); @@ -182,24 +187,21 @@ private: struct image_mixer::implementation : boost::noncopyable { - ogl_device& ogl_; - image_renderer renderer_; - std::vector transform_stack_; - blend_mode::type active_blend_mode_; - std::deque> layers_; // layer/stream/items + ogl_device& ogl_; + image_renderer renderer_; + std::vector transform_stack_; + std::vector layers_; // layer/stream/items public: implementation(video_channel_context& video_channel) : ogl_(video_channel.ogl()) , renderer_(video_channel) - , transform_stack_(1) - , active_blend_mode_(blend_mode::normal) + , transform_stack_(1) { } void begin_layer(blend_mode::type blend_mode) { - active_blend_mode_ = blend_mode; - layers_ += layer(); + layers_.push_back(layer(blend_mode)); } void begin(core::basic_frame& frame) @@ -216,9 +218,8 @@ public: item.pix_desc = frame.get_pixel_format_desc(); item.textures = frame.get_textures(); item.transform = transform_stack_.back(); - item.blend_mode = active_blend_mode_; - layers_.back() += item; + layers_.back().items.push_back(item); } void end() diff --git a/core/producer/frame_producer.cpp b/core/producer/frame_producer.cpp index f881d2adb..a17fa10ba 100644 --- a/core/producer/frame_producer.cpp +++ b/core/producer/frame_producer.cpp @@ -28,11 +28,55 @@ #include "separated/separated_producer.h" #include +#include #include +#include namespace caspar { namespace core { std::vector g_factories; + +class destroy_producer_proxy : public frame_producer +{ + safe_ptr producer_; + executor& destroy_context_; +public: + destroy_producer_proxy(executor& destroy_context, const safe_ptr& producer) + : producer_(producer) + , destroy_context_(destroy_context){} + + ~destroy_producer_proxy() + { + if(destroy_context_.size() > 4) + CASPAR_LOG(error) << L" Potential destroyer deadlock."; + + // Hacks to bypass compiler bugs. + auto mov_producer = make_move_on_copy>(std::move(producer_)); + auto empty_producer = frame_producer::empty(); + destroy_context_.begin_invoke([=] + { + if(!mov_producer.value.unique()) + CASPAR_LOG(debug) << mov_producer.value->print() << L" Not destroyed on safe asynchronous destruction thread."; + else + CASPAR_LOG(debug) << mov_producer.value->print() << L" Destroying on safe asynchronous destruction thread."; + + mov_producer.value = empty_producer; + }); + } + + virtual safe_ptr receive(int hints) {return producer_->receive(hints);} + virtual safe_ptr last_frame() const {return producer_->last_frame();} + virtual std::wstring print() const {return producer_->print();} + virtual void param(const std::wstring& str) {producer_->param(str);} + virtual safe_ptr get_following_producer() const {return producer_->get_following_producer();} + virtual void set_leading_producer(const safe_ptr& producer) {producer_->set_leading_producer(producer);} + virtual int64_t nb_frames() const {return producer_->nb_frames();} +}; + +safe_ptr create_destroy_producer_proxy(executor& destroy_context, const safe_ptr& producer) +{ + return make_safe(destroy_context, producer); +} class last_frame_producer : public frame_producer { diff --git a/core/producer/frame_producer.h b/core/producer/frame_producer.h index d2b1becdf..830461d5b 100644 --- a/core/producer/frame_producer.h +++ b/core/producer/frame_producer.h @@ -29,7 +29,11 @@ #include #include -namespace caspar { namespace core { +namespace caspar { + +class executor; + +namespace core { class basic_frame; struct frame_factory; @@ -66,5 +70,6 @@ typedef std::function(const safe_ptr create_producer(const safe_ptr&, const std::vector& params); +safe_ptr create_destroy_producer_proxy(executor& destroy_context, const safe_ptr& producer); }} diff --git a/core/producer/stage.cpp b/core/producer/stage.cpp index 6c7816ba9..9fe30bbd4 100644 --- a/core/producer/stage.cpp +++ b/core/producer/stage.cpp @@ -30,6 +30,7 @@ #include #include +#include #include @@ -39,40 +40,6 @@ #include namespace caspar { namespace core { - -void destroy_producer(safe_ptr& producer) -{ - if(!producer.unique()) - CASPAR_LOG(debug) << producer->print() << L" Not destroyed on safe asynchronous destruction thread."; - - producer = frame_producer::empty(); -} - -class destroy_producer_proxy : public frame_producer -{ - safe_ptr producer_; - executor& destroy_context_; -public: - destroy_producer_proxy(executor& destroy_context, const safe_ptr& producer) - : producer_(producer) - , destroy_context_(destroy_context){} - - ~destroy_producer_proxy() - { - if(destroy_context_.size() > 4) - CASPAR_LOG(error) << L" Potential destroyer deadlock."; - - destroy_context_.begin_invoke(std::bind(&destroy_producer, std::move(producer_))); - } - - virtual safe_ptr receive(int hints) {return producer_->receive(hints);} - virtual safe_ptr last_frame() const {return producer_->last_frame();} - virtual std::wstring print() const {return producer_->print();} - virtual void param(const std::wstring& str) {producer_->param(str);} - virtual safe_ptr get_following_producer() const {return producer_->get_following_producer();} - virtual void set_leading_producer(const safe_ptr& producer) {producer_->set_leading_producer(producer);} - virtual int64_t nb_frames() const {return producer_->nb_frames();} -}; struct stage::implementation : boost::noncopyable { @@ -111,7 +78,7 @@ public: { channel_.execution().invoke([&] { - layers_[index].load(make_safe(channel_.destruction(), producer), preview, auto_play_delta); + layers_[index].load(create_destroy_producer_proxy(channel_.destruction(), producer), preview, auto_play_delta); }, high_priority); } diff --git a/core/video_channel.cpp b/core/video_channel.cpp index c1a37a78f..267a821db 100644 --- a/core/video_channel.cpp +++ b/core/video_channel.cpp @@ -32,6 +32,8 @@ #include #include +#include "mixer/gpu/ogl_device.h" + #include #ifdef _MSC_VER @@ -151,5 +153,6 @@ safe_ptr video_channel::output() { return impl_->output_;} video_format_desc video_channel::get_video_format_desc() const{return impl_->context_.get_format_desc();} void video_channel::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);} std::wstring video_channel::print() const { return impl_->print();} +video_channel_context& video_channel::context(){return impl_->context_;} }} \ No newline at end of file diff --git a/core/video_channel.h b/core/video_channel.h index 2ca9c674c..7a0225b6b 100644 --- a/core/video_channel.h +++ b/core/video_channel.h @@ -31,6 +31,7 @@ class mixer; class output; class ogl_device; struct video_format_desc; +class video_channel_context; class video_channel : boost::noncopyable { @@ -42,6 +43,8 @@ public: safe_ptr mixer(); safe_ptr output(); + video_channel_context& context(); + video_format_desc get_video_format_desc() const; void set_video_format_desc(const video_format_desc& format_desc); diff --git a/core/video_channel_context.cpp b/core/video_channel_context.cpp index 677c1180e..84806b2a3 100644 --- a/core/video_channel_context.cpp +++ b/core/video_channel_context.cpp @@ -4,38 +4,58 @@ namespace caspar { namespace core { +struct video_channel_context::implementation +{ + mutable tbb::spin_rw_mutex mutex_; + const int index_; + video_format_desc format_desc_; + executor execution_; + executor destruction_; + ogl_device& ogl_; + + implementation(int index, ogl_device& ogl, const video_format_desc& format_desc) + : index_(index) + , format_desc_(format_desc) + , execution_(print() + L"/execution") + , destruction_(print() + L"/destruction") + , ogl_(ogl) + { + execution_.set_priority_class(above_normal_priority_class); + destruction_.set_priority_class(below_normal_priority_class); + } + + std::wstring print() const + { + return L"video_channel[" + boost::lexical_cast(index_+1) + L"|" + format_desc_.name + L"]"; + } +}; + video_channel_context::video_channel_context(int index, ogl_device& ogl, const video_format_desc& format_desc) - : index_(index) - , format_desc_(format_desc) - , execution_(print() + L"/execution") - , destruction_(print() + L"/destruction") - , ogl_(ogl) + : impl_(new implementation(index, ogl, format_desc)) { - execution_.set_priority_class(above_normal_priority_class); - destruction_.set_priority_class(below_normal_priority_class); } -const int video_channel_context::index() const {return index_;} +const int video_channel_context::index() const {return impl_->index_;} video_format_desc video_channel_context::get_format_desc() { - tbb::spin_rw_mutex::scoped_lock lock(mutex_, false); - return format_desc_; + tbb::spin_rw_mutex::scoped_lock lock(impl_->mutex_, false); + return impl_->format_desc_; } void video_channel_context::set_format_desc(const video_format_desc& format_desc) { - tbb::spin_rw_mutex::scoped_lock lock(mutex_, true); - format_desc_ = format_desc; + tbb::spin_rw_mutex::scoped_lock lock(impl_->mutex_, true); + impl_->format_desc_ = format_desc; } -executor& video_channel_context::execution() {return execution_;} -executor& video_channel_context::destruction() {return destruction_;} -ogl_device& video_channel_context::ogl() { return ogl_;} +executor& video_channel_context::execution() {return impl_->execution_;} +executor& video_channel_context::destruction() {return impl_->destruction_;} +ogl_device& video_channel_context::ogl() { return impl_->ogl_;} std::wstring video_channel_context::print() const { - return L"video_channel[" + boost::lexical_cast(index_+1) + L"|" + format_desc_.name + L"]"; + return impl_->print(); } }} \ No newline at end of file diff --git a/core/video_channel_context.h b/core/video_channel_context.h index f30799147..4c06e3a9f 100644 --- a/core/video_channel_context.h +++ b/core/video_channel_context.h @@ -2,7 +2,6 @@ #include -#include #include #include @@ -12,16 +11,16 @@ #include -namespace caspar { namespace core { +namespace caspar { + +class executor; + +namespace core { + +class ogl_device; class video_channel_context { - mutable tbb::spin_rw_mutex mutex_; - const int index_; - video_format_desc format_desc_; - executor execution_; - executor destruction_; - ogl_device& ogl_; public: video_channel_context(int index, ogl_device& ogl, const video_format_desc& format_desc); @@ -33,6 +32,9 @@ public: executor& destruction(); ogl_device& ogl(); std::wstring print() const; +private: + struct implementation; + std::shared_ptr impl_; }; }} \ No newline at end of file diff --git a/protocol/amcp/AMCPCommandsImpl.cpp b/protocol/amcp/AMCPCommandsImpl.cpp index 5eedd32f1..a5e1d8377 100644 --- a/protocol/amcp/AMCPCommandsImpl.cpp +++ b/protocol/amcp/AMCPCommandsImpl.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -649,7 +650,7 @@ bool LoadbgCommand::DoExecute() bool auto_play = std::find(_parameters.begin(), _parameters.end(), L"AUTO") != _parameters.end(); - auto pFP2 = create_transition_producer(GetChannel()->get_video_format_desc().field_mode, pFP, transitionInfo); + auto pFP2 = create_transition_producer(GetChannel()->get_video_format_desc().field_mode, create_destroy_producer_proxy(GetChannel()->context().destruction(), pFP), transitionInfo); GetChannel()->stage()->load(GetLayerIndex(), pFP2, false, auto_play ? transitionInfo.duration : -1); // TODO: LOOP CASPAR_LOG(info) << "Loaded " << _parameters[0] << TEXT(" successfully to background"); diff --git a/shell/casparcg.config b/shell/casparcg.config index 8e02dace4..ed235ac3c 100644 --- a/shell/casparcg.config +++ b/shell/casparcg.config @@ -1,7 +1,7 @@ - L:\casparcg\_media\ + C:\Lokala Filer\server\branches\2.0.0.2\bin\_media\ L:\casparcg\_log\ L:\casparcg\_data\ L:\casparcg\_templates\ @@ -49,14 +49,9 @@ - 720p5000 + PAL - - 1 - true - - 1