我使用SDL2用C ++编写了一个Space Invaders模拟器,仅用于创建游戏窗口和播放声音(sdl2_mixer)。在Windows上,模拟器可以60 FPS的速度运行(我可以将该值更改为所需的值,并且可以毫无问题地运行),但是如果我在Ubuntu或Mac OS X上构建它,则游戏将无法播放(可能是所需FPS的10%)。
对此有解释吗?
[我试图注释掉创建框架的部分(因此窗口上没有框架更新),并且游戏仍然很慢(音频仍在播放。)
Ubuntu上的渲染器名称:opengl
Windows上的渲染器名称:direct3d
Renderer标志在Windows上均在Windows上均为0x0a。
编译:
g++ -std=c++11 main.cpp spaceinvadersmachine.cpp intel8080.cpp -lSDL2 -lSDL2_mixer -I/usr/include/SDL2 -I/usr/include/SDL2_mixer -Ofast -D_REENTRANT -o spaceinvaders.app
或:
g++ -std=c++11 main.cpp spaceinvadersmachine.cpp intel8080.cpp -lSDL2 -lSDL2_mixer -I/usr/include/SDL2 -I/usr/include/SDL2_mixer -O2 -D_REENTRANT -o spaceinvaders.app
这里有一些代码:
//主循环
while (!quitEmulator)
{
// Handle events on queue
while (SDL_PollEvent(&events) == 1)
{
switch (events.type)
{
case SDL_QUIT:
{
// Game's window has been closed
quitEmulator = true;
break;
}
case SDL_KEYDOWN:
{
// Set magnification to 1x
if (events.key.keysym.sym == SDLK_1)
{
machine.magnificationFactor = 1.0;
machine.magnificationRequest = true;
}
// Save game request
if (events.key.keysym.sym == SDLK_2)
{
machine.saveGameRequest = true;
}
// Load game request
if (events.key.keysym.sym == SDLK_3)
{
machine.loadGameRequest = true;
}
// Set magnification to 4x
if (events.key.keysym.sym == SDLK_4)
{
machine.magnificationFactor = 2.0;
machine.magnificationRequest = true;
}
// Set bases dipswitch request
if (events.key.keysym.sym == SDLK_7)
{
machine.dipBasesRequest = true;
}
// Set bonus base dipswitch request
if (events.key.keysym.sym == SDLK_8)
{
machine.dipBonusBaseRequest = true;
}
// Set magnification to 9x
if (events.key.keysym.sym == SDLK_9)
{
machine.magnificationFactor = 3.0;
machine.magnificationRequest = true;
}
// Set coin informations dipswitch request
if (events.key.keysym.sym == SDLK_i)
{
machine.dipCoinInfoRequest = true;
}
// Game paused
if (events.key.keysym.sym == SDLK_p)
{
gamePaused = !gamePaused;
if (gamePaused)
cout << "INFO: Game paused!\n";
else
cout << "INFO: Game resumed!\n";
}
// Reset request
if (events.key.keysym.sym == SDLK_r)
{
machine.resetRequest = true;
}
// Change color mode
if (events.key.keysym.sym == SDLK_c)
{
machine.coloredFrame = !machine.coloredFrame;
if (machine.coloredFrame)
cout << "INFO: Color mode set to RGB\n";
else
cout << "INFO: Color mode set to B/W\n";
}
break;
}
}
}
if (!gamePaused)
{
// Check keyboard inputs
SDL_PumpEvents();
machine.checkKeyboardInput();
// Set bases dipswitch if requested
if (machine.dipBasesRequest)
{
machine.setBasesDipswitch();
}
// Set bonus base dipswitch if requested
if (machine.dipBonusBaseRequest)
{
machine.setBonusBaseDipswitch();
}
// Set coin informations dipswitch if requested
if (machine.dipCoinInfoRequest)
{
machine.setCoinInfoDipswitch();
}
// Change magnification factor if requested
if (machine.magnificationRequest)
{
machine.setMagnification();
}
// Check for interrupt
if (CPUInterruptDeltaCycles >= cyclePerInterrupt)
{
CPUInterruptDeltaCycles = 0;
machine.interruptRequest = true;
if (machine.lastInterruptNumber == 1) // RST 1
{
machine.interruptNumber = 2; // RST 2
}
else // RST 2
{
machine.interruptNumber = 1; // RST 1
}
machine.lastInterruptNumber = machine.interruptNumber;
}
else
{
machine.interruptRequest = false;
}
// Execute next instruction
CPU.executeROM(machine.interruptRequest, machine.interruptNumber);
// Increments CPU's cycle counters
CPUDeltaCycles += CPU.CPUCycles;
CPUInterruptDeltaCycles += CPU.CPUCycles;
// Check if OPCode is known
if (CPU.unimplementedOPCode)
quitEmulator = true;
// Check for I/O
machine.checkIO();
// Check if a frame must be drawn
// Save and Load if requested
if (CPUDeltaCycles >= cyclePerFrame)
{
CPUDeltaCycles = 0;
machine.createFrame();
machine.showFrame();
drewFrames += 1;
while ((SDL_GetTicks() - lastFPSSynchronization) < frameTimeInterval)
{
// Waiting
;
}
lastFPSSynchronization = SDL_GetTicks();
if (machine.saveGameRequest)
{
machine.saveGameRequest = false;
machine.saveGame(CPUInterruptDeltaCycles);
}
if (machine.loadGameRequest)
{
machine.loadGameRequest = false;
machine.loadGame(CPUInterruptDeltaCycles);
// Remove pending keyboard events
SDL_FlushEvent(SDL_KEYDOWN);
SDL_FlushEvent(SDL_KEYUP);
SDL_PumpEvents();
}
}
// Reset if requested
if (machine.resetRequest)
{
machine.resetRequest = false;
machine.resetMachine();
}
}
}
//通过SDL显示帧
void spaceInvadersMachine::showFrame()
{
loadedSurface = SDL_CreateRGBSurfaceFrom(frameBuffer32, SCREEN_HEIGHT, SCREEN_WIDTH, 32, 4 * SCREEN_HEIGHT, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
if (loadedSurface == NULL)
{
printf("Unable to load video RAM! Error: %s\n", SDL_GetError());
}
else
{
// Create texture from surface
gTexture = SDL_CreateTextureFromSurface(gRenderer, loadedSurface);
// Delete surface
SDL_FreeSurface(loadedSurface);
if (gTexture == NULL)
{
printf("Failed to create texture image! Error: %s\n", SDL_GetError());
}
else
{
// Clear screen
SDL_RenderClear(gRenderer);
// Render texture to screen
SDL_RenderCopyEx(gRenderer, gTexture, NULL, &destinationRectangle, 90, NULL, SDL_FLIP_NONE);
// Delete texture (avoid memory leak)
SDL_DestroyTexture(gTexture);
// Update screen
SDL_RenderPresent(gRenderer);
}
}
}
您正在每帧创建一个新的表面和新的纹理。是的,它将会很慢,创建纹理是一个荒谬的缓慢操作。不要经常这样做。
[如果您需要直接写入像素,请一次创建正确大小的纹理(使用SDL_TEXTUREACCESS_STREAMING
,然后使用SDL_LockTexture
和SDL_UnlockTexture
进行更新。我猜测Windows版本很快(偶然))因为您的驱动程序实现会注意到您在做一些奇怪的事情,并且悄悄地忽略了您要执行的操作,并且更快地完成了操作。
当然不用看代码,很难说这是它的[[only问题,但这很可能是一个瓶颈,甚至是瓶颈。