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)
{
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 {}: <Could not get error message>", err);
m_description = fmt::format("{}errno {}: <Could not get error message>", 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 {}: <Could not get error message>", err);
m_description = fmt::format("{}errno {}: <Could not get error message>", 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 {}: <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);
}
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}: <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);
}
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();

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)
#pragma once
#include "types.h"
#include "fmt/core.h"
#include <string>
#include <string_view>
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<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=(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)
#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<GPUDevice::FeatureMask>(disabled_features)))
static_cast<GPUDevice::FeatureMask>(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;

View File

@ -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<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);
@ -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<IDXGIFactory5> factory = D3DCommon::CreateFactory(false);
ComPtr<IDXGIFactory5> factory = D3DCommon::CreateFactory(false, nullptr);
if (factory)
GetAdapterAndModeList(&ret, factory.Get());
}

View File

@ -107,7 +107,8 @@ public:
protected:
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;
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)
#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<ID3D12RootSignature> D3D12Device::CreateRootSignature(const
}
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);
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<IDXGIFactory5> factory = D3DCommon::CreateFactory(false);
ComPtr<IDXGIFactory5> factory = D3DCommon::CreateFactory(false, nullptr);
if (factory)
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)
#pragma once
@ -175,7 +175,8 @@ public:
protected:
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;
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)
#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<IDXGIFactory5> D3DCommon::CreateFactory(bool debug)
Microsoft::WRL::ComPtr<IDXGIFactory5> D3DCommon::CreateFactory(bool debug, Error* error)
{
UINT flags = 0;
if (debug)
@ -63,7 +64,7 @@ Microsoft::WRL::ComPtr<IDXGIFactory5> D3DCommon::CreateFactory(bool debug)
Microsoft::WRL::ComPtr<IDXGIFactory5> 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;
}

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)
#pragma once
@ -16,6 +16,8 @@
#include <vector>
#include <wrl/client.h>
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<IDXGIFactory5> CreateFactory(bool debug);
Microsoft::WRL::ComPtr<IDXGIFactory5> CreateFactory(bool debug, Error* error);
// returns a list of all adapter names
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)
#include "context.h"
#include "../opengl_loader.h"
#include "common/error.h"
#include "common/log.h"
#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))
{
// 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::FullscreenModeInfo> Context::EnumerateFullscreenModes()
return {};
}
std::unique_ptr<GL::Context> Context::Create(const WindowInfo& wi, const Version* versions_to_try,
size_t num_versions_to_try)
std::unique_ptr<GL::Context> Context::Create(const WindowInfo& wi, Error* error)
{
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())
{
// 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;
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<const Version>(new_versions_to_try, versions_to_try.size());
}
std::unique_ptr<Context> 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<GL::Context> 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<GL::Context> 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<GL::Context> Context::Create(const WindowInfo& wi, const Version
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

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)
#pragma once
@ -7,10 +7,12 @@
#include "common/types.h"
#include <array>
#include <memory>
#include <span>
#include <vector>
class Error;
namespace GL {
class Context
{
@ -57,26 +59,9 @@ public:
virtual std::vector<FullscreenModeInfo> EnumerateFullscreenModes();
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try,
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();
static std::unique_ptr<Context> Create(const WindowInfo& wi, Error* error);
protected:
#ifdef _WIN32
#endif
WindowInfo m_wi;
Version m_version = {};
};

View File

@ -22,8 +22,7 @@ public:
ContextAGL(const WindowInfo& wi);
~ContextAGL() override;
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try,
size_t num_versions_to_try);
static std::unique_ptr<Context> Create(const WindowInfo& wi, std::span<const Version> 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<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);
void BindContextToView();

View File

@ -30,21 +30,19 @@ ContextAGL::~ContextAGL()
dlclose(m_opengl_module_handle);
}
std::unique_ptr<Context> ContextAGL::Create(const WindowInfo& wi, const Version* versions_to_try,
size_t num_versions_to_try)
std::unique_ptr<Context> ContextAGL::Create(const WindowInfo& wi, std::span<const Version> versions_to_try)
{
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 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))
{
// 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)
#include "context_egl.h"
#include "common/assert.h"
#include "common/log.h"
#include "common/error.h"
#include <optional>
#include <vector>
@ -22,21 +23,21 @@ ContextEGL::~ContextEGL()
DestroyContext();
}
std::unique_ptr<Context> ContextEGL::Create(const WindowInfo& wi, const Version* versions_to_try,
size_t num_versions_to_try)
std::unique_ptr<Context> ContextEGL::Create(const WindowInfo& wi, std::span<const Version> versions_to_try, Error* error)
{
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 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())
{
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<int>(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;
}

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)
#pragma once
@ -15,8 +15,7 @@ public:
ContextEGL(const WindowInfo& wi);
~ContextEGL() override;
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try,
size_t num_versions_to_try);
static std::unique_ptr<Context> Create(const WindowInfo& wi, std::span<const Version> 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<const Version> 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);

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)
#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<Context> ContextEGLWayland::Create(const WindowInfo& wi, const Version* versions_to_try,
size_t num_versions_to_try)
std::unique_ptr<Context> ContextEGLWayland::Create(const WindowInfo& wi, std::span<const Version> versions_to_try,
Error* error)
{
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 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)
#pragma once
@ -13,8 +13,7 @@ public:
ContextEGLWayland(const WindowInfo& wi);
~ContextEGLWayland() override;
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try,
size_t num_versions_to_try);
static std::unique_ptr<Context> Create(const WindowInfo& wi, std::span<const Version> versions_to_try, Error* error);
std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) 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)
#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<Context> ContextEGLX11::Create(const WindowInfo& wi, const Version* versions_to_try,
size_t num_versions_to_try)
std::unique_ptr<Context> ContextEGLX11::Create(const WindowInfo& wi, std::span<const Version> versions_to_try,
Error* error)
{
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 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)
#pragma once
@ -12,8 +12,7 @@ public:
ContextEGLX11(const WindowInfo& wi);
~ContextEGLX11() override;
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try,
size_t num_versions_to_try);
static std::unique_ptr<Context> Create(const WindowInfo& wi, std::span<const Version> versions_to_try, Error* error);
std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) 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)
#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<Context> ContextWGL::Create(const WindowInfo& wi, const Version* versions_to_try,
size_t num_versions_to_try)
std::unique_ptr<Context> ContextWGL::Create(const WindowInfo& wi, std::span<const Version> versions_to_try,
Error* error)
{
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 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 (!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;
}

View File

@ -20,8 +20,7 @@ public:
ContextWGL(const WindowInfo& wi);
~ContextWGL() override;
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try,
size_t num_versions_to_try);
static std::unique_ptr<Context> Create(const WindowInfo& wi, std::span<const Version> 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<const Version> versions_to_try, Error* error);
bool InitializeDC();
void ReleaseDC();
bool CreatePBuffer();

View File

@ -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<bool> exclusive_fullscreen_control, FeatureMask disabled_features)
std::optional<bool> 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;
}

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)
#pragma once
@ -23,6 +23,8 @@
#include <tuple>
#include <vector>
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<bool> exclusive_fullscreen_control, FeatureMask disabled_features);
std::optional<bool> 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<bool> exclusive_fullscreen_control, FeatureMask disabled_features) = 0;
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
Error* error) = 0;
virtual void DestroyDevice() = 0;
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)
#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;

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)
#pragma once
@ -6,6 +6,8 @@
#include "common/types.h"
#include <string>
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();

View File

@ -257,7 +257,8 @@ public:
protected:
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;
private:

View File

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

View File

@ -307,9 +307,9 @@ bool OpenGLDevice::HasSurface() const
}
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)
{
Log_ErrorPrintf("Failed to create any GL context");

View File

@ -120,7 +120,8 @@ public:
protected:
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;
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,
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)
{
}

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)
#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<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);
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;
}

View File

@ -218,7 +218,8 @@ public:
protected:
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;
bool ReadPipelineCache(const std::string& filename) override;