0

This is the Java code:

public static FloatBuffer createInterleavedVertexBuffer(AIMesh mesh) {
    FloatBuffer buffer = BufferUtils.createFloatBuffer(mesh.mNumVertices() * 8);
    for (int i = 0; i < mesh.mNumVertices(); i++) {
        var vertex = mesh.mVertices().get(i);
        buffer.put(vertex.x());
        buffer.put(vertex.y());
        buffer.put(vertex.z());

        var normal = mesh.mNormals().get(i);
        buffer.put(normal.x());
        buffer.put(normal.y());
        buffer.put(normal.z());

        var texCoords = mesh.mTextureCoords(0).get(i);
        buffer.put(texCoords.x());
        buffer.put(texCoords.y());
    }
    return buffer.flip();
}

And this is (as far as I can tell) equivalent Clojure code:

(defn create-vertex-buffer
  [mesh]
  (let [buffer (BufferUtils/createFloatBuffer (* (.mNumVertices mesh) 8))]
    (doseq [index (range (.mNumVertices mesh))]
      (let [vertex (.get (.mVertices mesh) index)
            normal (.get (.mNormals mesh) index)
            tex-coords (.get (.mTextureCoords mesh 0) index)]
        (.put buffer (.x vertex))
        (.put buffer (.y vertex))
        (.put buffer (.z vertex))
        (.put buffer (.x normal))
        (.put buffer (.y normal))
        (.put buffer (.z normal))
        (.put buffer (.x tex-coords))
        (.put buffer (.y tex-coords))))
    (.flip buffer)))

However, the Clojure version runs about five times longer than the Java version.

Why is this?

Is there a way to improve the performance of the Clojure version?

2
  • 3
    There are a few possibilities. Are you compiling with (set! *warn-on-reflection* true)? Commented Aug 5 at 21:05
  • 3
    Add (set! *warn-on-reflection* true) after the (ns ...) form and reload the namespace in your REPL. You'll see a bunch of reflection warnings coming from this function. Once if resolve them, the function should become close in performance to its Java version. BTW you can use dotimes instead of doseq + range. Commented Aug 5 at 21:06

1 Answer 1

3

Explicit type hinting might accelerate the execution:

(import [java.nio FloatBuffer]
        [org.lwjgl.assimp AIMesh AIVector3D]
        [org.lwjgl.system BufferUtils])

(defn create-vertex-buffer-optimized
  [^AIMesh mesh]
  (let [num-vertices (.mNumVertices mesh)
        ^FloatBuffer buffer (BufferUtils/createFloatBuffer (* num-vertices 8))]
    (dotimes [index num-vertices]
      (let [^AIVector3D vertex   (.get (.mVertices mesh) index)
            ^AIVector3D normal   (.get (.mNormals mesh) index)
            ^AIVector3D tex-coords (.get (.mTextureCoords mesh 0) index)]
        (.put buffer (.x vertex))
        (.put buffer (.y vertex))
        (.put buffer (.z vertex))
        (.put buffer (.x normal))
        (.put buffer (.y normal))
        (.put buffer (.z normal))
        (.put buffer (.x tex-coords))
        (.put buffer (.y tex-coords))))
    (.flip buffer)))
Sign up to request clarification or add additional context in comments.

1 Comment

You shouldn't need the hint on createFloatBuffer, but the others do look necessary since we don't have generics.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.