matrix: use a custom low-level C structure to avoid boxing of param types
authorAlexis Laferrière <alexis.laf@xymus.net>
Sat, 22 Apr 2017 18:36:04 +0000 (14:36 -0400)
committerAlexis Laferrière <alexis.laf@xymus.net>
Tue, 9 May 2017 18:56:37 +0000 (14:56 -0400)
Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>

lib/gamnit/flat.nit
lib/matrix/matrix.nit

index d5d2ef1..18d02f6 100644 (file)
@@ -35,6 +35,7 @@ module flat
 
 import glesv2
 intrude import geometry::points_and_lines # For _x, _y and _z
+intrude import matrix
 import matrix::projection
 import more_collections
 import performance_analysis
@@ -859,7 +860,7 @@ private class SpriteContext
                        else
                                rot = new Matrix.rotation(sprite.rotation, 0.0, 0.0, 1.0)
                        end
-                       data.fill_from(rot.items, o+15)
+                       data.fill_from_matrix(rot, o+15)
 
                        o += float_per_vertex
                end
@@ -1257,3 +1258,21 @@ private class GroupedArray[E]
                return ss.join
        end
 end
+
+redef class GLfloatArray
+       private fun fill_from_matrix(matrix: Matrix, dst_offset: nullable Int)
+       do
+               dst_offset = dst_offset or else 0
+               var mat_len = matrix.width*matrix.height
+               assert length >= mat_len + dst_offset
+               native_array.fill_from_matrix_native(matrix.items, dst_offset, mat_len)
+       end
+end
+
+redef class NativeGLfloatArray
+       private fun fill_from_matrix_native(matrix: matrix::NativeDoubleArray, dst_offset, len: Int) `{
+               int i;
+               for (i = 0; i < len; i ++)
+                       self[i+dst_offset] = (GLfloat)matrix[i];
+       `}
+end
index 91adb80..5d9a89d 100644 (file)
@@ -28,9 +28,7 @@ class Matrix
        var height: Int
 
        # Items of this matrix, rows by rows
-       var items: Array[Float] is lazy do
-               return new Array[Float].filled_with(0.0, width*height)
-       end
+       private var items = new NativeDoubleArray(width*height) is lazy
 
        # Create a matrix from nested sequences
        #
@@ -134,7 +132,12 @@ class Matrix
        end
 
        # Create a new clone of this matrix
-       redef fun clone do return new Matrix.from_array(width, height, items.clone)
+       redef fun clone
+       do
+               var c = new Matrix(width, height)
+               for i in [0..width*height[ do c.items[i] = items[i]
+               return c
+       end
 
        # Get the value at column `y` and row `x`
        #
@@ -212,7 +215,7 @@ class Matrix
                var out = new Matrix(other.width, self.height)
                for j in self.height.times do
                        for i in other.width.times do
-                               var sum = items.first.zero
+                               var sum = items[0].zero
                                for k in self.width.times do sum += self[j, k] * other[k, i]
                                out[j, i] = sum
                        end
@@ -244,15 +247,22 @@ class Matrix
 
        redef fun to_s
        do
-               var lines = new Array[String]
-               for y in height.times do
-                       lines.add items.subarray(y*width, width).join(" ")
+               var s = new FlatBuffer
+               for y in [0..height[ do
+                       for x in [0..width[ do
+                               s.append items[y*width+x].to_s
+                               if x < width-1 then s.add ' '
+                       end
+                       if y < height-1 then s.add '\n'
                end
-               return lines.join("\n")
+               return s.to_s
        end
 
-       redef fun ==(other) do return other isa Matrix and other.items == self.items
-       redef fun hash do return items.hash
+       redef fun ==(other) do return other isa Matrix and
+               width == other.width and height == other.height and
+               items.equal_items(items, width*height)
+
+       redef fun hash do return items.hash_items(width*height)
 end
 
 private class MatrixIndexIterator
@@ -293,3 +303,36 @@ class MatrixCoordinate
 
        redef fun to_s do return "({x},{y})"
 end
+
+# Specialized native structure to store matrix items and avoid boxing cost
+private extern class NativeDoubleArray `{ double* `}
+
+       new(size: Int) do
+               var sizeof_double = 8
+               var buf = new CString(sizeof_double*size)
+               return new NativeDoubleArray.in_buffer(buf)
+       end
+
+       new in_buffer(buffer: CString) `{ return (double*)buffer; `}
+
+       fun [](i: Int): Float `{ return self[i]; `}
+
+       fun []=(i: Int, value: Float) `{ self[i] = value; `}
+
+       fun equal_items(other: NativeDoubleArray, len: Int): Bool `{
+               int i;
+               for (i = 0; i < len; i ++)
+                       if (self[i] != other[i])
+                               return 0;
+               return 1;
+       `}
+
+       fun hash_items(len: Int): Int `{
+               // Adapted from `SequenceRead::hash`
+               long r = 17+len;
+               int i;
+               for (i = 0; i < len; i ++)
+                       r = r * 3 / 2 + (long)(i*1024.0);
+               return r;
+       `}
+end