Merge branch 'platform-independent' of https://github.com/AbigailBuccaneer/colobot into AbigailBuccaneer-platform-independent

fix-squashed-planets
MrSimbax 2021-09-11 10:47:39 +02:00
commit 2b107736e2
27 changed files with 102 additions and 591 deletions

View File

@ -83,10 +83,6 @@ add_library(colobotbase STATIC
common/singleton.h
common/stringutils.cpp
common/stringutils.h
common/thread/resource_owning_thread.h
common/thread/sdl_cond_wrapper.h
common/thread/sdl_mutex_wrapper.h
common/thread/thread.h
common/thread/worker_thread.h
graphics/core/color.cpp
graphics/core/color.h

View File

@ -37,8 +37,6 @@
#include "common/system/system.h"
#include "common/thread/thread.h"
#include "graphics/core/nulldevice.h"
#include "graphics/opengl/glutil.h"
@ -61,6 +59,7 @@
#include <libintl.h>
#include <getopt.h>
#include <localename.h>
#include <thread>
char CApplication::m_languageLocale[] = { 0 };
@ -1052,9 +1051,9 @@ int CApplication::Run()
{
m_active = true;
m_systemUtils->GetCurrentTimeStamp(m_baseTimeStamp);
m_systemUtils->GetCurrentTimeStamp(m_lastTimeStamp);
m_systemUtils->GetCurrentTimeStamp(m_curTimeStamp);
m_baseTimeStamp = m_systemUtils->GetCurrentTimeStamp();
m_lastTimeStamp = m_systemUtils->GetCurrentTimeStamp();
m_curTimeStamp = m_systemUtils->GetCurrentTimeStamp();
MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start
@ -1495,13 +1494,13 @@ void CApplication::Render()
void CApplication::RenderIfNeeded(int updateRate)
{
m_systemUtils->GetCurrentTimeStamp(m_manualFrameTime);
m_manualFrameTime = m_systemUtils->GetCurrentTimeStamp();
long long diff = m_systemUtils->TimeStampExactDiff(m_manualFrameLast, m_manualFrameTime);
if (diff < 1e9f / updateRate)
{
return;
}
m_systemUtils->CopyTimeStamp(m_manualFrameLast, m_manualFrameTime);
m_manualFrameLast = m_manualFrameTime;
Render();
}
@ -1529,15 +1528,15 @@ void CApplication::ResetTimeAfterLoading()
void CApplication::InternalResumeSimulation()
{
m_systemUtils->GetCurrentTimeStamp(m_baseTimeStamp);
m_systemUtils->CopyTimeStamp(m_curTimeStamp, m_baseTimeStamp);
m_baseTimeStamp = m_systemUtils->GetCurrentTimeStamp();
m_curTimeStamp = m_baseTimeStamp;
m_realAbsTimeBase = m_realAbsTime;
m_absTimeBase = m_exactAbsTime;
}
void CApplication::StartLoadingMusic()
{
CThread musicLoadThread([this]()
std::thread{[this]()
{
GetLogger()->Debug("Cache sounds...\n");
SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp();
@ -1550,9 +1549,7 @@ void CApplication::StartLoadingMusic()
m_systemUtils->GetCurrentTimeStamp(musicLoadEnd);
float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC);
GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime);
},
"Sound loading thread");
musicLoadThread.Start();
}).detach();
}
bool CApplication::GetSimulationSuspended() const

View File

@ -27,6 +27,7 @@
#include "common/event.h"
#include "common/language.h"
#include "common/singleton.h"
#include "common/system/system.h"
#include "graphics/core/device.h"
@ -46,7 +47,6 @@ class CModManager;
class CPathManager;
class CConfigFile;
class CSystemUtils;
struct SystemTimeStamp;
namespace Gfx
{
@ -354,9 +354,9 @@ protected:
//! Animation time stamps, etc.
//@{
SystemTimeStamp* m_baseTimeStamp;
SystemTimeStamp* m_lastTimeStamp;
SystemTimeStamp* m_curTimeStamp;
SystemTimeStamp m_baseTimeStamp;
SystemTimeStamp m_lastTimeStamp;
SystemTimeStamp m_curTimeStamp;
long long m_realAbsTimeBase;
long long m_realAbsTime;
@ -373,8 +373,8 @@ protected:
bool m_simulationSuspended;
//@}
SystemTimeStamp* m_manualFrameLast;
SystemTimeStamp* m_manualFrameTime;
SystemTimeStamp m_manualFrameLast;
SystemTimeStamp m_manualFrameTime;
//! Graphics device to use
bool m_graphicsOverride = false;

View File

@ -606,8 +606,7 @@ std::string ParseEventType(EventType eventType)
CEventQueue::CEventQueue()
: m_mutex{},
m_fifo(),
: m_fifo(),
m_head{0},
m_tail{0},
m_total{0}
@ -625,15 +624,13 @@ bool CEventQueue::IsEmpty()
Else, adds the event to the queue and returns \c true. */
bool CEventQueue::AddEvent(Event&& event)
{
bool result{};
SDL_LockMutex(*m_mutex);
std::lock_guard<std::mutex> lock{m_mutex};
if (m_total >= MAX_EVENT_QUEUE)
{
GetLogger()->Warn("Event queue flood!\n");
result = false;
return false;
}
else
{
@ -644,19 +641,15 @@ bool CEventQueue::AddEvent(Event&& event)
m_total++;
result = true;
return true;
}
SDL_UnlockMutex(*m_mutex);
return result;
}
Event CEventQueue::GetEvent()
{
Event event;
SDL_LockMutex(*m_mutex);
std::lock_guard<std::mutex> lock{m_mutex};
if (m_head == m_tail)
{
@ -673,7 +666,5 @@ Event CEventQueue::GetEvent()
}
SDL_UnlockMutex(*m_mutex);
return event;
}

View File

@ -27,12 +27,11 @@
#include "common/key.h"
#include "common/make_unique.h"
#include "common/thread/sdl_mutex_wrapper.h"
#include "math/point.h"
#include "math/vector.h"
#include <memory>
#include <mutex>
/**
\enum EventType
@ -932,7 +931,7 @@ public:
Event GetEvent();
protected:
CSDLMutexWrapper m_mutex;
std::mutex m_mutex;
Event m_fifo[MAX_EVENT_QUEUE];
int m_head;
int m_tail;

View File

@ -26,7 +26,7 @@
CSystemUtils* CProfiler::m_systemUtils = nullptr;
long long CProfiler::m_performanceCounters[PCNT_MAX] = {0};
long long CProfiler::m_prevPerformanceCounters[PCNT_MAX] = {0};
std::stack<SystemTimeStamp*> CProfiler::m_runningPerformanceCounters;
std::stack<SystemTimeStamp> CProfiler::m_runningPerformanceCounters;
std::stack<PerformanceCounter> CProfiler::m_runningPerformanceCountersType;
void CProfiler::SetSystemUtils(CSystemUtils* systemUtils)
@ -39,8 +39,7 @@ void CProfiler::StartPerformanceCounter(PerformanceCounter counter)
if (counter == PCNT_ALL)
ResetPerformanceCounters();
SystemTimeStamp* timeStamp = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(timeStamp);
SystemTimeStamp timeStamp = m_systemUtils->GetCurrentTimeStamp();
m_runningPerformanceCounters.push(timeStamp);
m_runningPerformanceCountersType.push(counter);
}
@ -50,11 +49,8 @@ void CProfiler::StopPerformanceCounter(PerformanceCounter counter)
assert(m_runningPerformanceCountersType.top() == counter);
m_runningPerformanceCountersType.pop();
SystemTimeStamp* timeStamp = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(timeStamp);
SystemTimeStamp timeStamp = m_systemUtils->GetCurrentTimeStamp();
m_performanceCounters[counter] += m_systemUtils->TimeStampExactDiff(m_runningPerformanceCounters.top(), timeStamp);
m_systemUtils->DestroyTimeStamp(timeStamp);
m_systemUtils->DestroyTimeStamp(m_runningPerformanceCounters.top());
m_runningPerformanceCounters.pop();
if (counter == PCNT_ALL)

View File

@ -20,8 +20,8 @@
#pragma once
class CSystemUtils;
struct SystemTimeStamp;
#include "common/system/system.h"
#include <stack>
/**
@ -73,7 +73,7 @@ private:
static long long m_performanceCounters[PCNT_MAX];
static long long m_prevPerformanceCounters[PCNT_MAX];
static std::stack<SystemTimeStamp*> m_runningPerformanceCounters;
static std::stack<SystemTimeStamp> m_runningPerformanceCounters;
static std::stack<PerformanceCounter> m_runningPerformanceCountersType;
};

View File

@ -35,6 +35,7 @@
#include <cassert>
#include <iostream>
#include <algorithm>
#include <thread>
#include <SDL2/SDL.h>
@ -142,25 +143,17 @@ SystemDialogResult CSystemUtils::ConsoleSystemDialog(SystemDialogType type, cons
return result;
}
SystemTimeStamp* CSystemUtils::CreateTimeStamp()
SystemTimeStamp CSystemUtils::GetCurrentTimeStamp()
{
auto timeStamp = MakeUnique<SystemTimeStamp>();
SystemTimeStamp* timeStampPtr = timeStamp.get();
m_timeStamps.push_back(std::move(timeStamp));
return timeStampPtr;
return std::chrono::high_resolution_clock::now();
}
void CSystemUtils::DestroyTimeStamp(SystemTimeStamp *stamp)
long long CSystemUtils::TimeStampExactDiff(SystemTimeStamp before, SystemTimeStamp after)
{
m_timeStamps.erase(std::remove_if(m_timeStamps.begin(), m_timeStamps.end(), [&](const std::unique_ptr<SystemTimeStamp>& timeStamp) { return timeStamp.get() == stamp; }));
return std::chrono::duration_cast<std::chrono::nanoseconds>(after - before).count();
}
void CSystemUtils::CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src)
{
*dst = *src;
}
float CSystemUtils::TimeStampDiff(SystemTimeStamp *before, SystemTimeStamp *after, SystemTimeUnit unit)
float CSystemUtils::TimeStampDiff(SystemTimeStamp before, SystemTimeStamp after, SystemTimeUnit unit)
{
long long exact = TimeStampExactDiff(before, after);
@ -225,3 +218,8 @@ bool CSystemUtils::OpenWebsite(const std::string& url)
{
return false;
}
void CSystemUtils::Usleep(int usecs)
{
std::this_thread::sleep_for(std::chrono::microseconds{usecs});
}

View File

@ -26,6 +26,7 @@
#include "common/config.h"
#include <chrono>
#include <memory>
#include <string>
#include <vector>
@ -76,12 +77,7 @@ enum SystemTimeUnit
STU_USEC
};
/*
* Forward declaration of time stamp struct
* SystemTimeStamp should only be used in a pointer context.
* The implementation details are hidden because of platform dependence.
*/
struct SystemTimeStamp;
using SystemTimeStamp = std::chrono::time_point<std::chrono::high_resolution_clock>;
/**
* \class CSystemUtils
@ -107,31 +103,19 @@ public:
//! Displays a fallback system dialog using console
TEST_VIRTUAL SystemDialogResult ConsoleSystemDialog(SystemDialogType type, const std::string& title, const std::string& message);
//! Creates a new time stamp object
TEST_VIRTUAL SystemTimeStamp* CreateTimeStamp();
//! Destroys a time stamp object
TEST_VIRTUAL void DestroyTimeStamp(SystemTimeStamp *stamp);
//! Copies the time stamp from \a src to \a dst
TEST_VIRTUAL void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src);
//! Interpolates between two timestamps. If i=0 then dst=a. If i=1 then dst=b. If i=0.5 then dst is halfway between.
virtual void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) = 0;
//! Returns a time stamp associated with current time
virtual void GetCurrentTimeStamp(SystemTimeStamp *stamp) = 0;
TEST_VIRTUAL SystemTimeStamp GetCurrentTimeStamp();
//! Returns a difference between two timestamps in given time unit
/** The difference is \a after - \a before. */
TEST_VIRTUAL float TimeStampDiff(SystemTimeStamp *before, SystemTimeStamp *after, SystemTimeUnit unit = STU_SEC);
float TimeStampDiff(SystemTimeStamp before, SystemTimeStamp after, SystemTimeUnit unit = STU_SEC);
//! Returns the exact (in nanosecond units) difference between two timestamps
/** The difference is \a after - \a before. */
virtual long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) = 0;
//! Returns the path where the executable binary is located (ends with the path separator)
virtual std::string GetBasePath();
long long TimeStampExactDiff(SystemTimeStamp before, SystemTimeStamp after);
//! Returns the data path (containing textures, levels, helpfiles, etc)
virtual std::string GetDataPath();
@ -154,7 +138,7 @@ public:
virtual bool OpenWebsite(const std::string& url);
//! Sleep for given amount of microseconds
virtual void Usleep(int usecs) = 0;
void Usleep(int usecs);
private:
std::string m_basePath;

View File

@ -172,7 +172,3 @@ bool CSystemUtilsLinux::OpenWebsite(const std::string& url)
return true;
}
void CSystemUtilsLinux::Usleep(int usec)
{
usleep(usec);
}

View File

@ -28,11 +28,6 @@
//@colobot-lint-exclude UndefinedFunctionRule
struct SystemTimeStamp
{
timespec clockTime = {0, 0};
};
class CSystemUtilsLinux : public CSystemUtils
{
public:
@ -41,8 +36,6 @@ public:
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override;
void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;
std::string GetSaveDir() override;
@ -51,8 +44,6 @@ public:
bool OpenPath(const std::string& path) override;
bool OpenWebsite(const std::string& url) override;
void Usleep(int usec) override;
private:
bool m_zenityAvailable = false;
};

View File

@ -140,8 +140,3 @@ bool CSystemUtilsMacOSX::OpenWebsite(const std::string& url)
}
return true;
}
void CSystemUtilsMacOSX::Usleep(int usec)
{
usleep(usec);
}

View File

@ -41,8 +41,6 @@ public:
bool OpenPath(const std::string& path) override;
bool OpenWebsite(const std::string& url) override;
void Usleep(int usec) override;
private:
std::string m_ASPath;
std::string m_dataPath;

View File

@ -1,6 +1,6 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* Copyright (C) 2001-2018, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
@ -29,22 +29,3 @@ SystemDialogResult CSystemUtilsOther::SystemDialog(SystemDialogType type, const
return ConsoleSystemDialog(type, title, message);
}
void CSystemUtilsOther::GetCurrentTimeStamp(SystemTimeStamp* stamp)
{
stamp->sdlTicks = SDL_GetTicks();
}
void CSystemUtilsOther::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i)
{
dst->sdlTicks = a->sdlTicks + static_cast<Uint32>((b->sdlTicks - a->sdlTicks) * i);
}
long long int CSystemUtilsOther::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after)
{
return (after->sdlTicks - before->sdlTicks) * 1000000ll;
}
void CSystemUtilsOther::Usleep(int usec)
{
SDL_Delay(usec / 1000); // close enough
}

View File

@ -30,27 +30,11 @@
//@colobot-lint-exclude UndefinedFunctionRule
struct SystemTimeStamp
{
Uint32 sdlTicks;
SystemTimeStamp()
{
sdlTicks = 0;
}
};
class CSystemUtilsOther : public CSystemUtils
{
public:
void Init() override;
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override;
void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;
void Usleep(int usec) override;
};
//@end-colobot-lint-exclude

View File

@ -27,11 +27,6 @@
void CSystemUtilsWindows::Init()
{
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
m_counterFrequency = freq.QuadPart;
assert(m_counterFrequency != 0);
}
SystemDialogResult CSystemUtilsWindows::SystemDialog(SystemDialogType type, const std::string& title, const std::string& message)
@ -77,24 +72,6 @@ SystemDialogResult CSystemUtilsWindows::SystemDialog(SystemDialogType type, cons
return SDR_OK;
}
void CSystemUtilsWindows::GetCurrentTimeStamp(SystemTimeStamp* stamp)
{
LARGE_INTEGER value;
QueryPerformanceCounter(&value);
stamp->counterValue = value.QuadPart;
}
void CSystemUtilsWindows::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i)
{
dst->counterValue = a->counterValue + static_cast<long long>((b->counterValue - a->counterValue) * static_cast<double>(i));
}
long long int CSystemUtilsWindows::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after)
{
float floatValue = static_cast<double>(after->counterValue - before->counterValue) * (1e9 / static_cast<double>(m_counterFrequency));
return static_cast<long long>(floatValue);
}
//! Converts a wide Unicode string to an UTF8 string
std::string CSystemUtilsWindows::UTF8_Encode(const std::wstring& wstr)
{
@ -175,13 +152,3 @@ bool CSystemUtilsWindows::OpenWebsite(const std::string& url)
return true;
}
void CSystemUtilsWindows::Usleep(int usec)
{
LARGE_INTEGER ft;
ft.QuadPart = -(10 * usec); // Convert to 100 nanosecond interval, negative value indicates relative time
HANDLE timer = CreateWaitableTimer(nullptr, TRUE, nullptr);
SetWaitableTimer(timer, &ft, 0, nullptr, nullptr, 0);
WaitForSingleObject(timer, INFINITE);
CloseHandle(timer);
}

View File

@ -26,11 +26,6 @@
//@colobot-lint-exclude UndefinedFunctionRule
struct SystemTimeStamp
{
long long counterValue = 0;
};
class CSystemUtilsWindows : public CSystemUtils
{
public:
@ -38,10 +33,6 @@ public:
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override;
void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;
std::string GetSaveDir() override;
std::string GetEnvVar(const std::string& name) override;
@ -49,14 +40,9 @@ public:
bool OpenPath(const std::string& path) override;
bool OpenWebsite(const std::string& url) override;
void Usleep(int usec) override;
public:
static std::string UTF8_Encode(const std::wstring &wstr);
static std::wstring UTF8_Decode(const std::string &str);
protected:
long long m_counterFrequency = 0;
};
//@end-colobot-lint-exclude

View File

@ -1,133 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "common/thread/sdl_cond_wrapper.h"
#include "common/thread/sdl_mutex_wrapper.h"
#include <SDL_thread.h>
#include <memory>
#include <string>
/**
* \class CResourceOwningThread
* \brief Wrapper around SDL thread allowing passing of resources in safe manner
*
* This class is a workaround for passing ownership of resources in a safe
* manner to newly created threads. It takes a pointer to a function to call
* in new thread and a unique_ptr to resource which is to be passed to the new thread.
*
* This is how it works:
* - in main thread: create a new thread passing to it a special temporary context,
* - in main thread: wait for synchronization signal that the ownership was passed,
* - in new thread: acquire the resource from the context
* - in new thread: signal back to main thread that the resource was acquired,
* - in main thread: clean up temporary context and exit
* - in new thread: run the specified function with the acquired resource.
*
* It's a bit complicated, but that's the safe (thread-safe and exception-safe)
* way of doing this.
*/
template<typename Resource>
class CResourceOwningThread
{
public:
using ResourceUPtr = std::unique_ptr<Resource>;
using ThreadFunctionPtr = void(*)(ResourceUPtr);
CResourceOwningThread(ThreadFunctionPtr threadFunction, ResourceUPtr resource, std::string name = "")
: m_threadFunction(threadFunction),
m_resource(std::move(resource)),
m_name(name)
{}
~CResourceOwningThread()
{
SDL_DetachThread(m_thread);
}
void Start()
{
CSDLMutexWrapper mutex;
CSDLCondWrapper cond;
bool condition = false;
ThreadData data;
data.resource = std::move(m_resource);
data.threadFunction = m_threadFunction;
data.mutex = &mutex;
data.cond = &cond;
data.condition = &condition;
SDL_LockMutex(*mutex);
m_thread = SDL_CreateThread(Run, !m_name.empty() ? m_name.c_str() : nullptr, reinterpret_cast<void*>(&data));
while (!condition)
{
SDL_CondWait(*cond, *mutex);
}
SDL_UnlockMutex(*mutex);
}
void Join()
{
if (m_thread == nullptr) return;
SDL_WaitThread(m_thread, nullptr);
m_thread = nullptr;
}
private:
static int Run(void* data)
{
ThreadFunctionPtr threadFunction = nullptr;
ResourceUPtr resource;
ThreadData* threadData = reinterpret_cast<ThreadData*>(data);
SDL_LockMutex(**threadData->mutex);
threadFunction = threadData->threadFunction;
resource = std::move(threadData->resource);
*threadData->condition = true;
SDL_CondSignal(**threadData->cond);
SDL_UnlockMutex(**threadData->mutex);
threadFunction(std::move(resource));
return 0;
}
private:
struct ThreadData
{
ResourceUPtr resource;
CSDLMutexWrapper* mutex = nullptr;
CSDLCondWrapper* cond = nullptr;
bool* condition = nullptr;
ThreadFunctionPtr threadFunction = nullptr;
};
ThreadFunctionPtr m_threadFunction;
ResourceUPtr m_resource;
std::string m_name;
SDL_Thread* m_thread = nullptr;
};

View File

@ -1,62 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "common/thread/sdl_mutex_wrapper.h"
#include <SDL_thread.h>
/**
* \class CSDLCondWrapper
* \brief Wrapper for safe creation/deletion of SDL_cond
*/
class CSDLCondWrapper
{
public:
CSDLCondWrapper()
: m_cond(SDL_CreateCond())
{}
~CSDLCondWrapper()
{
SDL_DestroyCond(m_cond);
}
CSDLCondWrapper(const CSDLCondWrapper&) = delete;
CSDLCondWrapper& operator=(const CSDLCondWrapper&) = delete;
SDL_cond* operator*()
{
return m_cond;
}
void Signal()
{
SDL_CondSignal(m_cond);
}
void Wait(SDL_mutex* mutex)
{
SDL_CondWait(m_cond, mutex);
}
private:
SDL_cond* m_cond;
};

View File

@ -1,77 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "common/make_unique.h"
#include "common/thread/resource_owning_thread.h"
#include <functional>
#include <string>
#include <memory>
/**
* \class CThread
* \brief Wrapper for using SDL_thread with std::function
*/
class CThread
{
public:
using ThreadFunctionPtr = std::function<void()>;
private:
struct ThreadData
{
ThreadFunctionPtr func;
};
public:
CThread(ThreadFunctionPtr func, std::string name = "")
: m_func(std::move(func))
, m_name(name)
{}
void Start()
{
std::unique_ptr<ThreadData> data = MakeUnique<ThreadData>();
data->func = m_func;
m_thread = MakeUnique<CResourceOwningThread<ThreadData>>(Run, std::move(data), m_name);
m_thread->Start();
}
void Join()
{
if (!m_thread) return;
m_thread->Join();
}
CThread(const CThread&) = delete;
CThread& operator=(const CThread&) = delete;
private:
static void Run(std::unique_ptr<ThreadData> data)
{
data->func();
}
std::unique_ptr<CResourceOwningThread<ThreadData>> m_thread;
ThreadFunctionPtr m_func;
std::string m_name;
};

View File

@ -21,13 +21,12 @@
#include "common/make_unique.h"
#include "common/thread/sdl_cond_wrapper.h"
#include "common/thread/sdl_mutex_wrapper.h"
#include "common/thread/thread.h"
#include <condition_variable>
#include <functional>
#include <string>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
/**
* \class CWorkerThread
@ -39,27 +38,23 @@ public:
using ThreadFunctionPtr = std::function<void()>;
public:
CWorkerThread(std::string name = "")
: m_thread(std::bind(&CWorkerThread::Run, this), name)
{
m_thread.Start();
}
CWorkerThread() : m_thread{&CWorkerThread::Run, this} {}
~CWorkerThread()
{
m_mutex.Lock();
m_running = false;
m_cond.Signal();
m_mutex.Unlock();
m_thread.Join();
{
std::lock_guard<std::mutex> lock{m_mutex};
m_running = false;
m_cond.notify_one();
}
m_thread.join();
}
void Start(ThreadFunctionPtr func)
void Start(ThreadFunctionPtr&& func)
{
m_mutex.Lock();
std::lock_guard<std::mutex> lock{m_mutex};
m_queue.push(func);
m_cond.Signal();
m_mutex.Unlock();
m_cond.notify_one();
}
CWorkerThread(const CWorkerThread&) = delete;
@ -68,25 +63,21 @@ public:
private:
void Run()
{
m_mutex.Lock();
auto lock = std::unique_lock<std::mutex>(m_mutex);
while (true)
{
while (m_queue.empty() && m_running)
{
m_cond.Wait(*m_mutex);
}
m_cond.wait(lock, [&]() { return !m_running || !m_queue.empty(); });
if (!m_running) break;
ThreadFunctionPtr func = m_queue.front();
ThreadFunctionPtr func = std::move(m_queue.front());
m_queue.pop();
func();
}
m_mutex.Unlock();
}
CThread m_thread;
CSDLMutexWrapper m_mutex;
CSDLCondWrapper m_cond;
std::thread m_thread;
std::mutex m_mutex;
std::condition_variable m_cond;
bool m_running = true;
std::queue<ThreadFunctionPtr> m_queue;
};

View File

@ -32,8 +32,6 @@
#include "common/system/system.h"
#include "common/thread/resource_owning_thread.h"
#include "graphics/core/device.h"
#include "graphics/core/framebuffer.h"
@ -63,6 +61,7 @@
#include <iomanip>
#include <SDL_surface.h>
#include <SDL_thread.h>
#include <thread>
// Graphics module namespace
namespace Gfx
@ -218,8 +217,6 @@ CEngine::CEngine(CApplication *app, CSystemUtils* systemUtils)
m_mouseType = ENG_MOUSE_NORM;
m_fpsCounter = 0;
m_lastFrameTime = m_systemUtils->CreateTimeStamp();
m_currentFrameTime = m_systemUtils->CreateTimeStamp();
m_shadowColor = 0.5f;
@ -243,10 +240,6 @@ CEngine::CEngine(CApplication *app, CSystemUtils* systemUtils)
CEngine::~CEngine()
{
m_systemUtils->DestroyTimeStamp(m_lastFrameTime);
m_lastFrameTime = nullptr;
m_systemUtils->DestroyTimeStamp(m_currentFrameTime);
m_currentFrameTime = nullptr;
}
void CEngine::SetDevice(CDevice *device)
@ -364,8 +357,8 @@ bool CEngine::Create()
params.mipmap = false;
m_miceTexture = LoadTexture("textures/interface/mouse.png", params);
m_systemUtils->GetCurrentTimeStamp(m_currentFrameTime);
m_systemUtils->GetCurrentTimeStamp(m_lastFrameTime);
m_currentFrameTime = m_systemUtils->GetCurrentTimeStamp();
m_lastFrameTime = m_systemUtils->GetCurrentTimeStamp();
return true;
}
@ -503,8 +496,7 @@ void CEngine::WriteScreenShot(const std::string& fileName)
data->fileName = fileName;
CResourceOwningThread<WriteScreenShotData> thread(CEngine::WriteScreenShotThread, std::move(data), "WriteScreenShot thread");
thread.Start();
std::thread{&CEngine::WriteScreenShotThread, std::move(data)}.detach();
}
void CEngine::WriteScreenShotThread(std::unique_ptr<WriteScreenShotData> data)
@ -3175,11 +3167,11 @@ void CEngine::Render()
{
m_fpsCounter++;
m_systemUtils->GetCurrentTimeStamp(m_currentFrameTime);
m_currentFrameTime = m_systemUtils->GetCurrentTimeStamp();
float diff = m_systemUtils->TimeStampDiff(m_lastFrameTime, m_currentFrameTime, STU_SEC);
if (diff > 1.0f)
{
m_systemUtils->CopyTimeStamp(m_lastFrameTime, m_currentFrameTime);
m_lastFrameTime = m_currentFrameTime;
m_fps = m_fpsCounter / diff;
m_fpsCounter = 0;

View File

@ -25,6 +25,7 @@
#pragma once
#include "common/singleton.h"
#include "common/system/system.h"
#include "graphics/core/color.h"
#include "graphics/core/material.h"
@ -50,7 +51,6 @@ class CApplication;
class CSoundInterface;
class CImage;
class CSystemUtils;
struct SystemTimeStamp;
struct Event;
@ -1310,8 +1310,8 @@ protected:
//! Last encountered error
std::string m_error;
SystemTimeStamp* m_lastFrameTime;
SystemTimeStamp* m_currentFrameTime;
SystemTimeStamp m_lastFrameTime;
SystemTimeStamp m_currentFrameTime;
int m_fpsCounter;
float m_fps;

View File

@ -32,8 +32,7 @@ CALSound::CALSound()
m_musicVolume(1.0f),
m_channelsLimit(2048),
m_device{},
m_context{},
m_thread("Music loading thread")
m_context{}
{
}

View File

@ -1,4 +1,9 @@
# Test files
# Platform-dependent tests
if(PLATFORM_WINDOWS)
set(PLATFORM_TESTS common/system/system_windows_test.cpp)
elseif(PLATFORM_LINUX)
set(PLATFORM_TESTS common/system/system_linux_test.cpp)
endif()
set(TEST_FILES
common/colobot.ini

View File

@ -32,14 +32,6 @@
using namespace HippoMocks;
namespace ph = std::placeholders;
struct FakeSystemTimeStamp : public SystemTimeStamp
{
FakeSystemTimeStamp(int uid) : uid(uid), time(0) {}
int uid;
long long time;
};
class CApplicationWrapper : public CApplication
{
public:
@ -66,7 +58,6 @@ class CApplicationUT : public testing::Test
protected:
CApplicationUT() :
m_systemUtils(nullptr),
m_stampUid(0),
m_currentTime(0)
{}
@ -78,11 +69,7 @@ protected:
void NextInstant(long long diff);
SystemTimeStamp* CreateTimeStamp();
void DestroyTimeStamp(SystemTimeStamp *stamp);
void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src);
void GetCurrentTimeStamp(SystemTimeStamp *stamp);
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after);
SystemTimeStamp GetCurrentTimeStamp();
void TestCreateUpdateEvent(long long relTimeExact, long long absTimeExact,
float relTime, float absTime,
@ -92,10 +79,8 @@ protected:
std::unique_ptr<CApplicationWrapper> m_app;
MockRepository m_mocks;
CSystemUtils* m_systemUtils;
std::vector<std::unique_ptr<FakeSystemTimeStamp>> m_timeStamps;
private:
int m_stampUid;
long long m_currentTime;
};
@ -107,11 +92,7 @@ void CApplicationUT::SetUp()
m_mocks.OnCall(m_systemUtils, CSystemUtils::GetLangPath).Return("");
m_mocks.OnCall(m_systemUtils, CSystemUtils::GetSaveDir).Return("");
m_mocks.OnCall(m_systemUtils, CSystemUtils::CreateTimeStamp).Do(std::bind(&CApplicationUT::CreateTimeStamp, this));
m_mocks.OnCall(m_systemUtils, CSystemUtils::DestroyTimeStamp).Do(std::bind(&CApplicationUT::DestroyTimeStamp, this, ph::_1));
m_mocks.OnCall(m_systemUtils, CSystemUtils::CopyTimeStamp).Do(std::bind(&CApplicationUT::CopyTimeStamp, this, ph::_1, ph::_2));
m_mocks.OnCall(m_systemUtils, CSystemUtils::GetCurrentTimeStamp).Do(std::bind(&CApplicationUT::GetCurrentTimeStamp, this, ph::_1));
m_mocks.OnCall(m_systemUtils, CSystemUtils::TimeStampExactDiff).Do(std::bind(&CApplicationUT::TimeStampExactDiff, this, ph::_1, ph::_2));
m_mocks.OnCall(m_systemUtils, CSystemUtils::GetCurrentTimeStamp).Do(std::bind(&CApplicationUT::GetCurrentTimeStamp, this));
m_app = MakeUnique<CApplicationWrapper>(m_systemUtils);
}
@ -121,31 +102,10 @@ void CApplicationUT::TearDown()
m_app.reset();
}
SystemTimeStamp* CApplicationUT::CreateTimeStamp()
{
auto stamp = MakeUnique<FakeSystemTimeStamp>(++m_stampUid);
auto stampPtr = stamp.get();
m_timeStamps.push_back(std::move(stamp));
return stampPtr;
}
void CApplicationUT::DestroyTimeStamp(SystemTimeStamp *stamp)
SystemTimeStamp CApplicationUT::GetCurrentTimeStamp()
{
}
void CApplicationUT::CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src)
{
*static_cast<FakeSystemTimeStamp*>(dst) = *static_cast<FakeSystemTimeStamp*>(src);
}
void CApplicationUT::GetCurrentTimeStamp(SystemTimeStamp *stamp)
{
static_cast<FakeSystemTimeStamp*>(stamp)->time = m_currentTime;
}
long long CApplicationUT::TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after)
{
return static_cast<FakeSystemTimeStamp*>(after)->time - static_cast<FakeSystemTimeStamp*>(before)->time;
return SystemTimeStamp{SystemTimeStamp::duration{m_currentTime}};
}
void CApplicationUT::NextInstant(long long diff)

View File

@ -1,6 +1,6 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* Copyright (C) 2018, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
@ -17,44 +17,21 @@
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "common/system/system_other.h"
#include <SDL_thread.h>
#include <gtest/gtest.h>
/**
* \class CSDLMutexWrapper
* \brief Wrapper for safe creation/deletion of SDL_mutex
*/
class CSDLMutexWrapper
{
public:
CSDLMutexWrapper()
: m_mutex(SDL_CreateMutex())
{}
~CSDLMutexWrapper()
{
SDL_DestroyMutex(m_mutex);
}
CSDLMutexWrapper(const CSDLMutexWrapper&) = delete;
CSDLMutexWrapper& operator=(const CSDLMutexWrapper&) = delete;
SDL_mutex* operator*()
{
return m_mutex;
}
void Lock()
{
SDL_LockMutex(m_mutex);
}
void Unlock()
{
SDL_UnlockMutex(m_mutex);
}
private:
SDL_mutex* m_mutex;
struct SystemTest : ::testing::Test {
CSystemUtilsOther system;
};
TEST_F(SystemTest, TimeStampExactDiff) {
auto epoch = SystemTimeStamp{};
EXPECT_EQ(system.TimeStampExactDiff(epoch, epoch), 0);
auto duration = std::chrono::microseconds{123456789L};
auto before = std::chrono::high_resolution_clock::now();
auto after = before + duration;
EXPECT_EQ(system.TimeStampExactDiff(before, after), std::chrono::nanoseconds{duration}.count());
EXPECT_EQ(system.TimeStampExactDiff(after, before), -std::chrono::nanoseconds{duration}.count());
}