summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRené Stadler <mail@renestadler.de>2012-09-24 02:15:09 +0200
committerRené Stadler <mail@renestadler.de>2012-09-24 02:43:37 +0200
commit5bc90c6162da1f01f3260f632010f57667501fd6 (patch)
treec675bd8c84aad6eca4cc12dce7c50904b9326c35
parent73746f445028d0bd4bd21c22a61e5b4f45f9fdba (diff)
timeline: only redraw updated parts of the graph
Improves rendering performance a lot.
-rw-r--r--GstDebugViewer/Plugins/Timeline.py105
1 files changed, 67 insertions, 38 deletions
diff --git a/GstDebugViewer/Plugins/Timeline.py b/GstDebugViewer/Plugins/Timeline.py
index 9435554..c826ceb 100644
--- a/GstDebugViewer/Plugins/Timeline.py
+++ b/GstDebugViewer/Plugins/Timeline.py
@@ -440,11 +440,11 @@ class TimelineWidget (gtk.DrawingArea):
self.process = UpdateProcess (None, None)
self.process.handle_sentinel_progress = self.__handle_sentinel_progress
self.process.handle_sentinel_finished = self.__handle_sentinel_finished
- self.process.handle_process_finished = self.__handle_process_finished
self.model = None
self.__offscreen = None
self.__offscreen_size = (0, 0)
+ self.__offscreen_dirty = (0, 0)
self.__position_ts_range = None
@@ -457,41 +457,52 @@ class TimelineWidget (gtk.DrawingArea):
def __handle_sentinel_progress (self, sentinel):
- self.__invalidate_offscreen ()
+ if sentinel == self.process.dist_sentinel:
+ old_progress = self.__dist_sentinel_progress
+ new_progress = len (sentinel.data)
+ if new_progress - old_progress >= 32:
+ self.__invalidate_offscreen (old_progress, new_progress)
+ self.__dist_sentinel_progress = new_progress
def __handle_sentinel_finished (self, sentinel):
if sentinel == self.process.freq_sentinel:
- self.__invalidate_offscreen ()
-
- def __handle_process_finished (self):
-
- self.__invalidate_offscreen ()
+ self.__invalidate_offscreen (0, -1)
+ else:
+ self.__invalidate_offscreen (self.__dist_sentinel_progress, -1)
def __ensure_offscreen (self):
x, y, width, height = self.get_allocation ()
+ if self.__offscreen_size == (width, height):
+ return
+
self.__offscreen = gtk.gdk.Pixmap (self.window, width, height, -1)
self.__offscreen_size = (width, height)
+ self.__offscreen_dirty = (0, width)
if not self.__offscreen:
self.__offscreen_size = (0, 0)
raise ValueError ("could not obtain pixmap")
- def __invalidate_offscreen (self):
-
- if self.__offscreen is None:
- return
+ def __invalidate_offscreen (self, start, stop):
- self.__offscreen = None
- self.queue_draw ()
-
- def __update_offscreen (self):
+ x, y, width, height = self.get_allocation ()
+ if stop < 0:
+ stop += width
- if not self.props.visible:
- return
+ dirty_start, dirty_stop = self.__offscreen_dirty
+ if dirty_start != dirty_stop:
+ dirty_start = min (dirty_start, start)
+ dirty_stop = max (dirty_stop, stop)
+ else:
+ dirty_start = start
+ dirty_stop = stop
+ self.__offscreen_dirty = (dirty_start, dirty_stop)
- self.__ensure_offscreen ()
- self.__draw_offscreen ()
+ # Just like in __draw_offscreen. FIXME: Need this in one place!
+ start -= 8
+ stop += 8
+ self.queue_draw_area (start, 0, stop - start, height)
def __draw_from_offscreen (self, rect = None):
@@ -536,6 +547,7 @@ class TimelineWidget (gtk.DrawingArea):
self.model = model
if model is not None:
+ self.__dist_sentinel_progress = 0
self.process.freq_sentinel = LineFrequencySentinel (model)
self.process.dist_sentinel = LevelDistributionSentinel (self.process.freq_sentinel, model)
width = self.get_allocation ()[2]
@@ -548,7 +560,7 @@ class TimelineWidget (gtk.DrawingArea):
self.process.abort ()
self.process.freq_sentinel = None
self.process.dist_sentinel = None
- self.__invalidate_offscreen ()
+ self.__invalidate_offscreen (0, -1)
def update_position (self, start_ts, end_ts):
@@ -578,11 +590,27 @@ class TimelineWidget (gtk.DrawingArea):
def __draw_offscreen (self):
+ dirty_start, dirty_stop = self.__offscreen_dirty
+ if dirty_start == dirty_stop:
+ return
+
+ self.__offscreen_dirty = (0, 0)
+
drawable = self.__offscreen
width, height = self.__offscreen_size
ctx = drawable.cairo_create ()
+ # Indicator (triangle) size is 8, so we need to draw surrounding areas
+ # a bit:
+ dirty_start -= 8
+ dirty_stop += 8
+ dirty_start = max (dirty_start, 0)
+ dirty_stop = min (dirty_stop, width)
+
+ ctx.rectangle (dirty_start, 0., dirty_stop, height)
+ ctx.clip ()
+
# White background rectangle.
ctx.set_line_width (0.)
ctx.rectangle (0, 0, width, height)
@@ -605,28 +633,30 @@ class TimelineWidget (gtk.DrawingArea):
# Vertical reference lines.
pixel_step = self.find_indicative_time_step ()
ctx.set_source_rgb (.9, .9, .9)
- for i in range (1, width // pixel_step + 1):
- x = i * pixel_step - .5
- ctx.move_to (x, 0)
- ctx.line_to (x, height)
+ start = dirty_start - dirty_start % pixel_step
+ for x in xrange (start + pixel_step, dirty_stop, pixel_step):
+ ctx.move_to (x - .5, 0)
+ ctx.line_to (x - .5, height)
ctx.stroke ()
if not self.process.freq_sentinel.data:
self.logger.debug ("frequency sentinel has no data yet")
return
+ ctx.translate (dirty_start, 0.)
+
maximum = max (self.process.freq_sentinel.data)
ctx.set_source_rgb (0., 0., 0.)
- self.__draw_graph (ctx, width, height, maximum,
- self.process.freq_sentinel.data)
+ data = self.process.freq_sentinel.data[dirty_start:dirty_stop]
+ self.__draw_graph (ctx, height, maximum, data)
if not self.process.dist_sentinel.data:
self.logger.debug ("level distribution sentinel has no data yet")
return
colors = LevelColorThemeTango ().colors
- dist_data = self.process.dist_sentinel.data
+ dist_data = self.process.dist_sentinel.data[dirty_start:dirty_stop]
def cumulative_level_counts (*levels):
for level_counts in dist_data:
@@ -638,7 +668,7 @@ class TimelineWidget (gtk.DrawingArea):
Data.debug_level_log,
Data.debug_level_debug,)
ctx.set_source_rgb (*(colors[level][1].float_tuple ()))
- self.__draw_graph (ctx, width, height, maximum,
+ self.__draw_graph (ctx, height, maximum,
list (cumulative_level_counts (level, *levels_prev)))
level = Data.debug_level_debug
@@ -646,24 +676,24 @@ class TimelineWidget (gtk.DrawingArea):
Data.debug_level_fixme,
Data.debug_level_log,)
ctx.set_source_rgb (*(colors[level][1].float_tuple ()))
- self.__draw_graph (ctx, width, height, maximum,
+ self.__draw_graph (ctx, height, maximum,
list (cumulative_level_counts (level, *levels_prev)))
level = Data.debug_level_log
levels_prev = (Data.debug_level_trace,Data.debug_level_fixme,)
ctx.set_source_rgb (*(colors[level][1].float_tuple ()))
- self.__draw_graph (ctx, width, height, maximum,
+ self.__draw_graph (ctx, height, maximum,
list (cumulative_level_counts (level, *levels_prev)))
level = Data.debug_level_fixme
levels_prev = (Data.debug_level_trace,)
ctx.set_source_rgb (*(colors[level][1].float_tuple ()))
- self.__draw_graph (ctx, width, height, maximum,
+ self.__draw_graph (ctx, height, maximum,
list (cumulative_level_counts (level, *levels_prev)))
level = Data.debug_level_trace
ctx.set_source_rgb (*(colors[level][1].float_tuple ()))
- self.__draw_graph (ctx, width, height, maximum, [counts[level] for counts in dist_data])
+ self.__draw_graph (ctx, height, maximum, [counts[level] for counts in dist_data])
# Draw error and warning triangle indicators:
@@ -678,12 +708,12 @@ class TimelineWidget (gtk.DrawingArea):
for i, counts in enumerate (dist_data):
if counts[level] == 0:
continue
- ctx.identity_matrix ()
- ctx.translate (i, 0)
+ ctx.translate (i, 0.)
triangle (ctx)
ctx.fill ()
+ ctx.translate (-i, 0.)
- def __draw_graph (self, ctx, width, height, maximum, data):
+ def __draw_graph (self, ctx, height, maximum, data):
if not data:
return
@@ -756,9 +786,8 @@ class TimelineWidget (gtk.DrawingArea):
def do_expose_event (self, event):
- if self.__offscreen is None:
- self.__update_offscreen ()
-
+ self.__ensure_offscreen ()
+ self.__draw_offscreen ()
self.__draw_from_offscreen (event.area)
return True