Introduces eve::cap in common/Capability.h: a name-keyed registry where the
consumer owns the interface, the provider registers an implementation, and
neither includes the other. It generalises what common/RenderTrace.h already
does for the render tracer, and supports both a single provider (provide/query)
and many ordered ones (addListener/forEach), keyed by string so a provider
compiled into a plugin lands in the same slot as the host.
Two upward dependencies go away:
system -> graphics IGpuInfo. The Vulkan physical-device fields move into
graphics/vulkan/GpuInfoProvider.cpp, with a WebGPU
counterpart, so System.cpp loses both the graphics
include and its EVENGINE_WEBGPU branches.
thread -> event IMainThreadPost. postMain and submitPost now enqueue
through the capability. The interface makes explicit
what was previously only a comment in submitPost: the
submitting thread calls prepare() so the worker never
reaches the module registry.
Both now report an error when no provider is linked, rather than lazily
creating a module the build may not contain.
Step S3 of docs/dev/模块编排与裁剪架构.md; back-edge whitelist 16 -> 14.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
217 lines
6.1 KiB
C++
217 lines
6.1 KiB
C++
#include "system/System.h"
|
|
|
|
#include "common/Exception.h"
|
|
#include "common/Module.h"
|
|
#include "common/Capability.h"
|
|
#include "common/GpuInfo.h"
|
|
#include "common/config.h"
|
|
|
|
#include <simplesquirrel/simplesquirrel.hpp>
|
|
|
|
#include <SDL2/SDL.h>
|
|
#include <SDL2/SDL_clipboard.h>
|
|
#include <SDL2/SDL_cpuinfo.h>
|
|
#include <SDL2/SDL_power.h>
|
|
|
|
#include <chrono>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <fstream>
|
|
#include <string>
|
|
|
|
#if defined(EVENGINE_WINDOWS) || defined(_WIN32)
|
|
#ifndef NOMINMAX
|
|
#define NOMINMAX
|
|
#endif
|
|
#include <windows.h>
|
|
#include <psapi.h>
|
|
#elif defined(__APPLE__)
|
|
#include <mach/mach.h>
|
|
#endif
|
|
|
|
namespace eve::system {
|
|
namespace {
|
|
|
|
/** The graphics backend's GPU description, or nullptr when none is linked. */
|
|
eve::caps::IGpuInfo *gpuInfoOrNull() {
|
|
auto *info = eve::cap::query<eve::caps::IGpuInfo>();
|
|
return (info && info->gpuReady()) ? info : nullptr;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
Module_IMPL(System, new System());
|
|
|
|
System::System() { SDL_InitSubSystem(SDL_INIT_TIMER); }
|
|
|
|
std::string System::getEngineVersion() const { return EVENGINE_VERSION; }
|
|
|
|
std::string System::getPlatform() const {
|
|
const char *p = SDL_GetPlatform();
|
|
return p ? p : "Unknown";
|
|
}
|
|
|
|
std::string System::getOS() const {
|
|
#if defined(EVENGINE_WINDOWS)
|
|
return "Windows";
|
|
#elif defined(EVENGINE_IOS)
|
|
return "iOS";
|
|
#elif defined(EVENGINE_MACOSX)
|
|
return "OS X";
|
|
#elif defined(EVENGINE_ANDROID)
|
|
return "Android";
|
|
#elif defined(EVENGINE_LINUX)
|
|
return "Linux";
|
|
#else
|
|
return getPlatform();
|
|
#endif
|
|
}
|
|
|
|
int System::getProcessorCount() const {
|
|
int n = SDL_GetCPUCount();
|
|
return n > 0 ? n : 1;
|
|
}
|
|
|
|
int System::getCPUCacheLineSize() const {
|
|
int n = SDL_GetCPUCacheLineSize();
|
|
return n > 0 ? n : 0;
|
|
}
|
|
|
|
int System::getSystemRAM() const {
|
|
int mb = SDL_GetSystemRAM();
|
|
return mb > 0 ? mb : 0;
|
|
}
|
|
|
|
int System::getProcessMemoryMB() const {
|
|
#if defined(EVENGINE_WINDOWS) || defined(_WIN32)
|
|
PROCESS_MEMORY_COUNTERS pmc{};
|
|
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
|
|
return static_cast<int>(pmc.WorkingSetSize / (1024ull * 1024ull));
|
|
return 0;
|
|
#elif defined(__APPLE__)
|
|
task_vm_info_data_t info{};
|
|
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
|
|
if (task_info(mach_task_self(), TASK_VM_INFO, reinterpret_cast<task_info_t>(&info), &count) ==
|
|
KERN_SUCCESS) {
|
|
return static_cast<int>(info.phys_footprint / (1024ull * 1024ull));
|
|
}
|
|
return 0;
|
|
#elif defined(__linux__) || defined(EVENGINE_ANDROID) || defined(EVENGINE_LINUX)
|
|
std::ifstream in("/proc/self/status");
|
|
if (!in) return 0;
|
|
std::string key;
|
|
while (in >> key) {
|
|
if (key == "VmRSS:") {
|
|
long kb = 0;
|
|
in >> kb;
|
|
return static_cast<int>(kb / 1024);
|
|
}
|
|
std::string rest;
|
|
std::getline(in, rest);
|
|
}
|
|
return 0;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
float System::getWallTime() const {
|
|
using clock = std::chrono::system_clock;
|
|
auto tp = clock::now().time_since_epoch();
|
|
auto us = std::chrono::duration_cast<std::chrono::microseconds>(tp).count();
|
|
return float(double(us) / 1'000'000.0);
|
|
}
|
|
|
|
void System::sleepMilliseconds(int ms) {
|
|
if (ms < 0) throw Exception("System.sleepMilliseconds: ms must be >= 0");
|
|
if (ms == 0) return;
|
|
SDL_Delay(static_cast<Uint32>(ms));
|
|
}
|
|
|
|
std::string System::getPowerState() const {
|
|
int secs = 0, pct = 0;
|
|
SDL_PowerState st = SDL_GetPowerInfo(&secs, &pct);
|
|
switch (st) {
|
|
case SDL_POWERSTATE_ON_BATTERY: return "on_battery";
|
|
case SDL_POWERSTATE_NO_BATTERY: return "no_battery";
|
|
case SDL_POWERSTATE_CHARGING: return "charging";
|
|
case SDL_POWERSTATE_CHARGED: return "charged";
|
|
default: return "unknown";
|
|
}
|
|
}
|
|
|
|
int System::getPowerSecondsLeft() const {
|
|
int secs = -1, pct = -1;
|
|
SDL_GetPowerInfo(&secs, &pct);
|
|
return secs;
|
|
}
|
|
|
|
int System::getPowerPercent() const {
|
|
int secs = -1, pct = -1;
|
|
SDL_GetPowerInfo(&secs, &pct);
|
|
return pct;
|
|
}
|
|
|
|
std::string System::getClipboardText() const {
|
|
if (!SDL_HasClipboardText()) return {};
|
|
char *t = SDL_GetClipboardText();
|
|
if (!t) return {};
|
|
std::string out(t);
|
|
SDL_free(t);
|
|
return out;
|
|
}
|
|
|
|
void System::setClipboardText(const std::string &text) {
|
|
if (SDL_SetClipboardText(text.c_str()) != 0)
|
|
throw Exception("System.setClipboardText failed: %s", SDL_GetError());
|
|
}
|
|
|
|
std::string System::getGpuName() const {
|
|
auto *info = gpuInfoOrNull();
|
|
return info ? info->gpuName() : std::string();
|
|
}
|
|
|
|
std::string System::getGpuVendor() const {
|
|
auto *info = gpuInfoOrNull();
|
|
return info ? info->gpuVendor() : std::string();
|
|
}
|
|
|
|
std::string System::getGpuDeviceType() const {
|
|
auto *info = gpuInfoOrNull();
|
|
return info ? info->gpuDeviceType() : std::string();
|
|
}
|
|
|
|
int System::getGpuMemoryTotalMB() const {
|
|
auto *info = gpuInfoOrNull();
|
|
return info ? info->gpuMemoryTotalMB() : 0;
|
|
}
|
|
|
|
void System::expose(ssq::Table &table) {
|
|
auto cls = table.addClass(name, System::create, false);
|
|
expose(cls);
|
|
}
|
|
|
|
void System::expose(ssq::Class &cls) {
|
|
cls.addFunc("getName", &System::getName);
|
|
cls.addFunc("getEngineVersion", &System::getEngineVersion);
|
|
cls.addFunc("getPlatform", &System::getPlatform);
|
|
cls.addFunc("getOS", &System::getOS);
|
|
cls.addFunc("getProcessorCount", &System::getProcessorCount);
|
|
cls.addFunc("getCPUCacheLineSize", &System::getCPUCacheLineSize);
|
|
cls.addFunc("getSystemRAM", &System::getSystemRAM);
|
|
cls.addFunc("getProcessMemoryMB", &System::getProcessMemoryMB);
|
|
cls.addFunc("getWallTime", &System::getWallTime);
|
|
cls.addFunc("sleepMilliseconds", &System::sleepMilliseconds);
|
|
cls.addFunc("getPowerState", &System::getPowerState);
|
|
cls.addFunc("getPowerSecondsLeft", &System::getPowerSecondsLeft);
|
|
cls.addFunc("getPowerPercent", &System::getPowerPercent);
|
|
cls.addFunc("getClipboardText", &System::getClipboardText);
|
|
cls.addFunc("setClipboardText", &System::setClipboardText);
|
|
cls.addFunc("getGpuName", &System::getGpuName);
|
|
cls.addFunc("getGpuVendor", &System::getGpuVendor);
|
|
cls.addFunc("getGpuDeviceType", &System::getGpuDeviceType);
|
|
cls.addFunc("getGpuMemoryTotalMB", &System::getGpuMemoryTotalMB);
|
|
}
|
|
|
|
} // namespace eve::system
|