2020-12-05 13:08:24 +01:00
|
|
|
#include "render_creator.h"
|
2020-04-07 19:53:07 +02:00
|
|
|
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
|
|
|
|
|
#include "Utilities/Thread.h"
|
|
|
|
|
|
2021-11-13 16:11:49 +01:00
|
|
|
#if defined(HAVE_VULKAN)
|
2021-01-09 19:46:50 +01:00
|
|
|
#include "Emu/RSX/VK/vkutils/instance.hpp"
|
2020-04-07 19:53:07 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <chrono>
|
|
|
|
|
#include <condition_variable>
|
|
|
|
|
#include <mutex>
|
2020-10-30 21:26:22 +01:00
|
|
|
#include <thread>
|
2021-01-09 19:46:50 +01:00
|
|
|
#include <util/logs.hpp>
|
2020-04-07 19:53:07 +02:00
|
|
|
|
|
|
|
|
LOG_CHANNEL(cfg_log, "CFG");
|
|
|
|
|
|
|
|
|
|
render_creator::render_creator(QObject *parent) : QObject(parent)
|
|
|
|
|
{
|
2021-11-13 16:11:49 +01:00
|
|
|
#if defined(HAVE_VULKAN)
|
2020-04-07 19:53:07 +02:00
|
|
|
// Some drivers can get stuck when checking for vulkan-compatible gpus, f.ex. if they're waiting for one to get
|
|
|
|
|
// plugged in. This whole contraption is for showing an error message in case that happens, so that user has
|
|
|
|
|
// some idea about why the emulator window isn't showing up.
|
|
|
|
|
|
2020-12-06 13:15:19 +01:00
|
|
|
static atomic_t<bool> was_called = false;
|
2020-04-07 19:53:07 +02:00
|
|
|
if (was_called.exchange(true))
|
2020-12-09 16:04:52 +01:00
|
|
|
fmt::throw_exception("Render_Creator cannot be created more than once");
|
2020-04-07 19:53:07 +02:00
|
|
|
|
|
|
|
|
static std::mutex mtx;
|
|
|
|
|
static std::condition_variable cond;
|
2021-03-18 10:09:42 +01:00
|
|
|
static bool work_done = false;
|
2020-04-07 19:53:07 +02:00
|
|
|
|
2021-03-18 10:09:42 +01:00
|
|
|
auto enum_thread_v = new named_thread("Vulkan Device Enumeration Thread"sv, [&, adapters = &this->vulkan_adapters]()
|
2020-04-07 19:53:07 +02:00
|
|
|
{
|
2021-01-25 19:49:16 +01:00
|
|
|
thread_ctrl::scoped_priority low_prio(-1);
|
2020-04-07 19:53:07 +02:00
|
|
|
|
2021-01-09 19:46:50 +01:00
|
|
|
vk::instance device_enum_context;
|
2021-03-18 10:09:42 +01:00
|
|
|
|
|
|
|
|
std::unique_lock lock(mtx, std::defer_lock);
|
|
|
|
|
|
2021-01-09 19:46:50 +01:00
|
|
|
if (device_enum_context.create("RPCS3", true))
|
2020-04-07 19:53:07 +02:00
|
|
|
{
|
2021-01-09 19:46:50 +01:00
|
|
|
device_enum_context.bind();
|
|
|
|
|
std::vector<vk::physical_device>& gpus = device_enum_context.enumerate_devices();
|
2020-04-07 19:53:07 +02:00
|
|
|
|
2021-03-18 10:09:42 +01:00
|
|
|
lock.lock();
|
2020-04-07 19:53:07 +02:00
|
|
|
|
2021-03-18 10:09:42 +01:00
|
|
|
if (!work_done) // The spawning thread gave up, do not attempt to modify vulkan_adapters
|
|
|
|
|
{
|
2023-04-28 16:09:08 +02:00
|
|
|
for (const auto& gpu : gpus)
|
2020-04-07 19:53:07 +02:00
|
|
|
{
|
2023-04-28 16:09:08 +02:00
|
|
|
adapters->append(QString::fromStdString(gpu.get_name()));
|
2020-04-07 19:53:07 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-18 10:09:42 +01:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lock.lock();
|
|
|
|
|
}
|
2020-04-07 19:53:07 +02:00
|
|
|
|
2021-03-18 10:09:42 +01:00
|
|
|
work_done = true;
|
|
|
|
|
lock.unlock();
|
2020-04-07 19:53:07 +02:00
|
|
|
cond.notify_all();
|
|
|
|
|
});
|
|
|
|
|
|
2021-03-09 13:50:58 +01:00
|
|
|
std::unique_ptr<std::remove_pointer_t<decltype(enum_thread_v)>> enum_thread(enum_thread_v);
|
2021-03-18 10:09:42 +01:00
|
|
|
|
|
|
|
|
if ([&]()
|
2020-04-07 19:53:07 +02:00
|
|
|
{
|
|
|
|
|
std::unique_lock lck(mtx);
|
2021-03-18 10:09:42 +01:00
|
|
|
cond.wait_for(lck, std::chrono::seconds(10), [&] { return work_done; });
|
|
|
|
|
return !std::exchange(work_done, true); // If thread hasn't done its job yet, it won't anymore
|
|
|
|
|
}())
|
2020-04-07 19:53:07 +02:00
|
|
|
{
|
2021-03-09 13:50:58 +01:00
|
|
|
enum_thread.release(); // Detach thread (destructor is not called)
|
|
|
|
|
|
2020-04-07 19:53:07 +02:00
|
|
|
cfg_log.error("Vulkan device enumeration timed out");
|
|
|
|
|
const auto button = QMessageBox::critical(nullptr, tr("Vulkan Check Timeout"),
|
|
|
|
|
tr("Querying for Vulkan-compatible devices is taking too long. This is usually caused by malfunctioning "
|
|
|
|
|
"graphics drivers, reinstalling them could fix the issue.\n\n"
|
|
|
|
|
"Selecting ignore starts the emulator without Vulkan support."),
|
|
|
|
|
QMessageBox::Ignore | QMessageBox::Abort, QMessageBox::Abort);
|
|
|
|
|
|
|
|
|
|
if (button != QMessageBox::Ignore)
|
2021-02-05 15:36:57 +01:00
|
|
|
{
|
|
|
|
|
abort_requested = true;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-04-07 19:53:07 +02:00
|
|
|
|
|
|
|
|
supports_vulkan = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-03-18 10:09:42 +01:00
|
|
|
supports_vulkan = !vulkan_adapters.isEmpty();
|
2021-03-09 13:50:58 +01:00
|
|
|
enum_thread.reset(); // Join thread
|
2020-04-07 19:53:07 +02:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Graphics Adapter
|
|
|
|
|
Vulkan = render_info(vulkan_adapters, supports_vulkan, emu_settings_type::VulkanAdapter, true);
|
|
|
|
|
OpenGL = render_info();
|
|
|
|
|
NullRender = render_info();
|
|
|
|
|
|
2022-01-10 14:37:26 +01:00
|
|
|
#ifdef __APPLE__
|
|
|
|
|
OpenGL.supported = false;
|
2022-01-10 14:37:43 +01:00
|
|
|
|
|
|
|
|
if (!Vulkan.supported)
|
|
|
|
|
{
|
|
|
|
|
QMessageBox::warning(nullptr,
|
|
|
|
|
tr("Warning"),
|
|
|
|
|
tr("Vulkan is not supported on this Mac.\n"
|
|
|
|
|
"No graphics will be rendered."));
|
|
|
|
|
}
|
2022-01-10 14:37:26 +01:00
|
|
|
#endif
|
|
|
|
|
|
2020-04-07 19:53:07 +02:00
|
|
|
renderers = { &Vulkan, &OpenGL, &NullRender };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void render_creator::update_names(const QStringList& names)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < names.size(); i++)
|
|
|
|
|
{
|
2020-12-18 08:39:54 +01:00
|
|
|
if (static_cast<usz>(i) >= renderers.size() || !renderers[i])
|
2020-04-07 19:53:07 +02:00
|
|
|
{
|
|
|
|
|
cfg_log.error("render_creator::update_names could not update renderer %d", i);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
renderers[i]->name = names[i];
|
|
|
|
|
}
|
|
|
|
|
}
|