Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
246 changes: 243 additions & 3 deletions project/src/backend/sdl/SDLApplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ namespace lime
static Uint32 s_lastSleepCalibration = 0;
static bool s_busyWaitOnly = false;
static bool firstTime = true;
static SDL_atomic_t s_waitEventBlocking;
#if defined(HX_WINDOWS) && !defined(HX_WINRT)
static SDL_atomic_t s_inModalEventWatch;
#endif

static inline void CalibrateSleepGuard(bool force = false)
{
Expand Down Expand Up @@ -119,6 +123,12 @@ namespace lime
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN);

currentApplication = this;
#if defined(HX_WINDOWS) && !defined(HX_WINRT)
modalWatchInstalled = false;
mainThreadID = SDL_ThreadID();
pendingResizeDispatchSkips = 0;
pendingWatchRenderSkips = 0;
#endif

framePeriod = 1000.0 / 60.0;
currentUpdate = 0;
Expand All @@ -142,6 +152,12 @@ namespace lime

SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
SDLJoystick::Init();
#if defined(HX_WINDOWS) && !defined(HX_WINRT)
SDL_AtomicSet(&s_inModalEventWatch, 0);
SDL_AtomicSet(&s_waitEventBlocking, 0);
SDL_AddEventWatch(ModalEventWatch, this);
modalWatchInstalled = true;
#endif

#ifdef HX_MACOS
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
Expand All @@ -159,8 +175,107 @@ namespace lime

SDLApplication::~SDLApplication()
{
#if defined(HX_WINDOWS) && !defined(HX_WINRT)
if (modalWatchInstalled && SDL_WasInit(0))
{
SDL_DelEventWatch(ModalEventWatch, this);
modalWatchInstalled = false;
}
#endif
}

#if defined(HX_WINDOWS) && !defined(HX_WINRT)
int SDLApplication::ModalEventWatch(void *userdata, SDL_Event *event)
{

if (!event || event->type != SDL_WINDOWEVENT)
return 0;

const Uint8 windowEvent = event->window.event;
if (windowEvent != SDL_WINDOWEVENT_EXPOSED && windowEvent != SDL_WINDOWEVENT_SIZE_CHANGED && windowEvent != SDL_WINDOWEVENT_RESIZED && windowEvent != SDL_WINDOWEVENT_MOVED)
return 0;

SDLApplication *application = (SDLApplication *)userdata;
if (!application || !application->active || inBackground)
return 0;
if (SDL_AtomicGet(&s_waitEventBlocking) == 0)
return 0;

if (SDL_ThreadID() != application->mainThreadID)
return 0;

// Prevent re-entry if rendering queues another window event.
if (!SDL_AtomicCAS(&s_inModalEventWatch, 0, 1))
return 0;

application->PumpOneFrameFromWatch(event);
SDL_AtomicSet(&s_inModalEventWatch, 0);
return 0;
}

void SDLApplication::PumpOneFrameFromWatch(SDL_Event *watchEvent)
{

if (!active || inBackground)
return;

bool isResizeEvent = false;
bool isExposeEvent = false;
if (watchEvent && watchEvent->type == SDL_WINDOWEVENT)
{
isResizeEvent = (watchEvent->window.event == SDL_WINDOWEVENT_SIZE_CHANGED || watchEvent->window.event == SDL_WINDOWEVENT_RESIZED);
isExposeEvent = (watchEvent->window.event == SDL_WINDOWEVENT_EXPOSED);
}

currentUpdate = SDL_GetTicks();
bool frameDue = ((Sint32)(currentUpdate - nextUpdate) >= 0);
bool isResizeOrExposeEvent = (isResizeEvent || isExposeEvent);
if (!frameDue && !isResizeEvent)
return;

bool exitedBlocking = false;
if (SDL_AtomicGet(&s_waitEventBlocking))
{
System::GCExitBlocking();
SDL_AtomicSet(&s_waitEventBlocking, 0);
exitedBlocking = true;
}

if (isResizeEvent)
{
ProcessWindowEvent(watchEvent);
pendingResizeDispatchSkips++;
}

if (frameDue)
{
applicationEvent.type = UPDATE;
applicationEvent.deltaTime = currentUpdate - lastUpdate;
lastUpdate = currentUpdate;

nextUpdate += NextFrameStep(framePeriod);
while (nextUpdate <= currentUpdate)
{
nextUpdate += NextFrameStep(framePeriod);
}

ApplicationEvent::Dispatch(&applicationEvent);
RenderEvent::Dispatch(&renderEvent);

if (watchEvent && isResizeOrExposeEvent)
{
pendingWatchRenderSkips++;
}
}

if (exitedBlocking)
{
System::GCEnterBlocking();
SDL_AtomicSet(&s_waitEventBlocking, 1);
}
}
#endif

int SDLApplication::Exec()
{

Expand Down Expand Up @@ -373,23 +488,106 @@ namespace lime

if (!inBackground)
{
bool skipImmediateRender = false;
#if defined(HX_WINDOWS) && !defined(HX_WINRT)
if (pendingWatchRenderSkips > 0)
{
pendingWatchRenderSkips--;
skipImmediateRender = true;
}

RenderEvent::Dispatch(&renderEvent);
if (SDL_AtomicGet(&s_waitEventBlocking))
{
PumpOneFrameFromWatch();
}
else
#endif
{
currentUpdate = SDL_GetTicks();
bool frameDue = ((Sint32)(currentUpdate - nextUpdate) >= 0);
if (frameDue)
{
applicationEvent.type = UPDATE;
applicationEvent.deltaTime = currentUpdate - lastUpdate;
lastUpdate = currentUpdate;

nextUpdate += NextFrameStep(framePeriod);
while (nextUpdate <= currentUpdate)
{
nextUpdate += NextFrameStep(framePeriod);
}

ApplicationEvent::Dispatch(&applicationEvent);
}

if (frameDue && !skipImmediateRender)
{
RenderEvent::Dispatch(&renderEvent);
}
}
}

break;

case SDL_WINDOWEVENT_SIZE_CHANGED:
case SDL_WINDOWEVENT_RESIZED:
{

ProcessWindowEvent(event);
bool skipResizeDispatch = false;
bool skipImmediateRender = false;
#if defined(HX_WINDOWS) && !defined(HX_WINRT)
if (pendingResizeDispatchSkips > 0)
{
pendingResizeDispatchSkips--;
skipResizeDispatch = true;
}
if (pendingWatchRenderSkips > 0)
{
pendingWatchRenderSkips--;
skipImmediateRender = true;
}
#endif
if (!skipResizeDispatch)
{
ProcessWindowEvent(event);
}

if (!inBackground)
{
#if defined(HX_WINDOWS) && !defined(HX_WINRT)
if (SDL_AtomicGet(&s_waitEventBlocking))
{
PumpOneFrameFromWatch();
}
else
#endif
{
currentUpdate = SDL_GetTicks();
bool frameDue = ((Sint32)(currentUpdate - nextUpdate) >= 0);
if (frameDue)
{
applicationEvent.type = UPDATE;
applicationEvent.deltaTime = currentUpdate - lastUpdate;
lastUpdate = currentUpdate;

RenderEvent::Dispatch(&renderEvent);
nextUpdate += NextFrameStep(framePeriod);
while (nextUpdate <= currentUpdate)
{
nextUpdate += NextFrameStep(framePeriod);
}

ApplicationEvent::Dispatch(&applicationEvent);
}

if (frameDue && !skipImmediateRender)
{
RenderEvent::Dispatch(&renderEvent);
}
}
}

break;
}

case SDL_WINDOWEVENT_CLOSE:

Expand Down Expand Up @@ -425,7 +623,12 @@ namespace lime
active = true;
lastUpdate = SDL_GetTicks();
nextUpdate = lastUpdate;
nextFrac = 0.0;
firstTime = true;
#if defined(HX_WINDOWS) && !defined(HX_WINRT)
pendingResizeDispatchSkips = 0;
pendingWatchRenderSkips = 0;
#endif
CalibrateSleepGuard(true);
}

Expand Down Expand Up @@ -902,6 +1105,7 @@ namespace lime
break;

case SDL_WINDOWEVENT_SIZE_CHANGED:
case SDL_WINDOWEVENT_RESIZED:

windowEvent.type = WINDOW_RESIZE;
windowEvent.width = event->window.data1;
Expand All @@ -923,6 +1127,13 @@ namespace lime

applicationEvent.type = EXIT;
ApplicationEvent::Dispatch(&applicationEvent);
#if defined(HX_WINDOWS) && !defined(HX_WINRT)
if (modalWatchInstalled)
{
SDL_DelEventWatch(ModalEventWatch, this);
modalWatchInstalled = false;
}
#endif

SDL_QuitSubSystem(initFlags);

Expand Down Expand Up @@ -956,6 +1167,7 @@ namespace lime
framePeriod = 1000.0;
}

nextFrac = 0.0;
s_busyWaitOnly = (framePeriod <= 2.0);
}

Expand Down Expand Up @@ -1116,6 +1328,7 @@ namespace lime
#else

bool isBlocking = false;
SDL_AtomicSet(&s_waitEventBlocking, 0);

for (;;)
{
Expand All @@ -1128,19 +1341,28 @@ namespace lime
case -1:

if (isBlocking)
{
SDL_AtomicSet(&s_waitEventBlocking, 0);
System::GCExitBlocking();
}
return 0;

case 1:

if (isBlocking)
{
SDL_AtomicSet(&s_waitEventBlocking, 0);
System::GCExitBlocking();
}
return 1;

default:

if (!isBlocking)
{
System::GCEnterBlocking();
SDL_AtomicSet(&s_waitEventBlocking, 1);
}
isBlocking = true;

Uint32 now = SDL_GetTicks();
Expand All @@ -1153,7 +1375,10 @@ namespace lime
event->type = SDL_USEREVENT;

if (isBlocking)
{
SDL_AtomicSet(&s_waitEventBlocking, 0);
System::GCExitBlocking();
}
return 1;
}

Expand All @@ -1179,14 +1404,20 @@ namespace lime
{

if (isBlocking)
{
SDL_AtomicSet(&s_waitEventBlocking, 0);
System::GCExitBlocking();
}
return 1;
}
else if (waitResult == -1)
{

if (isBlocking)
{
SDL_AtomicSet(&s_waitEventBlocking, 0);
System::GCExitBlocking();
}
return 0;
}

Expand All @@ -1207,13 +1438,19 @@ namespace lime
case -1:

if (isBlocking)
{
SDL_AtomicSet(&s_waitEventBlocking, 0);
System::GCExitBlocking();
}
return 0;

case 1:

if (isBlocking)
{
SDL_AtomicSet(&s_waitEventBlocking, 0);
System::GCExitBlocking();
}
return 1;

default:
Expand All @@ -1225,7 +1462,10 @@ namespace lime
event->type = SDL_USEREVENT;

if (isBlocking)
{
SDL_AtomicSet(&s_waitEventBlocking, 0);
System::GCExitBlocking();
}
return 1;
}

Expand Down
Loading