diff --git a/Source/Core/Common/Semaphore.h b/Source/Core/Common/Semaphore.h index 0c48d2fb4d..d132288f2a 100644 --- a/Source/Core/Common/Semaphore.h +++ b/Source/Core/Common/Semaphore.h @@ -30,7 +30,31 @@ private: }; } // namespace Common -#else // _WIN32 +#elif defined(__APPLE__) + +#include + +namespace Common +{ +class Semaphore +{ +public: + Semaphore(int initial_count, int maximum_count) + { + m_handle = dispatch_semaphore_create(0); + for (int i = 0; i < initial_count; i++) + dispatch_semaphore_signal(m_handle); + } + ~Semaphore() { dispatch_release(m_handle); } + void Wait() { dispatch_semaphore_wait(m_handle, DISPATCH_TIME_FOREVER); } + void Post() { dispatch_semaphore_signal(m_handle); } + +private: + dispatch_semaphore_t m_handle; +}; +} // namespace Common + +#else #include diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 30ae5e0946..b7c7caacd6 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -293,6 +293,7 @@ PUBLIC videonull videoogl videosoftware + videovulkan PRIVATE ${LZO} @@ -322,10 +323,6 @@ if(LIBUSB_FOUND) ) endif() -if(NOT APPLE) - target_link_libraries(core PUBLIC videovulkan) -endif() - if(WIN32) target_sources(core PRIVATE HW/EXI/BBA-TAP/TAP_Win32.cpp diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index b5a4b13ce0..b97d62a5d9 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -214,6 +214,9 @@ bool Init(std::unique_ptr boot, const WindowSystemInfo& wsi) Host_UpdateMainFrame(); // Disable any menus or buttons at boot + // Issue any API calls which must occur on the main thread for the graphics backend. + g_video_backend->PrepareWindow(wsi); + // Start the emu thread s_emu_thread = std::thread(EmuThread, std::move(boot), wsi); return true; diff --git a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp index 314e513213..1678a3f7bc 100644 --- a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp @@ -92,15 +92,17 @@ void AdvancedWidget::CreateWidgets() m_enable_cropping = new GraphicsBool(tr("Crop"), Config::GFX_CROP); m_enable_prog_scan = new QCheckBox(tr("Enable Progressive Scan")); + m_backend_multithreading = + new GraphicsBool(tr("Backend Multi-threading"), Config::GFX_BACKEND_MULTITHREADING); misc_layout->addWidget(m_enable_cropping, 0, 0); misc_layout->addWidget(m_enable_prog_scan, 0, 1); - + misc_layout->addWidget(m_backend_multithreading, 1, 0); #ifdef _WIN32 m_borderless_fullscreen = new GraphicsBool(tr("Borderless Fullscreen"), Config::GFX_BORDERLESS_FULLSCREEN); - misc_layout->addWidget(m_borderless_fullscreen, 1, 0); + misc_layout->addWidget(m_borderless_fullscreen, 1, 1); #endif main_layout->addWidget(debugging_box); @@ -191,6 +193,11 @@ void AdvancedWidget::AddDescriptions() static const char TR_PROGRESSIVE_SCAN_DESCRIPTION[] = QT_TR_NOOP( "Enables progressive scan if supported by the emulated software.\nMost games don't " "care about this.\n\nIf unsure, leave this unchecked."); + static const char TR_BACKEND_MULTITHREADING_DESCRIPTION[] = + QT_TR_NOOP("Enables multi-threaded command submission in backends where supported. Enabling " + "this option may result in a performance improvement on systems with more than " + "two CPU cores. Currently, this is limited to the Vulkan backend.\n\nIf unsure, " + "leave this checked."); #ifdef _WIN32 static const char TR_BORDERLESS_FULLSCREEN_DESCRIPTION[] = QT_TR_NOOP( "Implement fullscreen mode with a borderless window spanning the whole screen instead of " @@ -217,6 +224,7 @@ void AdvancedWidget::AddDescriptions() AddDescription(m_enable_cropping, TR_CROPPING_DESCRIPTION); AddDescription(m_enable_prog_scan, TR_PROGRESSIVE_SCAN_DESCRIPTION); AddDescription(m_enable_freelook, TR_FREE_LOOK_DESCRIPTION); + AddDescription(m_backend_multithreading, TR_BACKEND_MULTITHREADING_DESCRIPTION); #ifdef _WIN32 AddDescription(m_borderless_fullscreen, TR_BORDERLESS_FULLSCREEN_DESCRIPTION); #endif diff --git a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h index 05cacf0991..b0eaf6bf11 100644 --- a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h +++ b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h @@ -44,5 +44,6 @@ private: // Misc QCheckBox* m_enable_cropping; QCheckBox* m_enable_prog_scan; + QCheckBox* m_backend_multithreading; QCheckBox* m_borderless_fullscreen; }; diff --git a/Source/Core/VideoBackends/CMakeLists.txt b/Source/Core/VideoBackends/CMakeLists.txt index 119f92bca8..e670dd7d4a 100644 --- a/Source/Core/VideoBackends/CMakeLists.txt +++ b/Source/Core/VideoBackends/CMakeLists.txt @@ -1,11 +1,9 @@ add_subdirectory(OGL) add_subdirectory(Null) add_subdirectory(Software) +add_subdirectory(Vulkan) if(CMAKE_SYSTEM_NAME STREQUAL "Windows") add_subdirectory(D3D) endif() -if(NOT APPLE) - add_subdirectory(Vulkan) -endif() diff --git a/Source/Core/VideoBackends/Vulkan/SwapChain.cpp b/Source/Core/VideoBackends/Vulkan/SwapChain.cpp index 5222d88114..ffddfe4d07 100644 --- a/Source/Core/VideoBackends/Vulkan/SwapChain.cpp +++ b/Source/Core/VideoBackends/Vulkan/SwapChain.cpp @@ -118,6 +118,19 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, void* display_h return surface; +#elif defined(VK_USE_PLATFORM_MACOS_MVK) + VkMacOSSurfaceCreateInfoMVK surface_create_info = { + VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, nullptr, 0, hwnd}; + + VkSurfaceKHR surface; + VkResult res = vkCreateMacOSSurfaceMVK(instance, &surface_create_info, nullptr, &surface); + if (res != VK_SUCCESS) + { + LOG_VULKAN_ERROR(res, "vkCreateMacOSSurfaceMVK failed: "); + return VK_NULL_HANDLE; + } + + return surface; #else return VK_NULL_HANDLE; #endif diff --git a/Source/Core/VideoBackends/Vulkan/VideoBackend.h b/Source/Core/VideoBackends/Vulkan/VideoBackend.h index 83d960330e..91cdbb6a1e 100644 --- a/Source/Core/VideoBackends/Vulkan/VideoBackend.h +++ b/Source/Core/VideoBackends/Vulkan/VideoBackend.h @@ -18,5 +18,6 @@ public: std::string GetName() const override { return "Vulkan"; } std::string GetDisplayName() const override { return _trans("Vulkan"); } void InitBackendInfo() override; + void PrepareWindow(const WindowSystemInfo& wsi) override; }; } // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp index 52f0088239..a1f093ccf1 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp @@ -186,6 +186,9 @@ bool VulkanContext::SelectInstanceExtensions(ExtensionList* extension_list, bool #elif defined(VK_USE_PLATFORM_ANDROID_KHR) if (enable_surface && !SupportsExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true)) return false; +#elif defined(VK_USE_PLATFORM_MACOS_MVK) + if (enable_surface && !SupportsExtension(VK_MVK_MACOS_SURFACE_EXTENSION_NAME, true)) + return false; #endif // VK_EXT_debug_report @@ -833,6 +836,13 @@ void VulkanContext::InitDriverDetails() driver = DriverDetails::DRIVER_UNKNOWN; } +#ifdef __APPLE__ + // Vulkan on macOS goes through Metal, and is not susceptible to the same bugs + // as the vendor's native Vulkan drivers. We use a different driver fields to + // differentiate MoltenVK. + driver = DriverDetails::DRIVER_PORTABILITY; +#endif + DriverDetails::Init(DriverDetails::API_VULKAN, vendor, driver, static_cast(m_device_properties.driverVersion), DriverDetails::Family::UNKNOWN); diff --git a/Source/Core/VideoBackends/Vulkan/VulkanEntryPoints.inl b/Source/Core/VideoBackends/Vulkan/VulkanEntryPoints.inl index a6c392d84b..333efa62b2 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanEntryPoints.inl +++ b/Source/Core/VideoBackends/Vulkan/VulkanEntryPoints.inl @@ -16,7 +16,7 @@ VULKAN_MODULE_ENTRY_POINT(vkGetDeviceProcAddr, true) VULKAN_MODULE_ENTRY_POINT(vkEnumerateInstanceExtensionProperties, true) VULKAN_MODULE_ENTRY_POINT(vkEnumerateInstanceLayerProperties, true) -#endif // VULKAN_MODULE_ENTRY_POINT +#endif // VULKAN_MODULE_ENTRY_POINT #ifdef VULKAN_INSTANCE_ENTRY_POINT @@ -178,13 +178,17 @@ VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceXcbPresentationSupportKHR, false) VULKAN_INSTANCE_ENTRY_POINT(vkCreateAndroidSurfaceKHR, false) +#elif defined(VK_USE_PLATFORM_MACOS_MVK) + +VULKAN_INSTANCE_ENTRY_POINT(vkCreateMacOSSurfaceMVK, false) + #endif VULKAN_INSTANCE_ENTRY_POINT(vkCreateDebugReportCallbackEXT, false) VULKAN_INSTANCE_ENTRY_POINT(vkDestroyDebugReportCallbackEXT, false) VULKAN_INSTANCE_ENTRY_POINT(vkDebugReportMessageEXT, false) -#endif // VULKAN_INSTANCE_ENTRY_POINT +#endif // VULKAN_INSTANCE_ENTRY_POINT #ifdef VULKAN_DEVICE_ENTRY_POINT @@ -194,4 +198,4 @@ VULKAN_DEVICE_ENTRY_POINT(vkGetSwapchainImagesKHR, false) VULKAN_DEVICE_ENTRY_POINT(vkAcquireNextImageKHR, false) VULKAN_DEVICE_ENTRY_POINT(vkQueuePresentKHR, false) -#endif // VULKAN_DEVICE_ENTRY_POINT +#endif // VULKAN_DEVICE_ENTRY_POINT diff --git a/Source/Core/VideoBackends/Vulkan/VulkanLoader.cpp b/Source/Core/VideoBackends/Vulkan/VulkanLoader.cpp index 0c9fae677b..96f955ce2c 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanLoader.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanLoader.cpp @@ -4,8 +4,10 @@ #include #include +#include #include "Common/CommonFuncs.h" +#include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/StringUtil.h" @@ -14,7 +16,8 @@ #if defined(VK_USE_PLATFORM_WIN32_KHR) #include #elif defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR) || \ - defined(VK_USE_PLATFORM_ANDROID_KHR) || defined(USE_HEADLESS) + defined(VK_USE_PLATFORM_ANDROID_KHR) || defined(VK_USE_PLATFORM_MACOS_MVK) || \ + defined(USE_HEADLESS) #include #endif @@ -98,7 +101,8 @@ void UnloadVulkanLibrary() } #elif defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR) || \ - defined(VK_USE_PLATFORM_ANDROID_KHR) || defined(USE_HEADLESS) + defined(VK_USE_PLATFORM_ANDROID_KHR) || defined(VK_USE_PLATFORM_MACOS_MVK) || \ + defined(USE_HEADLESS) static void* vulkan_module; static std::atomic_int vulkan_module_ref_count = {0}; @@ -112,15 +116,27 @@ bool LoadVulkanLibrary() return true; } +#if defined(__APPLE__) + // Check if a path to a specific Vulkan library has been specified. + char* libvulkan_env = getenv("LIBVULKAN_PATH"); + if (libvulkan_env) + vulkan_module = dlopen(libvulkan_env, RTLD_NOW); + if (!vulkan_module) + { + // Use the libvulkan.dylib from the application bundle. + std::string path = File::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib"; + vulkan_module = dlopen(path.c_str(), RTLD_NOW); + } +#else // Names of libraries to search. Desktop should use libvulkan.so.1 or libvulkan.so. static const char* search_lib_names[] = {"libvulkan.so.1", "libvulkan.so"}; - for (size_t i = 0; i < ArraySize(search_lib_names); i++) { vulkan_module = dlopen(search_lib_names[i], RTLD_NOW); if (vulkan_module) break; } +#endif if (!vulkan_module) { @@ -164,6 +180,7 @@ void UnloadVulkanLibrary() dlclose(vulkan_module); vulkan_module = nullptr; } + #else //#warning Unknown platform, not compiling loader. diff --git a/Source/Core/VideoBackends/Vulkan/VulkanLoader.h b/Source/Core/VideoBackends/Vulkan/VulkanLoader.h index 5d67c67fbf..3ae2584f8b 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanLoader.h +++ b/Source/Core/VideoBackends/Vulkan/VulkanLoader.h @@ -15,6 +15,8 @@ //#define VK_USE_PLATFORM_XCB_KHR #elif defined(ANDROID) #define VK_USE_PLATFORM_ANDROID_KHR +#elif defined(__APPLE__) +#define VK_USE_PLATFORM_MACOS_MVK #else //#warning Unknown platform #endif diff --git a/Source/Core/VideoBackends/Vulkan/main.cpp b/Source/Core/VideoBackends/Vulkan/main.cpp index 40798934e7..63d61c9d01 100644 --- a/Source/Core/VideoBackends/Vulkan/main.cpp +++ b/Source/Core/VideoBackends/Vulkan/main.cpp @@ -24,6 +24,10 @@ #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoConfig.h" +#if defined(VK_USE_PLATFORM_MACOS_MVK) +#include +#endif + namespace Vulkan { void VideoBackend::InitBackendInfo() @@ -272,4 +276,33 @@ void VideoBackend::Shutdown() ShutdownShared(); UnloadVulkanLibrary(); } + +void VideoBackend::PrepareWindow(const WindowSystemInfo& wsi) +{ +#if defined(VK_USE_PLATFORM_MACOS_MVK) + // This is kinda messy, but it avoids having to write Objective C++ just to create a metal layer. + id view = reinterpret_cast(wsi.render_surface); + Class clsCAMetalLayer = objc_getClass("CAMetalLayer"); + if (!clsCAMetalLayer) + { + ERROR_LOG(VIDEO, "Failed to get CAMetalLayer class."); + return; + } + + // [CAMetalLayer layer] + id layer = reinterpret_cast(objc_msgSend)(objc_getClass("CAMetalLayer"), + sel_getUid("layer")); + if (!layer) + { + ERROR_LOG(VIDEO, "Failed to create Metal layer."); + return; + } + + // [view setWantsLayer:YES] + reinterpret_cast(objc_msgSend)(view, sel_getUid("setWantsLayer:"), YES); + + // [view setLayer:layer] + reinterpret_cast(objc_msgSend)(view, sel_getUid("setLayer:"), layer); +#endif +} } // namespace Vulkan diff --git a/Source/Core/VideoCommon/DriverDetails.h b/Source/Core/VideoCommon/DriverDetails.h index 7d60b0e168..12f4c56225 100644 --- a/Source/Core/VideoCommon/DriverDetails.h +++ b/Source/Core/VideoCommon/DriverDetails.h @@ -49,19 +49,20 @@ enum Vendor enum Driver { DRIVER_ALL = 0, - DRIVER_NVIDIA, // Official Nvidia, including mobile GPU - DRIVER_NOUVEAU, // OSS nouveau - DRIVER_ATI, // Official ATI - DRIVER_R600, // OSS Radeon - DRIVER_INTEL, // Official Intel - DRIVER_I965, // OSS Intel - DRIVER_ARM, // Official Mali driver - DRIVER_LIMA, // OSS Mali driver - DRIVER_QUALCOMM, // Official Adreno driver - DRIVER_FREEDRENO, // OSS Adreno driver - DRIVER_IMGTEC, // Official PowerVR driver - DRIVER_VIVANTE, // Official Vivante driver - DRIVER_UNKNOWN // Unknown driver, default to official hardware driver + DRIVER_NVIDIA, // Official Nvidia, including mobile GPU + DRIVER_NOUVEAU, // OSS nouveau + DRIVER_ATI, // Official ATI + DRIVER_R600, // OSS Radeon + DRIVER_INTEL, // Official Intel + DRIVER_I965, // OSS Intel + DRIVER_ARM, // Official Mali driver + DRIVER_LIMA, // OSS Mali driver + DRIVER_QUALCOMM, // Official Adreno driver + DRIVER_FREEDRENO, // OSS Adreno driver + DRIVER_IMGTEC, // Official PowerVR driver + DRIVER_VIVANTE, // Official Vivante driver + DRIVER_PORTABILITY, // Vulkan via Metal on macOS + DRIVER_UNKNOWN // Unknown driver, default to official hardware driver }; enum class Family @@ -283,4 +284,4 @@ void Init(API api, Vendor vendor, Driver driver, const double version, const Fam // Once Vendor and driver version is set, this will return if it has the applicable bug passed to // it. bool HasBug(Bug bug); -} +} // namespace DriverDetails diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index 5271d31671..936dd8e937 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -448,7 +448,7 @@ void WritePixelShaderCommonHeader(ShaderCode& out, APIType ApiType, u32 num_texg if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) { out.Write("SSBO_BINDING(0) buffer BBox {\n" - "\tint4 bbox_data;\n" + "\tint bbox_left, bbox_right, bbox_top, bbox_bottom;\n" "};\n"); } else @@ -853,13 +853,21 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host if (uid_data->bounding_box) { - const char* atomic_op = - (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) ? "atomic" : "Interlocked"; - out.Write("\tif(bbox_data[0] > int(rawpos.x)) %sMin(bbox_data[0], int(rawpos.x));\n" - "\tif(bbox_data[1] < int(rawpos.x)) %sMax(bbox_data[1], int(rawpos.x));\n" - "\tif(bbox_data[2] > int(rawpos.y)) %sMin(bbox_data[2], int(rawpos.y));\n" - "\tif(bbox_data[3] < int(rawpos.y)) %sMax(bbox_data[3], int(rawpos.y));\n", - atomic_op, atomic_op, atomic_op, atomic_op); + if (ApiType == APIType::D3D) + { + out.Write( + "\tif(bbox_data[0] > int(rawpos.x)) InterlockedMin(bbox_data[0], int(rawpos.x));\n" + "\tif(bbox_data[1] < int(rawpos.x)) InterlockedMax(bbox_data[1], int(rawpos.x));\n" + "\tif(bbox_data[2] > int(rawpos.y)) InterlockedMin(bbox_data[2], int(rawpos.y));\n" + "\tif(bbox_data[3] < int(rawpos.y)) InterlockedMax(bbox_data[3], int(rawpos.y));\n"); + } + else + { + out.Write("\tif(bbox_left > int(rawpos.x)) atomicMin(bbox_left, int(rawpos.x));\n" + "\tif(bbox_right < int(rawpos.x)) atomicMax(bbox_right, int(rawpos.x));\n" + "\tif(bbox_top > int(rawpos.y)) atomicMin(bbox_top, int(rawpos.y));\n" + "\tif(bbox_bottom < int(rawpos.y)) atomicMax(bbox_bottom, int(rawpos.y));\n"); + } } out.Write("}\n"); diff --git a/Source/Core/VideoCommon/UberShaderPixel.cpp b/Source/Core/VideoCommon/UberShaderPixel.cpp index 6c5f6f84fe..4d66fac968 100644 --- a/Source/Core/VideoCommon/UberShaderPixel.cpp +++ b/Source/Core/VideoCommon/UberShaderPixel.cpp @@ -1239,17 +1239,23 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config, if (bounding_box) { - const char* atomic_op = - (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) ? "atomic" : "Interlocked"; out.Write(" if (bpmem_bounding_box) {\n"); - out.Write(" if(bbox_data[0] > int(rawpos.x)) %sMin(bbox_data[0], int(rawpos.x));\n", - atomic_op); - out.Write(" if(bbox_data[1] < int(rawpos.x)) %sMax(bbox_data[1], int(rawpos.x));\n", - atomic_op); - out.Write(" if(bbox_data[2] > int(rawpos.y)) %sMin(bbox_data[2], int(rawpos.y));\n", - atomic_op); - out.Write(" if(bbox_data[3] < int(rawpos.y)) %sMax(bbox_data[3], int(rawpos.y));\n", - atomic_op); + if (ApiType == APIType::D3D) + { + out.Write( + " if(bbox_data[0] > int(rawpos.x)) InterlockedMin(bbox_data[0], int(rawpos.x));\n" + " if(bbox_data[1] < int(rawpos.x)) InterlockedMax(bbox_data[1], int(rawpos.x));\n" + " if(bbox_data[2] > int(rawpos.y)) InterlockedMin(bbox_data[2], int(rawpos.y));\n" + " if(bbox_data[3] < int(rawpos.y)) InterlockedMax(bbox_data[3], int(rawpos.y));\n"); + } + else + { + out.Write("\tif(bbox_left > int(rawpos.x)) atomicMin(bbox_left, int(rawpos.x));\n" + "\tif(bbox_right < int(rawpos.x)) atomicMax(bbox_right, int(rawpos.x));\n" + "\tif(bbox_top > int(rawpos.y)) atomicMin(bbox_top, int(rawpos.y));\n" + "\tif(bbox_bottom < int(rawpos.y)) atomicMax(bbox_bottom, int(rawpos.y));\n"); + } + out.Write(" }\n"); } @@ -1414,4 +1420,4 @@ void EnumeratePixelShaderUids(const std::function& } } } -} +} // namespace UberShader diff --git a/Source/Core/VideoCommon/VideoBackendBase.cpp b/Source/Core/VideoCommon/VideoBackendBase.cpp index 725857a85d..fd6bbdfa2b 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.cpp +++ b/Source/Core/VideoCommon/VideoBackendBase.cpp @@ -25,9 +25,7 @@ #include "VideoBackends/Null/VideoBackend.h" #include "VideoBackends/OGL/VideoBackend.h" #include "VideoBackends/Software/VideoBackend.h" -#ifndef __APPLE__ #include "VideoBackends/Vulkan/VideoBackend.h" -#endif #include "VideoCommon/AsyncRequests.h" #include "VideoCommon/BPStructs.h" @@ -187,9 +185,7 @@ void VideoBackendBase::PopulateList() #ifdef _WIN32 g_available_video_backends.push_back(std::make_unique()); #endif -#ifndef __APPLE__ g_available_video_backends.push_back(std::make_unique()); -#endif g_available_video_backends.push_back(std::make_unique()); g_available_video_backends.push_back(std::make_unique()); diff --git a/Source/Core/VideoCommon/VideoBackendBase.h b/Source/Core/VideoCommon/VideoBackendBase.h index 83a74b0608..d1dada2247 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.h +++ b/Source/Core/VideoCommon/VideoBackendBase.h @@ -43,6 +43,10 @@ public: virtual std::string GetDisplayName() const { return GetName(); } virtual void InitBackendInfo() = 0; + // Prepares a native window for rendering. This is called on the main thread, or the + // thread which owns the window. + virtual void PrepareWindow(const WindowSystemInfo& wsi) {} + void Video_ExitLoop(); void Video_BeginField(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks);