Ich versuche, eine Funktion, die ein BufferedImage nehmen und einen ByteBuffer zurückgeben kann ich dann als OpenGL-Textur verwenden. Um das zu tun, habe ich gelernt, dass ich einige Byte-Verschiebungen machen muss, die für meine Frage nicht relevant sind. Es hat damit zu tun, dass die BufferedImage-Werte ARGB und OpenGL RGBA sind.Wie kann ich diesen Puffer in Clojure schneller füllen
Die Funktion I (aus Java) ist dies eine zu implementieren bin versucht:
public static ByteBuffer toByteBuffer(BufferedImage img){
byte[] byteArray = new byte[img.getWidth()*img.getHeight()*4];
for(int i = 0; i < img.getWidth()*img.getHeight(); i++){
int value = img.getRGB(i%img.getWidth(), (i-(i%img.getWidth()))/img.getWidth());
byteArray[i*4] = (byte) ((value<<8)>>24);
byteArray[i*4+1] = (byte) ((value<<16)>>24);
byteArray[i*4+2] = (byte) ((value<<24)>>24);
byteArray[i*4+3] = (byte) (value>>24);
}
return (ByteBuffer) ByteBuffer.allocateDirect(byteArray.length).put(byteArray).flip();
}
Und das ist mein Versuch mit clojure:
(defn sub-byte [^long b ^long x]
(unchecked-byte (-> x
(bit-shift-left (* 8 b))
(bit-shift-right 24))))
(defn bufferedimage->bytebuffer [^BufferedImage img]
(binding [*unchecked-math* true]
(let [w (.getWidth img)
h (.getHeight img)
^bytes arr (make-array Byte/TYPE (* 4 w h))]
(loop [i 0]
(let [img-i (mod i w)
img-j (quot i w)
value (.getRGB img img-i img-j)]
(aset arr (* i 4) (sub-byte 1 value))
(aset arr (+ 1 (* i 4)) (sub-byte 2 value))
(aset arr (+ 2 (* i 4)) (sub-byte 3 value))
(aset arr (+ 3 (* i 4)) (sub-byte 0 value))
(when (< (+ i 1) (* w h)) (recur (+ i 1)))
))
(cast ByteBuffer (-> (ByteBuffer/allocateDirect (count arr))
(.put arr)
(.flip))))))
Dies dauert 10 Sekunden, um eine 512 zu laden * 512 Tileset, was völlig inakzeptabel ist. Ich versuche, das in weniger als einer Sekunde zu machen.
Beachten Sie, dass der Teil, der die ganze Zeit dauert, die Schleife ist.
Ich könnte auch erwähnen, dass diese Zeiten mit der REPL genommen werden.
Beachten Sie auch, dass ich weiß, dass ich Java für die performance-kritischen Teile meines Codes verwenden kann, also ist dies eher eine theoretische Frage, damit ich lernen kann, wie ich meinen Clojure-Code optimieren kann.
Sie könnten 'clojure.core/time' verwenden, um zu messen, welche Teile Ihres Codes die meiste Zeit benötigen. –
habe ich schon getan. Von meinem Beitrag: "Beachten Sie, dass der Teil, der die ganze Zeit beansprucht, die Schleife ist." – Setzer22
[Criterium] (https://github.com/hugoduncan/criterium) ist eine bessere Möglichkeit zum Benchmarking. Im Allgemeinen sind "map", "reduce" und "filter" wahrscheinlich bessere Wahlmöglichkeiten für Geschwindigkeit und idiomatischer als "loop/recur". – jmargolisvt