[Bf-committers] generic memoryviews

Theo de Ridder theo.de.ridder at planet.nl
Sat Jun 12 19:24:07 CEST 2010


For those appreciating 'Pythonic' solutions
here is a design for generating memoryviews
for any bpy collection object.

My intentions:
a) memoryviews that enable high performance in pure Python
	for handling individual elements of huge (multidimensional)
	collections of Blender data by delegating low level (vertices, pixels, ...)
	getter/setter loops to the C-level;
b) a generic composition that is small, robust, and a natural fit
	with modern concepts in Blender and Python.

My solution is represented by the following types and attributes
(to be builtins in C):
1. class Slicer:
	__getitem__(...): 	generates a ViewWrapper context manager from standard slice notation;
2. class ViewWrapper:
	__enter__(...): 	creates a tempory MemCache, and subscribes to supplier;
	__exit__(...):		disables the tempory MemCache, and unsubscribes from supplier;
	supplier: 		ref to original collection object
	memcache: 		generated MemCache
	refresh(...): 		refresh memcache from original
	update(...):		update original from memcache
3: class MemCache (memoryview):
	wrapper:		ref to original ViewWrapper

- Any MemCache can be subsliced as a normal memoryview,
	and the refresh/update methods can have such a subview as
	an optional argument to restrict datatransfer to a limited area.
- Any Memcache is robust against lost pointers and changing collections when:
	- the deletion of a collection is notifying its subscribing ViewWrappers;
	- a MemCache as argument of a refresh or update is checked for:
		- its supplier is still living;
		- its axes and sizes are stiil compliant with those of the supplier;

examples of slicing:
	mesh = bpy.data.meshes['Cube']
	wrapnormals = Slicer(mesh.faces)[:, 'normal', :]
	wrapverts = Slicer(mesh.verts)[:, 'co', :]
	wrap3xyz = Slicer(mesh.verts)[:, co', ('xxx', 'yyy', 'zzz'), :]
	wrapvertcolors = Slicer(mesh.vertex_colors)[['Col'], 'data', :, ('color1', 'color2'), :]

example of usage:
- 	def updater (name):
		# yielding enables reentering context without overhead of __enter__
		slicer = Slicer(bpy.data.meshes[name].faces)
		with slicer['normals', :] as vw: 
			subcache = yield vw.memcache
			while True:
				info = ...
				subcache = yield info
i				if subcache == None:
					break
				vw.update(subcache)
	generator = updater('Monkey')
	memcache = gen.next()
	while not stop_condition():
		i,j = ...
		subcache = memcache[i:j, :]
		modify(subcache)
		info = gen.send(subcache)
		
so far, so good;
if there is interest I am willing to work out this idea into a full Python
executable specification (including performance analysis with numpy in Blender 2.49),
however, I am feeling sorry being too old now for
hacking again in C after more than 20 years,

~Theo





More information about the Bf-committers mailing list