From 487ea5ab36120130ec2e43a458780df4deea963b Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 7 Nov 2018 05:10:51 -0800 Subject: [PATCH 1/6] VideoBackend: Add a virtual PrepareWindow function Executes backend-specific commands on the main thread. --- Source/Core/Core/Core.cpp | 3 +++ Source/Core/VideoCommon/VideoBackendBase.h | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index c64eb1e22e..91f1200f73 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/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); From a1b9a9f519100ae9b235c9e507dd76d7c99d7ed7 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Fri, 3 Aug 2018 08:00:04 -0700 Subject: [PATCH 2/6] DolphinQt: Add backend multithreading to graphics config --- .../DolphinQt/Config/Graphics/AdvancedWidget.cpp | 12 ++++++++++-- .../Core/DolphinQt/Config/Graphics/AdvancedWidget.h | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) 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; }; From 041b977523e203c26c139ae4bdfa31a113072cd0 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 31 May 2018 04:22:20 -0700 Subject: [PATCH 3/6] Common: Use GCD semaphores on macOS Unnamed semaphores are not supported. --- Source/Core/Common/Semaphore.h | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) 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 From c7a2b1572bba57d78bea78455f9cd1ab95cd36db Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 31 May 2018 04:23:07 -0700 Subject: [PATCH 4/6] CMake: Build Vulkan backend on macOS --- Source/Core/Core/CMakeLists.txt | 5 +---- Source/Core/VideoBackends/CMakeLists.txt | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 003f2122ec..658754b097 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/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() From 673f1963a068fb7d5cd8af9bb209c7633950e8f8 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 31 May 2018 04:23:45 -0700 Subject: [PATCH 5/6] Vulkan: Support macOS via MoltenVK The path to the MoltenVK library can be specified by the LIBMOLTENVK_PATH environment variable, otherwise it assumes it is located in the application bundle's Contents/MacOS directory. --- .../Core/VideoBackends/Vulkan/SwapChain.cpp | 13 ++++++++ .../Core/VideoBackends/Vulkan/VideoBackend.h | 1 + .../VideoBackends/Vulkan/VulkanContext.cpp | 10 ++++++ .../Vulkan/VulkanEntryPoints.inl | 10 ++++-- .../VideoBackends/Vulkan/VulkanLoader.cpp | 23 +++++++++++-- .../Core/VideoBackends/Vulkan/VulkanLoader.h | 2 ++ Source/Core/VideoBackends/Vulkan/main.cpp | 33 +++++++++++++++++++ Source/Core/VideoCommon/DriverDetails.h | 29 ++++++++-------- Source/Core/VideoCommon/VideoBackendBase.cpp | 4 --- 9 files changed, 101 insertions(+), 24 deletions(-) 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/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()); From 0c0d66809d9c029c0468982725ab63be48500081 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 29 Aug 2018 03:00:08 -0700 Subject: [PATCH 6/6] PixelShaderGen: Split bbox into seperate variables The Metal shader compiler fails to compile the atomic instructions when operating on individual components of a vector. Spltting it into four variables shouldn't make any difference for other platforms, as they are accessed independently. --- Source/Core/VideoCommon/PixelShaderGen.cpp | 24 ++++++++++++------ Source/Core/VideoCommon/UberShaderPixel.cpp | 28 +++++++++++++-------- 2 files changed, 33 insertions(+), 19 deletions(-) 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