1
\$\begingroup\$

I'm writing my own renderer in pure java without any external libraries. I'm using per-pixel rendering. I'm rendering an image with this method:

public void renderImage(int x, int y, RawImage image) {
        int[] img = image.getPixels();

        if (x >= surface.getWidth() || y > surface.getHeight())
            return;

        for (int i = 0; i < image.getWidth(); i++) {
            int xp = x + i;
            if (xp < 0)
                continue;
            if (xp >= surface.getWidth())
                return;
            for (int j = 0; j < image.getHeight(); j++) {
                int yp = y + j;
                if (yp < 0)
                    continue;
                if (yp >= surface.getHeight())
                    break;
                int pos = xp + yp * surface.getWidth();
                if (pos < 0 || pos >= pixels.length)
                    continue;
                pixels[pos] = blendMode.getColor(img[i + j * image.getWidth()], pixels[pos]);
            }
        }
    }

But if I render 500 images (with the size of 128x128) my FPS drops down to around 7. Is there anyway to make this more efficient?

The blendMode.getColor() is the blending I implemented. In this example I'm using additive:

public int getColor(int c1, int c2) {
        float a = (float) ((c1 & 0xff000000) >>> 24) / 255f;
        int red = (int) ((c1 & 0x00ff0000) * a + (c2 & 0x00ff0000)) + BlendMode.tint;
        int grn = (int) ((c1 & 0x0000ff00) * a + (c2 & 0x0000ff00)) + BlendMode.tint;
        int blu = (int) ((c1 & 0x000000ff) * a + (c2 & 0x000000ff)) + BlendMode.tint;
        return 0xff000000 + (red > 0x00ff0000 ? 0x00ff0000 : red) + (grn > 0x0000ff00 ? 0x0000ff00 : grn) + (blu > 0x000000ff ? 0x000000ff : blu);
    }

Thanks for any help!

\$\endgroup\$
1
  • 2
    \$\begingroup\$ You should swap the for loops so that the inner loop is horizontal, as that would be more cache friendly. \$\endgroup\$
    – msell
    Dec 17, 2014 at 13:36

2 Answers 2

2
\$\begingroup\$

When you really want to get good performance, implement it in hardware using pixel shaders. The graphic cards GPU is optimized for performing the same operation on lots and lots of values in parallel, so it does so really quick. When you don't want to learn GPU programming, there are many libraries available which implement many common blend effects in hardware and offer them to you with an easy to use API.

However, when you are determined to create your own CPU-only solution, you can try to speed it up by using parallelization. Almost all desktop PCs (and even some mobile phones) nowadays have multi-core processors. Each core can independently execute an own thread with the full speed of the CPU. When you create multiple threads (one for each CPU core) and divide the work in a way that each CPU has its own workload and doesn't need to communicate with the others until their work is done, you will reach a much higher data throughput.

Multithreading in Java is implemented best with a ThreadPoolExecutor. To create one which uses all available processors, use the handy static constructor method Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() );.

You assign new tasks to execute in parallel by passing Runnable objects to the execute( Runnable ) method of your ThreadPoolExecutor. Multithreading works best when threads are able to work on a single task for a long time, so the tasks should be as large as possible.

However, be aware of a pitfall: You have no way to predict in which order the Runnables will be finished. This will cause problems when you want to draw images in a specific order. This is not an issue when you only use additive blending where draw order is irrelevant, but it can be a problem with many other blend modes.

\$\endgroup\$
0
2
\$\begingroup\$

I don't know what RawImage exactly is here, but once you access pixel data of a Volatile or BufferedImage in Java you lose hardware acceleration. So even if these images were stored in vram before you called renderImage, they will no longer be once you access the underlying pixel array.

\$\endgroup\$
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .