Performance Issues while rendering tiled map

Started by Nitram, November 20, 2009, 23:41:43

Previous topic - Next topic

Nitram

Hello,

I have a few performance problems with a application I'm writing. The program displays a map, some objects and figures on it.
The map is completly tile based and it can't be presumed how the map will look like, since the data of the map is received from a server and can change at any time. So every tile, object and character on the map is a single individual sprite.

At the last test I got 1582 sprites on the screen. Those sprites are rendered as a square with GL11.GL_TRIANGLE_STRIP using glBegin, glTexCoord2f, glVertex2f, glEnd. Doing it this way the programm still runs barely with 70FPS. While there are alot of things done in the background, the main time consumed goes for the render actions.

I tried to improve the performance using display lists. Sadly its not possible to compile more then one such GL11.GL_TRIANGLE_STRIP to one display lists. It leads to 1582 display lists I got now and the client performance went up to about 77FPS.

I was also thinking about using VBOs. But they got the major problem (at least I think so) that I can't switch the texture that is used at the rendering. And since I got nearly 60 different textures in use all time and the context is switching basically with every rendered sprite, the effectivity of the VBOs won't be really good.

It looks to me that I'm at the limits of the render method I'm using. Now my question is, not I can speed the rendering up further. I'm only rendering textures on a orthogonal screen. Entirely 2D and all graphics are rendered in the way as they have to overlap from the bottom to the top of the stack. So bascially currently I don't use any part of the 3D function of OpenGL at all.

Does anyone could give me a hint how to improve my rendering? Or are there further informations needed to give a proper answer?

Regards,
Nitram

Rene

It might be your graphics hardware. If you're using something like an Intel chipset, I don't think you can get a lot more out of it. Texturing is very expensive on hardware like that.

Can you give some specification on your hardware? And the renderer's code would be useful, too.
When I am king, they shall not have bread and shelter only, but also teachings out of books, for a full belly is little worth where the mind is starved - Mark Twain

Nitram

Alright.

My development maschine is a DELL XPS M1710.
Intel Core 2 Duo T7200 @ 2.00GHz
4GB Ram
Nvidia GeForce Go 7900 GS - 256MB exclusive VRam

Windows 7 Professional x64
JDK 1.6.0_17 32bit/64bit (tried both)

The rendering itself goes pretty the straight forward way...
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_POLYGON_SMOOTH);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture.getTextureID());
GL11.glShadeModel(GL11.GL_FLAT);

GL11.glBegin(GL11.GL_TRIANGLE_STRIP);
GL11.glTexCoord2f(texture.getRelX2(), texture.getRelY2());
GL11.glVertex2f(0, 0);
GL11.glTexCoord2f(texture.getRelX2(), texture.getRelY1());
GL11.glVertex2f(0, height);
GL11.glTexCoord2f(texture.getRelX1(), texture.getRelY2());
GL11.glVertex2f(width, 0);
GL11.glTexCoord2f(texture.getRelX1(), texture.getRelY1());
GL11.glVertex2f(width, height);
GL11.glEnd();


Those lines are called at every render event. I maybe still could optimize those first 4 lines a little, but I have doubts that this would lead to a major increase of the performance.

The textures I use, are multiple small textures packed together on larger textures to decrease the amount of needed textures. The object behind "texture" in the code sample points to one of the small textures. The supplied values are not calculated at every turn, they are stored, so the time to fetch those should be minimal.

Nitram

EDIT:
Okay I tried to optimize the amount of needed driver calls by calling those things like glEnable etc. only in case its really needed. The improvement was low, as expected. For some strange reason it caused that the FPS count became unstable. It moves between 60FPS and 80FPS.

Rene

You said all textures are packed into one big ones?

Please make sure the big texture has power of two width and height.  Current hardware can use non-POT textures, but at a performance cost.

Also, if you're using only a few textures, you shouldn't call glBindTexture every time you're going to draw. First check to see which one is currently bound. Binding textures is quite an expensive operation. To make this more useful, try to make your drawing process draw quads using the same texture directly after each other.

Last, check the size of the texture and the maximum size supported by your graphics hardware. If you make the texture bigger than that, my guess is GL will store the texture in system memory instead of GPU memory, but I'm not sure about that.
When I am king, they shall not have bread and shelter only, but also teachings out of books, for a full belly is little worth where the mind is starved - Mark Twain

Nitram

All textures are packed into bigger ones. The bigger ones are at all time 1024px * 1024px or smaller, but always power of 2. The placement of the small textures on the large one is precalculated in a pretty time expensive way. Currently we are talking about around 80000 small textures packed to 60 large textures with a waste of texture space <1%. The calculation of the placement takes currently about 2h. So thats nothing to be done at loading the client.

The calls of glBindTexture are optimized now so thats only called in case its really needed to bind another texture. Sadly I can really optimize the order how the quads are rendered because its needed that the render order fits to the order how the textures have to overlap each other. So changing the order would only work by using the depth text I think. But this one would mess the transparency of the textures up.

Nitram

broumbroum

Quote from: Nitram on November 21, 2009, 12:15:45
I tried to improve the performance using display lists. Sadly its not possible to compile more then one such GL11.GL_TRIANGLE_STRIP to one display lists. It leads to 1582 display lists I got now and the client performance went up to about 77FPS.

77 FPS is quite sufficient,  isn't it though ? OpenGL always get things cached as needed, then nothing to worry anymore... You might define HOW caching is processed, as the gLPrioritizeTexture definition.

Nitram

77 Frames are fine on my computer. How ever this test did not run on the maximal resolution and there is about 50% of the render content lacking to fill the screen correctly. Also the whole GUI is missing and the particle engine is not running. So there are a few things that will still comsume a descent amount of runtime performance.

A question about VBOs:

If I put in a mapped VBO data buffer and update the data for every element that is drawn, would that increase the drawing performance?

Nitram

Rene

The VBO approach would be slower. Usually, display lists are faster than VBO's.

But please try to draw sorted on texture, even if the visuals will be incorrect.  We can think for a solution for that problem if it gives a significant performance gain.
When I am king, they shall not have bread and shelter only, but also teachings out of books, for a full belly is little worth where the mind is starved - Mark Twain

Nitram

Okay I wrote a set of texture renders that are easily replaceable so I can do some tests.

First test was done by rendering scene 1 (low complexity) at a resolution of 1768px * 992px * 32bit
Screenshot

Immediate Texture Render: 120fps
Displaylist Texture Render: 123fps
Array Pointer Texture Render: 121fps
VBO Texture Render: 60fps

Second test was done by rendering scene 1 (low complexity) at a resolution of 1024px * 768px * 32bit
Screenshot

Immediate Texture Render: 235fps
Displaylist Texture Render: 240fps
Array Pointer Texture Render: 245fps
VBO Texture Render: 91fps

Third test was done by rendering scene 2 (high complexity) at a resolution of 1768px * 992px * 32bit
Screenshot

Immediate Texture Render: 71fps
Displaylist Texture Render: 103fps
Array Pointer Texture Render: 105fps
VBO Texture Render: 55fps

Fourth test was done by rendering scene 2 (high complexity) at a resolution of 1024px * 768px * 32bit
Screenshot

Immediate Texture Render: 115fps
Displaylist Texture Render: 114fps
Array Pointer Texture Render: 116fps
VBO Texture Render: 50fps

Immediate Texture Render Source
package illarion.graphics.lwjgl.render;

import illarion.graphics.SpriteColor;
import illarion.graphics.lwjgl.DriverSettingsLWJGL;
import illarion.graphics.lwjgl.TextureLWJGL;

import org.lwjgl.opengl.GL11;

/**
 * This texture render uses the immediate methods to render a texture.
 * 
 * @author Martin Karing
 * @since 1.22
 */
public final class TextureRenderImmediate extends AbstractTextureRender {
    /**
     * The singleton instance of this class.
     */
    private static final TextureRenderImmediate INSTANCE =
        new TextureRenderImmediate();

    /**
     * Get the singleton instance of this class.
     * 
     * @return the singleton instance of the immediate texture render
     */
    public static TextureRenderImmediate getInstance() {
        return INSTANCE;
    }

    /**
     * Private constructor to avoid anything creating a instance of this
     * renderer but singleton instance.
     */
    private TextureRenderImmediate() {
        // nothing to do
    }

    /**
     * Draw a texture at a specified location using the immediate mode.
     * 
     * @param x the x coordinate of the texture
     * @param y the y coordinate of the texture
     * @param z the z coordinate (so the layer) of the texture
     * @param width the width of the area the texture shall be rendered on
     * @param height the height of the area the texture shall be rendered on
     * @param texture the texture that shall be drawn
     * @param color the color that is supposed to be used with that texture
     * @param mirror mirror the texture horizontal
     */
    @Override
    public void drawTexture(final float x, final float y, final float z,
        final float width, final float height, final TextureLWJGL texture,
        final SpriteColor color, final boolean mirror) {

        DriverSettingsLWJGL.getInstance().enableTexture(texture.getTextureID());
        color.setActiveColor();

        GL11.glBegin(GL11.GL_TRIANGLE_STRIP);

        if (mirror) {
            GL11.glTexCoord2f(texture.getRelX2(), texture.getRelY2());
            GL11.glVertex2f(x, y);
            GL11.glTexCoord2f(texture.getRelX2(), texture.getRelY1());
            GL11.glVertex2f(x, y + height);
            GL11.glTexCoord2f(texture.getRelX1(), texture.getRelY2());
            GL11.glVertex2f(x + width, y);
            GL11.glTexCoord2f(texture.getRelX1(), texture.getRelY1());
            GL11.glVertex2f(x + width, y + height);
        } else {
            GL11.glTexCoord2f(texture.getRelX1(), texture.getRelY2());
            GL11.glVertex2f(x, y);
            GL11.glTexCoord2f(texture.getRelX1(), texture.getRelY1());
            GL11.glVertex2f(x, y + height);
            GL11.glTexCoord2f(texture.getRelX2(), texture.getRelY2());
            GL11.glVertex2f(x + width, y);
            GL11.glTexCoord2f(texture.getRelX2(), texture.getRelY1());
            GL11.glVertex2f(x + width, y + height);
        }

        GL11.glEnd();
    }
}


Displaylist Texture Render Source:
package illarion.graphics.lwjgl.render;

import illarion.graphics.SpriteColor;
import illarion.graphics.lwjgl.DriverSettingsLWJGL;
import illarion.graphics.lwjgl.TextureLWJGL;

import gnu.trove.TIntIntHashMap;
import gnu.trove.TIntObjectHashMap;

import org.lwjgl.opengl.GL11;

/**
 * This texture render is drawing the graphics by using display lists.
 * 
 * @author Martin Karing
 * @since 1.22
 */
public final class TextureRenderDisplaylist extends AbstractTextureRender {
    /**
     * Get a new instance of this class.
     * 
     * @return get a new instance of the display list render
     */
    public static TextureRenderDisplaylist getInstance() {
        return new TextureRenderDisplaylist();
    }

    /**
     * The IDs of display lists stored in this instance of the texture render.
     */
    private TIntIntHashMap displayLists = new TIntIntHashMap();

    /**
     * The IDs of display lists for mirrored render events stored in this
     * texture render.
     */
    private TIntIntHashMap displayListsMirror = new TIntIntHashMap();

    /**
     * The last dimensions that were rendered to check if the display list is
     * still valid.
     */
    private TIntObjectHashMap<float[]> lastDimentions =
        new TIntObjectHashMap<float[]>();

    /**
     * Private constructor so new instances are only fetched by the
     * {@link #getInstance()} method.
     */
    private TextureRenderDisplaylist() {
        // nothing to do
    }

    /**
     * Draw a texture using display lists at a specified location.
     * 
     * @param x the x coordinate of the texture
     * @param y the y coordinate of the texture
     * @param z the z coordinate (so the layer) of the texture
     * @param width the width of the area the texture shall be rendered on
     * @param height the height of the area the texture shall be rendered on
     * @param texture the texture that shall be drawn
     * @param color the color that is supposed to be used with that texture
     * @param mirror mirror the texture horizontal
     */
    @Override
    public void drawTexture(final float x, final float y, final float z,
        final float width, final float height, final TextureLWJGL texture,
        final SpriteColor color, final boolean mirror) {

        GL11.glPushMatrix();
        final int textureID = texture.getUID();
        DriverSettingsLWJGL.getInstance().enableTexture(texture.getTextureID());
        color.setActiveColor();

        GL11.glTranslatef(x, y, z);

        TIntIntHashMap usedDisplayList;
        if (mirror) {
            usedDisplayList = displayListsMirror;
        } else {
            usedDisplayList = displayLists;
        }

        float[] textureSize = lastDimentions.get(textureID);
        if (textureSize == null) {
            textureSize = new float[2];
            lastDimentions.put(textureID, textureSize);
        }

        int displayList = usedDisplayList.get(textureID);
        boolean newList = false;

        if ((textureSize[0] != width) || (textureSize[1] != height)) {
            newList = true;
        }

        if (displayList < 1) {
            displayList = GL11.glGenLists(1);
            usedDisplayList.put(textureID, displayList);
            newList = true;
        }

        if (newList) {
            textureSize[0] = width;
            textureSize[1] = height;

            GL11.glNewList(displayList, GL11.GL_COMPILE);
            GL11.glBegin(GL11.GL_TRIANGLE_STRIP);

            if (mirror) {
                GL11.glTexCoord2f(texture.getRelX2(), texture.getRelY2());
                GL11.glVertex2f(0, 0);
                GL11.glTexCoord2f(texture.getRelX2(), texture.getRelY1());
                GL11.glVertex2f(0, height);
                GL11.glTexCoord2f(texture.getRelX1(), texture.getRelY2());
                GL11.glVertex2f(width, 0);
                GL11.glTexCoord2f(texture.getRelX1(), texture.getRelY1());
                GL11.glVertex2f(width, height);
            } else {
                GL11.glTexCoord2f(texture.getRelX1(), texture.getRelY2());
                GL11.glVertex2f(0, 0);
                GL11.glTexCoord2f(texture.getRelX1(), texture.getRelY1());
                GL11.glVertex2f(0, height);
                GL11.glTexCoord2f(texture.getRelX2(), texture.getRelY2());
                GL11.glVertex2f(width, 0);
                GL11.glTexCoord2f(texture.getRelX2(), texture.getRelY1());
                GL11.glVertex2f(width, height);
            }

            GL11.glEnd();
            GL11.glEndList();
        }

        GL11.glCallList(displayList);
        GL11.glPopMatrix();
    }
}


Array Pointer Texture Render Source
package illarion.graphics.lwjgl.render;

import illarion.graphics.SpriteColor;
import illarion.graphics.lwjgl.DriverSettingsLWJGL;
import illarion.graphics.lwjgl.TextureLWJGL;

import java.nio.FloatBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;

/**
 * This texture render uses array pointers to render a texture.
 * 
 * @author Martin Karing
 * @since 1.22
 */
public final class TextureRenderPointer extends AbstractTextureRender {
    /**
     * The singleton instance of this class.
     */
    private static final TextureRenderPointer INSTANCE =
        new TextureRenderPointer();

    /**
     * Get the singleton instance of this class.
     * 
     * @return the singleton instance of the texture pointer render
     */
    public static TextureRenderPointer getInstance() {
        return INSTANCE;
    }

    /**
     * The buffer that is used to store the texture coordinate data.
     */
    private final FloatBuffer textureBuffer = BufferUtils.createFloatBuffer(8);

    /**
     * The buffer that is used to store the vertex data.
     */
    private final FloatBuffer vertexBuffer = BufferUtils.createFloatBuffer(12);

    /**
     * Private constructor so new instances are only fetched by the
     * {@link #getInstance()} method.
     */
    private TextureRenderPointer() {
        // nothing to do
    }

    /**
     * Draw a texture using buffer pointers and draw arrays.
     * 
     * @param x the x coordinate of the texture
     * @param y the y coordinate of the texture
     * @param z the z coordinate (so the layer) of the texture
     * @param width the width of the area the texture shall be rendered on
     * @param height the height of the area the texture shall be rendered on
     * @param texture the texture that shall be drawn
     * @param color the color that is supposed to be used with that texture
     * @param mirror mirror the texture horizontal
     */
    @Override
    public void drawTexture(final float x, final float y, final float z,
        final float width, final float height, final TextureLWJGL texture,
        final SpriteColor color, final boolean mirror) {

        DriverSettingsLWJGL.getInstance().enableTexturePointer(
            texture.getTextureID());

        color.setActiveColor();

        vertexBuffer.rewind();
        textureBuffer.rewind();
        if (mirror) {
            vertexBuffer.put(x).put(y);
            textureBuffer.put(texture.getRelX2()).put(texture.getRelY2());

            vertexBuffer.put(x).put(y + height);
            textureBuffer.put(texture.getRelX2()).put(texture.getRelY1());

            vertexBuffer.put(x + width).put(y);
            textureBuffer.put(texture.getRelX1()).put(texture.getRelY2());

            vertexBuffer.put(x + width).put(y + height);
            textureBuffer.put(texture.getRelX1()).put(texture.getRelY1());
        } else {
            vertexBuffer.put(x).put(y);
            textureBuffer.put(texture.getRelX1()).put(texture.getRelY2());

            vertexBuffer.put(x).put(y + height);
            textureBuffer.put(texture.getRelX1()).put(texture.getRelY1());

            vertexBuffer.put(x + width).put(y);
            textureBuffer.put(texture.getRelX2()).put(texture.getRelY2());

            vertexBuffer.put(x + width).put(y + height);
            textureBuffer.put(texture.getRelX2()).put(texture.getRelY1());
        }

        vertexBuffer.flip();
        textureBuffer.flip();

        GL11.glTexCoordPointer(2, 0, textureBuffer);
        GL11.glVertexPointer(2, 0, vertexBuffer);

        GL11.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, 4);
    }
}


VBO Texture Render Source:
package illarion.graphics.lwjgl.render;

import illarion.graphics.SpriteColor;
import illarion.graphics.lwjgl.DriverSettingsLWJGL;
import illarion.graphics.lwjgl.TextureLWJGL;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import gnu.trove.TIntIntHashMap;
import gnu.trove.TIntObjectHashMap;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.ARBBufferObject;
import org.lwjgl.opengl.ARBVertexBufferObject;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GLContext;

/**
 * Texture render using vertex buffer objects in order to render the textures.
 * This texture render require the ARB extension for VBO rendering.
 * 
 * @author Martin Karing
 * @since 1.22
 */
public final class TextureRenderVBO extends AbstractTextureRender {

    /**
     * The byte offset of the texture data within the stride.
     */
    private static final int OFFSET_TEXTURE = 2 * Float.SIZE / 8;

    /**
     * The byte offset of the vertex data within the stride.
     */
    private static final int OFFSET_VERTEX = 0;

    /**
     * The length of one strife that contains vertex and texture coordinates in
     * byte.
     */
    private static final int STRIDE = (2 + 2) * Float.SIZE / 8;

    static {
        final int indexID = genBufferID();

        final IntBuffer indexBuffer = BufferUtils.createIntBuffer(4);
        indexBuffer.put(0).put(1).put(2).put(3);
        indexBuffer.flip();

        ARBBufferObject.glBindBufferARB(
            ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, indexID);
        ARBBufferObject.glBufferDataARB(
            ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, indexBuffer,
            ARBBufferObject.GL_STATIC_DRAW_ARB);
    }

    /**
     * Generate a new ID for a VBO Buffer.
     * 
     * @return the generated ID
     */
    private static int genBufferID() {
        final IntBuffer intBuf = BufferUtils.createIntBuffer(1);
        ARBBufferObject.glGenBuffersARB(intBuf);
        return intBuf.get(0);
    }

    /**
     * Get a instance of this class.
     * 
     * @return a instance of the texture VBO render
     */
    public static TextureRenderVBO getInstance() {
        return new TextureRenderVBO();
    }

    /**
     * The buffer that is used to store texture and vertex data.
     */
    private final FloatBuffer buffer =
        BufferUtils.createFloatBuffer(STRIDE * 4);

    /**
     * The last dimensions that were rendered to check if the display list is
     * still valid.
     */
    private TIntObjectHashMap<float[]> lastDimentions =
        new TIntObjectHashMap<float[]>();

    /**
     * The IDs of VBOs stored in this instance of the texture render.
     */
    private TIntIntHashMap vboIDs = new TIntIntHashMap();

    /**
     * The IDs of VBOs for mirrored render events stored in this texture render.
     */
    private TIntIntHashMap vboIDsMirror = new TIntIntHashMap();

    /**
     * Private constructor so new instances are only fetched by the
     * {@link #getInstance()} method.
     */
    @SuppressWarnings("nls")
    private TextureRenderVBO() {
        if (!GLContext.getCapabilities().GL_ARB_vertex_buffer_object) {
            throw new IllegalStateException("VBO not supported");
        }
    }

    @Override
    public void drawTexture(final float x, final float y, final float z,
        final float width, final float height, final TextureLWJGL texture,
        final SpriteColor color, final boolean mirror) {

        final int textureID = texture.getUID();
        DriverSettingsLWJGL.getInstance().enableTexturePointer(
            texture.getTextureID());

        GL11.glPushMatrix();
        color.setActiveColor();
        GL11.glTranslatef(x, y, z);

        TIntIntHashMap usedVBOs;
        if (mirror) {
            usedVBOs = vboIDsMirror;
        } else {
            usedVBOs = vboIDs;
        }

        float[] textureSize = lastDimentions.get(textureID);
        if (textureSize == null) {
            textureSize = new float[2];
            lastDimentions.put(textureID, textureSize);
        }

        int vboID = usedVBOs.get(textureID);
        boolean newVBO = false;

        if ((textureSize[0] != width) || (textureSize[1] != height)) {
            newVBO = true;
        }

        if (vboID < 1) {
            vboID = genBufferID();
            usedVBOs.put(textureID, vboID);
            newVBO = true;
        }

        ARBBufferObject.glBindBufferARB(
            ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, vboID);

        if (newVBO) {
            GL11.glVertexPointer(2, GL11.GL_FLOAT, STRIDE, OFFSET_VERTEX);
            GL11.glTexCoordPointer(2, GL11.GL_FLOAT, STRIDE, OFFSET_TEXTURE);

            buffer.rewind();
            if (mirror) {
                buffer.put(0).put(0);
                buffer.put(texture.getRelX2()).put(texture.getRelY2());

                buffer.put(0).put(height);
                buffer.put(texture.getRelX2()).put(texture.getRelY1());

                buffer.put(width).put(0);
                buffer.put(texture.getRelX1()).put(texture.getRelY2());

                buffer.put(width).put(height);
                buffer.put(texture.getRelX1()).put(texture.getRelY1());
            } else {
                buffer.put(0).put(0);
                buffer.put(texture.getRelX1()).put(texture.getRelY2());

                buffer.put(0).put(height);
                buffer.put(texture.getRelX1()).put(texture.getRelY1());

                buffer.put(width).put(0);
                buffer.put(texture.getRelX2()).put(texture.getRelY2());

                buffer.put(width).put(height);
                buffer.put(texture.getRelX2()).put(texture.getRelY1());
            }
            buffer.flip();

            ARBBufferObject.glBufferDataARB(
                ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, buffer,
                ARBBufferObject.GL_STREAM_DRAW_ARB);
        }

        GL12.glDrawRangeElements(GL11.GL_TRIANGLE_STRIP, 0, 4, 4,
            GL11.GL_UNSIGNED_INT, 0);

        GL11.glPopMatrix();
    }
}


So the VBO's are not really useable in this case. The other texture renders work pretty good, only the immediate mode goes at its limits in case the render screen is large and the scene contains alot of images.

I will try now sorting the images by the textures to see how much the render speed is improved by this.

Nitram

Nitram

Alright.

Tried the thing with the sorted textures.
The results are not really as perfect as they could be. Because I get the textures into the renderer in the same way as before. I just store them now and render them once all data is collected in the odered way.

I tried the complex scene at the large resolution. As expected the graphics are messed up entirely.
The ordered graphics are send after to the unchanged texture renders in the last post.

Immediate Texture Render: 96fps
Displaylist Texture Render: 90fps
Array Pointer Texture Render: 130fps
VBO Texture Render: 58fps

So yet it looks like collecting the graphics and rendering them ordered takes as long as switching the texture binds.

Nitram

Rene

To be honest, I'm running out of ideas :(

When you profile the application, where is the majority of the time spent? Also, if you use the non-debug build of lwjgl, does it make a difference?
When I am king, they shall not have bread and shelter only, but also teachings out of books, for a full belly is little worth where the mind is starved - Mark Twain

Nitram

Well, if you are running out of idea you get to the point where I am ;-) Makes me feel better some way.

Anyway. The profiling shows that the majority is really invested into the drawing functions. The rest of the application (map management, light calculation, etc.) is all multithreaded and works really fast. Just the drawing takes that long. Really a pitty that you can't multithread the drawing operations.

Anyway. There is a non-debug build of lwjgl?!

Nitram

Rene

There are 6 lwjgl jars: jinput, lwjgl, lwjgl_test, lwjgl_util, lwjgl_util_applet, and lwjgl-debug. lwjgl-debug and lwjgl are the same, but the debug version does some extra error checking and things like that. You might want to try running the application with the debug jar temporarily removed from your project to test the performance gain. I recommend using it during development though.
When I am king, they shall not have bread and shelter only, but also teachings out of books, for a full belly is little worth where the mind is starved - Mark Twain

Nitram

I never had the debug version in. Its not that I want to debug LWJGL ;)

So it runs already with the "fast" version.

Rene

The error checking the debug version does is to ease your job. If you're doing something wrong, it'll give you an error message so it becomes easier to find the bug.

But sorry I couldn't be much help. Maybe someone else around here has some more idea's.


Btw, does your project have a website? Those screenshots look pretty neat :)
When I am king, they shall not have bread and shelter only, but also teachings out of books, for a full belly is little worth where the mind is starved - Mark Twain