I have written a benchmark program that compares the performance of OpenGL and DirectX libraries. The problem is that OpenGL gets much lower performance than Direct3D. At the end the program generates a comparison chart. You can look at it here:
As you can see the OpenGL performance is poor compared with Direct3D (I know that FPS's aren't the best method of measuring out there but that was my choise from the begining). Rendered object is a BIG CUBE made of smaller cubes. BIG CUBE passes certain states that are:
COLOR
COLOR + LIGHTS
TEXTURE
TEXTURE + LIGHTS
WIRE
TRANSPARENT
OpenGL context uses atioglxx.dll (AMD) and nvoglv32.dll (NVidia) for HW rendering.
Now I will provide some code for better view of what and how I am doing things. First of all I'm creating a rendering context that is loaded on WM_CREATE
:
GLvoid StartOpenGL(HWND hwnd, HDC * hdC, HGLRC * hrc)
{
PIXELFORMATDESCRIPTOR pfd;
int format;
*hdC = GetDC(hwnd);
ZeroMemory( &pfd, sizeof( pfd ) );
pfd.nSize = sizeof( pfd );
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
format = ChoosePixelFormat(*hdC, &pfd);
SetPixelFormat(*hdC, format, &pfd);
*hrc = wglCreateContext(*hdC);
wglMakeCurrent(*hdC, *hrc);
}
// also these functions are called on WM_CREATE:
ApplyTextures(); //load texture
reshape(); // reshape
LOADcubeGL(); // load VBO's (for full code check LINK2 on Blockquote)
ACTIVATEcubeGL(); // activate VBO's (for full code check LINK2 on Blockquote)
Context is destroyed on WM_DESTROY:
GLvoid StopOpenGL(HWND hwnd, HDC hdC, HGLRC hrc)
{
wglMakeCurrent( NULL, NULL );
wglDeleteContext( hrc );
ReleaseDC(hwnd, hdC);
}
// also these functions are called on WM_DESTROY:
KILLcubeGL(); // zero VBO's (for full code check LINK2 on Blockquote)
On WINAPI WinMain
I do
animationGL(); // rotate the cube
init(); // inits GLlight
display(); // set view + transformation + rendering the cube object with glEnable(); glDisable(); states
SwapBuffers(hdC);
Here is the full code:
GLvoid LOADcubeGL(GLvoid){
glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB");
glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB");
glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB");
glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)wglGetProcAddress("glBufferSubDataARB");
glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)wglGetProcAddress("glDeleteBuffersARB");
glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)wglGetProcAddress("glGetBufferParameterivARB");
glGenBuffersARB(1, &gVerts);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, gVerts);
glBufferDataARB(GL_ARRAY_BUFFER_ARB,
sizeof(vertices) + sizeof(normals) + sizeof(colors) + sizeof(texcoords),
0,
GL_STATIC_DRAW_ARB );
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(vertices), vertices);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertices), sizeof(normals), normals);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertices) + sizeof(normals), sizeof(colors), colors);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertices) + sizeof(normals) + sizeof(colors), sizeof(texcoords), texcoords);
glGenBuffersARB(1, &gIndices);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, gIndices);
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(indices), indices, GL_STATIC_DRAW_ARB);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
};
GLvoid ACTIVATEcubeGL(GLvoid){
gVerts = 0;
gIndices = 0;
glBindBufferARB(GL_ARRAY_BUFFER_ARB, gVerts);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, gIndices);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glNormalPointer(GL_FLOAT, 0, normals);
glColorPointer(4, GL_FLOAT, 0, colors);
glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
};
GLvoid KILLcubeGL(GLvoid){
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
glDeleteBuffersARB(1, &gVerts);
glDeleteBuffersARB(1, &gIndices);
delete[] vertices;
delete[] indices;
};
The BIG CUBE is drawn in display();
stage by:
glNewList(1, GL_COMPILE);
glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(indices[0]), GL_UNSIGNED_BYTE, indices);
glEndList();
Now I know that mixing VBO's with display list may cause problems and moreover DirectX 9 doesn't have equivalent for display list but otherwise my OPENGL code runs even slower: at 20FPS! What I am doing wrong?
My DirectX calls look pretty same except that there is no rendering context like OpenGL have. I draw by vertex_buffer->Lock
index_buffer->Lock
and finaly d3ddev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 36, 0, 12);
. My equivalent for OpenGL's PIXELFORMATDESCRIPTOR
is:
d3dp.Windowed = TRUE;
d3dp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dp.hDeviceWindow = dxhwnd;
d3dp.BackBufferCount = 1;
d3dp.BackBufferFormat = d3ddm.Format;
d3dp.MultiSampleType = D3DMULTISAMPLE_NONE; // in OpenGL I set that elsewhere than pfd
d3dp.MultiSampleQuality = 0;
d3dp.BackBufferWidth = width;
d3dp.BackBufferHeight = height;
d3dp.EnableAutoDepthStencil = TRUE;
d3dp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
d3dp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // in OpenGL I use wglSwapIntervalEXT(0);
glGenLists
to generate a valid ID to use inglNewList
.GL_COMPILE
means it won't actually execute it at that time anyway. You are usingglDrawElements
as if you are using client-side arrays. When a buffer is bound toELEMENT_ARRAY_BUFFER
the last parameter is an offset into that buffer, not a pointer. \$\endgroup\$GL_UNSIGNED_BYTE
is a very bad choice of index size in the first place. The API supports it, but GPUs don't. The fundamental problem is that it leads to unaligned memory access when fetching indices, the driver can help the GPU to overcome this problem but it will not give good performance. If you enable Debug Output on one of your AMD GPUs, it will basically tell you the same thing I did in the form of a performance warning, only without the explanation. I am sure you must have noticed the smallest index size in D3D is 16-bit? :) \$\endgroup\$