53 constexpr U8 g_renderThreadPoolSize = 6u;
54 constexpr U8 g_assetLoadingPoolSize = 4u;
55 constexpr U8 g_backupThreadPoolSize = 2u;
57 DIVIDE_ASSERT(g_totalWorkerCount >= g_mininumTotalWorkerCount);
58 static_assert(g_renderThreadPoolSize + g_assetLoadingPoolSize + g_backupThreadPoolSize + g_renderThreadCount < g_mininumTotalWorkerCount);
65 case TaskPoolType::HIGH_PRIORITY:
return std::max(g_totalWorkerCount - g_backupThreadPoolSize - g_assetLoadingPoolSize - g_renderThreadPoolSize - g_renderThreadCount, 4u);
69 return g_totalWorkerCount;
73 : _platformContext(parentApp)
74 , _appLoopTimerMain(Time::ADD_TIMER(
"Main Loop Timer"))
75 , _appLoopTimerInternal(Time::ADD_TIMER(
"Internal Main Loop Timer"))
76 , _frameTimer(Time::ADD_TIMER(
"Total Frame Timer"))
77 , _appIdleTimer(Time::ADD_TIMER(
"Loop Idle Timer"))
78 , _appScenePass(Time::ADD_TIMER(
"Loop Scene Pass Timer"))
79 , _sceneUpdateTimer(Time::ADD_TIMER(
"Scene Update Timer"))
80 , _sceneUpdateLoopTimer(Time::ADD_TIMER(
"Scene Update Loop timer"))
81 , _cameraMgrTimer(Time::ADD_TIMER(
"Camera Manager Update Timer"))
82 , _flushToScreenTimer(Time::ADD_TIMER(
"Flush To Screen Timer"))
83 , _preRenderTimer(Time::ADD_TIMER(
"Pre-render Timer"))
84 , _postRenderTimer(Time::ADD_TIMER(
"Post-render Timer"))
85 , _splashScreenUpdating( false )
89 _platformContext.init(*
this);
103 _projectManager = std::make_unique<ProjectManager>(*
this);
104 _renderPassManager = std::make_unique<RenderPassManager>(*
this, _platformContext.gfx());
109 DIVIDE_ASSERT(projectManager() ==
nullptr && renderPassManager() ==
nullptr,
"Kernel destructor: not all resources have been released properly!");
113 bool expected =
false;
127 _splashScreen = std::make_unique<GUISplash>(
"divideLogo.jpg", _platformContext.config().runtime.splashScreenSize );
129 _platformContext.app().windowManager().drawToWindow(window);
131 _platformContext.app().windowManager().flushWindow();
145 if (window.type() ==
WindowType::WINDOW && _platformContext.config().runtime.maximizeOnStart)
163 _platformContext.idle(fast, deltaTimeUSGame, deltaTimeUSApp );
165 _projectManager->idle();
168 if (!fast && --g_printTimer == 0) {
170 g_printTimer = g_printTimerBase;
174 const bool freezeLoopTime = _platformContext.editor().simulationPaused() && _platformContext.editor().stepQueue() == 0u;
175 _timingData.freezeGameTime(freezeLoopTime);
176 _platformContext.app().mainLoopPaused(freezeLoopTime);
197 _platformContext.app().mainLoopActive(
false);
199 if (!projectManager()->saveActiveScene(
true,
false))
213 _platformContext.app().timer().update();
256 if (_platformContext.app().RestartRequested() || _platformContext.app().ShutdownRequested() )
261 const ErrorCode err = _platformContext.app().errorCode();
272 static bool statsEnabled =
false;
291 _platformContext.gui().modifyText(
"ProfileData",
platformContext().debug().output(),
true);
302 F32 fps = 0.f, frameTime = 0.f;
303 _platformContext.app().timer().getFrameRateAndTime(fps, frameTime);
304 const Str<256>& activeSceneName = _projectManager->activeProject()->getActiveScene()->resourceName();
306 constexpr const char* titleString =
"[{} - {}] - {} - {} - {:5.2f} FPS - {:3.2f} ms - FrameIndex: {} - Update Calls : {} - Alpha : {:1.2f}";
307 window.
title(titleString,
310 originalTitle.c_str(),
311 activeSceneName.c_str(),
315 _timingData.updateLoops(),
316 _timingData.alpha());
327 const I16 frameLimit = _platformContext.config().runtime.frameRateLimit;
331 const F32 deltaMilliseconds =
std::floorf(elapsedMS - (elapsedMS * 0.015f));
332 const F32 targetFrameTime = 1000.0f / frameLimit;
334 if (deltaMilliseconds < targetFrameTime)
338 std::this_thread::sleep_for(std::chrono::milliseconds(
to_I32(targetFrameTime - deltaMilliseconds)));
356 if (_platformContext.mainWindow().minimized())
363 if (!_platformContext.app().freezeRendering())
368 const U8 playerCount = _projectManager->activePlayerCount();
370 _timingData.updateLoops(0u);
372 constexpr U8 MAX_FRAME_SKIP = 4u;
385 if (_timingData.updateLoops() == 0u)
393 _platformContext.taskPool(
static_cast<TaskPoolType>(i)).flushCallbackQueue();
399 for (
U8 i = 0u; i < playerCount; ++i) {
416 _timingData.updateLoops(_timingData.updateLoops() + 1u);
419 const U8 loopCount = _timingData.updateLoops();
424 else if (loopCount == MAX_FRAME_SKIP)
464 const I32 xOffset = mainViewport.
x;
465 const I32 yOffset = mainViewport.
y;
466 const I32 width = mainViewport.
z;
467 const I32 height = mainViewport.
w;
469 targetViewports.resize(count);
472 }
else if (count == 1) {
473 targetViewports[0].set(mainViewport);
475 }
else if (count == 2) {
476 const I32 halfHeight = height / 2;
477 targetViewports[0].set(xOffset, halfHeight + yOffset, width, halfHeight);
478 targetViewports[1].set(xOffset, 0 + yOffset, width, halfHeight);
501 const auto resizeViewportContainer = [&rows](
const U32 numViewports) {
506 rows.resize(matrixSize);
507 std::for_each(std::begin(rows), std::end(rows), [matrixSize](ViewportRow& row) { row.resize(matrixSize); });
513 const U8 columnCount = resizeViewportContainer(count);
514 const U8 extraColumns = columnCount * columnCount - count;
515 const U8 extraRows = extraColumns / columnCount;
516 for (
U8 i = 0u; i < extraRows; ++i) {
519 const U8 columnsToRemove = extraColumns - extraRows * columnCount;
520 for (
U8 i = 0u; i < columnsToRemove; ++i) {
521 rows.back().pop_back();
524 const U8 rowCount =
to_U8(rows.size());
528 const I32 playerWidth = width / columnCount;
530 const I32 playerHeight = height /
to_I32(rowCount);
532 for (
U8 i = 0u; i < rowCount; ++i) {
533 ViewportRow& row = rows[i];
534 const I32 playerYOffset = playerHeight * (rowCount - i - 1);
535 for (
U8 j = 0; j <
to_U8(row.size()); ++j) {
536 const I32 playerXOffset = playerWidth * j;
537 row[j].set(playerXOffset, playerYOffset, playerWidth, playerHeight);
542 if (extraColumns > 0)
544 ViewportRow& lastRow = rows.back();
545 const I32 screenMidPoint = width / 2;
546 const I32 rowMidPoint = (
to_I32(lastRow.size()) * playerWidth) / 2;
547 const I32 slideFactor = screenMidPoint - rowMidPoint;
549 viewport.x += slideFactor;
555 for (
const ViewportRow& row : rows) {
557 targetViewports[idx++].set(viewport);
563 while (timers.size() <
to_size(index) + 1)
565 timers.push_back(&
Time::ADD_TIMER( Util::StringFormat<string>(
"{} {}", name, timers.size() ).c_str() ));
569 return *timers[index];
584 const U8 playerCount = _projectManager->activePlayerCount();
587 const Rect<I32> mainViewport{0, 0,
to_I32(backBufferRT->getWidth()),
to_I32(backBufferRT->getHeight())};
597 renderParams.
_sceneRenderState = &_projectManager->activeProject()->getActiveScene()->state()->renderState();
599 for (
U8 i = 0u; i < playerCount; ++i)
602 renderParams._playerPass = i;
613 renderParams._parentTimer = &timer;
615 _renderPassManager->render(renderParams);
646 _timingData.freezeGameTime(
true);
648 for (
U8 i = 0u; i < g_warmupFrameCount; ++i)
652 _timingData.freezeGameTime(
false);
670 g_printTimer = g_printTimerBase;
673 _platformContext.paramHandler().setDebugOutput(
false);
676 loadFromXML( config, Paths::g_xmlDataLocation, entryPoint.c_str() );
723 _platformContext.server().init(
static_cast<U16>(443),
"127.0.0.1",
true);
725 if (!_platformContext.client().connect(config.
serverAddress, 443))
727 _platformContext.client().connect(
"127.0.0.1", 443);
747 initError = _platformContext.gfx().initRenderingAPI(
_argc,
_argv, renderingAPI);
761 if (!_platformContext.taskPool( poolType ).init(
763 [&threadCounter, poolType, &ctx = _platformContext](
const std::thread::id& threadID)
766 threadCounter.fetch_sub(1);
776 initError = _platformContext.gfx().postInitRenderingAPI(config.
runtime.
resolution);
803 WindowManager& winManager = _platformContext.app().windowManager();
806 mgr->onChangeFocus(false);
811 mgr->onChangeFocus(true);
818 initError = _platformContext.gui().init(_platformContext);
827 initError = _platformContext.sfx().initAudioAPI();
852 if ( projects.empty() )
859 for (
auto& project : projects )
861 if (project._name == startupProject)
863 targetProject = project;
868 while ( targetProject._guid == 0 )
870 targetProject = projects.front();
872 startupProject = targetProject._name;
875 if ( targetProject._guid == 0 )
881 initError = _projectManager->loadProject( targetProject,
false );
890 if (!_projectManager->loadComplete())
896 _platformContext.gui().addText(
"ProfileData",
915 _renderPassManager->postInit();
925 ctx->editor().selectionChangeCallback(idx, nodes);
938 _platformContext.config().save();
942 _platformContext.taskPool(
static_cast<TaskPoolType>(i)).waitForAllTasks(
true);
947 _platformContext.editor().toggle(
false);
952 _projectManager.reset();
955 _renderPassManager.reset();
959 _platformContext.terminate();
973 _platformContext.editor().onWindowSizeChange(params);
978 _projectManager->onResolutionChange(params);
983 _platformContext.gui().onResolutionChange(params);
987 _platformContext.editor().onResolutionChange(params);
991#pragma region Input Management
994 vec2<I32> absPositionIn = { eventInOut.state().X.abs, eventInOut.state().Y.abs };
996 const Rect<I32> renderingViewport = _platformContext.mainWindow().renderingViewport();
1000 _platformContext.editor().running() &&
1001 !_platformContext.editor().hasFocus())
1003 const Rect<I32> previewRect = _platformContext.editor().scenePreviewRect(
false );
1004 absPositionIn =
COORD_REMAP( absPositionIn, previewRect, renderingViewport );
1005 if ( !previewRect.
contains(absPositionIn) )
1008 eventInOut.inScenePreviewRect(
true);
1012 const vec2<U16> resolution = _platformContext.gfx().renderingResolution();
1015 state.X.abs = absPositionIn.
x;
1016 state.Y.abs = absPositionIn.
y;
1022 !_projectManager->wantsMouse() &&
1044 !_projectManager->wantsMouse() &&
1066 !_projectManager->wantsMouse() &&
1088 if (inputConsumer && inputConsumer->onKeyDown(key)) {
1098 if (inputConsumer && inputConsumer->onKeyUp(key)) {
1108 if (inputConsumer && inputConsumer->joystickAxisMoved(arg)) {
1118 if (inputConsumer && inputConsumer->joystickPovMoved(arg)) {
1128 if (inputConsumer && inputConsumer->joystickButtonPressed(arg)) {
1138 if (inputConsumer && inputConsumer->joystickButtonReleased(arg)) {
1148 if (inputConsumer && inputConsumer->joystickBallMoved(arg)) {
1158 if (inputConsumer && inputConsumer->joystickAddRemove(arg)) {
1168 if (inputConsumer && inputConsumer->joystickRemap(arg)) {
1178 if (inputConsumer && inputConsumer->onTextEvent(arg)) {
#define WAIT_FOR_CONDITION(...)
#define PROFILE_SCOPE_AUTO(CATEGORY)
#define PROFILE_TAG(NAME,...)
#define PROFILE_SCOPE(NAME, CATEGORY)
static void SET_LOG_FUNCTION(const LOG_CBK &cbk)
Class that provides an interface between our framework and the OS (start/stop, display support,...
static ErrorCode SetRenderingAPI(Application &app, const RenderAPI api)
static void onWindowSizeChange(GFXDevice &device, const SizeChangeParams ¶ms)
static void update(GFXDevice &device, const U64 deltaTimeUSFixed, const U64 deltaTimeUSApp)
static void onResolutionChange(GFXDevice &device, const SizeChangeParams ¶ms)
static void onThreadCreated(const PlatformContext &context, const TaskPoolType poolType, const std::thread::id &threadID, const bool isMainRenderThread)
static bool networkUpdate(Divide::ProjectManager *manager, const U64 frameCount)
static ProjectIDs & init(Divide::ProjectManager *manager)
static void currentPlayerPass(Divide::ProjectManager *manager, const PlayerIndex idx)
static void initPostLoadState(Divide::ProjectManager *manager) noexcept
static void UseTextureDDSCache(const bool state) noexcept
static void DestroyPool()
static void Update(U64 deltaTimeUS)
bool hidden() const noexcept
bool maximized() const noexcept
void changeToPreviousType()
bool decorated() const noexcept
void centerWindowPosition()
Centering is also easier via SDL.
void setPosition(I32 x, I32 y, bool global=false, bool offset=false)
Window positioning is handled by SDL.
bool setDimensions(U16 width, U16 height)
width and height get adjusted to the closest supported value
const char * title() const noexcept
void changeType(WindowType newType)
vec2< U16 > getPreviousDimensions() const noexcept
static D64 FrameInterpolationFactor() noexcept
static U64 FrameCount() noexcept
bool joystickAddRemove(const Input::JoystickEvent &arg) override
bool joystickAxisMoved(const Input::JoystickEvent &arg) override
Joystick axis change.
ErrorCode initialize(const string &entryPoint)
FORCE_INLINE PlatformContext & platformContext() noexcept
Time::ProfileTimer & _frameTimer
Time::ProfileTimer & _postRenderTimer
bool onTextEvent(const Input::TextEvent &arg) override
Generated by text events (e.g. for SDL: SDL_TEXTEDITING and SDL_TEXTINPUT)
bool mouseButtonReleased(const Input::MouseButtonEvent &arg) override
Mouse button released.
bool joystickRemap(const Input::JoystickEvent &arg) override
bool mouseMoved(const Input::MouseMoveEvent &arg) override
Mouse moved.
Time::ProfileTimer & _sceneUpdateLoopTimer
bool joystickPovMoved(const Input::JoystickEvent &arg) override
Joystick direction change.
bool onKeyUp(const Input::KeyEvent &key) override
Key released.
void onWindowSizeChange(const SizeChangeParams ¶ms)
Time::ProfileTimer & _sceneUpdateTimer
bool presentToScreen(FrameEvent &evt)
Time::ProfileTimer & _appScenePass
static size_t TotalThreadCount(TaskPoolType type) noexcept
bool onKeyDown(const Input::KeyEvent &key) override
Key pressed.
Time::ProfileTimer & _cameraMgrTimer
bool joystickButtonPressed(const Input::JoystickEvent &arg) override
Joystick button pressed.
Time::ProfileTimer & _appIdleTimer
Time::ProfileTimer & _appLoopTimerInternal
void onLoop()
Our main application rendering loop: Call input requests, physics calculations, pre-rendering,...
std::array< InputAggregatorInterface *, to_base(InputConsumerType::COUNT)> _inputConsumers
bool mouseButtonPressed(const Input::MouseButtonEvent &arg) override
Mouse button pressed.
void remapAbsolutePosition(Input::MouseEvent &eventInOut) const noexcept
bool joystickButtonReleased(const Input::JoystickEvent &arg) override
Joystick button released.
Time::ProfileTimer & _flushToScreenTimer
Kernel(I32 argc, char **argv, Application &parentApp)
Time::ProfileTimer & _preRenderTimer
std::unique_ptr< GUISplash > _splashScreen
bool mainLoopScene(FrameEvent &evt)
FORCE_INLINE FrameListenerManager & frameListenerMgr() noexcept
Time::ProfileTimer & _appLoopTimerMain
bool joystickBallMoved(const Input::JoystickEvent &arg) override
void idle(bool fast, U64 deltaTimeUSGame, U64 deltaTimeUSApp)
vector< Rect< I32 > > _targetViewports
void onResolutionChange(const SizeChangeParams ¶ms)
vector< Time::ProfileTimer * > _renderTimer
std::atomic_bool _splashScreenUpdating
Rect< I32 > _prevViewport
GFXDevice & gfx() noexcept
static bool OnStartup(PlatformContext &context)
static bool OnShutdown(PlatformContext &context)
bool contains(U xIn, U yIn) const noexcept
static void OnFrameStart()
static void Init(RenderAPI renderAPI, PlatformContext &context)
static void PrintLeakedResources()
static void OnStartup(GFXDevice &context)
static void OnShutdown(GFXDevice &context)
static void initShadowMaps(GFXDevice &context)
static void destroyShadowMaps(GFXDevice &context)
void addChildTimer(ProfileTimer &child)
static void removeTimer(ProfileTimer &timer)
void set(const T *v) noexcept
set the 4 components of the vector manually using a source pointer to a (large enough) array
constexpr bool ENABLE_EDITOR
constexpr bool IS_SHIPPING_BUILD
constexpr bool IS_DEBUG_BUILD
constexpr bool IS_PROFILE_BUILD
constexpr bool IS_EDITOR_BUILD
constexpr U16 NETWORK_SEND_FREQUENCY_HZ
How often should the client send messages to the server.
constexpr U16 NETWORK_SEND_RETRY_COUNT
How many times should we try to send an update to the server before giving up?
constexpr U16 TARGET_FRAME_RATE
Application desired framerate for physics and input simulations.
constexpr char DEFAULT_PROJECT_NAME[]
constexpr size_t REQUIRED_RAM_SIZE_IN_BYTES
constexpr const char * DROID_SERIF_BOLD
ErrorCode ChangeLanguage(const char *newLanguage)
void Idle()
perform maintenance tasks
static const char * renderAPI[]
constexpr Optick::Category::Type IO
constexpr Optick::Category::Type Graphics
U64 ElapsedMicroseconds() noexcept
ProfileTimer & ADD_TIMER(const char *timerName)
const char * ErrorCodeToString(const ErrorCode err) noexcept
bool ExtractStartupProject(int argc, char **argv, string &projectOut, const char *arg_prefix="--")
bool FindCommandLineArgument(int argc, char **argv, const char *target_arg, const char *arg_prefix="--")
constexpr U32 g_printTimerBase
constexpr U8 g_warmupFrameCount
static U32 g_totalWorkerCount
constexpr U32 g_mininumTotalWorkerCount
constexpr U8 g_renderThreadCount
Handle console commands that start with a forward slash.
constexpr U32 to_U32(const T value)
@ FRAME_SCENERENDER_START
vector< ProjectID > ProjectIDs
void CLAMP_IN_RECT(T &inout_x, T &inout_y, T rect_x, T rect_y, T rect_z, T rect_w) noexcept
static Time::ProfileTimer & GetTimer(Time::ProfileTimer &parentTimer, vector< Time::ProfileTimer * > &timers, const U8 index, const char *name)
void SetThreadPriority(ThreadPriority priority)
static void ComputeViewports(const Rect< I32 > &mainViewport, vector< Rect< I32 > > &targetViewports, const U8 count)
eastl::vector< Type > vector
const SysInfo & const_sysInfo() noexcept
vec2< T > COORD_REMAP(vec2< T > input, const Rect< T > &in_rect, const Rect< T > &out_rect) noexcept
constexpr U8 to_U8(const T value)
constexpr size_t to_size(const T value)
constexpr U32 minSquareMatrixSize(U32 elementCount) noexcept
constexpr I32 to_I32(const T value)
void InitConditionalWait(PlatformContext &context) noexcept
@ MISSING_SCENE_LOAD_CALL
constexpr U64 FIXED_UPDATE_RATE_US
constexpr auto to_base(const Type value) -> Type
float floorf(const float in)
bool enableRenderAPIDebugging
bool enableRenderAPIBestPractices
bool assertOnRenderAPIError
struct Divide::Configuration::Debug::Cache cache
struct Divide::Configuration::Debug::Renderer renderer
struct Divide::Configuration::Runtime runtime
struct Divide::Configuration::Debug debug
static NO_INLINE void errorfn(const char *format, T &&... args)
static NO_INLINE void warnfn(const char *format, T &&... args)
static NO_INLINE void printfn(const char *format, T &&... args)
struct Divide::FrameEvent::Time::Impl _game
struct Divide::FrameEvent::Time::Impl _app
struct Divide::FrameEvent::Time _time
SceneRenderState * _sceneRenderState
static RenderTargetID BACK_BUFFER
StringReturnType< N > string() const noexcept
ResourcePath _workingDirectory
size_t _availableRamInBytes