Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I've got a JOGL application in which I am rendering 1 million textures (all the same texture) and 1 million lines between those textures. Basically it's a ball-and-stick graph.

I am storing the vertices in a vertex array on the card and referencing them via index arrays, which are also stored on the card. Each pass through the draw loop I am basically doing this:

gl.glBindBuffer(GL.GL_ARRAY_BUFFER, <buffer id>);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, <buffer id>);
gl.glDrawElements(GL.GL_POINTS, <size>, GL.GL_UNSIGNED_INT, 0);

gl.glBindBuffer(GL.GL_ARRAY_BUFFER, <buffer id>);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, <buffer id>);
gl.glDrawElements(GL.GL_LINES, <size>, GL.GL_UNSIGNED_INT, 0);

I noticed that the JOGL library is pegging one of my CPU cores. Every frame, the run method internal to the library is taking quite long. I'm not sure why this is happening since I have called setHardwareAccelerated(true) on the GLCapabilities used to create my canvas.

What's more interesting is that I changed it to setHardwareAccelerated(false) and there was no impact on the performance at all.

Is it possible that my code is not using hardware rendering even when it is set to true? Is there any way to check?

EDIT:

As suggested, I have tested breaking my calls up into smaller chunks. I have tried using glDrawRangeElements and respecting the limits that it requests. All of these simply resulted in the same pegged CPU usage and worse framerates.

I have also narrowed the problem down to a simpler example where I just render 4 million textures (no lines). The draw loop then just doing this:

gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL.GL_INDEX_ARRAY);
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();

<... Camera and transform related code ...>

gl.glEnableVertexAttribArray(0);
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glAlphaFunc(GL.GL_GREATER, ALPHA_TEST_LIMIT);
gl.glEnable(GL.GL_ALPHA_TEST);  

<... Bind texture ...>

gl.glBindBuffer(GL.GL_ARRAY_BUFFER, <buffer id>);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, <buffer id>);
gl.glDrawElements(GL.GL_POINTS, <size>, GL.GL_UNSIGNED_INT, 0);

gl.glDisable(GL.GL_TEXTURE_2D);
gl.glDisable(GL.GL_ALPHA_TEST);
gl.glDisableVertexAttribArray(0);

gl.glFlush();

Where the first buffer contains 12 million floats (the x,y,z coords of the 4 million textures) and the second (element) buffer contains 4 million integers. In this simple example it is simply the integers 0 through 3999999.

I really want to know what is being done in software that is pegging my CPU, and how I can make it stop (if I can).

My buffers are generated by the following code:

gl.glBindBuffer(GL.GL_ARRAY_BUFFER, <buffer id>);
gl.glBufferData(GL.GL_ARRAY_BUFFER, <size>
    * BufferUtil.SIZEOF_FLOAT, <buffer>,
    GL.GL_STATIC_DRAW);

gl.glVertexAttribPointer(0, 3, GL.GL_FLOAT, false, 0, 0);

and:

gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, <buffer id>);
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER,
    <size> * BufferUtil.SIZEOF_INT,
    <buffer>, GL.GL_STATIC_DRAW);

ADDITIONAL INFO:

Here is my initialization code:

gl.setSwapInterval(1); //Also tried 0

gl.glShadeModel(GL.GL_SMOOTH);
gl.glClearDepth(1.0f);
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL.GL_LESS);
gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_FASTEST);

gl.glPointParameterfv(GL.GL_POINT_DISTANCE_ATTENUATION,
        POINT_DISTANCE_ATTENUATION, 0);
gl.glPointParameterfv(GL.GL_POINT_SIZE_MIN, MIN_POINT_SIZE, 0);
gl.glPointParameterfv(GL.GL_POINT_SIZE_MAX, MAX_POINT_SIZE, 0);
gl.glPointSize(POINT_SIZE);

gl.glTexEnvf(GL.GL_POINT_SPRITE, GL.GL_COORD_REPLACE, GL.GL_TRUE);
gl.glEnable(GL.GL_POINT_SPRITE);

gl.glClearColor(clearColor.getX(), clearColor.getY(),
        clearColor.getZ(), 0.0f);

Also, I'm not sure if this helps or not, but when I drag the entire graph off the screen, the FPS shoots back up and the CPU usage falls to 0%. This seems obvious and intuitive to me, but I thought that might give a hint to someone else.

share|improve this question
    
Try turning off VSync and limiting your framerate manually to see if it's the routine that waits for the VSync on your monitor which does peg a core at 100% (a problem in both DirectX and OpenGL). –  Jonathan Dickinson Mar 15 '12 at 12:14
    
I tried turning off VSync too - assuming I'm doing it correctly - and still no change. I called gl.setSwapInterval(0) to turn it off. –  Luke Mar 15 '12 at 12:45
    
have you tried profiling to see exactly which call is using the most CPU time? –  Jonathan Dickinson Mar 15 '12 at 13:00
    
See my response to @MrCranky, but yes. It's com.sun.opengl.util.FPSAnimator$1.run() and javax.media.opengl.GLCanvas$DisplayOnEventDispatchThreadAction.run() (each almost exactly 50%) –  Luke Mar 15 '12 at 13:07
    
Let me amend that statement, that was before I changed the default profiler settings. More specifically, the two functions are javax.media.opengl.Threading.invokeOnOpenGLThread() and com.sun.opengl.impl.windows.WindowsOnscreenGLDrawable.swapBuffers() - I'm looking into those deeper right now. –  Luke Mar 15 '12 at 19:28

3 Answers 3

If you weren't using hardware acceleration at all you would be getting less than 1 fps. Unless that applies we can discount that possibility.

My hunch is that your vertex pipeline has dropped back to software emulation. You're saying that you've got one million lines and you're calling glDrawElements with GL_UNSIGNED_INT, which - depending on your hardware - may be overflowing your hardware maximum for number of vertexes per draw call and max vertex index.

Note that glDrawElements itself doesn't specify these maximums, but you can bet that they do exist in hardware.

To resolve this you can try splitting up your glDrawElements calls so that your indexes fit in unsigned shorts. Yes, it's more draw calls, but it will fit within hardware limits for everything and won't choke your vertex pipeline.

share|improve this answer
    
I pulled the values of GL_MAX_ELEMENTS_VERTICES and GL_MAX_ELEMENTS_INDICES, and they are both 1,048,576. This would seem to agree with your hunch. Are you saying that I need to break my vertex array buffers (GL.GL_ARRAY_BUFFER) up into smaller chunks or just my index array buffers(GL.GL_ELEMENT_ARRAY_BUFFER)? If I had to break both up into smaller chunks, that would be nightmarish for my current application... –  Luke Mar 12 '12 at 19:49
    
You could get away with the indexes and just set new array pointers with different offsets. –  Darth Satan Mar 12 '12 at 20:35
    
Note that MAX_ELEMENTS_VERTICES and MAX_ELEMENTS_INDICES are for glDraw<b>Range</b>Elements. It has nothing to do with glDrawElements. –  Nicol Bolas Mar 13 '12 at 3:39
1  
Yup, I've noted it, and have also noted that both glDrawElements and glDrawRangeElements predate hardware T&L. Bottom line is that if a limit exists in hardware then the spec can say that the moon is a blue cube for all it matters, and this is a limit that exists in hardware. –  Darth Satan Mar 13 '12 at 11:09
    
I don't think this is it. I've narrowed the problem down to a simpler test case, which is simply rendering 4 million textures. When I draw them all in one glDrawElements call I get 19 FPS. When I split it up into chunks of 750k indexed by an int, it drops to 17 FPS, when I split it up into chunks of 32k indexed by a short it drops to 11 FPS. I also tried 32k chunks indexed by an int, it's still 11 FPS. I believe the limits are for internal performance optimization of glDrawRangeElements only and performance reverts to that of glDrawElements if the conditions are not met. –  Luke Mar 13 '12 at 14:56

My bet would be that your performance is not bound by GPU operations, and that hardware acceleration makes no difference because the amount of time spent doing the GPU work is dwarfed by 'something else'; be that marshalling on the driver side, something in the OpenGL libs itself, or even possibly your own code. The trouble is, figuring out what overhead is getting you isn't straightforward unless you know what's going on under the hood.

That diagnosis would be consistent with your reply to mh01's answer; increasing the number of draw calls to render the same primitives adds yet more overhead, while keeping the number of primitives drawn the same. Have you tried making the task less complex to see if there's one element of the problem that causes a massive drop in performance? E.g. does disabling textures but rendering the same amount of primitives work fine?

My advice would be to dig out a sampling profiler (something that breaks into your process every X microseconds and grabs the callstack), and see which module it's spending all this time in.

share|improve this answer
    
I ran jvisualvm and determined that the slowdown was not in my user code. The functions using all the CPU are com.sun.opengl.util.FPSAnimator$1.run() and javax.media.opengl.GLCanvas$DisplayOnEventDispatchThreadAction.run(). I have stripped the code down. I tried disabling textures, depth testing, alpha testing, etc. Nothing seemed to help performance at all. Further, there shouldn't be much that needs marshalled. If I understand correctly my code should simply tell the card the address and number of points to draw. It's not like it's sending the whole buffer each frame. –  Luke Mar 15 '12 at 12:20
    
The deeper functions called by those 2 functions are actually: javax.media.opengl.Threading.invokeOnOpenGLThread() and com.sun.opengl.impl.windows.WindowsOnscreenGLDrawable.swapBuffers() –  Luke Mar 15 '12 at 19:29
    
Hmm, a spin-wait in swapBuffers is consistent with a heavy GPU load , so that probably rules my theory out. –  MrCranky Mar 17 '12 at 8:44
up vote 1 down vote accepted

The answer is that the GPU was taking too long to render the frame and subsequent frames ended up doing a CPU intensive busy wait before moving onto the next frame.

The busy wait was occurring in: com.sun.opengl.impl.windows.WindowsOnscreenGLDrawable.swapBuffers()

The solution was 2 fold.

First, to prevent frames from backing up I changed my FPSAnimator to have scheduleAtFixedRate as false. That is:

new FPSAnimator(canvas, 30, false);

The second change was to render my entire scene into a Framebuffer Object and simply draw the Framebuffer Object to the screen each frame. Since my scene is mostly static, I was able to use this to increase the FPS while my scene is not changing. When the scene does change, I render it to the Framebuffer Object again.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.