diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2015-06-23 14:26:10 -0400 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2015-06-23 14:26:26 -0400 |
commit | e9224a58d187a8fc403ffff904648d28f5045d69 (patch) | |
tree | a35d785f7b9906b7d8c2ff6149c218cca524701b /libs | |
parent | 2cb511e25a94b881a43e4e35972c247d9ad3930b (diff) |
several changes, major and minor, to improve threaded waveview rendering
Diffstat (limited to 'libs')
-rw-r--r-- | libs/canvas/canvas/wave_view.h | 4 | ||||
-rw-r--r-- | libs/canvas/wave_view.cc | 113 | ||||
-rw-r--r-- | libs/canvas/wscript | 2 |
3 files changed, 70 insertions, 49 deletions
diff --git a/libs/canvas/canvas/wave_view.h b/libs/canvas/canvas/wave_view.h index dc3fe4e13c..c4e19ec7bb 100644 --- a/libs/canvas/canvas/wave_view.h +++ b/libs/canvas/canvas/wave_view.h @@ -311,7 +311,6 @@ public: double _amplitude_above_axis; float _region_amplitude; double _start_shift; - mutable bool idle_queued; /** The `start' value to use for the region; we can't use the region's * value as the crossfade editor needs to alter it. @@ -378,6 +377,8 @@ public: ArdourCanvas::Coord y_extent (double) const; void compute_tips (ARDOUR::PeakData const & peak, LineTips& tips) const; + ARDOUR::framecnt_t desired_image_width () const; + void draw_image (Cairo::RefPtr<Cairo::ImageSurface>&, ARDOUR::PeakData*, int n_peaks, boost::shared_ptr<WaveViewThreadRequest>) const; void draw_absent_image (Cairo::RefPtr<Cairo::ImageSurface>&, ARDOUR::PeakData*, int) const; @@ -392,7 +393,6 @@ public: mutable boost::shared_ptr<WaveViewCache::Entry> _current_image; mutable boost::shared_ptr<WaveViewThreadRequest> current_request; - bool idle_send_request () const; static WaveViewCache* images; diff --git a/libs/canvas/wave_view.cc b/libs/canvas/wave_view.cc index 3a04961d12..7b00b0eae7 100644 --- a/libs/canvas/wave_view.cc +++ b/libs/canvas/wave_view.cc @@ -37,6 +37,7 @@ #include "ardour/lmath.h" #include "ardour/audioregion.h" #include "ardour/audiosource.h" +#include "ardour/session.h" #include "canvas/canvas.h" #include "canvas/colors.h" @@ -44,6 +45,8 @@ #include "canvas/utils.h" #include "canvas/wave_view.h" +#include "evoral/Range.hpp" + #include <gdkmm/general.h> #include "gtkmm2ext/gui_thread.h" @@ -87,7 +90,6 @@ WaveView::WaveView (Canvas* c, boost::shared_ptr<ARDOUR::AudioRegion> region) , _amplitude_above_axis (1.0) , _region_amplitude (region->scale_amplitude ()) , _start_shift (0.0) - , idle_queued (false) , _region_start (region->start()) , get_image_in_thread (false) , always_get_image_in_thread (false) @@ -121,7 +123,6 @@ WaveView::WaveView (Item* parent, boost::shared_ptr<ARDOUR::AudioRegion> region) , _amplitude_above_axis (1.0) , _region_amplitude (region->scale_amplitude ()) , _start_shift (0.0) - , idle_queued (false) , _region_start (region->start()) , get_image_in_thread (false) , always_get_image_in_thread (false) @@ -151,6 +152,7 @@ WaveView::debug_name() const void WaveView::image_ready () { + DEBUG_TRACE (DEBUG::WaveView, string_compose ("queue draw for %1 at %2 (vis = %3 bbox = %4 CR %5)\n", this, g_get_monotonic_time(), visible(), _bounding_box, current_request)); redraw (); } @@ -256,6 +258,7 @@ WaveView::set_clip_level (double dB) void WaveView::invalidate_image_cache () { + DEBUG_TRACE (DEBUG::WaveView, string_compose ("%1 invalidates image cache and cancels current request\n", this)); cancel_my_render_request (); _current_image.reset (); } @@ -766,6 +769,10 @@ WaveView::get_image (framepos_t start, framepos_t end, bool& full_image) const * have an image there. if so, use it (and put it in the cache * while we're here. */ + + DEBUG_TRACE (DEBUG::WaveView, string_compose ("%1 CR %2 stop? %3 image %4\n", this, current_request, + (current_request ? current_request->should_stop() : false), + (current_request ? current_request->image : 0))); if (current_request && !current_request->should_stop() && current_request->image) { @@ -809,7 +816,7 @@ WaveView::get_image (framepos_t start, framepos_t end, bool& full_image) const if (!ret || !full_image) { if ((rendered && get_image_in_thread) || always_get_image_in_thread) { - + DEBUG_TRACE (DEBUG::WaveView, string_compose ("%1: generating image in caller thread\n", name)); boost::shared_ptr<WaveViewThreadRequest> req (new WaveViewThreadRequest); @@ -820,10 +827,10 @@ WaveView::get_image (framepos_t start, framepos_t end, bool& full_image) const req->samples_per_pixel = _samples_per_pixel; req->region = _region; /* weak ptr, to avoid storing a reference in the request queue */ req->channel = _channel; - req->width = _canvas->visible_area().width(); req->height = _height; req->fill_color = _fill_color; req->amplitude = _region_amplitude * _amplitude_above_axis; + req->width = desired_image_width (); /* draw image in this (the GUI thread) */ @@ -864,6 +871,26 @@ WaveView::get_image_from_cache (framepos_t start, framepos_t end, bool& full) co _height, _region_amplitude * _amplitude_above_axis, _fill_color, _samples_per_pixel, full); } +framecnt_t +WaveView::desired_image_width () const +{ + /* compute how wide the image should be, in samples. + * + * We want at least 1 canvas width's worth, but if that + * represents less than 1/10th of a second, use 1/10th of + * a second instead. + */ + + framecnt_t canvas_width_samples = _canvas->visible_area().width() * _samples_per_pixel; + const framecnt_t one_tenth_of_second = _region->session().frame_rate() / 10; + + if (canvas_width_samples > one_tenth_of_second) { + return canvas_width_samples; + } + + return one_tenth_of_second; +} + void WaveView::queue_get_image (boost::shared_ptr<const ARDOUR::Region> region, framepos_t start, framepos_t end) const { @@ -875,10 +902,10 @@ WaveView::queue_get_image (boost::shared_ptr<const ARDOUR::Region> region, frame req->samples_per_pixel = _samples_per_pixel; req->region = _region; /* weak ptr, to avoid storing a reference in the request queue */ req->channel = _channel; - req->width = _canvas->visible_area().width(); req->height = _height; req->fill_color = _fill_color; req->amplitude = _region_amplitude * _amplitude_above_axis; + req->width = desired_image_width (); if (current_request) { /* this will stop rendering in progress (which might otherwise @@ -894,44 +921,31 @@ WaveView::queue_get_image (boost::shared_ptr<const ARDOUR::Region> region, frame { Glib::Threads::Mutex::Lock lm (request_queue_lock); current_request = req; - } - /* this is always called from the GUI thread (there is only one), and - * the same thread runs the idle callback chain. thus we do not need - * any locks to protect idle_queued - it is only ever set or read in - * the unitary GUI thread. - */ - - if (!idle_queued) { - Glib::signal_idle().connect (sigc::mem_fun (*this, &WaveView::idle_send_request)); - idle_queued = true; - } -} + DEBUG_TRACE (DEBUG::WaveView, string_compose ("%1 now has current request %2\n", this, req)); -bool -WaveView::idle_send_request () const -{ - Glib::Threads::Mutex::Lock lm (request_queue_lock); - - request_queue.insert (this); - request_cond.signal (); /* wake thread - must be done while holding lock */ - idle_queued = false; - - return false; /* do not call from idle again */ + if (request_queue.insert (this).second) { + /* this waveview was not already in the request queue, make sure we wake + the rendering thread in case it is asleep. + */ + request_cond.signal (); + } + } } - void WaveView::generate_image (boost::shared_ptr<WaveViewThreadRequest> req, bool in_render_thread) const { if (!req->should_stop()) { /* sample position is canonical here, and we want to generate - * an image that spans about twice the canvas width + * an image that spans about 3x the canvas width. We get to that + * width by using an image sample count of the screen width added + * on each side of the desired image center. */ const framepos_t center = req->start + ((req->end - req->start) / 2); - const framecnt_t image_samples = req->width * req->samples_per_pixel; /* one canvas width */ + const framecnt_t image_samples = req->width; /* we can request data from anywhere in the Source, between 0 and its length */ @@ -973,6 +987,7 @@ WaveView::generate_image (boost::shared_ptr<WaveViewThreadRequest> req, bool in_ } if (in_render_thread && !req->should_stop()) { + DEBUG_TRACE (DEBUG::WaveView, string_compose ("done with request for %1 at %2 CR %3 req %4 range %5 .. %6\n", this, g_get_monotonic_time(), current_request, req, req->start, req->end)); const_cast<WaveView*>(this)->ImageReady (); /* emit signal */ } @@ -1002,6 +1017,8 @@ WaveView::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) cons return; } + DEBUG_TRACE (DEBUG::WaveView, string_compose ("render %1 at %2\n", this, g_get_monotonic_time())); + /* a WaveView is intimately connected to an AudioRegion. It will * display the waveform within the region, anywhere from the start of * the region to its end. @@ -1428,6 +1445,8 @@ WaveView::cancel_my_render_request () const request_queue.erase (this); current_request.reset (); + DEBUG_TRACE (DEBUG::WaveView, string_compose ("%1 now has no request %2\n", this)); + } void @@ -1488,6 +1507,8 @@ WaveView::drawing_thread () requestor = *(request_queue.begin()); request_queue.erase (request_queue.begin()); + DEBUG_TRACE (DEBUG::WaveView, string_compose ("start request for %1 at %2\n", requestor, g_get_monotonic_time())); + boost::shared_ptr<WaveViewThreadRequest> req = requestor->current_request; if (!req) { @@ -1565,25 +1586,25 @@ WaveViewCache::lookup_image (boost::shared_ptr<ARDOUR::AudioSource> src, continue; } - if (end <= e->end && start >= e->start) { - /* found an image that covers the range we need */ + switch (Evoral::coverage (start, end, e->start, e->end)) { + case Evoral::OverlapExternal: /* required range is inside image range */ DEBUG_TRACE (DEBUG::WaveView, string_compose ("found image spanning %1..%2 covers %3..%4\n", e->start, e->end, start, end)); use (src, e); - full_coverage = true; - return e; - } - - if (start >= e->start) { - /* found an image that covers the start, but not the - * end. See if it is longer than any other similar - * partial image that we've found so far. - */ - - if ((e->end - e->start) > max_coverage) { - best_partial = e; - max_coverage = e->end - e->start; - } + full_coverage = true; + return e; + + case Evoral::OverlapStart: /* required range start is covered by image range */ + if ((e->end - start) > max_coverage) { + best_partial = e; + max_coverage = e->end - start; + } + break; + + case Evoral::OverlapNone: + case Evoral::OverlapEnd: + case Evoral::OverlapInternal: + break; } } diff --git a/libs/canvas/wscript b/libs/canvas/wscript index 2c4cca850e..3d741ec924 100644 --- a/libs/canvas/wscript +++ b/libs/canvas/wscript @@ -84,7 +84,7 @@ def build(bld): obj.export_includes = ['.'] obj.includes = ['.'] obj.uselib = 'SIGCPP CAIROMM GTKMM BOOST' - obj.use = [ 'libpbd', 'libevoral', 'libardour', 'libgtkmm2ext' ] + obj.use = [ 'libpbd', 'libevoral', 'libardour', 'libgtkmm2ext', 'libevoral' ] obj.name = 'libcanvas' obj.target = 'canvas' obj.vnum = CANVAS_LIB_VERSION |