Skip to content

Commit

Permalink
EVENTS: Generically force calling functions in the main thread
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
DrMcCoy committed Aug 6, 2012
1 parent 70aa420 commit 5268972
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 123 deletions.
31 changes: 3 additions & 28 deletions src/events/events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
Expand Down Expand Up @@ -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) {
Expand Down
7 changes: 1 addition & 6 deletions src/events/events.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,7 @@ class EventsManager : public Common::Singleton<EventsManager> {
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);

Expand Down
48 changes: 8 additions & 40 deletions src/events/requests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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);

Expand Down
23 changes: 12 additions & 11 deletions src/events/requests.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@

#include <list>

#include <boost/bind.hpp>

#include "common/types.h"
#include "common/singleton.h"
#include "common/thread.h"
Expand Down Expand Up @@ -87,17 +89,14 @@ class RequestManager : public Common::Singleton<RequestManager>, 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<typename T> T callInMainThread(const MainThreadFunctor<T> &f) {
MainThreadCallerFunctor caller(boost::bind(&MainThreadFunctor<T>::operator(), f));

callInMainThread(caller);

return f.getReturnValue();
}

/** Request that a GL container shall be rebuilt. */
RequestID rebuild(Graphics::GLContainer &glContainer);
Expand All @@ -120,6 +119,8 @@ class RequestManager : public Common::Singleton<RequestManager>, public Common::
void collectGarbage();

void threadMethod();

void callInMainThread(const MainThreadCallerFunctor &caller);
};

} // End of namespace Events
Expand Down
24 changes: 4 additions & 20 deletions src/events/requesttypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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. */
Expand Down
37 changes: 31 additions & 6 deletions src/events/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
#ifndef EVENTS_TYPES_H
#define EVENTS_TYPES_H

#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>

#include <SDL_events.h>

namespace Events {
Expand All @@ -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<typename T> struct MainThreadFunctor {
private:
boost::function<T ()> func;
boost::shared_ptr<T> retVal;

public:
MainThreadFunctor(const boost::function<T ()> &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<void> {
private:
boost::function<void ()> func;

public:
MainThreadFunctor(const boost::function<void ()> &f) : func(f) { }
void operator()() const { func(); }

void getReturnValue() const { (void) 0; }
};

typedef boost::function<void ()> MainThreadCallerFunctor;

} // End of namespace Events

#endif // EVENTS_TYPES_H
30 changes: 18 additions & 12 deletions src/graphics/graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
* The global graphics manager.
*/

#include <boost/bind.hpp>

#include "common/util.h"
#include "common/maths.h"
#include "common/error.h"
Expand Down Expand Up @@ -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<bool> functor(boost::bind(&GraphicsManager::setFSAA, this, level));

return RequestMan.callInMainThread(functor);
}

if (_fsaa == level)
Expand Down Expand Up @@ -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<void> functor(boost::bind(&GraphicsManager::setGamma, this, gamma));

return RequestMan.callInMainThread(functor);
}

_gamma = gamma;
Expand Down Expand Up @@ -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<void> functor(boost::bind(&GraphicsManager::setFullScreen, this, fullScreen));

return RequestMan.callInMainThread(functor);
}

destroyContext();
Expand Down Expand Up @@ -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<void> functor(boost::bind(&GraphicsManager::setScreenSize, this, width, height));

return RequestMan.callInMainThread(functor);
}

// Save properties
Expand Down

0 comments on commit 5268972

Please sign in to comment.