From ce34349ffb633722cb6ff0dc19b2018885cf73f2 Mon Sep 17 00:00:00 2001 From: Ahmad Sayed Alsayed Ebrahim Date: Sat, 10 Oct 2026 17:05:04 +0300 Subject: [PATCH] feat(vkbridge): report VK_EXT_robustness2 on drivers without it (Mali r44) DXVK refuses to start without robustness2. GameNative's wrapper reports it on Mali r44 (robustBufferAccess2, robustImageAccess2, nullDescriptor) without enforcing it, and DXVK games run. Same here, as VKB_EMU_ROBUSTNESS2: the client advertises the extension and features, the server strips the feature struct and keeps robustBufferAccess on (VKBRIDGE_EMU_ROBUSTNESS2=0 disables). The host Mali imitation now hides robustness2 too; DXVK checker 10/10. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01S1U9H1evGNjHRQ3wRUdv5V --- app/src/main/cpp/vkbridge/server_emu.c | 15 ++++++++++++++- app/src/main/cpp/vkbridge/server_emu.h | 2 +- tools/vkbridge/client/emu.c | 12 ++++++++++++ tools/vkbridge/common/vkb_proto.h | 1 + tools/vkbridge/host/mali_env.sh | 6 +++--- 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/app/src/main/cpp/vkbridge/server_emu.c b/app/src/main/cpp/vkbridge/server_emu.c index 027019fec..072ed8a9d 100644 --- a/app/src/main/cpp/vkbridge/server_emu.c +++ b/app/src/main/cpp/vkbridge/server_emu.c @@ -33,13 +33,14 @@ uint32_t vkb_emu_detect(const vkb_dispatch *idt, VkPhysicalDevice pd, uint32_t * idt->vkEnumerateDeviceExtensionProperties(pd, NULL, &n, NULL); VkExtensionProperties *e = calloc(n ? n : 1, sizeof(*e)); idt->vkEnumerateDeviceExtensionProperties(pd, NULL, &n, e); - int divisor = 0, depth_clip = 0, maint5 = 0; + int divisor = 0, depth_clip = 0, maint5 = 0, robust2 = 0; for (uint32_t i = 0; i < n; i++) { if (!strcmp(e[i].extensionName, "VK_EXT_vertex_attribute_divisor") || !strcmp(e[i].extensionName, "VK_KHR_vertex_attribute_divisor")) divisor = 1; if (!strcmp(e[i].extensionName, "VK_EXT_depth_clip_enable")) depth_clip = 1; if (!strcmp(e[i].extensionName, "VK_KHR_maintenance5")) maint5 = 1; + if (!strcmp(e[i].extensionName, "VK_EXT_robustness2") || !strcmp(e[i].extensionName, "VK_KHR_robustness2")) robust2 = 1; } free(e); /* VKBRIDGE_FAKE_MISSING=bc,divisor,clip,cull,depthclip pretends the GPU lacks them (host tests). */ @@ -51,6 +52,7 @@ uint32_t vkb_emu_detect(const vkb_dispatch *idt, VkPhysicalDevice pd, uint32_t * if (token(fake, "cull")) f.shaderCullDistance = VK_FALSE; if (token(fake, "depthclip")) depth_clip = 0; if (token(fake, "maint5")) maint5 = 0; + if (token(fake, "robustness2")) robust2 = 0; } uint32_t emu = 0; VkPhysicalDeviceProperties props; @@ -63,6 +65,10 @@ uint32_t vkb_emu_detect(const vkb_dispatch *idt, VkPhysicalDevice pd, uint32_t * if (!f.shaderClipDistance && !env_off("VKBRIDGE_EMU_CLIP")) emu |= VKB_EMU_CLIP_DISTANCE; if (!f.shaderCullDistance && !env_off("VKBRIDGE_EMU_CULL")) emu |= VKB_EMU_CULL_DISTANCE; if (!depth_clip && f.depthClamp && !env_off("VKBRIDGE_EMU_DEPTHCLIP")) emu |= VKB_EMU_DEPTH_CLIP; + /* DXVK will not start without robustness2. Mali r44 lacks it; GameNative's wrapper reports it + * (robustBufferAccess2, robustImageAccess2, nullDescriptor) without enforcing it, and DXVK + * games run - out-of-bounds reads and null descriptors are then up to the driver. */ + if (!robust2 && f.robustBufferAccess && !env_off("VKBRIDGE_EMU_ROBUSTNESS2")) emu |= VKB_EMU_ROBUSTNESS2; /* PointSize in geometry/tessellation stages: stripped when the feature is missing. */ if (!f.shaderTessellationAndGeometryPointSize && (f.geometryShader || f.tessellationShader)) emu |= VKB_EMU_POINT_SIZE; uint32_t miss = 0; @@ -72,6 +78,7 @@ uint32_t vkb_emu_detect(const vkb_dispatch *idt, VkPhysicalDevice pd, uint32_t * if (!f.shaderCullDistance) miss |= VKB_EMU_CULL_DISTANCE; if (!depth_clip) miss |= VKB_EMU_DEPTH_CLIP; if (emu & VKB_EMU_MAINT5) miss |= VKB_EMU_MAINT5; + if (!robust2) miss |= VKB_EMU_ROBUSTNESS2; *missing = miss; return emu & VKB_EMU_IMPLEMENTED; } @@ -119,6 +126,12 @@ void vkb_emu_device_create_info(vkb_srv_table *inst, VkPhysicalDevice pd, uint32 if (emu & VKB_EMU_DIVISOR) chain_remove(ci, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT); if (emu & VKB_EMU_DEPTH_CLIP) chain_remove(ci, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT); if (emu & VKB_EMU_MAINT5) chain_remove(ci, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES); + if (emu & VKB_EMU_ROBUSTNESS2) { + chain_remove(ci, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT); + /* What robustness the GPU has stays on; robustBufferAccess2 asks for at least that. */ + VkPhysicalDeviceFeatures *rf = find_features(ci); + if (rf) rf->robustBufferAccess = VK_TRUE; + } } void vkb_emu_device_init(vkb_srv_table *dev, uint32_t emu) diff --git a/app/src/main/cpp/vkbridge/server_emu.h b/app/src/main/cpp/vkbridge/server_emu.h index 252ca24cb..ed079692e 100644 --- a/app/src/main/cpp/vkbridge/server_emu.h +++ b/app/src/main/cpp/vkbridge/server_emu.h @@ -6,7 +6,7 @@ /* Emulations that are implemented (the rest are never offered to the client). */ #define VKB_EMU_IMPLEMENTED (VKB_EMU_MAINT5 | VKB_EMU_CLIP_DISTANCE | VKB_EMU_CULL_DISTANCE | VKB_EMU_POINT_SIZE | VKB_EMU_BCN | \ - VKB_EMU_DIVISOR | VKB_EMU_DEPTH_CLIP) + VKB_EMU_DIVISOR | VKB_EMU_DEPTH_CLIP | VKB_EMU_ROBUSTNESS2) #define VKB_EMU_BUCKETS 1024 diff --git a/tools/vkbridge/client/emu.c b/tools/vkbridge/client/emu.c index 4a57eaa97..08918f280 100644 --- a/tools/vkbridge/client/emu.c +++ b/tools/vkbridge/client/emu.c @@ -23,6 +23,7 @@ const VkExtensionProperties *vkb_emu_extensions(vkb_physdev *pd, uint32_t *n) list[c++] = (VkExtensionProperties){"VK_KHR_vertex_attribute_divisor", 1}; } if (EMU(pd, VKB_EMU_DEPTH_CLIP)) list[c++] = (VkExtensionProperties){"VK_EXT_depth_clip_enable", 1}; + if (EMU(pd, VKB_EMU_ROBUSTNESS2)) list[c++] = (VkExtensionProperties){"VK_EXT_robustness2", 1}; *n = c; return list; } @@ -35,6 +36,11 @@ void vkb_emu_patch_limits(vkb_physdev *pd, VkPhysicalDeviceProperties *p) void vkb_emu_patch_properties_chain(vkb_physdev *pd, VkBaseOutStructure *b) { + if (EMU(pd, VKB_EMU_ROBUSTNESS2) && b->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT) { + VkPhysicalDeviceRobustness2PropertiesEXT *r = (void *)b; + r->robustStorageBufferAccessSizeAlignment = 4; + r->robustUniformBufferAccessSizeAlignment = 256; + } if (EMU(pd, VKB_EMU_DIVISOR)) { if (b->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT) ((VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *)b)->maxVertexAttribDivisor = UINT32_MAX; @@ -79,6 +85,12 @@ void vkb_emu_patch_features_chain(vkb_physdev *pd, VkBaseOutStructure *b) if (EMU(pd, VKB_EMU_DEPTH_CLIP)) d3->extendedDynamicState3DepthClampEnable = VK_FALSE; } break; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT: + if (EMU(pd, VKB_EMU_ROBUSTNESS2)) { + VkPhysicalDeviceRobustness2FeaturesEXT *r = (void *)b; + r->robustBufferAccess2 = r->robustImageAccess2 = r->nullDescriptor = VK_TRUE; + } + break; case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT: set_feature(pd, VKB_EMU_DEPTH_CLIP, &((VkPhysicalDeviceDepthClipEnableFeaturesEXT *)b)->depthClipEnable); break; diff --git a/tools/vkbridge/common/vkb_proto.h b/tools/vkbridge/common/vkb_proto.h index f8958785e..0291fe12c 100644 --- a/tools/vkbridge/common/vkb_proto.h +++ b/tools/vkbridge/common/vkb_proto.h @@ -37,6 +37,7 @@ static inline const char *vkb_mem_strategy_name(uint32_t s) #define VKB_EMU_POINT_SIZE (1u << 4) /* strip PointSize from geometry/tessellation stages */ #define VKB_EMU_DEPTH_CLIP (1u << 5) /* VK_EXT_depth_clip_enable via depthClamp */ #define VKB_EMU_MAINT5 (1u << 6) /* VK_KHR_maintenance5 on a driver without it */ +#define VKB_EMU_ROBUSTNESS2 (1u << 7) /* VK_EXT_robustness2 reported, not enforced (GameNative's r44 profile) */ /* vkbQueryServer reply (per physical device). */ typedef struct vkb_server_pd_info { diff --git a/tools/vkbridge/host/mali_env.sh b/tools/vkbridge/host/mali_env.sh index f73d857bb..bb68a34fa 100755 --- a/tools/vkbridge/host/mali_env.sh +++ b/tools/vkbridge/host/mali_env.sh @@ -1,15 +1,15 @@ #!/bin/bash # Source this: a host bridge server that behaves like the Mali-G720 driver as far as Phase 0 -# found (no BCn, clip/cull distance, vertex attribute divisor, maintenance5, push descriptors; Vulkan 1.3). +# found (no BCn, clip/cull distance, vertex attribute divisor, maintenance5, push descriptors, robustness2; Vulkan 1.3). _vkb_host=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) export VKBRIDGE_SOCKET=${XDG_RUNTIME_DIR:-/tmp}/vkbridge-host.sock pgrep -x vkbridge-server >/dev/null && kill $(pgrep -x vkbridge-server) 2>/dev/null; sleep 0.3 rm -f "$VKBRIDGE_SOCKET" -VKBRIDGE_FAKE_MISSING=${VKB_MISSING:-bc,clip,cull,divisor,maint5,depthclip,push} VK_DRIVER_FILES=${VKB_HOST_ICD:-/usr/share/vulkan/icd.d/radeon_icd.json} \ +VKBRIDGE_FAKE_MISSING=${VKB_MISSING:-bc,clip,cull,divisor,maint5,depthclip,push,robustness2} VK_DRIVER_FILES=${VKB_HOST_ICD:-/usr/share/vulkan/icd.d/radeon_icd.json} \ nohup "$_vkb_host/out/vkbridge-server" --socket "$VKBRIDGE_SOCKET" --log "$_vkb_host/out/server.log" >/dev/null 2>&1 & for _i in $(seq 50); do [ -S "$VKBRIDGE_SOCKET" ] && break; sleep 0.1; done chmod 666 "$VKBRIDGE_SOCKET" export VK_DRIVER_FILES=$_vkb_host/out/vkbridge_icd.json -export VKBRIDGE_HIDE_EXTS=VK_KHR_maintenance5,VK_KHR_push_descriptor,VK_EXT_vertex_attribute_divisor,VK_KHR_vertex_attribute_divisor,VK_EXT_depth_clip_enable +export VKBRIDGE_HIDE_EXTS=VK_KHR_maintenance5,VK_KHR_push_descriptor,VK_EXT_robustness2,VK_KHR_robustness2,VK_EXT_vertex_attribute_divisor,VK_KHR_vertex_attribute_divisor,VK_EXT_depth_clip_enable export VKBRIDGE_MAX_API=1.3 echo "vkbridge server up, imitating Mali's gaps"