[SDL] Super slow framerate on Windows 7, GLEW shaders unavailable

Started by
4 comments, last by nitro404 12 years, 1 month ago
Hello!

I've been working on a project off and on in SDL for a number of months now, and I've had an issue from the start that I recently had some time to try and debug. I've been developing on Windows XP until this past week, so it was not really an issue until now.

Basically, my SDL bases game works perfectly fine on any Windows XP machine (ie. normal frame rate, shaders work no problem), but I initially noticed that if I ran the executable on Windows 7, the frame rate would only be 10-15 for no reason (on super high-end machines, ie. Phenom II X6 / 5970) but this was strictly a Windows 7 issue as indicated by testing on several different machines. Upon further investigation I realized that if I run the game from within Visual Studio 2008 on a Windows 7 machine it works perfectly (ie. 7000+ FPS w/o vsync), but as soon as I ran it from the executable instead, the frame rate would once again be between 10 and 15, and if shaders were being used via GLEW, the program would simply exit because GLEW 2.0 was unavailable.

tldr; SDL OpenGL game, works fine on XP, on Win7 works fine in VS2008 but EXE limited to 10 fps and shaders wont work

Honestly not sure what the issue could possibly be and has been baffling me for some time. If anyone has any suggestions or input, it would be greatly appreciated. It almost seems like SDL is somehow switching to software mode or some limited version of OpenGL. Also worth mentioning that the only things being rendered is some text (generated and rendered via lists) and a very simple skybox with 1024x1024 textures for each side.

My game is using SDLmain and a number of libraries, including:
SDL
SDL_ttf
GLEW
FreeImage
Qt
FMOD Ex
FBX SDK
Bullet Physics

Thanks for reading. Some code, if it helps any:

Main.cpp:

#include "Game.h"
int main(int argc, char * argv[]) {
Game * game = new Game();
if(!game->init()) { return -1; }
game->run();
delete game;
return 0;
}


OpenGL Setup:

bool Game::init() {
if(m_initialized) { return false; }
settings->load();
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK) == -1) { return false; }
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, settings->verticalSync ? 1 : 0);
m_graphics = SDL_SetVideoMode(settings->windowWidth, settings->windowHeight, 0, SDL_OPENGL | (settings->fullScreen ? SDL_FULLSCREEN : 0));
SDL_WM_SetCaption("Game", NULL);
QString iconPath;
iconPath.append(QString("%1/Icons/Block.bmp").arg(settings->dataDirectoryName));
QByteArray iconPathBytes = iconPath.toLocal8Bit();
m_icon = SDL_LoadBMP(iconPathBytes.data());
SDL_WM_SetIcon(m_icon, NULL);
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glDepthFunc(GL_LEQUAL);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glMatrixMode(GL_MODELVIEW);
glViewport(0, 0, settings->windowWidth, settings->windowHeight);
if(glewInit() != GLEW_OK) { return false; }
if(!GLEW_VERSION_2_0) { return false; }

etc.


Game Loop:

void Game::run() {
if(!m_initialized) { return; }
m_running = true;
SDL_Event event;
static unsigned int lastTime = SDL_GetTicks();
unsigned int currentTime = SDL_GetTicks();
do {
if(SDL_PollEvent(&event)) {
switch(event.type) {
case SDL_KEYDOWN:
if(!console->isActive()) {
menu->handleInput(event);
}
if(!menu->isActive()) {
console->handleInput(event);
}
break;
case SDL_MOUSEMOTION:
if(!console->isActive() &&
!menu->isActive() &&
SDL_GetAppState() & SDL_APPMOUSEFOCUS &&
SDL_GetAppState() & SDL_APPINPUTFOCUS &&
SDL_GetAppState() & SDL_APPACTIVE) {
camera->handleInput(event);
}
break;
case SDL_QUIT:
m_running = false;
break;
default:
break;
}
}
if(m_running) {
currentTime = SDL_GetTicks();
update(currentTime - lastTime);
draw();
lastTime = currentTime;
}
} while(m_running);
}
Advertisement
if(SDL_PollEvent(&event))

Should be:

while ( SDL_PollEvent( &event ) )

It's likely that your event queue accumulates more and and more windows events until your game slows down to a crawl -- you need to process all of the window messages between each frame, not just one per frame. (Not sure if this will fix your problem, but it will certainly help...)
Oh dear, I feel ashamed for implementing that wrong. Thanks for the reply! Although this did not fix my previous issues (slow framerate, shaders unsupported), it did fix my input handling and bizarre behaviours I was experiencing with my camera which I had yet to solve, so thanks!

Still looking for a solution, though. I just can't figure what's so different with the execution of the game between being run from Visual Studio 2008 vs. from the compiled release executable.
Are you mixing any regular SDL drawing (i.e. not OpenGL stuff) with your OpenGL drawing? That could be a possible cause on WDDM drivers.

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

Not as far as I know, I'm using glLists for my SkyBox, and standard OpenGL stuff for the rest, see code below. The only strange thing I'm doing is using SDL_ttf which uses SDL_Surface to blit text which I convert to an OpenGL texture. Irregardless, I don't think any of this should be an issue if it works perfectly fine from Visual Studio 2008, right?

Edit: Furthermore, there are no problems on Windows XP when running from either VS2008 or EXE. So why is it such a problem on Windows 7? I'm using platform independent libraries (ie. no STL), so I'm still completely baffled.

SkyBox Load:

bool SkyBox::load() {
if(m_loaded) { return true; }

for(int i=0;i<6;i++) {
m_textures = Game::resources->getTexture(m_textureNames);
if(m_textures == NULL) { return false; }
if(!m_textures->load()) { return false; }
}

m_skyBoxList = glGenLists(6);

float width = (float) (m_textures[0]->getWidth() - 1) / (float) m_textures[0]->getWidth();

// left side
glNewList(m_skyBoxList, GL_COMPILE);
glBegin(GL_POLYGON);
glTexCoord2d(1 - width, width);
glVertex3d(-0.5, 0.5, 0.5);
glTexCoord2d(1 - width, 1 - width);
glVertex3d(-0.5, -0.5, 0.5);
glTexCoord2d(width, 1 - width);
glVertex3d(-0.5, -0.5, -0.5);
glTexCoord2d(width, width);
glVertex3d(-0.5, 0.5, -0.5);
glEnd();
glEndList();

// right side
glNewList(m_skyBoxList + 1, GL_COMPILE);
glBegin(GL_POLYGON);
glTexCoord2d(1 - width, width);
glVertex3d(0.5, 0.5, -0.5);
glTexCoord2d(1 - width, 1 - width);
glVertex3d(0.5, -0.5, -0.5);
glTexCoord2d(width, 1 - width);
glVertex3d(0.5, -0.5, 0.5);
glTexCoord2d(width, width);
glVertex3d(0.5, 0.5, 0.5);
glEnd();
glEndList();

// front side
glNewList(m_skyBoxList + 2, GL_COMPILE);
glBegin(GL_POLYGON);
glTexCoord2d(1 - width, width);
glVertex3d(-0.5, 0.5, -0.5);
glTexCoord2d(1 - width, 1 - width);
glVertex3d(-0.5, -0.5, -0.5);
glTexCoord2d(width, 1 - width);
glVertex3d(0.5, -0.5, -0.5);
glTexCoord2d(width, width);
glVertex3d(0.5, 0.5, -0.5);
glEnd();
glEndList();

// back side
glNewList(m_skyBoxList + 3, GL_COMPILE);
glBegin(GL_POLYGON);
glTexCoord2d(1 - width, width);
glVertex3d(0.5, 0.5, 0.5);
glTexCoord2d(1 - width, 1 - width);
glVertex3d(0.5, -0.5, 0.5);
glTexCoord2d(width, 1 - width);
glVertex3d(-0.5, -0.5, 0.5);
glTexCoord2d(width, width);
glVertex3d(-0.5, 0.5, 0.5);
glEnd();
glEndList();

// top side
glNewList(m_skyBoxList + 4, GL_COMPILE);
glBegin(GL_POLYGON);
glTexCoord2d(width, 1 - width);
glVertex3d(-0.5, 0.5, 0.5);
glTexCoord2d(width, width);
glVertex3d(-0.5, 0.5, -0.5);
glTexCoord2d(1 - width, width);
glVertex3d(0.5, 0.5, -0.5);
glTexCoord2d(1 - width, 1 - width);
glVertex3d(0.5, 0.5, 0.5);
glEnd();
glEndList();

// bottom side
glNewList(m_skyBoxList + 5, GL_COMPILE);
glBegin(GL_POLYGON);
glTexCoord2d(width, 1 - width);
glVertex3d(-0.5, -0.5, -0.5);
glTexCoord2d(width, width);
glVertex3d(-0.5, -0.5, 0.5);
glTexCoord2d(1 - width, width);
glVertex3d(0.5, -0.5, 0.5);
glTexCoord2d(1 - width, 1 - width);
glVertex3d(0.5, -0.5, -0.5);
glEnd();
glEndList();

m_loaded = true;

return true;
}


SkyBox Draw:

void SkyBox::draw() {
if(!m_loaded) { return; }

glDisable(GL_DEPTH_TEST);

glLoadIdentity();

glRotated(Game::camera->getRotation().x, 1, 0, 0);
glRotated(Game::camera->getRotation().y, 0, 1, 0);

for(int i=0;i<6;i++) {
m_textures->activate();
glCallList(m_skyBoxList + i);
}

glEnable(GL_DEPTH_TEST);
}


Game Draw:

void Game::draw() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// set up 3d rendering
glEnable(GL_TEXTURE_2D);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70.0f, (GLfloat) settings->windowWidth / (GLfloat) settings->windowHeight, 0.1f, 10000.0f);
glMatrixMode(GL_MODELVIEW);

// render skybox
if(skyBox != NULL) {
skyBox->draw();
}

// render world
if(mainShader != NULL) { mainShader->activate(); }

glPushMatrix();
camera->setup();

glScalef(100, 100, 100);

glBegin(GL_POLYGON);

// left
glVertex3f(-1.0f, 0.0f, 0.0f);
glVertex3f(-1.0f, 0.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);

// right
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, -1.0f, 0.0f);
glVertex3f(0.0f, -1.0f, -1.0f);
glVertex3f(0.0f, 0.0f, -1.0f);

// front
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(-1.0f, 0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glVertex3f(0.0f, -1.0f, 0.0f);

// back
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(-1.0f, 0.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(0.0f, -1.0f, -1.0f);

// top
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 0.0f, -1.0f);
glVertex3f(-1.0f, 0.0f, -1.0f);
glVertex3f(-1.0f, 0.0f, 0.0f);

// bottom
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);

glEnd();
glPopMatrix();

if(mainShader != NULL) { mainShader->deactivate(); }

// set up 2d rendering
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, settings->windowWidth, settings->windowHeight, 0);

// render hud / gui elements
displayFPS();
menu->draw();
console->draw();

SDL_GL_SwapBuffers();
}


Font Draw / Load:

void Font::drawTextHelper(int x, int y, const char * text) const {
if(!m_loaded) { return; }

glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);

glBindTexture(GL_TEXTURE_2D, m_texture);

glMatrixMode(GL_MODELVIEW);
glPushMatrix();

glLoadIdentity();

glTranslated(x, y, 0);
glListBase(m_font - 32);
glCallLists(strlen(text), GL_BYTE, text);

glPopMatrix();
}

bool Font::load() {
if(m_loaded) { return true; }

QString fontPath = QString("%1/Fonts/%2").arg(Game::settings->dataDirectoryName).arg(m_fileName);

QFileInfo fontFile(fontPath);
if(!fontFile.exists()) { return false; }

QByteArray bytes = fontPath.toLocal8Bit();

TTF_Font * fontData;
if(!(fontData = TTF_OpenFont(bytes.data(), m_size))) {
return false;
}

SDL_Color colour = {255, 255, 255, 255};

SDL_Surface * character;
QVector characters;
int maxWidth = -1;
int maxHeight = -1;
char data[2];
data[1] = '\0';
for(int i=0;i<128;i++ ) {
data[0] = (char) (i + 32);
character = TTF_RenderText_Blended(fontData, data, colour);
characters.push_back(character);
if(maxWidth < 0 || maxWidth < character->w) { maxWidth = character->w; }
if(maxHeight < 0 || maxHeight < character->h) { maxHeight = character->h; }
}

m_horizontalSpacing = maxWidth;
m_verticalSpacing = maxHeight;

int width = 1, tempWidth = maxWidth * 16;
int height = 1, tempHeight = maxHeight * 8;
while(width < tempWidth) { width *= 2; }
while(height < tempHeight) { height *= 2; }

SDL_Surface * temp = SDL_CreateRGBSurface(0, width, height, 32,
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
#else
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
#endif
);

SDL_Rect sourceArea, destArea;
int x = 0;
int y = 0;
for(int i=0;i<128;i++) {
sourceArea.x = 0;
sourceArea.y = 0;
sourceArea.w = characters->w;
sourceArea.h = characters->h;

destArea.x = maxWidth * x;
destArea.y = maxHeight * y;
destArea.w = characters->w;
destArea.h = characters->h;

SDL_SetAlpha(characters, 0, 0);
SDL_BlitSurface(characters, &sourceArea, temp, &destArea);

x++;
if(x == 16) {
x = 0;
y++;
}
}

glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, temp->w, temp->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);

m_font = glGenLists(128);

x = 0;
y = 0;
float w = (float) maxWidth / (float) (temp->w);
float h = (float) maxHeight / (float) (temp->h);
for(int i=0;i<128;i++) {

glNewList(m_font + i, GL_COMPILE);

glBegin(GL_QUADS);
glTexCoord2f((w * x), ((h * y))); glVertex2i(0, 0);
glTexCoord2f((w * x) + w, ((h * y))); glVertex2i(maxWidth, 0);
glTexCoord2f((w * x) + w, ((h * y) + h)); glVertex2i(maxWidth, maxHeight);
glTexCoord2f((w * x), ((h * y) + h)); glVertex2i(0, maxHeight);
glEnd();

glTranslated(maxWidth, 0, 0);

glEndList();

x++;
if(x == 16) {
x = 0;
y++;
}
}

for(int i=0;i<128;i++) {
SDL_FreeSurface(characters);
}
SDL_FreeSurface(temp);

m_loaded = true;

return true;
}
Found the solution to all my issues finally, after consulting some friends. Turns out Visual Studio 2008 on Windows 7 would use the operating system's version of OpenGL, and when I ran it from the EXE it used the local OpenGL32.dll which was either out of date, or built for the wrong platform. So, removing this DLL fixed all framerate issues, and now runs no problem after defaulting to the operating system's OpenGL32.dll. Hopefully this helps anyone else who runs into this issue!

This topic is closed to new replies.

Advertisement