summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2015-06-23 14:26:10 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2015-06-23 14:26:26 -0400
commite9224a58d187a8fc403ffff904648d28f5045d69 (patch)
treea35d785f7b9906b7d8c2ff6149c218cca524701b
parent2cb511e25a94b881a43e4e35972c247d9ad3930b (diff)
several changes, major and minor, to improve threaded waveview rendering
-rw-r--r--libs/canvas/canvas/wave_view.h4
-rw-r--r--libs/canvas/wave_view.cc113
-rw-r--r--libs/canvas/wscript2
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