我正在完善我写的一个Linux游戏程序,在玩了大约10分钟之后,它突然减慢到每30秒左右1帧,同时减慢了整个系统的速度。即使在中断过程后,系统也会持续缓慢大约一分钟。
在多次测试中,我在发生减速时中断了GDB中的进程,并且总是在调用glXSwapBuffers
的过程中。
无论游戏状态或输入如何,都会发生这种情况。阻止它的唯一方法是不在单独的线程中开始播放重复音乐曲目:线程仍在运行,但它不会不断地写入声卡缓冲区。我确保两个共享列表都已正确锁定。
是否有人遇到glXSwapBuffers
和其他看似无关的线程的问题?
操作系统是Ubuntu 9,使用OpenGL的Mesa 7.6.0实现和ALSA libasound2 1.0.20-3。我今天早上为我的GeForce 6800显卡更新了我的NVIDIA驱动程序,但无济于事。
(相关?)代码如下。
显示功能:
int DisplayInterface::init()
{
xDisplay = XOpenDisplay(NULL);
if (xDisplay == NULL)
{
printf("Error: cannot connect to the X server\n");
return -1;
}
rootWindow = DefaultRootWindow(xDisplay);
fbConfigs = glXChooseFBConfig(xDisplay, DefaultScreen(xDisplay), fbAttributes, &numConfigs);
if (fbConfigs == NULL)
{
printf("Error: no X framebuffer configuration available as specified\n");
return -1;
}
visualInfo = glXGetVisualFromFBConfig(xDisplay, fbConfigs[0]);
if (visualInfo == NULL)
{
printf("Error: no appropriate X visual found\n");
return -1;
}
colorMap = XCreateColormap(xDisplay, rootWindow, visualInfo->visual, AllocNone);
xAttributes.colormap = colorMap;
xAttributes.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask; // need KeyPress and KeyRelease for InputInterface
gameWindow = XCreateWindow(xDisplay, rootWindow, 0, 0, displayWidth, displayHeight, 0, visualInfo->depth, InputOutput, visualInfo->visual, CWColormap | CWEventMask, &xAttributes);
XMapWindow(xDisplay, gameWindow);
XStoreName(xDisplay, gameWindow, "Vuess Vow Vong Vo Vold Vown Vhe Vey");
glxWindow = glXCreateWindow(xDisplay, fbConfigs[0], gameWindow, NULL);
renderContext = glXCreateNewContext(xDisplay, fbConfigs[0], GLX_RGBA_TYPE, NULL, GL_TRUE);
glXMakeContextCurrent(xDisplay, glxWindow, glxWindow, renderContext);
//glViewport(0, 0, displayWidth, displayHeight);
glViewport(-2.0 * displayWidth, -2.0 * displayHeight, 5.0 * displayWidth, 5.0 * displayHeight);
//glMatrixMode(GL_PROJECTION);
//glLoadIdentity();
//gluOrtho2D(0.0, (GLfloat)displayWidth, 0.0, (GLfloat)displayHeight);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPixelZoom((GLfloat)((float)displayWidth / (float) pictureWidth), (GLfloat)((float)displayHeight / (float) pictureHeight));
glClearColor((float)clearColor[0] / 255.0, (float)clearColor[1] / 255.0, (float)clearColor[2] / 255.0, (float)clearColor[3] / 255.0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glClear(GL_COLOR_BUFFER_BIT);
return 0;
}
// draw a Sprite from left to right and from top to bottom, starting at the given pixel
void DisplayInterface::draw(Sprite *sprite, Pixel& pixel)
{
if (sprite == NULL)
{
return;
}
pixelstorage_t *spritePixels = sprite->getPixelData();
const unsigned int format = sprite->getPixelFormat();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(-2.0 * (GLfloat)displayWidth, 3.0 * (GLfloat)displayWidth, -2.0 * (GLfloat)displayHeight, 3.0 * (GLfloat)displayHeight);
glRasterPos2i(pixel.x * (int)displayWidth / (int)pictureWidth, (int)displayHeight - (pixel.y + (int)sprite->getHeight()) * (int)displayHeight / (int)pictureHeight);
switch (format)
{
case SPRITE_RGBA:
glDrawPixels(sprite->getWidth(), sprite->getHeight(), GL_RGBA, PIXEL_TYPE, spritePixels);
}
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
void DisplayInterface::finalizeFrame()
{
glFinish();
glXSwapBuffers(xDisplay, glxWindow);
}
播放线程功能:
int writeFramesToHwBuffer(pcmsamplestorage_t *frames, snd_pcm_sframes_t numframes)
{
int pcmreturn;
while ((pcmreturn = snd_pcm_writei(pcm_handle, frames, numframes)) < 0)
{
snd_pcm_prepare(pcm_handle);
fprintf(stderr, "Speaker Interface error: hardware buffer underrun.\n");
}
return pcmreturn;
}
void *playback(void *arg)
{
int i;
unsigned int availableframes;
unsigned int framesFromThisBuffer;
unsigned int framesThisTime;
pcmsamplestorage_t *frames_mix;
pcmsamplestorage_t *frames_track;
unsigned int framesOffset;
std::list<struct playbackState *>::iterator stateIter;
while (1)
{
if (snd_pcm_wait(pcm_handle, 1000) < 0)
{
fprintf(stderr, "Speaker Interface error: poll failed.\n");
break;
}
if ((availableframes = snd_pcm_avail_update(pcm_handle)) < 0)
{
if (availableframes == -EPIPE)
{
fprintf(stderr, "Speaker Interface error: an xrun occured.\n");
break;
}
else
{
fprintf(stderr, "Speaker Interface error: unknown ALSA avail update return value (%d).\n", availableframes);
break;
}
}
// mix and write more frequently than necessary
while (availableframes > 0)
{
framesThisTime = std::min(availableframes, 1024u);
availableframes -= framesThisTime;
//printf("Frames this time: %d / frames left to go: %d\n", framesThisTime, availableframes);
frames_mix = new pcmsamplestorage_t[framesThisTime * 2];
for (i = 0; i < framesThisTime * 2; i++)
{
frames_mix[i] = 0;
}
// BEGIN CRITICAL SECTION
if (pthread_mutex_lock(&soundslists_lock) != 0)
{
fprintf(stderr, "Speaker Interface error: couldn't lock sounds lists from playback thread.\n");
}
printf("soundsPlaying has %d elements.\n", (int)soundsPlaying.size());
printf("soundsToStop has %d elements.\n", (int)soundsToStop.size());
for (stateIter = soundsPlaying.begin(); stateIter != soundsPlaying.end(); stateIter++)
{
frames_track = (*stateIter)->sound->getSamples();
if ((*stateIter)->deliveredframes < (*stateIter)->totalframes)
{
if ((*stateIter)->repeating)
{
framesFromThisBuffer = framesThisTime;
}
else
{
// mix in silence if we reach the end of this sound's buffer
framesFromThisBuffer = std::min(framesThisTime, (*stateIter)->totalframes - (*stateIter)->deliveredframes);
}
for (i = 0; i < framesFromThisBuffer * 2; i++)
{
// add samples to the mix, potentially running off the end of this buffer and wrapping around
if (SHRT_MAX - frames_mix[i] < frames_track[((*stateIter)->deliveredframes * 2 + i) % ((*stateIter)->totalframes * 2)])
{
// prevent overflow
frames_mix[i] = SHRT_MAX;
}
else if (SHRT_MIN - frames_mix[i] > frames_track[((*stateIter)->deliveredframes * 2 + i) % ((*stateIter)->totalframes * 2)])
{
// prevent underflow
frames_mix[i] = SHRT_MIN;
}
else
{
frames_mix[i] += frames_track[((*stateIter)->deliveredframes * 2 + i) % ((*stateIter)->totalframes * 2)];
}
}
(*stateIter)->deliveredframes = ((*stateIter)->deliveredframes + framesFromThisBuffer);
if ((*stateIter)->repeating)
{
(*stateIter)->deliveredframes = (*stateIter)->deliveredframes % (*stateIter)->totalframes;
}
}
else
{
soundsToStop.push_back(stateIter);
}
}
writeFramesToHwBuffer(frames_mix, framesThisTime);
delete frames_mix;
for (std::list<std::list<struct playbackState *>::iterator>::iterator stateiterIter = soundsToStop.begin(); stateiterIter != soundsToStop.end(); stateiterIter++)
{
soundsPlaying.erase(*stateiterIter);
free(**stateiterIter);
stateiterIter = soundsToStop.erase(stateiterIter);
}
if (pthread_mutex_unlock(&soundslists_lock) != 0)
{
fprintf(stderr, "Speaker Interface error: couldn't unlock sounds lists from playback thread.\n");
}
// END CRITICAL SECTION
}
}
}
答案 0 :(得分:0)
操作系统是Ubuntu 9,使用OpenGL的 Mesa 7.6.0实现和ALSA libasound2 1.0.20-3。今天早上我为我的GeForce 6800显卡更新了我的 NVIDIA 驱动程序,但无济于事。
您可以使用Mesa libGL.so或NVIDIA libGL.so,但不能同时使用两者。我建议你尝试不同的OpenGL驱动程序(例如真的使用Mesa。检查glxinfo | grep OpenGL.vendor
)
一个疯狂的猜测:glXSwapBuffers
通常会与屏幕上的垂直同步相关联,您可以尝试使用其中的选项(请参阅Google)。