jensjeflensje / minecraft_imagery

Toolkit for taking pictures and videos in Minecraft
https://www.spigotmc.org/resources/imageryapi-take-pictures-in-minecraft.111347/
MIT License
18 stars 3 forks source link

Enhancement: multi-thread the render function #11

Open ConnorBP opened 2 weeks ago

ConnorBP commented 2 weeks ago

I propose that the each pixel ray be sent off into it's own thread here:

https://github.com/jensjeflensje/minecraft_imagery/blob/16658fcaf4bfcc25c357e24fa3f4f266593d6b65/src/main/java/dev/jensderuiter/minecraft_imagery/image/ImageCapture.java#L98C9-L98C13

Instead of rendering each pixel sequentially, we can create an Asyncronous lambda which takes in an x and a y, returning the pixel result. We can loop through the x and y in the for loop the same, but instead of running the render we spawn a thread for that pixel and join it's CompletableFuture with the rest. Then after the for loop you spinwait until all pixels complete for the final result.

This type of design should speed up the render times substantially.

jensjeflensje commented 2 weeks ago

I like this idea and I agree that it will speed up rendering, but I am cautious of creating 128^2 threads in one go. I think it would be better to implement this in a thread pool or just using CompletableFuture.supplyAync. Making it async would dramatically increase performance on multi-core systems, so I think it's a nice idea :)

ConnorBP commented 2 weeks ago

I like this idea and I agree that it will speed up rendering, but I am cautious of creating 128^2 threads in one go. I think it would be better to implement this in a thread pool of just using CompletableFuture.supplyAync. Making it async would dramatically increase performance on multi-core systems, so I think it's a nice idea :)

I was also thinking threadpool. I did not mean CompletableFuture.supplyAync.

It would be something more like this with a custom Completable backed by a thread pool:

// takes in a simple synchronous functional interface and an object to act on
// and calls this function asynchronously in a thread pool on Function apply call
class AsyncTask<T, V> implements Function<ExecutorService, CompletableFuture<V>> {
    private SimpFunction<T> task;
    private T object;

    public AsyncTask(SimpFunction<T> task, T object) {
        this.task = task;
        this.object = object;
    }

    @Override
    public CompletableFuture<V> apply(ExecutorService pool) {
        CompletableFuture<V> theFuture = new CompletableFuture<>();
        pool.submit(() -> {
            this.task.run(object);
            theFuture.complete(null);
        });

        return theFuture;
    }
}

public class AsyncExample<T, V> {
    private SimpFunction<T> task;
    private ExecutorService pool;
    private CompletableFuture<V> theFuture = null;

    public AsyncExample(SimpFunction<T> task) {
        this.task = task;
        this.pool = Executors.newCachedThreadPool();
    }

    public CompletableFuture<V> run(T object) {
        AsyncTask t = new AsyncTask(task, object);

        theFuture = t.apply(pool);
        return theFuture;
    }

    public void close() {
        this.pool.close();
    }
}