GPUDevice: Use Error class for initialization errors

This commit is contained in:
Stenzek 2024-01-20 23:21:35 +10:00
parent 24cb489a32
commit f66866ed73
No known key found for this signature in database
32 changed files with 323 additions and 228 deletions

View file

@ -28,21 +28,26 @@ void Error::Clear()
} }
void Error::SetErrno(int err) void Error::SetErrno(int err)
{
SetErrno(std::string_view(), err);
}
void Error::SetErrno(std::string_view prefix, int err)
{ {
m_type = Type::Errno; m_type = Type::Errno;
#ifdef _MSC_VER #ifdef _MSC_VER
char buf[128]; char buf[128];
if (strerror_s(buf, sizeof(buf), err) == 0) if (strerror_s(buf, sizeof(buf), err) == 0)
m_description = fmt::format("errno {}: {}", err, buf); m_description = fmt::format("{}errno {}: {}", prefix, err, buf);
else else
m_description = fmt::format("errno {}: <Could not get error message>", err); m_description = fmt::format("{}errno {}: <Could not get error message>", prefix, err);
#else #else
const char* buf = std::strerror(err); const char* buf = std::strerror(err);
if (buf) if (buf)
m_description = fmt::format("errno {}: {}", err, buf); m_description = fmt::format("{}errno {}: {}", prefix, err, buf);
else else
m_description = fmt::format("errno {}: <Could not get error message>", err); m_description = fmt::format("{}errno {}: <Could not get error message>", prefix, err);
#endif #endif
} }
@ -52,20 +57,44 @@ void Error::SetErrno(Error* errptr, int err)
errptr->SetErrno(err); errptr->SetErrno(err);
} }
void Error::SetErrno(Error* errptr, std::string_view prefix, int err)
{
if (errptr)
errptr->SetErrno(prefix, err);
}
void Error::SetString(std::string description) void Error::SetString(std::string description)
{ {
m_type = Type::User; m_type = Type::User;
m_description = std::move(description); m_description = std::move(description);
} }
void Error::SetStringView(std::string_view description)
{
m_type = Type::User;
m_description = std::string(description);
}
void Error::SetString(Error* errptr, std::string description) void Error::SetString(Error* errptr, std::string description)
{ {
if (errptr) if (errptr)
errptr->SetString(std::move(description)); errptr->SetString(std::move(description));
} }
void Error::SetStringView(Error* errptr, std::string_view description)
{
if (errptr)
errptr->SetStringView(std::move(description));
}
#ifdef _WIN32 #ifdef _WIN32
void Error::SetWin32(unsigned long err) void Error::SetWin32(unsigned long err)
{
SetWin32(std::string_view(), err);
}
void Error::SetWin32(std::string_view prefix, unsigned long err)
{ {
m_type = Type::Win32; m_type = Type::Win32;
@ -75,11 +104,11 @@ void Error::SetWin32(unsigned long err)
if (r > 0) if (r > 0)
{ {
m_description = m_description =
fmt::format("Win32 Error {}: {}", err, StringUtil::WideStringToUTF8String(std::wstring_view(buf, r))); fmt::format("{}Win32 Error {}: {}", prefix, err, StringUtil::WideStringToUTF8String(std::wstring_view(buf, r)));
} }
else else
{ {
m_description = fmt::format("Win32 Error {}: <Could not resolve system error ID>", err); m_description = fmt::format("{}Win32 Error {}: <Could not resolve system error ID>", prefix, err);
} }
} }
@ -89,7 +118,18 @@ void Error::SetWin32(Error* errptr, unsigned long err)
errptr->SetWin32(err); errptr->SetWin32(err);
} }
void Error::SetWin32(Error* errptr, std::string_view prefix, unsigned long err)
{
if (errptr)
errptr->SetWin32(prefix, err);
}
void Error::SetHResult(long err) void Error::SetHResult(long err)
{
SetHResult(std::string_view(), err);
}
void Error::SetHResult(std::string_view prefix, long err)
{ {
m_type = Type::HResult; m_type = Type::HResult;
@ -99,11 +139,11 @@ void Error::SetHResult(long err)
if (r > 0) if (r > 0)
{ {
m_description = m_description =
fmt::format("HRESULT {:08X}: {}", err, StringUtil::WideStringToUTF8String(std::wstring_view(buf, r))); fmt::format("{}HRESULT {:08X}: {}", prefix, err, StringUtil::WideStringToUTF8String(std::wstring_view(buf, r)));
} }
else else
{ {
m_description = fmt::format("HRESULT {:08X}: <Could not resolve system error ID>", err); m_description = fmt::format("{}HRESULT {:08X}: <Could not resolve system error ID>", prefix, err);
} }
} }
@ -113,15 +153,26 @@ void Error::SetHResult(Error* errptr, long err)
errptr->SetHResult(err); errptr->SetHResult(err);
} }
void Error::SetHResult(Error* errptr, std::string_view prefix, long err)
{
if (errptr)
errptr->SetHResult(prefix, err);
}
#endif #endif
void Error::SetSocket(int err) void Error::SetSocket(int err)
{
SetSocket(std::string_view(), err);
}
void Error::SetSocket(std::string_view prefix, int err)
{ {
// Socket errors are win32 errors on windows // Socket errors are win32 errors on windows
#ifdef _WIN32 #ifdef _WIN32
SetWin32(err); SetWin32(prefix, err);
#else #else
SetErrno(err); SetErrno(prefix, err);
#endif #endif
m_type = Type::Socket; m_type = Type::Socket;
} }
@ -132,6 +183,12 @@ void Error::SetSocket(Error* errptr, int err)
errptr->SetSocket(err); errptr->SetSocket(err);
} }
void Error::SetSocket(Error* errptr, std::string_view prefix, int err)
{
if (errptr)
errptr->SetSocket(prefix, err);
}
Error Error::CreateNone() Error Error::CreateNone()
{ {
return Error(); return Error();

View file

@ -1,11 +1,14 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once #pragma once
#include "types.h" #include "types.h"
#include "fmt/core.h"
#include <string> #include <string>
#include <string_view>
class Error class Error
{ {
@ -26,26 +29,32 @@ public:
}; };
ALWAYS_INLINE Type GetType() const { return m_type; } ALWAYS_INLINE Type GetType() const { return m_type; }
ALWAYS_INLINE bool IsValid() const { return (m_type != Type::None); }
ALWAYS_INLINE const std::string& GetDescription() const { return m_description; } ALWAYS_INLINE const std::string& GetDescription() const { return m_description; }
void Clear(); void Clear();
/// Error that is set by system functions, such as open(). /// Error that is set by system functions, such as open().
void SetErrno(int err); void SetErrno(int err);
void SetErrno(std::string_view prefix, int err);
/// Error that is set by socket functions, such as socket(). On Unix this is the same as errno. /// Error that is set by socket functions, such as socket(). On Unix this is the same as errno.
void SetSocket(int err); void SetSocket(int err);
void SetSocket(std::string_view prefix, int err);
/// Set both description and message. /// Set both description and message.
void SetString(std::string description); void SetString(std::string description);
void SetStringView(std::string_view description);
#ifdef _WIN32 #ifdef _WIN32
/// Error that is returned by some Win32 functions, such as RegOpenKeyEx. Also used by other APIs through /// Error that is returned by some Win32 functions, such as RegOpenKeyEx. Also used by other APIs through
/// GetLastError(). /// GetLastError().
void SetWin32(unsigned long err); void SetWin32(unsigned long err);
void SetWin32(std::string_view prefix, unsigned long err);
/// Error that is returned by Win32 COM methods, e.g. S_OK. /// Error that is returned by Win32 COM methods, e.g. S_OK.
void SetHResult(long err); void SetHResult(long err);
void SetHResult(std::string_view prefix, long err);
#endif #endif
static Error CreateNone(); static Error CreateNone();
@ -59,10 +68,26 @@ public:
// helpers for setting // helpers for setting
static void SetErrno(Error* errptr, int err); static void SetErrno(Error* errptr, int err);
static void SetErrno(Error* errptr, std::string_view prefix, int err);
static void SetSocket(Error* errptr, int err); static void SetSocket(Error* errptr, int err);
static void SetSocket(Error* errptr, std::string_view prefix, int err);
static void SetString(Error* errptr, std::string description); static void SetString(Error* errptr, std::string description);
static void SetStringView(Error* errptr, std::string_view description);
#ifdef _WIN32
static void SetWin32(Error* errptr, unsigned long err); static void SetWin32(Error* errptr, unsigned long err);
static void SetWin32(Error* errptr, std::string_view prefix, unsigned long err);
static void SetHResult(Error* errptr, long err); static void SetHResult(Error* errptr, long err);
static void SetHResult(Error* errptr, std::string_view prefix, long err);
#endif
/// Sets a formatted message.
template<typename... T>
static void SetStringFmt(Error* errptr, fmt::format_string<T...> fmt, T&&... args)
{
if (errptr)
Error::SetString(errptr, fmt::vformat(fmt, fmt::make_format_args(args...)));
}
Error& operator=(const Error& e); Error& operator=(const Error& e);
Error& operator=(Error&& e); Error& operator=(Error&& e);

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "host.h" #include "host.h"
@ -14,6 +14,7 @@
#include "util/imgui_manager.h" #include "util/imgui_manager.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/error.h"
#include "common/layered_settings_interface.h" #include "common/layered_settings_interface.h"
#include "common/log.h" #include "common/log.h"
#include "common/string_util.h" #include "common/string_util.h"
@ -259,29 +260,30 @@ bool Host::CreateGPUDevice(RenderAPI api)
disabled_features |= GPUDevice::FEATURE_MASK_TEXTURE_COPY_TO_SELF; disabled_features |= GPUDevice::FEATURE_MASK_TEXTURE_COPY_TO_SELF;
// TODO: FSUI should always use vsync.. // TODO: FSUI should always use vsync..
Error error;
const bool vsync = System::IsValid() ? System::ShouldUseVSync() : g_settings.video_sync_enabled; const bool vsync = System::IsValid() ? System::ShouldUseVSync() : g_settings.video_sync_enabled;
if (!g_gpu_device || !g_gpu_device->Create(g_settings.gpu_adapter, if (!g_gpu_device || !g_gpu_device->Create(g_settings.gpu_adapter,
g_settings.gpu_disable_shader_cache ? std::string_view() : g_settings.gpu_disable_shader_cache ? std::string_view() :
std::string_view(EmuFolders::Cache), std::string_view(EmuFolders::Cache),
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, vsync, SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, vsync,
g_settings.gpu_threaded_presentation, exclusive_fullscreen_control, g_settings.gpu_threaded_presentation, exclusive_fullscreen_control,
static_cast<GPUDevice::FeatureMask>(disabled_features))) static_cast<GPUDevice::FeatureMask>(disabled_features), &error))
{ {
Log_ErrorPrintf("Failed to create GPU device."); Log_ErrorPrintf("Failed to create GPU device.");
if (g_gpu_device) if (g_gpu_device)
g_gpu_device->Destroy(); g_gpu_device->Destroy();
g_gpu_device.reset(); g_gpu_device.reset();
Host::ReportErrorAsync("Error", Host::ReportErrorAsync(
fmt::format("Failed to create render device. This may be due to your GPU not supporting the " "Error", fmt::format("Failed to create render device:\n\n{}\n\nThis may be due to your GPU not supporting the "
"chosen renderer ({}), or because your graphics drivers need to be updated.", "chosen renderer ({}), or because your graphics drivers need to be updated.",
GPUDevice::RenderAPIToString(api))); error.GetDescription(), GPUDevice::RenderAPIToString(api)));
return false; return false;
} }
if (!ImGuiManager::Initialize(g_settings.display_osd_scale / 100.0f, g_settings.display_show_osd_messages)) if (!ImGuiManager::Initialize(g_settings.display_osd_scale / 100.0f, g_settings.display_show_osd_messages, &error))
{ {
Log_ErrorPrintf("Failed to initialize ImGuiManager."); Host::ReportErrorAsync("Error", fmt::format("Failed to initialize ImGuiManager: {}", error.GetDescription()));
g_gpu_device->Destroy(); g_gpu_device->Destroy();
g_gpu_device.reset(); g_gpu_device.reset();
return false; return false;

View file

@ -10,6 +10,7 @@
#include "common/align.h" #include "common/align.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/bitutils.h" #include "common/bitutils.h"
#include "common/error.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
#include "common/path.h" #include "common/path.h"
@ -64,7 +65,8 @@ bool D3D11Device::HasSurface() const
} }
bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation, bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
Error* error)
{ {
std::unique_lock lock(s_instance_mutex); std::unique_lock lock(s_instance_mutex);
@ -72,7 +74,7 @@ bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_pr
if (m_debug_device) if (m_debug_device)
create_flags |= D3D11_CREATE_DEVICE_DEBUG; create_flags |= D3D11_CREATE_DEVICE_DEBUG;
m_dxgi_factory = D3DCommon::CreateFactory(m_debug_device); m_dxgi_factory = D3DCommon::CreateFactory(m_debug_device, error);
if (!m_dxgi_factory) if (!m_dxgi_factory)
return false; return false;
@ -90,12 +92,12 @@ bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_pr
if (FAILED(hr)) if (FAILED(hr))
{ {
Log_ErrorPrintf("Failed to create D3D device: 0x%08X", hr); Error::SetHResult(error, "Failed to create D3D device: ", hr);
return false; return false;
} }
else if (FAILED(hr = temp_device.As(&m_device)) || FAILED(hr = temp_context.As(&m_context))) else if (FAILED(hr = temp_device.As(&m_device)) || FAILED(hr = temp_context.As(&m_context)))
{ {
Log_ErrorPrintf("Failed to get D3D11.1 device: 0x%08X", hr); Error::SetHResult(error, "Failed to get D3D11.1 device: ", hr);
return false; return false;
} }
@ -135,10 +137,16 @@ bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_pr
SetFeatures(disabled_features); SetFeatures(disabled_features);
if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateSwapChain()) if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateSwapChain())
{
Error::SetStringView(error, "Failed to create swap chain");
return false; return false;
}
if (!CreateBuffers()) if (!CreateBuffers())
{
Error::SetStringView(error, "Failed to create buffers");
return false; return false;
}
return true; return true;
} }
@ -663,7 +671,7 @@ GPUDevice::AdapterAndModeList D3D11Device::StaticGetAdapterAndModeList()
} }
else else
{ {
ComPtr<IDXGIFactory5> factory = D3DCommon::CreateFactory(false); ComPtr<IDXGIFactory5> factory = D3DCommon::CreateFactory(false, nullptr);
if (factory) if (factory)
GetAdapterAndModeList(&ret, factory.Get()); GetAdapterAndModeList(&ret, factory.Get());
} }

View file

@ -107,7 +107,8 @@ public:
protected: protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) override; std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
Error* error) override;
void DestroyDevice() override; void DestroyDevice() override;
private: private:

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "d3d12_device.h" #include "d3d12_device.h"
@ -13,6 +13,7 @@
#include "common/align.h" #include "common/align.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/bitutils.h" #include "common/bitutils.h"
#include "common/error.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
#include "common/path.h" #include "common/path.h"
@ -117,11 +118,11 @@ D3D12Device::ComPtr<ID3D12RootSignature> D3D12Device::CreateRootSignature(const
} }
bool D3D12Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation, bool D3D12Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features, Error* error)
{ {
std::unique_lock lock(s_instance_mutex); std::unique_lock lock(s_instance_mutex);
m_dxgi_factory = D3DCommon::CreateFactory(m_debug_device); m_dxgi_factory = D3DCommon::CreateFactory(m_debug_device, error);
if (!m_dxgi_factory) if (!m_dxgi_factory)
return false; return false;
@ -150,7 +151,7 @@ bool D3D12Device::CreateDevice(const std::string_view& adapter, bool threaded_pr
hr = D3D12CreateDevice(m_adapter.Get(), m_feature_level, IID_PPV_ARGS(&m_device)); hr = D3D12CreateDevice(m_adapter.Get(), m_feature_level, IID_PPV_ARGS(&m_device));
if (FAILED(hr)) if (FAILED(hr))
{ {
Log_ErrorPrintf("Failed to create D3D12 device: %08X", hr); Error::SetHResult(error, "Failed to create D3D12 device: ", hr);
return false; return false;
} }
@ -192,7 +193,7 @@ bool D3D12Device::CreateDevice(const std::string_view& adapter, bool threaded_pr
hr = m_device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&m_command_queue)); hr = m_device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&m_command_queue));
if (FAILED(hr)) if (FAILED(hr))
{ {
Log_ErrorPrintf("Failed to create command queue: %08X", hr); Error::SetHResult(error, "Failed to create command queue: ", hr);
return false; return false;
} }
@ -206,34 +207,43 @@ bool D3D12Device::CreateDevice(const std::string_view& adapter, bool threaded_pr
hr = D3D12MA::CreateAllocator(&allocatorDesc, m_allocator.GetAddressOf()); hr = D3D12MA::CreateAllocator(&allocatorDesc, m_allocator.GetAddressOf());
if (FAILED(hr)) if (FAILED(hr))
{ {
Log_ErrorPrintf("D3D12MA::CreateAllocator() failed with HRESULT %08X", hr); Error::SetHResult(error, "D3D12MA::CreateAllocator() failed: ", hr);
return false; return false;
} }
hr = m_device->CreateFence(m_completed_fence_value, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)); hr = m_device->CreateFence(m_completed_fence_value, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence));
if (FAILED(hr)) if (FAILED(hr))
{ {
Log_ErrorPrintf("Failed to create fence: %08X", hr); Error::SetHResult(error, "Failed to create fence: ", hr);
return false; return false;
} }
m_fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr); m_fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (m_fence_event == NULL) if (m_fence_event == NULL)
{ {
Log_ErrorPrintf("Failed to create fence event: %08X", GetLastError()); Error::SetWin32(error, "Failed to create fence event: ", GetLastError());
return false; return false;
} }
SetFeatures(disabled_features); SetFeatures(disabled_features);
if (!CreateCommandLists() || !CreateDescriptorHeaps()) if (!CreateCommandLists() || !CreateDescriptorHeaps())
{
Error::SetStringView(error, "Failed to create command lists/descriptor heaps.");
return false; return false;
}
if (!m_window_info.IsSurfaceless() && !CreateSwapChain()) if (!m_window_info.IsSurfaceless() && !CreateSwapChain())
{
Error::SetStringView(error, "Failed to create swap chain.");
return false; return false;
}
if (!CreateRootSignatures() || !CreateBuffers()) if (!CreateRootSignatures() || !CreateBuffers())
{
Error::SetStringView(error, "Failed to create root signature/buffers.");
return false; return false;
}
CreateTimestampQuery(); CreateTimestampQuery();
return true; return true;
@ -741,7 +751,7 @@ GPUDevice::AdapterAndModeList D3D12Device::StaticGetAdapterAndModeList()
} }
else else
{ {
ComPtr<IDXGIFactory5> factory = D3DCommon::CreateFactory(false); ComPtr<IDXGIFactory5> factory = D3DCommon::CreateFactory(false, nullptr);
if (factory) if (factory)
GetAdapterAndModeList(&ret, factory.Get()); GetAdapterAndModeList(&ret, factory.Get());
} }

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once #pragma once
@ -175,7 +175,8 @@ public:
protected: protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) override; std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
Error* error) override;
void DestroyDevice() override; void DestroyDevice() override;
bool ReadPipelineCache(const std::string& filename) override; bool ReadPipelineCache(const std::string& filename) override;

View file

@ -1,9 +1,10 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "d3d_common.h" #include "d3d_common.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/error.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
#include "common/rectangle.h" #include "common/rectangle.h"
@ -54,7 +55,7 @@ const char* D3DCommon::GetFeatureLevelShaderModelString(D3D_FEATURE_LEVEL featur
return "unk"; return "unk";
} }
Microsoft::WRL::ComPtr<IDXGIFactory5> D3DCommon::CreateFactory(bool debug) Microsoft::WRL::ComPtr<IDXGIFactory5> D3DCommon::CreateFactory(bool debug, Error* error)
{ {
UINT flags = 0; UINT flags = 0;
if (debug) if (debug)
@ -63,7 +64,7 @@ Microsoft::WRL::ComPtr<IDXGIFactory5> D3DCommon::CreateFactory(bool debug)
Microsoft::WRL::ComPtr<IDXGIFactory5> factory; Microsoft::WRL::ComPtr<IDXGIFactory5> factory;
const HRESULT hr = CreateDXGIFactory2(flags, IID_PPV_ARGS(factory.GetAddressOf())); const HRESULT hr = CreateDXGIFactory2(flags, IID_PPV_ARGS(factory.GetAddressOf()));
if (FAILED(hr)) if (FAILED(hr))
Log_ErrorPrintf("Failed to create DXGI factory: %08X", hr); Error::SetHResult(error, "Failed to create DXGI factory: ", hr);
return factory; return factory;
} }

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once #pragma once
@ -16,6 +16,8 @@
#include <vector> #include <vector>
#include <wrl/client.h> #include <wrl/client.h>
class Error;
struct IDXGIFactory5; struct IDXGIFactory5;
struct IDXGIAdapter1; struct IDXGIAdapter1;
struct IDXGIOutput; struct IDXGIOutput;
@ -27,7 +29,7 @@ const char* GetFeatureLevelString(D3D_FEATURE_LEVEL feature_level);
const char* GetFeatureLevelShaderModelString(D3D_FEATURE_LEVEL feature_level); const char* GetFeatureLevelShaderModelString(D3D_FEATURE_LEVEL feature_level);
// create a dxgi factory // create a dxgi factory
Microsoft::WRL::ComPtr<IDXGIFactory5> CreateFactory(bool debug); Microsoft::WRL::ComPtr<IDXGIFactory5> CreateFactory(bool debug, Error* error);
// returns a list of all adapter names // returns a list of all adapter names
std::vector<std::string> GetAdapterNames(IDXGIFactory5* factory); std::vector<std::string> GetAdapterNames(IDXGIFactory5* factory);

View file

@ -1,9 +1,10 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "context.h" #include "context.h"
#include "../opengl_loader.h" #include "../opengl_loader.h"
#include "common/error.h"
#include "common/log.h" #include "common/log.h"
#include <cstdio> #include <cstdio>
@ -65,7 +66,7 @@ static void DisableBrokenExtensions(const char* gl_vendor, const char* gl_render
gl_major_version >= 3 && gl_minor_version >= 2 && major_version > 0)) gl_major_version >= 3 && gl_minor_version >= 2 && major_version > 0))
{ {
// r32p0 and beyond seem okay. // r32p0 and beyond seem okay.
//Log_VerbosePrintf("Keeping copy_image for driver version '%s'", gl_version); // Log_VerbosePrintf("Keeping copy_image for driver version '%s'", gl_version);
// Framebuffer blits still end up faster. // Framebuffer blits still end up faster.
Log_VerbosePrintf("Newer Mali driver detected, disabling GL_{EXT,OES}_copy_image."); Log_VerbosePrintf("Newer Mali driver detected, disabling GL_{EXT,OES}_copy_image.");
@ -117,45 +118,60 @@ std::vector<Context::FullscreenModeInfo> Context::EnumerateFullscreenModes()
return {}; return {};
} }
std::unique_ptr<GL::Context> Context::Create(const WindowInfo& wi, const Version* versions_to_try, std::unique_ptr<GL::Context> Context::Create(const WindowInfo& wi, Error* error)
size_t num_versions_to_try)
{ {
static constexpr std::array<Version, 14> vlist = {{{Profile::Core, 4, 6},
{Profile::Core, 4, 5},
{Profile::Core, 4, 4},
{Profile::Core, 4, 3},
{Profile::Core, 4, 2},
{Profile::Core, 4, 1},
{Profile::Core, 4, 0},
{Profile::Core, 3, 3},
{Profile::Core, 3, 2},
{Profile::Core, 3, 1},
{Profile::Core, 3, 0},
{Profile::ES, 3, 2},
{Profile::ES, 3, 1},
{Profile::ES, 3, 0}}};
std::span<const Version> versions_to_try = vlist;
if (ShouldPreferESContext()) if (ShouldPreferESContext())
{ {
// move ES versions to the front // move ES versions to the front
Version* new_versions_to_try = static_cast<Version*>(alloca(sizeof(Version) * num_versions_to_try)); Version* new_versions_to_try = static_cast<Version*>(alloca(sizeof(Version) * versions_to_try.size()));
size_t count = 0; size_t count = 0;
for (size_t i = 0; i < num_versions_to_try; i++) for (const Version& cv : versions_to_try)
{ {
if (versions_to_try[i].profile == Profile::ES) if (cv.profile == Profile::ES)
new_versions_to_try[count++] = versions_to_try[i]; new_versions_to_try[count++] = cv;
} }
for (size_t i = 0; i < num_versions_to_try; i++) for (const Version& cv : versions_to_try)
{ {
if (versions_to_try[i].profile != Profile::ES) if (cv.profile != Profile::ES)
new_versions_to_try[count++] = versions_to_try[i]; new_versions_to_try[count++] = cv;
} }
versions_to_try = new_versions_to_try; versions_to_try = std::span<const Version>(new_versions_to_try, versions_to_try.size());
} }
std::unique_ptr<Context> context; std::unique_ptr<Context> context;
#if defined(_WIN32) && !defined(_M_ARM64) #if defined(_WIN32) && !defined(_M_ARM64)
context = ContextWGL::Create(wi, versions_to_try, num_versions_to_try); context = ContextWGL::Create(wi, versions_to_try, error);
#elif defined(__APPLE__) #elif defined(__APPLE__)
context = ContextAGL::Create(wi, versions_to_try, num_versions_to_try); context = ContextAGL::Create(wi, versions_to_try);
#elif defined(__ANDROID__) #elif defined(__ANDROID__)
context = ContextEGLAndroid::Create(wi, versions_to_try, num_versions_to_try); context = ContextEGLAndroid::Create(wi, versions_to_try, error);
#else #else
#if defined(ENABLE_X11) #if defined(ENABLE_X11)
if (wi.type == WindowInfo::Type::X11) if (wi.type == WindowInfo::Type::X11)
context = ContextEGLX11::Create(wi, versions_to_try, num_versions_to_try); context = ContextEGLX11::Create(wi, versions_to_try, error);
#endif #endif
#if defined(ENABLE_WAYLAND) #if defined(ENABLE_WAYLAND)
if (wi.type == WindowInfo::Type::Wayland) if (wi.type == WindowInfo::Type::Wayland)
context = ContextEGLWayland::Create(wi, versions_to_try, num_versions_to_try); context = ContextEGLWayland::Create(wi, versions_to_try, error);
#endif #endif
if (wi.type == WindowInfo::Type::Surfaceless) if (wi.type == WindowInfo::Type::Surfaceless)
context = ContextEGL::Create(wi, versions_to_try, num_versions_to_try); context = ContextEGL::Create(wi, versions_to_try, error);
#endif #endif
if (!context) if (!context)
@ -172,7 +188,7 @@ std::unique_ptr<GL::Context> Context::Create(const WindowInfo& wi, const Version
{ {
if (!gladLoadGLLoader([](const char* name) { return context_being_created->GetProcAddress(name); })) if (!gladLoadGLLoader([](const char* name) { return context_being_created->GetProcAddress(name); }))
{ {
Log_ErrorPrintf("Failed to load GL functions for GLAD"); Error::SetStringView(error, "Failed to load GL functions for GLAD");
return nullptr; return nullptr;
} }
} }
@ -180,7 +196,7 @@ std::unique_ptr<GL::Context> Context::Create(const WindowInfo& wi, const Version
{ {
if (!gladLoadGLES2Loader([](const char* name) { return context_being_created->GetProcAddress(name); })) if (!gladLoadGLES2Loader([](const char* name) { return context_being_created->GetProcAddress(name); }))
{ {
Log_ErrorPrintf("Failed to load GLES functions for GLAD"); Error::SetStringView(error, "Failed to load GLES functions for GLAD");
return nullptr; return nullptr;
} }
} }
@ -199,65 +215,4 @@ std::unique_ptr<GL::Context> Context::Create(const WindowInfo& wi, const Version
return context; return context;
} }
const std::array<Context::Version, 11>& Context::GetAllDesktopVersionsList()
{
static constexpr std::array<Version, 11> vlist = {{{Profile::Core, 4, 6},
{Profile::Core, 4, 5},
{Profile::Core, 4, 4},
{Profile::Core, 4, 3},
{Profile::Core, 4, 2},
{Profile::Core, 4, 1},
{Profile::Core, 4, 0},
{Profile::Core, 3, 3},
{Profile::Core, 3, 2},
{Profile::Core, 3, 1},
{Profile::Core, 3, 0}}};
return vlist;
}
const std::array<Context::Version, 12>& Context::GetAllDesktopVersionsListWithFallback()
{
static constexpr std::array<Version, 12> vlist = {{{Profile::Core, 4, 6},
{Profile::Core, 4, 5},
{Profile::Core, 4, 4},
{Profile::Core, 4, 3},
{Profile::Core, 4, 2},
{Profile::Core, 4, 1},
{Profile::Core, 4, 0},
{Profile::Core, 3, 3},
{Profile::Core, 3, 2},
{Profile::Core, 3, 1},
{Profile::Core, 3, 0},
{Profile::NoProfile, 0, 0}}};
return vlist;
}
const std::array<Context::Version, 4>& Context::GetAllESVersionsList()
{
static constexpr std::array<Version, 4> vlist = {
{{Profile::ES, 3, 2}, {Profile::ES, 3, 1}, {Profile::ES, 3, 0}, {Profile::ES, 2, 0}}};
return vlist;
}
const std::array<Context::Version, 16>& Context::GetAllVersionsList()
{
static constexpr std::array<Version, 16> vlist = {{{Profile::Core, 4, 6},
{Profile::Core, 4, 5},
{Profile::Core, 4, 4},
{Profile::Core, 4, 3},
{Profile::Core, 4, 2},
{Profile::Core, 4, 1},
{Profile::Core, 4, 0},
{Profile::Core, 3, 3},
{Profile::Core, 3, 2},
{Profile::Core, 3, 1},
{Profile::Core, 3, 0},
{Profile::ES, 3, 2},
{Profile::ES, 3, 1},
{Profile::ES, 3, 0},
{Profile::ES, 2, 0},
{Profile::NoProfile, 0, 0}}};
return vlist;
}
} // namespace GL } // namespace GL

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once #pragma once
@ -7,10 +7,12 @@
#include "common/types.h" #include "common/types.h"
#include <array>
#include <memory> #include <memory>
#include <span>
#include <vector> #include <vector>
class Error;
namespace GL { namespace GL {
class Context class Context
{ {
@ -57,26 +59,9 @@ public:
virtual std::vector<FullscreenModeInfo> EnumerateFullscreenModes(); virtual std::vector<FullscreenModeInfo> EnumerateFullscreenModes();
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, static std::unique_ptr<Context> Create(const WindowInfo& wi, Error* error);
size_t num_versions_to_try);
template<size_t N>
static std::unique_ptr<Context> Create(const WindowInfo& wi, const std::array<Version, N>& versions_to_try)
{
return Create(wi, versions_to_try.data(), versions_to_try.size());
}
static std::unique_ptr<Context> Create(const WindowInfo& wi) { return Create(wi, GetAllVersionsList()); }
static const std::array<Version, 11>& GetAllDesktopVersionsList();
static const std::array<Version, 12>& GetAllDesktopVersionsListWithFallback();
static const std::array<Version, 4>& GetAllESVersionsList();
static const std::array<Version, 16>& GetAllVersionsList();
protected: protected:
#ifdef _WIN32
#endif
WindowInfo m_wi; WindowInfo m_wi;
Version m_version = {}; Version m_version = {};
}; };

View file

@ -22,8 +22,7 @@ public:
ContextAGL(const WindowInfo& wi); ContextAGL(const WindowInfo& wi);
~ContextAGL() override; ~ContextAGL() override;
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, static std::unique_ptr<Context> Create(const WindowInfo& wi, std::span<const Version> versions_to_try);
size_t num_versions_to_try);
void* GetProcAddress(const char* name) override; void* GetProcAddress(const char* name) override;
bool ChangeSurface(const WindowInfo& new_wi) override; bool ChangeSurface(const WindowInfo& new_wi) override;
@ -38,7 +37,7 @@ public:
private: private:
ALWAYS_INLINE NSView* GetView() const { return static_cast<NSView*>((__bridge NSView*)m_wi.window_handle); } ALWAYS_INLINE NSView* GetView() const { return static_cast<NSView*>((__bridge NSView*)m_wi.window_handle); }
bool Initialize(const Version* versions_to_try, size_t num_versions_to_try); bool Initialize(std::span<const Version> versions_to_try);
bool CreateContext(NSOpenGLContext* share_context, int profile, bool make_current); bool CreateContext(NSOpenGLContext* share_context, int profile, bool make_current);
void BindContextToView(); void BindContextToView();

View file

@ -30,21 +30,19 @@ ContextAGL::~ContextAGL()
dlclose(m_opengl_module_handle); dlclose(m_opengl_module_handle);
} }
std::unique_ptr<Context> ContextAGL::Create(const WindowInfo& wi, const Version* versions_to_try, std::unique_ptr<Context> ContextAGL::Create(const WindowInfo& wi, std::span<const Version> versions_to_try)
size_t num_versions_to_try)
{ {
std::unique_ptr<ContextAGL> context = std::make_unique<ContextAGL>(wi); std::unique_ptr<ContextAGL> context = std::make_unique<ContextAGL>(wi);
if (!context->Initialize(versions_to_try, num_versions_to_try)) if (!context->Initialize(versions_to_try))
return nullptr; return nullptr;
return context; return context;
} }
bool ContextAGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try) bool ContextAGL::Initialize(const std::span<const Version> versions_to_try)
{ {
for (size_t i = 0; i < num_versions_to_try; i++) for (const Version& cv : versions_to_try)
{ {
const Version& cv = versions_to_try[i];
if (cv.profile == Profile::NoProfile && CreateContext(nullptr, NSOpenGLProfileVersionLegacy, true)) if (cv.profile == Profile::NoProfile && CreateContext(nullptr, NSOpenGLProfileVersionLegacy, true))
{ {
// we already have the dummy context, so just use that // we already have the dummy context, so just use that

View file

@ -1,10 +1,11 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "context_egl.h" #include "context_egl.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/log.h" #include "common/log.h"
#include "common/error.h"
#include <optional> #include <optional>
#include <vector> #include <vector>
@ -22,21 +23,21 @@ ContextEGL::~ContextEGL()
DestroyContext(); DestroyContext();
} }
std::unique_ptr<Context> ContextEGL::Create(const WindowInfo& wi, const Version* versions_to_try, std::unique_ptr<Context> ContextEGL::Create(const WindowInfo& wi, std::span<const Version> versions_to_try, Error* error)
size_t num_versions_to_try)
{ {
std::unique_ptr<ContextEGL> context = std::make_unique<ContextEGL>(wi); std::unique_ptr<ContextEGL> context = std::make_unique<ContextEGL>(wi);
if (!context->Initialize(versions_to_try, num_versions_to_try)) if (!context->Initialize(versions_to_try, error))
return nullptr; return nullptr;
return context; return context;
} }
bool ContextEGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try) bool ContextEGL::Initialize(std::span<const Version> versions_to_try, Error* error)
{ {
if (!gladLoadEGL()) if (!gladLoadEGL())
{ {
Log_ErrorPrintf("Loading GLAD EGL functions failed"); Log_ErrorPrint("Loading GLAD EGL functions failed");
Error::SetStringView(error, "Loading GLAD EGL functions failed");
return false; return false;
} }
@ -46,7 +47,9 @@ bool ContextEGL::Initialize(const Version* versions_to_try, size_t num_versions_
int egl_major, egl_minor; int egl_major, egl_minor;
if (!eglInitialize(m_display, &egl_major, &egl_minor)) if (!eglInitialize(m_display, &egl_major, &egl_minor))
{ {
Log_ErrorPrintf("eglInitialize() failed: %d", eglGetError()); const int gerror = static_cast<int>(eglGetError());
Log_ErrorFmt("eglInitialize() failed: {} (0x{:X})", gerror, gerror);
Error::SetStringFmt(error, "eglInitialize() failed: {} (0x{:X})", gerror, gerror);
return false; return false;
} }
Log_InfoPrintf("EGL Version: %d.%d", egl_major, egl_minor); Log_InfoPrintf("EGL Version: %d.%d", egl_major, egl_minor);
@ -60,12 +63,13 @@ bool ContextEGL::Initialize(const Version* versions_to_try, size_t num_versions_
if (!m_supports_surfaceless) if (!m_supports_surfaceless)
Log_WarningPrint("EGL implementation does not support surfaceless contexts, emulating with pbuffers"); Log_WarningPrint("EGL implementation does not support surfaceless contexts, emulating with pbuffers");
for (size_t i = 0; i < num_versions_to_try; i++) for (const Version& cv : versions_to_try)
{ {
if (CreateContextAndSurface(versions_to_try[i], nullptr, true)) if (CreateContextAndSurface(cv, nullptr, true))
return true; return true;
} }
Error::SetStringView(error, "Failed to create any context versions");
return false; return false;
} }

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once #pragma once
@ -15,8 +15,7 @@ public:
ContextEGL(const WindowInfo& wi); ContextEGL(const WindowInfo& wi);
~ContextEGL() override; ~ContextEGL() override;
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, static std::unique_ptr<Context> Create(const WindowInfo& wi, std::span<const Version> versions_to_try, Error* error);
size_t num_versions_to_try);
void* GetProcAddress(const char* name) override; void* GetProcAddress(const char* name) override;
virtual bool ChangeSurface(const WindowInfo& new_wi) override; virtual bool ChangeSurface(const WindowInfo& new_wi) override;
@ -32,7 +31,7 @@ protected:
virtual bool SetDisplay(); virtual bool SetDisplay();
virtual EGLNativeWindowType GetNativeWindow(EGLConfig config); virtual EGLNativeWindowType GetNativeWindow(EGLConfig config);
bool Initialize(const Version* versions_to_try, size_t num_versions_to_try); bool Initialize(std::span<const Version> versions_to_try, Error* error);
bool CreateDisplay(); bool CreateDisplay();
bool CreateContext(const Version& version, EGLContext share_context); bool CreateContext(const Version& version, EGLContext share_context);
bool CreateContextAndSurface(const Version& version, EGLContext share_context, bool make_current); bool CreateContextAndSurface(const Version& version, EGLContext share_context, bool make_current);

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "context_egl_wayland.h" #include "context_egl_wayland.h"
@ -12,7 +12,9 @@ Log_SetChannel(ContextEGL);
namespace GL { namespace GL {
static const char* WAYLAND_EGL_MODNAME = "libwayland-egl.so.1"; static const char* WAYLAND_EGL_MODNAME = "libwayland-egl.so.1";
ContextEGLWayland::ContextEGLWayland(const WindowInfo& wi) : ContextEGL(wi) {} ContextEGLWayland::ContextEGLWayland(const WindowInfo& wi) : ContextEGL(wi)
{
}
ContextEGLWayland::~ContextEGLWayland() ContextEGLWayland::~ContextEGLWayland()
{ {
if (m_wl_window) if (m_wl_window)
@ -21,11 +23,11 @@ ContextEGLWayland::~ContextEGLWayland()
dlclose(m_wl_module); dlclose(m_wl_module);
} }
std::unique_ptr<Context> ContextEGLWayland::Create(const WindowInfo& wi, const Version* versions_to_try, std::unique_ptr<Context> ContextEGLWayland::Create(const WindowInfo& wi, std::span<const Version> versions_to_try,
size_t num_versions_to_try) Error* error)
{ {
std::unique_ptr<ContextEGLWayland> context = std::make_unique<ContextEGLWayland>(wi); std::unique_ptr<ContextEGLWayland> context = std::make_unique<ContextEGLWayland>(wi);
if (!context->LoadModule() || !context->Initialize(versions_to_try, num_versions_to_try)) if (!context->LoadModule() || !context->Initialize(versions_to_try, error))
return nullptr; return nullptr;
return context; return context;

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once #pragma once
@ -13,8 +13,7 @@ public:
ContextEGLWayland(const WindowInfo& wi); ContextEGLWayland(const WindowInfo& wi);
~ContextEGLWayland() override; ~ContextEGLWayland() override;
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, static std::unique_ptr<Context> Create(const WindowInfo& wi, std::span<const Version> versions_to_try, Error* error);
size_t num_versions_to_try);
std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override; std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override;
void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override;

View file

@ -1,17 +1,19 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "context_egl_x11.h" #include "context_egl_x11.h"
namespace GL { namespace GL {
ContextEGLX11::ContextEGLX11(const WindowInfo& wi) : ContextEGL(wi) {} ContextEGLX11::ContextEGLX11(const WindowInfo& wi) : ContextEGL(wi)
{
}
ContextEGLX11::~ContextEGLX11() = default; ContextEGLX11::~ContextEGLX11() = default;
std::unique_ptr<Context> ContextEGLX11::Create(const WindowInfo& wi, const Version* versions_to_try, std::unique_ptr<Context> ContextEGLX11::Create(const WindowInfo& wi, std::span<const Version> versions_to_try,
size_t num_versions_to_try) Error* error)
{ {
std::unique_ptr<ContextEGLX11> context = std::make_unique<ContextEGLX11>(wi); std::unique_ptr<ContextEGLX11> context = std::make_unique<ContextEGLX11>(wi);
if (!context->Initialize(versions_to_try, num_versions_to_try)) if (!context->Initialize(versions_to_try, error))
return nullptr; return nullptr;
return context; return context;

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once #pragma once
@ -12,8 +12,7 @@ public:
ContextEGLX11(const WindowInfo& wi); ContextEGLX11(const WindowInfo& wi);
~ContextEGLX11() override; ~ContextEGLX11() override;
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, static std::unique_ptr<Context> Create(const WindowInfo& wi, std::span<const Version> versions_to_try, Error* error);
size_t num_versions_to_try);
std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override; std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override;
void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override;

View file

@ -1,10 +1,11 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "context_wgl.h" #include "context_wgl.h"
#include "../opengl_loader.h" #include "../opengl_loader.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/error.h"
#include "common/log.h" #include "common/log.h"
#include "common/scoped_guard.h" #include "common/scoped_guard.h"
@ -51,36 +52,44 @@ ContextWGL::~ContextWGL()
ReleaseDC(); ReleaseDC();
} }
std::unique_ptr<Context> ContextWGL::Create(const WindowInfo& wi, const Version* versions_to_try, std::unique_ptr<Context> ContextWGL::Create(const WindowInfo& wi, std::span<const Version> versions_to_try,
size_t num_versions_to_try) Error* error)
{ {
std::unique_ptr<ContextWGL> context = std::make_unique<ContextWGL>(wi); std::unique_ptr<ContextWGL> context = std::make_unique<ContextWGL>(wi);
if (!context->Initialize(versions_to_try, num_versions_to_try)) if (!context->Initialize(versions_to_try, error))
return nullptr; return nullptr;
return context; return context;
} }
bool ContextWGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try) bool ContextWGL::Initialize(std::span<const Version> versions_to_try, Error* error)
{ {
if (m_wi.type == WindowInfo::Type::Win32) if (m_wi.type == WindowInfo::Type::Win32)
{ {
if (!InitializeDC()) if (!InitializeDC())
{
Error::SetStringView(error, "Failed to create DC.");
return false; return false;
}
} }
else else
{ {
if (!CreatePBuffer()) if (!CreatePBuffer())
{
Error::SetStringView(error, "Failed to create PBuffer");
return false; return false;
}
} }
// Everything including core/ES requires a dummy profile to load the WGL extensions. // Everything including core/ES requires a dummy profile to load the WGL extensions.
if (!CreateAnyContext(nullptr, true)) if (!CreateAnyContext(nullptr, true))
return false;
for (size_t i = 0; i < num_versions_to_try; i++)
{ {
const Version& cv = versions_to_try[i]; Error::SetStringView(error, "Failed to create dummy context.");
return false;
}
for (const Version& cv : versions_to_try)
{
if (cv.profile == Profile::NoProfile) if (cv.profile == Profile::NoProfile)
{ {
// we already have the dummy context, so just use that // we already have the dummy context, so just use that
@ -94,6 +103,7 @@ bool ContextWGL::Initialize(const Version* versions_to_try, size_t num_versions_
} }
} }
Error::SetStringView(error, "Failed to create any contexts.");
return false; return false;
} }

View file

@ -20,8 +20,7 @@ public:
ContextWGL(const WindowInfo& wi); ContextWGL(const WindowInfo& wi);
~ContextWGL() override; ~ContextWGL() override;
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try, static std::unique_ptr<Context> Create(const WindowInfo& wi, std::span<const Version> versions_to_try, Error* error);
size_t num_versions_to_try);
void* GetProcAddress(const char* name) override; void* GetProcAddress(const char* name) override;
bool ChangeSurface(const WindowInfo& new_wi) override; bool ChangeSurface(const WindowInfo& new_wi) override;
@ -38,7 +37,7 @@ private:
HDC GetDCAndSetPixelFormat(HWND hwnd); HDC GetDCAndSetPixelFormat(HWND hwnd);
bool Initialize(const Version* versions_to_try, size_t num_versions_to_try); bool Initialize(std::span<const Version> versions_to_try, Error* error);
bool InitializeDC(); bool InitializeDC();
void ReleaseDC(); void ReleaseDC();
bool CreatePBuffer(); bool CreatePBuffer();

View file

@ -8,6 +8,7 @@
#include "shadergen.h" #include "shadergen.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/error.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
#include "common/path.h" #include "common/path.h"
@ -258,20 +259,21 @@ bool GPUDevice::IsSameRenderAPI(RenderAPI lhs, RenderAPI rhs)
bool GPUDevice::Create(const std::string_view& adapter, const std::string_view& shader_cache_path, bool GPUDevice::Create(const std::string_view& adapter, const std::string_view& shader_cache_path,
u32 shader_cache_version, bool debug_device, bool vsync, bool threaded_presentation, u32 shader_cache_version, bool debug_device, bool vsync, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features, Error* error)
{ {
m_vsync_enabled = vsync; m_vsync_enabled = vsync;
m_debug_device = debug_device; m_debug_device = debug_device;
if (!AcquireWindow(true)) if (!AcquireWindow(true))
{ {
Log_ErrorPrintf("Failed to acquire window from host."); Error::SetStringView(error, "Failed to acquire window from host.");
return false; return false;
} }
if (!CreateDevice(adapter, threaded_presentation, exclusive_fullscreen_control, disabled_features)) if (!CreateDevice(adapter, threaded_presentation, exclusive_fullscreen_control, disabled_features, error))
{ {
Log_ErrorPrintf("Failed to create device."); if (error && !error->IsValid())
error->SetStringView("Failed to create device.");
return false; return false;
} }
@ -281,7 +283,7 @@ bool GPUDevice::Create(const std::string_view& adapter, const std::string_view&
if (!CreateResources()) if (!CreateResources())
{ {
Log_ErrorPrintf("Failed to create base resources."); Error::SetStringView(error, "Failed to create base resources.");
return false; return false;
} }

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once #pragma once
@ -23,6 +23,8 @@
#include <tuple> #include <tuple>
#include <vector> #include <vector>
class Error;
enum class RenderAPI : u32 enum class RenderAPI : u32
{ {
None, None,
@ -537,7 +539,7 @@ public:
bool Create(const std::string_view& adapter, const std::string_view& shader_cache_path, u32 shader_cache_version, bool Create(const std::string_view& adapter, const std::string_view& shader_cache_path, u32 shader_cache_version,
bool debug_device, bool vsync, bool threaded_presentation, bool debug_device, bool vsync, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features); std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features, Error* error);
void Destroy(); void Destroy();
virtual bool HasSurface() const = 0; virtual bool HasSurface() const = 0;
@ -652,7 +654,8 @@ public:
protected: protected:
virtual bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, virtual bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) = 0; std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
Error* error) = 0;
virtual void DestroyDevice() = 0; virtual void DestroyDevice() = 0;
std::string GetShaderCacheBaseName(const std::string_view& type) const; std::string GetShaderCacheBaseName(const std::string_view& type) const;

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "imgui_manager.h" #include "imgui_manager.h"
@ -9,6 +9,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/easing.h" #include "common/easing.h"
#include "common/error.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/image.h" #include "common/image.h"
#include "common/log.h" #include "common/log.h"
@ -154,11 +155,11 @@ void ImGuiManager::SetShowOSDMessages(bool enable)
Host::ClearOSDMessages(); Host::ClearOSDMessages();
} }
bool ImGuiManager::Initialize(float global_scale, bool show_osd_messages) bool ImGuiManager::Initialize(float global_scale, bool show_osd_messages, Error* error)
{ {
if (!LoadFontData()) if (!LoadFontData())
{ {
Panic("Failed to load font data"); Error::SetString(error, "Failed to load font data");
return false; return false;
} }
@ -191,7 +192,7 @@ bool ImGuiManager::Initialize(float global_scale, bool show_osd_messages)
if (!AddImGuiFonts(false) || !g_gpu_device->UpdateImGuiFontTexture()) if (!AddImGuiFonts(false) || !g_gpu_device->UpdateImGuiFontTexture())
{ {
Panic("Failed to create ImGui font text"); Error::SetString(error, "Failed to create ImGui font text");
ImGui::DestroyContext(); ImGui::DestroyContext();
return false; return false;
} }
@ -554,8 +555,25 @@ ImFont* ImGuiManager::AddFixedFont(float size)
bool ImGuiManager::AddIconFonts(float size) bool ImGuiManager::AddIconFonts(float size)
{ {
static constexpr ImWchar range_fa[] = { 0xf002,0xf002,0xf005,0xf005,0xf007,0xf007,0xf00c,0xf00e,0xf011,0xf011,0xf013,0xf013,0xf017,0xf017,0xf019,0xf019,0xf01c,0xf01c,0xf021,0xf021,0xf023,0xf023,0xf025,0xf025,0xf027,0xf028,0xf02e,0xf02e,0xf030,0xf030,0xf03a,0xf03a,0xf03d,0xf03d,0xf049,0xf04c,0xf050,0xf050,0xf059,0xf059,0xf05e,0xf05e,0xf062,0xf063,0xf065,0xf065,0xf067,0xf067,0xf071,0xf071,0xf075,0xf075,0xf077,0xf078,0xf07b,0xf07c,0xf084,0xf085,0xf091,0xf091,0xf0a0,0xf0a0,0xf0ac,0xf0ad,0xf0c5,0xf0c5,0xf0c7,0xf0c8,0xf0cb,0xf0cb,0xf0d0,0xf0d0,0xf0dc,0xf0dc,0xf0e2,0xf0e2,0xf0eb,0xf0eb,0xf0f1,0xf0f1,0xf0f3,0xf0f3,0xf0fe,0xf0fe,0xf110,0xf110,0xf119,0xf119,0xf11b,0xf11c,0xf140,0xf140,0xf144,0xf144,0xf14a,0xf14a,0xf15b,0xf15b,0xf15d,0xf15d,0xf188,0xf188,0xf191,0xf192,0xf1ab,0xf1ab,0xf1dd,0xf1de,0xf1e6,0xf1e6,0xf1eb,0xf1eb,0xf1f8,0xf1f8,0xf1fc,0xf1fc,0xf242,0xf242,0xf245,0xf245,0xf26c,0xf26c,0xf279,0xf279,0xf2d0,0xf2d0,0xf2db,0xf2db,0xf2f2,0xf2f2,0xf2f5,0xf2f5,0xf3c1,0xf3c1,0xf410,0xf410,0xf466,0xf466,0xf500,0xf500,0xf51f,0xf51f,0xf545,0xf545,0xf547,0xf548,0xf552,0xf552,0xf57a,0xf57a,0xf5a2,0xf5a2,0xf5aa,0xf5aa,0xf5e7,0xf5e7,0xf65d,0xf65e,0xf6a9,0xf6a9,0xf7c2,0xf7c2,0xf807,0xf807,0xf815,0xf815,0xf818,0xf818,0xf84c,0xf84c,0xf8cc,0xf8cc,0x0,0x0 }; static constexpr ImWchar range_fa[] = {
static constexpr ImWchar range_pf[] = { 0x2196,0x2199,0x219e,0x21a1,0x21b0,0x21b3,0x21ba,0x21c3,0x21c7,0x21ca,0x21d0,0x21d4,0x21dc,0x21dd,0x21e0,0x21e3,0x21ed,0x21ee,0x21f7,0x21f8,0x21fa,0x21fb,0x227a,0x227d,0x23b2,0x23b4,0x23f4,0x23f7,0x2427,0x243a,0x243c,0x243c,0x243e,0x243e,0x2460,0x246b,0x24f5,0x24fd,0x24ff,0x24ff,0x278a,0x278e,0x27fc,0x27fc,0xe001,0xe001,0xff21,0xff3a,0x0,0x0 }; 0xf002, 0xf002, 0xf005, 0xf005, 0xf007, 0xf007, 0xf00c, 0xf00e, 0xf011, 0xf011, 0xf013, 0xf013, 0xf017, 0xf017,
0xf019, 0xf019, 0xf01c, 0xf01c, 0xf021, 0xf021, 0xf023, 0xf023, 0xf025, 0xf025, 0xf027, 0xf028, 0xf02e, 0xf02e,
0xf030, 0xf030, 0xf03a, 0xf03a, 0xf03d, 0xf03d, 0xf049, 0xf04c, 0xf050, 0xf050, 0xf059, 0xf059, 0xf05e, 0xf05e,
0xf062, 0xf063, 0xf065, 0xf065, 0xf067, 0xf067, 0xf071, 0xf071, 0xf075, 0xf075, 0xf077, 0xf078, 0xf07b, 0xf07c,
0xf084, 0xf085, 0xf091, 0xf091, 0xf0a0, 0xf0a0, 0xf0ac, 0xf0ad, 0xf0c5, 0xf0c5, 0xf0c7, 0xf0c8, 0xf0cb, 0xf0cb,
0xf0d0, 0xf0d0, 0xf0dc, 0xf0dc, 0xf0e2, 0xf0e2, 0xf0eb, 0xf0eb, 0xf0f1, 0xf0f1, 0xf0f3, 0xf0f3, 0xf0fe, 0xf0fe,
0xf110, 0xf110, 0xf119, 0xf119, 0xf11b, 0xf11c, 0xf140, 0xf140, 0xf144, 0xf144, 0xf14a, 0xf14a, 0xf15b, 0xf15b,
0xf15d, 0xf15d, 0xf188, 0xf188, 0xf191, 0xf192, 0xf1ab, 0xf1ab, 0xf1dd, 0xf1de, 0xf1e6, 0xf1e6, 0xf1eb, 0xf1eb,
0xf1f8, 0xf1f8, 0xf1fc, 0xf1fc, 0xf242, 0xf242, 0xf245, 0xf245, 0xf26c, 0xf26c, 0xf279, 0xf279, 0xf2d0, 0xf2d0,
0xf2db, 0xf2db, 0xf2f2, 0xf2f2, 0xf2f5, 0xf2f5, 0xf3c1, 0xf3c1, 0xf410, 0xf410, 0xf466, 0xf466, 0xf500, 0xf500,
0xf51f, 0xf51f, 0xf545, 0xf545, 0xf547, 0xf548, 0xf552, 0xf552, 0xf57a, 0xf57a, 0xf5a2, 0xf5a2, 0xf5aa, 0xf5aa,
0xf5e7, 0xf5e7, 0xf65d, 0xf65e, 0xf6a9, 0xf6a9, 0xf7c2, 0xf7c2, 0xf807, 0xf807, 0xf815, 0xf815, 0xf818, 0xf818,
0xf84c, 0xf84c, 0xf8cc, 0xf8cc, 0x0, 0x0};
static constexpr ImWchar range_pf[] = {0x2196, 0x2199, 0x219e, 0x21a1, 0x21b0, 0x21b3, 0x21ba, 0x21c3, 0x21c7, 0x21ca,
0x21d0, 0x21d4, 0x21dc, 0x21dd, 0x21e0, 0x21e3, 0x21ed, 0x21ee, 0x21f7, 0x21f8,
0x21fa, 0x21fb, 0x227a, 0x227d, 0x23b2, 0x23b4, 0x23f4, 0x23f7, 0x2427, 0x243a,
0x243c, 0x243c, 0x243e, 0x243e, 0x2460, 0x246b, 0x24f5, 0x24fd, 0x24ff, 0x24ff,
0x278a, 0x278e, 0x27fc, 0x27fc, 0xe001, 0xe001, 0xff21, 0xff3a, 0x0, 0x0};
{ {
ImFontConfig cfg; ImFontConfig cfg;

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once #pragma once
@ -6,6 +6,8 @@
#include "common/types.h" #include "common/types.h"
#include <string> #include <string>
class Error;
struct ImFont; struct ImFont;
union InputBindingKey; union InputBindingKey;
@ -22,7 +24,7 @@ void SetGlobalScale(float global_scale);
void SetShowOSDMessages(bool enable); void SetShowOSDMessages(bool enable);
/// Initializes ImGui, creates fonts, etc. /// Initializes ImGui, creates fonts, etc.
bool Initialize(float global_scale, bool show_osd_messages); bool Initialize(float global_scale, bool show_osd_messages, Error* error);
/// Frees all ImGui resources. /// Frees all ImGui resources.
void Shutdown(); void Shutdown();

View file

@ -257,7 +257,8 @@ public:
protected: protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) override; std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
Error* error) override;
void DestroyDevice() override; void DestroyDevice() override;
private: private:

View file

@ -6,6 +6,7 @@
#include "common/align.h" #include "common/align.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/error.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
#include "common/path.h" #include "common/path.h"
@ -122,7 +123,7 @@ void MetalDevice::SetVSync(bool enabled)
bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation, bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control, std::optional<bool> exclusive_fullscreen_control,
FeatureMask disabled_features) FeatureMask disabled_features, Error* error)
{ {
@autoreleasepool @autoreleasepool
{ {
@ -149,7 +150,7 @@ bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_pr
device = [MTLCreateSystemDefaultDevice() autorelease]; device = [MTLCreateSystemDefaultDevice() autorelease];
if (device == nil) if (device == nil)
{ {
Log_ErrorPrint("Failed to create default Metal device."); Error::SetStringView(error, "Failed to create default Metal device.");
return false; return false;
} }
} }
@ -157,7 +158,7 @@ bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_pr
id<MTLCommandQueue> queue = [[device newCommandQueue] autorelease]; id<MTLCommandQueue> queue = [[device newCommandQueue] autorelease];
if (queue == nil) if (queue == nil)
{ {
Log_ErrorPrint("Failed to create command queue."); Error::SetStringView(error, "Failed to create command queue.");
return false; return false;
} }
@ -168,20 +169,23 @@ bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_pr
SetFeatures(disabled_features); SetFeatures(disabled_features);
if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateLayer()) if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateLayer())
{
Error::SetStringView(error, "Failed to create layer.");
return false; return false;
}
CreateCommandBuffer(); CreateCommandBuffer();
RenderBlankFrame(); RenderBlankFrame();
if (!LoadShaders()) if (!LoadShaders())
{ {
Log_ErrorPrint("Failed to load shaders."); Error::SetStringView(error, "Failed to load shaders.");
return false; return false;
} }
if (!CreateBuffers()) if (!CreateBuffers())
{ {
Log_ErrorPrintf("Failed to create buffers."); Error::SetStringView(error, "Failed to create buffers.");
return false; return false;
} }

View file

@ -307,9 +307,9 @@ bool OpenGLDevice::HasSurface() const
} }
bool OpenGLDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation, bool OpenGLDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features, Error* error)
{ {
m_gl_context = GL::Context::Create(m_window_info); m_gl_context = GL::Context::Create(m_window_info, error);
if (!m_gl_context) if (!m_gl_context)
{ {
Log_ErrorPrintf("Failed to create any GL context"); Log_ErrorPrintf("Failed to create any GL context");

View file

@ -120,7 +120,8 @@ public:
protected: protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) override; std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
Error* error) override;
void DestroyDevice() override; void DestroyDevice() override;
bool ReadPipelineCache(const std::string& filename) override; bool ReadPipelineCache(const std::string& filename) override;

View file

@ -544,7 +544,7 @@ void OpenGLDevice::UnrefVAO(const OpenGLPipeline::VertexArrayCacheKey& key)
OpenGLPipeline::OpenGLPipeline(const ProgramCacheKey& key, GLuint program, VertexArrayCache::const_iterator vao, OpenGLPipeline::OpenGLPipeline(const ProgramCacheKey& key, GLuint program, VertexArrayCache::const_iterator vao,
const RasterizationState& rs, const DepthState& ds, const BlendState& bs, const RasterizationState& rs, const DepthState& ds, const BlendState& bs,
GLenum topology) GLenum topology)
: m_key(key), m_program(program), m_vao(vao), m_blend_state(bs), m_rasterization_state(rs), m_depth_state(ds), : m_key(key), m_vao(vao), m_program(program), m_blend_state(bs), m_rasterization_state(rs), m_depth_state(ds),
m_topology(topology) m_topology(topology)
{ {
} }

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "vulkan_device.h" #include "vulkan_device.h"
@ -13,6 +13,7 @@
#include "common/align.h" #include "common/align.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/bitutils.h" #include "common/bitutils.h"
#include "common/error.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
#include "common/path.h" #include "common/path.h"
@ -1859,7 +1860,8 @@ bool VulkanDevice::HasSurface() const
} }
bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation, bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
Error* error)
{ {
std::unique_lock lock(s_instance_mutex); std::unique_lock lock(s_instance_mutex);
bool enable_debug_utils = m_debug_device; bool enable_debug_utils = m_debug_device;
@ -1867,7 +1869,7 @@ bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_p
if (!Vulkan::LoadVulkanLibrary()) if (!Vulkan::LoadVulkanLibrary())
{ {
Host::ReportErrorAsync("Error", "Failed to load Vulkan library. Does your GPU and/or driver support Vulkan?"); Error::SetStringView(error, "Failed to load Vulkan library. Does your GPU and/or driver support Vulkan?");
return false; return false;
} }
@ -1883,8 +1885,7 @@ bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_p
CreateVulkanInstance(m_window_info, &m_optional_extensions, enable_debug_utils, enable_validation_layer); CreateVulkanInstance(m_window_info, &m_optional_extensions, enable_debug_utils, enable_validation_layer);
if (m_instance == VK_NULL_HANDLE) if (m_instance == VK_NULL_HANDLE)
{ {
Host::ReportErrorAsync("Error", Error::SetStringView(error, "Failed to create Vulkan instance. Does your GPU and/or driver support Vulkan?");
"Failed to create Vulkan instance. Does your GPU and/or driver support Vulkan?");
return false; return false;
} }
@ -1895,13 +1896,14 @@ bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_p
if (!Vulkan::LoadVulkanInstanceFunctions(m_instance)) if (!Vulkan::LoadVulkanInstanceFunctions(m_instance))
{ {
Log_ErrorPrintf("Failed to load Vulkan instance functions"); Log_ErrorPrintf("Failed to load Vulkan instance functions");
Error::SetStringView(error, "Failed to load Vulkan instance functions");
return false; return false;
} }
GPUList gpus = EnumerateGPUs(m_instance); GPUList gpus = EnumerateGPUs(m_instance);
if (gpus.empty()) if (gpus.empty())
{ {
Host::ReportErrorAsync("Error", "No physical devices found. Does your GPU and/or driver support Vulkan?"); Error::SetStringView(error, "No physical devices found. Does your GPU and/or driver support Vulkan?");
return false; return false;
} }
@ -1964,7 +1966,7 @@ bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_p
if (!CheckFeatures(disabled_features)) if (!CheckFeatures(disabled_features))
{ {
Host::ReportErrorAsync("Error", "Your GPU does not support the required Vulkan features."); Error::SetStringView(error, "Your GPU does not support the required Vulkan features.");
return false; return false;
} }
@ -1982,7 +1984,7 @@ bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_p
m_swap_chain = VulkanSwapChain::Create(m_window_info, surface, m_vsync_enabled, m_exclusive_fullscreen_control); m_swap_chain = VulkanSwapChain::Create(m_window_info, surface, m_vsync_enabled, m_exclusive_fullscreen_control);
if (!m_swap_chain) if (!m_swap_chain)
{ {
Log_ErrorPrintf("Failed to create swap chain"); Error::SetStringView(error, "Failed to create swap chain");
return false; return false;
} }
@ -1998,12 +2000,15 @@ bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_p
if (!CreateNullTexture()) if (!CreateNullTexture())
{ {
Log_ErrorPrint("Failed to create dummy texture"); Error::SetStringView(error, "Failed to create dummy texture");
return false; return false;
} }
if (!CreateBuffers() || !CreatePersistentDescriptorSets()) if (!CreateBuffers() || !CreatePersistentDescriptorSets())
{
Error::SetStringView(error, "Failed to create buffers/descriptor sets");
return false; return false;
}
return true; return true;
} }

View file

@ -218,7 +218,8 @@ public:
protected: protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) override; std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
Error* error) override;
void DestroyDevice() override; void DestroyDevice() override;
bool ReadPipelineCache(const std::string& filename) override; bool ReadPipelineCache(const std::string& filename) override;