more c++ bootstrap refactoring

This commit is contained in:
Eric Froemling 2022-09-12 10:09:31 -07:00
parent 014a996933
commit 866f9475fb
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
18 changed files with 676 additions and 684 deletions

File diff suppressed because it is too large Load Diff

View File

@ -38,7 +38,7 @@ def bootstrap() -> None:
# Give a soft warning if we're being used with a different binary
# version than we expect.
expected_build = 20821
expected_build = 20822
running_build: int = env['build_number']
if running_build != expected_build:
print(

View File

@ -14,6 +14,7 @@
#include "ballistica/core/fatal_error.h"
#include "ballistica/core/logging.h"
#include "ballistica/core/thread.h"
#include "ballistica/dynamics/bg/bg_dynamics.h"
#include "ballistica/dynamics/bg/bg_dynamics_server.h"
#include "ballistica/game/v1_account.h"
#include "ballistica/graphics/graphics_server.h"
@ -30,7 +31,7 @@
namespace ballistica {
// These are set automatically via script; don't modify them here.
const int kAppBuildNumber = 20821;
const int kAppBuildNumber = 20822;
const char* kAppVersion = "1.7.7";
// Our standalone globals.
@ -55,8 +56,8 @@ Input* g_input{};
Thread* g_main_thread{};
Assets* g_assets{};
AssetsServer* g_assets_server{};
NetworkReader* g_network_reader{};
Networking* g_networking{};
NetworkReader* g_network_reader{};
NetworkWriter* g_network_writer{};
Platform* g_platform{};
Python* g_python{};
@ -99,16 +100,15 @@ auto BallisticaMain(int argc, char** argv) -> int {
g_app = new App(argc, argv);
g_platform = Platform::Create();
// Bootstrap our Python environment as early as we can (depends on
// g_platform for locating OS-specific paths).
g_python = new Python();
// Create a Thread wrapper around the current (main) thread.
g_main_thread = new Thread(ThreadIdentifier::kMain, ThreadType::kMain);
Thread::UpdateMainThreadID();
// Spin up our specific app and graphics variations
// (VR, headless, regular, etc.)
// Bootstrap our Python environment as early as we can (depends on
// g_platform for locating OS-specific paths).
g_python = new Python();
// Spin up our specific app and graphics variations (VR, headless, etc.)
g_app_flavor = g_platform->CreateAppFlavor();
g_graphics = g_platform->CreateGraphics();
@ -125,25 +125,21 @@ auto BallisticaMain(int argc, char** argv) -> int {
g_assets_server = new AssetsServer();
g_ui = Object::NewUnmanaged<UI>();
g_networking = new Networking();
g_network_writer = new NetworkWriter();
g_input = new Input();
g_app_internal = GetAppInternal();
g_app_internal = CreateAppInternal();
g_game = new Game();
Scene::Init();
if (!HeadlessMode()) {
g_bg_dynamics = new BGDynamics();
g_bg_dynamics_server = new BGDynamicsServer();
}
// Spin up our other standard threads.
auto* logic_thread{new Thread(ThreadIdentifier::kLogic)};
g_app->pausable_threads.push_back(logic_thread);
auto* network_write_thread{new Thread(ThreadIdentifier::kNetworkWrite)};
g_app->pausable_threads.push_back(network_write_thread);
// FIXME - move this later but need to init Python earlier then.
g_game->Start();
// Spin up our subsystems in those threads.
logic_thread->PushCallSynchronous(
[logic_thread] { new Game(logic_thread); });
network_write_thread->PushCallSynchronous(
[network_write_thread] { new NetworkWriter(network_write_thread); });
// Now let the platform spin up any other threads/modules it uses.
// (bg-dynamics in non-headless builds, stdin/stdout where applicable,
// etc.)
// NOTE TO SELF: this starts reading stdin and py-init hangs if we do
// it after here.
g_platform->CreateAuxiliaryModules();
// Ok at this point we can be considered up-and-running.

View File

@ -84,7 +84,7 @@ void Thread::WaitForNextEvent(bool single_cycle) {
}
// While we're waiting, allow other python threads to run.
if (holds_python_gil_) {
if (acquires_python_gil_) {
g_python->ReleaseGIL();
}
@ -117,7 +117,7 @@ void Thread::WaitForNextEvent(bool single_cycle) {
}
}
if (holds_python_gil_) {
if (acquires_python_gil_) {
g_python->AcquireGIL();
}
}
@ -357,8 +357,8 @@ auto Thread::ThreadMain() -> int {
}
}
void Thread::SetHoldsPythonGIL() {
holds_python_gil_ = true;
void Thread::SetAcquiresPythonGIL() {
acquires_python_gil_ = true;
g_python->AcquireGIL();
}

View File

@ -44,7 +44,7 @@ class Thread {
// Used to quit the main thread.
void Quit();
void SetHoldsPythonGIL();
void SetAcquiresPythonGIL();
void SetPaused(bool paused);
auto thread_id() const -> std::thread::id { return thread_id_; }
@ -137,7 +137,7 @@ class Thread {
std::thread::id thread_id_{};
ThreadIdentifier identifier_{ThreadIdentifier::kInvalid};
millisecs_t last_complaint_time_{};
bool holds_python_gil_{};
bool acquires_python_gil_{};
// FIXME: Should generalize this to some sort of PlatformThreadData class.
#if BA_XCODE_BUILD

View File

@ -14,15 +14,9 @@
namespace ballistica {
void BGDynamics::Init() {
// Just init our singleton.
new BGDynamics();
}
BGDynamics::BGDynamics() {
assert(InLogicThread());
// We're a singleton; make sure we don't already exist.
assert(g_bg_dynamics == nullptr);
g_bg_dynamics = this;
}
void BGDynamics::AddTerrain(CollideModelData* o) {

View File

@ -48,7 +48,7 @@ class BGDynamicsEmission {
// client (game thread) functionality for bg dynamics
class BGDynamics {
public:
static void Init();
BGDynamics();
void Emit(const BGDynamicsEmission& def);
void Step(const Vector3f& cam_pos);
@ -68,7 +68,6 @@ class BGDynamics {
void SetDrawSnapshot(BGDynamicsDrawSnapshot* s);
private:
BGDynamics();
void DrawChunks(FrameDef* frame_def, std::vector<Matrix44f>* instances,
BGDynamicsChunkType chunk_type);
Object::Ref<SpriteMesh> lights_mesh_;

View File

@ -660,12 +660,15 @@ void BGDynamicsServer::ParticleSet::UpdateAndCreateSnapshot(
current_set = !current_set;
}
BGDynamicsServer::BGDynamicsServer(Thread* thread)
: thread_(thread),
height_cache_(new BGDynamicsHeightCache()),
BGDynamicsServer::BGDynamicsServer()
: height_cache_(new BGDynamicsHeightCache()),
collision_cache_(new CollisionCache) {
// We're a singleton; make sure we don't already exist.
BA_PRECONDITION(g_bg_dynamics_server == nullptr);
g_bg_dynamics_server = this;
// Spin up our thread.
thread_ = new Thread(ThreadIdentifier::kBGDynamics);
g_app->pausable_threads.push_back(thread_);
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
ode_world_ = dWorldCreate();

View File

@ -80,7 +80,7 @@ class BGDynamicsServer {
std::vector<std::pair<BGDynamicsFuseData*, FuseStepData> > fuse_step_data_;
};
explicit BGDynamicsServer(Thread* thread);
BGDynamicsServer();
auto time() const -> uint32_t { return time_; }
auto graphics_quality() const -> GraphicsQuality { return graphics_quality_; }

View File

@ -17,12 +17,12 @@ CollisionCache::~CollisionCache() {
dGeomDestroy(test_box_);
}
void CollisionCache::SetGeoms(const std::vector<dGeomID>& geoms) {
auto CollisionCache::SetGeoms(const std::vector<dGeomID>& geoms) -> void {
dirty_ = true;
geoms_ = geoms;
}
void CollisionCache::Draw(FrameDef* frame_def) {
auto CollisionCache::Draw(FrameDef* frame_def) -> void {
if (cells_.empty()) {
return;
}
@ -124,7 +124,7 @@ void CollisionCache::Draw(FrameDef* frame_def) {
}
}
void CollisionCache::Precalc() {
auto CollisionCache::Precalc() -> void {
Update();
if (precalc_index_ >= cells_.size()) {
@ -138,8 +138,8 @@ void CollisionCache::Precalc() {
TestCell(precalc_index_++, x, z);
}
void CollisionCache::CollideAgainstGeom(dGeomID g1, void* data,
dNearCallback* callback) {
auto CollisionCache::CollideAgainstGeom(dGeomID g1, void* data,
dNearCallback* callback) -> void {
// Update bounds, test for quick out against our height map,
// and proceed to a full test on a positive result.
g1->recomputeAABB();
@ -204,7 +204,7 @@ void CollisionCache::CollideAgainstGeom(dGeomID g1, void* data,
}
}
void CollisionCache::TestCell(size_t cell_index, int x, int z) {
auto CollisionCache::TestCell(size_t cell_index, int x, int z) -> void {
int t_count = static_cast<int>(geoms_.size());
float top = cells_[cell_index].height_confirmed_empty_;
@ -252,8 +252,8 @@ void CollisionCache::TestCell(size_t cell_index, int x, int z) {
}
}
void CollisionCache::CollideAgainstSpace(dSpaceID space, void* data,
dNearCallback* callback) {
auto CollisionCache::CollideAgainstSpace(dSpaceID space, void* data,
dNearCallback* callback) -> void {
// We handle our own testing against trimeshes, so we can bring our fancy
// caching into play.
if (!geoms_.empty()) {
@ -264,7 +264,7 @@ void CollisionCache::CollideAgainstSpace(dSpaceID space, void* data,
}
}
void CollisionCache::Update() {
auto CollisionCache::Update() -> void {
if (!dirty_) {
return;
}

View File

@ -27,7 +27,7 @@ class CollisionCache {
// Call this periodically (once per cycle or so) to slowly fill in
// the cache so there's less to do during spurts of activity;
void Precalc();
auto Precalc() -> void;
private:
auto TestCell(size_t cell_index, int x, int z) -> void;

View File

@ -64,29 +64,33 @@ const int kMaxChatMessages = 40;
// Go with 5 minute ban.
const int kKickBanSeconds = 5 * 60;
Game::Game(Thread* thread)
: thread_(thread),
game_roster_(cJSON_CreateArray()),
Game::Game()
: game_roster_(cJSON_CreateArray()),
realtimers_(new TimerList()),
connections_(std::make_unique<ConnectionSet>()) {
// We're a singleton; make sure we don't already exist.
assert(g_game == nullptr);
g_game = this;
InitSpecialChars();
// Spin up our thread.
thread_ = new Thread(ThreadIdentifier::kLogic);
g_app->pausable_threads.push_back(thread_);
// Our thread should hold the Python GIL by default.
// TODO(ericf): It could be better to have each individual Python call
// we make acquire the GIL. Then we're not holding it during long
// bits of C++ logic.
thread_->SetAcquiresPythonGIL();
}
auto Game::Start() -> void {
thread_->PushCallSynchronous([this] { StartInThread(); });
}
auto Game::StartInThread() -> void {
try {
// Our thread should hold the Python GIL by default.
// TODO(ericf): It could be better to have each individual Python call
// we make acquire the GIL. Then we're not holding it during long
// bits of C++ logic.
thread->SetHoldsPythonGIL();
if (!HeadlessMode()) {
BGDynamics::Init();
}
InitSpecialChars();
// We want to be informed when our thread is pausing.
thread->AddPauseCallback(NewLambdaRunnableRaw([this] { OnThreadPause(); }));
thread()->AddPauseCallback(
NewLambdaRunnableRaw([this] { OnThreadPause(); }));
g_ui->LogicThreadInit();

View File

@ -24,7 +24,8 @@ const int kMaxPartyNameCombinedSize = 25;
/// rendering, etc.
class Game {
public:
explicit Game(Thread* thread);
Game();
auto Start() -> void;
auto LaunchHostSession(PyObject* session_type_obj,
BenchmarkType benchmark_type = BenchmarkType::kNone)
@ -244,6 +245,7 @@ class Game {
auto thread() const -> Thread* { return thread_; }
private:
auto StartInThread() -> void;
auto HandleQuitOnIdle() -> void;
auto InitSpecialChars() -> void;
auto Draw() -> void;

View File

@ -24,7 +24,7 @@ void StdInputModule::PushBeginReadCall() {
while (true) {
// Print a prompt if we're a tty.
// We send this to the game thread so it happens AFTER the
// We send this to the logic thread so it happens AFTER the
// results of the last script-command message we may have just sent.
if (stdin_is_terminal) {
g_game->thread()->PushCall([] {

View File

@ -10,7 +10,7 @@
namespace ballistica {
auto GetAppInternal() -> AppInternal*;
auto CreateAppInternal() -> AppInternal*;
class AppInternal {
public:

View File

@ -8,10 +8,13 @@
namespace ballistica {
NetworkWriter::NetworkWriter(Thread* thread) : thread_(thread) {
// we're a singleton
NetworkWriter::NetworkWriter() {
// We're a singleton; make sure we don't already exist.
assert(g_network_writer == nullptr);
g_network_writer = this;
// Spin up our thread.
thread_ = new Thread(ThreadIdentifier::kNetworkWrite);
g_app->pausable_threads.push_back(thread_);
}
void NetworkWriter::PushSendToCall(const std::vector<uint8_t>& msg,

View File

@ -12,8 +12,8 @@ namespace ballistica {
// A subsystem handling outbound network traffic.
class NetworkWriter {
public:
NetworkWriter();
void PushSendToCall(const std::vector<uint8_t>& msg, const SockAddr& addr);
explicit NetworkWriter(Thread* thread);
auto thread() const -> Thread* { return thread_; }
private:

View File

@ -701,15 +701,6 @@ auto Platform::GetKeyName(int keycode) -> std::string {
}
void Platform::CreateAuxiliaryModules() {
#if !BA_HEADLESS_BUILD
auto* bg_dynamics_thread = new Thread(ThreadIdentifier::kBGDynamics);
g_app->pausable_threads.push_back(bg_dynamics_thread);
#endif
#if !BA_HEADLESS_BUILD
bg_dynamics_thread->PushCallSynchronous(
[bg_dynamics_thread] { new BGDynamicsServer(bg_dynamics_thread); });
#endif
if (g_buildconfig.use_stdin_thread()) {
// Start listening for stdin commands (on platforms where that makes sense).
// Note: this thread blocks indefinitely for input so we don't add it to the