mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-10-14 19:27:09 -04:00
Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42e8bc3f78 | ||
|
|
ffb4477514 | ||
|
|
6448352dc8 | ||
|
|
e427c087b1 | ||
|
|
b0b5f78d5d | ||
|
|
feb1fb1faa | ||
|
|
dcd2641a90 | ||
|
|
2ece5b7314 | ||
|
|
423c5388ee | ||
|
|
5f3112fb4b |
No files matched your search
@@ -0,0 +1,3 @@
|
||||
# Patch context includes the indentation and blank lines of the source being patched.
|
||||
tools/gamescope/patches/*.patch -whitespace
|
||||
tools/panvk/patches/*.patch -whitespace
|
||||
@@ -18,6 +18,7 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
@@ -190,7 +191,13 @@ jobs:
|
||||
done
|
||||
if [ -f tools/gamescope/release.env ]; then
|
||||
. tools/gamescope/release.env
|
||||
gh release download "${GAMESCOPE_TAG}" -R "${GITHUB_REPOSITORY}" -p gamescope.tzst -O gamescope.tzst
|
||||
if [ -n "${GAMESCOPE_ARTIFACT_RUN:-}" ]; then
|
||||
gh run download "${GAMESCOPE_ARTIFACT_RUN}" -R "${GITHUB_REPOSITORY}" -n gamescope-patched -D gamescope-artifact
|
||||
mv gamescope-artifact/gamescope.tzst gamescope.tzst
|
||||
rm -r gamescope-artifact
|
||||
else
|
||||
gh release download "${GAMESCOPE_TAG}" -R "${GITHUB_REPOSITORY}" -p gamescope.tzst -O gamescope.tzst
|
||||
fi
|
||||
echo "${GAMESCOPE_SHA256} gamescope.tzst" | sha256sum -c -
|
||||
tar --use-compress-program=unzstd -xf gamescope.tzst -C "$D"
|
||||
test -f "$D/usr/local/bin/gamescope"
|
||||
|
||||
@@ -3478,7 +3478,8 @@ int banner_wayland_run(void) {
|
||||
/* libdecor binds wl_output at 4; a lower version is a protocol error for the client. */
|
||||
wl_global_create(display, &wl_output_interface, 4, NULL, bind_output);
|
||||
wl_global_create(display, &xdg_wm_base_interface, 1, NULL, bind_xdg_wm_base);
|
||||
wl_global_create(display, &zwp_linux_dmabuf_v1_interface, 4, NULL, bind_dmabuf);
|
||||
if (vkp_dmabuf_supported())
|
||||
wl_global_create(display, &zwp_linux_dmabuf_v1_interface, 4, NULL, bind_dmabuf);
|
||||
/* gamescope's Wayland backend refuses a seat older than 8. */
|
||||
wl_global_create(display, &wl_seat_interface, 9, NULL, bind_seat);
|
||||
wl_global_create(display, &banner_desktop_v1_interface, 1, NULL, bind_desktop);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#define VK_USE_PLATFORM_ANDROID_KHR
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#define VK_GLOBAL_FUNCS(X) X(CreateInstance) X(EnumerateInstanceExtensionProperties)
|
||||
#define VK_GLOBAL_FUNCS(X) X(CreateInstance) X(EnumerateInstanceExtensionProperties) X(EnumerateInstanceVersion)
|
||||
|
||||
#define VK_INSTANCE_FUNCS(X) \
|
||||
X(EnumeratePhysicalDevices) X(GetPhysicalDeviceProperties) \
|
||||
|
||||
@@ -40,6 +40,7 @@ struct vkp_image {
|
||||
static ANativeWindow *g_window; /* the window frames go to; compositor thread only */
|
||||
static char *g_driver_path, *g_library_name, *g_native_lib_dir;
|
||||
static int g_dev_state; /* 0 = not yet, 1 = ok, -1 = failed, -2 = lost (VK_ERROR_DEVICE_LOST) */
|
||||
static int g_dmabuf_import;
|
||||
static VkInstance g_inst;
|
||||
static VkPhysicalDevice g_pd;
|
||||
static VkDevice g_dev;
|
||||
@@ -411,11 +412,13 @@ static int dev_init(void) {
|
||||
"generation %s)", g_colorspace_ext ? "enables" : "has no",
|
||||
g_colorspace_ext ? "is possible where the screen surface offers one" : "is not possible: tone-mapped instead");
|
||||
}
|
||||
/* 1.3 like the X11 renderer's instance: the frame-generation probe (framegen_engine.cpp)
|
||||
* queries VkPhysicalDeviceVulkan12Features, and a 1.1 instance may be answered as 1.1. */
|
||||
/* Prefer 1.3 for the frame-generation feature probe, but respect older system loaders. */
|
||||
uint32_t loader_api = VK_API_VERSION_1_0;
|
||||
if (g_vk.EnumerateInstanceVersion)
|
||||
g_vk.EnumerateInstanceVersion(&loader_api);
|
||||
VkApplicationInfo app = {.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
.pApplicationName = "banner-wayland-present",
|
||||
.apiVersion = VK_API_VERSION_1_3};
|
||||
.apiVersion = loader_api < VK_API_VERSION_1_3 ? loader_api : VK_API_VERSION_1_3};
|
||||
VkInstanceCreateInfo ici = {.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
.pApplicationInfo = &app,
|
||||
.enabledExtensionCount = n_inst_exts,
|
||||
@@ -450,18 +453,25 @@ static int dev_init(void) {
|
||||
}
|
||||
g_vk.GetPhysicalDeviceMemoryProperties(g_pd, &g_memprops);
|
||||
|
||||
/* Verify the dmabuf-import extensions are present, and log any that are missing. */
|
||||
const char *dev_exts[7] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME, "VK_KHR_external_memory_fd",
|
||||
"VK_EXT_external_memory_dma_buf", "VK_EXT_image_drm_format_modifier",
|
||||
"VK_KHR_image_format_list", NULL, NULL};
|
||||
uint32_t n_dev_exts = 5;
|
||||
/* Shared-memory clients need only a swapchain. Advertise dma-buf import only when its
|
||||
* complete extension set is available, rather than failing device creation on older GPUs. */
|
||||
const char *import_exts[] = {"VK_KHR_external_memory_fd", "VK_EXT_external_memory_dma_buf",
|
||||
"VK_EXT_image_drm_format_modifier", "VK_KHR_image_format_list"};
|
||||
const char *dev_exts[7] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
|
||||
uint32_t n_dev_exts = 1;
|
||||
uint32_t ne = 0;
|
||||
g_vk.EnumerateDeviceExtensionProperties(g_pd, NULL, &ne, NULL);
|
||||
VkExtensionProperties *exts = calloc(ne ? ne : 1, sizeof(*exts));
|
||||
g_vk.EnumerateDeviceExtensionProperties(g_pd, NULL, &ne, exts);
|
||||
for (unsigned i = 0; i < 5; i++)
|
||||
if (!has_ext(exts, ne, dev_exts[i]))
|
||||
LOGE("present: driver MISSING %s (dmabuf import will fail)", dev_exts[i]);
|
||||
g_dmabuf_import = 1;
|
||||
for (unsigned i = 0; i < sizeof(import_exts) / sizeof(import_exts[0]); i++) {
|
||||
if (has_ext(exts, ne, import_exts[i]))
|
||||
dev_exts[n_dev_exts++] = import_exts[i];
|
||||
else {
|
||||
g_dmabuf_import = 0;
|
||||
banner_log("gpu", "driver has no %s; shared-memory clients remain available", import_exts[i]);
|
||||
}
|
||||
}
|
||||
/* HDR sessions only: the HDR10 swapchain (frame generation) can carry the game's metadata. */
|
||||
int want_hdr_md = 0;
|
||||
if (banner_color_requested()) {
|
||||
@@ -538,6 +548,7 @@ static int dev_init(void) {
|
||||
}
|
||||
|
||||
int vkp_ready(void) { return dev_init(); }
|
||||
int vkp_dmabuf_supported(void) { return dev_init() == 0 && g_dmabuf_import; }
|
||||
|
||||
static int swap_init_locked(void);
|
||||
|
||||
@@ -899,7 +910,7 @@ static int modifier_importable(VkFormat fmt, uint64_t modifier, VkImageUsageFlag
|
||||
}
|
||||
|
||||
int vkp_dmabuf_modifiers(uint32_t drm_format, uint64_t *out, int max) {
|
||||
if (max <= 0 || dev_init() != 0 || !g_vk.GetPhysicalDeviceFormatProperties2) return 0;
|
||||
if (max <= 0 || !vkp_dmabuf_supported() || !g_vk.GetPhysicalDeviceFormatProperties2) return 0;
|
||||
VkFormat fmt = drm_to_vk(drm_format);
|
||||
VkDrmFormatModifierPropertiesListEXT list = {
|
||||
.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT};
|
||||
@@ -941,7 +952,7 @@ int vkp_image_is_dmabuf(const struct vkp_image *img) { return img && img->dmabuf
|
||||
struct vkp_image *vkp_image_import_dmabuf(int fd, uint32_t drm_format, uint64_t modifier, int w, int h,
|
||||
uint32_t stride, uint32_t offset, int as_blit_dst) {
|
||||
if (modifier == MOD_INVALID || w <= 0 || h <= 0) return NULL;
|
||||
if (dev_init() != 0) return NULL;
|
||||
if (!vkp_dmabuf_supported()) return NULL;
|
||||
|
||||
struct vkp_image *img = calloc(1, sizeof(*img));
|
||||
if (!img) return NULL;
|
||||
|
||||
@@ -87,6 +87,8 @@ const char *vkp_gpu_name(void);
|
||||
|
||||
// 0 if the renderer can create images (device up), -1 otherwise.
|
||||
int vkp_ready(void);
|
||||
/* Whether the selected driver supports the complete dma-buf import extension set. */
|
||||
int vkp_dmabuf_supported(void);
|
||||
/* Whether an output window is attached (or requested); without one vkp_render() draws nothing. */
|
||||
int vkp_has_window(void);
|
||||
/* 1 once the Vulkan device was lost: nothing is presented any more (the session must restart). */
|
||||
|
||||
@@ -337,6 +337,10 @@ public final class TurnipDriver {
|
||||
if (forced.startsWith("a8")) return DRIVER_A8XX;
|
||||
if (forced.startsWith("a7")) return DRIVER_A7XX;
|
||||
}
|
||||
if (!com.droiddeck.launcher.core.DeviceSupport.INSTANCE.adreno()) {
|
||||
Log.i(TAG, "non-Adreno GPU: using system Vulkan for the compositor");
|
||||
return null;
|
||||
}
|
||||
String model = gpuModel();
|
||||
Log.i(TAG, "gpu model: " + (model == null ? "unknown" : model));
|
||||
if (model != null) {
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# Mali software Steam experiment
|
||||
|
||||
This branch adds an opt-in CPU rendering path for Steam and Gamescope. Android's compositor selects system Vulkan automatically on non-Adreno hardware; explicit custom driver choices are retained. Linux uses Lavapipe for Gamescope and llvmpipe/software SDL for Steam. This is a UI compatibility fallback, not proof of accelerated game support.
|
||||
|
||||
Set `/sdcard/Download/droiddeck-env` to:
|
||||
|
||||
```sh
|
||||
BL_STEAM_SOFTWARE=1
|
||||
```
|
||||
|
||||
Launch **Steam → Play Steam**. The session selects Gamescope's SDL Wayland Vulkan swapchain, which can present Lavapipe frames through `wl_shm`. Gamescope's native Wayland backend requires exportable dma-bufs even for its blank texture. The new patch keeps locally sampled textures, including cursors and shared-memory client frames, private on swapchain backends and makes `VK_KHR_present_id`/`VK_KHR_present_wait` optional, using the existing timer pacing when they are unavailable. Drivers that support both features retain the present-wait thread. Shared-memory pixels are uploaded on every commit because clients reuse their buffers; the private textures are marked ready after the synchronous copy, avoiding an invalid dma-buf fence lookup.
|
||||
|
||||
Steam's embedded browser disables GPU rendering, and the native client uses the SDL software renderer and X11. The performance overlay is disabled in this mode.
|
||||
|
||||
## Building this branch
|
||||
|
||||
This experimental branch pins native CI run [37146942306](https://github.com/Droid-Deck/DroidDeck/actions/runs/37146942306) and its bundle checksum in `tools/gamescope/release.env`. Both the APK workflow and ordinary local build fetch and verify that artifact. No component release is published.
|
||||
|
||||
```sh
|
||||
DROIDDECK_BUILD_VARIANT=debug tools/build_local.sh
|
||||
```
|
||||
|
||||
To test a different successful native build, download its **gamescope-patched** artifact and verify the accompanying checksum:
|
||||
|
||||
```sh
|
||||
gh run download <run-id> -R Droid-Deck/DroidDeck -n gamescope-patched -D /tmp/mali-gamescope
|
||||
(cd /tmp/mali-gamescope && shasum -a 256 -c gamescope.tzst.sha256)
|
||||
DROIDDECK_GAMESCOPE_BUNDLE=/tmp/mali-gamescope/gamescope.tzst \
|
||||
DROIDDECK_BUILD_VARIANT=debug tools/build_local.sh
|
||||
```
|
||||
|
||||
`DROIDDECK_GAMESCOPE_BUNDLE` overrides the pin for that local build. Before shipping, publish the native component and replace the temporary artifact pin with its release tag and checksum. CI artifacts have limited retention; this branch is an experiment, not a permanent release source.
|
||||
|
||||
The desktop path can also use the software Steam settings. On the tested G52 device, its labwc renderer requires `/sdcard/Download/droiddeck-wlr-renderer` containing `pixman`. Add `BL_DESKTOP_STEAM=1` only to start Steam automatically on the desktop.
|
||||
|
||||
## Device validation
|
||||
|
||||
Validated 2026-10-03 on the wired Unisoc T618 / Mali-G52 MC2 device (`RGB05001607258`, Android 12, kernel 5.4, 4 KiB pages). **Steam → Play Steam reaches the Big Picture QR sign-in screen inside Gamescope with only `BL_STEAM_SOFTWARE=1`.** The selected Deck mode was retained: the client command includes `-gamepadui -steamdeck -steamos3`. A test string was entered and cleared in the account field without submitting it; no account was signed in during that initial test. The desktop and desktop Steam QR screen also worked in the earlier test.
|
||||
|
||||
- Native bundle SHA-256: `22df550d60fcd62e351790eb775ee857e037fcd49fcc23a5bfa4638377e6b4b7`; the installed Gamescope binary matches the bundle (`41a067202e94af16b6f09b819208450e667dcc709480a2b97405d59a0e93cb69`).
|
||||
- Signed debug APK SHA-256: `7a19928dc93e72c81b553c62515f3881a249eb037a81fbb6296e05bb9edd23b3`, built from commit `e427c08` using the ordinary artifact-pin path.
|
||||
- Device logs: `Download/DroidDeck/2026-10-03-10-steam/`. They identify Lavapipe, SDL swapchain creation, timer pacing, and the outer window `Steam Big Picture Mode` drawing through the system Mali-G52 presenter.
|
||||
- The native ARM build, full local Android build, bundle checksum, installed binary identity, shell syntax, workflow YAML, and diff checks passed. App data and the primary checkout were preserved.
|
||||
|
||||
The shared-memory commit fixes are both needed: without a ready fence, commits never display; with the old buffer memoization, a reused buffer keeps displaying its first copied pixels (the boot logo or black) despite ongoing frame delivery. Refreshing the copy also makes the account-field edits visible.
|
||||
|
||||
## Geometry Wars gameplay follow-up
|
||||
|
||||
After the user signed in, Geometry Wars: Retro Evolved (`8400`) was downloaded through the native Steam client on the same device and APK. Steam verified all seven files (66,019,943 bytes, build `251921`, depot `8401`). The first install confirmation crashed Steam with exit 139 while it queued additional compatibility runtimes. Restarting the session retained the install request; the download then completed successfully. The cause of that client crash is unverified.
|
||||
|
||||
The game launches through `bannerlator-proton-arm64` using the installed Proton Experimental (ARM64), Wine and DXVK, with the guest still using Lavapipe. It reached the animated menu and an active round; the on-screen A button starts a round, the left stick moves the ship, the right stick fires in different directions, and Start pauses it.
|
||||
|
||||
The first run was cropped and repeatedly recreated its swapchain. Turning off **Stretch games to fill** did not resolve the cropping. A game-specific Steam launch option did:
|
||||
|
||||
```sh
|
||||
DISABLE_GAMESCOPE_WSI=1 %command%
|
||||
```
|
||||
|
||||
That disables the Vulkan Xwayland-bypass layer for the game while keeping the outer Gamescope session. The subsequent menu and gameplay show the whole 4:3 image, including the high-score column and all menu entries. Fullscreen stretching remains off on the test device, and on-screen controls are set to **Always**. These are runtime settings; the branch does not automatically apply this per-game workaround.
|
||||
|
||||
The Android presenter reported roughly 3–5 displayed frames per second in representative gameplay samples. Movement and shooting work, but CPU-rendered performance is insufficient for normal play. Audio was not verified. The game was left paused with scrcpy running. Follow-up logs are in `Download/DroidDeck/2026-10-03-11-steam/`; screenshots and raw logs are retained locally, outside Git.
|
||||
|
||||
A guest glibc Mali ICD and compatible image transport remain necessary for hardware acceleration. This patch does not install Steam-ARM's feature layers or validate other Mali generations; the gameplay result establishes one Windows D3D9 title through software rendering, not general Proton/DXVK compatibility. The Android presenter also caps its requested Vulkan API to the loader's supported version and withholds dma-buf advertisement when the complete import extension set is missing; that missing-extension branch has not been exercised on this G52 driver.
|
||||
|
||||
## GPU acceleration follow-up
|
||||
|
||||
The [kbase/JM driver lab](../../tools/panvk/README.md) now includes a pinned
|
||||
source build and three fixes validated on this wired G52. GPU compute,
|
||||
offscreen draw/readback, indexed draw and visible VKCube presentation work.
|
||||
Geometry Wars remains blocked: the bundled DXVK requires an unsupported
|
||||
feature, while an isolated older DXVK reaches rendering and loses the GPU
|
||||
device. The software Steam/Gamescope settings remain the recovery path.
|
||||
+21
-2
@@ -207,10 +207,29 @@ cached() {
|
||||
echo "${out}"
|
||||
}
|
||||
|
||||
# Experimental branches can pin a CI artifact until their native component is released.
|
||||
download_gamescope_artifact() (
|
||||
set -e
|
||||
local artifact_dir
|
||||
artifact_dir=$(mktemp -d)
|
||||
trap 'rm -rf "$artifact_dir"' EXIT
|
||||
gh run download "$1" -R "$2" -n gamescope-patched -D "$artifact_dir"
|
||||
cp "$artifact_dir/gamescope.tzst" "$out"
|
||||
)
|
||||
|
||||
if [[ -f "${repo_root}/tools/gamescope/release.env" ]]; then
|
||||
. "${repo_root}/tools/gamescope/release.env"
|
||||
gamescope_archive=$(cached "${GAMESCOPE_SHA256}" gamescope.tzst \
|
||||
bash -c 'gh release download "$0" -R "$1" -p gamescope.tzst -O "$out"' "${GAMESCOPE_TAG}" "${github_repo}")
|
||||
if [[ -n "${DROIDDECK_GAMESCOPE_BUNDLE:-}" ]]; then
|
||||
gamescope_archive=${DROIDDECK_GAMESCOPE_BUNDLE}
|
||||
test -f "${gamescope_archive}"
|
||||
echo "Using local Gamescope bundle: ${gamescope_archive}"
|
||||
elif [[ -n "${GAMESCOPE_ARTIFACT_RUN:-}" ]]; then
|
||||
gamescope_archive=$(cached "${GAMESCOPE_SHA256}" gamescope.tzst \
|
||||
download_gamescope_artifact "${GAMESCOPE_ARTIFACT_RUN}" "${github_repo}")
|
||||
else
|
||||
gamescope_archive=$(cached "${GAMESCOPE_SHA256}" gamescope.tzst \
|
||||
bash -c 'gh release download "$0" -R "$1" -p gamescope.tzst -O "$out"' "${GAMESCOPE_TAG}" "${github_repo}")
|
||||
fi
|
||||
zstd -dc "${gamescope_archive}" | tar -xf - -C "${linuxfs_dir}"
|
||||
test -f "${linuxfs_dir}/usr/local/bin/gamescope"
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp
|
||||
index 54e4efc..88a6353 100644
|
||||
--- a/src/rendervulkan.cpp
|
||||
+++ b/src/rendervulkan.cpp
|
||||
@@ -450,7 +450,13 @@ bool CVulkanDevice::createDevice()
|
||||
bool hasDrmProps = vulkan_has_drm_props();
|
||||
bool supportsForeignQueue = false;
|
||||
bool supportsHDRMetadata = false;
|
||||
+ bool supportsPresentId = false;
|
||||
+ bool supportsPresentWait = false;
|
||||
for (const auto& ext : m_supportedExts) {
|
||||
+ if ( strcmp(ext.extensionName, VK_KHR_PRESENT_ID_EXTENSION_NAME) == 0 )
|
||||
+ supportsPresentId = true;
|
||||
+ if ( strcmp(ext.extensionName, VK_KHR_PRESENT_WAIT_EXTENSION_NAME) == 0 )
|
||||
+ supportsPresentWait = true;
|
||||
if ( strcmp(ext.extensionName, VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME) == 0 )
|
||||
m_bSupportsModifiers = true;
|
||||
|
||||
@@ -518,6 +524,25 @@ bool CVulkanDevice::createDevice()
|
||||
m_bSupportsModifiers = false;
|
||||
}
|
||||
|
||||
+ if ( supportsPresentId && supportsPresentWait )
|
||||
+ {
|
||||
+ VkPhysicalDevicePresentWaitFeaturesKHR waitFeatures = {
|
||||
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR,
|
||||
+ };
|
||||
+ VkPhysicalDevicePresentIdFeaturesKHR idFeatures = {
|
||||
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR,
|
||||
+ .pNext = &waitFeatures,
|
||||
+ };
|
||||
+ VkPhysicalDeviceFeatures2 features = {
|
||||
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
||||
+ .pNext = &idFeatures,
|
||||
+ };
|
||||
+ vk.GetPhysicalDeviceFeatures2( physDev(), &features );
|
||||
+ m_bSupportsPresentWait = idFeatures.presentId && waitFeatures.presentWait;
|
||||
+ }
|
||||
+ if ( GetBackend()->UsesVulkanSwapchain() && !m_bSupportsPresentWait )
|
||||
+ vk_log.infof( "Present ID/wait unavailable; using timer-based pacing." );
|
||||
+
|
||||
{
|
||||
VkPhysicalDeviceVulkan12Features vulkan12Features = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
|
||||
@@ -570,8 +595,11 @@ bool CVulkanDevice::createDevice()
|
||||
enabledExtensions.push_back( VK_KHR_SWAPCHAIN_EXTENSION_NAME );
|
||||
enabledExtensions.push_back( VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME );
|
||||
|
||||
- enabledExtensions.push_back( VK_KHR_PRESENT_ID_EXTENSION_NAME );
|
||||
- enabledExtensions.push_back( VK_KHR_PRESENT_WAIT_EXTENSION_NAME );
|
||||
+ if ( m_bSupportsPresentWait )
|
||||
+ {
|
||||
+ enabledExtensions.push_back( VK_KHR_PRESENT_ID_EXTENSION_NAME );
|
||||
+ enabledExtensions.push_back( VK_KHR_PRESENT_WAIT_EXTENSION_NAME );
|
||||
+ }
|
||||
|
||||
if ( supportsHDRMetadata )
|
||||
enabledExtensions.push_back( VK_EXT_HDR_METADATA_EXTENSION_NAME );
|
||||
@@ -646,7 +674,7 @@ bool CVulkanDevice::createDevice()
|
||||
|
||||
VkPhysicalDeviceFeatures2 features2 = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
||||
- .pNext = &presentIdFeatures,
|
||||
+ .pNext = m_bSupportsPresentWait ? static_cast<void *>( &presentIdFeatures ) : static_cast<void *>( &features13 ),
|
||||
.features = {
|
||||
.shaderInt16 = m_bSupportsFp16,
|
||||
},
|
||||
@@ -2082,6 +2110,12 @@ static VkImageViewType VulkanImageTypeToViewType(VkImageType type)
|
||||
|
||||
bool CVulkanTexture::BInit( uint32_t width, uint32_t height, uint32_t depth, uint32_t drmFormat, createFlags flags, wlr_dmabuf_attributes *pDMA /* = nullptr */, uint32_t contentWidth /* = 0 */, uint32_t contentHeight /* = 0 */, CVulkanTexture *pExistingImageToReuseMemory, gamescope::OwningRc<gamescope::IBackendFb> pBackendFb )
|
||||
{
|
||||
+ // Swapchain backends composite into their own images; textures are never scanned out.
|
||||
+ // Keep explicit exports and dma-buf imports, but do not require a DRM export for local
|
||||
+ // cursor, blank, or wl_shm textures (Lavapipe has no DRM allocator).
|
||||
+ if ( GetBackend()->UsesVulkanSwapchain() )
|
||||
+ flags.bFlippable = false;
|
||||
+
|
||||
m_pBackendFb = std::move( pBackendFb );
|
||||
m_drmFormat = drmFormat;
|
||||
VkResult res = VK_ERROR_INITIALIZATION_FAILED;
|
||||
@@ -3086,7 +3120,7 @@ void vulkan_present_to_window( void )
|
||||
|
||||
VkPresentInfoKHR presentInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
- .pNext = &presentIdInfo,
|
||||
+ .pNext = g_device.supportsPresentWait() ? &presentIdInfo : nullptr,
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = &g_output.swapChain,
|
||||
.pImageIndices = &g_output.nOutImage,
|
||||
@@ -3094,8 +3128,11 @@ void vulkan_present_to_window( void )
|
||||
|
||||
if ( g_device.vk.QueuePresentKHR( g_device.queue(), &presentInfo ) == VK_SUCCESS )
|
||||
{
|
||||
- g_currentPresentWaitId = presentId;
|
||||
- g_currentPresentWaitId.notify_all();
|
||||
+ if ( g_device.supportsPresentWait() )
|
||||
+ {
|
||||
+ g_currentPresentWaitId = presentId;
|
||||
+ g_currentPresentWaitId.notify_all();
|
||||
+ }
|
||||
}
|
||||
else
|
||||
vulkan_remake_swapchain();
|
||||
@@ -3662,7 +3699,7 @@ bool vulkan_init( VkInstance instance, VkSurfaceKHR surface )
|
||||
if (!init_nis_data())
|
||||
return false;
|
||||
|
||||
- if ( GetBackend()->UsesVulkanSwapchain() )
|
||||
+ if ( GetBackend()->UsesVulkanSwapchain() && g_device.supportsPresentWait() )
|
||||
{
|
||||
std::thread present_wait_thread( present_wait_thread_func );
|
||||
present_wait_thread.detach();
|
||||
diff --git a/src/rendervulkan.hpp b/src/rendervulkan.hpp
|
||||
index fa519db..91f7793 100644
|
||||
--- a/src/rendervulkan.hpp
|
||||
+++ b/src/rendervulkan.hpp
|
||||
@@ -862,6 +862,7 @@ public:
|
||||
inline VkPipelineLayout pipelineLayout() {return m_pipelineLayout;}
|
||||
inline int drmRenderFd() {return m_drmRendererFd;}
|
||||
inline bool supportsModifiers() {return m_bSupportsModifiers;}
|
||||
+ inline bool supportsPresentWait() {return m_bSupportsPresentWait;}
|
||||
inline bool hasDrmPrimaryDevId() {return m_bHasDrmPrimaryDevId;}
|
||||
inline dev_t primaryDevId() {return m_drmPrimaryDevId;}
|
||||
inline bool supportsFp16() {return m_bSupportsFp16;}
|
||||
@@ -930,6 +931,7 @@ protected:
|
||||
uint32_t m_uVendorID = 0;
|
||||
bool m_bHasDrmPrimaryDevId = false;
|
||||
bool m_bSupportsModifiers = false;
|
||||
+ bool m_bSupportsPresentWait = false;
|
||||
bool m_bInitialized = false;
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp
|
||||
index 18b799e..26cf64e 100644
|
||||
--- a/src/steamcompmgr.cpp
|
||||
+++ b/src/steamcompmgr.cpp
|
||||
@@ -1850,19 +1850,20 @@ import_commit (
|
||||
commit->fifo = false;
|
||||
}
|
||||
|
||||
- if ( gamescope::OwningRc<CVulkanTexture> pTexture = s_BufferMemos.LookupVulkanTexture( buf ) )
|
||||
- {
|
||||
- // Going from OwningRc -> Rc now.
|
||||
- commit->vulkanTex = pTexture;
|
||||
- return commit;
|
||||
- }
|
||||
-
|
||||
struct wlr_dmabuf_attributes dmabuf = {0};
|
||||
+ const bool bHasDmabuf = wlr_buffer_get_dmabuf( buf, &dmabuf );
|
||||
gamescope::OwningRc<gamescope::IBackendFb> pBackendFb;
|
||||
- if ( wlr_buffer_get_dmabuf( buf, &dmabuf ) )
|
||||
+ if ( bHasDmabuf )
|
||||
{
|
||||
+ if ( gamescope::OwningRc<CVulkanTexture> pTexture = s_BufferMemos.LookupVulkanTexture( buf ) )
|
||||
+ {
|
||||
+ commit->vulkanTex = pTexture;
|
||||
+ return commit;
|
||||
+ }
|
||||
pBackendFb = GetBackend()->ImportDmabufToBackend( &dmabuf );
|
||||
}
|
||||
+ // A dma-buf image aliases its backing storage. A wl_shm texture is a private copy:
|
||||
+ // upload each commit, since clients reuse the same buffer with different pixels.
|
||||
|
||||
gamescope::OwningRc<CVulkanTexture> pOwnedTexture = vulkan_create_texture_from_wlr_buffer( buf, std::move( pBackendFb ) );
|
||||
|
||||
@@ -1873,7 +1874,8 @@ import_commit (
|
||||
|
||||
commit->vulkanTex = pOwnedTexture;
|
||||
|
||||
- s_BufferMemos.MemoizeBuffer( buf, std::move( pOwnedTexture ) );
|
||||
+ if ( bHasDmabuf )
|
||||
+ s_BufferMemos.MemoizeBuffer( buf, std::move( pOwnedTexture ) );
|
||||
|
||||
return commit;
|
||||
}
|
||||
@@ -8504,6 +8506,12 @@ void update_wayland_res(CommitDoneList_t *doneCommits, steamcompmgr_win_t *w, Re
|
||||
{
|
||||
fence = dup( dmabuf.fd[0] );
|
||||
}
|
||||
+ else if ( !newCommit->vulkanTex->externalImage() )
|
||||
+ {
|
||||
+ // wl_shm uploads wait for their copy to finish in vulkan_create_texture_from_wlr_buffer.
|
||||
+ // A private swapchain texture has no dma-buf to poll; it is already ready.
|
||||
+ bKnownReady = true;
|
||||
+ }
|
||||
else
|
||||
{
|
||||
fence = newCommit->vulkanTex->memoryFence();
|
||||
@@ -1,2 +1,5 @@
|
||||
# Experimental branch pin: build the tested native patch without publishing a component release.
|
||||
# Before shipping, publish a Gamescope release and remove GAMESCOPE_ARTIFACT_RUN.
|
||||
GAMESCOPE_ARTIFACT_RUN=37146942306
|
||||
GAMESCOPE_SHA256=22df550d60fcd62e351790eb775ee857e037fcd49fcc23a5bfa4638377e6b4b7
|
||||
GAMESCOPE_TAG=gamescope-3.16.29-p5
|
||||
GAMESCOPE_SHA256=188144e5564e020d0bc485a1f4f90e1c5fd61d0d1d6dd29db21e8b019036a5c6
|
||||
@@ -73,6 +73,15 @@ if [ -n "${BL_VK_DRIVER:-}" ]; then
|
||||
fi
|
||||
unset bl_icd_lib
|
||||
fi
|
||||
# Compatibility mode: the Android presenter still uses its selected Vulkan driver, while the
|
||||
# Linux session renders on the CPU. Gamescope's SDL swapchain can carry these frames as wl_shm;
|
||||
# its Wayland backend requires exportable dma-bufs even for its dummy black texture.
|
||||
if [ "${BL_STEAM_SOFTWARE:-0}" = 1 ]; then
|
||||
export VK_DRIVER_FILES=/usr/share/vulkan/icd.d/lvp_icd.json
|
||||
export VK_ICD_FILENAMES=$VK_DRIVER_FILES
|
||||
export LIBGL_ALWAYS_SOFTWARE=1 GALLIUM_DRIVER=llvmpipe MESA_LOADER_DRIVER_OVERRIDE=swrast
|
||||
echo "== linux graphics: software rendering requested (Lavapipe/llvmpipe)"
|
||||
fi
|
||||
# The app's gamescope build (tools/gamescope) asks for realtime-priority Vulkan queues on this
|
||||
# switch instead of on CAP_SYS_NICE, which proot never has; it falls back to normal priority
|
||||
# where the driver refuses, and the runtime's own build ignores it. On KGSL Turnip (Mesa 26.2) it
|
||||
@@ -148,7 +157,13 @@ if [ -z "${BL_INSIDE:-}" ]; then
|
||||
echo "== gamescope: games at ${nested}x${height} stretched to the ${width}x${height} output"
|
||||
fi
|
||||
fi
|
||||
args=(--backend wayland --expose-wayland -f -W "$width" -H "$height" -w "$nested" -h "$height")
|
||||
backend=wayland
|
||||
if [ "${BL_STEAM_SOFTWARE:-0}" = 1 ]; then
|
||||
backend=sdl
|
||||
export SDL_VIDEODRIVER=wayland
|
||||
echo "== gamescope: SDL Wayland swapchain for software rendering"
|
||||
fi
|
||||
args=(--backend "$backend" --expose-wayland -f -W "$width" -H "$height" -w "$nested" -h "$height")
|
||||
[ "$nested" != "$width" ] && args+=(-S stretch)
|
||||
# -r is what gamescope advertises as the refresh rate, and what a game reads as the display's.
|
||||
# Left unset it defaults to 60, so a 120 Hz panel offers only 60 Hz in game settings. The FPS
|
||||
@@ -179,7 +194,8 @@ if [ -z "${BL_INSIDE:-}" ]; then
|
||||
# MANGOHUD_CONFIGFILE. The apk stages Valve's aarch64 build (tools/mangoapp) - without it the menu
|
||||
# still offers the levels and nothing appears. Starts hidden until the client writes a level.
|
||||
# BL_MANGOAPP=0 turns it off (one community build found Valve's mangoapp crashing on Turnip).
|
||||
if [ "$mode" = steam ] && [ "${BL_STEAMDECK:-0}" = 1 ] && [ "${BL_MANGOAPP:-1}" = 1 ] \
|
||||
if [ "$mode" = steam ] && [ "${BL_STEAM_SOFTWARE:-0}" != 1 ] \
|
||||
&& [ "${BL_STEAMDECK:-0}" = 1 ] && [ "${BL_MANGOAPP:-1}" = 1 ] \
|
||||
&& [ "${BL_STEAM_UI:-}" != desktop ] && command -v mangoapp >/dev/null 2>&1; then
|
||||
MANGOHUD_CONFIGFILE=$(mktemp /tmp/mangohud.XXXXXXXX)
|
||||
echo no_display > "$MANGOHUD_CONFIGFILE"
|
||||
@@ -639,6 +655,15 @@ BUSCONF
|
||||
# desktop's launchers ask for; gamescope shows one window at a time and the game takes over.
|
||||
_bl_ui=(-gamepadui)
|
||||
[ "${BL_STEAM_UI:-}" = desktop ] && _bl_ui=()
|
||||
# Software compatibility mode: CEF and Steam use CPU frames through Xwayland,
|
||||
# inside either the desktop or the software Gamescope session.
|
||||
_bl_cef=(-cef-force-gpu -cef-use-gl=angle -cef-use-angle=vulkan)
|
||||
if [ "${BL_STEAM_SOFTWARE:-0}" = 1 ]; then
|
||||
_bl_cef=(-cef-disable-gpu -cef-disable-gpu-compositing)
|
||||
export LIBGL_ALWAYS_SOFTWARE=1 GALLIUM_DRIVER=llvmpipe
|
||||
export MESA_LOADER_DRIVER_OVERRIDE=swrast SDL_RENDER_DRIVER=software SDL_VIDEODRIVER=x11
|
||||
echo "== steam: software rendering requested"
|
||||
fi
|
||||
# Deck mode (BL_STEAMDECK=1, the Steam page's Client settings): -steamdeck is the flag that puts
|
||||
# the Quick Access Menu and the Deck settings pages on screen; the QAM's performance overlay
|
||||
# controls stay greyed out without -steamos3, as SteamOS and Armada launch it. -steamos3 makes
|
||||
@@ -698,7 +723,7 @@ BUSCONF
|
||||
done
|
||||
) &
|
||||
fi
|
||||
echo "== steam args: ${_bl_ui[*]} -clientbeta $steam_channel -no-cef-sandbox -cef-force-gpu -cef-ozone-platform=x11 -cef-use-gl=angle -cef-use-angle=vulkan $*"
|
||||
echo "== steam args: ${_bl_ui[*]} -clientbeta $steam_channel -no-cef-sandbox -cef-ozone-platform=x11 ${_bl_cef[*]} $*"
|
||||
# An update that cannot install asks for a restart (rc=42) every time; the count is capped so a
|
||||
# session can never again loop in silence, which reads as a menu opening and closing by itself.
|
||||
steam_updates=0
|
||||
@@ -745,8 +770,7 @@ BUSCONF
|
||||
fi
|
||||
step "starting the Steam client${BL_STEAM_UI:+ ($BL_STEAM_UI UI)}"
|
||||
"$steam_root/steamrtarm64/steam" "${_bl_ui[@]}" -clientbeta "$steam_channel" \
|
||||
-no-cef-sandbox -cef-force-gpu -cef-ozone-platform=x11 \
|
||||
-cef-use-gl=angle -cef-use-angle=vulkan "$@"
|
||||
-no-cef-sandbox -cef-ozone-platform=x11 "${_bl_cef[@]}" "$@"
|
||||
rc=$?
|
||||
echo "== steam exited rc=$rc"
|
||||
collect_steam_logs
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
# On a software desktop (pixman: the GPU renderers failed on this device) there is no dma-buf, so a
|
||||
# game - or the client's own Vulkan window - would die at its first frame. There the request goes
|
||||
# to the app, which ends the desktop and starts a Steam session under gamescope in its place.
|
||||
# BL_STEAM_SOFTWARE=1 opts into a CPU-rendered client on that desktop for compatibility testing.
|
||||
set -u
|
||||
ui=${1:-desktop}
|
||||
target=${2:-}
|
||||
@@ -28,7 +29,8 @@ esac
|
||||
steam_root=${XDG_DATA_HOME:-${HOME:-/root}/.local/share}/Steam
|
||||
client=$steam_root/steamrtarm64/steam
|
||||
|
||||
if [ "${BL_DESKTOP:-}" = 1 ] && [ -n "${WLR_RENDERER:-}" ] && [ "$WLR_RENDERER" != pixman ]; then
|
||||
if [ "${BL_DESKTOP:-}" = 1 ] && [ -n "${WLR_RENDERER:-}" ] \
|
||||
&& { [ "$WLR_RENDERER" != pixman ] || [ "${BL_STEAM_SOFTWARE:-0}" = 1 ]; }; then
|
||||
log=${BL_DEBUG_DIR:-$HOME/.cache/droiddeck}/steam-desktop.log
|
||||
mkdir -p "$(dirname "$log")" 2>/dev/null
|
||||
if pgrep -f 'steamrtarm64/steam( |$)' >/dev/null 2>&1 && [ -x "$client" ]; then
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
# Experimental Mali kbase/JM driver
|
||||
|
||||
This lab builds the Linux Vulkan ICD from
|
||||
[FristOneRR-Panvk-Source](https://github.com/FristOneRR-Admin/FristOneRR-Panvk-Source)
|
||||
at `efd07bab401b263a9ac114560ecdb9a2934f5d43`. The fork includes the older Job
|
||||
Manager submission path needed by Mali-G52. It talks to `/dev/mali0` through
|
||||
the proprietary kbase kernel interface; upstream DRM-only PanVK cannot use
|
||||
that device node.
|
||||
|
||||
The local patches make Android `liblog` conditional, fix the JM atom ABI,
|
||||
and withhold placed mapping on kbase.
|
||||
The original fork padded its v2 layout to 64 bytes, which this kernel interprets
|
||||
as v3 with an eight-byte sequence-number prefix. Jobs arrived under atom 0 and
|
||||
timed out after a configuration fault. The patch submits the actual 56-byte v2
|
||||
structure on JM 11.19 and later (48 bytes on older JM), as specified in
|
||||
[Arm's kbase UAPI header](https://nest-open-source.googlesource.com/manifest_repos/mali-driver/+/0f8397eced2de6bc649a9cc32d0fae77a1dc34dc/bifrost/r44p0/kernel/include/uapi/gpu/arm/midgard/jm/mali_base_jm_kernel.h).
|
||||
|
||||
Build inside an AArch64 glibc environment with Clang/LLVM 22, Meson, Ninja,
|
||||
libclc, SPIRV-Tools, SPIRV-LLVM-Translator, Vulkan headers, Python Mako/YAML,
|
||||
and the X11/Wayland development dependencies installed. The tested DroidDeck
|
||||
runtime already supplied several of these dependencies. Avoid installing an
|
||||
entire development toolchain into a user's runtime by default.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/FristOneRR-Admin/FristOneRR-Panvk-Source.git panvk-src
|
||||
git -C panvk-src checkout efd07bab401b263a9ac114560ecdb9a2934f5d43
|
||||
JOBS=2 tools/panvk/build-in-runtime.sh "$PWD/panvk-src" "$PWD/panvk-build"
|
||||
```
|
||||
|
||||
The build stays under `panvk-build`; it does not install or replace a global
|
||||
ICD. Its manifest selects the newly built driver explicitly:
|
||||
|
||||
```sh
|
||||
PAN_I_WANT_A_BROKEN_VULKAN_DRIVER=1 PANVK_KBASE_DRI3=0 \
|
||||
VK_DRIVER_FILES="$PWD/panvk-build/panvk-g52-icd.json" \
|
||||
VK_ICD_FILENAMES="$PWD/panvk-build/panvk-g52-icd.json" \
|
||||
vulkaninfo --summary
|
||||
```
|
||||
|
||||
To launch the tested GPU cube from the Mac against this device's lab build:
|
||||
|
||||
```sh
|
||||
ADB_SERIAL=RGB05001607258 tools/droiddeckctl run /usr/bin/env -- \
|
||||
PAN_I_WANT_A_BROKEN_VULKAN_DRIVER=1 PANVK_KBASE_DRI3=0 \
|
||||
VK_DRIVER_FILES=/opt/panvk-g52-lab/panvk-g52-icd.json \
|
||||
VK_ICD_FILENAMES=/opt/panvk-g52-lab/panvk-g52-icd.json \
|
||||
DISABLE_GAMESCOPE_WSI=1 LD_LIBRARY_PATH=/usr/lib \
|
||||
/usr/bin/vkcube --wsi xcb --width 640 --height 480
|
||||
```
|
||||
|
||||
Stop the current session before using `droiddeckctl run`.
|
||||
|
||||
`PANVK_KBASE_DRI3=0` selects shared-memory presentation. DroidDeck's Xwayland
|
||||
does not implement the fork's private Termux:X11 raw dma-buf protocol. GPU
|
||||
rendering and CPU presentation copies are separate: choosing this presentation
|
||||
path does not select Lavapipe.
|
||||
|
||||
Before selecting this driver for a session, validate GPU compute and offscreen
|
||||
render readback, then X11 presentation, then the desired game. Device detection
|
||||
alone is insufficient. The wired Unisoc T618 / Mali-G52 MC2 reports kbase UAPI
|
||||
11.31, while the separate
|
||||
[G52 reference project](https://github.com/LukeValen/panvk-mali-g52) was tested
|
||||
on MediaTek with UAPI 11.38. Keep `BL_STEAM_SOFTWARE=1` available for recovery.
|
||||
|
||||
The Linux ICD is distinct from the Android Vulkan driver used by DroidDeck's
|
||||
presenter. Android/Bionic driver packages cannot be loaded by the glibc Steam
|
||||
runtime.
|
||||
|
||||
## Wired G52 results (2026-10-03)
|
||||
|
||||
Built natively in DroidDeck's AArch64 glibc runtime with Clang/LLVM 22.1.8.
|
||||
The app UID can open `/dev/mali0` and submit jobs without root. No DRM render
|
||||
node or dma-heap was available. This is experimental driver work, with the
|
||||
Steam UI and outer Gamescope still running in software mode.
|
||||
|
||||
| Test | Result |
|
||||
| --- | --- |
|
||||
| Vulkan enumeration | Mali-G52 r1 MC2, integrated GPU, Vulkan 1.3.354 |
|
||||
| Compute shader and host readback | Expected integer 777 returned |
|
||||
| Vertex/fragment draw and image readback | Expected red pixel 255,0,0,255 returned |
|
||||
| Indexed triangle and image readback | Expected red pixel returned |
|
||||
| X11 VKCube inside a DroidDeck Gamescope session | Rotating cube visible; about 15–17 displayed FPS through SHM |
|
||||
| Geometry Wars, bundled DXVK 3.1.1 | Adapter rejected: `multiDrawIndirect` is unsupported |
|
||||
| Geometry Wars, isolated DXVK 1.10.3 | Device and 640×480 swapchain created; rendering loses the GPU device |
|
||||
|
||||
The fork advertises `VK_EXT_map_memory_placed` although its kbase mapping code
|
||||
rejects caller-selected addresses for ordinary SAME_VA allocations. Wine's
|
||||
WoW64 Vulkan path selects that extension and DXVK buffer mapping fails with
|
||||
`VK_ERROR_MEMORY_MAP_FAILED`. The third patch withholds the extension and
|
||||
features on kbase, keeping them on DRM. Wine then uses its fallback mapping
|
||||
path and reaches real game submissions.
|
||||
|
||||
The remaining Geometry Wars failure includes terminated jobs (`0x04`) and
|
||||
`BASE_JD_EVENT_JOB_READ_FAULT` (`0x42`), followed by
|
||||
`VK_ERROR_DEVICE_LOST`. A diagnostic build that waits after each batch showed
|
||||
successful uploads and clears, then termination of the first vertex/tiler
|
||||
chain. Its compute job completed, but its vertex job, tiler job and dependent
|
||||
fragment job did not complete. Basic indexed rendering also passes with IDVS
|
||||
disabled, so a generic indexed-draw or separate-vertex-job failure was not
|
||||
reproduced. The complex vertex workload remains unresolved. Disabling submission overlap and compiler IDVS or
|
||||
optimizations did not recover rendering. Native draw/readback and VKCube
|
||||
success therefore do not establish working Proton game acceleration.
|
||||
|
||||
Do not advertise missing Vulkan features just to pass DXVK's adapter check.
|
||||
Keep game overrides and legacy DXVK trials isolated from the Proton depot,
|
||||
and restore the working software launch option when the trial fails:
|
||||
|
||||
```sh
|
||||
DISABLE_GAMESCOPE_WSI=1 %command%
|
||||
```
|
||||
|
||||
The tested three-patch build has SHA-256
|
||||
`5fc3f57fe335ebf524871ca24fd38b3c384c31baaebe9a2220e8e482e09e5ad6`.
|
||||
That identifies the retained evidence binary; rebuilds need not be byte-identical.
|
||||
|
||||
The patched driver remains a private lab ICD. It is not bundled in the APK,
|
||||
selected globally, or production-ready. A compatible DXVK path and reliable
|
||||
complex rendering must be validated before adding automatic Mali selection.
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
# Experimental kbase/JM PanVK build. Run inside an AArch64 glibc environment.
|
||||
# Output stays private to the supplied build directory; no system ICD is installed.
|
||||
set -euo pipefail
|
||||
|
||||
source_dir=${1:?Usage: build-in-runtime.sh SOURCE_DIR BUILD_DIR}
|
||||
build_dir=${2:?Usage: build-in-runtime.sh SOURCE_DIR BUILD_DIR}
|
||||
revision=efd07bab401b263a9ac114560ecdb9a2934f5d43
|
||||
script_dir=$(cd -- "$(dirname -- "$0")" && pwd)
|
||||
source_dir=$(cd -- "$source_dir" && pwd)
|
||||
mkdir -p "$build_dir"
|
||||
build_dir=$(cd -- "$build_dir" && pwd)
|
||||
|
||||
if [ "$(uname -m)" != aarch64 ]; then
|
||||
echo 'This script needs a native AArch64 Linux build environment.' >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$(git -C "$source_dir" rev-parse HEAD)" != "$revision" ]; then
|
||||
echo "Expected FristOneRR-Panvk-Source revision $revision." >&2
|
||||
exit 1
|
||||
fi
|
||||
for patch_file in "$script_dir"/patches/*.patch; do
|
||||
if git -C "$source_dir" apply --reverse --check "$patch_file" 2>/dev/null; then
|
||||
continue
|
||||
fi
|
||||
git -C "$source_dir" apply --check "$patch_file"
|
||||
git -C "$source_dir" apply "$patch_file"
|
||||
done
|
||||
|
||||
# The fork's SPIRV-Tools probe contains Clang-only warning options.
|
||||
export CC=clang CXX=clang++
|
||||
meson setup "$build_dir" "$source_dir" --buildtype=release \
|
||||
--prefix="$build_dir/install" --libdir=lib \
|
||||
-Dbuild-tests=false -Dgallium-drivers= -Dvulkan-drivers=panfrost \
|
||||
-Dpanfrost-kmds=kbase -Dplatforms=x11,wayland \
|
||||
-Dglx=disabled -Degl=disabled -Dgbm=disabled \
|
||||
-Dgles1=disabled -Dgles2=disabled -Dopengl=false \
|
||||
-Dllvm=enabled -Dmesa-clc=enabled -Dprecomp-compiler=enabled \
|
||||
-Dpanfrost-rust=false -Dvalgrind=disabled -Dzstd=enabled
|
||||
ninja -C "$build_dir" -j"${JOBS:-2}" src/panfrost/vulkan/libvulkan_panfrost.so
|
||||
|
||||
python3 - "$build_dir" <<'PY'
|
||||
import json, pathlib, sys
|
||||
root = pathlib.Path(sys.argv[1])
|
||||
driver = root / 'src/panfrost/vulkan/libvulkan_panfrost.so'
|
||||
manifest = {'file_format_version': '1.0.0', 'ICD': {
|
||||
'library_path': str(driver), 'api_version': '1.4.0'}}
|
||||
(root / 'panvk-g52-icd.json').write_text(json.dumps(manifest, indent=2) + '\n')
|
||||
PY
|
||||
sha256sum "$build_dir/src/panfrost/vulkan/libvulkan_panfrost.so"
|
||||
echo "Private ICD: $build_dir/panvk-g52-icd.json"
|
||||
@@ -0,0 +1,17 @@
|
||||
diff --git a/meson.build b/meson.build
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -16,10 +16,9 @@ project(
|
||||
'build.rust_std=2021',
|
||||
],
|
||||
)
|
||||
-add_project_link_arguments(
|
||||
- '-llog',
|
||||
- language : ['c', 'cpp'],
|
||||
-)
|
||||
+if host_machine.system() == 'android'
|
||||
+ add_project_link_arguments('-llog', language : ['c', 'cpp'])
|
||||
+endif
|
||||
project_version = meson.project_version()
|
||||
|
||||
if host_machine.system() == 'darwin'
|
||||
@@ -0,0 +1,95 @@
|
||||
diff --git a/src/panfrost/lib/kmod/kbase_kmod.c b/src/panfrost/lib/kmod/kbase_kmod.c
|
||||
--- a/src/panfrost/lib/kmod/kbase_kmod.c
|
||||
+++ b/src/panfrost/lib/kmod/kbase_kmod.c
|
||||
@@ -97,6 +97,7 @@
|
||||
|
||||
struct base_jd_udata { __u64 blob[2]; };
|
||||
|
||||
+/* kbase atom v2: 56 bytes, without the v3 sequence-number prefix. */
|
||||
struct base_jd_atom {
|
||||
__u64 jc;
|
||||
struct base_jd_udata udata;
|
||||
@@ -110,11 +111,12 @@
|
||||
__u8 jobslot;
|
||||
__u32 core_req;
|
||||
__u8 renderpass_id;
|
||||
- __u8 padding[15]; /* pad struct to 64 bytes total; this kernel rejects any other JOB_SUBMIT stride */
|
||||
+ __u8 padding[7];
|
||||
};
|
||||
|
||||
-/* Some kbase builds (e.g. r49 on 6.6 kernels) expect a 56-byte atom
|
||||
- * stride instead of 64. PANVK_ATOM_STRIDE overrides the default. */
|
||||
+/* JM 11.19 added renderpass_id and extended v2 from 48 to 56 bytes.
|
||||
+ * A 64-byte atom is v3: it has a leading seq_nr and a different layout.
|
||||
+ * Do not submit a padded v2 as v3. */
|
||||
static unsigned g_atom_stride;
|
||||
|
||||
static unsigned
|
||||
@@ -123,7 +125,7 @@
|
||||
if (!g_atom_stride) {
|
||||
const char *e = getenv("PANVK_ATOM_STRIDE");
|
||||
unsigned v = e ? (unsigned)atoi(e) : 0;
|
||||
- g_atom_stride = (v == 48 || v == 56 || v == 64) ? v : 64;
|
||||
+ g_atom_stride = (v == 48 || v == 56) ? v : 56;
|
||||
if (e)
|
||||
dprintf(2, "[FristOneRR] atom stride = %u\n", g_atom_stride);
|
||||
}
|
||||
@@ -1223,43 +1225,6 @@
|
||||
}
|
||||
|
||||
|
||||
-/* Probe the JOB_SUBMIT atom stride once per process: submit an empty
|
||||
- * dependency-only atom (no GPU work) with stride 64. Kernels that expect
|
||||
- * 56 (e.g. r49 on 6.6) answer with a config fault (0x40) or reject the
|
||||
- * ioctl; then we switch to 56. PANVK_ATOM_STRIDE always wins. */
|
||||
-static void
|
||||
-kbase_probe_atom_stride(int fd)
|
||||
-{
|
||||
- if (g_atom_stride || getenv("PANVK_ATOM_STRIDE")) {
|
||||
- (void)kbase_atom_stride();
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- struct base_jd_atom atom = { .atom_number = 255, .core_req = 0 };
|
||||
- struct kbase_ioctl_job_submit sub = {
|
||||
- .addr = (uint64_t)(uintptr_t)&atom,
|
||||
- .nr_atoms = 1,
|
||||
- .stride = 64,
|
||||
- };
|
||||
- unsigned result = 64;
|
||||
-
|
||||
- if (ioctl(fd, KBASE_IOCTL_JOB_SUBMIT, &sub) < 0) {
|
||||
- result = 56;
|
||||
- } else {
|
||||
- struct pollfd pfd = { .fd = fd, .events = POLLIN };
|
||||
- if (poll(&pfd, 1, 1000) > 0) {
|
||||
- struct base_jd_event_v2 ev = { 0 };
|
||||
- if (read(fd, &ev, sizeof(ev)) == (ssize_t)sizeof(ev) &&
|
||||
- (ev.event_code & BASE_JD_EVENT_ERR_MASK))
|
||||
- result = 56;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- g_atom_stride = result;
|
||||
- if (result != 64)
|
||||
- dprintf(2, "[FristOneRR] atom stride auto-detected: %u\n", result);
|
||||
-}
|
||||
-
|
||||
static struct pan_kmod_dev *
|
||||
kbase_kmod_dev_create(int fd, uint32_t flags,
|
||||
UNUSED const struct pan_kmod_driver *drv_info,
|
||||
@@ -1307,8 +1272,12 @@
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- if (!is_csf)
|
||||
- kbase_probe_atom_stride(fd);
|
||||
+ STATIC_ASSERT(sizeof(struct base_jd_atom) == 56);
|
||||
+ if (!is_csf) {
|
||||
+ if (!g_atom_stride && !getenv("PANVK_ATOM_STRIDE"))
|
||||
+ g_atom_stride = ver.minor < 19 ? 48 : 56;
|
||||
+ (void)kbase_atom_stride();
|
||||
+ }
|
||||
|
||||
/* Empirically, this Mali-G57 kbase JM backend needs ~2s of real
|
||||
* wall-clock time after context creation before the GPU power domain
|
||||
@@ -0,0 +1,26 @@
|
||||
diff --git a/src/panfrost/vulkan/panvk_vX_physical_device.c b/src/panfrost/vulkan/panvk_vX_physical_device.c
|
||||
--- a/src/panfrost/vulkan/panvk_vX_physical_device.c
|
||||
+++ b/src/panfrost/vulkan/panvk_vX_physical_device.c
|
||||
@@ -198,7 +198,9 @@
|
||||
.EXT_legacy_dithering = true,
|
||||
.EXT_line_rasterization = true,
|
||||
.EXT_load_store_op_none = true,
|
||||
- .EXT_map_memory_placed = true,
|
||||
+ /* kbase SAME_VA allocations cannot be mapped at a caller-chosen
|
||||
+ * address. Wine WoW64 selects that path when this extension exists. */
|
||||
+ .EXT_map_memory_placed = !device->kbase_node_path[0],
|
||||
.EXT_external_memory_host = true,
|
||||
.EXT_nested_command_buffer = PAN_ARCH >= 10,
|
||||
.EXT_memory_budget = true,
|
||||
@@ -729,9 +731,9 @@
|
||||
.nestedCommandBufferSimultaneousUse = PAN_ARCH >= 10,
|
||||
|
||||
/* VK_EXT_map_memory_placed */
|
||||
- .memoryMapPlaced = true,
|
||||
+ .memoryMapPlaced = !device->kbase_node_path[0],
|
||||
.memoryMapRangePlaced = false,
|
||||
- .memoryUnmapReserve = true,
|
||||
+ .memoryUnmapReserve = !device->kbase_node_path[0],
|
||||
|
||||
/* VK_EXT_non_seamless_cube_map */
|
||||
.nonSeamlessCubeMap = true,
|
||||
Reference in new issue
Block a user