[App] Simplify and improve factory template.

[App] Rework audio and input system creation.
This commit is contained in:
gibbed 2019-08-03 17:01:34 -05:00
parent 848e2a4088
commit f5cddbbf3f
3 changed files with 90 additions and 63 deletions

View File

@ -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;
} }

View File

@ -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,

View File

@ -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,