From f66866ed73b56e89a59eb776b334d295163bb2d2 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 20 Jan 2024 23:21:35 +1000 Subject: [PATCH] GPUDevice: Use Error class for initialization errors --- src/common/error.cpp | 77 +++++++++++++++--- src/common/error.h | 27 ++++++- src/core/host.cpp | 18 +++-- src/util/d3d11_device.cpp | 18 +++-- src/util/d3d11_device.h | 3 +- src/util/d3d12_device.cpp | 28 ++++--- src/util/d3d12_device.h | 5 +- src/util/d3d_common.cpp | 7 +- src/util/d3d_common.h | 6 +- src/util/gl/context.cpp | 117 +++++++++------------------- src/util/gl/context.h | 25 ++---- src/util/gl/context_agl.h | 5 +- src/util/gl/context_agl.mm | 10 +-- src/util/gl/context_egl.cpp | 22 +++--- src/util/gl/context_egl.h | 7 +- src/util/gl/context_egl_wayland.cpp | 12 +-- src/util/gl/context_egl_wayland.h | 5 +- src/util/gl/context_egl_x11.cpp | 12 +-- src/util/gl/context_egl_x11.h | 5 +- src/util/gl/context_wgl.cpp | 28 ++++--- src/util/gl/context_wgl.h | 5 +- src/util/gpu_device.cpp | 12 +-- src/util/gpu_device.h | 9 ++- src/util/imgui_manager.cpp | 30 +++++-- src/util/imgui_manager.h | 6 +- src/util/metal_device.h | 3 +- src/util/metal_device.mm | 14 ++-- src/util/opengl_device.cpp | 4 +- src/util/opengl_device.h | 3 +- src/util/opengl_pipeline.cpp | 2 +- src/util/vulkan_device.cpp | 23 +++--- src/util/vulkan_device.h | 3 +- 32 files changed, 323 insertions(+), 228 deletions(-) diff --git a/src/common/error.cpp b/src/common/error.cpp index 32661b9ad..4f48548ca 100644 --- a/src/common/error.cpp +++ b/src/common/error.cpp @@ -28,21 +28,26 @@ void Error::Clear() } void Error::SetErrno(int err) +{ + SetErrno(std::string_view(), err); +} + +void Error::SetErrno(std::string_view prefix, int err) { m_type = Type::Errno; #ifdef _MSC_VER char buf[128]; if (strerror_s(buf, sizeof(buf), err) == 0) - m_description = fmt::format("errno {}: {}", err, buf); + m_description = fmt::format("{}errno {}: {}", prefix, err, buf); else - m_description = fmt::format("errno {}: ", err); + m_description = fmt::format("{}errno {}: ", prefix, err); #else const char* buf = std::strerror(err); if (buf) - m_description = fmt::format("errno {}: {}", err, buf); + m_description = fmt::format("{}errno {}: {}", prefix, err, buf); else - m_description = fmt::format("errno {}: ", err); + m_description = fmt::format("{}errno {}: ", prefix, err); #endif } @@ -52,20 +57,44 @@ void Error::SetErrno(Error* errptr, int 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) { m_type = Type::User; 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) { if (errptr) errptr->SetString(std::move(description)); } +void Error::SetStringView(Error* errptr, std::string_view description) +{ + if (errptr) + errptr->SetStringView(std::move(description)); +} + #ifdef _WIN32 + 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; @@ -75,11 +104,11 @@ void Error::SetWin32(unsigned long err) if (r > 0) { 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 { - m_description = fmt::format("Win32 Error {}: ", err); + m_description = fmt::format("{}Win32 Error {}: ", prefix, err); } } @@ -89,7 +118,18 @@ void Error::SetWin32(Error* errptr, unsigned long 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) +{ + SetHResult(std::string_view(), err); +} + +void Error::SetHResult(std::string_view prefix, long err) { m_type = Type::HResult; @@ -99,11 +139,11 @@ void Error::SetHResult(long err) if (r > 0) { 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 { - m_description = fmt::format("HRESULT {:08X}: ", err); + m_description = fmt::format("{}HRESULT {:08X}: ", prefix, err); } } @@ -113,15 +153,26 @@ void Error::SetHResult(Error* errptr, long err) errptr->SetHResult(err); } +void Error::SetHResult(Error* errptr, std::string_view prefix, long err) +{ + if (errptr) + errptr->SetHResult(prefix, err); +} + #endif 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 #ifdef _WIN32 - SetWin32(err); + SetWin32(prefix, err); #else - SetErrno(err); + SetErrno(prefix, err); #endif m_type = Type::Socket; } @@ -132,6 +183,12 @@ void Error::SetSocket(Error* errptr, int err) errptr->SetSocket(err); } +void Error::SetSocket(Error* errptr, std::string_view prefix, int err) +{ + if (errptr) + errptr->SetSocket(prefix, err); +} + Error Error::CreateNone() { return Error(); diff --git a/src/common/error.h b/src/common/error.h index 754cc65a9..2d9190451 100644 --- a/src/common/error.h +++ b/src/common/error.h @@ -1,11 +1,14 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once #include "types.h" +#include "fmt/core.h" + #include +#include class Error { @@ -26,26 +29,32 @@ public: }; 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; } void Clear(); /// Error that is set by system functions, such as open(). 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. void SetSocket(int err); + void SetSocket(std::string_view prefix, int err); /// Set both description and message. void SetString(std::string description); + void SetStringView(std::string_view description); #ifdef _WIN32 /// Error that is returned by some Win32 functions, such as RegOpenKeyEx. Also used by other APIs through /// GetLastError(). 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. void SetHResult(long err); + void SetHResult(std::string_view prefix, long err); #endif static Error CreateNone(); @@ -59,10 +68,26 @@ public: // helpers for setting 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, std::string_view prefix, int err); 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, std::string_view prefix, unsigned 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 + static void SetStringFmt(Error* errptr, fmt::format_string fmt, T&&... args) + { + if (errptr) + Error::SetString(errptr, fmt::vformat(fmt, fmt::make_format_args(args...))); + } Error& operator=(const Error& e); Error& operator=(Error&& e); diff --git a/src/core/host.cpp b/src/core/host.cpp index b8801abe6..0c4d685fa 100644 --- a/src/core/host.cpp +++ b/src/core/host.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "host.h" @@ -14,6 +14,7 @@ #include "util/imgui_manager.h" #include "common/assert.h" +#include "common/error.h" #include "common/layered_settings_interface.h" #include "common/log.h" #include "common/string_util.h" @@ -259,29 +260,30 @@ bool Host::CreateGPUDevice(RenderAPI api) disabled_features |= GPUDevice::FEATURE_MASK_TEXTURE_COPY_TO_SELF; // TODO: FSUI should always use vsync.. + Error error; const bool vsync = System::IsValid() ? System::ShouldUseVSync() : g_settings.video_sync_enabled; if (!g_gpu_device || !g_gpu_device->Create(g_settings.gpu_adapter, g_settings.gpu_disable_shader_cache ? std::string_view() : std::string_view(EmuFolders::Cache), SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, vsync, g_settings.gpu_threaded_presentation, exclusive_fullscreen_control, - static_cast(disabled_features))) + static_cast(disabled_features), &error)) { Log_ErrorPrintf("Failed to create GPU device."); if (g_gpu_device) g_gpu_device->Destroy(); g_gpu_device.reset(); - Host::ReportErrorAsync("Error", - fmt::format("Failed to create render device. This may be due to your GPU not supporting the " - "chosen renderer ({}), or because your graphics drivers need to be updated.", - GPUDevice::RenderAPIToString(api))); + Host::ReportErrorAsync( + "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.", + error.GetDescription(), GPUDevice::RenderAPIToString(api))); 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.reset(); return false; diff --git a/src/util/d3d11_device.cpp b/src/util/d3d11_device.cpp index 6502a6a4b..a460ddfff 100644 --- a/src/util/d3d11_device.cpp +++ b/src/util/d3d11_device.cpp @@ -10,6 +10,7 @@ #include "common/align.h" #include "common/assert.h" #include "common/bitutils.h" +#include "common/error.h" #include "common/file_system.h" #include "common/log.h" #include "common/path.h" @@ -64,7 +65,8 @@ bool D3D11Device::HasSurface() const } bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation, - std::optional exclusive_fullscreen_control, FeatureMask disabled_features) + std::optional exclusive_fullscreen_control, FeatureMask disabled_features, + Error* error) { 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) 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) return false; @@ -90,12 +92,12 @@ bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_pr if (FAILED(hr)) { - Log_ErrorPrintf("Failed to create D3D device: 0x%08X", hr); + Error::SetHResult(error, "Failed to create D3D device: ", hr); return false; } 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; } @@ -135,10 +137,16 @@ bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_pr SetFeatures(disabled_features); if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateSwapChain()) + { + Error::SetStringView(error, "Failed to create swap chain"); return false; + } if (!CreateBuffers()) + { + Error::SetStringView(error, "Failed to create buffers"); return false; + } return true; } @@ -663,7 +671,7 @@ GPUDevice::AdapterAndModeList D3D11Device::StaticGetAdapterAndModeList() } else { - ComPtr factory = D3DCommon::CreateFactory(false); + ComPtr factory = D3DCommon::CreateFactory(false, nullptr); if (factory) GetAdapterAndModeList(&ret, factory.Get()); } diff --git a/src/util/d3d11_device.h b/src/util/d3d11_device.h index d0f55b953..e2bd15dad 100644 --- a/src/util/d3d11_device.h +++ b/src/util/d3d11_device.h @@ -107,7 +107,8 @@ public: protected: bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, - std::optional exclusive_fullscreen_control, FeatureMask disabled_features) override; + std::optional exclusive_fullscreen_control, FeatureMask disabled_features, + Error* error) override; void DestroyDevice() override; private: diff --git a/src/util/d3d12_device.cpp b/src/util/d3d12_device.cpp index 202488dc3..0b99ac017 100644 --- a/src/util/d3d12_device.cpp +++ b/src/util/d3d12_device.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "d3d12_device.h" @@ -13,6 +13,7 @@ #include "common/align.h" #include "common/assert.h" #include "common/bitutils.h" +#include "common/error.h" #include "common/file_system.h" #include "common/log.h" #include "common/path.h" @@ -117,11 +118,11 @@ D3D12Device::ComPtr D3D12Device::CreateRootSignature(const } bool D3D12Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation, - std::optional exclusive_fullscreen_control, FeatureMask disabled_features) + std::optional exclusive_fullscreen_control, FeatureMask disabled_features, Error* error) { 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) 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)); if (FAILED(hr)) { - Log_ErrorPrintf("Failed to create D3D12 device: %08X", hr); + Error::SetHResult(error, "Failed to create D3D12 device: ", hr); 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)); if (FAILED(hr)) { - Log_ErrorPrintf("Failed to create command queue: %08X", hr); + Error::SetHResult(error, "Failed to create command queue: ", hr); return false; } @@ -206,34 +207,43 @@ bool D3D12Device::CreateDevice(const std::string_view& adapter, bool threaded_pr hr = D3D12MA::CreateAllocator(&allocatorDesc, m_allocator.GetAddressOf()); if (FAILED(hr)) { - Log_ErrorPrintf("D3D12MA::CreateAllocator() failed with HRESULT %08X", hr); + Error::SetHResult(error, "D3D12MA::CreateAllocator() failed: ", hr); return false; } hr = m_device->CreateFence(m_completed_fence_value, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)); if (FAILED(hr)) { - Log_ErrorPrintf("Failed to create fence: %08X", hr); + Error::SetHResult(error, "Failed to create fence: ", hr); return false; } m_fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr); 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; } SetFeatures(disabled_features); if (!CreateCommandLists() || !CreateDescriptorHeaps()) + { + Error::SetStringView(error, "Failed to create command lists/descriptor heaps."); return false; + } if (!m_window_info.IsSurfaceless() && !CreateSwapChain()) + { + Error::SetStringView(error, "Failed to create swap chain."); return false; + } if (!CreateRootSignatures() || !CreateBuffers()) + { + Error::SetStringView(error, "Failed to create root signature/buffers."); return false; + } CreateTimestampQuery(); return true; @@ -741,7 +751,7 @@ GPUDevice::AdapterAndModeList D3D12Device::StaticGetAdapterAndModeList() } else { - ComPtr factory = D3DCommon::CreateFactory(false); + ComPtr factory = D3DCommon::CreateFactory(false, nullptr); if (factory) GetAdapterAndModeList(&ret, factory.Get()); } diff --git a/src/util/d3d12_device.h b/src/util/d3d12_device.h index 6eb6ed815..c338b13bb 100644 --- a/src/util/d3d12_device.h +++ b/src/util/d3d12_device.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once @@ -175,7 +175,8 @@ public: protected: bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, - std::optional exclusive_fullscreen_control, FeatureMask disabled_features) override; + std::optional exclusive_fullscreen_control, FeatureMask disabled_features, + Error* error) override; void DestroyDevice() override; bool ReadPipelineCache(const std::string& filename) override; diff --git a/src/util/d3d_common.cpp b/src/util/d3d_common.cpp index 7031a144b..e66f3a5d4 100644 --- a/src/util/d3d_common.cpp +++ b/src/util/d3d_common.cpp @@ -1,9 +1,10 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "d3d_common.h" #include "common/assert.h" +#include "common/error.h" #include "common/file_system.h" #include "common/log.h" #include "common/rectangle.h" @@ -54,7 +55,7 @@ const char* D3DCommon::GetFeatureLevelShaderModelString(D3D_FEATURE_LEVEL featur return "unk"; } -Microsoft::WRL::ComPtr D3DCommon::CreateFactory(bool debug) +Microsoft::WRL::ComPtr D3DCommon::CreateFactory(bool debug, Error* error) { UINT flags = 0; if (debug) @@ -63,7 +64,7 @@ Microsoft::WRL::ComPtr D3DCommon::CreateFactory(bool debug) Microsoft::WRL::ComPtr factory; const HRESULT hr = CreateDXGIFactory2(flags, IID_PPV_ARGS(factory.GetAddressOf())); if (FAILED(hr)) - Log_ErrorPrintf("Failed to create DXGI factory: %08X", hr); + Error::SetHResult(error, "Failed to create DXGI factory: ", hr); return factory; } diff --git a/src/util/d3d_common.h b/src/util/d3d_common.h index 1390a7d76..a4666139e 100644 --- a/src/util/d3d_common.h +++ b/src/util/d3d_common.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once @@ -16,6 +16,8 @@ #include #include +class Error; + struct IDXGIFactory5; struct IDXGIAdapter1; struct IDXGIOutput; @@ -27,7 +29,7 @@ const char* GetFeatureLevelString(D3D_FEATURE_LEVEL feature_level); const char* GetFeatureLevelShaderModelString(D3D_FEATURE_LEVEL feature_level); // create a dxgi factory -Microsoft::WRL::ComPtr CreateFactory(bool debug); +Microsoft::WRL::ComPtr CreateFactory(bool debug, Error* error); // returns a list of all adapter names std::vector GetAdapterNames(IDXGIFactory5* factory); diff --git a/src/util/gl/context.cpp b/src/util/gl/context.cpp index 33406d86f..3272e050d 100644 --- a/src/util/gl/context.cpp +++ b/src/util/gl/context.cpp @@ -1,9 +1,10 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "context.h" #include "../opengl_loader.h" +#include "common/error.h" #include "common/log.h" #include @@ -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)) { // 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. Log_VerbosePrintf("Newer Mali driver detected, disabling GL_{EXT,OES}_copy_image."); @@ -117,45 +118,60 @@ std::vector Context::EnumerateFullscreenModes() return {}; } -std::unique_ptr Context::Create(const WindowInfo& wi, const Version* versions_to_try, - size_t num_versions_to_try) +std::unique_ptr Context::Create(const WindowInfo& wi, Error* error) { + static constexpr std::array 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 versions_to_try = vlist; if (ShouldPreferESContext()) { // move ES versions to the front - Version* new_versions_to_try = static_cast(alloca(sizeof(Version) * num_versions_to_try)); + Version* new_versions_to_try = static_cast(alloca(sizeof(Version) * versions_to_try.size())); 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) - new_versions_to_try[count++] = versions_to_try[i]; + if (cv.profile == Profile::ES) + 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) - new_versions_to_try[count++] = versions_to_try[i]; + if (cv.profile != Profile::ES) + new_versions_to_try[count++] = cv; } - versions_to_try = new_versions_to_try; + versions_to_try = std::span(new_versions_to_try, versions_to_try.size()); } std::unique_ptr context; #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__) - context = ContextAGL::Create(wi, versions_to_try, num_versions_to_try); + context = ContextAGL::Create(wi, versions_to_try); #elif defined(__ANDROID__) - context = ContextEGLAndroid::Create(wi, versions_to_try, num_versions_to_try); + context = ContextEGLAndroid::Create(wi, versions_to_try, error); #else #if defined(ENABLE_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 #if defined(ENABLE_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 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 if (!context) @@ -172,7 +188,7 @@ std::unique_ptr Context::Create(const WindowInfo& wi, const Version { 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; } } @@ -180,7 +196,7 @@ std::unique_ptr Context::Create(const WindowInfo& wi, const Version { 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; } } @@ -199,65 +215,4 @@ std::unique_ptr Context::Create(const WindowInfo& wi, const Version return context; } -const std::array& Context::GetAllDesktopVersionsList() -{ - static constexpr std::array 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::GetAllDesktopVersionsListWithFallback() -{ - static constexpr std::array 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::GetAllESVersionsList() -{ - static constexpr std::array vlist = { - {{Profile::ES, 3, 2}, {Profile::ES, 3, 1}, {Profile::ES, 3, 0}, {Profile::ES, 2, 0}}}; - return vlist; -} - -const std::array& Context::GetAllVersionsList() -{ - static constexpr std::array 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 diff --git a/src/util/gl/context.h b/src/util/gl/context.h index 75e4a9848..930fe6d04 100644 --- a/src/util/gl/context.h +++ b/src/util/gl/context.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once @@ -7,10 +7,12 @@ #include "common/types.h" -#include #include +#include #include +class Error; + namespace GL { class Context { @@ -57,26 +59,9 @@ public: virtual std::vector EnumerateFullscreenModes(); - static std::unique_ptr Create(const WindowInfo& wi, const Version* versions_to_try, - size_t num_versions_to_try); - - template - static std::unique_ptr Create(const WindowInfo& wi, const std::array& versions_to_try) - { - return Create(wi, versions_to_try.data(), versions_to_try.size()); - } - - static std::unique_ptr Create(const WindowInfo& wi) { return Create(wi, GetAllVersionsList()); } - - static const std::array& GetAllDesktopVersionsList(); - static const std::array& GetAllDesktopVersionsListWithFallback(); - static const std::array& GetAllESVersionsList(); - static const std::array& GetAllVersionsList(); + static std::unique_ptr Create(const WindowInfo& wi, Error* error); protected: -#ifdef _WIN32 -#endif - WindowInfo m_wi; Version m_version = {}; }; diff --git a/src/util/gl/context_agl.h b/src/util/gl/context_agl.h index 526ec878e..73c91d971 100644 --- a/src/util/gl/context_agl.h +++ b/src/util/gl/context_agl.h @@ -22,8 +22,7 @@ public: ContextAGL(const WindowInfo& wi); ~ContextAGL() override; - static std::unique_ptr Create(const WindowInfo& wi, const Version* versions_to_try, - size_t num_versions_to_try); + static std::unique_ptr Create(const WindowInfo& wi, std::span versions_to_try); void* GetProcAddress(const char* name) override; bool ChangeSurface(const WindowInfo& new_wi) override; @@ -38,7 +37,7 @@ public: private: ALWAYS_INLINE NSView* GetView() const { return static_cast((__bridge NSView*)m_wi.window_handle); } - bool Initialize(const Version* versions_to_try, size_t num_versions_to_try); + bool Initialize(std::span versions_to_try); bool CreateContext(NSOpenGLContext* share_context, int profile, bool make_current); void BindContextToView(); diff --git a/src/util/gl/context_agl.mm b/src/util/gl/context_agl.mm index 17a3c333d..37a52b74c 100644 --- a/src/util/gl/context_agl.mm +++ b/src/util/gl/context_agl.mm @@ -30,21 +30,19 @@ ContextAGL::~ContextAGL() dlclose(m_opengl_module_handle); } -std::unique_ptr ContextAGL::Create(const WindowInfo& wi, const Version* versions_to_try, - size_t num_versions_to_try) +std::unique_ptr ContextAGL::Create(const WindowInfo& wi, std::span versions_to_try) { std::unique_ptr context = std::make_unique(wi); - if (!context->Initialize(versions_to_try, num_versions_to_try)) + if (!context->Initialize(versions_to_try)) return nullptr; return context; } -bool ContextAGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try) +bool ContextAGL::Initialize(const std::span 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)) { // we already have the dummy context, so just use that diff --git a/src/util/gl/context_egl.cpp b/src/util/gl/context_egl.cpp index f7c92a072..042d8c9a0 100644 --- a/src/util/gl/context_egl.cpp +++ b/src/util/gl/context_egl.cpp @@ -1,10 +1,11 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "context_egl.h" #include "common/assert.h" #include "common/log.h" +#include "common/error.h" #include #include @@ -22,21 +23,21 @@ ContextEGL::~ContextEGL() DestroyContext(); } -std::unique_ptr ContextEGL::Create(const WindowInfo& wi, const Version* versions_to_try, - size_t num_versions_to_try) +std::unique_ptr ContextEGL::Create(const WindowInfo& wi, std::span versions_to_try, Error* error) { std::unique_ptr context = std::make_unique(wi); - if (!context->Initialize(versions_to_try, num_versions_to_try)) + if (!context->Initialize(versions_to_try, error)) return nullptr; return context; } -bool ContextEGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try) +bool ContextEGL::Initialize(std::span versions_to_try, Error* error) { 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; } @@ -46,7 +47,9 @@ bool ContextEGL::Initialize(const Version* versions_to_try, size_t num_versions_ int egl_major, egl_minor; if (!eglInitialize(m_display, &egl_major, &egl_minor)) { - Log_ErrorPrintf("eglInitialize() failed: %d", eglGetError()); + const int gerror = static_cast(eglGetError()); + Log_ErrorFmt("eglInitialize() failed: {} (0x{:X})", gerror, gerror); + Error::SetStringFmt(error, "eglInitialize() failed: {} (0x{:X})", gerror, gerror); return false; } 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) 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; } + Error::SetStringView(error, "Failed to create any context versions"); return false; } diff --git a/src/util/gl/context_egl.h b/src/util/gl/context_egl.h index 5125e4269..2b3008552 100644 --- a/src/util/gl/context_egl.h +++ b/src/util/gl/context_egl.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once @@ -15,8 +15,7 @@ public: ContextEGL(const WindowInfo& wi); ~ContextEGL() override; - static std::unique_ptr Create(const WindowInfo& wi, const Version* versions_to_try, - size_t num_versions_to_try); + static std::unique_ptr Create(const WindowInfo& wi, std::span versions_to_try, Error* error); void* GetProcAddress(const char* name) override; virtual bool ChangeSurface(const WindowInfo& new_wi) override; @@ -32,7 +31,7 @@ protected: virtual bool SetDisplay(); virtual EGLNativeWindowType GetNativeWindow(EGLConfig config); - bool Initialize(const Version* versions_to_try, size_t num_versions_to_try); + bool Initialize(std::span versions_to_try, Error* error); bool CreateDisplay(); bool CreateContext(const Version& version, EGLContext share_context); bool CreateContextAndSurface(const Version& version, EGLContext share_context, bool make_current); diff --git a/src/util/gl/context_egl_wayland.cpp b/src/util/gl/context_egl_wayland.cpp index d5b08e89b..64aa29d5c 100644 --- a/src/util/gl/context_egl_wayland.cpp +++ b/src/util/gl/context_egl_wayland.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "context_egl_wayland.h" @@ -12,7 +12,9 @@ Log_SetChannel(ContextEGL); namespace GL { 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() { if (m_wl_window) @@ -21,11 +23,11 @@ ContextEGLWayland::~ContextEGLWayland() dlclose(m_wl_module); } -std::unique_ptr ContextEGLWayland::Create(const WindowInfo& wi, const Version* versions_to_try, - size_t num_versions_to_try) +std::unique_ptr ContextEGLWayland::Create(const WindowInfo& wi, std::span versions_to_try, + Error* error) { std::unique_ptr context = std::make_unique(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 context; diff --git a/src/util/gl/context_egl_wayland.h b/src/util/gl/context_egl_wayland.h index 8c034755e..ee289fbb7 100644 --- a/src/util/gl/context_egl_wayland.h +++ b/src/util/gl/context_egl_wayland.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once @@ -13,8 +13,7 @@ public: ContextEGLWayland(const WindowInfo& wi); ~ContextEGLWayland() override; - static std::unique_ptr Create(const WindowInfo& wi, const Version* versions_to_try, - size_t num_versions_to_try); + static std::unique_ptr Create(const WindowInfo& wi, std::span versions_to_try, Error* error); std::unique_ptr CreateSharedContext(const WindowInfo& wi) override; void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; diff --git a/src/util/gl/context_egl_x11.cpp b/src/util/gl/context_egl_x11.cpp index 440c4a755..18597c4bc 100644 --- a/src/util/gl/context_egl_x11.cpp +++ b/src/util/gl/context_egl_x11.cpp @@ -1,17 +1,19 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "context_egl_x11.h" namespace GL { -ContextEGLX11::ContextEGLX11(const WindowInfo& wi) : ContextEGL(wi) {} +ContextEGLX11::ContextEGLX11(const WindowInfo& wi) : ContextEGL(wi) +{ +} ContextEGLX11::~ContextEGLX11() = default; -std::unique_ptr ContextEGLX11::Create(const WindowInfo& wi, const Version* versions_to_try, - size_t num_versions_to_try) +std::unique_ptr ContextEGLX11::Create(const WindowInfo& wi, std::span versions_to_try, + Error* error) { std::unique_ptr context = std::make_unique(wi); - if (!context->Initialize(versions_to_try, num_versions_to_try)) + if (!context->Initialize(versions_to_try, error)) return nullptr; return context; diff --git a/src/util/gl/context_egl_x11.h b/src/util/gl/context_egl_x11.h index 6bd3d8cae..413f72853 100644 --- a/src/util/gl/context_egl_x11.h +++ b/src/util/gl/context_egl_x11.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once @@ -12,8 +12,7 @@ public: ContextEGLX11(const WindowInfo& wi); ~ContextEGLX11() override; - static std::unique_ptr Create(const WindowInfo& wi, const Version* versions_to_try, - size_t num_versions_to_try); + static std::unique_ptr Create(const WindowInfo& wi, std::span versions_to_try, Error* error); std::unique_ptr CreateSharedContext(const WindowInfo& wi) override; void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override; diff --git a/src/util/gl/context_wgl.cpp b/src/util/gl/context_wgl.cpp index c89604d4c..94347e259 100644 --- a/src/util/gl/context_wgl.cpp +++ b/src/util/gl/context_wgl.cpp @@ -1,10 +1,11 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "context_wgl.h" #include "../opengl_loader.h" #include "common/assert.h" +#include "common/error.h" #include "common/log.h" #include "common/scoped_guard.h" @@ -51,36 +52,44 @@ ContextWGL::~ContextWGL() ReleaseDC(); } -std::unique_ptr ContextWGL::Create(const WindowInfo& wi, const Version* versions_to_try, - size_t num_versions_to_try) +std::unique_ptr ContextWGL::Create(const WindowInfo& wi, std::span versions_to_try, + Error* error) { std::unique_ptr context = std::make_unique(wi); - if (!context->Initialize(versions_to_try, num_versions_to_try)) + if (!context->Initialize(versions_to_try, error)) return nullptr; return context; } -bool ContextWGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try) +bool ContextWGL::Initialize(std::span versions_to_try, Error* error) { if (m_wi.type == WindowInfo::Type::Win32) { if (!InitializeDC()) + { + Error::SetStringView(error, "Failed to create DC."); return false; + } } else { if (!CreatePBuffer()) + { + Error::SetStringView(error, "Failed to create PBuffer"); return false; + } } // Everything including core/ES requires a dummy profile to load the WGL extensions. 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) { // 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; } diff --git a/src/util/gl/context_wgl.h b/src/util/gl/context_wgl.h index d5bc005e6..6a888f60d 100644 --- a/src/util/gl/context_wgl.h +++ b/src/util/gl/context_wgl.h @@ -20,8 +20,7 @@ public: ContextWGL(const WindowInfo& wi); ~ContextWGL() override; - static std::unique_ptr Create(const WindowInfo& wi, const Version* versions_to_try, - size_t num_versions_to_try); + static std::unique_ptr Create(const WindowInfo& wi, std::span versions_to_try, Error* error); void* GetProcAddress(const char* name) override; bool ChangeSurface(const WindowInfo& new_wi) override; @@ -38,7 +37,7 @@ private: HDC GetDCAndSetPixelFormat(HWND hwnd); - bool Initialize(const Version* versions_to_try, size_t num_versions_to_try); + bool Initialize(std::span versions_to_try, Error* error); bool InitializeDC(); void ReleaseDC(); bool CreatePBuffer(); diff --git a/src/util/gpu_device.cpp b/src/util/gpu_device.cpp index 3feea4a95..810605fec 100644 --- a/src/util/gpu_device.cpp +++ b/src/util/gpu_device.cpp @@ -8,6 +8,7 @@ #include "shadergen.h" #include "common/assert.h" +#include "common/error.h" #include "common/file_system.h" #include "common/log.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, u32 shader_cache_version, bool debug_device, bool vsync, bool threaded_presentation, - std::optional exclusive_fullscreen_control, FeatureMask disabled_features) + std::optional exclusive_fullscreen_control, FeatureMask disabled_features, Error* error) { m_vsync_enabled = vsync; m_debug_device = debug_device; if (!AcquireWindow(true)) { - Log_ErrorPrintf("Failed to acquire window from host."); + Error::SetStringView(error, "Failed to acquire window from host."); 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; } @@ -281,7 +283,7 @@ bool GPUDevice::Create(const std::string_view& adapter, const std::string_view& if (!CreateResources()) { - Log_ErrorPrintf("Failed to create base resources."); + Error::SetStringView(error, "Failed to create base resources."); return false; } diff --git a/src/util/gpu_device.h b/src/util/gpu_device.h index b2a36365b..a3fefef41 100644 --- a/src/util/gpu_device.h +++ b/src/util/gpu_device.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once @@ -23,6 +23,8 @@ #include #include +class Error; + enum class RenderAPI : u32 { 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 debug_device, bool vsync, bool threaded_presentation, - std::optional exclusive_fullscreen_control, FeatureMask disabled_features); + std::optional exclusive_fullscreen_control, FeatureMask disabled_features, Error* error); void Destroy(); virtual bool HasSurface() const = 0; @@ -652,7 +654,8 @@ public: protected: virtual bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, - std::optional exclusive_fullscreen_control, FeatureMask disabled_features) = 0; + std::optional exclusive_fullscreen_control, FeatureMask disabled_features, + Error* error) = 0; virtual void DestroyDevice() = 0; std::string GetShaderCacheBaseName(const std::string_view& type) const; diff --git a/src/util/imgui_manager.cpp b/src/util/imgui_manager.cpp index 16846b1ed..b8aa5fafb 100644 --- a/src/util/imgui_manager.cpp +++ b/src/util/imgui_manager.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "imgui_manager.h" @@ -9,6 +9,7 @@ #include "common/assert.h" #include "common/easing.h" +#include "common/error.h" #include "common/file_system.h" #include "common/image.h" #include "common/log.h" @@ -154,11 +155,11 @@ void ImGuiManager::SetShowOSDMessages(bool enable) 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()) { - Panic("Failed to load font data"); + Error::SetString(error, "Failed to load font data"); return false; } @@ -191,7 +192,7 @@ bool ImGuiManager::Initialize(float global_scale, bool show_osd_messages) 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(); return false; } @@ -554,8 +555,25 @@ ImFont* ImGuiManager::AddFixedFont(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_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 }; + 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_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; diff --git a/src/util/imgui_manager.h b/src/util/imgui_manager.h index a20f6383a..a425eac9e 100644 --- a/src/util/imgui_manager.h +++ b/src/util/imgui_manager.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once @@ -6,6 +6,8 @@ #include "common/types.h" #include +class Error; + struct ImFont; union InputBindingKey; @@ -22,7 +24,7 @@ void SetGlobalScale(float global_scale); void SetShowOSDMessages(bool enable); /// 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. void Shutdown(); diff --git a/src/util/metal_device.h b/src/util/metal_device.h index 181e942ed..5df1242a2 100644 --- a/src/util/metal_device.h +++ b/src/util/metal_device.h @@ -257,7 +257,8 @@ public: protected: bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, - std::optional exclusive_fullscreen_control, FeatureMask disabled_features) override; + std::optional exclusive_fullscreen_control, FeatureMask disabled_features, + Error* error) override; void DestroyDevice() override; private: diff --git a/src/util/metal_device.mm b/src/util/metal_device.mm index 676d3d6e5..354abb979 100644 --- a/src/util/metal_device.mm +++ b/src/util/metal_device.mm @@ -6,6 +6,7 @@ #include "common/align.h" #include "common/assert.h" +#include "common/error.h" #include "common/file_system.h" #include "common/log.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, std::optional exclusive_fullscreen_control, - FeatureMask disabled_features) + FeatureMask disabled_features, Error* error) { @autoreleasepool { @@ -149,7 +150,7 @@ bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_pr device = [MTLCreateSystemDefaultDevice() autorelease]; if (device == nil) { - Log_ErrorPrint("Failed to create default Metal device."); + Error::SetStringView(error, "Failed to create default Metal device."); return false; } } @@ -157,7 +158,7 @@ bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_pr id queue = [[device newCommandQueue] autorelease]; if (queue == nil) { - Log_ErrorPrint("Failed to create command queue."); + Error::SetStringView(error, "Failed to create command queue."); return false; } @@ -168,20 +169,23 @@ bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_pr SetFeatures(disabled_features); if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateLayer()) + { + Error::SetStringView(error, "Failed to create layer."); return false; + } CreateCommandBuffer(); RenderBlankFrame(); if (!LoadShaders()) { - Log_ErrorPrint("Failed to load shaders."); + Error::SetStringView(error, "Failed to load shaders."); return false; } if (!CreateBuffers()) { - Log_ErrorPrintf("Failed to create buffers."); + Error::SetStringView(error, "Failed to create buffers."); return false; } diff --git a/src/util/opengl_device.cpp b/src/util/opengl_device.cpp index 4302da5e3..6e83b372b 100644 --- a/src/util/opengl_device.cpp +++ b/src/util/opengl_device.cpp @@ -307,9 +307,9 @@ bool OpenGLDevice::HasSurface() const } bool OpenGLDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation, - std::optional exclusive_fullscreen_control, FeatureMask disabled_features) + std::optional 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) { Log_ErrorPrintf("Failed to create any GL context"); diff --git a/src/util/opengl_device.h b/src/util/opengl_device.h index 140a76814..a020823dc 100644 --- a/src/util/opengl_device.h +++ b/src/util/opengl_device.h @@ -120,7 +120,8 @@ public: protected: bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, - std::optional exclusive_fullscreen_control, FeatureMask disabled_features) override; + std::optional exclusive_fullscreen_control, FeatureMask disabled_features, + Error* error) override; void DestroyDevice() override; bool ReadPipelineCache(const std::string& filename) override; diff --git a/src/util/opengl_pipeline.cpp b/src/util/opengl_pipeline.cpp index 3d2d3fe92..dd1cd7329 100644 --- a/src/util/opengl_pipeline.cpp +++ b/src/util/opengl_pipeline.cpp @@ -544,7 +544,7 @@ void OpenGLDevice::UnrefVAO(const OpenGLPipeline::VertexArrayCacheKey& key) OpenGLPipeline::OpenGLPipeline(const ProgramCacheKey& key, GLuint program, VertexArrayCache::const_iterator vao, const RasterizationState& rs, const DepthState& ds, const BlendState& bs, 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) { } diff --git a/src/util/vulkan_device.cpp b/src/util/vulkan_device.cpp index 9d34e8709..a7adbc707 100644 --- a/src/util/vulkan_device.cpp +++ b/src/util/vulkan_device.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "vulkan_device.h" @@ -13,6 +13,7 @@ #include "common/align.h" #include "common/assert.h" #include "common/bitutils.h" +#include "common/error.h" #include "common/file_system.h" #include "common/log.h" #include "common/path.h" @@ -1859,7 +1860,8 @@ bool VulkanDevice::HasSurface() const } bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation, - std::optional exclusive_fullscreen_control, FeatureMask disabled_features) + std::optional exclusive_fullscreen_control, FeatureMask disabled_features, + Error* error) { std::unique_lock lock(s_instance_mutex); 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()) { - 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; } @@ -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); if (m_instance == VK_NULL_HANDLE) { - Host::ReportErrorAsync("Error", - "Failed to create Vulkan instance. Does your GPU and/or driver support Vulkan?"); + Error::SetStringView(error, "Failed to create Vulkan instance. Does your GPU and/or driver support Vulkan?"); return false; } @@ -1895,13 +1896,14 @@ bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_p if (!Vulkan::LoadVulkanInstanceFunctions(m_instance)) { Log_ErrorPrintf("Failed to load Vulkan instance functions"); + Error::SetStringView(error, "Failed to load Vulkan instance functions"); return false; } GPUList gpus = EnumerateGPUs(m_instance); 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; } @@ -1964,7 +1966,7 @@ bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_p 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; } @@ -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); if (!m_swap_chain) { - Log_ErrorPrintf("Failed to create swap chain"); + Error::SetStringView(error, "Failed to create swap chain"); return false; } @@ -1998,12 +2000,15 @@ bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_p if (!CreateNullTexture()) { - Log_ErrorPrint("Failed to create dummy texture"); + Error::SetStringView(error, "Failed to create dummy texture"); return false; } if (!CreateBuffers() || !CreatePersistentDescriptorSets()) + { + Error::SetStringView(error, "Failed to create buffers/descriptor sets"); return false; + } return true; } diff --git a/src/util/vulkan_device.h b/src/util/vulkan_device.h index c693f76ad..d31d6c984 100644 --- a/src/util/vulkan_device.h +++ b/src/util/vulkan_device.h @@ -218,7 +218,8 @@ public: protected: bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, - std::optional exclusive_fullscreen_control, FeatureMask disabled_features) override; + std::optional exclusive_fullscreen_control, FeatureMask disabled_features, + Error* error) override; void DestroyDevice() override; bool ReadPipelineCache(const std::string& filename) override;