Exemple #1
0
bool VideoBackend::Initialize(void *&window_handle)
{
	InitializeShared();
	InitBackendInfo();

	frameCount = 0;

	const SCoreStartupParameter& core_params = SConfig::GetInstance().m_LocalCoreStartupParameter;

	g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_dx11.ini").c_str());
	g_Config.GameIniLoad();
	g_Config.UpdateProjectionHack();
	g_Config.VerifyValidity();
	UpdateActiveConfig();

	window_handle = (void*)EmuWindow::Create((HWND)window_handle, GetModuleHandle(0), _T("Loading - Please wait."));
	if (window_handle == NULL)
	{
		ERROR_LOG(VIDEO, "An error has occurred while trying to create the window.");
		return false;
	}

	s_BackendInitialized = true;

	return true;
}
Exemple #2
0
bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
{
  InitializeShared();

  std::unique_ptr<GLContext> main_gl_context =
      GLContext::Create(wsi, g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer, true, false,
                        Config::Get(Config::GFX_PREFER_GLES));
  if (!main_gl_context)
    return false;

  if (!InitializeGLExtensions(main_gl_context.get()) || !FillBackendInfo())
    return false;

  g_renderer = std::make_unique<Renderer>(std::move(main_gl_context), wsi.render_surface_scale);
  ProgramShaderCache::Init();
  g_vertex_manager = std::make_unique<VertexManager>();
  g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
  g_framebuffer_manager = std::make_unique<FramebufferManager>();
  g_perf_query = GetPerfQuery();
  g_texture_cache = std::make_unique<TextureCacheBase>();
  g_sampler_cache = std::make_unique<SamplerCache>();
  BoundingBox::Init();

  if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() ||
      !g_renderer->Initialize() || !g_framebuffer_manager->Initialize() ||
      !g_texture_cache->Initialize())
  {
    PanicAlert("Failed to initialize renderer classes");
    Shutdown();
    return false;
  }

  g_shader_cache->InitializeShaderCache();
  return true;
}
Exemple #3
0
bool VideoSoftware::Initialize(void *window_handle)
{
	InitializeShared();
	InitBackendInfo();

	g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_software.ini").c_str());
	g_Config.GameIniLoad();
	g_Config.UpdateProjectionHack();
	g_Config.VerifyValidity();
	UpdateActiveConfig();

	SWOGLWindow::Init(window_handle);

	PixelEngine::Init();
	Clipper::Init();
	Rasterizer::Init();
	SWRenderer::Init();
	DebugUtil::Init();

	// Do our OSD callbacks
	OSD::DoCallbacks(OSD::CallbackType::Initialization);

	m_initialized = true;

	return true;
}
Exemple #4
0
bool VideoBackend::Initialize(void *&window_handle)
{
	InitializeShared();
	InitBackendInfo();

	frameCount = 0;

	g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_dx9.ini").c_str());
	g_Config.GameIniLoad(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strGameIni.c_str());
	g_Config.UpdateProjectionHack();
	g_Config.VerifyValidity();
	UpdateActiveConfig();

	window_handle = (void*)EmuWindow::Create((HWND)window_handle, GetModuleHandle(0), _T("Loading - Please wait."));
	if (window_handle == NULL)
	{
		ERROR_LOG(VIDEO, "An error has occurred while trying to create the window.");
		return false;
	}
	else if (FAILED(DX9::D3D::Init()))
	{
		MessageBox(GetActiveWindow(), _T("Unable to initialize Direct3D. Please make sure that you have the latest version of DirectX 9.0c correctly installed."), _T("Fatal Error"), MB_ICONERROR|MB_OK);
		return false;
	}

	s_BackendInitialized = true;

	return true;
}
Exemple #5
0
bool VideoSoftware::Initialize(const WindowSystemInfo& wsi)
{
  InitializeShared();

  std::unique_ptr<SWOGLWindow> window = SWOGLWindow::Create(wsi);
  if (!window)
    return false;

  Clipper::Init();
  Rasterizer::Init();
  DebugUtil::Init();

  g_renderer = std::make_unique<SWRenderer>(std::move(window));
  g_vertex_manager = std::make_unique<SWVertexLoader>();
  g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
  g_framebuffer_manager = std::make_unique<FramebufferManager>();
  g_perf_query = std::make_unique<PerfQuery>();
  g_texture_cache = std::make_unique<TextureCache>();

  if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() ||
      !g_renderer->Initialize() || !g_framebuffer_manager->Initialize() ||
      !g_texture_cache->Initialize())
  {
    PanicAlert("Failed to initialize renderer classes");
    Shutdown();
    return false;
  }

  g_shader_cache->InitializeShaderCache();
  return true;
}
bool VideoBackend::Initialize(void* window_handle)
{
  InitializeShared();
  InitBackendInfo();

  // Load Configs
  g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini");
  g_Config.GameIniLoad();
  g_Config.UpdateProjectionHack();
  g_Config.VerifyValidity();
  UpdateActiveConfig();

  // Do our OSD callbacks
  OSD::DoCallbacks(OSD::CallbackType::Initialization);

  // Initialize VideoCommon
  CommandProcessor::Init();
  PixelEngine::Init();
  BPInit();
  Fifo::Init();
  OpcodeDecoder::Init();
  IndexGenerator::Init();
  VertexShaderManager::Init();
  PixelShaderManager::Init();
  VertexLoaderManager::Init();
  Host_Message(WM_USER_CREATE);

  return true;
}
Exemple #7
0
bool VideoBackend::Initialize(void *window_handle)
{
	InitializeShared();
	InitBackendInfo();

	frameCount = 0;

	g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + GetConfigName() + ".ini");
	g_Config.GameIniLoad();
	g_Config.UpdateProjectionHack();
	g_Config.VerifyValidity();
	UpdateActiveConfig();

	InitInterface();
	GLInterface->SetMode(GLInterfaceMode::MODE_DETECT);
	if (!GLInterface->Create(window_handle))
		return false;

	// Do our OSD callbacks
	OSD::DoCallbacks(OSD::OSD_INIT);

	s_BackendInitialized = true;

	return true;
}
Exemple #8
0
bool VideoBackend::Initialize(void* window_handle)
{
	InitializeShared();
	InitBackendInfo();

	frameCount = 0;

	if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"))
		g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini");
	else
		g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "gfx_opengl.ini");
	g_Config.GameIniLoad();
	g_Config.UpdateProjectionHack();
	g_Config.VerifyValidity();
	UpdateActiveConfig();

	InitInterface();
	GLInterface->SetMode(GLInterfaceMode::MODE_DETECT);
	if (!GLInterface->Create(window_handle))
		return false;

	// Do our OSD callbacks
	OSD::DoCallbacks(OSD::CallbackType::Initialization);

	m_initialized = true;

	return true;
}
Exemple #9
0
bool VideoBackend::Initialize(void *window_handle)
{
	if (window_handle == nullptr)
		return false;

	if (FAILED(D3D::Create((HWND)window_handle)))
		return false;

	InitializeShared();
	InitBackendInfo();

	frameCount = 0;
	if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"))
		g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini");
	else
		g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "gfx_dx12.ini");
	
	g_Config.GameIniLoad();
	g_Config.UpdateProjectionHack();
	g_Config.VerifyValidity();
	UpdateActiveConfig();

	m_window_handle = window_handle;

	m_initialized = true;

	return true;
}
Exemple #10
0
bool VideoBackend::Initialize(void* window_handle)
{
  InitBackendInfo();
  InitializeShared();

  InitInterface();
  GLInterface->SetMode(GLInterfaceMode::MODE_DETECT);
  if (!GLInterface->Create(window_handle))
    return false;

  return true;
}
Exemple #11
0
bool VideoBackend::Initialize(void* window_handle)
{
  if (window_handle == nullptr)
    return false;

  InitBackendInfo();
  InitializeShared();

  m_window_handle = window_handle;

  return true;
}
Exemple #12
0
bool VideoSoftware::Initialize(void* window_handle)
{
  InitBackendInfo();
  InitializeShared();

  SWOGLWindow::Init(window_handle);

  Clipper::Init();
  Rasterizer::Init();
  SWRenderer::Init();
  DebugUtil::Init();

  return true;
}
Exemple #13
0
bool VideoBackend::Initialize(void* window_handle)
{
    if (window_handle == nullptr)
        return false;

    InitBackendInfo();
    InitializeShared();

    if (FAILED(D3D::Create((HWND)window_handle)))
        return false;

    m_window_handle = window_handle;

    return true;
}
Exemple #14
0
bool VideoBackend::Initialize(void *window_handle)
{
	InitializeShared();
	InitBackendInfo();

	if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"))
		g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini");
	else
		g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_null.ini").c_str());
	g_Config.GameIniLoad();
	g_Config.UpdateProjectionHack();
	g_Config.VerifyValidity();
	UpdateActiveConfig();

	// Do our OSD callbacks
	OSD::DoCallbacks(OSD::CallbackType::Initialization);

	return true;
}
Exemple #15
0
bool VideoBackend::Initialize(void *window_handle)
{
	InitializeShared();
	InitBackendInfo();

	frameCount = 0;

	const SConfig& core_params = SConfig::GetInstance();

	g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + GetConfigName() + ".ini").c_str());
	g_Config.GameIniLoad();
	g_Config.UpdateProjectionHack();
	g_Config.VerifyValidity();
	UpdateActiveConfig();

	m_window_handle = window_handle;

	s_BackendInitialized = true;

	return true;
}
Exemple #16
0
bool VideoBackend::Initialize(void *&window_handle)
{
	InitializeShared();
	InitBackendInfo();

	frameCount = 0;

	g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_opengl.ini").c_str());
	g_Config.GameIniLoad(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strGameIni.c_str());
	g_Config.UpdateProjectionHack();
	g_Config.VerifyValidity();
	UpdateActiveConfig();

	InitInterface();
	if (!GLInterface->Create(window_handle))
		return false;

	s_BackendInitialized = true;

	return true;
}
Exemple #17
0
bool VideoBackend::Initialize(void *&window_handle)
{
	if (window_handle == nullptr)
		return false;

	InitializeShared();
	InitBackendInfo();

	frameCount = 0;

	g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "gfx_dx11.ini");
	g_Config.GameIniLoad();
	g_Config.UpdateProjectionHack();
	g_Config.VerifyValidity();
	UpdateActiveConfig();	

	m_window_handle = window_handle;

	s_BackendInitialized = true;

	return true;
}
Exemple #18
0
bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
{
  InitializeShared();

  if (FAILED(D3D::Create(reinterpret_cast<HWND>(wsi.render_surface))))
  {
    PanicAlert("Failed to create D3D device.");
    return false;
  }

  int backbuffer_width = 1, backbuffer_height = 1;
  if (D3D::swapchain)
  {
    DXGI_SWAP_CHAIN_DESC1 desc = {};
    D3D::swapchain->GetDesc1(&desc);
    backbuffer_width = std::max(desc.Width, 1u);
    backbuffer_height = std::max(desc.Height, 1u);
  }

  // internal interfaces
  g_renderer =
      std::make_unique<Renderer>(backbuffer_width, backbuffer_height, wsi.render_surface_scale);
  g_vertex_manager = std::make_unique<VertexManager>();
  g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();
  g_framebuffer_manager = std::make_unique<FramebufferManager>();
  g_texture_cache = std::make_unique<TextureCacheBase>();
  g_perf_query = std::make_unique<PerfQuery>();
  if (!g_renderer->Initialize() || !g_vertex_manager->Initialize() ||
      !g_shader_cache->Initialize() || !g_framebuffer_manager->Initialize() ||
      !g_texture_cache->Initialize())
  {
    return false;
  }

  BBox::Init();
  g_shader_cache->InitializeShaderCache();
  return true;
}
Exemple #19
0
bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
{
  InitializeShared();

  g_renderer = std::make_unique<Renderer>();
  g_vertex_manager = std::make_unique<VertexManager>();
  g_perf_query = std::make_unique<PerfQuery>();
  g_framebuffer_manager = std::make_unique<FramebufferManager>();
  g_texture_cache = std::make_unique<TextureCache>();
  g_shader_cache = std::make_unique<VideoCommon::ShaderCache>();

  if (!g_vertex_manager->Initialize() || !g_shader_cache->Initialize() ||
      !g_renderer->Initialize() || !g_framebuffer_manager->Initialize() ||
      !g_texture_cache->Initialize())
  {
    PanicAlert("Failed to initialize renderer classes");
    Shutdown();
    return false;
  }

  g_shader_cache->InitializeShaderCache();
  return true;
}
Exemple #20
0
bool VideoBackend::Initialize(void* window_handle)
{
  if (window_handle == nullptr)
    return false;

  InitBackendInfo();
  InitializeShared();

  if (FAILED(D3D::Create(reinterpret_cast<HWND>(window_handle))))
  {
    PanicAlert("Failed to create D3D device.");
    return false;
  }

  int backbuffer_width = 1, backbuffer_height = 1;
  if (D3D::swapchain)
  {
    DXGI_SWAP_CHAIN_DESC1 desc = {};
    D3D::swapchain->GetDesc1(&desc);
    backbuffer_width = std::max(desc.Width, 1u);
    backbuffer_height = std::max(desc.Height, 1u);
  }

  // internal interfaces
  g_renderer = std::make_unique<Renderer>(backbuffer_width, backbuffer_height);
  g_texture_cache = std::make_unique<TextureCache>();
  g_vertex_manager = std::make_unique<VertexManager>();
  g_perf_query = std::make_unique<PerfQuery>();

  VertexShaderCache::Init();
  PixelShaderCache::Init();
  GeometryShaderCache::Init();
  VertexShaderCache::WaitForBackgroundCompilesToComplete();
  D3D::InitUtils();
  BBox::Init();
  return true;
}
Exemple #21
0
bool VideoBackend::Initialize(void* window_handle)
{
  if (!LoadVulkanLibrary())
  {
    PanicAlert("Failed to load Vulkan library.");
    return false;
  }

  // Check for presence of the validation layers before trying to enable it
  bool enable_validation_layer = g_Config.bEnableValidationLayer;
  if (enable_validation_layer && !VulkanContext::CheckValidationLayerAvailablility())
  {
    WARN_LOG(VIDEO, "Validation layer requested but not available, disabling.");
    enable_validation_layer = false;
  }

  // Create Vulkan instance, needed before we can create a surface, or enumerate devices.
  // We use this instance to fill in backend info, then re-use it for the actual device.
  bool enable_surface = window_handle != nullptr;
  bool enable_debug_reports = ShouldEnableDebugReports(enable_validation_layer);
  VkInstance instance = VulkanContext::CreateVulkanInstance(enable_surface, enable_debug_reports,
                                                            enable_validation_layer);
  if (instance == VK_NULL_HANDLE)
  {
    PanicAlert("Failed to create Vulkan instance.");
    UnloadVulkanLibrary();
    return false;
  }

  // Load instance function pointers.
  if (!LoadVulkanInstanceFunctions(instance))
  {
    PanicAlert("Failed to load Vulkan instance functions.");
    vkDestroyInstance(instance, nullptr);
    UnloadVulkanLibrary();
    return false;
  }

  // Obtain a list of physical devices (GPUs) from the instance.
  // We'll re-use this list later when creating the device.
  VulkanContext::GPUList gpu_list = VulkanContext::EnumerateGPUs(instance);
  if (gpu_list.empty())
  {
    PanicAlert("No Vulkan physical devices available.");
    vkDestroyInstance(instance, nullptr);
    UnloadVulkanLibrary();
    return false;
  }

  // Populate BackendInfo with as much information as we can at this point.
  VulkanContext::PopulateBackendInfo(&g_Config);
  VulkanContext::PopulateBackendInfoAdapters(&g_Config, gpu_list);

  // We need the surface before we can create a device, as some parameters depend on it.
  VkSurfaceKHR surface = VK_NULL_HANDLE;
  if (enable_surface)
  {
    surface = SwapChain::CreateVulkanSurface(instance, window_handle);
    if (surface == VK_NULL_HANDLE)
    {
      PanicAlert("Failed to create Vulkan surface.");
      vkDestroyInstance(instance, nullptr);
      UnloadVulkanLibrary();
      return false;
    }
  }

  // Since we haven't called InitializeShared yet, iAdapter may be out of range,
  // so we have to check it ourselves.
  size_t selected_adapter_index = static_cast<size_t>(g_Config.iAdapter);
  if (selected_adapter_index >= gpu_list.size())
  {
    WARN_LOG(VIDEO, "Vulkan adapter index out of range, selecting first adapter.");
    selected_adapter_index = 0;
  }

  // Now we can create the Vulkan device. VulkanContext takes ownership of the instance and surface.
  g_vulkan_context = VulkanContext::Create(instance, gpu_list[selected_adapter_index], surface,
                                           enable_debug_reports, enable_validation_layer);
  if (!g_vulkan_context)
  {
    PanicAlert("Failed to create Vulkan device");
    UnloadVulkanLibrary();
    return false;
  }

  // Since VulkanContext maintains a copy of the device features and properties, we can use this
  // to initialize the backend information, so that we don't need to enumerate everything again.
  VulkanContext::PopulateBackendInfoFeatures(&g_Config, g_vulkan_context->GetPhysicalDevice(),
                                             g_vulkan_context->GetDeviceProperties(),
                                             g_vulkan_context->GetDeviceFeatures());
  VulkanContext::PopulateBackendInfoMultisampleModes(
      &g_Config, g_vulkan_context->GetPhysicalDevice(), g_vulkan_context->GetDeviceProperties());

  // With the backend information populated, we can now initialize videocommon.
  InitializeShared();

  // Create command buffers. We do this separately because the other classes depend on it.
  g_command_buffer_mgr = std::make_unique<CommandBufferManager>(g_Config.bBackendMultithreading);
  if (!g_command_buffer_mgr->Initialize())
  {
    PanicAlert("Failed to create Vulkan command buffers");
    Shutdown();
    return false;
  }

  // Remaining classes are also dependent on object/shader cache.
  g_object_cache = std::make_unique<ObjectCache>();
  g_shader_cache = std::make_unique<ShaderCache>();
  if (!g_object_cache->Initialize() || !g_shader_cache->Initialize())
  {
    PanicAlert("Failed to initialize Vulkan object cache.");
    Shutdown();
    return false;
  }

  // Create swap chain. This has to be done early so that the target size is correct for auto-scale.
  std::unique_ptr<SwapChain> swap_chain;
  if (surface != VK_NULL_HANDLE)
  {
    swap_chain = SwapChain::Create(window_handle, surface, g_Config.IsVSync());
    if (!swap_chain)
    {
      PanicAlert("Failed to create Vulkan swap chain.");
      Shutdown();
      return false;
    }
  }

  // Create main wrapper instances.
  g_framebuffer_manager = std::make_unique<FramebufferManager>();
  g_renderer = std::make_unique<Renderer>(std::move(swap_chain));
  g_vertex_manager = std::make_unique<VertexManager>();
  g_texture_cache = std::make_unique<TextureCache>();
  g_perf_query = std::make_unique<PerfQuery>();

  // Invoke init methods on main wrapper classes.
  // These have to be done before the others because the destructors
  // for the remaining classes may call methods on these.
  if (!StateTracker::CreateInstance() || !FramebufferManager::GetInstance()->Initialize() ||
      !Renderer::GetInstance()->Initialize() || !VertexManager::GetInstance()->Initialize() ||
      !TextureCache::GetInstance()->Initialize() || !PerfQuery::GetInstance()->Initialize())
  {
    PanicAlert("Failed to initialize Vulkan classes.");
    Shutdown();
    return false;
  }

  // Ensure all pipelines previously used by the game have been created.
  StateTracker::GetInstance()->ReloadPipelineUIDCache();

  // Lastly, precompile ubershaders, if requested.
  // This has to be done after the texture cache and shader cache are initialized.
  if (g_ActiveConfig.CanPrecompileUberShaders())
    g_shader_cache->PrecompileUberShaders();

  // Display the name so the user knows which device was actually created.
  INFO_LOG(VIDEO, "Vulkan Device: %s", g_vulkan_context->GetDeviceProperties().deviceName);
  return true;
}
Exemple #22
0
bool VideoBackend::Initialize(void* window_handle)
{
  if (!LoadVulkanLibrary())
  {
    PanicAlert("Failed to load Vulkan library.");
    return false;
  }

  // HACK: Use InitBackendInfo to initially populate backend features.
  // This is because things like stereo get disabled when the config is validated,
  // which happens before our device is created (settings control instance behavior),
  // and we don't want that to happen if the device actually supports it.
  InitBackendInfo();
  InitializeShared();

  // Check for presence of the debug layer before trying to enable it
  bool enable_validation_layer = g_Config.bEnableValidationLayer;
  if (enable_validation_layer && !VulkanContext::CheckValidationLayerAvailablility())
  {
    WARN_LOG(VIDEO, "Validation layer requested but not available, disabling.");
    enable_validation_layer = false;
  }

  // Create Vulkan instance, needed before we can create a surface.
  bool enable_surface = (window_handle != nullptr);
  VkInstance instance =
      VulkanContext::CreateVulkanInstance(enable_surface, enable_validation_layer);
  if (instance == VK_NULL_HANDLE)
  {
    PanicAlert("Failed to create Vulkan instance.");
    UnloadVulkanLibrary();
    ShutdownShared();
    return false;
  }

  // Load instance function pointers
  if (!LoadVulkanInstanceFunctions(instance))
  {
    PanicAlert("Failed to load Vulkan instance functions.");
    vkDestroyInstance(instance, nullptr);
    UnloadVulkanLibrary();
    ShutdownShared();
    return false;
  }

  // Create Vulkan surface
  VkSurfaceKHR surface = VK_NULL_HANDLE;
  if (enable_surface)
  {
    surface = SwapChain::CreateVulkanSurface(instance, window_handle);
    if (surface == VK_NULL_HANDLE)
    {
      PanicAlert("Failed to create Vulkan surface.");
      vkDestroyInstance(instance, nullptr);
      UnloadVulkanLibrary();
      ShutdownShared();
      return false;
    }
  }

  // Fill the adapter list, and check if the user has selected an invalid device
  // For some reason nvidia's driver crashes randomly if you call vkEnumeratePhysicalDevices
  // after creating a device..
  VulkanContext::GPUList gpu_list = VulkanContext::EnumerateGPUs(instance);
  size_t selected_adapter_index = static_cast<size_t>(g_Config.iAdapter);
  if (gpu_list.empty())
  {
    PanicAlert("No Vulkan physical devices available.");
    if (surface != VK_NULL_HANDLE)
      vkDestroySurfaceKHR(instance, surface, nullptr);

    vkDestroyInstance(instance, nullptr);
    UnloadVulkanLibrary();
    ShutdownShared();
    return false;
  }
  else if (selected_adapter_index >= gpu_list.size())
  {
    WARN_LOG(VIDEO, "Vulkan adapter index out of range, selecting first adapter.");
    selected_adapter_index = 0;
  }

  // Pass ownership over to VulkanContext, and let it take care of everything.
  g_vulkan_context = VulkanContext::Create(instance, gpu_list[selected_adapter_index], surface,
                                           &g_Config, enable_validation_layer);
  if (!g_vulkan_context)
  {
    PanicAlert("Failed to create Vulkan device");
    UnloadVulkanLibrary();
    ShutdownShared();
    return false;
  }

  // Create swap chain. This has to be done early so that the target size is correct for auto-scale.
  std::unique_ptr<SwapChain> swap_chain;
  if (surface != VK_NULL_HANDLE)
  {
    swap_chain = SwapChain::Create(window_handle, surface, g_Config.IsVSync());
    if (!swap_chain)
    {
      PanicAlert("Failed to create Vulkan swap chain.");
      return false;
    }
  }

  // Create command buffers. We do this separately because the other classes depend on it.
  g_command_buffer_mgr = std::make_unique<CommandBufferManager>(g_Config.bBackendMultithreading);
  if (!g_command_buffer_mgr->Initialize())
  {
    PanicAlert("Failed to create Vulkan command buffers");
    g_command_buffer_mgr.reset();
    g_vulkan_context.reset();
    UnloadVulkanLibrary();
    ShutdownShared();
    return false;
  }

  // Create main wrapper instances.
  g_object_cache = std::make_unique<ObjectCache>();
  g_framebuffer_manager = std::make_unique<FramebufferManager>();
  g_renderer = std::make_unique<Renderer>(std::move(swap_chain));

  // Invoke init methods on main wrapper classes.
  // These have to be done before the others because the destructors
  // for the remaining classes may call methods on these.
  if (!g_object_cache->Initialize() || !FramebufferManager::GetInstance()->Initialize() ||
      !StateTracker::CreateInstance() || !Renderer::GetInstance()->Initialize())
  {
    PanicAlert("Failed to initialize Vulkan classes.");
    g_renderer.reset();
    StateTracker::DestroyInstance();
    g_framebuffer_manager.reset();
    g_object_cache.reset();
    g_command_buffer_mgr.reset();
    g_vulkan_context.reset();
    UnloadVulkanLibrary();
    ShutdownShared();
    return false;
  }

  // Create remaining wrapper instances.
  g_vertex_manager = std::make_unique<VertexManager>();
  g_texture_cache = std::make_unique<TextureCache>();
  g_perf_query = std::make_unique<PerfQuery>();
  if (!VertexManager::GetInstance()->Initialize() || !TextureCache::GetInstance()->Initialize() ||
      !PerfQuery::GetInstance()->Initialize())
  {
    PanicAlert("Failed to initialize Vulkan classes.");
    g_perf_query.reset();
    g_texture_cache.reset();
    g_vertex_manager.reset();
    g_renderer.reset();
    StateTracker::DestroyInstance();
    g_framebuffer_manager.reset();
    g_object_cache.reset();
    g_command_buffer_mgr.reset();
    g_vulkan_context.reset();
    UnloadVulkanLibrary();
    ShutdownShared();
    return false;
  }

  return true;
}