Skip to content

Commit 186549d

Browse files
Vulkan probe: fix mailbox false-positive, fix Adreno quirk over-matching, add Vk1.4/hostImageCopy/pushDescriptors detection, harmonize log tags
Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/39a59ff0-542b-46df-a078-ea21135c349b Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
1 parent 49fd43c commit 186549d

4 files changed

Lines changed: 75 additions & 17 deletions

File tree

osu.Android/AndroidNativeBridgeManager.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,19 @@ public void StartVulkanProbe()
190190
public string GetVulkanStatus()
191191
{
192192
if (vulkanProbe is not VulkanProbe probe) return string.Empty;
193-
return cachedVulkanStatus ??= $"{(probe.SupportsMailboxPresentMode ? "MAILBOX" : "FIFO")}{(probe.DisablePresentId ? " [NoID]" : "")}{(probe.DisablePresentWait ? " [NoWait]" : "")}{(probe.DisableGraphicsPipelineLibrary ? " [NoGPL]" : "")}";
193+
194+
if (cachedVulkanStatus != null)
195+
return cachedVulkanStatus;
196+
197+
int ver = probe.ApiVersion;
198+
int major = (ver >> 22) & 0x3FF;
199+
int minor = (ver >> 12) & 0x3FF;
200+
201+
cachedVulkanStatus = $"Vk{major}.{minor}"
202+
+ (probe.DisablePresentId ? " [NoID]" : "")
203+
+ (probe.DisablePresentWait ? " [NoWait]" : "")
204+
+ (probe.DisableGraphicsPipelineLibrary ? " [NoGPL]" : "");
205+
return cachedVulkanStatus;
194206
}
195207

196208
public void StopVulkanProbe()
@@ -211,10 +223,12 @@ private static void logVulkanInfo(VulkanProbe probe)
211223

212224
Debug.WriteLine($"[osu!] Vulkan GPU: {probe.DeviceLocalMemoryMB}MB, "
213225
+ $"API={major}.{minor}.{patch}, "
214-
+ $"mailbox={probe.SupportsMailboxPresentMode}, "
215226
+ $"vk1.3={probe.MeetsVulkan13}, "
227+
+ $"vk1.4={probe.MeetsVulkan14}, "
216228
+ $"gpl={probe.SupportsGraphicsPipelineLibrary}, "
217-
+ $"shaderObj={probe.SupportsShaderObject}");
229+
+ $"shaderObj={probe.SupportsShaderObject}, "
230+
+ $"hostCopy={probe.SupportsHostImageCopy}, "
231+
+ $"pushDesc={probe.SupportsPushDescriptors}");
218232
}
219233

220234
[MethodImpl(MethodImplOptions.NoInlining)]

osu.Android/Native/VulkanProbe.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ static VulkanProbe()
6868
public bool SupportsGlobalPriority => !disposed && nativePtr != IntPtr.Zero && nVulkanSupportsGlobalPriority(nativePtr) != 0;
6969
public bool SupportsMemoryBudget => !disposed && nativePtr != IntPtr.Zero && nVulkanSupportsMemoryBudget(nativePtr) != 0;
7070
public bool SupportsSurfaceMaintenance1 => !disposed && nativePtr != IntPtr.Zero && nVulkanSupportsSurfaceMaintenance1(nativePtr) != 0;
71+
public bool MeetsVulkan14 => !disposed && nativePtr != IntPtr.Zero && nVulkanMeetsVulkan14(nativePtr) != 0;
72+
public bool SupportsHostImageCopy => !disposed && nativePtr != IntPtr.Zero && nVulkanSupportsHostImageCopy(nativePtr) != 0;
73+
public bool SupportsPushDescriptors => !disposed && nativePtr != IntPtr.Zero && nVulkanSupportsPushDescriptors(nativePtr) != 0;
7174

7275
public bool DisablePresentId => !disposed && nativePtr != IntPtr.Zero && nVulkanDisablePresentId(nativePtr) != 0;
7376
public bool DisablePresentWait => !disposed && nativePtr != IntPtr.Zero && nVulkanDisablePresentWait(nativePtr) != 0;
@@ -108,5 +111,8 @@ public void Dispose()
108111
[DllImport(lib_name)] private static extern byte nVulkanDisablePresentId(IntPtr ptr);
109112
[DllImport(lib_name)] private static extern byte nVulkanDisablePresentWait(IntPtr ptr);
110113
[DllImport(lib_name)] private static extern byte nVulkanDisableGraphicsPipelineLibrary(IntPtr ptr);
114+
[DllImport(lib_name)] private static extern byte nVulkanMeetsVulkan14(IntPtr ptr);
115+
[DllImport(lib_name)] private static extern byte nVulkanSupportsHostImageCopy(IntPtr ptr);
116+
[DllImport(lib_name)] private static extern byte nVulkanSupportsPushDescriptors(IntPtr ptr);
111117
}
112118
}

osu.Android/Native/vulkan_bridge.cpp

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include <cstring>
88
#include <new>
99

10-
#define LOG_TAG "osu_native"
10+
#define LOG_TAG "osu!native"
1111
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
1212
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
1313

@@ -26,7 +26,8 @@ VulkanProbe::VulkanProbe() {
2626
available_ = true;
2727

2828
LOGI("Vulkan available: %s (Vendor: 0x%x, API %u.%u.%u, driver %u, VRAM %u MB, "
29-
"qCount %u, mailbox %d, vk1.3 %d, sync2 %d, pWait %d, gpl %d, sObj %d, gPrio %d)",
29+
"qCount %u, vk1.3 %d, vk1.4 %d, sync2 %d, pWait %d, gpl %d, sObj %d, gPrio %d, "
30+
"hostCopy %d, pushDesc %d)",
3031
deviceInfo_.deviceName.c_str(),
3132
deviceInfo_.vendorId,
3233
VK_VERSION_MAJOR(deviceInfo_.apiVersion),
@@ -35,13 +36,15 @@ VulkanProbe::VulkanProbe() {
3536
deviceInfo_.driverVersion,
3637
deviceInfo_.deviceLocalMemoryMB,
3738
deviceInfo_.queueFamilyCount,
38-
deviceInfo_.supportsMailboxPresentMode ? 1 : 0,
3939
deviceInfo_.meetsVulkan13 ? 1 : 0,
40+
deviceInfo_.meetsVulkan14 ? 1 : 0,
4041
deviceInfo_.supportsSynchronization2 ? 1 : 0,
4142
deviceInfo_.supportsPresentWait ? 1 : 0,
4243
deviceInfo_.supportsGraphicsPipelineLibrary ? 1 : 0,
4344
deviceInfo_.supportsShaderObject ? 1 : 0,
44-
deviceInfo_.supportsGlobalPriority ? 1 : 0);
45+
deviceInfo_.supportsGlobalPriority ? 1 : 0,
46+
deviceInfo_.supportsHostImageCopy ? 1 : 0,
47+
deviceInfo_.supportsPushDescriptors ? 1 : 0);
4548
}
4649

4750
VulkanProbe::~VulkanProbe() {
@@ -99,8 +102,15 @@ bool VulkanProbe::queryDevice() {
99102

100103
queryMemory(selected);
101104
queryQueueFamilies(selected);
102-
queryVulkan13Features(selected);
105+
// Query extensions first (sets extension-based feature flags for pre-1.3 devices).
103106
queryModernExtensions(selected);
107+
// Feature queries for 1.3+ override extension-based values with actual feature support.
108+
queryVulkan13Features(selected);
109+
110+
// MAILBOX present mode cannot be queried without a VkSurfaceKHR (we have none in
111+
// this lightweight probe). The actual present mode is selected by the renderer
112+
// (Veldrid) at swapchain creation time via vkGetPhysicalDeviceSurfacePresentModesKHR.
113+
// We leave supportsMailboxPresentMode = false (default) to avoid false positives.
104114

105115
return true;
106116
}
@@ -137,26 +147,40 @@ void VulkanProbe::queryModernExtensions(VkPhysicalDevice device) {
137147
std::vector<VkExtensionProperties> exts(count);
138148
vkEnumerateDeviceExtensionProperties(device, nullptr, &count, exts.data());
139149
for (const auto& ext : exts) {
140-
if (strcmp(ext.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) { deviceInfo_.supportsSwapchain = true; deviceInfo_.supportsMailboxPresentMode = true; }
150+
if (strcmp(ext.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) deviceInfo_.supportsSwapchain = true;
141151
if (strcmp(ext.extensionName, VK_KHR_PRESENT_ID_EXTENSION_NAME) == 0) deviceInfo_.supportsPresentId = true;
142152
if (strcmp(ext.extensionName, VK_KHR_PRESENT_WAIT_EXTENSION_NAME) == 0) deviceInfo_.supportsPresentWait = true;
143153
if (strcmp(ext.extensionName, VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME) == 0) deviceInfo_.supportsGraphicsPipelineLibrary = true;
144154
if (strcmp(ext.extensionName, VK_EXT_SHADER_OBJECT_EXTENSION_NAME) == 0) deviceInfo_.supportsShaderObject = true;
145155
if (strcmp(ext.extensionName, VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME) == 0 || strcmp(ext.extensionName, VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME) == 0) deviceInfo_.supportsGlobalPriority = true;
146156
if (strcmp(ext.extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0) deviceInfo_.supportsMemoryBudget = true;
147157
if (strcmp(ext.extensionName, "VK_EXT_surface_maintenance1") == 0) deviceInfo_.supportsSurfaceMaintenance1 = true;
158+
159+
// Extension-based fallback for pre-1.3 devices (overridden by queryVulkan13Features on 1.3+).
160+
if (strcmp(ext.extensionName, "VK_KHR_dynamic_rendering") == 0) deviceInfo_.supportsDynamicRendering = true;
161+
if (strcmp(ext.extensionName, "VK_KHR_synchronization2") == 0) deviceInfo_.supportsSynchronization2 = true;
162+
163+
// Vulkan 1.4+ / Android 16+ extensions — used by string literals since NDK r29
164+
// headers may not define these macros.
165+
if (strcmp(ext.extensionName, "VK_EXT_host_image_copy") == 0) deviceInfo_.supportsHostImageCopy = true;
166+
if (strcmp(ext.extensionName, "VK_KHR_push_descriptor") == 0) deviceInfo_.supportsPushDescriptors = true;
148167
}
149168

150169
// ── Vendor-specific GPU quirks ──────────────────────────────────────
151170
// Qualcomm Adreno 7xx series: known flickering with PresentId/PresentWait
152171
// and broken Graphics Pipeline Library compilation on some driver versions.
153-
if (deviceInfo_.vendorId == 0x5143 && (deviceInfo_.deviceName.find("740") != std::string::npos ||
154-
deviceInfo_.deviceName.find("750") != std::string::npos ||
155-
deviceInfo_.deviceName.find("Adreno") != std::string::npos)) {
156-
LOGI("Adreno 7xx GPU detected: applying performance and flickering overrides");
157-
deviceInfo_.disablePresentId = true;
158-
deviceInfo_.disablePresentWait = true;
159-
deviceInfo_.disableGraphicsPipelineLibrary = true;
172+
// Only target 7xx (730/740/750) — other Adreno generations are unaffected.
173+
if (deviceInfo_.vendorId == 0x5143) {
174+
const auto& name = deviceInfo_.deviceName;
175+
bool isAdreno7xx = name.find("730") != std::string::npos ||
176+
name.find("740") != std::string::npos ||
177+
name.find("750") != std::string::npos;
178+
if (isAdreno7xx) {
179+
LOGI("Adreno 7xx GPU detected: applying performance and flickering overrides");
180+
deviceInfo_.disablePresentId = true;
181+
deviceInfo_.disablePresentWait = true;
182+
deviceInfo_.disableGraphicsPipelineLibrary = true;
183+
}
160184
}
161185

162186
// ARM Mali (Samsung Exynos, MediaTek Dimensity, Google Tensor):
@@ -184,12 +208,18 @@ void VulkanProbe::queryModernExtensions(VkPhysicalDevice device) {
184208
void VulkanProbe::queryVulkan13Features(VkPhysicalDevice device) {
185209
if (VK_VERSION_MAJOR(deviceInfo_.apiVersion) < 1 || (VK_VERSION_MAJOR(deviceInfo_.apiVersion) == 1 && VK_VERSION_MINOR(deviceInfo_.apiVersion) < 3)) return;
186210
deviceInfo_.meetsVulkan13 = true;
211+
212+
// Vulkan 1.4 is just a version check — no NDK header support needed.
213+
if (VK_VERSION_MINOR(deviceInfo_.apiVersion) >= 4)
214+
deviceInfo_.meetsVulkan14 = true;
215+
187216
VkPhysicalDeviceVulkan13Features f13{};
188217
f13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
189218
VkPhysicalDeviceFeatures2 f2{};
190219
f2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
191220
f2.pNext = &f13;
192221
vkGetPhysicalDeviceFeatures2(device, &f2);
222+
// Override extension-based flags with accurate feature queries for 1.3+ devices.
193223
deviceInfo_.supportsDynamicRendering = f13.dynamicRendering == VK_TRUE;
194224
deviceInfo_.supportsSynchronization2 = f13.synchronization2 == VK_TRUE;
195225
}
@@ -227,4 +257,7 @@ OSU_EXPORT byte nVulkanSupportsSurfaceMaintenance1(intptr_t ptr) { return (ptr &
227257
OSU_EXPORT byte nVulkanDisablePresentId(intptr_t ptr) { return (ptr && reinterpret_cast<VulkanProbe*>(ptr)->getDeviceInfo().disablePresentId) ? 1 : 0; }
228258
OSU_EXPORT byte nVulkanDisablePresentWait(intptr_t ptr) { return (ptr && reinterpret_cast<VulkanProbe*>(ptr)->getDeviceInfo().disablePresentWait) ? 1 : 0; }
229259
OSU_EXPORT byte nVulkanDisableGraphicsPipelineLibrary(intptr_t ptr) { return (ptr && reinterpret_cast<VulkanProbe*>(ptr)->getDeviceInfo().disableGraphicsPipelineLibrary) ? 1 : 0; }
260+
OSU_EXPORT byte nVulkanMeetsVulkan14(intptr_t ptr) { return (ptr && reinterpret_cast<VulkanProbe*>(ptr)->getDeviceInfo().meetsVulkan14) ? 1 : 0; }
261+
OSU_EXPORT byte nVulkanSupportsHostImageCopy(intptr_t ptr) { return (ptr && reinterpret_cast<VulkanProbe*>(ptr)->getDeviceInfo().supportsHostImageCopy) ? 1 : 0; }
262+
OSU_EXPORT byte nVulkanSupportsPushDescriptors(intptr_t ptr) { return (ptr && reinterpret_cast<VulkanProbe*>(ptr)->getDeviceInfo().supportsPushDescriptors) ? 1 : 0; }
230263
}

osu.Android/Native/vulkan_bridge.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class VulkanProbe {
2929
bool supportsDynamicRendering = false;
3030
bool supportsSynchronization2 = false;
3131

32-
// API 31+ / Modern High-Performance Extensions
32+
// Modern High-Performance Extensions
3333
bool supportsPresentId = false;
3434
bool supportsPresentWait = false;
3535
bool supportsGraphicsPipelineLibrary = false;
@@ -38,6 +38,11 @@ class VulkanProbe {
3838
bool supportsMemoryBudget = false;
3939
bool supportsSurfaceMaintenance1 = false;
4040

41+
// Vulkan 1.4+ / Android 16+ features
42+
bool meetsVulkan14 = false;
43+
bool supportsHostImageCopy = false;
44+
bool supportsPushDescriptors = false;
45+
4146
// Quirks / Blacklist flags
4247
bool disablePresentId = false;
4348
bool disablePresentWait = false;

0 commit comments

Comments
 (0)