Odd frame rate fluctuation when using glm::rotate.

Started by
4 comments, last by Ashaman73 10 years, 10 months ago

I wrote a simple instancing demo for a member here. The demo just creates a cube composed of 512 instances of a cube and the view rotates around this by updating the MVP matrix with glm::rotate. I noticed that the framerate was fluctuating in an almost sinusoidal fashion and this led me to the rotate function. The frame rate goes from a high of around .75 ms/frame to a low of around 1.5 ms/frame. This isn't too bad, but what I find curious, and my main question is, why is this not constant? I tested it and it seems that the frame rate spikes when the angle is 180° and drops to the low point at 0°.

Is this normal? I took a look at the source for glm::rotate, but couldn't find anything wrong. This leads me to believe that I am doing something wrong.

Here is the source:


 
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
MSG msg;
BOOL done;
gl_win_app app_instance;
RECT bounds;
 
float angle;
float aspect;
float fov;
 
GLuint mvp_matrix_loc;
GLuint texture_loc;
GLuint instance_matrix_loc;
GLuint loc_1,loc_2,loc_3,loc_4;
 
glm::mat4 projection;
glm::mat4 view;
glm::mat4 mvp;
 
fov = 60.0f;
 
SetupConsole();
 
app_instance.InitializeApp("GL Instance Test");
 
app_instance.RegisterAppClass(hInstance);
app_instance.CreateAppWindow("GL Instance Test",WS_EX_APPWINDOW,WS_CAPTION | WS_SYSMENU | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,10,10,1000,1000,false);
app_instance.ShowAppWindow(true);
app_instance.SetAppWindowForeground();
app_instance.SetAppWindowFocus();
 
glClearColor(1.0f,1.0f,1.0f,1.0f);
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
 
done = false;
 
GetClientRect(app_instance.h_wnd,&bounds);
bounds.bottom += GetSystemMetrics(SM_CYCAPTION) + (GetSystemMetrics(SM_CYFRAME) * 3) + (GetSystemMetrics(SM_CYBORDER) * 3);
bounds.right += (GetSystemMetrics(SM_CXFRAME) * 3) + (GetSystemMetrics(SM_CXBORDER) * 3);
 
aspect = float(bounds.right) / float(bounds.bottom);
 
projection = glm::perspective(fov,aspect,0.1f,1000.0f);
view = glm::lookAt(glm::vec3(0.0,0.0,25.0),glm::vec3(0.0,0.0,-25.0),glm::vec3(0,1,0));
 
shader = LoadShaders("data/instance.vs","data/instance.fs");
 
limestone.LoadTexture("data/limestone.tga");
 
CreateInstanceMatrices();
LoadCube();
 
glBindTexture(GL_TEXTURE_2D,limestone.GetTextureID());
glActiveTexture(GL_TEXTURE0);
glUniform1i(limestone.GetTextureID(),0);
 
mvp_matrix_loc = glGetUniformLocation(shader,"MVP");
texture_loc = glGetUniformLocation(shader,"texture_sampler");
 
instance_matrix_loc = glGetAttribLocation(shader,"instance_matrix");
loc_1 = instance_matrix_loc + 0;
loc_2 = instance_matrix_loc + 1;
loc_3 = instance_matrix_loc + 2;
loc_4 = instance_matrix_loc + 3;
 
glUseProgram(shader);
 
angle = 0.0f;
 
while(!done)
{
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
if(msg.message == WM_QUIT){
done = true;
}else{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}else{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
mvp = projection * view * glm::rotate(glm::mat4(),angle,glm::vec3(0.0,1.0,1.0));
angle += 0.025f;
if(angle > 360.0f)
angle = 0.0f;
 
glBindBuffer(GL_ARRAY_BUFFER,matrix_vbo);
 
glEnableVertexAttribArray(loc_1);
glEnableVertexAttribArray(loc_2);
glEnableVertexAttribArray(loc_3);
glEnableVertexAttribArray(loc_4); 
 
glVertexAttribPointer(loc_1,4,GL_FLOAT,GL_FALSE,sizeof(GLfloat) * 4 * 4,(void*)(0));
glVertexAttribPointer(loc_2,4,GL_FLOAT,GL_FALSE,sizeof(GLfloat) * 4 * 4,(void*)(sizeof(float) * 4));
glVertexAttribPointer(loc_3,4,GL_FLOAT,GL_FALSE,sizeof(GLfloat) * 4 * 4,(void*)(sizeof(float) * 8));
glVertexAttribPointer(loc_4,4,GL_FLOAT,GL_FALSE,sizeof(GLfloat) * 4 * 4,(void*)(sizeof(float) * 12)); 
 
glVertexAttribDivisor(loc_1,1);
glVertexAttribDivisor(loc_2,1);
glVertexAttribDivisor(loc_3,1);
glVertexAttribDivisor(loc_4,1);
 
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER,vertexbuffer);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,20,BUFFER_OFFSET(0));
glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,20,BUFFER_OFFSET(12));
 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,elementbuffer);
 
glUniformMatrix4fv(mvp_matrix_loc,1,GL_FALSE,glm::value_ptr(mvp));
 
glDrawElementsInstanced(GL_TRIANGLES,index_array.size(),GL_UNSIGNED_INT,BUFFER_OFFSET(0),matrices.size());
 
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
 
app_instance.gl_context.SwapBuffers();
}
}
 
glUseProgram(0);
 
// Cleanup VBO and shader
glDeleteBuffers(1,&vertexbuffer);
glDeleteBuffers(1,&matrix_vbo);
glDeleteBuffers(1,&elementbuffer);
 
glDeleteProgram(shader);
 
FreeConsole();
 
app_instance.ReleaseApp();
 
return(msg.wParam);
}
Advertisement

Nothing?unsure.png

Since you're only calling glm::rotate once per frame, it's extremely unlikely that it's overhead is even remotely near sufficient to cause this kind of performance drop.

Examine what's happening on-screen during the slower parts and compare to the faster parts. Are more objects going in and out of the view frustum? Are objects being occluded that otherwise were not? Are big objects towards the end of your vertex buffer coming close to the viewpoint? These would be realistic causes of such a performance drop, and would be entirely in the realm of expected behaviour.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

All of the objects are in view and the issue disappears if I replace glm::rotate with glm::mat4(1.0f). All of the objects are the same size and vertex counts. The thing is, this is done using instancing. The largest buffer is the matrix buffer. The actual vertex buffer only has 12 vertices.

If your program bottleneck is in the fragment shader then the framerate will drop and climb as the models rotate unless they are spheres. How burdened the fragment processor is depends on how many pixels are visible. For a flat plane that is sideways at the center of the screen, the visible fragment count will be close to zero, your program will run faster if it happens to be fragment processor bound. When it is completely facing the screen more pixels are visible and your framerate will drop. Try scaling the models down to see if the framerate increases.

Consider it pure joy, my brothers and sisters, whenever you face trials of many kinds, 3 because you know that the testing of your faith produces perseverance. 4 Let perseverance finish its work so that you may be mature and complete, not lacking anything.

It is hard to tell without a video or some screenshots. But I would guess, that by rotating the objects you could encounter view dependent (early-)z-buffer effects, aka pixel overdraw.

A simple example: You draw your cubes in such an order, that they will be drawn from front to back. In this case the z-buffer will reach a stable state quite quickly and a lot of pixels will be rejected. Now you rotate your camera by 180° and the draw order changed from back to front. The early-z-buffer rejection effects will not be as effective as before resulting an high rate of pixel overdraw and therefor a potential performance loss.

This topic is closed to new replies.

Advertisement