[App] Simplify and improve factory template.
[App] Rework audio and input system creation.
This commit is contained in:
parent
848e2a4088
commit
f5cddbbf3f
|
@ -65,64 +65,93 @@ DEFINE_bool(discord, true, "Enable Discord rich presence", "General");
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
template <class T>
|
template <typename T, typename... Args>
|
||||||
struct Factory {
|
class Factory {
|
||||||
|
private:
|
||||||
|
struct Creator {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::function<bool()> is_available;
|
std::function<bool()> is_available;
|
||||||
std::function<std::unique_ptr<T>()> instantiate;
|
std::function<std::unique_ptr<T>(Args...)> instantiate;
|
||||||
|
};
|
||||||
|
|
||||||
template <class DT>
|
std::vector<Creator> creators_;
|
||||||
static Factory Define(const std::string& name) {
|
|
||||||
return {name, DT::IsAvailable,
|
public:
|
||||||
[]() { return std::unique_ptr<DT>(new DT); }};
|
void Add(const std::string& name, std::function<bool()> is_available,
|
||||||
|
std::function<std::unique_ptr<T>(Args...)> instantiate) {
|
||||||
|
creators_.push_back({name, is_available, instantiate});
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<T> Create(const std::string& name,
|
void Add(const std::string& name,
|
||||||
const std::vector<Factory>& factories) {
|
std::function<std::unique_ptr<T>(Args...)> instantiate) {
|
||||||
|
Add(name, []() { return true; }, instantiate);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename DT>
|
||||||
|
void Add(const std::string& name) {
|
||||||
|
Add(name, DT::IsAvailable, [](Args... args) {
|
||||||
|
return std::unique_ptr<DT>(new DT(std::forward<Args>(args)...));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<T> Create(const std::string& name, Args... args) {
|
||||||
if (!name.empty() && name != "any") {
|
if (!name.empty() && name != "any") {
|
||||||
auto it = std::find_if(
|
auto it = std::find_if(
|
||||||
factories.begin(), factories.end(),
|
creators_.cbegin(), creators_.cend(),
|
||||||
[&name](const auto& f) { return name.compare(f.name) == 0; });
|
[&name](const auto& f) { return name.compare(f.name) == 0; });
|
||||||
if (it != factories.end() && (*it).is_available()) {
|
if (it != creators_.cend() && (*it).is_available()) {
|
||||||
return (*it).instantiate();
|
return (*it).instantiate(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else {
|
} else {
|
||||||
// Create best available.
|
for (const auto& creator : creators_) {
|
||||||
std::unique_ptr<T> best;
|
if (!creator.is_available()) continue;
|
||||||
for (const auto& factory : factories) {
|
auto instance = creator.instantiate(std::forward<Args>(args)...);
|
||||||
if (!factory.is_available()) continue;
|
if (!instance) continue;
|
||||||
best = factory.instantiate();
|
return instance;
|
||||||
if (!best) continue;
|
|
||||||
return best;
|
|
||||||
}
|
}
|
||||||
// Nothing!
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<T>> CreateAll(const std::string& name,
|
||||||
|
Args... args) {
|
||||||
|
std::vector<std::unique_ptr<T>> instances;
|
||||||
|
if (!name.empty() && name != "any") {
|
||||||
|
auto it = std::find_if(
|
||||||
|
creators_.cbegin(), creators_.cend(),
|
||||||
|
[&name](const auto& f) { return name.compare(f.name) == 0; });
|
||||||
|
if (it != creators_.cend() && (*it).is_available()) {
|
||||||
|
auto instance = (*it).instantiate(std::forward<Args>(args)...);
|
||||||
|
if (instance) {
|
||||||
|
instances.push_back(std::move(instance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const auto& creator : creators_) {
|
||||||
|
if (!creator.is_available()) continue;
|
||||||
|
auto instance = creator.instantiate(std::forward<Args>(args)...);
|
||||||
|
if (instance) {
|
||||||
|
instances.push_back(std::move(instance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instances;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<apu::AudioSystem> CreateAudioSystem(cpu::Processor* processor) {
|
std::unique_ptr<apu::AudioSystem> CreateAudioSystem(cpu::Processor* processor) {
|
||||||
if (cvars::apu.compare("nop") == 0) {
|
using NopAS = apu::nop::NopAudioSystem;
|
||||||
return apu::nop::NopAudioSystem::Create(processor);
|
using XAudio2AS = apu::xaudio2::XAudio2AudioSystem;
|
||||||
#if XE_PLATFORM_WIN32
|
using Factory = Factory<apu::AudioSystem, cpu::Processor*>;
|
||||||
} else if (cvars::apu.compare("xaudio2") == 0) {
|
|
||||||
return apu::xaudio2::XAudio2AudioSystem::Create(processor);
|
|
||||||
#endif // XE_PLATFORM_WIN32
|
|
||||||
} else {
|
|
||||||
// Create best available.
|
|
||||||
std::unique_ptr<apu::AudioSystem> best;
|
|
||||||
|
|
||||||
|
Factory factory;
|
||||||
#if XE_PLATFORM_WIN32
|
#if XE_PLATFORM_WIN32
|
||||||
best = apu::xaudio2::XAudio2AudioSystem::Create(processor);
|
factory.Add<XAudio2AS>("xaudio2");
|
||||||
if (best) {
|
|
||||||
return best;
|
|
||||||
}
|
|
||||||
#endif // XE_PLATFORM_WIN32
|
#endif // XE_PLATFORM_WIN32
|
||||||
|
factory.Add<NopAS>("nop");
|
||||||
|
|
||||||
// Fallback to nop.
|
return factory.Create(cvars::apu, processor);
|
||||||
return apu::nop::NopAudioSystem::Create(processor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() {
|
std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() {
|
||||||
|
@ -130,39 +159,31 @@ std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() {
|
||||||
using D3D12GS = gpu::d3d12::D3D12GraphicsSystem;
|
using D3D12GS = gpu::d3d12::D3D12GraphicsSystem;
|
||||||
using VulkanGS = gpu::vulkan::VulkanGraphicsSystem;
|
using VulkanGS = gpu::vulkan::VulkanGraphicsSystem;
|
||||||
using Factory = Factory<gpu::GraphicsSystem>;
|
using Factory = Factory<gpu::GraphicsSystem>;
|
||||||
std::vector<Factory> factories = {
|
|
||||||
|
Factory factory;
|
||||||
#if XE_PLATFORM_WIN32
|
#if XE_PLATFORM_WIN32
|
||||||
Factory::Define<D3D12GS>("d3d12"),
|
factory.Add<D3D12GS>("d3d12");
|
||||||
#endif // XE_PLATFORM_WIN32
|
#endif // XE_PLATFORM_WIN32
|
||||||
Factory::Define<VulkanGS>("vulkan"),
|
factory.Add<VulkanGS>("vulkan");
|
||||||
Factory::Define<NullGS>("null"),
|
factory.Add<NullGS>("null");
|
||||||
};
|
|
||||||
return Factory::Create(cvars::gpu, factories);
|
return factory.Create(cvars::gpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<hid::InputDriver>> CreateInputDrivers(
|
std::vector<std::unique_ptr<hid::InputDriver>> CreateInputDrivers(
|
||||||
ui::Window* window) {
|
ui::Window* window) {
|
||||||
std::vector<std::unique_ptr<hid::InputDriver>> drivers;
|
using Factory = Factory<hid::InputDriver, ui::Window*>;
|
||||||
if (cvars::hid.compare("nop") == 0) {
|
|
||||||
drivers.emplace_back(xe::hid::nop::Create(window));
|
Factory factory;
|
||||||
#if XE_PLATFORM_WIN32
|
#if XE_PLATFORM_WIN32
|
||||||
} else if (cvars::hid.compare("winkey") == 0) {
|
factory.Add("winkey", xe::hid::winkey::Create);
|
||||||
drivers.emplace_back(xe::hid::winkey::Create(window));
|
factory.Add("xinput", xe::hid::xinput::Create);
|
||||||
} else if (cvars::hid.compare("xinput") == 0) {
|
|
||||||
drivers.emplace_back(xe::hid::xinput::Create(window));
|
|
||||||
#endif // XE_PLATFORM_WIN32
|
#endif // XE_PLATFORM_WIN32
|
||||||
} else {
|
factory.Add("nop", xe::hid::nop::Create);
|
||||||
#if XE_PLATFORM_WIN32
|
|
||||||
auto xinput_driver = xe::hid::xinput::Create(window);
|
auto drivers = factory.CreateAll(cvars::hid, window);
|
||||||
if (xinput_driver) {
|
|
||||||
drivers.emplace_back(std::move(xinput_driver));
|
// Remove drivers that fail to setup.
|
||||||
}
|
|
||||||
auto winkey_driver = xe::hid::winkey::Create(window);
|
|
||||||
if (winkey_driver) {
|
|
||||||
drivers.emplace_back(std::move(winkey_driver));
|
|
||||||
}
|
|
||||||
#endif // XE_PLATFORM_WIN32
|
|
||||||
}
|
|
||||||
for (auto it = drivers.begin(); it != drivers.end();) {
|
for (auto it = drivers.begin(); it != drivers.end();) {
|
||||||
if (XFAILED((*it)->Setup())) {
|
if (XFAILED((*it)->Setup())) {
|
||||||
it = drivers.erase(it);
|
it = drivers.erase(it);
|
||||||
|
@ -170,10 +191,12 @@ std::vector<std::unique_ptr<hid::InputDriver>> CreateInputDrivers(
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drivers.empty()) {
|
if (drivers.empty()) {
|
||||||
// Fallback to nop if none created.
|
// Fallback to nop if none created.
|
||||||
drivers.emplace_back(xe::hid::nop::Create(window));
|
drivers.emplace_back(xe::hid::nop::Create(window));
|
||||||
}
|
}
|
||||||
|
|
||||||
return drivers;
|
return drivers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ class NopAudioSystem : public AudioSystem {
|
||||||
explicit NopAudioSystem(cpu::Processor* processor);
|
explicit NopAudioSystem(cpu::Processor* processor);
|
||||||
~NopAudioSystem() override;
|
~NopAudioSystem() override;
|
||||||
|
|
||||||
|
static bool IsAvailable() { return true; }
|
||||||
|
|
||||||
static std::unique_ptr<AudioSystem> Create(cpu::Processor* processor);
|
static std::unique_ptr<AudioSystem> Create(cpu::Processor* processor);
|
||||||
|
|
||||||
X_STATUS CreateDriver(size_t index, xe::threading::Semaphore* semaphore,
|
X_STATUS CreateDriver(size_t index, xe::threading::Semaphore* semaphore,
|
||||||
|
|
|
@ -21,6 +21,8 @@ class XAudio2AudioSystem : public AudioSystem {
|
||||||
explicit XAudio2AudioSystem(cpu::Processor* processor);
|
explicit XAudio2AudioSystem(cpu::Processor* processor);
|
||||||
~XAudio2AudioSystem() override;
|
~XAudio2AudioSystem() override;
|
||||||
|
|
||||||
|
static bool IsAvailable() { return true; }
|
||||||
|
|
||||||
static std::unique_ptr<AudioSystem> Create(cpu::Processor* processor);
|
static std::unique_ptr<AudioSystem> Create(cpu::Processor* processor);
|
||||||
|
|
||||||
X_RESULT CreateDriver(size_t index, xe::threading::Semaphore* semaphore,
|
X_RESULT CreateDriver(size_t index, xe::threading::Semaphore* semaphore,
|
||||||
|
|
Loading…
Reference in New Issue