From 526897227e82efe64427c842aeed0aec64c41d3d Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Mon, 6 Aug 2012 14:06:36 +0200 Subject: [PATCH] EVENTS: Generically force calling functions in the main thread Instead of having one request type each for every thing that needs to be done in the main thread, we now throw functors around with the parameters bound to what was originally specified. So we can now have functions that notice they're not being called from the main thread automagically call themselves in the main thread with the correct parameters. --- src/events/events.cpp | 31 +++---------------------- src/events/events.h | 7 +----- src/events/requests.cpp | 48 +++++++-------------------------------- src/events/requests.h | 23 ++++++++++--------- src/events/requesttypes.h | 24 ++++---------------- src/events/types.h | 37 +++++++++++++++++++++++++----- src/graphics/graphics.cpp | 30 ++++++++++++++---------- 7 files changed, 77 insertions(+), 123 deletions(-) diff --git a/src/events/events.cpp b/src/events/events.cpp index f1e59693ff..e7345e266c 100644 --- a/src/events/events.cpp +++ b/src/events/events.cpp @@ -52,12 +52,7 @@ namespace Events { const EventsManager::RequestHandler EventsManager::_requestHandler[kITCEventMAX] = { 0, - &EventsManager::requestFullscreen, - &EventsManager::requestWindowed, - &EventsManager::requestResize, - &EventsManager::requestChangeFSAA, - &EventsManager::requestChangeVSync, - &EventsManager::requestChangeGamma, + &EventsManager::requestCallInMainThread, &EventsManager::requestRebuildGLContainer, &EventsManager::requestDestroyGLContainer }; @@ -333,28 +328,8 @@ Joystick *EventsManager::getJoystickByName(const Common::UString &name) const { return 0; } -void EventsManager::requestFullscreen(Request &request) { - GfxMan.setFullScreen(true); -} - -void EventsManager::requestWindowed(Request &request) { - GfxMan.setFullScreen(false); -} - -void EventsManager::requestResize(Request &request) { - GfxMan.setScreenSize(request._resize.width, request._resize.height); -} - -void EventsManager::requestChangeFSAA(Request &request) { - GfxMan.setFSAA(request._fsaa.level); -} - -void EventsManager::requestChangeVSync(Request &request) { - // TODO -} - -void EventsManager::requestChangeGamma(Request &request) { - GfxMan.setGamma(request._gamma.gamma); +void EventsManager::requestCallInMainThread(Request &request) { + (*request._callInMainThread.caller)(); } void EventsManager::requestRebuildGLContainer(Request &request) { diff --git a/src/events/events.h b/src/events/events.h index 8ddcd13522..be36399519 100644 --- a/src/events/events.h +++ b/src/events/events.h @@ -182,12 +182,7 @@ class EventsManager : public Common::Singleton { bool parseITC(const Event &event); // Request handler - void requestFullscreen(Request &request); - void requestWindowed(Request &request); - void requestResize(Request &request); - void requestChangeFSAA(Request &request); - void requestChangeVSync(Request &request); - void requestChangeGamma(Request &request); + void requestCallInMainThread(Request &request); void requestRebuildGLContainer(Request &request); void requestDestroyGLContainer(Request &request); diff --git a/src/events/requests.cpp b/src/events/requests.cpp index ec51e843a3..73e6bff999 100644 --- a/src/events/requests.cpp +++ b/src/events/requests.cpp @@ -131,46 +131,6 @@ void RequestManager::sync() { dispatchAndWait(syncID); } -RequestID RequestManager::fullscreen(bool fs) { - if (fs) - return newRequest(kITCEventFullscreen); - else - return newRequest(kITCEventWindowed); -} - -RequestID RequestManager::resize(int width, int height) { - RequestID rID = newRequest(kITCEventResize); - - (*rID)->_resize.width = width; - (*rID)->_resize.height = height; - - return rID; -} - -RequestID RequestManager::changeFSAA(int level) { - RequestID rID = newRequest(kITCEventChangeFSAA); - - (*rID)->_fsaa.level = level; - - return rID; -} - -RequestID RequestManager::changeVSync(bool vsync) { - RequestID rID = newRequest(kITCEventChangeVSync); - - (*rID)->_vsync.vsync = vsync; - - return rID; -} - -RequestID RequestManager::changeGamma(float gamma) { - RequestID rID = newRequest(kITCEventChangeGamma); - - (*rID)->_gamma.gamma = gamma; - - return rID; -} - RequestID RequestManager::rebuild(Graphics::GLContainer &glContainer) { RequestID rID = newRequest(kITCEventRebuildGLContainer); @@ -195,6 +155,14 @@ RequestID RequestManager::newRequest(ITCEvent type) { return --_requests.end(); } +void RequestManager::callInMainThread(const MainThreadCallerFunctor &caller) { + RequestID rID = newRequest(kITCEventCallInMainThread); + + (*rID)->_callInMainThread.caller = &caller; + + dispatchAndWait(rID); +} + void RequestManager::clearList() { Common::StackLock lock(_mutexUse); diff --git a/src/events/requests.h b/src/events/requests.h index bff9900835..7afdb03162 100644 --- a/src/events/requests.h +++ b/src/events/requests.h @@ -32,6 +32,8 @@ #include +#include + #include "common/types.h" #include "common/singleton.h" #include "common/thread.h" @@ -87,17 +89,14 @@ class RequestManager : public Common::Singleton, public Common:: /** Request a sync, letting all prior requests finish. */ void sync(); - // Screen mode - /** Request that the display shall be switched to fullscreen or windowed mode. */ - RequestID fullscreen(bool fs); - /** Request that the display shall be resized. */ - RequestID resize(int width, int height); - /** Request that the FSAA level shall be changed. */ - RequestID changeFSAA(int level); - /** Request that the vsync settings shall be changed. */ - RequestID changeVSync(bool vsync); - /** Request that the gamma settings shall be changed. */ - RequestID changeGamma(float gamma); + /** Call this function in the main thread. */ + template T callInMainThread(const MainThreadFunctor &f) { + MainThreadCallerFunctor caller(boost::bind(&MainThreadFunctor::operator(), f)); + + callInMainThread(caller); + + return f.getReturnValue(); + } /** Request that a GL container shall be rebuilt. */ RequestID rebuild(Graphics::GLContainer &glContainer); @@ -120,6 +119,8 @@ class RequestManager : public Common::Singleton, public Common:: void collectGarbage(); void threadMethod(); + + void callInMainThread(const MainThreadCallerFunctor &caller); }; } // End of namespace Events diff --git a/src/events/requesttypes.h b/src/events/requesttypes.h index 71181cdcb0..7105f85fa6 100644 --- a/src/events/requesttypes.h +++ b/src/events/requesttypes.h @@ -45,21 +45,8 @@ namespace Events { // Data structures for specific requests -struct RequestDataResize { - int width; - int height; -}; - -struct RequestDataChangeFSAA { - int level; -}; - -struct RequestDataChangeVSync { - bool vsync; -}; - -struct RequestDataChangeGamma { - float gamma; +struct RequestCallInMainThread { + const MainThreadCallerFunctor *caller; }; struct RequestDataGLContainer { @@ -86,11 +73,8 @@ class Request { /** Request data. */ union { - RequestDataResize _resize; - RequestDataChangeFSAA _fsaa; - RequestDataChangeVSync _vsync; - RequestDataChangeGamma _gamma; - RequestDataGLContainer _glContainer; + RequestCallInMainThread _callInMainThread; + RequestDataGLContainer _glContainer; }; /** Create the empty request frame. */ diff --git a/src/events/types.h b/src/events/types.h index 4609d32ff2..d002d2b0ad 100644 --- a/src/events/types.h +++ b/src/events/types.h @@ -30,6 +30,9 @@ #ifndef EVENTS_TYPES_H #define EVENTS_TYPES_H +#include +#include + #include namespace Events { @@ -54,17 +57,39 @@ enum EventType { /** Specific type of the inter-thread communication. */ enum ITCEvent { kITCEventSync = 0, ///< Request a sync, letting all prior requests finish. - kITCEventFullscreen , ///< Request switching to fullscreen mode. - kITCEventWindowed , ///< Request switching to windowed mode. - kITCEventResize , ///< Request changing the display size. - kITCEventChangeFSAA , ///< Request changing the FSAA level. - kITCEventChangeVSync , ///< Request changing the vsync settings. - kITCEventChangeGamma , ///< Request changing the gamma settings. + kITCEventCallInMainThread , ///< Request to call a function in the main thread. kITCEventRebuildGLContainer , ///< Request the rebuilding of a GL container. kITCEventDestroyGLContainer , ///< Request the destruction of a GL container. kITCEventMAX ///< For range checks. }; +/** A functor for a function that needs to be called in the main thread. */ +template struct MainThreadFunctor { +private: + boost::function func; + boost::shared_ptr retVal; + +public: + MainThreadFunctor(const boost::function &f) : func(f), retVal(new T) { } + void operator()() const { *retVal = func(); } + + T getReturnValue() const { return *retVal; } +}; + +/** Template specialization for a MainThreadFunctor returning void. */ +template<> struct MainThreadFunctor { +private: + boost::function func; + +public: + MainThreadFunctor(const boost::function &f) : func(f) { } + void operator()() const { func(); } + + void getReturnValue() const { (void) 0; } +}; + +typedef boost::function MainThreadCallerFunctor; + } // End of namespace Events #endif // EVENTS_TYPES_H diff --git a/src/graphics/graphics.cpp b/src/graphics/graphics.cpp index f64b2e6fb1..73f23f73ff 100644 --- a/src/graphics/graphics.cpp +++ b/src/graphics/graphics.cpp @@ -27,6 +27,8 @@ * The global graphics manager. */ +#include + #include "common/util.h" #include "common/maths.h" #include "common/error.h" @@ -207,10 +209,11 @@ void GraphicsManager::initSize(int width, int height, bool fullscreen) { } bool GraphicsManager::setFSAA(int level) { + // Force calling it from the main thread if (!Common::isMainThread()) { - // Not the main thread, send a request instead - RequestMan.dispatchAndWait(RequestMan.changeFSAA(level)); - return _fsaa == level; + Events::MainThreadFunctor functor(boost::bind(&GraphicsManager::setFSAA, this, level)); + + return RequestMan.callInMainThread(functor); } if (_fsaa == level) @@ -331,10 +334,11 @@ float GraphicsManager::getGamma() const { } void GraphicsManager::setGamma(float gamma) { + // Force calling it from the main thread if (!Common::isMainThread()) { - // Not the main thread, send a request instead - RequestMan.dispatchAndWait(RequestMan.changeGamma(gamma)); - return; + Events::MainThreadFunctor functor(boost::bind(&GraphicsManager::setGamma, this, gamma)); + + return RequestMan.callInMainThread(functor); } _gamma = gamma; @@ -1045,10 +1049,11 @@ void GraphicsManager::setFullScreen(bool fullScreen) { // Nothing to do return; + // Force calling it from the main thread if (!Common::isMainThread()) { - // Not the main thread, send a request instead - RequestMan.dispatchAndWait(RequestMan.fullscreen(fullScreen)); - return; + Events::MainThreadFunctor functor(boost::bind(&GraphicsManager::setFullScreen, this, fullScreen)); + + return RequestMan.callInMainThread(functor); } destroyContext(); @@ -1085,10 +1090,11 @@ void GraphicsManager::setScreenSize(int width, int height) { // No changes, nothing to do return; + // Force calling it from the main thread if (!Common::isMainThread()) { - // Not the main thread, send a request instead - RequestMan.dispatchAndWait(RequestMan.resize(width, height)); - return; + Events::MainThreadFunctor functor(boost::bind(&GraphicsManager::setScreenSize, this, width, height)); + + return RequestMan.callInMainThread(functor); } // Save properties