Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions .github/workflows/build-proton.yml
Original file line number Diff line number Diff line change
Expand Up @@ -331,13 +331,23 @@ jobs:
Single SDK 28 build with 16KB page size support (works on Android 9+ and Android 15+).

### Features
- Experimental userspace ntsync (via [ntsync-android](https://github.com/GameNative/ntsync-android)) + fsync
- Experimental userspace ntsync (via [ntsync-android](https://github.com/GameNative/ntsync-android) V8, commit [`d00ac47`](https://github.com/GameNative/ntsync-android/commit/d00ac47491f2a5505d2ea3a2c8533f498a9811b0)) + fsync, with wineserver-side `ntsync_event_set` support
- `WINE_FAST_YIELD` fast-yield hook in `NtYieldExecution`
- FEX integration (stats shm, `SkipThreadAttach` detach guard) via bylaws' arm64ec patches
- FEX unixlib loader: `MemoryWineLoadUnixLibByName` / wow64 / unload support with `$PREFIX/lib/wine` fallback
- `WINEVMEMMAXSIZE` virtual-address cap for FEX environments
- Integrated lsteamclient built into Proton (supports GameNative bionic Steam)
- Stripped, `-g0 -O2` build: smaller tree, faster install (zstd-packed `.wcp`)

### Android / bionic fixes
- Anonymous PE-image mapping for bionic (vc4 devices); `LC_ALL=C.UTF-8` default; shell32 drive-root path fix
- Android clipboard bridge (user32/win32u) and Android URL/intent launching in winebrowser
- dnsapi libresolv bionic port; nsiproxy interface/route enumeration without netlink; ws2_32 socket tweaks
- winepulse audio period fix, MIDI mapper rework, SDL gamepad init fixes
- winex11 window/keyboard/mouse/GL/desktop tweaks; explorer desktop sizing; `GetUserNameA` on Android

### Credits
Compile optimizations (ccache, -g0/strip, zstd packaging) are adopted from [The412Banner/proton-wine](https://github.com/The412Banner/proton-wine) release [build-p11-20260821](https://github.com/The412Banner/proton-wine/releases/tag/build-p11-20260821).
Compile optimizations (ccache, -g0/strip, zstd packaging) and runtime improvements — `WINE_FAST_YIELD` fast-yield, FEX unixlib loader, `WINEVMEMMAXSIZE` VA cap, vc4 bionic fixes (anonymous PE mappings, `LC_ALL=C.UTF-8`, shell32 drive-root fix), and xrandr/xrender enablement — are adopted from [The412Banner/proton-wine](https://github.com/The412Banner/proton-wine) release [build-p11-20260821](https://github.com/The412Banner/proton-wine/releases/tag/build-p11-20260821) (merged in commit `b08376b`).

### WCP Files
**Proton Type:**
Expand Down
14 changes: 10 additions & 4 deletions android/ntsync_android/ntsync_user.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
* process that opens the same region path sees the same handles. Waits use
* futexes on the shared pages.
*
* Not implemented: alertable waits (ntsync_wait_args.alert must be 0).
* Alertable waits are supported: if ntsync_wait_args.alert is nonzero it
* names an event object that aborts the wait; the wait returns success with
* index == count, exactly like the kernel ioctls.
* Divergence from the kernel: closing an object other threads are waiting on
* fails those waits with -EINVAL; objects leaked by a crashed process must
* be reclaimed with ntsync_sweep_dead().
Expand Down Expand Up @@ -68,7 +70,8 @@ struct ntsync_wait_args {
uint32_t flags;
/* In: owner tid used to acquire mutexes. */
uint32_t owner;
/* Unsupported; must be 0. */
/* In: optional alert event handle (0 = none); aborts the wait, which
* then returns success with index == count. */
uint32_t alert;
uint32_t pad;
};
Expand All @@ -82,7 +85,8 @@ struct ntsync_wait_args {
#define NTSYNC_ANDROID_USED_BY_SERVER 0x7eadfe01

/* Initialize the shared region. `path` may be NULL to use
* $TMPDIR/ntsync_userspace.shm (the caller must export TMPDIR).
* $TMPDIR/ntsync_userspace.shm (the caller must export TMPDIR); a layout
* version is inserted before the ".shm" extension (ntsync_userspace.vN.shm).
* Idempotent; all other functions auto-initialize on first use. */
int32_t ntsync_init(const char *path);

Expand All @@ -91,7 +95,9 @@ int32_t ntsync_init(const char *path);
* process exits. Returns the number of freed objects or a negative errno. */
int32_t ntsync_sweep_dead(void);

/* Create objects. Return 0 and store the handle, or a negative errno. */
/* Create objects. Return 0 and store the handle, or a negative errno.
* Handles are never 0: slot 0 is permanently reserved because 0 is the
* "no alert" sentinel in ntsync_wait_args.alert. */
int32_t ntsync_create_sem(uint32_t *out_handle, const struct ntsync_sem_args *args);
int32_t ntsync_create_mutex(uint32_t *out_handle, const struct ntsync_mutex_args *args);
int32_t ntsync_create_event(uint32_t *out_handle, const struct ntsync_event_args *args);
Expand Down
131 changes: 126 additions & 5 deletions android/patches/arm64ec/dlls_ntdll_unix_loader_c.patch
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index f8aa468..35bc233 100644
index f8aa468..291bf9b 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -340,7 +340,11 @@ static const char *get_pe_dir( WORD machine )
Expand All @@ -15,21 +15,142 @@ index f8aa468..35bc233 100644
case IMAGE_FILE_MACHINE_ARMNT: return "/arm-windows";
case IMAGE_FILE_MACHINE_ARM64: return "/aarch64-windows";
default: return "";
@@ -2451,7 +2455,9 @@ static void start_main_thread(void)
@@ -362,6 +366,7 @@ static WORD get_alt_machine( WORD machine )
static void set_dll_path(void)
{
char *p, *path = getenv( "WINEDLLPATH" ), *be_runtime = getenv( "PROTON_BATTLEYE_RUNTIME" ), *eac_runtime = getenv( "PROTON_EAC_RUNTIME" );
+ char *prefix = getenv( "PREFIX" );
int i, count = 0;

if (path) for (p = path, count = 1; *p; p++) if (*p == ':') count++;
@@ -372,6 +377,9 @@ static void set_dll_path(void)
if (eac_runtime)
count += 2;

+ if (prefix && *prefix)
+ count += 1;
+
dll_paths = malloc( (count + 2) * sizeof(*dll_paths) );
count = 0;

@@ -420,6 +428,20 @@ static void set_dll_path(void)
dll_paths[count++] = p;
}

+ /* Winlator-bionic containers set PREFIX to the imagefs mount; components
+ * (e.g. a FEX-unix companion) drop their unixlibs under $PREFIX/lib/wine.
+ * Add it as the lowest-priority search dir so the builtin's own dir wins. */
+ if (prefix && *prefix)
+ {
+ const char suffix[] = "/lib/wine";
+
+ p = malloc( strlen(prefix) + strlen(suffix) + 1 );
+ strcpy(p, prefix);
+ strcat(p, suffix);
+
+ dll_paths[count++] = p;
+ }
+
for (i = 0; i < count; i++) dll_path_maxlen = max( dll_path_maxlen, strlen(dll_paths[i]) );
dll_paths[count] = NULL;
}
@@ -1785,6 +1807,81 @@ NTSTATUS load_builtin( const struct pe_image_info *image_info, UNICODE_STRING *n
}


+/***********************************************************************
+ * load_unixlib_by_name
+ */
+NTSTATUS load_unixlib_by_name( const UNICODE_STRING *nt_name, void **handle_ret )
+{
+ unsigned int i, pos, namepos, maxlen = 0;
+ unsigned int len = nt_name->Length / sizeof(WCHAR);
+ const char *so_dir = get_so_dir( current_machine );
+ char *ptr = NULL, *file, *ext = NULL;
+ void *handle = NULL;
+
+ if (!len) return STATUS_DLL_NOT_FOUND;
+
+ for (i = namepos = 0; i < len; i++)
+ if (nt_name->Buffer[i] == '/' || nt_name->Buffer[i] == '\\') break;
+
+ if (i < len) /* explicit path */
+ {
+ UNICODE_STRING true_nt_name;
+ OBJECT_ATTRIBUTES attr;
+
+ InitializeObjectAttributes( &attr, (UNICODE_STRING *)nt_name, 0, 0, NULL );
+ if (!get_nt_and_unix_names( &attr, &true_nt_name, &file, FILE_OPEN, FALSE ))
+ handle = dlopen( file, RTLD_NOW );
+ free( true_nt_name.Buffer );
+ goto done;
+ }
+
+ if (build_dir) maxlen = strlen(build_dir) + sizeof("/dlls/") + len;
+ maxlen = max( maxlen, dll_path_maxlen + 1 ) + len + sizeof("/aarch64-unix") + sizeof(".so");
+
+ if (!(file = malloc( maxlen ))) return STATUS_NO_MEMORY;
+
+ pos = maxlen - len - 4;
+ ext = file + pos + len;
+ /* we don't want to depend on the current codepage here */
+ for (i = 0; i < len; i++)
+ {
+ if (nt_name->Buffer[namepos + i] > 127) goto done;
+ file[pos + i] = (char)nt_name->Buffer[namepos + i];
+ if (file[pos + i] >= 'A' && file[pos + i] <= 'Z') file[pos + i] += 'a' - 'A';
+ else if (file[pos + i] == '.') ext = file + pos + i;
+ }
+ file[pos + len] = 0;
+ file[--pos] = '/';
+
+ if (build_dir)
+ {
+ ptr = prepend_build_dir_path( file + pos, ".so", "", "/dlls", build_dir );
+ strcpy( ext, ".so" );
+ if ((handle = dlopen( ptr, RTLD_NOW ))) goto done;
+ }
+
+ strcpy( ext, ".so" );
+ for (i = 0; dll_paths[i]; i++)
+ {
+ ptr = prepend( file + pos, so_dir, strlen(so_dir) );
+ ptr = prepend( ptr, dll_paths[i], strlen(dll_paths[i]) );
+ WARN_(module)( "load_unixlib_by_name: trying %s\n", ptr );
+ if ((handle = dlopen( ptr, RTLD_NOW ))) goto done;
+
+ ptr = prepend( file + pos, dll_paths[i], strlen(dll_paths[i]) );
+ WARN_(module)( "load_unixlib_by_name: trying %s\n", ptr );
+ if ((handle = dlopen( ptr, RTLD_NOW ))) goto done;
+ }
+ WARN_(module)( "load_unixlib_by_name: no unixlib found for %s\n", file + pos );
+
+ done:
+ free( file );
+ if (!handle) return STATUS_DLL_NOT_FOUND;
+ *handle_ret = handle;
+ return STATUS_SUCCESS;
+}
+
+
/***************************************************************************
* get_machine_wow64_dir
*
@@ -2451,7 +2548,9 @@ static void start_main_thread(void)
set_thread_teb( teb );
#endif

+#if defined(M_PERTURB)
+#ifndef __ANDROID__
mallopt( M_PERTURB, 0xff );
+#endif
init_startup_info();
*(ULONG_PTR *)&peb->CloudFileFlags = get_image_address();
set_load_order_app_name( main_wargv[0] );
@@ -2460,7 +2466,9 @@ static void start_main_thread(void)
@@ -2460,7 +2559,9 @@ static void start_main_thread(void)
load_ntdll();
load_wow64_ntdll( main_image_info.Machine );
load_apiset_dll();
+#if defined(M_PERTURB)
+#ifndef __ANDROID__
mallopt( M_PERTURB, 0 );
+#endif
server_init_process_done();
Expand Down
Loading
Loading