From: Helge Norberg Date: Thu, 29 Oct 2015 13:54:28 +0000 (+0100) Subject: * Absolutely *huge* performance improvement (or bugfix actually) in the rendering... X-Git-Tag: 2.1.0_Beta1~244 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=d258948302c84b792497f8382d2f3a7da0f02a13;p=casparcg * Absolutely *huge* performance improvement (or bugfix actually) in the rendering pipeline, allowing the next frame to be rendered immediately after the current frame has been *sent* to consumers, instead of *after* the consumers are ready for next frame. --- diff --git a/core/consumer/output.cpp b/core/consumer/output.cpp index bf274f163..5040caad0 100644 --- a/core/consumer/output.cpp +++ b/core/consumer/output.cpp @@ -160,21 +160,18 @@ public: .any(); } - void operator()(const_frame input_frame, const core::video_format_desc& format_desc, const core::audio_channel_layout& channel_layout) + std::future operator()(const_frame input_frame, const core::video_format_desc& format_desc, const core::audio_channel_layout& channel_layout) { - caspar::timer frame_timer; + spl::shared_ptr frame_timer; change_channel_format(format_desc, channel_layout); - executor_.invoke([=] - { - if(!has_synchronization_clock()) - sync_timer_.tick(1.0/format_desc_.fps); - - if(input_frame.size() != format_desc_.size) + auto pending_send_results = executor_.invoke([=]() -> std::shared_ptr>> + { + if (input_frame.size() != format_desc_.size) { CASPAR_LOG(debug) << print() << L" Invalid input frame dimension."; - return; + return nullptr; } auto minmax = minmax_buffer_depth(); @@ -182,23 +179,23 @@ public: frames_.set_capacity(std::max(2, minmax.second - minmax.first) + 1); // std::max(2, x) since we want to guarantee some pipeline depth for asycnhronous mixer read-back. frames_.push_back(input_frame); - if(!frames_.full()) - return; + if (!frames_.full()) + return nullptr; - std::map> send_results; + spl::shared_ptr>> send_results; // Start invocations for (auto it = ports_.begin(); it != ports_.end();) { - auto& port = it->second; + auto& port = it->second; auto depth = port.buffer_depth(); auto& frame = depth < 0 ? frames_.back() : frames_.at(depth - minmax.first); send_to_consumers_delays_[it->first] = frame.get_age_millis(); - + try { - send_results.insert(std::make_pair(it->first, port.send(frame))); + send_results->insert(std::make_pair(it->first, port.send(frame))); ++it; } catch (...) @@ -206,10 +203,10 @@ public: CASPAR_LOG_CURRENT_EXCEPTION(); try { - send_results.insert(std::make_pair(it->first, port.send(frame))); + send_results->insert(std::make_pair(it->first, port.send(frame))); ++it; } - catch(...) + catch (...) { CASPAR_LOG_CURRENT_EXCEPTION(); CASPAR_LOG(error) << "Failed to recover consumer: " << port.print() << L". Removing it."; @@ -219,8 +216,16 @@ public: } } + return send_results; + }); + + if (!pending_send_results) + return make_ready_future(); + + return executor_.begin_invoke([=]() + { // Retrieve results - for (auto it = send_results.begin(); it != send_results.end(); ++it) + for (auto it = pending_send_results->begin(); it != pending_send_results->end(); ++it) { try { @@ -237,13 +242,16 @@ public: ports_.erase(it->first); } } - }); - auto consume_time = frame_timer.elapsed(); - graph_->set_value("consume-time", consume_time * format_desc.fps * 0.5); - *monitor_subject_ - << monitor::message("/consume_time") % consume_time - << monitor::message("/profiler/time") % consume_time % (1.0 / format_desc.fps); + if (!has_synchronization_clock()) + sync_timer_.tick(1.0 / format_desc_.fps); + + auto consume_time = frame_timer->elapsed(); + graph_->set_value("consume-time", consume_time * format_desc.fps * 0.5); + *monitor_subject_ + << monitor::message("/consume_time") % consume_time + << monitor::message("/profiler/time") % consume_time % (1.0 / format_desc.fps); + }); } std::wstring print() const @@ -298,6 +306,6 @@ void output::remove(int index){impl_->remove(index);} void output::remove(const spl::shared_ptr& consumer){impl_->remove(consumer);} std::future output::info() const{return impl_->info();} std::future output::delay_info() const{ return impl_->delay_info(); } -void output::operator()(const_frame frame, const video_format_desc& format_desc, const core::audio_channel_layout& channel_layout){ (*impl_)(std::move(frame), format_desc, channel_layout); } +std::future output::operator()(const_frame frame, const video_format_desc& format_desc, const core::audio_channel_layout& channel_layout){ return (*impl_)(std::move(frame), format_desc, channel_layout); } monitor::subject& output::monitor_output() {return *impl_->monitor_subject_;} }} diff --git a/core/consumer/output.h b/core/consumer/output.h index 1f2d4e320..05a37681f 100644 --- a/core/consumer/output.h +++ b/core/consumer/output.h @@ -31,6 +31,8 @@ #include +#include + FORWARD2(caspar, diagnostics, class graph); namespace caspar { namespace core { @@ -49,7 +51,8 @@ public: // Methods - void operator()(const_frame frame, const video_format_desc& format_desc, const core::audio_channel_layout& channel_layout); + // Returns when submitted to consumers, but the future indicates when the consumers are ready for a new frame. + std::future operator()(const_frame frame, const video_format_desc& format_desc, const core::audio_channel_layout& channel_layout); void add(const spl::shared_ptr& consumer); void add(int index, const spl::shared_ptr& consumer); diff --git a/core/video_channel.cpp b/core/video_channel.cpp index 78520b060..445d612c9 100644 --- a/core/video_channel.cpp +++ b/core/video_channel.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -62,19 +63,20 @@ struct video_channel::impl final mutable tbb::spin_mutex channel_layout_mutex_; core::audio_channel_layout channel_layout_; - const spl::shared_ptr graph_ = [](int index) - { - core::diagnostics::scoped_call_context save; - core::diagnostics::call_context::for_thread().video_channel = index; - return spl::make_shared(); - }(index_); + const spl::shared_ptr graph_ = [](int index) + { + core::diagnostics::scoped_call_context save; + core::diagnostics::call_context::for_thread().video_channel = index; + return spl::make_shared(); + }(index_); caspar::core::output output_; + std::future output_ready_for_frame_ = make_ready_future(); spl::shared_ptr image_mixer_; caspar::core::mixer mixer_; caspar::core::stage stage_; - executor executor_ { L"video_channel " + boost::lexical_cast(index_) }; + executor executor_ { L"video_channel " + boost::lexical_cast(index_) }; public: impl( int index, @@ -162,8 +164,9 @@ public: auto mixed_frame = mixer_(std::move(stage_frames), format_desc, channel_layout); // Consume - - output_(std::move(mixed_frame), format_desc, channel_layout); + + output_ready_for_frame_.get(); + output_ready_for_frame_ = output_(std::move(mixed_frame), format_desc, channel_layout); auto frame_time = frame_timer.elapsed()*format_desc.fps*0.5; graph_->set_value("tick-time", frame_time);