diff --git a/app/src/main/java/com/droiddeck/launcher/session/SessionFiles.kt b/app/src/main/java/com/droiddeck/launcher/session/SessionFiles.kt
index ca9cafcab..b65f3ac72 100644
--- a/app/src/main/java/com/droiddeck/launcher/session/SessionFiles.kt
+++ b/app/src/main/java/com/droiddeck/launcher/session/SessionFiles.kt
@@ -165,6 +165,8 @@ object SessionFiles {
val gpuLoad = listOf(
"usr/local/lib/droiddeck-gpuload/libVkLayer_droiddeck_gpuload.so" to "usr/local/lib/droiddeck-gpuload/libVkLayer_droiddeck_gpuload.so",
"usr/local/lib/droiddeck-gpuload/VK_LAYER_DROIDDECK_gpu_load.json" to "usr/share/vulkan/implicit_layer.d/droiddeck_gpu_load.json",
+ "usr/local/lib/droiddeck-gpuload/libVkLayer_droiddeck_vramcap.so" to "usr/local/lib/droiddeck-gpuload/libVkLayer_droiddeck_vramcap.so",
+ "usr/local/lib/droiddeck-gpuload/VK_LAYER_DROIDDECK_vram_cap.json" to "usr/share/vulkan/implicit_layer.d/droiddeck_vram_cap.json",
)
val fexPreloads = listOf("x86_64", "i386").flatMap { arch ->
listOf("libblsession.so", "libfakeinput.so", "libfaultreport.so").map { "$arch/$it" to "usr/local/lib/droiddeck-fex/$arch/$it" }
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index 7b9a17ca7..d0222536c 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -593,7 +593,7 @@
يُطبَّق أثناء تشغيل عميل Steam، في جلسة Steam أو من سطح المكتب. عندما تستخدم الجلسة أكثر من هذا الحد، يُضغط Steam ثم عمليات الجلسة المدعومة الأخرى في zRAM. حد مرن: لا يُغلَق شيء، لكن قد تتقطّع الألعاب أثناء استعادة الصفحات.
يتطلب مساحة تبديل zRAM، وهي غير متوفرة على هذا الجهاز.
حد VRAM
- ذاكرة الفيديو التي يُبلغ بها DXVK ألعاب Direct3D، فتخصّص للأنسجة مساحة أقل. تظل إعدادات DXVK الخاصة باللعبة هي الأولى. يسري في الجلسة التالية.
+ يُبلّغ ألعاب Direct3D من 9 إلى 12 بميزانية ذاكرة الفيديو هذه لتشجيع تقليل استخدامها. قد تتجاوزها الألعاب؛ لا يضيف هذا ترحيل ذاكرة GPU ولا يضمن منع الانهيار بسبب نفاد الذاكرة. يسري في الجلسة التالية.
تثبيت GPU على أعلى تردد له
لـ Adreno فقط. تقطّع أقل، مع استهلاك أكبر للبطارية والحرارة.
إصلاحات الجلسة
diff --git a/app/src/main/res/values-b+es+419/strings.xml b/app/src/main/res/values-b+es+419/strings.xml
index eff665227..e89919b32 100644
--- a/app/src/main/res/values-b+es+419/strings.xml
+++ b/app/src/main/res/values-b+es+419/strings.xml
@@ -587,7 +587,7 @@
Se aplica mientras se ejecuta el cliente de Steam, en modo Steam o desde el escritorio. Cuando la sesión usa más de esto, Steam y luego los demás procesos compatibles de la sesión se comprimen en zRAM. Es un límite flexible: no se cierra nada, pero los juegos pueden tener microcortes mientras se recuperan las páginas.
Requiere swap de zRAM, y este dispositivo no lo tiene.
Límite de VRAM
- La memoria de video que DXVK informa a los juegos Direct3D, para que calculen sus texturas con menos. Los ajustes de DXVK propios de un juego siguen teniendo prioridad. Se aplica en la próxima sesión.
+ Informa a los juegos Direct3D 9 a 12 de este presupuesto de memoria de video para reducir su uso. Los juegos pueden superarlo; no agrega paginación de GPU ni garantiza evitar fallos por falta de memoria. Se aplica en la próxima sesión.
Mantener la GPU a su reloj máximo
Solo Adreno. Menos microcortes, más consumo de batería y calor.
Correcciones de sesión
diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml
index 1b17dcbb1..3087a2cca 100644
--- a/app/src/main/res/values-bg/strings.xml
+++ b/app/src/main/res/values-bg/strings.xml
@@ -585,7 +585,7 @@
Прилага се, докато клиентът на Steam работи, в режим Steam или от работния плот. Когато сесията използва повече от това, Steam и след това другите поддържани процеси на сесията се компресират в zRAM. Меко ограничение: нищо не се затваря, но игрите може да засичат, докато страниците се връщат.
Изисква zRAM swap, който това устройство няма.
Ограничение на VRAM
- Видеопаметта, която DXVK отчита на игрите с Direct3D, за да планират текстури за по-малко. Собствените настройки на DXVK на играта имат предимство. Прилага се от следващата сесия.
+ Съобщава този бюджет за видео памет на игри с Direct3D 9 до 12, за да намали използването на памет. Игрите може да го надвишат; това не добавя странициране на GPU и не гарантира защита от сривове при недостиг на памет. Прилага се от следващата сесия.
Задръжте GPU на максималната му честота
Само за Adreno. По-малко засечки, по-голямо използване на батерията и повече топлина.
Корекции на сесията
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 58616db34..6d6058813 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -589,7 +589,7 @@
Platí, když běží klient Steam, v režimu Steam nebo z Plochy. Když relace použije víc, zkomprimuje se do zRAM Steam a poté další podporované procesy relace. Měkký limit: nic se nezavře, ale hry mohou trhat, než se stránky načtou zpět.
Vyžaduje swap zRAM, který toto zařízení nemá.
Limit VRAM
- Video paměť, kterou DXVK hlásí hrám Direct3D, aby počítaly s menším rozpočtem na textury. Vlastní nastavení DXVK hry mají přednost. Použije se od příští relace.
+ Hlásí hrám s Direct3D 9 až 12 tento rozpočet videopaměti, aby snížily její využití. Hry jej mohou překročit; nepřidává stránkování GPU ani nezaručuje ochranu před pády kvůli nedostatku paměti. Platí od příští relace.
Udržet GPU na nejvyšších taktech
Jen Adreno. Méně zadrhávání, více spotřeby baterie a tepla.
Opravy relace
diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml
index 36e87a79e..191c15c7b 100644
--- a/app/src/main/res/values-da/strings.xml
+++ b/app/src/main/res/values-da/strings.xml
@@ -585,7 +585,7 @@
Gælder, mens Steam-klienten kører, i Steam-tilstand eller fra skrivebordet. Når sessionen bruger mere end dette, komprimeres Steam og derefter sessionens andre understøttede processer i zRAM. En blød grænse: intet lukkes, men spil kan hakke, mens sider hentes tilbage.
Kræver zRAM-swap, som denne enhed ikke har.
VRAM-grænse
- Den videohukommelse, DXVK rapporterer til Direct3D-spil, så de budgetterer teksturer til mindre. Et spils egne DXVK-indstillinger har forrang. Træder i kraft ved næste session.
+ Rapporterer dette videohukommelsesbudget til Direct3D 9 til 12-spil for at mindske hukommelsesforbruget. Spil kan overskride det; dette tilføjer ikke GPU-paging og garanterer ikke beskyttelse mod nedbrud ved hukommelsesmangel. Gælder fra næste session.
Hold GPU’en på dens højeste clock
Kun Adreno. Færre hak, mere batteribrug og varme.
Sessionsrettelser
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 37c35d3f1..200e8e242 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -585,7 +585,7 @@
Gilt, solange der Steam-Client läuft, im Steam-Modus oder vom Desktop aus. Verbraucht die Sitzung mehr als diesen Wert, werden Steam und danach die übrigen unterstützten Prozesse der Sitzung in zRAM komprimiert. Ein weiches Limit: Nichts wird geschlossen, aber Spiele können ruckeln, während Seiten zurückgeladen werden.
Benötigt zRAM-Swap, den dieses Gerät nicht hat.
VRAM-Limit
- Der Grafikspeicher, den DXVK an Direct3D-Spiele meldet, damit sie weniger für Texturen einplanen. Eigene DXVK-Einstellungen eines Spiels haben Vorrang. Gilt ab der nächsten Sitzung.
+ Meldet Direct3D-9-bis-12-Spielen dieses Videospeicherbudget, um den Speicherverbrauch zu senken. Spiele können es überschreiten; dies fügt kein GPU-Paging hinzu und garantiert keinen Schutz vor Abstürzen durch Speichermangel. Gilt ab der nächsten Sitzung.
GPU auf höchstem Takt halten
Nur Adreno. Weniger Ruckler, mehr Akkuverbrauch und Wärme.
Sitzungskorrekturen
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index 25c7c40d7..d8a9e8d13 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -585,7 +585,7 @@
Ισχύει όσο τρέχει ο πελάτης Steam, σε λειτουργία Steam ή από την επιφάνεια εργασίας. Όταν η συνεδρία χρησιμοποιεί περισσότερη, το Steam και έπειτα οι άλλες υποστηριζόμενες διεργασίες της συνεδρίας συμπιέζονται στη zRAM. Ήπιο όριο: τίποτα δεν κλείνει, αλλά τα παιχνίδια μπορεί να κολλάνε όσο επιστρέφουν οι σελίδες.
Απαιτεί zRAM swap, που δεν υπάρχει σε αυτή τη συσκευή.
Όριο VRAM
- Η μνήμη βίντεο που αναφέρει το DXVK στα παιχνίδια Direct3D, ώστε να προγραμματίζουν υφές για λιγότερη. Οι δικές ρυθμίσεις DXVK του παιχνιδιού υπερισχύουν. Εφαρμόζεται στην επόμενη συνεδρία.
+ Αναφέρει αυτόν τον προϋπολογισμό μνήμης βίντεο σε παιχνίδια Direct3D 9 έως 12 για να μειωθεί η χρήση μνήμης. Τα παιχνίδια μπορεί να τον υπερβούν· δεν προσθέτει σελιδοποίηση GPU ούτε εγγυάται προστασία από σφάλματα έλλειψης μνήμης. Ισχύει από την επόμενη συνεδρία.
Διατήρηση της GPU στη μέγιστη συχνότητά της
Μόνο Adreno. Λιγότερα κολλήματα, μεγαλύτερη χρήση μπαταρίας και θερμότητα.
Διορθώσεις συνεδρίας
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 9f09dd2e9..ae6cda557 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -587,7 +587,7 @@
Se aplica mientras se ejecuta el cliente de Steam, en modo Steam o desde el escritorio. Cuando la sesión usa más de esto, Steam y luego los demás procesos compatibles de la sesión se comprimen en zRAM. Es un límite flexible: no se cierra nada, pero los juegos pueden tener tirones mientras se recuperan las páginas.
Requiere swap de zRAM, y este dispositivo no lo tiene.
Límite de VRAM
- La memoria de vídeo que DXVK indica a los juegos Direct3D, para que calculen sus texturas con menos. Los ajustes de DXVK propios de un juego siguen teniendo prioridad. Se aplica en la próxima sesión.
+ Informa a los juegos Direct3D 9 a 12 de este presupuesto de memoria de vídeo para reducir su uso. Los juegos pueden superarlo; no añade paginación de GPU ni garantiza evitar fallos por falta de memoria. Se aplica en la próxima sesión.
Mantener la GPU a su reloj máximo
Solo Adreno. Menos tirones, más consumo de batería y calor.
Correcciones de sesión
diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml
index 2bab8a4f8..b96591b1c 100644
--- a/app/src/main/res/values-fi/strings.xml
+++ b/app/src/main/res/values-fi/strings.xml
@@ -585,7 +585,7 @@
Koskee aikaa, jolloin Steam-asiakasohjelma on käynnissä, Steam-tilassa tai työpöydältä. Kun istunto käyttää tätä enemmän, Steam ja sen jälkeen istunnon muut tuetut prosessit pakataan zRAMiin. Pehmeä raja: mitään ei suljeta, mutta pelit voivat nykiä, kun sivuja luetaan takaisin.
Vaatii zRAM-swapin, jota tässä laitteessa ei ole.
VRAM-raja
- Videomuisti, jonka DXVK ilmoittaa Direct3D-peleille, jotta ne mitoittavat tekstuurit pienemmälle. Pelin omat DXVK-asetukset menevät edelle. Tulee voimaan seuraavassa istunnossa.
+ Ilmoittaa tämän videomuistibudjetin Direct3D 9–12 -peleille muistin käytön vähentämiseksi. Pelit voivat ylittää sen; tämä ei lisää GPU-sivutusta eikä takaa suojaa muistin loppumisesta johtuvilta kaatumisilta. Tulee voimaan seuraavassa istunnossa.
Pidä GPU huippukellotaajuudessaan
Vain Adreno. Vähemmän nykäyksiä, enemmän akun kulutusta ja lämpöä.
Istunnon korjaukset
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 6b20807dd..2b71aeadd 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -587,7 +587,7 @@
S\'applique tant que le client Steam fonctionne, en mode Steam ou depuis le bureau. Lorsque la session dépasse cette valeur, Steam puis les autres processus pris en charge de la session sont compressés dans zRAM. Limite souple : rien n\'est fermé, mais les jeux peuvent saccader pendant le rechargement des pages.
Nécessite un swap zRAM, dont cet appareil ne dispose pas.
Limite de VRAM
- La mémoire vidéo que DXVK signale aux jeux Direct3D, pour qu\'ils prévoient moins de textures. Les paramètres DXVK propres à un jeu restent prioritaires. Prendra effet à la prochaine session.
+ Signale ce budget de mémoire vidéo aux jeux Direct3D 9 à 12 pour réduire leur consommation. Les jeux peuvent le dépasser ; cela ne fournit pas de pagination GPU et ne garantit pas une protection contre les plantages par manque de mémoire. Prend effet à la prochaine session.
Maintenir le GPU à sa fréquence maximale
Uniquement pour Adreno. Moins de saccades, mais plus de consommation d\'énergie et de chaleur.
Correctifs de session
diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml
index ad4934b34..f039dd022 100644
--- a/app/src/main/res/values-hi/strings.xml
+++ b/app/src/main/res/values-hi/strings.xml
@@ -585,7 +585,7 @@
Steam क्लाइंट चलते समय लागू होती है, Steam मोड में या डेस्कटॉप से। जब सेशन इससे ज़्यादा इस्तेमाल करता है, तो Steam और फिर सेशन की दूसरी समर्थित प्रोसेस zRAM में कंप्रेस होती हैं। यह सॉफ़्ट सीमा है: कुछ बंद नहीं होता, लेकिन पेज वापस आते समय गेम अटक सकते हैं।
zRAM स्वैप चाहिए, जो इस डिवाइस में नहीं है।
VRAM सीमा
- वह वीडियो मेमोरी जो DXVK, Direct3D गेम को बताता है, ताकि वे टेक्सचर के लिए कम बजट रखें। गेम की अपनी DXVK सेटिंग को प्राथमिकता मिलती है। अगले सेशन से लागू होता है।
+ मेमोरी का उपयोग कम करने के लिए Direct3D 9 से 12 गेम को यह वीडियो मेमोरी बजट बताता है। गेम इसे पार कर सकते हैं; यह GPU पेजिंग नहीं जोड़ता और मेमोरी खत्म होने से क्रैश रोकने की गारंटी नहीं देता। अगले सत्र से लागू होगा।
GPU को उसकी टॉप क्लॉक पर बनाए रखें
सिर्फ़ Adreno के लिए। कम हिचकोले, लेकिन ज़्यादा बैटरी खर्च और गर्मी।
सेशन फ़िक्स
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index f1559e0f1..bfa3f5f5a 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -585,7 +585,7 @@
Akkor érvényes, amikor a Steam-kliens fut, Steam módban vagy az asztalról. Ha a munkamenet ennél többet használ, a Steam, majd a munkamenet többi támogatott folyamata a zRAM-ba tömörül. Puha korlát: semmi sem zárul be, de a játékok akadhatnak, amíg a lapok visszatöltődnek.
zRAM swap szükséges, amely ezen az eszközön nincs.
VRAM-korlát
- A DXVK által a Direct3D-játékoknak jelentett videomemória, így azok kevesebbel számolnak a textúráknál. A játék saját DXVK-beállításai elsőbbséget élveznek. A következő munkamenettől érvényes.
+ Ezt a videomemória-keretet jelzi a Direct3D 9–12 játékoknak a memóriahasználat csökkentésére. A játékok túlléphetik; nem biztosít GPU-lapozást, és nem garantál védelmet a memóriahiány miatti összeomlás ellen. A következő munkamenettől érvényes.
A GPU legmagasabb órajelen tartása
Csak Adreno. Kevesebb akadás, nagyobb akkumulátorhasználat és hőtermelés.
Munkamenet-javítások
diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml
index 4f0731184..902720023 100644
--- a/app/src/main/res/values-in/strings.xml
+++ b/app/src/main/res/values-in/strings.xml
@@ -583,7 +583,7 @@
Berlaku saat klien Steam berjalan, di mode Steam atau dari desktop. Saat sesi menggunakan lebih dari ini, Steam lalu proses lain yang didukung dalam sesi dikompres ke zRAM. Batas lunak: tidak ada yang ditutup, tetapi gim dapat tersendat saat halaman dimuat kembali.
Memerlukan swap zRAM, yang tidak dimiliki perangkat ini.
Batas VRAM
- Memori video yang dilaporkan DXVK ke gim Direct3D, sehingga gim menganggarkan tekstur lebih sedikit. Setelan DXVK milik gim tetap diutamakan. Berlaku pada sesi berikutnya.
+ Melaporkan anggaran memori video ini ke game Direct3D 9 hingga 12 untuk mengurangi penggunaan memori. Game dapat melampauinya; ini tidak menambahkan paging GPU atau menjamin perlindungan dari crash akibat kehabisan memori. Berlaku pada sesi berikutnya.
Pertahankan GPU pada clock tertingginya
Hanya Adreno. Lebih sedikit tersendat, lebih banyak penggunaan baterai dan panas.
Perbaikan sesi
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 23339bd24..1015207fe 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -583,7 +583,7 @@
Steamモードでもデスクトップからでも、Steamクライアントの実行中に適用されます。セッションの使用量がこの値を超えると、Steam、次にセッション内の対応する他のプロセスがzRAMに圧縮されます。ソフトな上限のため何も終了されませんが、ページの読み戻し中にゲームがカクつくことがあります。
zRAMスワップが必要ですが、このデバイスにはありません。
VRAM上限
- DXVKがDirect3Dゲームに報告するビデオメモリ量です。ゲームはこれに合わせてテクスチャ量を抑えます。ゲーム独自のDXVK設定が優先されます。次回のセッションから有効になります。
+ Direct3D 9~12のゲームにこのビデオメモリ予算を通知し、メモリ使用量の削減を促します。ゲームは予算を超える場合があります。GPUのページングを追加するものではなく、メモリ不足によるクラッシュの防止は保証されません。次のセッションから有効になります。
GPUを最高クロックに保つ
Adrenoのみ。スタッターは減りますが、消費電力と発熱が増えます。
セッション修正
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 3f43a0a1c..09b427356 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -583,7 +583,7 @@
Steam 모드나 데스크톱에서 Steam 클라이언트가 실행되는 동안 적용됩니다. 세션이 이 값보다 많이 사용하면 Steam과 세션의 다른 지원 프로세스를 차례로 zRAM으로 압축합니다. 소프트 제한이므로 종료되는 것은 없지만, 페이지를 다시 읽어 들이는 동안 게임이 끊길 수 있습니다.
zRAM 스왑이 필요하지만 이 기기에는 없습니다.
VRAM 제한
- DXVK가 Direct3D 게임에 보고하는 비디오 메모리로, 게임이 더 적은 양에 맞춰 텍스처를 할당합니다. 게임 자체의 DXVK 설정이 우선합니다. 다음 세션에 적용됩니다.
+ 메모리 사용량을 줄이도록 Direct3D 9~12 게임에 이 비디오 메모리 예산을 알립니다. 게임은 예산을 초과할 수 있으며, GPU 페이징을 추가하거나 메모리 부족으로 인한 충돌 방지를 보장하지 않습니다. 다음 세션부터 적용됩니다.
GPU를 최고 클럭으로 유지
Adreno에만 해당됩니다. 끊김이 줄어들지만 전력 소모와 발열이 증가합니다.
세션 수정
diff --git a/app/src/main/res/values-ms/strings.xml b/app/src/main/res/values-ms/strings.xml
index b0adb1463..f39b73212 100644
--- a/app/src/main/res/values-ms/strings.xml
+++ b/app/src/main/res/values-ms/strings.xml
@@ -583,7 +583,7 @@
Berkuat kuasa semasa klien Steam berjalan, dalam mod Steam atau dari desktop. Apabila sesi menggunakan lebih daripada ini, Steam dan kemudian proses lain sesi yang disokong dimampatkan ke dalam zRAM. Had lembut: tiada apa yang ditutup, tetapi permainan mungkin tersekat-sekat semasa halaman dibaca semula.
Memerlukan swap zRAM, yang tiada pada peranti ini.
Had VRAM
- Memori video yang dilaporkan DXVK kepada permainan Direct3D, supaya ia memperuntukkan tekstur untuk jumlah yang lebih kecil. Tetapan DXVK permainan itu sendiri tetap diutamakan. Berkuat kuasa pada sesi seterusnya.
+ Melaporkan bajet memori video ini kepada permainan Direct3D 9 hingga 12 untuk mengurangkan penggunaan memori. Permainan boleh melebihinya; ini tidak menambah paging GPU atau menjamin perlindungan daripada ranap akibat kehabisan memori. Berkuat kuasa pada sesi seterusnya.
Kekalkan GPU pada kelajuan tertinggi
Adreno sahaja. Kurang tersekat-sekat, lebih penggunaan bateri dan haba.
Pembetulan sesi
diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml
index 9cf373f05..6efdff992 100644
--- a/app/src/main/res/values-nb/strings.xml
+++ b/app/src/main/res/values-nb/strings.xml
@@ -585,7 +585,7 @@
Gjelder mens Steam-klienten kjører, i Steam-modus eller fra skrivebordet. Når sesjonen bruker mer enn dette, komprimeres Steam og deretter sesjonens andre støttede prosesser til zRAM. En myk grense: ingenting lukkes, men spill kan hakke mens sider hentes tilbake.
Krever zRAM-swap, som denne enheten ikke har.
VRAM-grense
- Videominnet DXVK rapporterer til Direct3D-spill, slik at de beregner teksturer for mindre. Spillets egne DXVK-innstillinger har forrang. Trer i kraft fra neste sesjon.
+ Rapporterer dette videominnebudsjettet til Direct3D 9 til 12-spill for å redusere minnebruken. Spill kan overskride det; dette legger ikke til GPU-sideveksling og garanterer ikke beskyttelse mot krasj ved minnemangel. Gjelder fra neste økt.
Hold GPU-en på toppfrekvens
Bare Adreno. Færre hikk, mer batteribruk og varme.
Sesjonsfikser
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index ee5325cf3..40e6503ca 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -585,7 +585,7 @@
Geldt terwijl de Steam-client draait, in de Steam-modus of vanaf de desktop. Als de sessie meer gebruikt dan dit, worden Steam en daarna de andere ondersteunde processen van de sessie in zRAM gecomprimeerd. Een zachte limiet: er wordt niets gesloten, maar games kunnen haperen terwijl pagina’s terugkomen.
Vereist zRAM-swap, die dit apparaat niet heeft.
VRAM-limiet
- Het videogeheugen dat DXVK aan Direct3D-games meldt, zodat ze minder ruimte voor texturen plannen. De eigen DXVK-instellingen van een game gaan voor. Geldt vanaf de volgende sessie.
+ Meldt dit videogeheugenbudget aan Direct3D 9- tot 12-games om het geheugengebruik te verlagen. Games kunnen het overschrijden; dit voegt geen GPU-paging toe en garandeert geen bescherming tegen crashes door geheugentekort. Geldt vanaf de volgende sessie.
GPU op hoogste kloksnelheid houden
Alleen Adreno. Minder haperingen, meer batterijverbruik en warmte.
Sessiefixes
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index a6b177159..0265a3ab8 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -589,7 +589,7 @@
Działa, gdy działa klient Steam, w trybie Steam lub z pulpitu. Gdy sesja używa więcej, Steam, a następnie inne obsługiwane procesy sesji są kompresowane do zRAM. Miękki limit: nic nie jest zamykane, ale gry mogą się zacinać podczas wczytywania stron z powrotem.
Wymaga swapu zRAM, którego to urządzenie nie ma.
Limit VRAM
- Pamięć wideo, którą DXVK zgłasza grom Direct3D, aby planowały tekstury na mniej. Własne ustawienia DXVK gry mają pierwszeństwo. Działa od następnej sesji.
+ Zgłasza ten budżet pamięci wideo grom Direct3D od 9 do 12, aby ograniczyć zużycie pamięci. Gry mogą go przekroczyć; nie dodaje to stronicowania GPU ani nie gwarantuje ochrony przed awariami z powodu braku pamięci. Działa od następnej sesji.
Utrzymuj GPU na najwyższym taktowaniu
Tylko Adreno. Mniej przycięć, większe zużycie baterii i więcej ciepła.
Poprawki sesji
diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml
index 543de9b58..aaff56fc0 100644
--- a/app/src/main/res/values-pt-rPT/strings.xml
+++ b/app/src/main/res/values-pt-rPT/strings.xml
@@ -587,7 +587,7 @@
Aplica-se enquanto o cliente Steam está em execução, no modo Steam ou a partir do ambiente de trabalho. Quando a sessão utiliza mais do que isto, o Steam e depois os outros processos suportados da sessão são comprimidos na zRAM. Um limite flexível: nada é fechado, mas os jogos podem ter soluços enquanto as páginas são repostas.
Requer swap em zRAM, que este dispositivo não tem.
Limite de VRAM
- A memória de vídeo que o DXVK indica aos jogos Direct3D, para que reservem menos para texturas. As definições de DXVK do próprio jogo têm prioridade. Aplica-se na próxima sessão.
+ Comunica este orçamento de memória de vídeo aos jogos Direct3D 9 a 12 para reduzir a utilização de memória. Os jogos podem excedê-lo; isto não adiciona paginação da GPU nem garante proteção contra falhas por falta de memória. Aplica-se na próxima sessão.
Manter a GPU na frequência máxima
Apenas Adreno. Menos soluços, mais consumo de bateria e mais calor.
Correções da sessão
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index be0368f50..31ea84d9d 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -587,7 +587,7 @@
Vale enquanto o cliente Steam está em execução, no modo Steam ou pela área de trabalho. Quando a sessão usa mais que isso, a Steam e depois os outros processos compatíveis da sessão são comprimidos na zRAM. Um limite flexível: nada é fechado, mas os jogos podem travar enquanto as páginas voltam.
Requer swap em zRAM, que este dispositivo não tem.
Limite de VRAM
- A memória de vídeo que o DXVK informa aos jogos Direct3D, para que reservem menos para texturas. As configurações de DXVK do próprio jogo têm prioridade. Vale a partir da próxima sessão.
+ Informa este orçamento de memória de vídeo aos jogos Direct3D 9 a 12 para reduzir o uso de memória. Os jogos podem excedê-lo; isso não adiciona paginação de GPU nem garante proteção contra falhas por falta de memória. Entra em vigor na próxima sessão.
Manter a GPU no clock máximo
Só em Adreno. Menos engasgos, mais gasto de bateria e mais calor.
Correções da sessão
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
index 08ecc9183..859638f0f 100644
--- a/app/src/main/res/values-ro/strings.xml
+++ b/app/src/main/res/values-ro/strings.xml
@@ -587,7 +587,7 @@
Se aplică cât rulează clientul Steam, în modul Steam sau de pe desktop. Când sesiunea folosește mai mult de atât, Steam și apoi celelalte procese acceptate ale sesiunii sunt comprimate în zRAM. O limită flexibilă: nimic nu se închide, dar jocurile pot sacada cât paginile revin.
Necesită swap zRAM, pe care acest dispozitiv nu îl are.
Limită VRAM
- Memoria video pe care DXVK o raportează jocurilor Direct3D, ca acestea să aloce mai puțin pentru texturi. Setările DXVK proprii ale unui joc au prioritate. Intră în vigoare la sesiunea următoare.
+ Raportează acest buget de memorie video jocurilor Direct3D 9 până la 12 pentru a reduce utilizarea memoriei. Jocurile îl pot depăși; nu adaugă paginare GPU și nu garantează protecție împotriva blocărilor cauzate de lipsa memoriei. Se aplică din sesiunea următoare.
Fixează GPU-ul la frecvența maximă
Doar Adreno. Mai puține întreruperi, consum mai mare de baterie și căldură.
Remedieri de sesiune
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 451f06077..a710de925 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -608,7 +608,7 @@
Действует, пока работает клиент Steam, в режиме Steam или с рабочего стола. Когда сессия использует больше этого значения, Steam, а затем другие поддерживаемые процессы сессии сжимаются в zRAM. Мягкий лимит: ничего не закрывается, но игры могут подтормаживать, пока страницы возвращаются.
Нужен своп zRAM, которого на этом устройстве нет.
Лимит VRAM
- Объём видеопамяти, который DXVK сообщает играм Direct3D, чтобы они рассчитывали текстуры на меньший объём. Собственные настройки DXVK игры имеют приоритет. Вступит в силу в следующей сессии.
+ Сообщает играм Direct3D 9–12 этот бюджет видеопамяти для снижения её использования. Игры могут его превысить; это не добавляет подкачку памяти GPU и не гарантирует защиту от сбоев из-за нехватки памяти. Действует со следующего сеанса.
Поддерживать максимальную частоту GPU
Только для Adreno. Меньше подтормаживаний, но больше энергопотребления и нагрева.
Исправления сессии
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index 5958734ae..b1546f900 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -585,7 +585,7 @@
Gäller medan Steam-klienten körs, i Steam-läge eller från skrivbordet. När sessionen använder mer än detta komprimeras Steam och sedan sessionens övriga processer som stöds till zRAM. En mjuk gräns: inget stängs, men spel kan hacka medan sidor läses tillbaka.
Kräver zRAM-swap, vilket den här enheten saknar.
VRAM-gräns
- Videominnet som DXVK rapporterar till Direct3D-spel, så att de budgeterar texturer för mindre. Ett spels egna DXVK-inställningar har företräde. Börjar gälla vid nästa session.
+ Rapporterar denna videominnesbudget till Direct3D 9 till 12-spel för att minska minnesanvändningen. Spel kan överskrida den; detta lägger inte till sidväxling av GPU-minne och garanterar inte skydd mot krascher vid minnesbrist. Gäller från nästa session.
Håll GPU:n på dess högsta klockfrekvens
Bara Adreno. Färre hack, högre batteriförbrukning och mer värme.
Sessionsfixar
diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml
index e795ca955..a28cdeeaf 100644
--- a/app/src/main/res/values-th/strings.xml
+++ b/app/src/main/res/values-th/strings.xml
@@ -583,7 +583,7 @@
มีผลขณะไคลเอนต์ Steam ทำงาน ทั้งในโหมด Steam หรือจากเดสก์ท็อป เมื่อเซสชันใช้เกินค่านี้ Steam และโปรเซสอื่นที่รองรับของเซสชันจะถูกบีบอัดลงใน zRAM ตามลำดับ เป็นขีดจำกัดแบบอ่อน: ไม่มีอะไรถูกปิด แต่เกมอาจกระตุกขณะดึงหน้าหน่วยความจำกลับมา
ต้องใช้ zRAM swap ซึ่งอุปกรณ์นี้ไม่มี
ขีดจำกัด VRAM
- หน่วยความจำวิดีโอที่ DXVK รายงานต่อเกม Direct3D เพื่อให้เกมจัดสรรเท็กซ์เจอร์น้อยลง การตั้งค่า DXVK ของเกมเองยังมีผลเหนือกว่า มีผลในเซสชันถัดไป
+ แจ้งงบประมาณหน่วยความจำวิดีโอนี้ให้เกม Direct3D 9 ถึง 12 เพื่อลดการใช้หน่วยความจำ เกมอาจใช้เกินงบได้ ฟีเจอร์นี้ไม่ได้เพิ่มการสลับหน้าหน่วยความจำ GPU และไม่รับประกันว่าจะป้องกันการแครชเมื่อหน่วยความจำหมด มีผลในเซสชันถัดไป
ตรึง GPU ไว้ที่ความเร็วสัญญาณนาฬิกาสูงสุด
สำหรับ Adreno เท่านั้น สะดุดน้อยลง แต่ใช้แบตเตอรี่และเกิดความร้อนมากขึ้น
การแก้ไขเซสชัน
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 19151d434..794f7225e 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -585,7 +585,7 @@
Steam istemcisi Steam oturumunda veya masaüstünden çalışırken uygulanır. Oturum bundan fazlasını kullandığında önce Steam, ardından oturumun desteklenen diğer işlemleri zRAM\'e sıkıştırılır. Yumuşak bir sınırdır: hiçbir şey kapatılmaz, ancak sayfalar geri yüklenirken oyunlar takılabilir.
Bu cihazda olmayan zRAM takası gerekir.
VRAM sınırı
- DXVK\'nin Direct3D oyunlarına bildirdiği video belleği; böylece oyunlar dokuları daha az belleğe göre ayarlar. Oyunun kendi DXVK ayarları yine önceliklidir. Sonraki oturumda geçerli olur.
+ Bellek kullanımını azaltmak için Direct3D 9–12 oyunlarına bu video belleği bütçesini bildirir. Oyunlar bütçeyi aşabilir; GPU sayfalaması eklemez veya bellek yetersizliğinden kaynaklanan çökmeleri önlemeyi garanti etmez. Sonraki oturumda geçerli olur.
GPU\'yu en yüksek saat hızında tut
Yalnızca Adreno. Daha az takılma, daha fazla pil tüketimi ve ısınma.
Oturum düzeltmeleri
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 03f96a3a0..90cb9d7e7 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -589,7 +589,7 @@
Діє, поки працює клієнт Steam, у режимі Steam або з робочого столу. Коли сеанс використовує більше цього значення, Steam, а потім інші підтримувані процеси сеансу стискаються в zRAM. Мʼякий ліміт: нічого не закривається, але ігри можуть підвисати, поки сторінки повертаються.
Потрібен своп zRAM, якого на цьому пристрої немає.
Ліміт VRAM
- Обсяг відеопамʼяті, який DXVK повідомляє іграм Direct3D, щоб вони розраховували текстури на менше. Власні налаштування DXVK гри мають пріоритет. Набуде чинності в наступному сеансі.
+ Повідомляє іграм Direct3D 9–12 цей бюджет відеопам’яті для зменшення її використання. Ігри можуть його перевищити; це не додає підкачку пам’яті GPU й не гарантує захисту від збоїв через нестачу пам’яті. Діє з наступного сеансу.
Тримати GPU на максимальній частоті
Лише Adreno. Менше запинок, вища витрата заряду та нагрів.
Виправлення сеансу
diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml
index 61910dbbf..b4c2c9ec6 100644
--- a/app/src/main/res/values-vi/strings.xml
+++ b/app/src/main/res/values-vi/strings.xml
@@ -583,7 +583,7 @@
Áp dụng khi client Steam đang chạy, ở chế độ Steam hoặc từ desktop. Khi phiên dùng nhiều hơn mức này, Steam rồi đến các tiến trình được hỗ trợ khác của phiên sẽ bị nén vào zRAM. Giới hạn mềm: không có gì bị đóng, nhưng game có thể giật khi các trang được nạp lại.
Cần swap zRAM, thiết bị này không có.
Giới hạn VRAM
- Bộ nhớ video mà DXVK báo cho game Direct3D, để chúng dùng ít texture hơn. Thiết lập DXVK riêng của game vẫn được ưu tiên. Có hiệu lực từ phiên sau.
+ Báo ngân sách bộ nhớ video này cho các trò chơi Direct3D 9 đến 12 để giảm mức dùng bộ nhớ. Trò chơi có thể vượt ngân sách; tính năng này không bổ sung phân trang GPU hay bảo đảm tránh lỗi do hết bộ nhớ. Có hiệu lực ở phiên tiếp theo.
Giữ GPU ở xung nhịp cao nhất
Chỉ dành cho Adreno. Ít giật hơn, dùng nhiều pin và nhiệt hơn.
Các bản sửa phiên
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 83e786d27..ab4ea5242 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -583,7 +583,7 @@
在 Steam 客户端运行时生效,无论是 Steam 模式还是从桌面启动。会话使用量超过此值时,会先将 Steam、再将会话中其他受支持的进程压缩到 zRAM。这是软上限:不会关闭任何进程,但在页面读回时游戏可能卡顿。
需要 zRAM 交换空间,但此设备不支持。
VRAM 上限
- DXVK 向 Direct3D 游戏报告的显存大小,使游戏按更少的显存分配纹理。游戏自身的 DXVK 设置仍然优先。下次会话时生效。
+ 向 Direct3D 9 至 12 游戏报告此显存预算,以促使游戏减少内存使用。游戏可能超出预算;此功能不提供 GPU 分页,也不保证避免内存不足导致的崩溃。下次会话生效。
把 GPU 锁定在最高频率
仅限 Adreno。卡顿更少,但更耗电、更发热。
会话修复
diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml
index f43523bc5..f555a538c 100644
--- a/app/src/main/res/values-zh-rHK/strings.xml
+++ b/app/src/main/res/values-zh-rHK/strings.xml
@@ -583,7 +583,7 @@
在 Steam 用戶端執行時生效,無論是 Steam 模式或從桌面啟動。當會話的用量超過此值時,會先將 Steam、再將會話中其他受支援的程序壓縮到 zRAM。這是軟性上限:不會關閉任何程式,但在分頁讀回時遊戲可能會卡頓。
需要 zRAM 交換空間,但此裝置沒有。
VRAM 上限
- DXVK 向 Direct3D 遊戲回報的顯示記憶體,讓遊戲以較少的量規劃紋理。遊戲本身的 DXVK 設定仍優先。下次會話生效。
+ 向 Direct3D 9 至 12 遊戲報告此顯存預算,以促使遊戲減少記憶體用量。遊戲可能超出預算;此功能不提供 GPU 分頁,也不保證避免因記憶體不足而崩潰。下次工作階段生效。
讓 GPU 保持最高頻率
只限 Adreno。減少卡頓,但更耗電、更發熱。
會話修正
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index f5546b265..6fe964d7f 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -583,7 +583,7 @@
在 Steam 用戶端執行時生效,無論是 Steam 模式或從桌面啟動。當工作階段的用量超過此值時,會先將 Steam、再將工作階段中其他受支援的程序壓縮到 zRAM。這是軟性上限:不會關閉任何程式,但在分頁讀回時遊戲可能會卡頓。
需要 zRAM 交換空間,但這部裝置沒有。
VRAM 上限
- DXVK 向 Direct3D 遊戲回報的顯示記憶體,讓遊戲以較少的量規劃紋理。遊戲本身的 DXVK 設定仍優先。下次工作階段生效。
+ 向 Direct3D 9 至 12 遊戲回報此顯示記憶體預算,以促使遊戲減少記憶體使用量。遊戲可能超出預算;此功能不提供 GPU 分頁,也不保證避免記憶體不足造成的當機。下次工作階段生效。
讓 GPU 保持最高頻率
僅適用於 Adreno。卡頓更少,但耗電和發熱更多。
工作階段修復
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 56c27ae79..df5cf9ac2 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -632,7 +632,7 @@
Applies while the Steam client runs, in Steam mode or from the desktop. When the session uses more than this, Steam and then the session\'s other supported processes are compressed into zRAM. A soft cap: nothing is closed, but games may stutter while pages come back.
Needs zRAM swap, which this device does not have.
VRAM cap
- The video memory DXVK reports to Direct3D games, so they budget textures for less. A game\'s own DXVK settings still win. Takes effect at the next session.
+ Reports this video memory budget to Direct3D 9 to 12 games to encourage lower memory use. Games may exceed it; this does not add GPU paging or guarantee protection from out-of-memory crashes. Takes effect at the next session.
Hold the GPU at its top clock
Adreno only. Fewer hitches, more battery use and heat.
Session fixes
diff --git a/docs/development/vram-budget.md b/docs/development/vram-budget.md
new file mode 100644
index 000000000..fe790f9ac
--- /dev/null
+++ b/docs/development/vram-budget.md
@@ -0,0 +1,20 @@
+# Reported video memory budget
+
+The Performance VRAM setting enables `VK_LAYER_DROIDDECK_vram_cap` for games and reports smaller device-local `VK_EXT_memory_budget` budgets. DXVK and vkd3d-proton can use these reports when choosing memory pools. The driver still supplies real heap sizes, usage figures, memory types, and actual allocation results. DXVK also receives its existing `dxgi.maxDeviceMemory` setting. A lower driver budget remains lower; the layer never increases it.
+
+This is a budget hint, not a physical reservation or a GPU paging implementation. Games may exceed it. On UMA hardware, host-visible Vulkan allocations can share the same device-local heap as textures. Rejecting every allocation above a fixed total can therefore break required upload buffers and other allocations, rather than make a game reduce its texture pool. The layer does not intercept `vkAllocateMemory` or `vkFreeMemory`, and preserves the real heap size so individual allocations larger than the budget remain Vulkan-valid.
+
+The layer activates only with `DROIDDECK_VRAM_CAP=1` and a positive `DROIDDECK_VRAM_CAP_MB`. With the Performance setting on Auto, the game environment does not enable it. Explicit DXVK configuration remains available, while the Vulkan layer also covers D3D12 and games that replace their DXVK configuration.
+
+## Physical investigation
+
+On an 8 GB Pocket FIT Elite with DD Turnip 0.4.0, Proton 11-12.1, and Caravan SandWitch build 25301828:
+
+- A native Vulkan probe reported a device-local heap of 5,650,776,064 bytes. All exposed memory types used the same device-local UMA heap. The initial implementation clamped both heap and budget to 2048 MiB; the revised layer preserves heap capacity and clamps only the budget.
+- The initial hard allocation cap caused the existing save to fail a required 603,979,776-byte D3D12 allocation. Android survived, but the game crashed. Discord testers also reported crashes after reaching the cap in Fallout 76.
+- In the initial test with allocation rejection disabled, vkd3d-proton logged the smaller 2048 MiB heap and budget. Caravan still exhausted system memory while loading the save. A reported budget alone does not solve this workload.
+- DX11 loaded the same save and supported movement around the station at approximately 60 FPS for more than five minutes, both with and without the reported budget layer. Graphics settings were unchanged. This establishes a renderer workaround, not proof that the layer solved Caravan's OOM.
+
+Native regression coverage exercises core and KHR memory-property queries, chained budget structures, unchanged real usage above the budget, separate heap types, disabled behavior, device lifecycle dispatch, and successful driver allocations whose individual and combined sizes exceed the reported budget.
+
+The Vulkan specification describes [`heapBudget` as a guideline](https://docs.vulkan.org/refpages/latest/refpages/source/VkPhysicalDeviceMemoryBudgetPropertiesEXT.html). Transparent movement between device-local and host-local memory requires driver and operating-system support for [pageable device-local memory](https://docs.vulkan.org/refpages/latest/refpages/source/vkAllocateMemory.html).
diff --git a/tools/components/recipes.json b/tools/components/recipes.json
index 88ae5b79d..8278e966f 100644
--- a/tools/components/recipes.json
+++ b/tools/components/recipes.json
@@ -23,7 +23,8 @@
"outputs": [
"app/src/main/assets/linuxfs/usr/local/bin/gamescope",
"app/src/main/assets/linuxfs/usr/local/lib/droiddeck-vr/droiddeck/bin/linuxarm64/driver_droiddeck.so",
- "app/src/main/assets/linuxfs/usr/local/lib/droiddeck-gpuload/libVkLayer_droiddeck_gpuload.so"
+ "app/src/main/assets/linuxfs/usr/local/lib/droiddeck-gpuload/libVkLayer_droiddeck_gpuload.so",
+ "app/src/main/assets/linuxfs/usr/local/lib/droiddeck-gpuload/libVkLayer_droiddeck_vramcap.so"
],
"ndk": true,
"packages": [
diff --git a/tools/gpuload/build.sh b/tools/gpuload/build.sh
index b2729de7f..683057c38 100755
--- a/tools/gpuload/build.sh
+++ b/tools/gpuload/build.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Builds VK_LAYER_DROIDDECK_gpu_load for the arm64 guest: tools/gpuload/build.sh [--native] OUT
-# OUT gets libVkLayer_droiddeck_gpuload.so and its implicit-layer manifest.
+# OUT gets libVkLayer_droiddeck_gpuload.so, libVkLayer_droiddeck_vramcap.so and their implicit-layer manifests.
set -euo pipefail
here=$(cd "$(dirname "$0")" && pwd)
repo=$(cd "$here/../.." && pwd)
@@ -36,10 +36,15 @@ cmd=(sh -c '
build/gpuload/test_gpuload_busy
cc -std=c11 -O2 -Wall -Wextra -Werror -Ibuild/gpuload/include -Itools/gpuload/src -o build/gpuload/test_gpuload_ring tools/gpuload/tests/test_gpuload_ring.c
build/gpuload/test_gpuload_ring
+ cc -std=c11 -O2 -Wall -Wextra -Werror -Ibuild/gpuload/include -Itools/gpuload/src -pthread -Wno-unused-parameter -Wno-missing-field-initializers -o build/gpuload/test_vramcap_budget tools/gpuload/tests/test_vramcap_budget.c
+ build/gpuload/test_vramcap_budget
aarch64-linux-gnu-gcc -std=c11 -shared -fPIC -O2 -Wall -Wextra -Werror -Wno-unused-parameter -Wno-missing-field-initializers \
-fvisibility=hidden -pthread -Wl,-z,defs -Ibuild/gpuload/include -Itools/gpuload/src \
-o build/gpuload/out/libVkLayer_droiddeck_gpuload.so tools/gpuload/src/vk_layer_droiddeck_gpuload.c
- aarch64-linux-gnu-strip --strip-unneeded build/gpuload/out/libVkLayer_droiddeck_gpuload.so')
+ aarch64-linux-gnu-gcc -std=c11 -shared -fPIC -O2 -Wall -Wextra -Werror -Wno-unused-parameter -Wno-missing-field-initializers \
+ -fvisibility=hidden -pthread -Wl,-z,defs -Ibuild/gpuload/include -Itools/gpuload/src \
+ -o build/gpuload/out/libVkLayer_droiddeck_vramcap.so tools/gpuload/src/vk_layer_droiddeck_vramcap.c
+ aarch64-linux-gnu-strip --strip-unneeded build/gpuload/out/libVkLayer_droiddeck_gpuload.so build/gpuload/out/libVkLayer_droiddeck_vramcap.so')
if [ "$native" = 1 ]; then
(cd "$repo" && "${cmd[@]}")
else
@@ -47,7 +52,8 @@ else
"${DROIDDECK_BUILD_IMAGE:-droiddeck-local-cross:24.04-v3}" "${cmd[@]}"
fi
-cp "$here/layer/VK_LAYER_DROIDDECK_gpu_load.json" "$work/out/"
+cp "$here/layer/VK_LAYER_DROIDDECK_gpu_load.json" "$here/layer/VK_LAYER_DROIDDECK_vram_cap.json" "$work/out/"
mkdir -p "$out"
-cp "$work/out/libVkLayer_droiddeck_gpuload.so" "$work/out/VK_LAYER_DROIDDECK_gpu_load.json" "$out/"
+cp "$work/out/libVkLayer_droiddeck_gpuload.so" "$work/out/libVkLayer_droiddeck_vramcap.so" \
+ "$work/out/VK_LAYER_DROIDDECK_gpu_load.json" "$work/out/VK_LAYER_DROIDDECK_vram_cap.json" "$out/"
echo "built $out"
diff --git a/tools/gpuload/layer/VK_LAYER_DROIDDECK_vram_cap.json b/tools/gpuload/layer/VK_LAYER_DROIDDECK_vram_cap.json
new file mode 100644
index 000000000..9bff13fe7
--- /dev/null
+++ b/tools/gpuload/layer/VK_LAYER_DROIDDECK_vram_cap.json
@@ -0,0 +1,20 @@
+{
+ "file_format_version": "1.2.0",
+ "layer": {
+ "name": "VK_LAYER_DROIDDECK_vram_cap",
+ "type": "GLOBAL",
+ "library_path": "/usr/local/lib/droiddeck-gpuload/libVkLayer_droiddeck_vramcap.so",
+ "api_version": "1.3.0",
+ "implementation_version": "1",
+ "description": "Reports a smaller video memory budget to DXVK and vkd3d-proton",
+ "functions": {
+ "vkNegotiateLoaderLayerInterfaceVersion": "DroidDeckVramCap_NegotiateLoaderLayerInterfaceVersion"
+ },
+ "enable_environment": {
+ "DROIDDECK_VRAM_CAP": "1"
+ },
+ "disable_environment": {
+ "DROIDDECK_VRAM_CAP_DISABLE": "1"
+ }
+ }
+}
diff --git a/tools/gpuload/src/vk_layer_droiddeck_vramcap.c b/tools/gpuload/src/vk_layer_droiddeck_vramcap.c
new file mode 100644
index 000000000..eefa5608d
--- /dev/null
+++ b/tools/gpuload/src/vk_layer_droiddeck_vramcap.c
@@ -0,0 +1,206 @@
+#define _GNU_SOURCE
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "vramcap_budget.h"
+
+#define EXPORT __attribute__((visibility("default")))
+
+static uint64_t g_cap;
+
+__attribute__((constructor)) static void init(void) {
+ g_cap = vramcap_parse_mb(getenv("DROIDDECK_VRAM_CAP_MB"));
+}
+
+struct inst {
+ struct inst *next_in_list;
+ VkInstance handle;
+ PFN_vkGetInstanceProcAddr gipa;
+ PFN_vkDestroyInstance destroy;
+ PFN_vkGetPhysicalDeviceMemoryProperties2 mem2;
+ PFN_vkGetPhysicalDeviceMemoryProperties2 mem2_khr;
+};
+
+struct dev {
+ struct dev *next_in_list;
+ VkDevice handle;
+ PFN_vkGetDeviceProcAddr gdpa;
+ PFN_vkDestroyDevice destroy;
+};
+
+static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
+static struct inst *g_insts;
+static struct dev *g_devs;
+static int g_announced;
+
+static void *key(const void *obj) { return *(void *const *)obj; }
+
+static struct inst *inst_for(const void *obj) {
+ struct inst *r;
+ pthread_mutex_lock(&g_lock);
+ for (r = g_insts; r && key(r->handle) != key(obj); r = r->next_in_list) {}
+ pthread_mutex_unlock(&g_lock);
+ return r;
+}
+
+static struct dev *dev_for(const void *obj) {
+ struct dev *r;
+ pthread_mutex_lock(&g_lock);
+ for (r = g_devs; r && key(r->handle) != key(obj); r = r->next_in_list) {}
+ pthread_mutex_unlock(&g_lock);
+ return r;
+}
+
+static void say(const char *what) {
+ fprintf(stderr, "[droiddeck-vram-cap] pid %d: %s\n", (int)getpid(), what);
+}
+
+static void announce(void) {
+ if (__atomic_exchange_n(&g_announced, 1, __ATOMIC_RELAXED)) return;
+ char line[96];
+ snprintf(line, sizeof(line), "reported device memory budget %llu MB", (unsigned long long)(g_cap >> 20));
+ say(line);
+}
+
+static void clamp_properties2(PFN_vkGetPhysicalDeviceMemoryProperties2 next, VkPhysicalDevice pd,
+ VkPhysicalDeviceMemoryProperties2 *out) {
+ next(pd, out);
+ for (VkBaseOutStructure *s = out->pNext; s; s = s->pNext)
+ if (s->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT) {
+ vramcap_budget(&out->memoryProperties, (VkPhysicalDeviceMemoryBudgetPropertiesEXT *)s, g_cap);
+ if (g_cap) announce();
+ }
+}
+
+static void VKAPI_CALL GetMemoryProperties2(VkPhysicalDevice pd, VkPhysicalDeviceMemoryProperties2 *out) {
+ struct inst *in = inst_for(pd);
+ if (in) clamp_properties2(in->mem2, pd, out);
+}
+
+static void VKAPI_CALL GetMemoryProperties2KHR(VkPhysicalDevice pd, VkPhysicalDeviceMemoryProperties2 *out) {
+ struct inst *in = inst_for(pd);
+ if (in) clamp_properties2(in->mem2_khr, pd, out);
+}
+
+static VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *ci, const VkAllocationCallbacks *alloc, VkInstance *out) {
+ VkLayerInstanceCreateInfo *link = (VkLayerInstanceCreateInfo *)ci->pNext;
+ while (link && !(link->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO && link->function == VK_LAYER_LINK_INFO))
+ link = (VkLayerInstanceCreateInfo *)link->pNext;
+ if (!link) return VK_ERROR_INITIALIZATION_FAILED;
+ PFN_vkGetInstanceProcAddr next_gipa = link->u.pLayerInfo->pfnNextGetInstanceProcAddr;
+ link->u.pLayerInfo = link->u.pLayerInfo->pNext;
+ PFN_vkCreateInstance create = (PFN_vkCreateInstance)next_gipa(VK_NULL_HANDLE, "vkCreateInstance");
+ if (!create) return VK_ERROR_INITIALIZATION_FAILED;
+ struct inst *in = calloc(1, sizeof(*in));
+ if (!in) return VK_ERROR_OUT_OF_HOST_MEMORY;
+ VkResult r = create(ci, alloc, out);
+ if (r != VK_SUCCESS) { free(in); return r; }
+ in->handle = *out;
+ in->gipa = next_gipa;
+ in->destroy = (PFN_vkDestroyInstance)next_gipa(*out, "vkDestroyInstance");
+ in->mem2 = (PFN_vkGetPhysicalDeviceMemoryProperties2)next_gipa(*out, "vkGetPhysicalDeviceMemoryProperties2");
+ in->mem2_khr = (PFN_vkGetPhysicalDeviceMemoryProperties2)next_gipa(*out, "vkGetPhysicalDeviceMemoryProperties2KHR");
+ pthread_mutex_lock(&g_lock);
+ in->next_in_list = g_insts;
+ g_insts = in;
+ pthread_mutex_unlock(&g_lock);
+ return VK_SUCCESS;
+}
+
+static void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *alloc) {
+ struct inst *in = inst_for(instance);
+ if (!in) return;
+ PFN_vkDestroyInstance destroy = in->destroy;
+ pthread_mutex_lock(&g_lock);
+ for (struct inst **p = &g_insts; *p; p = &(*p)->next_in_list)
+ if (*p == in) { *p = in->next_in_list; break; }
+ pthread_mutex_unlock(&g_lock);
+ free(in);
+ if (destroy) destroy(instance, alloc);
+}
+
+static VkLayerDeviceCreateInfo *device_chain(const VkDeviceCreateInfo *ci, VkLayerFunction function) {
+ VkLayerDeviceCreateInfo *c = (VkLayerDeviceCreateInfo *)ci->pNext;
+ while (c && !(c->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO && c->function == function))
+ c = (VkLayerDeviceCreateInfo *)c->pNext;
+ return c;
+}
+
+static VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice pd, const VkDeviceCreateInfo *ci, const VkAllocationCallbacks *alloc,
+ VkDevice *out) {
+ VkLayerDeviceCreateInfo *link = device_chain(ci, VK_LAYER_LINK_INFO);
+ if (!link) return VK_ERROR_INITIALIZATION_FAILED;
+ PFN_vkGetInstanceProcAddr next_gipa = link->u.pLayerInfo->pfnNextGetInstanceProcAddr;
+ PFN_vkGetDeviceProcAddr next_gdpa = link->u.pLayerInfo->pfnNextGetDeviceProcAddr;
+ link->u.pLayerInfo = link->u.pLayerInfo->pNext;
+ struct inst *in = inst_for(pd);
+ PFN_vkCreateDevice create = (PFN_vkCreateDevice)next_gipa(in ? in->handle : VK_NULL_HANDLE, "vkCreateDevice");
+ if (!create) return VK_ERROR_INITIALIZATION_FAILED;
+ struct dev *d = calloc(1, sizeof(*d));
+ if (!d) return VK_ERROR_OUT_OF_HOST_MEMORY;
+ VkResult r = create(pd, ci, alloc, out);
+ if (r != VK_SUCCESS) { free(d); return r; }
+ d->handle = *out;
+ d->gdpa = next_gdpa;
+ d->destroy = (PFN_vkDestroyDevice)next_gdpa(*out, "vkDestroyDevice");
+ pthread_mutex_lock(&g_lock);
+ d->next_in_list = g_devs;
+ g_devs = d;
+ pthread_mutex_unlock(&g_lock);
+ return VK_SUCCESS;
+}
+
+static void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *alloc) {
+ struct dev *d = dev_for(device);
+ if (!d) return;
+ pthread_mutex_lock(&g_lock);
+ for (struct dev **p = &g_devs; *p; p = &(*p)->next_in_list)
+ if (*p == d) { *p = d->next_in_list; break; }
+ pthread_mutex_unlock(&g_lock);
+ PFN_vkDestroyDevice destroy = d->destroy;
+ free(d);
+ if (destroy) destroy(device, alloc);
+}
+
+EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL DroidDeckVramCap_GetDeviceProcAddr(VkDevice device, const char *name);
+
+EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL DroidDeckVramCap_GetInstanceProcAddr(VkInstance instance, const char *name) {
+ if (!strcmp(name, "vkCreateInstance")) return (PFN_vkVoidFunction)CreateInstance;
+ if (!strcmp(name, "vkDestroyInstance")) return (PFN_vkVoidFunction)DestroyInstance;
+ if (!strcmp(name, "vkCreateDevice")) return (PFN_vkVoidFunction)CreateDevice;
+ if (!strcmp(name, "vkDestroyDevice")) return (PFN_vkVoidFunction)DestroyDevice;
+ if (!strcmp(name, "vkGetInstanceProcAddr")) return (PFN_vkVoidFunction)DroidDeckVramCap_GetInstanceProcAddr;
+ if (!strcmp(name, "vkGetDeviceProcAddr")) return (PFN_vkVoidFunction)DroidDeckVramCap_GetDeviceProcAddr;
+ if (!instance) return NULL;
+ struct inst *in = inst_for(instance);
+ if (!in) return NULL;
+ if (g_cap) {
+ if (!strcmp(name, "vkGetPhysicalDeviceMemoryProperties2") && in->mem2) return (PFN_vkVoidFunction)GetMemoryProperties2;
+ if (!strcmp(name, "vkGetPhysicalDeviceMemoryProperties2KHR") && in->mem2_khr)
+ return (PFN_vkVoidFunction)GetMemoryProperties2KHR;
+ }
+ return in->gipa(instance, name);
+}
+
+EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL DroidDeckVramCap_GetDeviceProcAddr(VkDevice device, const char *name) {
+ if (!strcmp(name, "vkGetDeviceProcAddr")) return (PFN_vkVoidFunction)DroidDeckVramCap_GetDeviceProcAddr;
+ if (!strcmp(name, "vkDestroyDevice")) return (PFN_vkVoidFunction)DestroyDevice;
+ struct dev *d = dev_for(device);
+ if (!d) return NULL;
+ return d->gdpa(device, name);
+}
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL DroidDeckVramCap_NegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *v) {
+ if (v->loaderLayerInterfaceVersion > 2) v->loaderLayerInterfaceVersion = 2;
+ v->pfnGetInstanceProcAddr = DroidDeckVramCap_GetInstanceProcAddr;
+ v->pfnGetDeviceProcAddr = DroidDeckVramCap_GetDeviceProcAddr;
+ v->pfnGetPhysicalDeviceProcAddr = NULL;
+ return VK_SUCCESS;
+}
diff --git a/tools/gpuload/src/vramcap_budget.h b/tools/gpuload/src/vramcap_budget.h
new file mode 100644
index 000000000..3d77b1c95
--- /dev/null
+++ b/tools/gpuload/src/vramcap_budget.h
@@ -0,0 +1,32 @@
+#ifndef VRAMCAP_BUDGET_H
+#define VRAMCAP_BUDGET_H
+
+#include
+#include
+
+static inline uint64_t vramcap_parse_mb(const char *text) {
+ if (!text || !*text) return 0;
+ uint64_t value = 0, limit = UINT64_MAX >> 20;
+ for (; *text; text++) {
+ if (*text < '0' || *text > '9') return 0;
+ unsigned digit = (unsigned)(*text - '0');
+ if (value > (limit - digit) / 10) return 0;
+ value = value * 10 + digit;
+ }
+ return value << 20;
+}
+
+static inline VkDeviceSize vramcap_clamp(VkDeviceSize value, uint64_t cap) {
+ return cap && value > cap ? cap : value;
+}
+
+static inline void vramcap_budget(const VkPhysicalDeviceMemoryProperties *p,
+ VkPhysicalDeviceMemoryBudgetPropertiesEXT *budget, uint64_t cap) {
+ for (uint32_t i = 0; i < p->memoryHeapCount && i < VK_MAX_MEMORY_HEAPS; i++)
+ if (p->memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) {
+ budget->heapBudget[i] = vramcap_clamp(budget->heapBudget[i], cap);
+ budget->heapBudget[i] = vramcap_clamp(budget->heapBudget[i], p->memoryHeaps[i].size);
+ }
+}
+
+#endif
diff --git a/tools/gpuload/tests/test_vramcap_budget.c b/tools/gpuload/tests/test_vramcap_budget.c
new file mode 100644
index 000000000..40c6f9d8c
--- /dev/null
+++ b/tools/gpuload/tests/test_vramcap_budget.c
@@ -0,0 +1,154 @@
+#include
+#include
+#include "../src/vk_layer_droiddeck_vramcap.c"
+
+static int instance_dispatch, device_dispatch;
+static void *instance_object = &instance_dispatch, *physical_object = &instance_dispatch;
+static void *device_object = &device_dispatch;
+static VkInstance instance;
+static VkPhysicalDevice physical;
+static VkDevice device;
+static unsigned allocations, frees, destroyed_devices, destroyed_instances;
+
+static void VKAPI_CALL memory_properties(VkPhysicalDevice pd, VkPhysicalDeviceMemoryProperties *out) {
+ assert(pd == physical);
+ *out = (VkPhysicalDeviceMemoryProperties){
+ .memoryHeapCount = 3,
+ .memoryHeaps = {{8ULL << 30, VK_MEMORY_HEAP_DEVICE_LOCAL_BIT}, {4ULL << 30, 0},
+ {512ULL << 20, VK_MEMORY_HEAP_DEVICE_LOCAL_BIT}},
+ .memoryTypeCount = 1,
+ .memoryTypes = {{VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 0}},
+ };
+}
+
+static void VKAPI_CALL memory_properties2(VkPhysicalDevice pd, VkPhysicalDeviceMemoryProperties2 *out) {
+ memory_properties(pd, &out->memoryProperties);
+ for (VkBaseOutStructure *p = out->pNext; p; p = p->pNext)
+ if (p->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT) {
+ VkPhysicalDeviceMemoryBudgetPropertiesEXT *b = (void *)p;
+ b->heapBudget[0] = 6ULL << 30;
+ b->heapBudget[1] = 3ULL << 30;
+ b->heapBudget[2] = 256ULL << 20;
+ b->heapUsage[0] = 3ULL << 30;
+ }
+}
+
+static VkResult VKAPI_CALL allocate(VkDevice d, const VkMemoryAllocateInfo *info,
+ const VkAllocationCallbacks *a, VkDeviceMemory *out) {
+ assert(d == device && info->allocationSize == (3ULL << 30));
+ *out = (VkDeviceMemory)(uintptr_t)++allocations;
+ return VK_SUCCESS;
+}
+
+static void VKAPI_CALL release(VkDevice d, VkDeviceMemory m, const VkAllocationCallbacks *a) {
+ assert(d == device && m);
+ frees++;
+}
+
+static void VKAPI_CALL destroy_device(VkDevice d, const VkAllocationCallbacks *a) {
+ assert(d == device);
+ destroyed_devices++;
+}
+
+static void VKAPI_CALL destroy_instance(VkInstance in, const VkAllocationCallbacks *a) {
+ assert(in == instance);
+ destroyed_instances++;
+}
+
+static PFN_vkVoidFunction VKAPI_CALL gdpa(VkDevice d, const char *name) {
+ assert(d == device);
+ if (!strcmp(name, "vkAllocateMemory")) return (PFN_vkVoidFunction)allocate;
+ if (!strcmp(name, "vkFreeMemory")) return (PFN_vkVoidFunction)release;
+ if (!strcmp(name, "vkDestroyDevice")) return (PFN_vkVoidFunction)destroy_device;
+ return NULL;
+}
+
+static VkResult VKAPI_CALL create_device(VkPhysicalDevice pd, const VkDeviceCreateInfo *ci,
+ const VkAllocationCallbacks *a, VkDevice *out) {
+ assert(pd == physical);
+ *out = device;
+ return VK_SUCCESS;
+}
+
+static VkResult VKAPI_CALL create_instance(const VkInstanceCreateInfo *ci, const VkAllocationCallbacks *a, VkInstance *out) {
+ *out = instance;
+ return VK_SUCCESS;
+}
+
+static PFN_vkVoidFunction VKAPI_CALL gipa(VkInstance in, const char *name) {
+ assert(in == instance || in == VK_NULL_HANDLE);
+ if (!strcmp(name, "vkCreateInstance")) return (PFN_vkVoidFunction)create_instance;
+ if (!strcmp(name, "vkDestroyInstance")) return (PFN_vkVoidFunction)destroy_instance;
+ if (!strcmp(name, "vkCreateDevice")) return (PFN_vkVoidFunction)create_device;
+ if (!strcmp(name, "vkGetPhysicalDeviceMemoryProperties")) return (PFN_vkVoidFunction)memory_properties;
+ if (!strcmp(name, "vkGetPhysicalDeviceMemoryProperties2") || !strcmp(name, "vkGetPhysicalDeviceMemoryProperties2KHR"))
+ return (PFN_vkVoidFunction)memory_properties2;
+ return NULL;
+}
+
+int main(void) {
+ assert(vramcap_parse_mb("2048") == (2ULL << 30));
+ assert(vramcap_parse_mb(NULL) == 0 && vramcap_parse_mb("") == 0 && vramcap_parse_mb("0") == 0);
+ const char *bad[] = {"-1", "+1", " 1024", "1024 ", "1GB", "18446744073709551616", "17592186044416"};
+ for (size_t i = 0; i < sizeof(bad) / sizeof(bad[0]); i++) assert(vramcap_parse_mb(bad[i]) == 0);
+ assert(vramcap_parse_mb("17592186044415") == ((UINT64_MAX >> 20) << 20));
+
+ instance = (VkInstance)&instance_object;
+ physical = (VkPhysicalDevice)&physical_object;
+ device = (VkDevice)&device_object;
+ g_cap = 2ULL << 30;
+ VkLayerInstanceLink il = {.pfnNextGetInstanceProcAddr = gipa};
+ VkLayerInstanceCreateInfo ic = {.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO,
+ .function = VK_LAYER_LINK_INFO, .u.pLayerInfo = &il};
+ VkInstanceCreateInfo ici = {.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pNext = &ic};
+ VkInstance got_instance;
+ assert(CreateInstance(&ici, NULL, &got_instance) == VK_SUCCESS && got_instance == instance);
+ VkPhysicalDeviceMemoryProperties p;
+ PFN_vkGetPhysicalDeviceMemoryProperties get = (void *)DroidDeckVramCap_GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties");
+ assert(get == memory_properties);
+ get(physical, &p);
+ assert(p.memoryHeaps[0].size == (8ULL << 30) && p.memoryHeaps[1].size == (4ULL << 30));
+ assert(p.memoryHeaps[2].size == (512ULL << 20));
+ assert(p.memoryTypes[0].propertyFlags == (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
+
+ const char *names[] = {"vkGetPhysicalDeviceMemoryProperties2", "vkGetPhysicalDeviceMemoryProperties2KHR"};
+ for (size_t i = 0; i < 2; i++) {
+ VkPhysicalDeviceMemoryBudgetPropertiesEXT b = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT};
+ VkPhysicalDeviceIDProperties id = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES, .pNext = &b};
+ VkPhysicalDeviceMemoryProperties2 p2 = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2, .pNext = &id};
+ PFN_vkGetPhysicalDeviceMemoryProperties2 get2 = (void *)DroidDeckVramCap_GetInstanceProcAddr(instance, names[i]);
+ get2(physical, &p2);
+ assert(p2.memoryProperties.memoryHeaps[0].size == (8ULL << 30));
+ assert(b.heapBudget[0] == g_cap && b.heapBudget[1] == (3ULL << 30));
+ assert(b.heapBudget[2] == (256ULL << 20));
+ assert(b.heapUsage[0] == (3ULL << 30));
+ assert(p2.pNext == &id && id.pNext == &b);
+ }
+
+ VkLayerDeviceLink dl = {.pfnNextGetInstanceProcAddr = gipa, .pfnNextGetDeviceProcAddr = gdpa};
+ VkLayerDeviceCreateInfo dc = {.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO,
+ .function = VK_LAYER_LINK_INFO, .u.pLayerInfo = &dl};
+ VkDeviceCreateInfo dci = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .pNext = &dc};
+ VkDevice got_device;
+ assert(CreateDevice(physical, &dci, NULL, &got_device) == VK_SUCCESS && got_device == device);
+ PFN_vkAllocateMemory next_allocate = (void *)DroidDeckVramCap_GetDeviceProcAddr(device, "vkAllocateMemory");
+ PFN_vkFreeMemory next_free = (void *)DroidDeckVramCap_GetDeviceProcAddr(device, "vkFreeMemory");
+ assert(next_allocate == allocate && next_free == release);
+ VkMemoryAllocateInfo ai = {.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, .allocationSize = 3ULL << 30};
+ VkDeviceMemory blocks[2];
+ for (unsigned i = 0; i < 2; i++) assert(next_allocate(device, &ai, NULL, &blocks[i]) == VK_SUCCESS);
+ assert(allocations == 2);
+ for (unsigned i = 0; i < 2; i++) next_free(device, blocks[i], NULL);
+ assert(frees == 2);
+
+ g_cap = 0;
+ assert(DroidDeckVramCap_GetInstanceProcAddr(instance, names[0]) == (PFN_vkVoidFunction)memory_properties2);
+ assert(DroidDeckVramCap_GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties") == (PFN_vkVoidFunction)memory_properties);
+ PFN_vkDestroyDevice destroy = (void *)DroidDeckVramCap_GetInstanceProcAddr(instance, "vkDestroyDevice");
+ assert(destroy == DestroyDevice);
+ destroy(device, NULL);
+ DestroyInstance(instance, NULL);
+ assert(destroyed_devices == 1 && destroyed_instances == 1 && !g_devs && !g_insts);
+ puts("test_vramcap_budget: ok");
+ return 0;
+}
diff --git a/tools/linuxfs/overlay/usr/local/bin/droiddeck-game-env b/tools/linuxfs/overlay/usr/local/bin/droiddeck-game-env
index 886bf10bd..dfa5681f3 100755
--- a/tools/linuxfs/overlay/usr/local/bin/droiddeck-game-env
+++ b/tools/linuxfs/overlay/usr/local/bin/droiddeck-game-env
@@ -360,6 +360,8 @@ def vram_cap(env):
cap = "dxgi.maxDeviceMemory = %d" % int(value)
own = result.get("DXVK_CONFIG", "").strip().strip(";").strip()
result["DXVK_CONFIG"] = cap + "; " + own if own else cap
+ result["DROIDDECK_VRAM_CAP"] = "1"
+ result["DROIDDECK_VRAM_CAP_MB"] = value
return result
diff --git a/tools/release/runtime_inputs.py b/tools/release/runtime_inputs.py
index 9682ef46a..b03f5235d 100644
--- a/tools/release/runtime_inputs.py
+++ b/tools/release/runtime_inputs.py
@@ -92,7 +92,8 @@ def required():
'layer/VK_LAYER_DROIDDECK_vr.json', 'layer/VK_LAYER_DROIDDECK_vr_implicit.json',
'layer/libdroiddeck_vr_scheduling.so']]
paths += ['assets/linuxfs/usr/local/lib/droiddeck-gpuload/' + name for name in
- ['libVkLayer_droiddeck_gpuload.so', 'VK_LAYER_DROIDDECK_gpu_load.json']]
+ ['libVkLayer_droiddeck_gpuload.so', 'VK_LAYER_DROIDDECK_gpu_load.json',
+ 'libVkLayer_droiddeck_vramcap.so', 'VK_LAYER_DROIDDECK_vram_cap.json']]
for side in ['left', 'right']:
paths += [f'assets/linuxfs/usr/local/lib/droiddeck-vr/droiddeck/resources/rendermodels/droiddeck_hand_{side}/{name}'
for name in [f'droiddeck_hand_{side}.json', 'hand.mtl', 'hand.png', 'hand_open.obj', 'hand_fist.obj',
diff --git a/tools/tests/test_game_environment.py b/tools/tests/test_game_environment.py
index cd58fba4d..fcbb10357 100644
--- a/tools/tests/test_game_environment.py
+++ b/tools/tests/test_game_environment.py
@@ -747,6 +747,12 @@ class GameEnvironmentTest(unittest.TestCase):
"dxgi.maxDeviceMemory = 2048; dxvk.maxFrameRate = 60")
for off in ({}, {"BL_VRAM_MB": "0"}, {"BL_VRAM_MB": "lots"}, {"BL_VRAM_MB": "²"}, {"BL_VRAM_MB": "-1"}):
self.assertNotIn("DXVK_CONFIG", cap(off))
+ self.assertNotIn("DROIDDECK_VRAM_CAP", cap(off))
+ self.assertNotIn("DROIDDECK_VRAM_CAP_MB", cap(off))
+
+ def test_the_vram_cap_also_turns_on_the_vulkan_layer_that_holds_the_game_to_it(self):
+ env = MODULE["vram_cap"]({"BL_VRAM_MB": "3072", "DXVK_CONFIG": "dxgi.maxDeviceMemory = 16384"})
+ self.assertEqual((env["DROIDDECK_VRAM_CAP"], env["DROIDDECK_VRAM_CAP_MB"]), ("1", "3072"))
def test_a_games_wine_sync_choice_also_reaches_its_setup_runs(self):
env = {"BL_SYNC": "1", "BL_SYNC_FALLBACK": "1", "BL_FSYNC_FIRST": "0", "OTHER": "kept"}