From 47ddffb6c32443a2fb4ba0ba006a5ba751faa4da Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Thu, 20 Jun 2013 16:14:10 +0200 Subject: [PATCH 1/8] Another stab at correct SDL audio handling Fully de-initialize SDL audio in AudioManager::deinit(). --- src/AudioManager.cpp | 10 +++++++++- src/Renderer_init_sdlgl.cpp | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/AudioManager.cpp b/src/AudioManager.cpp index 4b1a8e463..9f68dde8d 100644 --- a/src/AudioManager.cpp +++ b/src/AudioManager.cpp @@ -1,5 +1,6 @@ #include "AudioManager.h" +#include #include "Log.h" #include "VolumeControl.h" @@ -70,6 +71,12 @@ std::shared_ptr & AudioManager::getInstance() void AudioManager::init() { + if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) + { + LOG(LogError) << "Error initializing SDL audio!\n" << SDL_GetError(); + return; + } + //stop playing all Sounds for(unsigned int i = 0; i < sSoundVector.size(); i++) { @@ -97,8 +104,9 @@ void AudioManager::deinit() { //stop all playback stop(); - + //completely tear down SDL audio. else SDL hogs audio resources and emulators might fail to start... SDL_CloseAudio(); + SDL_QuitSubSystem(SDL_INIT_AUDIO); } void AudioManager::registerSound(std::shared_ptr & sound) diff --git a/src/Renderer_init_sdlgl.cpp b/src/Renderer_init_sdlgl.cpp index 568347acf..3a464fd08 100644 --- a/src/Renderer_init_sdlgl.cpp +++ b/src/Renderer_init_sdlgl.cpp @@ -34,7 +34,7 @@ namespace Renderer { LOG(LogInfo) << "Creating surface..."; - if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) + if(SDL_Init(SDL_INIT_VIDEO) != 0) { LOG(LogError) << "Error initializing SDL!\n " << SDL_GetError(); return false; From 4a1206aee28705232308024ce4c03f39b96478fa Mon Sep 17 00:00:00 2001 From: Aloshi Date: Wed, 26 Jun 2013 23:25:58 -0500 Subject: [PATCH 2/8] Disable input device polling code to resolve freeze after ~45 minutes. See issue #87. --- src/InputManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/InputManager.cpp b/src/InputManager.cpp index 5df74a951..ae81962f1 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -165,14 +165,14 @@ void InputManager::init() SDL_JoystickEventState(SDL_ENABLE); //start timer for input device polling - devicePollingTimer = SDL_AddTimer(POLLING_INTERVAL, devicePollingCallback, (void *)this); + //devicePollingTimer = SDL_AddTimer(POLLING_INTERVAL, devicePollingCallback, (void *)this); loadConfig(); } void InputManager::deinit() { - SDL_RemoveTimer(devicePollingTimer); + //SDL_RemoveTimer(devicePollingTimer); SDL_JoystickEventState(SDL_DISABLE); From 887a1e00f8e8fa1c26fa53b814ae303a4e5bb035 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Thu, 27 Jun 2013 10:26:56 +0200 Subject: [PATCH 3/8] Fix ES freezing without input And also hook up SDL joystick reinit when device removal or insertion is detected. --- src/InputManager.cpp | 38 +++++++++++++++++++++----------------- src/main.cpp | 5 ++--- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/InputManager.cpp b/src/InputManager.cpp index 5df74a951..e3490e207 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -58,7 +58,7 @@ std::vector InputManager::getInputDevices() const //looks like a joystick. add to devices. currentDevices.push_back(InputDevice(deviceName, 0, 0)); } - dirIt++; + ++dirIt; } //or dump /proc/bus/input/devices anbd search for a Handler=..."js"... entry #elif defined(WIN32) || defined(_WIN32) @@ -122,14 +122,13 @@ Uint32 InputManager::devicePollingCallback(Uint32 interval, void* param) //this thing my be running in a different thread, so we're not allowed to call //any functions or change/allocate/delete stuff, but can send a user event SDL_Event event; - SDL_UserEvent userevent; - userevent.type = SDL_USEREVENT_POLLDEVICES; - userevent.code = 0; - userevent.data1 = nullptr; - userevent.data2 = nullptr; - event.type = SDL_USEREVENT; - event.user = userevent; - SDL_PushEvent(&event); + event.user.type = SDL_USEREVENT; + event.user.code = SDL_USEREVENT_POLLDEVICES; + event.user.data1 = nullptr; + event.user.data2 = nullptr; + if (SDL_PushEvent(&event) != 0) { + LOG(LogError) << "InputManager::devicePollingCallback - SDL event queue is full!"; + } return interval; } @@ -290,15 +289,20 @@ bool InputManager::parseEvent(const SDL_Event& ev) mWindow->input(getInputConfigByDevice(DEVICE_KEYBOARD), Input(DEVICE_KEYBOARD, TYPE_KEY, ev.key.keysym.sym, 0, false)); return true; - case SDL_USEREVENT_POLLDEVICES: - //poll joystick / HID again - std::vector currentDevices = getInputDevices(); - //compare device lists to see if devices were added/deleted - if (currentDevices != inputDevices) { - LOG(LogInfo) << "Device configuration changed!"; - inputDevices = currentDevices; + case SDL_USEREVENT: + if (ev.user.code == SDL_USEREVENT_POLLDEVICES) { + //poll joystick / HID again + std::vector currentDevices = getInputDevices(); + //compare device lists to see if devices were added/deleted + if (currentDevices != inputDevices) { + LOG(LogInfo) << "Device configuration changed!"; + inputDevices = currentDevices; + //deinit and reinit InputManager + deinit(); + init(); + } + return true; } - return true; } return false; diff --git a/src/main.cpp b/src/main.cpp index 64367bb05..4823308bb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -168,7 +168,7 @@ int main(int argc, char* argv[]) timeSinceLastEvent = 0; } break; - case InputManager::SDL_USEREVENT_POLLDEVICES: + case SDL_USEREVENT: //try to poll input devices, but do not necessarily wake up... window.getInputManager()->parseEvent(event); break; @@ -181,7 +181,7 @@ int main(int argc, char* argv[]) if(sleeping) { lastTime = SDL_GetTicks(); - sleep(1); //this doesn't need to accurate + SDL_Delay(1); //this doesn't need to be accurate continue; } @@ -225,7 +225,6 @@ int main(int argc, char* argv[]) Renderer::swapBuffers(); } - Log::flush(); } From b187f05a16ef1a0a7e2383a32853956e0310151b Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Thu, 27 Jun 2013 12:30:04 +0200 Subject: [PATCH 4/8] Fix font rendering for fonts with horizontal bearing --- src/Font.cpp | 15 +++++++++------ src/Font.h | 7 ++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/Font.cpp b/src/Font.cpp index f085c7586..bb62f06a8 100644 --- a/src/Font.cpp +++ b/src/Font.cpp @@ -183,9 +183,10 @@ void Font::buildAtlas() charData[i].texY = y; charData[i].texW = g->bitmap.width; charData[i].texH = g->bitmap.rows; - charData[i].advX = g->metrics.horiAdvance / 64.0f; - charData[i].advY = g->metrics.vertAdvance / 64.0f; - charData[i].bearingY = g->metrics.horiBearingY / 64.0f; + charData[i].advX = (float)g->metrics.horiAdvance / 64.0f; + charData[i].advY = (float)g->metrics.vertAdvance / 64.0f; + charData[i].bearingX = (float)g->metrics.horiBearingX / 64.0f; + charData[i].bearingY = (float)g->metrics.horiBearingY / 64.0f; if(charData[i].texH > mMaxGlyphHeight) mMaxGlyphHeight = charData[i].texH; @@ -257,10 +258,12 @@ void Font::drawText(std::string text, int startx, int starty, int color) if(letter < 32 || letter >= 128) letter = 127; //print [X] if character is not standard ASCII + //the glyph might not start at the cursor position, but needs to be shifted a bit + const float glyphStartX = x + charData[letter].bearingX * fontScale; //order is bottom left, top right, top left - vert[i + 0].pos = Vector2(x, y + (charData[letter].texH - charData[letter].bearingY) * fontScale); - vert[i + 1].pos = Vector2(x + charData[letter].texW * fontScale, y - charData[letter].bearingY * fontScale); - vert[i + 2].pos = Vector2(x, vert[i + 1].pos.y); + vert[i + 0].pos = Vector2(glyphStartX, y + (charData[letter].texH - charData[letter].bearingY) * fontScale); + vert[i + 1].pos = Vector2(glyphStartX + charData[letter].texW * fontScale, y - charData[letter].bearingY * fontScale); + vert[i + 2].pos = Vector2(glyphStartX, vert[i + 1].pos.y); Vector2 charTexCoord(charData[letter].texX, charData[letter].texY); Vector2 charTexSize(charData[letter].texW, charData[letter].texH); diff --git a/src/Font.h b/src/Font.h index 22644bdea..69c19fa3d 100644 --- a/src/Font.h +++ b/src/Font.h @@ -26,10 +26,11 @@ public: int texW; int texH; - float advX; - float advY; + float advX; //! Date: Thu, 27 Jun 2013 12:31:16 +0200 Subject: [PATCH 5/8] Slightly better color array function Converting only once should be faster. --- src/Renderer_draw_gl.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Renderer_draw_gl.cpp b/src/Renderer_draw_gl.cpp index 22dcf4c1e..afa0b1d4b 100644 --- a/src/Renderer_draw_gl.cpp +++ b/src/Renderer_draw_gl.cpp @@ -14,18 +14,22 @@ namespace Renderer { void setColor4bArray(GLubyte* array, unsigned int color) { - array[0] = (color & 0xff000000) / 0x1000000; - array[1] = (color & 0x00ff0000) / 0x10000; - array[2] = (color & 0x0000ff00) / 0x100; + array[0] = (color & 0xff000000) >> 24; + array[1] = (color & 0x00ff0000) >> 16; + array[2] = (color & 0x0000ff00) >> 8; array[3] = (color & 0x000000ff); } void buildGLColorArray(GLubyte* ptr, unsigned int color, unsigned int vertCount) { + //convert color from ???? to RGBA? + unsigned int colorRGBA; + setColor4bArray((GLubyte *)&colorRGBA, color); + //write color to unsigned int array + GLuint * uiPtr = (GLuint *)ptr; for(unsigned int i = 0; i < vertCount; i++) { - setColor4bArray(ptr, color); - ptr += 4; + uiPtr[i] = colorRGBA; } } From d986d739b2b139b7b89cfea9d3a35a9f7b34e1f4 Mon Sep 17 00:00:00 2001 From: Aloshi Date: Sat, 29 Jun 2013 07:30:32 -0500 Subject: [PATCH 6/8] Revert "Disable input device polling code to resolve freeze after ~45 minutes." This reverts commit 4a1206aee28705232308024ce4c03f39b96478fa. --- src/InputManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/InputManager.cpp b/src/InputManager.cpp index ae81962f1..5df74a951 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -165,14 +165,14 @@ void InputManager::init() SDL_JoystickEventState(SDL_ENABLE); //start timer for input device polling - //devicePollingTimer = SDL_AddTimer(POLLING_INTERVAL, devicePollingCallback, (void *)this); + devicePollingTimer = SDL_AddTimer(POLLING_INTERVAL, devicePollingCallback, (void *)this); loadConfig(); } void InputManager::deinit() { - //SDL_RemoveTimer(devicePollingTimer); + SDL_RemoveTimer(devicePollingTimer); SDL_JoystickEventState(SDL_DISABLE); From 1dfb45e133c04d7e8d38fb35ea5109e6a3565c14 Mon Sep 17 00:00:00 2001 From: Aloshi Date: Sat, 29 Jun 2013 20:37:18 -0500 Subject: [PATCH 7/8] Print all Log messages to cout with --debug set. Added startPolling and stopPolling to InputManager. --- src/InputManager.cpp | 25 ++++++++++++++++++++++--- src/InputManager.h | 3 +++ src/Log.cpp | 3 ++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/InputManager.cpp b/src/InputManager.cpp index e3490e207..168787a9f 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -28,7 +28,7 @@ bool InputDevice::operator==(const InputDevice & b) const InputManager::InputManager(Window* window) : mWindow(window), mJoysticks(NULL), mInputConfigs(NULL), mKeyboardInputConfig(NULL), mPrevAxisValues(NULL), - mNumJoysticks(0), mNumPlayers(0), devicePollingTimer(nullptr) + mNumJoysticks(0), mNumPlayers(0), devicePollingTimer(NULL) { } @@ -164,14 +164,31 @@ void InputManager::init() SDL_JoystickEventState(SDL_ENABLE); //start timer for input device polling - devicePollingTimer = SDL_AddTimer(POLLING_INTERVAL, devicePollingCallback, (void *)this); + startPolling(); loadConfig(); } +void InputManager::startPolling() +{ + if(devicePollingTimer != NULL) + return; + + devicePollingTimer = SDL_AddTimer(POLLING_INTERVAL, devicePollingCallback, (void *)this); +} + +void InputManager::stopPolling() +{ + if(devicePollingTimer == NULL) + return; + + SDL_RemoveTimer(devicePollingTimer); + devicePollingTimer = NULL; +} + void InputManager::deinit() { - SDL_RemoveTimer(devicePollingTimer); + stopPolling(); SDL_JoystickEventState(SDL_DISABLE); @@ -380,6 +397,8 @@ void InputManager::loadConfig() LOG(LogInfo) << "No input configs loaded. Loading default keyboard config."; loadDefaultConfig(); } + + LOG(LogInfo) << "Loaded InputConfig data for " << getNumPlayers() << " devices."; } //used in an "emergency" where no configs could be loaded from the inputmanager config file diff --git a/src/InputManager.h b/src/InputManager.h index 921a29fa5..e0cef8b61 100644 --- a/src/InputManager.h +++ b/src/InputManager.h @@ -77,6 +77,9 @@ public: bool parseEvent(const SDL_Event& ev); InputConfig* getInputConfigByPlayer(int player); + + void startPolling(); + void stopPolling(); }; #endif diff --git a/src/Log.cpp b/src/Log.cpp index fe3c50c6c..0e8522601 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -65,6 +65,7 @@ Log::~Log() fprintf(getOutput(), "%s", os.str().c_str()); //if it's an error, also print to console - if(messageLevel == LogError) + //print all messages if using --debug + if(messageLevel == LogError || reportingLevel >= LogDebug) fprintf(stderr, "%s", os.str().c_str()); } From f4e2a146857aef210dd5964f94be0a317fd6274b Mon Sep 17 00:00:00 2001 From: Aloshi Date: Sat, 29 Jun 2013 20:43:13 -0500 Subject: [PATCH 8/8] Temporarily disable polling while configuring inputs. Polling is disabled once the first device is chosen, and resumed once the last device is configured. --- src/components/GuiDetectDevice.cpp | 4 ++++ src/components/GuiInputConfig.cpp | 1 + 2 files changed, 5 insertions(+) diff --git a/src/components/GuiDetectDevice.cpp b/src/components/GuiDetectDevice.cpp index 8c05f1d91..570d4c9f4 100644 --- a/src/components/GuiDetectDevice.cpp +++ b/src/components/GuiDetectDevice.cpp @@ -44,6 +44,10 @@ bool GuiDetectDevice::input(InputConfig* config, Input input) if(!input.value) return false; + //don't allow device list to change once the first player has registered + if(mCurrentPlayer == 0) + mWindow->getInputManager()->stopPolling(); + config->setPlayerNum(mCurrentPlayer); mWindow->getInputManager()->setNumPlayers(mWindow->getInputManager()->getNumPlayers() + 1); //inc total number of players mCurrentPlayer++; diff --git a/src/components/GuiInputConfig.cpp b/src/components/GuiInputConfig.cpp index 6f217fcec..78f7a272a 100644 --- a/src/components/GuiInputConfig.cpp +++ b/src/components/GuiInputConfig.cpp @@ -38,6 +38,7 @@ bool GuiInputConfig::input(InputConfig* config, Input input) mWindow->pushGui(new GuiInputConfig(mWindow, mWindow->getInputManager()->getInputConfigByPlayer(mTargetConfig->getPlayerNum() + 1))); }else{ mWindow->getInputManager()->writeConfig(); + mWindow->getInputManager()->startPolling(); //enable polling again since we're done GuiGameList::create(mWindow); } delete this;