kivy/kivy — pull request #2187 by matham (2014-05-13 00:32:50+00:00)
Title: Change mesh vertices and indices to accept memoryviews.

This continues in the line of #2186 but does not depends on it.

* Until now, whatever was passed to mesh indices or vertices was converted to a list. This pr changes such that, if a memoryview or instance that implements the python buffer interface is passed, that is used, otherwise, it creates internally, a array from the iterable and uses that.
* With this, you can pass python/cython/numpy arrays directly to it and it'll use them in place without creating additional copies. Then you could edit a few elements in the array, re-assign it and since the underlying buffer memory is used, no additonal copies is created at any time.
* I only added it to mesh because that seemed to be the obvious one to benefit from this. But it could be used elsewhere. The functions added to `common.pxi` should help there.

Following are test I have done with the following code.There are two places to test, the assignment of the iterable to vertices and the build call. In order to be able to test the build duration, I temporarily added the following function to mesh which I then used in the test code below:

def test_build(self):
self.build()

.The test code is::

```
import timeit
from functools import partial
from array import array
from kivy.base import EventLoop
EventLoop.ensure_window()
from kivy.graphics.texture import Texture
from kivy.graphics import Mesh

count = 100
print 'count: {}'.format(count)
m = Mesh()
vertices = [100, 100, 0, 0] * count
indices = range(count) + range(count) + range(count) + range(count)
d1 = timeit.Timer(partial(setattr, m, 'vertices', vertices)).repeat(1, 10000)
d2 = timeit.Timer(partial(setattr, m, 'indices', indices)).repeat(1, 10000)
d3 = timeit.Timer(m.test_build).repeat(1, 10000)
print 'setting vertices, indices with list: {:.4f}, {:.4f}. Building: {:.4f}'.format(d1[0], d2[0], d3[0])
vertices = array('f', vertices)
indices = array('H', indices)
d1 = timeit.Timer(partial(setattr, m, 'vertices', vertices)).repeat(1, 10000)
d2 = timeit.Timer(partial(setattr, m, 'indices', indices)).repeat(1, 10000)
d3 = timeit.Timer(m.test_build).repeat(1, 10000)
print 'setting vertices, indices with array: {:.4f}, {:.4f}. Building: {:.4f}'.format(d1[0], d2[0], d3[0])
```

On my branch it printed:
```
count: 100
setting vertices, indices with list: 0.1680, 0.1074. Building: 0.1264
setting vertices, indices with array: 0.0364, 0.0383. Building: 0.1225
count: 1000
setting vertices, indices with list: 1.5712, 0.9147. Building: 1.0536
setting vertices, indices with array: 0.0371, 0.0393. Building: 1.0618
```

On master it printed:
```
count: 100
setting vertices, indices with list: 0.0259, 0.0251. Building: 0.3027
setting vertices, indices with array: 0.0882, 0.0774. Building: 0.2233
count: 1000
setting vertices, indices with list: 0.1924, 0.2047. Building: 2.9872
setting vertices, indices with array: 0.8173, 0.7695. Building: 2.2262
```

The main thing to compare is the total setting + build time. As you can see in all cases, this branch is faster, but the major difference is when a an array type is passed in.