13
0

Better line cache. Without a tempo change occurring, lines are never moved (except to 'steal' from outside the visible range).

Scrolling left now gets perfect cache hits as well as scrolling right, and steals minimally from the right.


git-svn-id: svn://localhost/ardour2/branches/3.0@3800 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2008-09-24 01:45:03 +00:00
parent 95d82d7a16
commit 91fea1066e

View File

@ -40,14 +40,15 @@ TempoLines::tempo_map_changed()
_clean_left = DBL_MAX;
_clean_right = 0.0;
size_t d = 0;
// TODO: Dirty/slow, but 'needed' for zoom :(
for (Lines::iterator i = _lines.begin(); i != _lines.end(); ) {
for (Lines::iterator i = _lines.begin(); i != _lines.end(); ++d) {
Lines::iterator next = i;
++next;
i->second->property_x1() = DBL_MAX;
i->second->property_x2() = DBL_MAX;
i->second->property_x1() = DBL_MAX - d;
i->second->property_x2() = DBL_MAX - d;
_lines.erase(i);
_lines.insert(make_pair(DBL_MAX, i->second));
_lines.insert(make_pair(DBL_MAX - d, i->second));
i = next;
}
}
@ -72,7 +73,7 @@ void
TempoLines::draw (ARDOUR::TempoMap::BBTPointList& points, double frames_per_unit)
{
ARDOUR::TempoMap::BBTPointList::iterator i;
ArdourCanvas::SimpleLine *line;
ArdourCanvas::SimpleLine *line = NULL;
gdouble xpos;
double who_cares;
double x1, x2, y1, y2, beat_density;
@ -112,17 +113,19 @@ TempoLines::draw (ARDOUR::TempoMap::BBTPointList& points, double frames_per_unit
bool exhausted = (left == _lines.end());
Lines::iterator li = left;
if (li != _lines.end())
line = li->second;
// Tempo map hasn't changed and we're entirely within a clean
// range, don't need to do anything. Yay.
if (needed_left >= _clean_left && needed_right <= _clean_right) {
//cout << "LINE CACHE PERFECT HIT!" << endl;
//cout << endl << "*** LINE CACHE PERFECT HIT" << endl;
return;
}
//cout << "LINE CACHE MISS :/" << endl;
//cout << endl << "*** LINE CACHE MISS" << endl;
bool inserted_last_time = false;
bool inserted_last_time = true;
bool invalidated = false;
for (i = points.begin(); i != points.end(); ++i) {
@ -132,29 +135,88 @@ TempoLines::draw (ARDOUR::TempoMap::BBTPointList& points, double frames_per_unit
break;
case ARDOUR::TempoMap::Beat:
if ((*i).beat == 1) {
color = ARDOUR_UI::config()->canvasvar_MeasureLineBar.get();
} else {
color = ARDOUR_UI::config()->canvasvar_MeasureLineBeat.get();
if (beat_density > 2.0) {
/* only draw beat lines if the gaps between beats are large. */
break;
break; /* only draw beat lines if the gaps between beats are large. */
}
}
xpos = rint(((nframes64_t)(*i).frame) / (double)frames_per_unit);
if (inserted_last_time) {
if (inserted_last_time && !_lines.empty()) {
li = _lines.lower_bound(xpos); // first line >= xpos
}
line = (li != _lines.end()) ? li->second : NULL;
assert(!line || line->property_x1() == li->first);
Lines::iterator next = li;
if (next != _lines.end())
++next;
exhausted = (next == _lines.end());
if (!exhausted) {
line = li->second;
exhausted = ((++li) == _lines.end());
inserted_last_time = false;
// Hooray, line is perfect
if (line && line->property_x1() == xpos) {
if (li != _lines.end())
++li;
line->property_color_rgba() = color;
inserted_last_time = false; // don't search next time
// Use existing line, moving if necessary
} else if (!exhausted) {
Lines::iterator steal = _lines.end();
--steal;
// Steal from the right
if (left->first > needed_left && li != steal && steal->first > needed_right) {
//cout << "*** STEALING FROM RIGHT" << endl;
line = steal->second;
_lines.erase(steal);
line->property_x1() = xpos;
line->property_x2() = xpos;
line->property_color_rgba() = color;
_lines.insert(make_pair(xpos, line));
inserted_last_time = true; // search next time
invalidated = true;
// Shift clean range left
_clean_left = min(_clean_left, xpos);
_clean_right = min(_clean_right, steal->first);
// Move this line to where we need it
} else {
Lines::iterator existing = _lines.find(xpos);
if (existing != _lines.end()) {
//cout << "*** EXISTING LINE" << endl;
li = existing;
li->second->property_color_rgba() = color;
inserted_last_time = false; // don't search next time
} else {
//cout << "*** MOVING LINE" << endl;
const double x1 = line->property_x1();
const bool was_clean = x1 >= _clean_left && x1 <= _clean_right;
invalidated = invalidated || was_clean;
// Invalidate clean portion (XXX: too harsh?)
_clean_left = needed_left;
_clean_right = needed_right;
_lines.erase(li);
line->property_color_rgba() = color;
line->property_x1() = xpos;
line->property_x2() = xpos;
_lines.insert(make_pair(xpos, line));
inserted_last_time = true; // search next time
}
}
// Create a new line
} else if (_lines.size() < needed || _lines.size() < MAX_CACHED_LINES) {
//cout << "*** CREATING LINE" << endl;
assert(_lines.find(xpos) == _lines.end());
line = new ArdourCanvas::SimpleLine (*_group);
line->property_x1() = xpos;
line->property_x2() = xpos;
@ -162,38 +224,32 @@ TempoLines::draw (ARDOUR::TempoMap::BBTPointList& points, double frames_per_unit
line->property_color_rgba() = color;
_lines.insert(make_pair(xpos, line));
inserted_last_time = true;
} else {
assert(li != _lines.begin());
line = _lines.begin()->second; // steal leftmost line
_lines.erase(_lines.begin());
_lines.insert(make_pair(xpos, line));
inserted_last_time = true;
invalidated = true;
}
/* At this point, line's key is correct, but actual pos may not be */
if (line->property_x1() != xpos) {
// Turn this on to see the case where this isn't quite ideal yet
// (scrolling left, lots of lines are moved left when there is
// likely to be a huge chunk with equivalent coords)
//cout << "MOVE " << line->property_x1() << " -> " << xpos << endl;
double x1 = line->property_x1();
bool was_clean = x1 >= _clean_left && x1 <= _clean_right;
invalidated = invalidated || was_clean;
// Steal from the left
} else {
//cout << "*** STEALING FROM LEFT" << endl;
assert(_lines.find(xpos) == _lines.end());
Lines::iterator steal = _lines.begin();
line = steal->second;
_lines.erase(steal);
line->property_color_rgba() = color;
line->property_x1() = xpos;
line->property_x2() = xpos;
line->property_y2() = y2;
line->property_color_rgba() = color;
_lines.insert(make_pair(xpos, line));
inserted_last_time = true; // search next time
invalidated = true;
// Shift clean range right
_clean_left = max(_clean_left, steal->first);
_clean_right = max(_clean_right, xpos);
}
break;
}
}
if (invalidated) { // We messed things up, visible range is all we know is valid
_clean_left = needed_left;
_clean_right = needed_right;
} else { // Extend range to what we've 'fixed'
// Extend range to what we've 'fixed'
if (!invalidated) {
_clean_left = min(_clean_left, needed_left);
_clean_right = max(_clean_right, needed_right);
}