--- /dev/null
+# This file is part of MyPaint.
+# Copyright (C) 2009 by Martin Renold <martinxyz@gmx.ch>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+import gobject
+
+class Processor:
+ """
+ A queue of low priority tasks that are automatically processed
+ when gtk is idle, or on demand.
+ """
+ def __init__(self, max_pending):
+ self._queue = []
+ self.max_pending = max_pending
+
+ def add_work(self, func, weight=1.0):
+ if not self._queue:
+ gobject.idle_add(self._idle_cb)
+ func.__weight = weight
+ self._queue.append(func)
+ self.finish_downto(self.max_pending)
+
+ def finish_one(self):
+ print '.'
+ func = self._queue.pop(0)
+ func()
+
+ def finish_downto(self, max_pending):
+ while 1:
+ pending_weight = sum([func.__weight for func in self._queue])
+ if pending_weight <= max_pending:
+ return
+ self.finish_one()
+
+ def finish_all(self):
+ self.finish_downto(0)
+
+ def _idle_cb(self):
+ if not self._queue:
+ return False
+ self.finish_one()
+ return True
+
# (at your option) any later version.
import time
-import gobject, zlib
+import zlib
from numpy import *
-import tiledsurface, strokemap_pb2
+import tiledsurface, idletask, strokemap_pb2
N = tiledsurface.N
+tasks = idletask.Processor(max_pending=6)
+
class StrokeInfo:
"""
This class stores permanent (saved with image) information about a
single stroke. Mainly this is the stroke shape and the brush
settings that were used. Needed to pick brush from canvas.
"""
- processing_queue = [] # global (static) list
def __init__(self):
self.strokemap = {}
self.brush = None
data_compressed = zlib.compress(data.tostring())
self.strokemap[tx, ty] = data_compressed
- queue.append(work)
- self.processing_queue.append(queue)
-
- gobject.idle_add(self.idle_cb)
-
- # make sure we never lag too much behind with processing
- # (otherwise we waste way too much memory)
- self.process_pending_strokes(max_pending_strokes=6)
+ tasks.add_work(work, weight=1.0/len(tiles_modified))
def init_from_pb(self, stroke_pb, translate_x, translate_y):
assert not self.strokemap
assert translate_y % N == 0
translate_x /= N
translate_y /= N
- self.process_pending_strokes()
+ tasks.finish_all()
for (tx, ty), data in self.strokemap.iteritems():
t = stroke_pb.tiles.add()
t.tx, t.ty = tx + translate_x, ty + translate_y
t.data_compressed = data
stroke_pb.brush_string_compressed = zlib.compress(self.brush_string)
- def process_one_item(self):
- items = self.processing_queue[0]
- if items:
- func = items.pop(0)
- func()
- else:
- self.processing_queue.pop(0)
-
- def process_pending_strokes(self, max_pending_strokes=0):
- while len(self.processing_queue) > max_pending_strokes:
- self.process_one_item()
-
- def idle_cb(self):
- if not self.processing_queue:
- return False
- self.process_one_item()
- return True
-
def touches_pixel(self, x, y):
- self.process_pending_strokes()
+ tasks.finish_all()
data = self.strokemap.get((x/N, y/N))
if data:
data = fromstring(zlib.decompress(data), dtype='uint8')
return data[y%N, x%N]
def render_overlay(self, surf):
- self.process_pending_strokes()
+ tasks.finish_all()
for (tx, ty), data in self.strokemap.iteritems():
data = fromstring(zlib.decompress(data), dtype='uint8')
data.shape = (N, N)
rgba[:,:,0] = rgba[:,:,3]/2
rgba[:,:,1] = rgba[:,:,3]/2
rgba[:,:,2] = rgba[:,:,3]/2
+
+
doc.stroke_to(dtime, x, y, pressure)
#gc.set_debug(gc.DEBUG_LEAK)
- paint()
- doc.clear()
- m0 = mem()
- paint()
- assert mem() >= m0
- doc.clear()
- m1 = mem()
-
- for i in range(100):
+ m = []
+ for i in range(20):
paint()
doc.clear()
m2 = mem()
+ m.append(m2)
print 'iteration %02d/100: %d pages used' % (i, m2)
- assert m1 == m2, 'memory leak during paint/clear cycles'
-
- paint()
- doc.save('test_memory_leak.png', alpha=False)
- #doc.clear()
+ for i in range(10,20):
+ assert m[i] == m[9], 'memory leak during paint/clear cycles'
- m3 = mem()
+ #import objgraph
+ #from lib import strokemap
+ #objgraph.show_refs(doc)
+ #sys.exit(0)
#assert m2 == m0, (m2-m0, m3-m2)