Discussion:
[SDL] SDL_PollEvent freezes on alt-tab
lemmn
2016-09-19 16:35:34 UTC
Permalink
I am using Windows 10 and visual studio 2015, and SDL 2.0.4.

I believe this is a minimal repro case.. I had to cut out a lot of code to get down to this, so I'm sorry if there is extra code here.

This program just draws a square on the screen and then should quit when you press the space bar.

Repro steps:
- run the program
- press alt-tab while the game is running
- notice the game program locking up

The bug happens when I hit alt-tab. If I do that, then the game becomes locked up at the call to PeekMessage() inside of WIN_PumpEvents(), with this callstack if I break:


Code:

[External Code]
SDL2.dll!WIN_PumpEvents(SDL_VideoDevice * _this) Line 977 C
SDL2.dll!SDL_PumpEvents_REAL() Line 405 C
SDL2.dll!SDL_WaitEventTimeout_REAL(SDL_Event * event, int timeout) Line 437 C
SDL2.dll!SDL_PollEvent_REAL(SDL_Event * event) Line 419 C
SDL2.dll!SDL_PollEvent(SDL_Event * a) Line 157 C
MyMusic.exe!SDL_main(int argc, char * * argv) Line 154 C++
MyMusic.exe!main_utf8(int argc, char * * argv) Line 127 C
MyMusic.exe!WinMain(HINSTANCE__ * hInst, HINSTANCE__ * hPrev, char * szCmdLine, int sw) Line 191 C
[External Code]




And the render thread is running happily.

This bug only happens in full screen. If I remove this code:

flags |= SDL_WINDOW_FULLSCREEN;

then the game runs fine, and I do not get any freeze on using alt-tab.


I have a feeling that the render thread might be the problem, but I must be able to render in a separate thread for this game. I followed this guide and everything seems to be working fine, apart from this freeze
https://github.com/vheuken/SDL-Render-Thread-Example/blob/master/main.cpp



Code:

#include "stdafx.h"

#include <vector>
#include <map>
#include <fstream>
#include <memory>
#include <limits>
#include <iomanip>
#include <thread>

#include <Windows.h>

#include <SDL.h>



// singleton to hold a bunch of global game state stuff
class Game
{
public:
Game()
{}

SDL_Rect m_windowedRect;

void SetUpScreen();
void TearDownScreen();

void StartRenderer();
void KillRenderer();


static Game& Get();

// window and screen
SDL_Window* m_Window;
SDL_GLContext m_Context;


bool m_QuitGame;

SDL_Renderer* m_Renderer = nullptr;
std::thread* m_RenderThread = nullptr;
};



static Game g_Game;
Game& Game::Get()
{
return g_Game;
}

void Game::SetUpScreen()
{
// make a sane default window position and size
if ( 0 == SDL_GetDisplayBounds( 0, &m_windowedRect ) )
{
m_windowedRect.x = m_windowedRect.w * 0.05f;
m_windowedRect.y = m_windowedRect.h * 0.05f;
m_windowedRect.w = m_windowedRect.w * 0.9f;
m_windowedRect.h = m_windowedRect.h * 0.9f;
}
else
{
m_windowedRect = { 10, 10, 1024, 768 };
}

int32_t flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE;

flags |= SDL_WINDOW_FULLSCREEN;

SDL_Rect resolution;
resolution = m_windowedRect;

m_Window = SDL_CreateWindow( "hi friend", resolution.x, resolution.y, resolution.w, resolution.h, flags );
}

void Game::TearDownScreen()
{
SDL_DestroyWindow( m_Window );
m_Window = NULL;
}

void RenderThread();

void Game::StartRenderer()
{
m_RenderThread = new std::thread( RenderThread );
}

static bool stopRenderer;

void Game::KillRenderer()
{
stopRenderer = true;
m_RenderThread->join();

delete m_RenderThread;
m_RenderThread = nullptr;
}

void RenderThread()
{
SDL_GL_MakeCurrent( g_Game.m_Window, g_Game.m_Context ); // not sure what this does - it was happening in the example

g_Game.m_Renderer = SDL_CreateRenderer( g_Game.m_Window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
SDL_SetRenderDrawBlendMode( g_Game.m_Renderer, SDL_BLENDMODE_BLEND );

while( 1 )
{
if ( stopRenderer )
{
goto quit;
}

SDL_Rect rect{ 10, 10, 10, 10 };
SDL_SetRenderDrawColor( g_Game.m_Renderer, 0xff, 0xff, 0xff, 0xff );
SDL_RenderFillRect( g_Game.m_Renderer, &rect );
SDL_RenderPresent( g_Game.m_Renderer );
}

quit:
// shut down
SDL_DestroyRenderer( g_Game.m_Renderer );
g_Game.m_Renderer = NULL;
}

int main( int argc, char* argv[] )
{

SDL_Init( SDL_INIT_AUDIO | SDL_INIT_VIDEO );

SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "linear" );

g_Game.SetUpScreen();


// not entirely sure this is needed but it was happening before creating the render thread in example
g_Game.m_Context = SDL_GL_GetCurrentContext();
SDL_GL_MakeCurrent( g_Game.m_Window, nullptr );

g_Game.StartRenderer();

// main loopy thing
while ( 1 )
{
if ( g_Game.m_QuitGame )
{
break;
}

SDL_Event e;
while ( SDL_PollEvent( &e ) )
{
if ( e.type == SDL_KEYDOWN )
{
if ( e.key.keysym.sym == SDLK_SPACE )
{
g_Game.m_QuitGame = true;
}
}
}

Sleep( 10 );
}

g_Game.KillRenderer();

g_Game.TearDownScreen();

SDL_Quit();
return 0;
}
lemmn
2016-09-19 16:58:43 UTC
Permalink
Ok, I would like to fix a few more things but I can't edit and I don't want to post the same thing over and over.
lemmn
2016-09-19 18:43:53 UTC
Permalink
I notice I also have problems with resizing the window. The program crashes. Am I trying to do something that isn't possible???

This game's main loop where I process input needs to spin extremely fast! Because i need sub-millisecond accuracy on input handling. I need to get those events as fast as possible.

So, my rendering cannot happen in the loop where I handle input.

I need to be able to either render or handle input in a separate thread. Is either thing possible?
Loading...