Why are display lists running faster than VBOs in my game?

I created two simple voxel engines, literally just chunks that hold cubes. For the first one, I use display lists and can render hundreds of chunks at 60 FPS no problem, despite the fact that the technology behind it is years old and deprecated by now. With my VBO version, I try to render 27 chunks and I suddenly drop to less than 50 FPS. What gives? I use shaders for my VBO version, but not for display list one. Without shaders for the VBO version, I still get the same FPS rate. I’ll post some relevant code:

VBO

Initialization of chunk:


    public void initGL() {
		rand = new Random();
		
		sizeX = (int) pos.getX() + CHUNKSIZE;
		sizeY = (int) pos.getY() + CHUNKSIZE;
		sizeZ = (int) pos.getZ() + CHUNKSIZE;

		tiles = new byte[sizeX][sizeY][sizeZ];

		vCoords = BufferUtils.createFloatBuffer(CHUNKSIZE * CHUNKSIZE * CHUNKSIZE * (3 * 4 * 6));
		cCoords = BufferUtils.createFloatBuffer(CHUNKSIZE * CHUNKSIZE * CHUNKSIZE * (4 * 4 * 6));

		createChunk();

		verticeCount = CHUNKSIZE * CHUNKSIZE * CHUNKSIZE * (4 * 4 * 6);

		vCoords.flip();
		cCoords.flip();

		vID = glGenBuffers();
		glBindBuffer(GL_ARRAY_BUFFER, vID);
		glBufferData(GL_ARRAY_BUFFER, vCoords, GL_STATIC_DRAW);
		glBindBuffer(GL_ARRAY_BUFFER, 0);

		cID = glGenBuffers();
		glBindBuffer(GL_ARRAY_BUFFER, cID);
		glBufferData(GL_ARRAY_BUFFER, cCoords, GL_STATIC_DRAW);
		glBindBuffer(GL_ARRAY_BUFFER, 0);
	}
    private void createChunk() {
		for (int x = (int) pos.getX(); x < sizeX; x++) {
			for (int y = (int) pos.getY(); y < sizeY; y++) {
				for (int z = (int) pos.getZ(); z < sizeZ; z++) {
					if (rand.nextBoolean() == true) {
						tiles[x][y][z] = Tile.Grass.getId();
					} else {
						tiles[x][y][z] = Tile.Void.getId();
					}
					vCoords.put(Shape.createCubeVertices(x, y, z, 1));
					cCoords.put(Shape.getCubeColors(tiles[x][y][z]));
				}
			}
		}
	}

And then rendering:


    public void render() {
		glBindBuffer(GL_ARRAY_BUFFER, vID);
		glVertexPointer(3, GL_FLOAT, 0, 0L);

		glBindBuffer(GL_ARRAY_BUFFER, cID);
		glColorPointer(4, GL_FLOAT, 0, 0L);

		glEnableClientState(GL_VERTEX_ARRAY);
		glEnableClientState(GL_COLOR_ARRAY);

		shader.use();
		glDrawArrays(GL_QUADS, 0, verticeCount);
		shader.release();

		glDisableClientState(GL_COLOR_ARRAY);
		glDisableClientState(GL_VERTEX_ARRAY);
	}

I know I use quads, and that’s bad, but I’m also using quads for my display list engine. The shaders are very simple, all they do is take a color and apply it to the vertices, I won’t even post them they are that simple.

Display List

Initialization:


    public void init() {
		rand = new Random();

		opaqueID = glGenLists(1);

		tiles = new byte[(int) lPosition.x][(int) lPosition.y][(int) lPosition.z];

		genRandomWorld();
		rebuild();
	}
    public void rebuild() {
		glNewList(opaqueID, GL_COMPILE);
		glBegin(GL_QUADS);
		for (int x = (int) sPosition.x; x < (int) lPosition.x; x++) {
			for (int y = (int) sPosition.y; y < (int) lPosition.y; y++) {
				for (int z = (int) sPosition.z; z < (int) lPosition.z; z++) {
					if (checkCubeHidden(x, y, z)) {
						// check if tiles hidden. if not, add vertices to
						// display list
						if (type != 0) {
							Tile.getTile(tiles[x][y][z]).getVertices(x, y, z, 1, spritesheet.getTextureCoordsX(tiles[x][y][z]), spritesheet.getTextureCoordsY(tiles[x][y][z]));
						} else {
							Tile.getTile(tiles[x][y][z]).getVertices(x, y, z, 1);
						}
					}
				}
			}
		}
		glEnd();
		glEndList();
		spritesheet.bind();
	}

I should note that in my display list version, I only add in the visible cubes. So, that may be an unfair advantage, but it should not bring the VBO version down to that FPS with just 27 chunks versus 500 chunks for the display list version.
I render like this:


    public void render() {
		if (tiles.length != -1) {
			glEnable(GL_BLEND);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glCallList(opaqueID);
		}
	}

So, after all of that code, I really still wonder why my VBO version is just so darn slow? I do have a one dimensional list of chunks in my display list version for when I’m calling them to render, and a 3 dimensional one in my VBO version, but I think the JVM pretty much eliminates any lag with the extra dimensions. So, what am I doing wrong?

Edit: I just turned off individual block culling in my display list version and it still ran just as fast, albeit the start up time was slower, as expected.