mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-03 04:52:28 +00:00
timeline: only redraw updated parts of the graph
Improves rendering performance a lot.
This commit is contained in:
parent
af308379b4
commit
6cfca1c322
1 changed files with 67 additions and 38 deletions
|
@ -440,11 +440,11 @@ class TimelineWidget (gtk.DrawingArea):
|
||||||
self.process = UpdateProcess (None, None)
|
self.process = UpdateProcess (None, None)
|
||||||
self.process.handle_sentinel_progress = self.__handle_sentinel_progress
|
self.process.handle_sentinel_progress = self.__handle_sentinel_progress
|
||||||
self.process.handle_sentinel_finished = self.__handle_sentinel_finished
|
self.process.handle_sentinel_finished = self.__handle_sentinel_finished
|
||||||
self.process.handle_process_finished = self.__handle_process_finished
|
|
||||||
|
|
||||||
self.model = None
|
self.model = None
|
||||||
self.__offscreen = None
|
self.__offscreen = None
|
||||||
self.__offscreen_size = (0, 0)
|
self.__offscreen_size = (0, 0)
|
||||||
|
self.__offscreen_dirty = (0, 0)
|
||||||
|
|
||||||
self.__position_ts_range = None
|
self.__position_ts_range = None
|
||||||
|
|
||||||
|
@ -457,41 +457,52 @@ class TimelineWidget (gtk.DrawingArea):
|
||||||
|
|
||||||
def __handle_sentinel_progress (self, sentinel):
|
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):
|
def __handle_sentinel_finished (self, sentinel):
|
||||||
|
|
||||||
if sentinel == self.process.freq_sentinel:
|
if sentinel == self.process.freq_sentinel:
|
||||||
self.__invalidate_offscreen ()
|
self.__invalidate_offscreen (0, -1)
|
||||||
|
else:
|
||||||
def __handle_process_finished (self):
|
self.__invalidate_offscreen (self.__dist_sentinel_progress, -1)
|
||||||
|
|
||||||
self.__invalidate_offscreen ()
|
|
||||||
|
|
||||||
def __ensure_offscreen (self):
|
def __ensure_offscreen (self):
|
||||||
|
|
||||||
x, y, width, height = self.get_allocation ()
|
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 = gtk.gdk.Pixmap (self.window, width, height, -1)
|
||||||
self.__offscreen_size = (width, height)
|
self.__offscreen_size = (width, height)
|
||||||
|
self.__offscreen_dirty = (0, width)
|
||||||
if not self.__offscreen:
|
if not self.__offscreen:
|
||||||
self.__offscreen_size = (0, 0)
|
self.__offscreen_size = (0, 0)
|
||||||
raise ValueError ("could not obtain pixmap")
|
raise ValueError ("could not obtain pixmap")
|
||||||
|
|
||||||
def __invalidate_offscreen (self):
|
def __invalidate_offscreen (self, start, stop):
|
||||||
|
|
||||||
if self.__offscreen is None:
|
x, y, width, height = self.get_allocation ()
|
||||||
return
|
if stop < 0:
|
||||||
|
stop += width
|
||||||
|
|
||||||
self.__offscreen = None
|
dirty_start, dirty_stop = self.__offscreen_dirty
|
||||||
self.queue_draw ()
|
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)
|
||||||
|
|
||||||
def __update_offscreen (self):
|
# Just like in __draw_offscreen. FIXME: Need this in one place!
|
||||||
|
start -= 8
|
||||||
if not self.props.visible:
|
stop += 8
|
||||||
return
|
self.queue_draw_area (start, 0, stop - start, height)
|
||||||
|
|
||||||
self.__ensure_offscreen ()
|
|
||||||
self.__draw_offscreen ()
|
|
||||||
|
|
||||||
def __draw_from_offscreen (self, rect = None):
|
def __draw_from_offscreen (self, rect = None):
|
||||||
|
|
||||||
|
@ -536,6 +547,7 @@ class TimelineWidget (gtk.DrawingArea):
|
||||||
self.model = model
|
self.model = model
|
||||||
|
|
||||||
if model is not None:
|
if model is not None:
|
||||||
|
self.__dist_sentinel_progress = 0
|
||||||
self.process.freq_sentinel = LineFrequencySentinel (model)
|
self.process.freq_sentinel = LineFrequencySentinel (model)
|
||||||
self.process.dist_sentinel = LevelDistributionSentinel (self.process.freq_sentinel, model)
|
self.process.dist_sentinel = LevelDistributionSentinel (self.process.freq_sentinel, model)
|
||||||
width = self.get_allocation ()[2]
|
width = self.get_allocation ()[2]
|
||||||
|
@ -548,7 +560,7 @@ class TimelineWidget (gtk.DrawingArea):
|
||||||
self.process.abort ()
|
self.process.abort ()
|
||||||
self.process.freq_sentinel = None
|
self.process.freq_sentinel = None
|
||||||
self.process.dist_sentinel = None
|
self.process.dist_sentinel = None
|
||||||
self.__invalidate_offscreen ()
|
self.__invalidate_offscreen (0, -1)
|
||||||
|
|
||||||
def update_position (self, start_ts, end_ts):
|
def update_position (self, start_ts, end_ts):
|
||||||
|
|
||||||
|
@ -578,11 +590,27 @@ class TimelineWidget (gtk.DrawingArea):
|
||||||
|
|
||||||
def __draw_offscreen (self):
|
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
|
drawable = self.__offscreen
|
||||||
width, height = self.__offscreen_size
|
width, height = self.__offscreen_size
|
||||||
|
|
||||||
ctx = drawable.cairo_create ()
|
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.
|
# White background rectangle.
|
||||||
ctx.set_line_width (0.)
|
ctx.set_line_width (0.)
|
||||||
ctx.rectangle (0, 0, width, height)
|
ctx.rectangle (0, 0, width, height)
|
||||||
|
@ -605,28 +633,30 @@ class TimelineWidget (gtk.DrawingArea):
|
||||||
# Vertical reference lines.
|
# Vertical reference lines.
|
||||||
pixel_step = self.find_indicative_time_step ()
|
pixel_step = self.find_indicative_time_step ()
|
||||||
ctx.set_source_rgb (.9, .9, .9)
|
ctx.set_source_rgb (.9, .9, .9)
|
||||||
for i in range (1, width // pixel_step + 1):
|
start = dirty_start - dirty_start % pixel_step
|
||||||
x = i * pixel_step - .5
|
for x in xrange (start + pixel_step, dirty_stop, pixel_step):
|
||||||
ctx.move_to (x, 0)
|
ctx.move_to (x - .5, 0)
|
||||||
ctx.line_to (x, height)
|
ctx.line_to (x - .5, height)
|
||||||
ctx.stroke ()
|
ctx.stroke ()
|
||||||
|
|
||||||
if not self.process.freq_sentinel.data:
|
if not self.process.freq_sentinel.data:
|
||||||
self.logger.debug ("frequency sentinel has no data yet")
|
self.logger.debug ("frequency sentinel has no data yet")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
ctx.translate (dirty_start, 0.)
|
||||||
|
|
||||||
maximum = max (self.process.freq_sentinel.data)
|
maximum = max (self.process.freq_sentinel.data)
|
||||||
|
|
||||||
ctx.set_source_rgb (0., 0., 0.)
|
ctx.set_source_rgb (0., 0., 0.)
|
||||||
self.__draw_graph (ctx, width, height, maximum,
|
data = self.process.freq_sentinel.data[dirty_start:dirty_stop]
|
||||||
self.process.freq_sentinel.data)
|
self.__draw_graph (ctx, height, maximum, data)
|
||||||
|
|
||||||
if not self.process.dist_sentinel.data:
|
if not self.process.dist_sentinel.data:
|
||||||
self.logger.debug ("level distribution sentinel has no data yet")
|
self.logger.debug ("level distribution sentinel has no data yet")
|
||||||
return
|
return
|
||||||
|
|
||||||
colors = LevelColorThemeTango ().colors
|
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):
|
def cumulative_level_counts (*levels):
|
||||||
for level_counts in dist_data:
|
for level_counts in dist_data:
|
||||||
|
@ -638,7 +668,7 @@ class TimelineWidget (gtk.DrawingArea):
|
||||||
Data.debug_level_log,
|
Data.debug_level_log,
|
||||||
Data.debug_level_debug,)
|
Data.debug_level_debug,)
|
||||||
ctx.set_source_rgb (*(colors[level][1].float_tuple ()))
|
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)))
|
list (cumulative_level_counts (level, *levels_prev)))
|
||||||
|
|
||||||
level = Data.debug_level_debug
|
level = Data.debug_level_debug
|
||||||
|
@ -646,24 +676,24 @@ class TimelineWidget (gtk.DrawingArea):
|
||||||
Data.debug_level_fixme,
|
Data.debug_level_fixme,
|
||||||
Data.debug_level_log,)
|
Data.debug_level_log,)
|
||||||
ctx.set_source_rgb (*(colors[level][1].float_tuple ()))
|
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)))
|
list (cumulative_level_counts (level, *levels_prev)))
|
||||||
|
|
||||||
level = Data.debug_level_log
|
level = Data.debug_level_log
|
||||||
levels_prev = (Data.debug_level_trace,Data.debug_level_fixme,)
|
levels_prev = (Data.debug_level_trace,Data.debug_level_fixme,)
|
||||||
ctx.set_source_rgb (*(colors[level][1].float_tuple ()))
|
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)))
|
list (cumulative_level_counts (level, *levels_prev)))
|
||||||
|
|
||||||
level = Data.debug_level_fixme
|
level = Data.debug_level_fixme
|
||||||
levels_prev = (Data.debug_level_trace,)
|
levels_prev = (Data.debug_level_trace,)
|
||||||
ctx.set_source_rgb (*(colors[level][1].float_tuple ()))
|
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)))
|
list (cumulative_level_counts (level, *levels_prev)))
|
||||||
|
|
||||||
level = Data.debug_level_trace
|
level = Data.debug_level_trace
|
||||||
ctx.set_source_rgb (*(colors[level][1].float_tuple ()))
|
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:
|
# Draw error and warning triangle indicators:
|
||||||
|
|
||||||
|
@ -678,12 +708,12 @@ class TimelineWidget (gtk.DrawingArea):
|
||||||
for i, counts in enumerate (dist_data):
|
for i, counts in enumerate (dist_data):
|
||||||
if counts[level] == 0:
|
if counts[level] == 0:
|
||||||
continue
|
continue
|
||||||
ctx.identity_matrix ()
|
ctx.translate (i, 0.)
|
||||||
ctx.translate (i, 0)
|
|
||||||
triangle (ctx)
|
triangle (ctx)
|
||||||
ctx.fill ()
|
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:
|
if not data:
|
||||||
return
|
return
|
||||||
|
@ -756,9 +786,8 @@ class TimelineWidget (gtk.DrawingArea):
|
||||||
|
|
||||||
def do_expose_event (self, event):
|
def do_expose_event (self, event):
|
||||||
|
|
||||||
if self.__offscreen is None:
|
self.__ensure_offscreen ()
|
||||||
self.__update_offscreen ()
|
self.__draw_offscreen ()
|
||||||
|
|
||||||
self.__draw_from_offscreen (event.area)
|
self.__draw_from_offscreen (event.area)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
Loading…
Reference in a new issue