Sign in to follow this  
MarkS

Odd frame rate fluctuation when using glm::rotate.

Recommended Posts

MarkS    3502

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);
}

Share this post


Link to post
Share on other sites
mhagain    13430

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.

Share this post


Link to post
Share on other sites
MarkS    3502
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.

Share this post


Link to post
Share on other sites
marcClintDion    435

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.

Share this post


Link to post
Share on other sites
Ashaman73    13715

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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this