X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=decklink_output.cpp;h=2285bb2a7ceed3b7ac1237224447f8c70ce78380;hb=4db1223f01b0d1731ff571f20c677a7675b645ec;hp=17cc520d25964fca766d511fd653ef8c2e68b2d1;hpb=dccb8335c91044493b7d6b236892feef655abf1e;p=nageru diff --git a/decklink_output.cpp b/decklink_output.cpp index 17cc520..2285bb2 100644 --- a/decklink_output.cpp +++ b/decklink_output.cpp @@ -2,6 +2,9 @@ #include #include // Must be above the Xlib includes. #include +#include + +#include #include @@ -9,6 +12,7 @@ #include "decklink_output.h" #include "decklink_util.h" #include "flags.h" +#include "metrics.h" #include "print_latency.h" #include "timebase.h" #include "v210_converter.h" @@ -20,7 +24,7 @@ using namespace std::chrono; namespace { // This class can be deleted during regular use, so make all the metrics static. -bool metrics_inited = false; +once_flag decklink_metrics_inited; LatencyHistogram latency_histogram; atomic metric_decklink_output_width_pixels{-1}; atomic metric_decklink_output_height_pixels{-1}; @@ -42,6 +46,8 @@ atomic metric_decklink_output_completed_frames_unknown{0}; atomic metric_decklink_output_scheduled_samples{0}; +Summary metric_decklink_output_margin_seconds; + } // namespace DeckLinkOutput::DeckLinkOutput(ResourcePool *resource_pool, QSurface *surface, unsigned width, unsigned height, unsigned card_index) @@ -49,7 +55,7 @@ DeckLinkOutput::DeckLinkOutput(ResourcePool *resource_pool, QSurface *surface, u { chroma_subsampler.reset(new ChromaSubsampler(resource_pool)); - if (!metrics_inited) { + call_once(decklink_metrics_inited, [](){ latency_histogram.init("decklink_output"); global_metrics.add("decklink_output_width_pixels", &metric_decklink_output_width_pixels, Metrics::TYPE_GAUGE); global_metrics.add("decklink_output_height_pixels", &metric_decklink_output_height_pixels, Metrics::TYPE_GAUGE); @@ -70,9 +76,10 @@ DeckLinkOutput::DeckLinkOutput(ResourcePool *resource_pool, QSurface *surface, u global_metrics.add("decklink_output_completed_frames", {{ "status", "unknown" }}, &metric_decklink_output_completed_frames_unknown); global_metrics.add("decklink_output_scheduled_samples", &metric_decklink_output_scheduled_samples); - - metrics_inited = true; - } + vector quantiles{0.01, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99}; + metric_decklink_output_margin_seconds.init(quantiles, 60.0); + global_metrics.add("decklink_output_margin_seconds", &metric_decklink_output_margin_seconds); + }); } void DeckLinkOutput::set_device(IDeckLink *decklink) @@ -262,7 +269,7 @@ void DeckLinkOutput::send_frame(GLuint y_tex, GLuint cbcr_tex, YCbCrLumaCoeffici last_frame_had_mode_mismatch = false; } - unique_ptr frame = move(get_frame()); + unique_ptr frame = get_frame(); if (global_flags.ten_bit_output) { chroma_subsampler->create_v210(y_tex, cbcr_tex, width, height, frame->uyvy_tex); } else { @@ -372,6 +379,9 @@ void DeckLinkOutput::wait_for_frame(int64_t pts, int *dropped_frames, int64_t *f *frame_timestamp = steady_clock::now() + nanoseconds((target_time - stream_frame_time) * 1000000000 / TIMEBASE); + metric_decklink_output_margin_seconds.count_event( + (target_time - stream_frame_time) / double(TIMEBASE)); + // If we're ahead of time, wait for the frame to (approximately) start. if (stream_frame_time < target_time) { should_quit.sleep_until(*frame_timestamp); @@ -543,7 +553,15 @@ void DeckLinkOutput::present_thread_func() ++metric_decklink_output_inflight_frames; } - glClientWaitSync(frame->fence.get(), /*flags=*/0, GL_TIMEOUT_IGNORED); + for ( ;; ) { + int err = glClientWaitSync(frame->fence.get(), /*flags=*/0, 0); + if (err == GL_TIMEOUT_EXPIRED) { + // NVIDIA likes to busy-wait; yield instead. + this_thread::sleep_for(milliseconds(1)); + } else { + break; + } + } check_error(); frame->fence.reset();