From: Helge Norberg Date: Fri, 8 Jan 2016 15:32:26 +0000 (+0100) Subject: Only memcpy on Linux if the decklink card will attempt DMA directly from BGRA buffer... X-Git-Tag: 2.1.0_Beta1~119 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=6776e8b21aceff166bd3a0d6141fd4b1edd136f1;p=casparcg Only memcpy on Linux if the decklink card will attempt DMA directly from BGRA buffer to card. This only happens on cards with hardware support for BGRA, otherwise the driver will convert it to an YCbCr buffer before transfering to card, in which case it is an unnecessary extra copy. --- diff --git a/modules/decklink/consumer/decklink_consumer.cpp b/modules/decklink/consumer/decklink_consumer.cpp index 58a53e658..c8492e653 100644 --- a/modules/decklink/consumer/decklink_consumer.cpp +++ b/modules/decklink/consumer/decklink_consumer.cpp @@ -175,14 +175,23 @@ class decklink_frame : public IDeckLinkVideoFrame const core::video_format_desc format_desc_; const bool key_only_; + bool needs_to_copy_; cache_aligned_vector> data_; public: - decklink_frame(core::const_frame frame, const core::video_format_desc& format_desc, bool key_only) + decklink_frame(core::const_frame frame, const core::video_format_desc& format_desc, bool key_only, bool will_attempt_dma) : frame_(frame) , format_desc_(format_desc) , key_only_(key_only) { ref_count_ = 0; + +#if !defined(_MSC_VER) + // On Linux Decklink cannot DMA transfer from memory returned by glMapBuffer + needs_to_copy_ = will_attempt_dma; +#else + // On Windows it does + needs_to_copy_ = false; +#endif } // IUnknown @@ -234,12 +243,12 @@ public: { *buffer = const_cast(frame_.image_data().begin()); -#if !defined(_MSC_VER) - // On Linux Decklink cannot DMA transfer from memory returned by glMapBuffer - data_.resize(frame_.image_data().size()); - fast_memcpy(data_.data(), *buffer, frame_.image_data().size()); - *buffer = data_.data(); -#endif + if (needs_to_copy_) + { + data_.resize(frame_.image_data().size()); + fast_memcpy(data_.data(), *buffer, frame_.image_data().size()); + *buffer = data_.data(); + } } } catch(...) @@ -354,6 +363,7 @@ struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLink tbb::atomic is_running_; const std::wstring model_name_ = get_model_name(decklink_); + bool will_attempt_dma_; const core::video_format_desc format_desc_; const core::audio_channel_layout in_channel_layout_; const core::audio_channel_layout out_channel_layout_ = config_.get_adjusted_layout(in_channel_layout_); @@ -418,7 +428,7 @@ public: graph_->set_text(print()); diagnostics::register_graph(graph_); - enable_video(get_display_mode(output_, format_desc_.format, bmdFormat8BitBGRA, bmdVideoOutputFlagDefault)); + enable_video(get_display_mode(output_, format_desc_.format, bmdFormat8BitBGRA, bmdVideoOutputFlagDefault, will_attempt_dma_)); if(config.embedded_audio) enable_audio(); @@ -611,12 +621,12 @@ public: { if (key_context_) { - auto key_frame = wrap_raw(new decklink_frame(frame, format_desc_, true)); + auto key_frame = wrap_raw(new decklink_frame(frame, format_desc_, true, will_attempt_dma_)); if (FAILED(key_context_->output_->ScheduleVideoFrame(get_raw(key_frame), video_scheduled_, format_desc_.duration, format_desc_.time_scale))) CASPAR_LOG(error) << print() << L" Failed to schedule key video."; } - auto fill_frame = wrap_raw(new decklink_frame(frame, format_desc_, config_.key_only)); + auto fill_frame = wrap_raw(new decklink_frame(frame, format_desc_, config_.key_only, will_attempt_dma_)); if (FAILED(output_->ScheduleVideoFrame(get_raw(fill_frame), video_scheduled_, format_desc_.duration, format_desc_.time_scale))) CASPAR_LOG(error) << print() << L" Failed to schedule fill video."; diff --git a/modules/decklink/producer/decklink_producer.cpp b/modules/decklink/producer/decklink_producer.cpp index c099d8788..b64c97656 100644 --- a/modules/decklink/producer/decklink_producer.cpp +++ b/modules/decklink/producer/decklink_producer.cpp @@ -145,7 +145,8 @@ public: graph_->set_text(print()); diagnostics::register_graph(graph_); - auto display_mode = get_display_mode(input_, in_format_desc.format, bmdFormat8BitYUV, bmdVideoInputFlagDefault); + bool will_attempt_dma; + auto display_mode = get_display_mode(input_, in_format_desc.format, bmdFormat8BitYUV, bmdVideoInputFlagDefault, will_attempt_dma); // NOTE: bmdFormat8BitARGB is currently not supported by any decklink card. (2011-05-08) if(FAILED(input_->EnableVideoInput(display_mode, bmdFormat8BitYUV, 0))) diff --git a/modules/decklink/util/util.h b/modules/decklink/util/util.h index 1cfa95f59..e91a42e2b 100644 --- a/modules/decklink/util/util.h +++ b/modules/decklink/util/util.h @@ -115,8 +115,15 @@ static core::video_format get_caspar_video_format(BMDDisplayMode fmt) } } +static std::wstring get_mode_name(const com_ptr& mode) +{ + String mode_name; + mode->GetName(&mode_name); + return u16(mode_name); +} + template -BMDDisplayMode get_display_mode(const T& device, BMDDisplayMode format, BMDPixelFormat pix_fmt, F flag) +BMDDisplayMode get_display_mode(const T& device, BMDDisplayMode format, BMDPixelFormat pix_fmt, F flag, bool& will_attempt_dma) { IDeckLinkDisplayMode* m = nullptr; IDeckLinkDisplayModeIterator* iter; @@ -137,21 +144,24 @@ BMDDisplayMode get_display_mode(const T& device, BMDDisplayMode format, BMDPixel com_ptr mode = wrap_raw(m, true); BMDDisplayModeSupport displayModeSupport; - if(FAILED(device->DoesSupportVideoMode(mode->GetDisplayMode(), pix_fmt, flag, &displayModeSupport, nullptr)) || displayModeSupport == bmdDisplayModeNotSupported) - CASPAR_LOG(warning) << L"Device does not support video-format: " << mode->GetDisplayMode(); - //CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Device does not support requested video-format.") - // << arg_value_info(boost::lexical_cast(format)) - // << arg_name_info("format")); - else if(displayModeSupport == bmdDisplayModeSupportedWithConversion) - CASPAR_LOG(warning) << L"Device supports video-format with conversion: " << mode->GetDisplayMode(); + will_attempt_dma = false; + + if (FAILED(device->DoesSupportVideoMode(mode->GetDisplayMode(), pix_fmt, flag, &displayModeSupport, nullptr))) + CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(L"Could not determine whether device supports requested video format: " + get_mode_name(mode))); + else if (displayModeSupport == bmdDisplayModeNotSupported) + CASPAR_LOG(warning) << L"Device does not support video-format: " << get_mode_name(mode); + else if (displayModeSupport == bmdDisplayModeSupportedWithConversion) + CASPAR_LOG(warning) << L"Device supports video-format with conversion: " << get_mode_name(mode); + else + will_attempt_dma = true; return mode->GetDisplayMode(); } template -static BMDDisplayMode get_display_mode(const T& device, core::video_format fmt, BMDPixelFormat pix_fmt, F flag) +static BMDDisplayMode get_display_mode(const T& device, core::video_format fmt, BMDPixelFormat pix_fmt, F flag, bool& will_attempt_dma) { - return get_display_mode(device, get_decklink_video_format(fmt), pix_fmt, flag); + return get_display_mode(device, get_decklink_video_format(fmt), pix_fmt, flag, will_attempt_dma); } template