This is a simple code that just color the window 4 times.
Maybe there is something obvious that I don't see.
My goal is to learn computer graphic from scratch and I want to draw pixel by pixel to have full control. I'm looking for a fast way to do it.
Here is the full code.
The relevant clojure part:
(defmacro for-loop [[sym init check change :as params] & steps]
`(loop [~sym ~init value# nil]
(if ~check
(let [new-value# (do ~@steps)]
(recur ~change new-value#))
value#)))
(time
(for-loop
[k 0 (< k 2) (inc k)]
(for-loop
[c 0 (< c 2) (inc c)]
(for-loop
[i 0 (< i width) (inc i)]
(for-loop
[j 0 (< j height) (inc j)]
(aset ^ints @pixels (+ i (* j width)) (get cs c))))
(.repaint canvas))))
The same code in java:
long t = System.currentTimeMillis();
for (int k = 0 ; k < 2; k++) {
for (int c = 0; c < 2; c++) {
for (int i = 0 ; i < width; i++) {
for (int j = 0; j < height; j++) {
pixels[i + j * width] = cs[c];
}
}
repaint();
}
}
System.out.println(System.currentTimeMillis() - t);
There's a couple problems:
If you run lein check
, you'll see reflection warnings. You're forcing reflection at runtime which can slow things down. I changed the canvas
creation to:
(defonce canvas (doto (proxy [Frame] []
(update [g] (.paint this g))
(paint [^Graphics2D g]
(.drawImage g, ^BufferedImage image, 0, 0 nil)))
(.setSize width height)
(.setBackground Color/black)
(.setFocusableWindowState false)
(.setVisible true)))
Notice the type hints I'm using. It didn't know which overload of drawImage
to use, and outright couldn't find the paint
method.
The main issue however is the use of aset
. From aset
's docs:
Sets the value at the index/indices. Works on Java arrays of reference types. Returns val.
Emphasis mine.
The problem is that aset
doesn't work with primitives. It forces each number to be wrapped as an Integer
, then unwrapped again when it's used in the image. This is quite expensive when multiplied over each pixel of an image.
Change aset
to aset-int
to use int
primitives instead. This takes the execution time down from roughly 20 seconds to half a second.
Honestly though, I can't get it any lower. It's much faster than it was, but is still about 20x slower than the Java version. I've been working on this for almost 2 hours now, and I've hit a wall. Hopefully someone else can squeeze the last bit of time out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With