Compare commits
37 Commits
Author | SHA1 | Date | |
---|---|---|---|
ece36b274d | |||
f3cc2e5703 | |||
5a39d3c4a1 | |||
cc51a03af9 | |||
567c64e149 | |||
36f00985d3 | |||
748d87adcc | |||
0fd47ff490 | |||
f088c3d344 | |||
905a191e28 | |||
ab0491817e | |||
5de6ae426e | |||
69ced3a6e8 | |||
2e43d01d36 | |||
7373ec5792 | |||
de162a648b | |||
131baebe2a | |||
187372cbde | |||
022d495335 | |||
c1372ed775 | |||
a16682cfd3 | |||
7c53b69c30 | |||
33a4d7d1ba | |||
391e08dd27 | |||
b5cf8b8af9 | |||
55043c8afc | |||
5d73a9f5fc | |||
2c9ab5e45f | |||
d536cc8ae6 | |||
d751da84f9 | |||
11aae9cfbc | |||
b96794e72b | |||
f1d1670b0b | |||
b8de72de8f | |||
eebc39228d | |||
9daf029f35 | |||
51a27032f0 |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -34,7 +34,7 @@ about: Something doesn't work correctly in Ryujinx. Note that game-specific issu
|
||||
- OS: *(e.g. Windows 10)*
|
||||
- CPU: *(e.g. i7-6700)*
|
||||
- GPU: *(e.g. NVIDIA RTX 2070)*
|
||||
- RAM: *(e.g. 16GB)*
|
||||
- RAM: *(e.g. 16GiB)*
|
||||
- Applied Mods : [ Yes (Which ones) / No ]
|
||||
|
||||
### Additional context?
|
||||
|
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@ -52,26 +52,22 @@ jobs:
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Ensure NuGet Source
|
||||
uses: fabriciomurta/ensure-nuget-source@v1
|
||||
- name: Get git short hash
|
||||
id: git_short_hash
|
||||
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
- name: Clear
|
||||
run: dotnet clean && dotnet nuget locals all --clear
|
||||
- name: Build
|
||||
run: dotnet build -c "${{ matrix.configuration }}" /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER
|
||||
run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER
|
||||
- name: Test
|
||||
run: dotnet test --no-build -c "${{ matrix.configuration }}"
|
||||
- name: Publish Ryujinx
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx --self-contained
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx --self-contained true
|
||||
if: github.event_name == 'pull_request'
|
||||
- name: Publish Ryujinx.Headless.SDL2
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Headless.SDL2 --self-contained
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Headless.SDL2 --self-contained true
|
||||
if: github.event_name == 'pull_request'
|
||||
- name: Publish Ryujinx.Ava
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava /p:Version="1.0.0" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Ava
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Ava --self-contained true
|
||||
if: github.event_name == 'pull_request'
|
||||
- name: Upload Ryujinx artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
|
16
.github/workflows/release.yml
vendored
16
.github/workflows/release.yml
vendored
@ -29,10 +29,6 @@ jobs:
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Ensure NuGet Source
|
||||
uses: fabriciomurta/ensure-nuget-source@v1
|
||||
- name: Clear
|
||||
run: dotnet clean && dotnet nuget locals all --clear
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
@ -51,9 +47,9 @@ jobs:
|
||||
run: "mkdir release_output"
|
||||
- name: Publish Windows
|
||||
run: |
|
||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained
|
||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained
|
||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows_ava/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Ava --self-contained
|
||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx --self-contained true
|
||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained true
|
||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Ava --self-contained true
|
||||
- name: Packing Windows builds
|
||||
run: |
|
||||
pushd publish_windows
|
||||
@ -71,9 +67,9 @@ jobs:
|
||||
|
||||
- name: Publish Linux
|
||||
run: |
|
||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained
|
||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained
|
||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux_ava/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Ava --self-contained
|
||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx --self-contained true
|
||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained true
|
||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Ava --self-contained true
|
||||
|
||||
- name: Packing Linux builds
|
||||
run: |
|
||||
|
@ -1,15 +1,11 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace ARMeilleure.Common
|
||||
{
|
||||
static class BitUtils
|
||||
{
|
||||
private static readonly sbyte[] HbsNibbleLut;
|
||||
|
||||
static BitUtils()
|
||||
{
|
||||
HbsNibbleLut = new sbyte[] { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
|
||||
}
|
||||
private static ReadOnlySpan<sbyte> HbsNibbleLut => new sbyte[] { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
|
||||
|
||||
public static long FillWithOnes(int bits)
|
||||
{
|
||||
|
@ -25,13 +25,13 @@ namespace ARMeilleure.Diagnostics
|
||||
_funcTabSizeCounter = new PollingCounter("addr-tab-alloc", this, () => _funcTabSize / 1024d / 1024d)
|
||||
{
|
||||
DisplayName = "AddressTable Total Bytes Allocated",
|
||||
DisplayUnits = "MB"
|
||||
DisplayUnits = "MiB"
|
||||
};
|
||||
|
||||
_funcTabLeafSizeCounter = new PollingCounter("addr-tab-leaf-alloc", this, () => _funcTabLeafSize / 1024d / 1024d)
|
||||
{
|
||||
DisplayName = "AddressTable Total Leaf Bytes Allocated",
|
||||
DisplayUnits = "MB"
|
||||
DisplayUnits = "MiB"
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ You can check out the compatibility list [here](https://github.com/Ryujinx/Ryuji
|
||||
|
||||
## Usage
|
||||
|
||||
To run this emulator, your PC must be equipped with at least 8GB of RAM; failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
|
||||
To run this emulator, your PC must be equipped with at least 8GiB of RAM; failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
|
||||
|
||||
See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide) on how to set up the emulator.
|
||||
|
||||
|
@ -34,10 +34,10 @@ namespace Ryujinx.Audio.Renderer.Utils
|
||||
|
||||
writer.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
writer.Write(Encoding.ASCII.GetBytes("RIFF"));
|
||||
writer.Write("RIFF"u8);
|
||||
writer.Write((int)(writer.BaseStream.Length - 8));
|
||||
writer.Write(Encoding.ASCII.GetBytes("WAVE"));
|
||||
writer.Write(Encoding.ASCII.GetBytes("fmt "));
|
||||
writer.Write("WAVE"u8);
|
||||
writer.Write("fmt "u8);
|
||||
writer.Write(16);
|
||||
writer.Write((short)1);
|
||||
writer.Write((short)GetChannelCount());
|
||||
@ -45,7 +45,7 @@ namespace Ryujinx.Audio.Renderer.Utils
|
||||
writer.Write(GetSampleRate() * GetChannelCount() * sizeof(short));
|
||||
writer.Write((short)(GetChannelCount() * sizeof(short)));
|
||||
writer.Write((short)(sizeof(short) * 8));
|
||||
writer.Write(Encoding.ASCII.GetBytes("data"));
|
||||
writer.Write("data"u8);
|
||||
writer.Write((int)(writer.BaseStream.Length - HeaderSize));
|
||||
|
||||
writer.Seek((int)currentPos, SeekOrigin.Begin);
|
||||
|
@ -10,6 +10,7 @@ using Ryujinx.Ava.Ui.Windows;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using Ryujinx.Ui.Common.Helper;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
@ -64,8 +65,7 @@ namespace Ryujinx.Ava
|
||||
if (result == UserResult.Yes)
|
||||
{
|
||||
var path = Process.GetCurrentProcess().MainModule.FileName;
|
||||
var info = new ProcessStartInfo() { FileName = path, UseShellExecute = false };
|
||||
var proc = Process.Start(info);
|
||||
var proc = Process.Start(path, CommandLineState.Arguments);
|
||||
desktop.Shutdown();
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
@ -741,7 +741,7 @@ namespace Ryujinx.Ava
|
||||
}
|
||||
}
|
||||
|
||||
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? HLE.MemoryConfiguration.MemoryConfiguration6GB : HLE.MemoryConfiguration.MemoryConfiguration4GB;
|
||||
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? HLE.MemoryConfiguration.MemoryConfiguration6GiB : HLE.MemoryConfiguration.MemoryConfiguration4GiB;
|
||||
|
||||
IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None;
|
||||
|
||||
|
@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (Kann Fehler verursachen)",
|
||||
"SettingsTabSystemExpandDramSize": "Erweitere DRAM Größe auf 6GB",
|
||||
"SettingsTabSystemExpandDramSize": "Erweitere DRAM Größe auf 6GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignoriere fehlende Dienste",
|
||||
"SettingsTabGraphics": "Grafik",
|
||||
"SettingsTabGraphicsAPI": "Grafik-API",
|
||||
@ -440,7 +440,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "Verwendung einer Software-Seitentabelle für die Adressumsetzung. Höchste Genauigkeit, aber langsamste Leistung.",
|
||||
"MemoryManagerHostTooltip": "Direkte Zuordnung von Speicher im Host-Adressraum. Viel schnellere JIT-Kompilierung und Ausführung.",
|
||||
"MemoryManagerUnsafeTooltip": "Direkte Zuordnung des Speichers, aber keine Maskierung der Adresse innerhalb des Gastadressraums vor dem Zugriff. Schneller, aber auf Kosten der Sicherheit. Die Gastanwendung kann von überall in Ryujinx auf den Speicher zugreifen, daher sollte in diesem Modus nur Programme ausgeführt werden denen vertraut wird.",
|
||||
"DRamTooltip": "Erhöht den Arbeitsspeicher des emulierten Systems von 4 GB auf 6 GB.\n\nDies ist nur für Texturenpakete mit höherer Auflösung oder Mods mit 4K-Auflösung nützlich. Diese Option verbessert NICHT die Leistung.\n\nIm Zweifelsfall AUS lassen.",
|
||||
"DRamTooltip": "Erhöht den Arbeitsspeicher des emulierten Systems von 4 GiB auf 6 GiB.\n\nDies ist nur für Texturenpakete mit höherer Auflösung oder Mods mit 4K-Auflösung nützlich. Diese Option verbessert NICHT die Leistung.\n\nIm Zweifelsfall AUS lassen.",
|
||||
"IgnoreMissingServicesTooltip": "Durch diese Option werden nicht implementierte Dienste der Switch-Firmware ignoriert. Dies kann dabei helfen, Abstürze beim Starten bestimmter Spiele zu umgehen.\n\nIm Zweifelsfall AUS lassen.",
|
||||
"GraphicsBackendThreadingTooltip": "Führt Grafik-Backend Befehle auf einem zweiten Thread aus.\n\nDies beschleunigt die Shader-Kompilierung, reduziert Stottern und verbessert die Leistung auf GPU-Treibern ohne eigene Multithreading-Unterstützung. Geringfügig bessere Leistung bei Treibern mit Multithreading.\n\nIm Zweifelsfall auf AUTO stellen.",
|
||||
"GalThreadingTooltip": "Führt Grafik-Backend Befehle auf einem zweiten Thread aus.\n\nDies Beschleunigt die Shader-Kompilierung, reduziert Stottern und verbessert die Leistung auf GPU-Treibern ohne eigene Multithreading-Unterstützung. Geringfügig bessere Leistung bei Treibern mit Multithreading.\n\nIm Zweifelsfall auf auf AUTO stellen.",
|
||||
@ -583,7 +583,7 @@
|
||||
"SettingsTabGraphicsBackend": "Grafik-Backend:",
|
||||
"SettingsTabGraphicsBackendTooltip": "Verwendendetes Grafik-Backend",
|
||||
"SettingsEnableTextureRecompression": "Textur-Rekompression",
|
||||
"SettingsEnableTextureRecompressionTooltip": "Komprimiert bestimmte Texturen, um den VRAM-Verbrauch zu reduzieren.\n\nEmpfohlen für die Verwendung von GPUs, die weniger als 4 GB VRAM haben.\n\nIm Zweifelsfall AUS lassen",
|
||||
"SettingsEnableTextureRecompressionTooltip": "Komprimiert bestimmte Texturen, um den VRAM-Verbrauch zu reduzieren.\n\nEmpfohlen für die Verwendung von GPUs, die weniger als 4 GiB VRAM haben.\n\nIm Zweifelsfall AUS lassen",
|
||||
"SettingsTabGraphicsPreferredGpu": "Bevorzugte GPU:",
|
||||
"SettingsTabGraphicsPreferredGpuTooltip": "Wähle die Grafikkarte aus, die mit dem Vulkan Grafik-Backend verwendet werden soll.\n\nDies hat keinen Einfluss auf die GPU die OpenGL verwendet.\n\nIm Zweifelsfall die als \"dGPU\" gekennzeichnete GPU auswählen. Diese Einstellung unberührt lassen, wenn keine zur Auswahl steht.",
|
||||
"SettingsAppRequiredRestartMessage": "Ein Neustart von Ryujinx ist erforderlich",
|
||||
|
@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Μικροδιορθώσεις",
|
||||
"SettingsTabSystemHacksNote": " (Μπορεί να προκαλέσουν αστάθεια)",
|
||||
"SettingsTabSystemExpandDramSize": "Επέκταση μεγέθους DRAM στα 6GB",
|
||||
"SettingsTabSystemExpandDramSize": "Επέκταση μεγέθους DRAM στα 6GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Αγνόηση υπηρεσιών που λείπουν",
|
||||
"SettingsTabGraphics": "Γραφικά",
|
||||
"SettingsTabGraphicsAPI": "API Γραφικά",
|
||||
@ -440,7 +440,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "Χρησιμοποιήστε έναν πίνακα σελίδων λογισμικού για τη μετάφραση διευθύνσεων. Υψηλότερη ακρίβεια αλλά πιο αργή απόδοση.",
|
||||
"MemoryManagerHostTooltip": "Απευθείας αντιστοίχιση της μνήμης στον χώρο διευθύνσεων υπολογιστή υποδοχής. Πολύ πιο γρήγορη μεταγλώττιση και εκτέλεση JIT.",
|
||||
"MemoryManagerUnsafeTooltip": "Απευθείας χαρτογράφηση της μνήμης, αλλά μην καλύπτετε τη διεύθυνση εντός του χώρου διευθύνσεων επισκέπτη πριν από την πρόσβαση. Πιο γρήγορα, αλλά με κόστος ασφάλειας. Η εφαρμογή μπορεί να έχει πρόσβαση στη μνήμη από οπουδήποτε στο Ryujinx, επομένως εκτελείτε μόνο προγράμματα που εμπιστεύεστε με αυτήν τη λειτουργία.",
|
||||
"DRamTooltip": "Επεκτείνει την ποσότητα της μνήμης στο εξομοιούμενο σύστημα από 4 GB σε 6 GB",
|
||||
"DRamTooltip": "Επεκτείνει την ποσότητα της μνήμης στο εξομοιούμενο σύστημα από 4 GiB σε 6 GiB",
|
||||
"IgnoreMissingServicesTooltip": "Ενεργοποίηση ή απενεργοποίηση της αγνοώησης για υπηρεσίες που λείπουν",
|
||||
"GraphicsBackendThreadingTooltip": "Ενεργοποίηση Πολυνηματικής Επεξεργασίας Γραφικών",
|
||||
"GalThreadingTooltip": "Εκτελεί εντολές γραφικών σε ένα δεύτερο νήμα. Επιτρέπει την πολυνηματική μεταγλώττιση Shader σε χρόνο εκτέλεσης, μειώνει το τρεμόπαιγμα και βελτιώνει την απόδοση των προγραμμάτων οδήγησης χωρίς τη δική τους υποστήριξη πολλαπλών νημάτων. Ποικίλες κορυφαίες επιδόσεις σε προγράμματα οδήγησης με multithreading. Μπορεί να χρειαστεί επανεκκίνηση του Ryujinx για να απενεργοποιήσετε σωστά την ενσωματωμένη λειτουργία πολλαπλών νημάτων του προγράμματος οδήγησης ή ίσως χρειαστεί να το κάνετε χειροκίνητα για να έχετε την καλύτερη απόδοση.",
|
||||
|
@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (may cause instability)",
|
||||
"SettingsTabSystemExpandDramSize": "Expand DRAM Size to 6GB",
|
||||
"SettingsTabSystemExpandDramSize": "Use alternative memory layout (Developers)",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignore Missing Services",
|
||||
"SettingsTabGraphics": "Graphics",
|
||||
"SettingsTabGraphicsAPI": "Graphics API",
|
||||
@ -440,7 +440,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "Use a software page table for address translation. Highest accuracy but slowest performance.",
|
||||
"MemoryManagerHostTooltip": "Directly map memory in the host address space. Much faster JIT compilation and execution.",
|
||||
"MemoryManagerUnsafeTooltip": "Directly map memory, but do not mask the address within the guest address space before access. Faster, but at the cost of safety. The guest application can access memory from anywhere in Ryujinx, so only run programs you trust with this mode.",
|
||||
"DRamTooltip": "Increases the amount of memory on the emulated system from 4GB to 6GB.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.",
|
||||
"DRamTooltip": "Utilizes an alternative MemoryMode layout to mimic a Switch development model.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.",
|
||||
"IgnoreMissingServicesTooltip": "Ignores unimplemented Horizon OS services. This may help in bypassing crashes when booting certain games.\n\nLeave OFF if unsure.",
|
||||
"GraphicsBackendThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
|
||||
"GalThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
|
||||
@ -583,14 +583,16 @@
|
||||
"SettingsTabGraphicsBackend": "Graphics Backend",
|
||||
"SettingsTabGraphicsBackendTooltip": "Graphics Backend to use",
|
||||
"SettingsEnableTextureRecompression": "Enable Texture Recompression",
|
||||
"SettingsEnableTextureRecompressionTooltip": "Compresses certain textures in order to reduce VRAM usage.\n\nRecommended for use with GPUs that have less than 4GB VRAM.\n\nLeave OFF if unsure.",
|
||||
"SettingsEnableTextureRecompressionTooltip": "Compresses certain textures in order to reduce VRAM usage.\n\nRecommended for use with GPUs that have less than 4GiB VRAM.\n\nLeave OFF if unsure.",
|
||||
"SettingsTabGraphicsPreferredGpu": "Preferred GPU",
|
||||
"SettingsTabGraphicsPreferredGpuTooltip": "Select the graphics card that will be used with the Vulkan graphics backend.\n\nDoes not affect the GPU that OpenGL will use.\n\nSet to the GPU flagged as \"dGPU\" if unsure. If there isn't one, leave untouched.",
|
||||
"SettingsAppRequiredRestartMessage": "Ryujinx Restart Required",
|
||||
"SettingsGpuBackendRestartMessage": "Graphics Backend or Gpu settings have been modified. This will require a restart to be applied",
|
||||
"SettingsGpuBackendRestartMessage": "Graphics Backend or GPU settings have been modified. This will require a restart to be applied",
|
||||
"SettingsGpuBackendRestartSubMessage": "Do you want to restart now?",
|
||||
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
|
||||
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
|
||||
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
||||
"VolumeShort": "Vol"
|
||||
"VolumeShort": "Vol",
|
||||
"SettingsEnableMacroHLE": "Enable Macro HLE",
|
||||
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure."
|
||||
}
|
||||
|
@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (Pueden causar inestabilidad)",
|
||||
"SettingsTabSystemExpandDramSize": "Expandir DRAM a 6GB",
|
||||
"SettingsTabSystemExpandDramSize": "Expandir DRAM a 6GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignorar servicios no implementados",
|
||||
"SettingsTabGraphics": "Gráficos",
|
||||
"SettingsTabGraphicsAPI": "API de gráficos",
|
||||
@ -440,7 +440,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "Usa una tabla de paginación de software para traducir direcciones. Ofrece la precisión más exacta pero el rendimiento más lento.",
|
||||
"MemoryManagerHostTooltip": "Mapea la memoria directamente en la dirección de espacio del host. Compilación y ejecución JIT mucho más rápida.",
|
||||
"MemoryManagerUnsafeTooltip": "Mapea la memoria directamente, pero no enmascara la dirección dentro del espacio de dirección del guest antes del acceso. El modo más rápido, pero a costa de seguridad. La aplicación guest puede acceder a la memoria desde cualquier parte en Ryujinx, así que ejecuta solo programas en los que confíes cuando uses este modo.",
|
||||
"DRamTooltip": "Expande la memoria DRAM del sistema emulado de 4GB a 6GB.\n\nUtilizar solo con packs de texturas HD o mods de resolución 4K. NO mejora el rendimiento.\n\nDesactívalo si no sabes qué hacer.",
|
||||
"DRamTooltip": "Expande la memoria DRAM del sistema emulado de 4GiB a 6GiB.\n\nUtilizar solo con packs de texturas HD o mods de resolución 4K. NO mejora el rendimiento.\n\nDesactívalo si no sabes qué hacer.",
|
||||
"IgnoreMissingServicesTooltip": "Hack para ignorar servicios no implementados del Horizon OS. Esto puede ayudar a sobrepasar crasheos cuando inicies ciertos juegos.\n\nDesactívalo si no sabes qué hacer.",
|
||||
"GraphicsBackendThreadingTooltip": "Ejecuta los comandos del motor gráfico en un segundo hilo. Acelera la compilación de sombreadores, reduce los tirones, y mejora el rendimiento en controladores gráficos que no realicen su propio multihilado. Rendimiento máximo ligeramente superior en controladores gráficos que soporten multihilado.\n\nSelecciona \"Auto\" si no sabes qué hacer.",
|
||||
"GalThreadingTooltip": "Ejecuta los comandos del motor gráfico en un segundo hilo. Acelera la compilación de sombreadores, reduce los tirones, y mejora el rendimiento en controladores gráficos que no realicen su propio multihilado. Rendimiento máximo ligeramente superior en controladores gráficos que soporten multihilado.\n\nSelecciona \"Auto\" si no sabes qué hacer.",
|
||||
|
@ -112,7 +112,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (Cela peut causer des instabilitées)",
|
||||
"SettingsTabSystemExpandDramSize": "Augmenter la taille de la DRAM à 6GB",
|
||||
"SettingsTabSystemExpandDramSize": "Augmenter la taille de la DRAM à 6GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignorer les services manquant",
|
||||
"SettingsTabGraphics": "Graphique",
|
||||
"SettingsTabGraphicsAPI": "API Graphique",
|
||||
|
@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (Possono causare instabilità)",
|
||||
"SettingsTabSystemExpandDramSize": "Espandi dimensione DRAM a 6GB",
|
||||
"SettingsTabSystemExpandDramSize": "Espandi dimensione DRAM a 6GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignora servizi mancanti",
|
||||
"SettingsTabGraphics": "Grafica",
|
||||
"SettingsTabGraphicsAPI": "API Grafiche",
|
||||
@ -440,7 +440,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "Usa una software page table per la traduzione degli indirizzi. Massima precisione ma prestazioni più lente.",
|
||||
"MemoryManagerHostTooltip": "Mappa direttamente la memoria nello spazio degli indirizzi dell'host. Compilazione ed esecuzione JIT molto più veloce.",
|
||||
"MemoryManagerUnsafeTooltip": "Mappa direttamente la memoria, ma non maschera l'indirizzo all'interno dello spazio degli indirizzi guest prima dell'accesso. Più veloce, ma a costo della sicurezza. L'applicazione guest può accedere alla memoria da qualsiasi punto di Ryujinx, quindi esegui solo programmi di cui ti fidi con questa modalità.",
|
||||
"DRamTooltip": "Espande l'ammontare di memoria sul sistema emulato da 4GB A 6GB",
|
||||
"DRamTooltip": "Espande l'ammontare di memoria sul sistema emulato da 4GiB A 6GiB",
|
||||
"IgnoreMissingServicesTooltip": "Attiva o disattiva l'opzione di ignorare i servizi mancanti",
|
||||
"GraphicsBackendThreadingTooltip": "Attiva il Graphics Backend Multithreading",
|
||||
"GalThreadingTooltip": "Esegue i comandi del backend grafico su un secondo thread. Permette il multithreading runtime della compilazione degli shader, riduce lo stuttering e migliora le prestazioni sui driver senza supporto multithreading proprio. Varia leggermente le prestazioni di picco sui driver con multithreading. Ryujinx potrebbe aver bisogno di essere riavviato per disabilitare correttamente il multithreading integrato nel driver, o potrebbe essere necessario farlo manualmente per ottenere le migliori prestazioni.",
|
||||
|
@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "ハック",
|
||||
"SettingsTabSystemHacksNote": " (挙動が不安定になる可能性があります)",
|
||||
"SettingsTabSystemExpandDramSize": "DRAMサイズを6GBに拡大",
|
||||
"SettingsTabSystemExpandDramSize": "DRAMサイズを6GiBに拡大",
|
||||
"SettingsTabSystemIgnoreMissingServices": "未実装サービスを無視",
|
||||
"SettingsTabGraphics": "グラフィックス",
|
||||
"SettingsTabGraphicsAPI": "グラフィックスAPI",
|
||||
@ -440,7 +440,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "アドレス変換にソフトウェアページテーブルを使用します. 非常に正確ですがパフォーマンスが大きく低下します.",
|
||||
"MemoryManagerHostTooltip": "ホストのアドレス空間にメモリを直接マップします.JITのコンパイルと実行速度が大きく向上します.",
|
||||
"MemoryManagerUnsafeTooltip": "メモリを直接マップしますが, アクセス前にゲストのアドレス空間内のアドレスをマスクしません. より高速になりますが, 安全性が犠牲になります. ゲストアプリケーションは Ryujinx のどこからでもメモリにアクセスできるので,このモードでは信頼できるプログラムだけを実行するようにしてください.",
|
||||
"DRamTooltip": "エミュレートされたシステムのメモリ容量を 4GB から 6GB に増加します.\n\n高解像度のテクスチャパックや 4K解像度の mod を使用する場合に有用です. パフォーマンスを改善するものではありません.\n\nよくわからない場合はオフのままにしてください.",
|
||||
"DRamTooltip": "エミュレートされたシステムのメモリ容量を 4GiB から 6GiB に増加します.\n\n高解像度のテクスチャパックや 4K解像度の mod を使用する場合に有用です. パフォーマンスを改善するものではありません.\n\nよくわからない場合はオフのままにしてください.",
|
||||
"IgnoreMissingServicesTooltip": "未実装の Horizon OS サービスを無視します. 特定のゲームにおいて起動時のクラッシュを回避できる場合があります.\n\nよくわからない場合はオフのままにしてください.",
|
||||
"GraphicsBackendThreadingTooltip": "グラフィックスバックエンドのコマンドを別スレッドで実行します.\n\nシェーダのコンパイルを高速化し, 遅延を軽減し, マルチスレッド非対応の GPU ドライバにおいてパフォーマンスを改善します. マルチスレッド対応のドライバでも若干パフォーマンス改善が見られます.\n\nよくわからない場合は自動に設定してください.",
|
||||
"GalThreadingTooltip": "グラフィックスバックエンドのコマンドを別スレッドで実行します.\n\nシェーダのコンパイルを高速化し, 遅延を軽減し, マルチスレッド非対応の GPU ドライバにおいてパフォーマンスを改善します. マルチスレッド対応のドライバでも若干パフォーマンス改善が見られます.\n\nよくわからない場合は自動に設定してください.",
|
||||
@ -583,7 +583,7 @@
|
||||
"SettingsTabGraphicsBackend": "グラフィックスバックエンド",
|
||||
"SettingsTabGraphicsBackendTooltip": "使用するグラフィックスバックエンドです",
|
||||
"SettingsEnableTextureRecompression": "テクスチャの再圧縮を有効",
|
||||
"SettingsEnableTextureRecompressionTooltip": "VRAMの使用量を削減するためテクスチャを圧縮します.\n\nGPUのVRAMが4GB未満の場合は使用を推奨します.\n\nよくわからない場合はオフのままにしてください.",
|
||||
"SettingsEnableTextureRecompressionTooltip": "VRAMの使用量を削減するためテクスチャを圧縮します.\n\nGPUのVRAMが4GiB未満の場合は使用を推奨します.\n\nよくわからない場合はオフのままにしてください.",
|
||||
"SettingsTabGraphicsPreferredGpu": "優先使用するGPU",
|
||||
"SettingsTabGraphicsPreferredGpuTooltip": "Vulkanグラフィックスバックエンドで使用されるグラフィックスカードを選択します.\n\nOpenGLが使用するGPUには影響しません.\n\n不明な場合は, \"dGPU\" としてフラグが立っているGPUに設定します. ない場合はそのままにします.",
|
||||
"SettingsAppRequiredRestartMessage": "Ryujinx の再起動が必要です",
|
||||
|
@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "해킹",
|
||||
"SettingsTabSystemHacksNote": " (불안정을 일으킬 수 있음)",
|
||||
"SettingsTabSystemExpandDramSize": "DRAM 크기를 6GB로 확장",
|
||||
"SettingsTabSystemExpandDramSize": "DRAM 크기를 6GiB로 확장",
|
||||
"SettingsTabSystemIgnoreMissingServices": "누락된 서비스 무시",
|
||||
"SettingsTabGraphics": "제도법",
|
||||
"SettingsTabGraphicsAPI": "그래픽 API",
|
||||
@ -439,7 +439,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "주소 변환을 위해 소프트웨어 페이지 테이블을 사용하십시오. 정확도는 가장 높지만 성능은 가장 느립니다.",
|
||||
"MemoryManagerHostTooltip": "호스트 주소 공간에서 메모리를 직접 매핑합니다. 훨씬 더 빠른 JIT 컴파일 및 실행.",
|
||||
"MemoryManagerUnsafeTooltip": "메모리를 직접 매핑하지만 액세스하기 전에 게스트 주소 공간 내의 주소를 마스킹하지 마십시오. 더 빠르지만 안전을 희생해야 합니다. 게스트 응용 프로그램은 Ryujinx의 어디에서나 메모리에 액세스할 수 있으므로 이 모드로 신뢰할 수 있는 프로그램만 실행하십시오.",
|
||||
"DRamTooltip": "에뮬레이트된 시스템의 메모리 양을 4GB에서 6GB로 확장",
|
||||
"DRamTooltip": "에뮬레이트된 시스템의 메모리 양을 4GiB에서 6GiB로 확장",
|
||||
"IgnoreMissingServicesTooltip": "누락된 서비스 무시 옵션 활성화 또는 비활성화",
|
||||
"GraphicsBackendThreadingTooltip": "그래픽 백엔드 멀티스레딩 활성화",
|
||||
"GalThreadingTooltip": "두 번째 스레드에서 그래픽 백엔드 명령을 실행합니다. 셰이더 컴파일의 런타임 멀티스레딩을 허용하고, 말더듬을 줄이고, 자체 멀티스레딩 지원 없이 드라이버의 성능을 개선합니다. 멀티스레딩이 있는 드라이버에서 약간 다른 최대 성능. 드라이버 내장 멀티스레딩을 올바르게 비활성화하려면 Ryujinx를 다시 시작해야 할 수도 있고 최상의 성능을 얻으려면 수동으로 수행해야 할 수도 있습니다.",
|
||||
|
@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacki",
|
||||
"SettingsTabSystemHacksNote": " (mogą powodować niestabilność)",
|
||||
"SettingsTabSystemExpandDramSize": "Rozszerz Rozmiar DRAM do 6 GB",
|
||||
"SettingsTabSystemExpandDramSize": "Rozszerz Rozmiar DRAM do 6 GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignoruj Brakujące Usługi",
|
||||
"SettingsTabGraphics": "Grafika",
|
||||
"SettingsTabGraphicsAPI": "Graficzne API",
|
||||
@ -440,7 +440,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "Użyj tabeli stron oprogramowania do translacji adresów. Najwyższa celność, ale najwolniejsza wydajność.",
|
||||
"MemoryManagerHostTooltip": "Bezpośrednio mapuj pamięć w przestrzeni adresowej hosta. Znacznie szybsza kompilacja i wykonanie JIT.",
|
||||
"MemoryManagerUnsafeTooltip": "Bezpośrednio mapuj pamięć, ale nie maskuj adresu w przestrzeni adresowej gościa przed uzyskaniem dostępu. Szybciej, ale kosztem bezpieczeństwa. Aplikacja gościa może uzyskać dostęp do pamięci z dowolnego miejsca w Ryujinx, więc w tym trybie uruchamiaj tylko programy, którym ufasz.",
|
||||
"DRamTooltip": "Zwiększa ilość pamięci w emulowanym systemie z 4 GB do 6 GB.\n\nJest to przydatne tylko w przypadku pakietów tekstur o wyższej rozdzielczości lub modów w rozdzielczości 4k. NIE poprawia wydajności.\n\nW razie wątpliwości pozostaw WYŁĄCZONE.",
|
||||
"DRamTooltip": "Zwiększa ilość pamięci w emulowanym systemie z 4 GiB do 6 GiB.\n\nJest to przydatne tylko w przypadku pakietów tekstur o wyższej rozdzielczości lub modów w rozdzielczości 4k. NIE poprawia wydajności.\n\nW razie wątpliwości pozostaw WYŁĄCZONE.",
|
||||
"IgnoreMissingServicesTooltip": "Ignoruje niezaimplementowane usługi Horizon OS. Może to pomóc w ominięciu awarii podczas uruchamiania niektórych gier.\n\nW razie wątpliwości pozostaw WYŁĄCZONE.",
|
||||
"GraphicsBackendThreadingTooltip": "Wykonuje polecenia backend'u graficznego w drugim wątku.\n\nPrzyspiesza kompilację shaderów, zmniejsza zacinanie się i poprawia wydajność sterowników GPU bez własnej obsługi wielowątkowości. Nieco lepsza wydajność w sterownikach z wielowątkowością.\n\nUstaw na AUTO, jeśli nie masz pewności.",
|
||||
"GalThreadingTooltip": "Wykonuje polecenia backend'u graficznego w drugim wątku.\n\nPrzyspiesza kompilację shaderów, zmniejsza zacinanie się i poprawia wydajność sterowników GPU bez własnej obsługi wielowątkowości. Nieco lepsza wydajność w sterownikach z wielowątkowością.\n\nUstaw na AUTO, jeśli nie masz pewności.",
|
||||
@ -583,7 +583,7 @@
|
||||
"SettingsTabGraphicsBackend": "Backend Graficzny",
|
||||
"SettingsTabGraphicsBackendTooltip": "Używalne Backendy Graficzne",
|
||||
"SettingsEnableTextureRecompression": "Włącz Rekompresję Tekstur",
|
||||
"SettingsEnableTextureRecompressionTooltip": "Kompresuje niektóre tekstury w celu zmniejszenia zużycia pamięci VRAM.\n\nZalecane do użytku z GPU, które mają mniej niż 4 GB pamięci VRAM.\n\nW razie wątpliwości pozostaw WYŁĄCZONE.",
|
||||
"SettingsEnableTextureRecompressionTooltip": "Kompresuje niektóre tekstury w celu zmniejszenia zużycia pamięci VRAM.\n\nZalecane do użytku z GPU, które mają mniej niż 4 GiB pamięci VRAM.\n\nW razie wątpliwości pozostaw WYŁĄCZONE.",
|
||||
"SettingsTabGraphicsPreferredGpu": "Preferowane GPU",
|
||||
"SettingsTabGraphicsPreferredGpuTooltip": "Wybierz kartę graficzną, która będzie używana z backendem graficznym Vulkan.\n\nNie wpływa na GPU używane przez OpenGL.\n\nW razie wątpliwości ustaw flagę GPU jako \"dGPU\". Jeśli żadnej nie ma, pozostaw nietknięte.",
|
||||
"SettingsAppRequiredRestartMessage": "Wymagane Zrestartowanie Ryujinx",
|
||||
|
@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (Pode causar instabilidade)",
|
||||
"SettingsTabSystemExpandDramSize": "Expandir memória para 6GB",
|
||||
"SettingsTabSystemExpandDramSize": "Expandir memória para 6GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignorar serviços não implementados",
|
||||
"SettingsTabGraphics": "Gráficos",
|
||||
"SettingsTabGraphicsAPI": "API gráfica",
|
||||
@ -440,7 +440,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "Usar uma tabela de página via software para tradução de endereços. Maior precisão, porém performance mais baixa.",
|
||||
"MemoryManagerHostTooltip": "Mapeia memória no espaço de endereço hóspede diretamente. Compilação e execução do JIT muito mais rápida.",
|
||||
"MemoryManagerUnsafeTooltip": "Mapeia memória diretamente, mas sem limitar o acesso ao espaço de endereçamento do sistema convidado. Mais rápido, porém menos seguro. O aplicativo convidado pode acessar memória de qualquer parte do Ryujinx, então apenas rode programas em que você confia nesse modo.",
|
||||
"DRamTooltip": "Expande a memória do sistema emulado de 4GB para 6GB",
|
||||
"DRamTooltip": "Expande a memória do sistema emulado de 4GiB para 6GiB",
|
||||
"IgnoreMissingServicesTooltip": "Habilita ou desabilita a opção de ignorar serviços não implementados",
|
||||
"GraphicsBackendThreadingTooltip": "Habilita multithreading do backend gráfico",
|
||||
"GalThreadingTooltip": "Executa comandos do backend gráfico em uma segunda thread. Permite multithreading em tempo de execução da compilação de shader, diminui os travamentos, e melhora performance em drivers sem suporte embutido a multithreading. Pequena variação na performance máxima em drivers com suporte a multithreading. Ryujinx pode precisar ser reiniciado para desabilitar adequadamente o multithreading embutido do driver, ou você pode precisar fazer isso manualmente para ter a melhor performance.",
|
||||
@ -556,5 +556,7 @@
|
||||
"SettingsSelectThemeFileDialogTitle" : "Selecionar arquivo do tema",
|
||||
"SettingsXamlThemeFile" : "Arquivo de tema Xaml",
|
||||
"SettingsTabHotkeysResScaleUpHotkey": "Aumentar a resolução:",
|
||||
"SettingsTabHotkeysResScaleDownHotkey": "Diminuir a resolução:"
|
||||
"SettingsTabHotkeysResScaleDownHotkey": "Diminuir a resolução:",
|
||||
"SettingsEnableMacroHLE": "Habilitar emulação de alto nível para Macros",
|
||||
"SettingsEnableMacroHLETooltip": "Habilita emulação de alto nível de códigos Macro da GPU.\n\nMelhora a performance, mas pode causar problemas gráficos em alguns jogos.\n\nEm caso de dúvida, deixe ATIVADO."
|
||||
}
|
||||
|
@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Хаки",
|
||||
"SettingsTabSystemHacksNote": " (Эти многие настройки вызывают нестабильность)",
|
||||
"SettingsTabSystemExpandDramSize": "Увеличение размера DRAM до 6GB",
|
||||
"SettingsTabSystemExpandDramSize": "Увеличение размера DRAM до 6GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Игнорировать отсутствующие службы",
|
||||
"SettingsTabGraphics": "Графика",
|
||||
"SettingsTabGraphicsAPI": "Графические API",
|
||||
|
@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacklar",
|
||||
"SettingsTabSystemHacksNote": " (Bunlar birçok dengesizlik oluşturabilir)",
|
||||
"SettingsTabSystemExpandDramSize": "DRAM boyutunu 6GB'a genişlet",
|
||||
"SettingsTabSystemExpandDramSize": "DRAM boyutunu 6GiB'a genişlet",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Eksik Servisleri Görmezden Gel",
|
||||
"SettingsTabGraphics": "Grafikler",
|
||||
"SettingsTabGraphicsAPI": "Grafikler API",
|
||||
@ -440,7 +440,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "Adres çevirisi için bir işlemci sayfası kullanır. En yüksek doğruluğu ve en yavaş performansı sunar.",
|
||||
"MemoryManagerHostTooltip": "Hafızayı doğrudan host adres aralığında tahsis eder. Çok daha hızlı JIT derleme ve işletimi sunar.",
|
||||
"MemoryManagerUnsafeTooltip": "Hafızayı doğrudan tahsis eder, ancak host aralığına erişimden önce adresi maskelemez. Daha iyi performansa karşılık emniyetten ödün verir. Misafir uygulama Ryujinx içerisinden istediği hafızaya erişebilir, bu sebeple bu seçenek ile sadece güvendiğiniz uygulamaları çalıştırın.",
|
||||
"DRamTooltip": "Emüle edilen sistem hafızasını 4GB'dan 6GB'a yükseltir.\n\nBu seçenek yalnızca yüksek çözünürlük doku paketleri veya 4k çözünürlük modları için kullanılır. Performansı artırMAZ!\n\nEmin değilseniz devre dışı bırakın.",
|
||||
"DRamTooltip": "Emüle edilen sistem hafızasını 4GiB'dan 6GiB'a yükseltir.\n\nBu seçenek yalnızca yüksek çözünürlük doku paketleri veya 4k çözünürlük modları için kullanılır. Performansı artırMAZ!\n\nEmin değilseniz devre dışı bırakın.",
|
||||
"IgnoreMissingServicesTooltip": "Henüz programlanmamış Horizon işletim sistemi servislerini görmezden gelir. Bu seçenek belirli oyunların açılırken çökmesinin önüne geçmeye yardımcı olabilir.\n\nEmin değilseniz devre dışı bırakın.",
|
||||
"GraphicsBackendThreadingTooltip": "Grafik arka uç komutlarını ikinci bir iş parçacığında işletir.\n\nKendi multithreading desteği olmayan sürücülerde shader derlemeyi hızlandırıp performansı artırır. Multithreading desteği olan sürücülerde çok az daha iyi performans sağlar.\n\nEmin değilseniz Otomatik seçeneğine ayarlayın.",
|
||||
"GalThreadingTooltip": "Grafik arka uç komutlarını ikinci bir iş parçacığında işletir.\n\nKendi multithreading desteği olmayan sürücülerde shader derlemeyi hızlandırıp performansı artırır. Multithreading desteği olan sürücülerde çok az daha iyi performans sağlar.\n\nEmin değilseniz Otomatik seçeneğine ayarlayın.",
|
||||
|
@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "修正",
|
||||
"SettingsTabSystemHacksNote": " (会引起模拟器不稳定)",
|
||||
"SettingsTabSystemExpandDramSize": "将模拟RAM大小扩展到 6GB",
|
||||
"SettingsTabSystemExpandDramSize": "将模拟RAM大小扩展到 6GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "忽略缺少的服务",
|
||||
"SettingsTabGraphics": "图形",
|
||||
"SettingsTabGraphicsAPI": "图形 API",
|
||||
@ -440,7 +440,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "使用软件内存页管理,最精确但是速度最慢",
|
||||
"MemoryManagerHostTooltip": "直接映射内存页到电脑内存,JIT效率高",
|
||||
"MemoryManagerUnsafeTooltip": "直接映射内存页,但不检查内存溢出,JIT效率最高。\nRyujinx可以访问任何位置的内存,因而相对不安全。\n此模式下只应运行您信任的游戏或软件(即官方游戏)",
|
||||
"DRamTooltip": "扩展模拟的 Switch 内存为6GB。\n某些高清纹理MOD或4K MOD需要此选项",
|
||||
"DRamTooltip": "扩展模拟的 Switch 内存为6GiB。\n某些高清纹理MOD或4K MOD需要此选项",
|
||||
"IgnoreMissingServicesTooltip": "开启后,游戏会忽略未实现的系统服务,从而继续运行。\n少部分新发布的游戏由于使用新的未知系统服务,可能需要此选项来避免闪退。\n模拟器更新完善系统服务之后,则无需开启选项。\n如您的游戏已经正常运行,请保持此选项关闭",
|
||||
"GraphicsBackendThreadingTooltip": "启用后端多线程",
|
||||
"GalThreadingTooltip": "使用模拟器内置的多线程优化,减少着色器编译的卡顿,并提高驱动程序的性能(尤其是缺失多线程的AMD)。\nNVIDIA显卡需要重启模拟器才能禁用驱动本身的线程优化,您也可以手动在控制面板将其禁用",
|
||||
@ -583,7 +583,7 @@
|
||||
"SettingsTabGraphicsBackend": "图形后端",
|
||||
"SettingsTabGraphicsBackendTooltip": "显卡使用的图形后端",
|
||||
"SettingsEnableTextureRecompression": "启用纹理重压缩",
|
||||
"SettingsEnableTextureRecompressionTooltip": "压缩某些纹理以减少显存的使用。\n适合显存小于 4GB 的 GPU开启。\n如果您不确定,请保持此项为关闭。",
|
||||
"SettingsEnableTextureRecompressionTooltip": "压缩某些纹理以减少显存的使用。\n适合显存小于 4GiB 的 GPU开启。\n如果您不确定,请保持此项为关闭。",
|
||||
"SettingsTabGraphicsPreferredGpu": "首选 GPU",
|
||||
"SettingsTabGraphicsPreferredGpuTooltip": "选择Vulkan API使用的显卡。\n此选项不会影响OpenGL API。\n如果您不确定,建议选择\"dGPU(独立显卡)\"。如果没有独立显卡,则无需改动此选项",
|
||||
"SettingsAppRequiredRestartMessage": "Ryujinx 需要重启",
|
||||
|
@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "修正",
|
||||
"SettingsTabSystemHacksNote": " (會引起模擬器不穩定)",
|
||||
"SettingsTabSystemExpandDramSize": "將模擬記憶體大小擴充至 6GB",
|
||||
"SettingsTabSystemExpandDramSize": "將模擬記憶體大小擴充至 6GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "忽略缺少的服務",
|
||||
"SettingsTabGraphics": "圖形",
|
||||
"SettingsTabGraphicsEnhancements": "增強",
|
||||
@ -440,7 +440,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "使用軟體記憶體頁管理,最精確但是速度最慢",
|
||||
"MemoryManagerHostTooltip": "直接映射記憶體頁到電腦記憶體,JIT效率高",
|
||||
"MemoryManagerUnsafeTooltip": "直接映射記憶體頁,但是不檢查記憶體溢出,JIT效率最高。\nRyujinx可以存取任何位置的記憶體,因而相對不安全。此模式下只應執行您信任的遊戲或軟體(即官方遊戲)",
|
||||
"DRamTooltip": "擴展模擬的 Switch 記憶體為6GB,某些高畫質材質模組或 4K 模組需要此選項",
|
||||
"DRamTooltip": "擴展模擬的 Switch 記憶體為6GiB,某些高畫質材質模組或 4K 模組需要此選項",
|
||||
"IgnoreMissingServicesTooltip": "忽略某些未實現的系統服務,少部分遊戲需要此選項才能啟動",
|
||||
"GraphicsBackendThreadingTooltip": "啟用後端多執行緒",
|
||||
"GalThreadingTooltip": "使用模擬器自帶的多執行緒調度,減少渲染器編譯的卡頓,並提高驅動程式的效能(尤其是缺失多執行緒的AMD)。\nNVIDIA使用者需要重啟模擬器才能停用驅動本身的多執行緒,否則您需手動執行停用獲得最佳效能",
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@ -93,7 +94,7 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
return;
|
||||
}
|
||||
|
||||
var strings = JsonSerializer.Deserialize<Dictionary<string, string>>(languageJson);
|
||||
var strings = JsonHelper.Deserialize<Dictionary<string, string>>(languageJson);
|
||||
|
||||
foreach (var item in strings)
|
||||
{
|
||||
|
@ -13,6 +13,7 @@ using Ryujinx.Common.SystemInfo;
|
||||
using Ryujinx.Modules;
|
||||
using Ryujinx.Ui.Common;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using Ryujinx.Ui.Common.Helper;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
@ -26,7 +27,6 @@ namespace Ryujinx.Ava
|
||||
public static double ActualScaleFactor { get; set; }
|
||||
public static string Version { get; private set; }
|
||||
public static string ConfigurationPath { get; private set; }
|
||||
public static string CommandLineProfile { get; set; }
|
||||
public static bool PreviewerDetached { get; private set; }
|
||||
|
||||
public static RenderTimer RenderTimer { get; private set; }
|
||||
@ -87,46 +87,8 @@ namespace Ryujinx.Ava
|
||||
|
||||
private static void Initialize(string[] args)
|
||||
{
|
||||
// Parse Arguments.
|
||||
string launchPathArg = null;
|
||||
string baseDirPathArg = null;
|
||||
bool startFullscreenArg = false;
|
||||
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
{
|
||||
string arg = args[i];
|
||||
|
||||
if (arg == "-r" || arg == "--root-data-dir")
|
||||
{
|
||||
if (i + 1 >= args.Length)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
baseDirPathArg = args[++i];
|
||||
}
|
||||
else if (arg == "-p" || arg == "--profile")
|
||||
{
|
||||
if (i + 1 >= args.Length)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
CommandLineProfile = args[++i];
|
||||
}
|
||||
else if (arg == "-f" || arg == "--fullscreen")
|
||||
{
|
||||
startFullscreenArg = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
launchPathArg = arg;
|
||||
}
|
||||
}
|
||||
// Parse arguments
|
||||
CommandLineState.ParseArguments(args);
|
||||
|
||||
// Delete backup files after updating.
|
||||
Task.Run(Updater.CleanupUpdate);
|
||||
@ -138,7 +100,7 @@ namespace Ryujinx.Ava
|
||||
AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit();
|
||||
|
||||
// Setup base data directory.
|
||||
AppDataManager.Initialize(baseDirPathArg);
|
||||
AppDataManager.Initialize(CommandLineState.BaseDirPathArg);
|
||||
|
||||
// Initialize the configuration.
|
||||
ConfigurationState.Initialize();
|
||||
@ -173,9 +135,9 @@ namespace Ryujinx.Ava
|
||||
}
|
||||
}
|
||||
|
||||
if (launchPathArg != null)
|
||||
if (CommandLineState.LaunchPathArg != null)
|
||||
{
|
||||
MainWindow.DeferLoadApplication(launchPathArg, startFullscreenArg);
|
||||
MainWindow.DeferLoadApplication(CommandLineState.LaunchPathArg, CommandLineState.StartFullscreenArg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,6 +177,19 @@ namespace Ryujinx.Ava
|
||||
Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location {ConfigurationPath}");
|
||||
}
|
||||
}
|
||||
|
||||
// Check if graphics backend was overridden
|
||||
if (CommandLineState.OverrideGraphicsBackend != null)
|
||||
{
|
||||
if (CommandLineState.OverrideGraphicsBackend.ToLower() == "opengl")
|
||||
{
|
||||
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.OpenGl;
|
||||
}
|
||||
else if (CommandLineState.OverrideGraphicsBackend.ToLower() == "vulkan")
|
||||
{
|
||||
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.Vulkan;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrintSystemInfo()
|
||||
|
@ -18,7 +18,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="0.10.15" />
|
||||
<PackageReference Include="Avalonia" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="0.10.15" />
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.15" />
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.15" />
|
||||
@ -36,7 +36,7 @@
|
||||
<PackageReference Include="Silk.NET.Vulkan" Version="2.10.1" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.10.1" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.10.1" />
|
||||
<PackageReference Include="SPB" Version="0.0.4-build27" />
|
||||
<PackageReference Include="SPB" Version="0.0.4-build28" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
|
@ -10,22 +10,22 @@ namespace Ryujinx.Ava.Ui.Models
|
||||
string aValue = (x as ApplicationData).TimePlayed;
|
||||
string bValue = (y as ApplicationData).TimePlayed;
|
||||
|
||||
if (aValue[^2..] == "GB")
|
||||
if (aValue[^3..] == "GiB")
|
||||
{
|
||||
aValue = (float.Parse(aValue[0..^2]) * 1024).ToString();
|
||||
aValue = (float.Parse(aValue[0..^3]) * 1024).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
aValue = aValue[0..^2];
|
||||
aValue = aValue[0..^3];
|
||||
}
|
||||
|
||||
if (bValue[^2..] == "GB")
|
||||
if (bValue[^3..] == "GiB")
|
||||
{
|
||||
bValue = (float.Parse(bValue[0..^2]) * 1024).ToString();
|
||||
bValue = (float.Parse(bValue[0..^3]) * 1024).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
bValue = bValue[0..^2];
|
||||
bValue = bValue[0..^3];
|
||||
}
|
||||
|
||||
if (float.Parse(aValue) > float.Parse(bValue))
|
||||
|
@ -15,22 +15,22 @@ namespace Ryujinx.Ava.Ui.Models.Generic
|
||||
string aValue = x.FileSize;
|
||||
string bValue = y.FileSize;
|
||||
|
||||
if (aValue[^2..] == "GB")
|
||||
if (aValue[^3..] == "GiB")
|
||||
{
|
||||
aValue = (float.Parse(aValue[0..^2]) * 1024).ToString();
|
||||
aValue = (float.Parse(aValue[0..^3]) * 1024).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
aValue = aValue[0..^2];
|
||||
aValue = aValue[0..^3];
|
||||
}
|
||||
|
||||
if (bValue[^2..] == "GB")
|
||||
if (bValue[^3..] == "GiB")
|
||||
{
|
||||
bValue = (float.Parse(bValue[0..^2]) * 1024).ToString();
|
||||
bValue = (float.Parse(bValue[0..^3]) * 1024).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
bValue = bValue[0..^2];
|
||||
bValue = bValue[0..^3];
|
||||
}
|
||||
|
||||
if (float.Parse(aValue) > float.Parse(bValue))
|
||||
|
@ -8,6 +8,7 @@ using Ryujinx.Ava.Ui.Models;
|
||||
using Ryujinx.Ava.Ui.Windows;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
@ -189,7 +190,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
amiiboJsonString = File.ReadAllText(_amiiboJsonPath);
|
||||
|
||||
if (await NeedsUpdate(JsonSerializer.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).LastUpdated))
|
||||
if (await NeedsUpdate(JsonHelper.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).LastUpdated))
|
||||
{
|
||||
amiiboJsonString = await DownloadAmiiboJson();
|
||||
}
|
||||
@ -206,7 +207,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
_amiiboList = JsonSerializer.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).Amiibo;
|
||||
_amiiboList = JsonHelper.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).Amiibo;
|
||||
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
||||
|
||||
ParseAmiiboData();
|
||||
|
@ -460,8 +460,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
using IGamepad gamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id);
|
||||
|
||||
Logger.Info?.Print(LogClass.Configuration, $"{GetShortGamepadName(gamepad.Name)} has been connected with ID: {gamepad.Id}");
|
||||
|
||||
if (gamepad != null)
|
||||
{
|
||||
Devices.Add((DeviceType.Keyboard, id, $"{GetShortGamepadName(gamepad.Name)}"));
|
||||
@ -472,8 +470,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
using IGamepad gamepad = _mainWindow.InputManager.GamepadDriver.GetGamepad(id);
|
||||
|
||||
Logger.Info?.Print(LogClass.Configuration, $"{GetShortGamepadName(gamepad.Name)} has been connected with ID: {gamepad.Id}");
|
||||
|
||||
if (gamepad != null)
|
||||
{
|
||||
if (Devices.Any(controller => GetShortGamepadId(controller.Id) == GetShortGamepadId(gamepad.Id)))
|
||||
|
@ -21,14 +21,10 @@ using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||
using Ryujinx.Input;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using Ryujinx.Ui.Common.Configuration.System;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using TimeZone = Ryujinx.Ava.Ui.Models.TimeZone;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.ViewModels
|
||||
@ -138,6 +134,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
public bool ExpandDramSize { get; set; }
|
||||
public bool EnableShaderCache { get; set; }
|
||||
public bool EnableTextureRecompression { get; set; }
|
||||
public bool EnableMacroHLE { get; set; }
|
||||
public bool EnableFileLog { get; set; }
|
||||
public bool EnableStub { get; set; }
|
||||
public bool EnableInfo { get; set; }
|
||||
@ -339,6 +336,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
ExpandDramSize = config.System.ExpandRam;
|
||||
EnableShaderCache = config.Graphics.EnableShaderCache;
|
||||
EnableTextureRecompression = config.Graphics.EnableTextureRecompression;
|
||||
EnableMacroHLE = config.Graphics.EnableMacroHLE;
|
||||
EnableFileLog = config.Logger.EnableFileLog;
|
||||
EnableStub = config.Logger.EnableStub;
|
||||
EnableInfo = config.Logger.EnableInfo;
|
||||
@ -422,6 +420,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
config.Graphics.EnableVsync.Value = EnableVsync;
|
||||
config.Graphics.EnableShaderCache.Value = EnableShaderCache;
|
||||
config.Graphics.EnableTextureRecompression.Value = EnableTextureRecompression;
|
||||
config.Graphics.EnableMacroHLE.Value = EnableMacroHLE;
|
||||
config.Graphics.GraphicsBackend.Value = (GraphicsBackend)GraphicsBackendIndex;
|
||||
config.System.EnablePtc.Value = EnablePptc;
|
||||
config.System.EnableInternetAccess.Value = EnableInternetAccess;
|
||||
|
@ -23,6 +23,7 @@ using Ryujinx.Modules;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using Ryujinx.Ui.Common;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using Ryujinx.Ui.Common.Helper;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
@ -432,7 +433,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
// Consider removing this at some point in the future when we don't need to worry about old saves.
|
||||
VirtualFileSystem.FixExtraData(LibHacHorizonManager.RyujinxClient);
|
||||
|
||||
AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient, Program.CommandLineProfile);
|
||||
AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient, CommandLineState.Profile);
|
||||
|
||||
VirtualFileSystem.ReloadKeySet();
|
||||
|
||||
@ -525,6 +526,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath;
|
||||
GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
|
||||
GraphicsConfig.EnableTextureRecompression = ConfigurationState.Instance.Graphics.EnableTextureRecompression;
|
||||
GraphicsConfig.EnableMacroHLE = ConfigurationState.Instance.Graphics.EnableMacroHLE;
|
||||
}
|
||||
|
||||
public void LoadHotKeys()
|
||||
|
@ -568,6 +568,10 @@
|
||||
ToolTip.Tip="{locale:Locale SettingsEnableTextureRecompressionTooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsEnableTextureRecompression}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding EnableMacroHLE}"
|
||||
ToolTip.Tip="{locale:Locale SettingsEnableMacroHLETooltip}">
|
||||
<TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
|
@ -36,13 +36,13 @@ namespace Ryujinx.Common.SystemInfo
|
||||
|
||||
ParseKeyValues("/proc/meminfo", memDict);
|
||||
|
||||
// Entries are in KB
|
||||
ulong.TryParse(memDict["MemTotal"]?.Split(' ')[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong totalKB);
|
||||
ulong.TryParse(memDict["MemAvailable"]?.Split(' ')[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong availableKB);
|
||||
// Entries are in KiB
|
||||
ulong.TryParse(memDict["MemTotal"]?.Split(' ')[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong totalKiB);
|
||||
ulong.TryParse(memDict["MemAvailable"]?.Split(' ')[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong availableKiB);
|
||||
|
||||
CpuName = $"{cpuName} ; {LogicalCoreCount} logical";
|
||||
RamTotal = totalKB * 1024;
|
||||
RamAvailable = availableKB * 1024;
|
||||
RamTotal = totalKiB * 1024;
|
||||
RamAvailable = availableKiB * 1024;
|
||||
}
|
||||
|
||||
private static void ParseKeyValues(string filePath, Dictionary<string, string> itemDict)
|
||||
|
@ -20,13 +20,13 @@ namespace Ryujinx.Common.SystemInfo
|
||||
CpuName = "Unknown";
|
||||
}
|
||||
|
||||
private static string ToMBString(ulong bytesValue) => (bytesValue == 0) ? "Unknown" : $"{bytesValue / 1024 / 1024} MB";
|
||||
private static string ToMiBString(ulong bytesValue) => (bytesValue == 0) ? "Unknown" : $"{bytesValue / 1024 / 1024} MiB";
|
||||
|
||||
public void Print()
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"Operating System: {OsDescription}");
|
||||
Logger.Notice.Print(LogClass.Application, $"CPU: {CpuName}");
|
||||
Logger.Notice.Print(LogClass.Application, $"RAM: Total {ToMBString(RamTotal)} ; Available {ToMBString(RamAvailable)}");
|
||||
Logger.Notice.Print(LogClass.Application, $"RAM: Total {ToMiBString(RamTotal)} ; Available {ToMiBString(RamAvailable)}");
|
||||
}
|
||||
|
||||
public static SystemInfo Gather()
|
||||
|
@ -27,7 +27,7 @@ namespace Ryujinx.Cpu
|
||||
long TpidrroEl0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Processor State register.
|
||||
/// Processor State Register.
|
||||
/// </summary>
|
||||
uint Pstate { get; set; }
|
||||
|
||||
|
14
Ryujinx.Graphics.GAL/BufferAssignment.cs
Normal file
14
Ryujinx.Graphics.GAL/BufferAssignment.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct BufferAssignment
|
||||
{
|
||||
public readonly int Binding;
|
||||
public readonly BufferRange Range;
|
||||
|
||||
public BufferAssignment(int binding, BufferRange range)
|
||||
{
|
||||
Binding = binding;
|
||||
Range = range;
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
public readonly bool SupportsFragmentShaderOrderingIntel;
|
||||
public readonly bool SupportsGeometryShaderPassthrough;
|
||||
public readonly bool SupportsImageLoadFormatted;
|
||||
public readonly bool SupportsLayerVertexTessellation;
|
||||
public readonly bool SupportsMismatchingViewFormat;
|
||||
public readonly bool SupportsCubemapView;
|
||||
public readonly bool SupportsNonConstantTextureOffset;
|
||||
@ -55,6 +56,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
bool supportsFragmentShaderOrderingIntel,
|
||||
bool supportsGeometryShaderPassthrough,
|
||||
bool supportsImageLoadFormatted,
|
||||
bool supportsLayerVertexTessellation,
|
||||
bool supportsMismatchingViewFormat,
|
||||
bool supportsCubemapView,
|
||||
bool supportsNonConstantTextureOffset,
|
||||
@ -86,6 +88,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
|
||||
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
||||
SupportsImageLoadFormatted = supportsImageLoadFormatted;
|
||||
SupportsLayerVertexTessellation = supportsLayerVertexTessellation;
|
||||
SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
|
||||
SupportsCubemapView = supportsCubemapView;
|
||||
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
|
||||
|
@ -34,13 +34,14 @@ namespace Ryujinx.Graphics.GAL
|
||||
int firstIndex,
|
||||
int firstVertex,
|
||||
int firstInstance);
|
||||
void DrawIndexedIndirect(BufferRange indirectBuffer);
|
||||
void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride);
|
||||
void DrawIndirect(BufferRange indirectBuffer);
|
||||
void DrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride);
|
||||
void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion);
|
||||
|
||||
void EndTransformFeedback();
|
||||
|
||||
void MultiDrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride);
|
||||
void MultiDrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride);
|
||||
|
||||
void SetAlphaTest(bool enable, float reference, CompareOp op);
|
||||
|
||||
void SetBlendState(int index, BlendDescriptor blend);
|
||||
@ -85,12 +86,12 @@ namespace Ryujinx.Graphics.GAL
|
||||
|
||||
void SetStencilTest(StencilTestDescriptor stencilTest);
|
||||
|
||||
void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers);
|
||||
void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers);
|
||||
|
||||
void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler);
|
||||
|
||||
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
|
||||
void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers);
|
||||
void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers);
|
||||
|
||||
void SetUserClipDistance(int index, bool enableClip);
|
||||
|
||||
|
@ -142,6 +142,30 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
return ranges;
|
||||
}
|
||||
|
||||
internal Span<BufferAssignment> MapBufferRanges(Span<BufferAssignment> ranges)
|
||||
{
|
||||
// Rewrite the buffer ranges to point to the mapped handles.
|
||||
|
||||
lock (_bufferMap)
|
||||
{
|
||||
for (int i = 0; i < ranges.Length; i++)
|
||||
{
|
||||
ref BufferAssignment assignment = ref ranges[i];
|
||||
BufferRange range = assignment.Range;
|
||||
BufferHandle result;
|
||||
|
||||
if (!_bufferMap.TryGetValue(range.Handle, out result))
|
||||
{
|
||||
result = BufferHandle.Null;
|
||||
}
|
||||
|
||||
assignment = new BufferAssignment(ranges[i].Binding, new BufferRange(result, range.Offset, range.Size));
|
||||
}
|
||||
}
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
internal Span<VertexBufferDescriptor> MapBufferRanges(Span<VertexBufferDescriptor> ranges)
|
||||
{
|
||||
// Rewrite the buffer ranges to point to the mapped handles.
|
||||
|
@ -141,16 +141,20 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
DrawCommand.Run(ref GetCommand<DrawCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.DrawIndexed] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
DrawIndexedCommand.Run(ref GetCommand<DrawIndexedCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.DrawIndexedIndirect] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
DrawIndexedIndirectCommand.Run(ref GetCommand<DrawIndexedIndirectCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.DrawIndexedIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
DrawIndexedIndirectCountCommand.Run(ref GetCommand<DrawIndexedIndirectCountCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.DrawIndirect] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
DrawIndirectCommand.Run(ref GetCommand<DrawIndirectCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.DrawIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
DrawIndirectCountCommand.Run(ref GetCommand<DrawIndirectCountCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.DrawTexture] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
DrawTextureCommand.Run(ref GetCommand<DrawTextureCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.EndHostConditionalRendering] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
EndHostConditionalRenderingCommand.Run(renderer);
|
||||
_lookup[(int)CommandType.EndTransformFeedback] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
EndTransformFeedbackCommand.Run(ref GetCommand<EndTransformFeedbackCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.MultiDrawIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
MultiDrawIndirectCountCommand.Run(ref GetCommand<MultiDrawIndirectCountCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.MultiDrawIndexedIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
MultiDrawIndexedIndirectCountCommand.Run(ref GetCommand<MultiDrawIndexedIndirectCountCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetAlphaTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
SetAlphaTestCommand.Run(ref GetCommand<SetAlphaTestCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.SetBlendState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
|
@ -52,11 +52,13 @@
|
||||
DispatchCompute,
|
||||
Draw,
|
||||
DrawIndexed,
|
||||
DrawIndexedIndirect,
|
||||
DrawIndexedIndirectCount,
|
||||
DrawIndirect,
|
||||
DrawIndirectCount,
|
||||
DrawTexture,
|
||||
EndHostConditionalRendering,
|
||||
EndTransformFeedback,
|
||||
MultiDrawIndirectCount,
|
||||
MultiDrawIndexedIndirectCount,
|
||||
SetAlphaTest,
|
||||
SetBlendState,
|
||||
SetDepthBias,
|
||||
|
@ -0,0 +1,18 @@
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||
{
|
||||
struct DrawIndexedIndirectCommand : IGALCommand
|
||||
{
|
||||
public CommandType CommandType => CommandType.DrawIndexedIndirect;
|
||||
private BufferRange _indirectBuffer;
|
||||
|
||||
public void Set(BufferRange indirectBuffer)
|
||||
{
|
||||
_indirectBuffer = indirectBuffer;
|
||||
}
|
||||
|
||||
public static void Run(ref DrawIndexedIndirectCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
renderer.Pipeline.DrawIndexedIndirect(threaded.Buffers.MapBufferRange(command._indirectBuffer));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||
{
|
||||
struct MultiDrawIndexedIndirectCountCommand : IGALCommand
|
||||
struct DrawIndexedIndirectCountCommand : IGALCommand
|
||||
{
|
||||
public CommandType CommandType => CommandType.MultiDrawIndexedIndirectCount;
|
||||
public CommandType CommandType => CommandType.DrawIndexedIndirectCount;
|
||||
private BufferRange _indirectBuffer;
|
||||
private BufferRange _parameterBuffer;
|
||||
private int _maxDrawCount;
|
||||
@ -16,9 +16,9 @@
|
||||
_stride = stride;
|
||||
}
|
||||
|
||||
public static void Run(ref MultiDrawIndexedIndirectCountCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
public static void Run(ref DrawIndexedIndirectCountCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
renderer.Pipeline.MultiDrawIndexedIndirectCount(
|
||||
renderer.Pipeline.DrawIndexedIndirectCount(
|
||||
threaded.Buffers.MapBufferRange(command._indirectBuffer),
|
||||
threaded.Buffers.MapBufferRange(command._parameterBuffer),
|
||||
command._maxDrawCount,
|
@ -0,0 +1,18 @@
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||
{
|
||||
struct DrawIndirectCommand : IGALCommand
|
||||
{
|
||||
public CommandType CommandType => CommandType.DrawIndirect;
|
||||
private BufferRange _indirectBuffer;
|
||||
|
||||
public void Set(BufferRange indirectBuffer)
|
||||
{
|
||||
_indirectBuffer = indirectBuffer;
|
||||
}
|
||||
|
||||
public static void Run(ref DrawIndirectCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
renderer.Pipeline.DrawIndirect(threaded.Buffers.MapBufferRange(command._indirectBuffer));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||
{
|
||||
struct MultiDrawIndirectCountCommand : IGALCommand
|
||||
struct DrawIndirectCountCommand : IGALCommand
|
||||
{
|
||||
public CommandType CommandType => CommandType.MultiDrawIndirectCount;
|
||||
public CommandType CommandType => CommandType.DrawIndirectCount;
|
||||
private BufferRange _indirectBuffer;
|
||||
private BufferRange _parameterBuffer;
|
||||
private int _maxDrawCount;
|
||||
@ -16,9 +16,9 @@
|
||||
_stride = stride;
|
||||
}
|
||||
|
||||
public static void Run(ref MultiDrawIndirectCountCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
public static void Run(ref DrawIndirectCountCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
renderer.Pipeline.MultiDrawIndirectCount(
|
||||
renderer.Pipeline.DrawIndirectCount(
|
||||
threaded.Buffers.MapBufferRange(command._indirectBuffer),
|
||||
threaded.Buffers.MapBufferRange(command._parameterBuffer),
|
||||
command._maxDrawCount,
|
@ -6,19 +6,17 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||
struct SetStorageBuffersCommand : IGALCommand
|
||||
{
|
||||
public CommandType CommandType => CommandType.SetStorageBuffers;
|
||||
private int _first;
|
||||
private SpanRef<BufferRange> _buffers;
|
||||
private SpanRef<BufferAssignment> _buffers;
|
||||
|
||||
public void Set(int first, SpanRef<BufferRange> buffers)
|
||||
public void Set(SpanRef<BufferAssignment> buffers)
|
||||
{
|
||||
_first = first;
|
||||
_buffers = buffers;
|
||||
}
|
||||
|
||||
public static void Run(ref SetStorageBuffersCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
Span<BufferRange> buffers = command._buffers.Get(threaded);
|
||||
renderer.Pipeline.SetStorageBuffers(command._first, threaded.Buffers.MapBufferRanges(buffers));
|
||||
Span<BufferAssignment> buffers = command._buffers.Get(threaded);
|
||||
renderer.Pipeline.SetStorageBuffers(threaded.Buffers.MapBufferRanges(buffers));
|
||||
command._buffers.Dispose(threaded);
|
||||
}
|
||||
}
|
||||
|
@ -6,19 +6,17 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||
struct SetUniformBuffersCommand : IGALCommand
|
||||
{
|
||||
public CommandType CommandType => CommandType.SetUniformBuffers;
|
||||
private int _first;
|
||||
private SpanRef<BufferRange> _buffers;
|
||||
private SpanRef<BufferAssignment> _buffers;
|
||||
|
||||
public void Set(int first, SpanRef<BufferRange> buffers)
|
||||
public void Set(SpanRef<BufferAssignment> buffers)
|
||||
{
|
||||
_first = first;
|
||||
_buffers = buffers;
|
||||
}
|
||||
|
||||
public static void Run(ref SetUniformBuffersCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
Span<BufferRange> buffers = command._buffers.Get(threaded);
|
||||
renderer.Pipeline.SetUniformBuffers(command._first, threaded.Buffers.MapBufferRanges(buffers));
|
||||
Span<BufferAssignment> buffers = command._buffers.Get(threaded);
|
||||
renderer.Pipeline.SetUniformBuffers(threaded.Buffers.MapBufferRanges(buffers));
|
||||
command._buffers.Dispose(threaded);
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +83,30 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void DrawIndexedIndirect(BufferRange indirectBuffer)
|
||||
{
|
||||
_renderer.New<DrawIndexedIndirectCommand>().Set(indirectBuffer);
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
||||
{
|
||||
_renderer.New<DrawIndexedIndirectCountCommand>().Set(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void DrawIndirect(BufferRange indirectBuffer)
|
||||
{
|
||||
_renderer.New<DrawIndirectCommand>().Set(indirectBuffer);
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void DrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
||||
{
|
||||
_renderer.New<DrawIndirectCountCommand>().Set(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion)
|
||||
{
|
||||
_renderer.New<DrawTextureCommand>().Set(Ref(texture), Ref(sampler), srcRegion, dstRegion);
|
||||
@ -101,18 +125,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void MultiDrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
||||
{
|
||||
_renderer.New<MultiDrawIndirectCountCommand>().Set(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void MultiDrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
||||
{
|
||||
_renderer.New<MultiDrawIndexedIndirectCountCommand>().Set(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void SetAlphaTest(bool enable, float reference, CompareOp op)
|
||||
{
|
||||
_renderer.New<SetAlphaTestCommand>().Set(enable, reference, op);
|
||||
@ -263,9 +275,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers)
|
||||
public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
||||
{
|
||||
_renderer.New<SetStorageBuffersCommand>().Set(first, _renderer.CopySpan(buffers));
|
||||
_renderer.New<SetStorageBuffersCommand>().Set(_renderer.CopySpan(buffers));
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
@ -281,9 +293,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers)
|
||||
public void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
||||
{
|
||||
_renderer.New<SetUniformBuffersCommand>().Set(first, _renderer.CopySpan(buffers));
|
||||
_renderer.New<SetUniformBuffersCommand>().Set(_renderer.CopySpan(buffers));
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
|
@ -95,5 +95,10 @@ namespace Ryujinx.Graphics.Gpu
|
||||
/// Byte alignment for block linear textures
|
||||
/// </summary>
|
||||
public const int GobAlignment = 64;
|
||||
|
||||
/// <summary>
|
||||
/// Expected byte alignment for storage buffers
|
||||
/// </summary>
|
||||
public const int StorageAlignment = 16;
|
||||
}
|
||||
}
|
@ -138,7 +138,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
||||
qmd.CtaThreadDimension1,
|
||||
qmd.CtaThreadDimension2,
|
||||
localMemorySize,
|
||||
sharedMemorySize);
|
||||
sharedMemorySize,
|
||||
_channel.BufferManager.HasUnalignedStorageBuffers);
|
||||
|
||||
CachedShaderProgram cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa);
|
||||
|
||||
@ -150,6 +151,33 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
||||
|
||||
ShaderProgramInfo info = cs.Shaders[0].Info;
|
||||
|
||||
bool hasUnaligned = _channel.BufferManager.HasUnalignedStorageBuffers;
|
||||
|
||||
for (int index = 0; index < info.SBuffers.Count; index++)
|
||||
{
|
||||
BufferDescriptor sb = info.SBuffers[index];
|
||||
|
||||
ulong sbDescAddress = _channel.BufferManager.GetComputeUniformBufferAddress(0);
|
||||
|
||||
int sbDescOffset = 0x310 + sb.Slot * 0x10;
|
||||
|
||||
sbDescAddress += (ulong)sbDescOffset;
|
||||
|
||||
SbDescriptor sbDescriptor = _channel.MemoryManager.Physical.Read<SbDescriptor>(sbDescAddress);
|
||||
|
||||
_channel.BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags);
|
||||
}
|
||||
|
||||
if ((_channel.BufferManager.HasUnalignedStorageBuffers) != hasUnaligned)
|
||||
{
|
||||
// Refetch the shader, as assumptions about storage buffer alignment have changed.
|
||||
cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa);
|
||||
|
||||
_context.Renderer.Pipeline.SetProgram(cs.HostProgram);
|
||||
|
||||
info = cs.Shaders[0].Info;
|
||||
}
|
||||
|
||||
for (int index = 0; index < info.CBuffers.Count; index++)
|
||||
{
|
||||
BufferDescriptor cb = info.CBuffers[index];
|
||||
@ -174,21 +202,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
||||
_channel.BufferManager.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
|
||||
}
|
||||
|
||||
for (int index = 0; index < info.SBuffers.Count; index++)
|
||||
{
|
||||
BufferDescriptor sb = info.SBuffers[index];
|
||||
|
||||
ulong sbDescAddress = _channel.BufferManager.GetComputeUniformBufferAddress(0);
|
||||
|
||||
int sbDescOffset = 0x310 + sb.Slot * 0x10;
|
||||
|
||||
sbDescAddress += (ulong)sbDescOffset;
|
||||
|
||||
SbDescriptor sbDescriptor = _channel.MemoryManager.Physical.Read<SbDescriptor>(sbDescAddress);
|
||||
|
||||
_channel.BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags);
|
||||
}
|
||||
|
||||
_channel.BufferManager.SetComputeStorageBufferBindings(info.SBuffers);
|
||||
_channel.BufferManager.SetComputeUniformBufferBindings(info.CBuffers);
|
||||
|
||||
|
@ -51,16 +51,35 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
||||
/// </summary>
|
||||
public uint EntryCount;
|
||||
|
||||
/// <summary>
|
||||
/// Get the entries for the command buffer from memory.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">The memory manager used to fetch the data</param>
|
||||
/// <param name="flush">If true, flushes potential GPU written data before reading the command buffer</param>
|
||||
/// <returns>The fetched data</returns>
|
||||
private ReadOnlySpan<int> GetWords(MemoryManager memoryManager, bool flush)
|
||||
{
|
||||
return MemoryMarshal.Cast<byte, int>(memoryManager.GetSpan(EntryAddress, (int)EntryCount * 4, flush));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prefetch the command buffer.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">The memory manager used to fetch the data</param>
|
||||
public void Prefetch(MemoryManager memoryManager)
|
||||
{
|
||||
Words = GetWords(memoryManager, true).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetch the command buffer.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">The memory manager used to fetch the data</param>
|
||||
/// <param name="flush">If true, flushes potential GPU written data before reading the command buffer</param>
|
||||
public void Fetch(MemoryManager memoryManager, bool flush = true)
|
||||
/// <returns>The command buffer words</returns>
|
||||
public ReadOnlySpan<int> Fetch(MemoryManager memoryManager, bool flush)
|
||||
{
|
||||
if (Words == null)
|
||||
{
|
||||
Words = MemoryMarshal.Cast<byte, int>(memoryManager.GetSpan(EntryAddress, (int)EntryCount * 4, flush)).ToArray();
|
||||
}
|
||||
return Words ?? GetWords(memoryManager, flush);
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,7 +177,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
||||
|
||||
if (beforeBarrier && commandBuffer.Type == CommandBufferType.Prefetch)
|
||||
{
|
||||
commandBuffer.Fetch(processor.MemoryManager);
|
||||
commandBuffer.Prefetch(processor.MemoryManager);
|
||||
}
|
||||
|
||||
if (commandBuffer.Type == CommandBufferType.NoPrefetch)
|
||||
@ -199,7 +218,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
||||
}
|
||||
|
||||
_currentCommandBuffer = entry;
|
||||
_currentCommandBuffer.Fetch(entry.Processor.MemoryManager, flushCommandBuffer);
|
||||
ReadOnlySpan<int> words = entry.Fetch(entry.Processor.MemoryManager, flushCommandBuffer);
|
||||
|
||||
// If we are changing the current channel,
|
||||
// we need to force all the host state to be updated.
|
||||
@ -209,7 +228,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
||||
entry.Processor.ForceAllDirty();
|
||||
}
|
||||
|
||||
entry.Processor.Process(entry.EntryAddress, _currentCommandBuffer.Words);
|
||||
entry.Processor.Process(entry.EntryAddress, words);
|
||||
}
|
||||
|
||||
_interrupt = false;
|
||||
|
@ -62,10 +62,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
}
|
||||
}
|
||||
|
||||
if (_hleFunction == MacroHLEFunctionName.MultiDrawElementsIndirectCount)
|
||||
{
|
||||
// We don't consume the parameter buffer value, so we don't need to flush it.
|
||||
// Doing so improves performance if the value was written by a GPU shader.
|
||||
if (_hleFunction == MacroHLEFunctionName.DrawElementsIndirect)
|
||||
{
|
||||
context.GPFifo.SetFlushSkips(1);
|
||||
}
|
||||
else if (_hleFunction == MacroHLEFunctionName.MultiDrawElementsIndirectCount)
|
||||
{
|
||||
context.GPFifo.SetFlushSkips(2);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
private const int ColorStructSize = 0x40;
|
||||
private const int ZetaLayerCountOffset = 0x1230;
|
||||
|
||||
private const int IndirectDataEntrySize = 0x10;
|
||||
private const int IndirectIndexedDataEntrySize = 0x14;
|
||||
|
||||
private readonly GPFifoProcessor _processor;
|
||||
private readonly MacroHLEFunctionName _functionName;
|
||||
|
||||
@ -27,9 +30,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
/// <summary>
|
||||
/// Creates a new instance of the HLE macro handler.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context the macro is being executed on</param>
|
||||
/// <param name="memoryManager">GPU memory manager</param>
|
||||
/// <param name="engine">3D engine where this macro is being called</param>
|
||||
/// <param name="processor">GPU GP FIFO command processor</param>
|
||||
/// <param name="functionName">Name of the HLE macro function to be called</param>
|
||||
public MacroHLE(GPFifoProcessor processor, MacroHLEFunctionName functionName)
|
||||
{
|
||||
@ -55,12 +56,24 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
case MacroHLEFunctionName.ClearDepthStencil:
|
||||
ClearDepthStencil(state, arg0);
|
||||
break;
|
||||
case MacroHLEFunctionName.DrawArraysInstanced:
|
||||
DrawArraysInstanced(state, arg0);
|
||||
break;
|
||||
case MacroHLEFunctionName.DrawElementsInstanced:
|
||||
DrawElementsInstanced(state, arg0);
|
||||
break;
|
||||
case MacroHLEFunctionName.DrawElementsIndirect:
|
||||
DrawElementsIndirect(state, arg0);
|
||||
break;
|
||||
case MacroHLEFunctionName.MultiDrawElementsIndirectCount:
|
||||
MultiDrawElementsIndirectCount(state, arg0);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(_functionName.ToString());
|
||||
}
|
||||
|
||||
// It should be empty at this point, but clear it just to be safe.
|
||||
Fifo.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -89,7 +102,118 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indirect multi-draw, with parameters from a GPU buffer.
|
||||
/// Performs a draw.
|
||||
/// </summary>
|
||||
/// <param name="state">GPU state at the time of the call</param>
|
||||
/// <param name="arg0">First argument of the call</param>
|
||||
private void DrawArraysInstanced(IDeviceState state, int arg0)
|
||||
{
|
||||
var topology = (PrimitiveTopology)arg0;
|
||||
|
||||
var count = FetchParam();
|
||||
var instanceCount = FetchParam();
|
||||
var firstVertex = FetchParam();
|
||||
var firstInstance = FetchParam();
|
||||
|
||||
if (ShouldSkipDraw(state, instanceCount.Word))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_processor.ThreedClass.Draw(
|
||||
topology,
|
||||
count.Word,
|
||||
instanceCount.Word,
|
||||
0,
|
||||
firstVertex.Word,
|
||||
firstInstance.Word,
|
||||
indexed: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw.
|
||||
/// </summary>
|
||||
/// <param name="state">GPU state at the time of the call</param>
|
||||
/// <param name="arg0">First argument of the call</param>
|
||||
private void DrawElementsInstanced(IDeviceState state, int arg0)
|
||||
{
|
||||
var topology = (PrimitiveTopology)arg0;
|
||||
|
||||
var count = FetchParam();
|
||||
var instanceCount = FetchParam();
|
||||
var firstIndex = FetchParam();
|
||||
var firstVertex = FetchParam();
|
||||
var firstInstance = FetchParam();
|
||||
|
||||
if (ShouldSkipDraw(state, instanceCount.Word))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_processor.ThreedClass.Draw(
|
||||
topology,
|
||||
count.Word,
|
||||
instanceCount.Word,
|
||||
firstIndex.Word,
|
||||
firstVertex.Word,
|
||||
firstInstance.Word,
|
||||
indexed: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indirect indexed draw, with parameters from a GPU buffer.
|
||||
/// </summary>
|
||||
/// <param name="state">GPU state at the time of the call</param>
|
||||
/// <param name="arg0">First argument of the call</param>
|
||||
private void DrawElementsIndirect(IDeviceState state, int arg0)
|
||||
{
|
||||
var topology = (PrimitiveTopology)arg0;
|
||||
|
||||
var count = FetchParam();
|
||||
var instanceCount = FetchParam();
|
||||
var firstIndex = FetchParam();
|
||||
var firstVertex = FetchParam();
|
||||
var firstInstance = FetchParam();
|
||||
|
||||
ulong indirectBufferGpuVa = count.GpuVa;
|
||||
|
||||
var bufferCache = _processor.MemoryManager.Physical.BufferCache;
|
||||
|
||||
bool useBuffer = bufferCache.CheckModified(_processor.MemoryManager, indirectBufferGpuVa, IndirectIndexedDataEntrySize, out ulong indirectBufferAddress);
|
||||
|
||||
if (useBuffer)
|
||||
{
|
||||
int indexCount = firstIndex.Word + count.Word;
|
||||
|
||||
_processor.ThreedClass.DrawIndirect(
|
||||
topology,
|
||||
indirectBufferAddress,
|
||||
0,
|
||||
1,
|
||||
IndirectIndexedDataEntrySize,
|
||||
indexCount,
|
||||
Threed.IndirectDrawType.DrawIndexedIndirect);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ShouldSkipDraw(state, instanceCount.Word))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_processor.ThreedClass.Draw(
|
||||
topology,
|
||||
count.Word,
|
||||
instanceCount.Word,
|
||||
firstIndex.Word,
|
||||
firstVertex.Word,
|
||||
firstInstance.Word,
|
||||
indexed: true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indirect indexed multi-draw, with parameters from a GPU buffer.
|
||||
/// </summary>
|
||||
/// <param name="state">GPU state at the time of the call</param>
|
||||
/// <param name="arg0">First argument of the call</param>
|
||||
@ -132,8 +256,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
return;
|
||||
}
|
||||
|
||||
int indirectBufferSize = maxDrawCount * stride;
|
||||
|
||||
ulong indirectBufferGpuVa = 0;
|
||||
int indexCount = 0;
|
||||
|
||||
@ -142,8 +264,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
var count = FetchParam();
|
||||
var instanceCount = FetchParam();
|
||||
var firstIndex = FetchParam();
|
||||
var baseVertex = FetchParam();
|
||||
var baseInstance = FetchParam();
|
||||
var firstVertex = FetchParam();
|
||||
var firstInstance = FetchParam();
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
@ -161,15 +283,32 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
}
|
||||
}
|
||||
|
||||
// It should be empty at this point, but clear it just to be safe.
|
||||
Fifo.Clear();
|
||||
|
||||
var bufferCache = _processor.MemoryManager.Physical.BufferCache;
|
||||
|
||||
var parameterBuffer = bufferCache.GetGpuBufferRange(_processor.MemoryManager, parameterBufferGpuVa, 4);
|
||||
var indirectBuffer = bufferCache.GetGpuBufferRange(_processor.MemoryManager, indirectBufferGpuVa, (ulong)indirectBufferSize);
|
||||
ulong indirectBufferSize = (ulong)maxDrawCount * (ulong)stride;
|
||||
|
||||
_processor.ThreedClass.MultiDrawIndirectCount(indexCount, topology, indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
||||
ulong indirectBufferAddress = bufferCache.TranslateAndCreateBuffer(_processor.MemoryManager, indirectBufferGpuVa, indirectBufferSize);
|
||||
ulong parameterBufferAddress = bufferCache.TranslateAndCreateBuffer(_processor.MemoryManager, parameterBufferGpuVa, 4);
|
||||
|
||||
_processor.ThreedClass.DrawIndirect(
|
||||
topology,
|
||||
indirectBufferAddress,
|
||||
parameterBufferAddress,
|
||||
maxDrawCount,
|
||||
stride,
|
||||
indexCount,
|
||||
Threed.IndirectDrawType.DrawIndexedIndirectCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the draw should be skipped, because the masked instance count is zero.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="instanceCount">Draw instance count</param>
|
||||
/// <returns>True if the draw should be skipped, false otherwise</returns>
|
||||
private static bool ShouldSkipDraw(IDeviceState state, int instanceCount)
|
||||
{
|
||||
return (Read(state, 0xd1b) & instanceCount) == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -189,14 +328,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a GPU method call.
|
||||
/// Reads data from a GPU register.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="methAddr">Address, in words, of the method</param>
|
||||
/// <param name="value">Call argument</param>
|
||||
private static void Send(IDeviceState state, int methAddr, int value)
|
||||
/// <param name="reg">Register offset to read</param>
|
||||
/// <returns>GPU register value</returns>
|
||||
private static int Read(IDeviceState state, int reg)
|
||||
{
|
||||
state.Write(methAddr * 4, value);
|
||||
return state.Read(reg * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,9 @@
|
||||
None,
|
||||
ClearColor,
|
||||
ClearDepthStencil,
|
||||
DrawArraysInstanced,
|
||||
DrawElementsInstanced,
|
||||
DrawElementsIndirect,
|
||||
MultiDrawElementsIndirectCount
|
||||
}
|
||||
}
|
||||
|
@ -44,17 +44,29 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly TableEntry[] Table = new TableEntry[]
|
||||
private static readonly TableEntry[] _table = new TableEntry[]
|
||||
{
|
||||
new TableEntry(MacroHLEFunctionName.ClearColor, new Hash128(0xA9FB28D1DC43645A, 0xB177E5D2EAE67FB0), 0x28),
|
||||
new TableEntry(MacroHLEFunctionName.ClearDepthStencil, new Hash128(0x1B96CB77D4879F4F, 0x8557032FE0C965FB), 0x24),
|
||||
new TableEntry(MacroHLEFunctionName.DrawArraysInstanced, new Hash128(0x197FB416269DBC26, 0x34288C01DDA82202), 0x48),
|
||||
new TableEntry(MacroHLEFunctionName.DrawElementsInstanced, new Hash128(0x1A501FD3D54EC8E0, 0x6CF570CF79DA74D6), 0x5c),
|
||||
new TableEntry(MacroHLEFunctionName.DrawElementsIndirect, new Hash128(0x86A3E8E903AF8F45, 0xD35BBA07C23860A4), 0x7c),
|
||||
new TableEntry(MacroHLEFunctionName.MultiDrawElementsIndirectCount, new Hash128(0x890AF57ED3FB1C37, 0x35D0C95C61F5386F), 0x19C)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the host supports all features required by the HLE macro.
|
||||
/// </summary>
|
||||
/// <param name="caps">Host capabilities</param>
|
||||
/// <param name="name">Name of the HLE macro to be checked</param>
|
||||
/// <returns>True if the host supports the HLE macro, false otherwise</returns>
|
||||
private static bool IsMacroHLESupported(Capabilities caps, MacroHLEFunctionName name)
|
||||
{
|
||||
if (name == MacroHLEFunctionName.ClearColor ||
|
||||
name == MacroHLEFunctionName.ClearDepthStencil)
|
||||
name == MacroHLEFunctionName.ClearDepthStencil ||
|
||||
name == MacroHLEFunctionName.DrawArraysInstanced ||
|
||||
name == MacroHLEFunctionName.DrawElementsInstanced ||
|
||||
name == MacroHLEFunctionName.DrawElementsIndirect)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -77,15 +89,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
{
|
||||
var mc = MemoryMarshal.Cast<int, byte>(code);
|
||||
|
||||
for (int i = 0; i < Table.Length; i++)
|
||||
for (int i = 0; i < _table.Length; i++)
|
||||
{
|
||||
ref var entry = ref Table[i];
|
||||
ref var entry = ref _table[i];
|
||||
|
||||
var hash = XXHash128.ComputeHash(mc.Slice(0, entry.Length));
|
||||
if (hash == entry.Hash)
|
||||
{
|
||||
if (IsMacroHLESupported(caps, entry.Name))
|
||||
{
|
||||
name = entry.Name;
|
||||
return IsMacroHLESupported(caps, name);
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
else
|
||||
{
|
||||
evt.Flush();
|
||||
return (memoryManager.Read<ulong>(gpuVa) != 0) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
|
||||
return (memoryManager.Read<ulong>(gpuVa, true) != 0) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,8 +108,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
evt?.Flush();
|
||||
evt2?.Flush();
|
||||
|
||||
ulong x = memoryManager.Read<ulong>(gpuVa);
|
||||
ulong y = memoryManager.Read<ulong>(gpuVa + 16);
|
||||
ulong x = memoryManager.Read<ulong>(gpuVa, true);
|
||||
ulong y = memoryManager.Read<ulong>(gpuVa + 16, true);
|
||||
|
||||
return (isEqual ? x == y : x != y) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
@ -9,6 +10,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
class DrawManager
|
||||
{
|
||||
// Since we don't know the index buffer size for indirect draws,
|
||||
// we must assume a minimum and maximum size and use that for buffer data update purposes.
|
||||
private const int MinIndirectIndexCount = 0x10000;
|
||||
private const int MaxIndirectIndexCount = 0x4000000;
|
||||
|
||||
private readonly GpuContext _context;
|
||||
private readonly GpuChannel _channel;
|
||||
private readonly DeviceStateWithShadow<ThreedClassState> _state;
|
||||
@ -28,6 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
private int _instanceIndex;
|
||||
|
||||
private const int VertexBufferFirstMethodOffset = 0x35d;
|
||||
private const int IndexBufferCountMethodOffset = 0x5f8;
|
||||
|
||||
/// <summary>
|
||||
@ -237,6 +244,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_instanceIndex = 0;
|
||||
}
|
||||
|
||||
UpdateTopology(topology);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the current primitive topology if needed.
|
||||
/// </summary>
|
||||
/// <param name="topology">New primitive topology</param>
|
||||
private void UpdateTopology(PrimitiveTopology topology)
|
||||
{
|
||||
if (_drawState.Topology != topology || !_topologySet)
|
||||
{
|
||||
_context.Renderer.Pipeline.SetPrimitiveTopology(topology);
|
||||
@ -356,7 +372,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
float srcX1 = ((float)_state.State.DrawTextureDuDx / (1UL << 32)) * dstWidth + srcX0;
|
||||
float srcY1 = ((float)_state.State.DrawTextureDvDy / (1UL << 32)) * dstHeight + srcY0;
|
||||
|
||||
engine.UpdateState();
|
||||
engine.UpdateState(ulong.MaxValue & ~(1UL << StateUpdater.ShaderStateIndex));
|
||||
|
||||
_channel.TextureManager.UpdateRenderTargets();
|
||||
|
||||
int textureId = _state.State.DrawTextureTextureId;
|
||||
int samplerId = _state.State.DrawTextureSamplerId;
|
||||
@ -383,28 +401,27 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indirect multi-draw, with parameters from a GPU buffer.
|
||||
/// Performs a indexed or non-indexed draw.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="topology">Primitive topology</param>
|
||||
/// <param name="indirectBuffer">GPU buffer with the draw parameters, such as count, first index, etc</param>
|
||||
/// <param name="parameterBuffer">GPU buffer with the draw count</param>
|
||||
/// <param name="maxDrawCount">Maximum number of draws that can be made</param>
|
||||
/// <param name="stride">Distance in bytes between each element on the <paramref name="indirectBuffer"/> array</param>
|
||||
public void MultiDrawIndirectCount(
|
||||
/// <param name="count">Index count for indexed draws, vertex count for non-indexed draws</param>
|
||||
/// <param name="instanceCount">Instance count</param>
|
||||
/// <param name="firstIndex">First index on the index buffer for indexed draws, ignored for non-indexed draws</param>
|
||||
/// <param name="firstVertex">First vertex on the vertex buffer</param>
|
||||
/// <param name="firstInstance">First instance</param>
|
||||
/// <param name="indexed">True if the draw is indexed, false otherwise</param>
|
||||
public void Draw(
|
||||
ThreedClass engine,
|
||||
int indexCount,
|
||||
PrimitiveTopology topology,
|
||||
BufferRange indirectBuffer,
|
||||
BufferRange parameterBuffer,
|
||||
int maxDrawCount,
|
||||
int stride)
|
||||
int count,
|
||||
int instanceCount,
|
||||
int firstIndex,
|
||||
int firstVertex,
|
||||
int firstInstance,
|
||||
bool indexed)
|
||||
{
|
||||
engine.Write(IndexBufferCountMethodOffset * 4, indexCount);
|
||||
|
||||
_context.Renderer.Pipeline.SetPrimitiveTopology(topology);
|
||||
_drawState.Topology = topology;
|
||||
_topologySet = true;
|
||||
UpdateTopology(topology);
|
||||
|
||||
ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable(
|
||||
_context,
|
||||
@ -418,21 +435,133 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
return;
|
||||
}
|
||||
|
||||
_drawState.FirstIndex = _state.State.IndexBufferState.First;
|
||||
_drawState.IndexCount = indexCount;
|
||||
|
||||
engine.UpdateState();
|
||||
|
||||
if (_drawState.DrawIndexed)
|
||||
if (indexed)
|
||||
{
|
||||
_context.Renderer.Pipeline.MultiDrawIndexedIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
||||
_drawState.FirstIndex = firstIndex;
|
||||
_drawState.IndexCount = count;
|
||||
_state.State.FirstVertex = (uint)firstVertex;
|
||||
engine.ForceStateDirty(IndexBufferCountMethodOffset * 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.Renderer.Pipeline.MultiDrawIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
||||
_state.State.VertexBufferDrawState.First = firstVertex;
|
||||
_state.State.VertexBufferDrawState.Count = count;
|
||||
engine.ForceStateDirty(VertexBufferFirstMethodOffset * 4);
|
||||
}
|
||||
|
||||
_state.State.FirstInstance = (uint)firstInstance;
|
||||
|
||||
_drawState.DrawIndexed = indexed;
|
||||
_drawState.HasConstantBufferDrawParameters = true;
|
||||
|
||||
engine.UpdateState();
|
||||
|
||||
if (indexed)
|
||||
{
|
||||
_context.Renderer.Pipeline.DrawIndexed(count, instanceCount, firstIndex, firstVertex, firstInstance);
|
||||
_state.State.FirstVertex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.Renderer.Pipeline.Draw(count, instanceCount, firstVertex, firstInstance);
|
||||
}
|
||||
|
||||
_state.State.FirstInstance = 0;
|
||||
|
||||
_drawState.DrawIndexed = false;
|
||||
_drawState.HasConstantBufferDrawParameters = false;
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
_context.Renderer.Pipeline.EndHostConditionalRendering();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indirect draw, with parameters from a GPU buffer.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="topology">Primitive topology</param>
|
||||
/// <param name="indirectBufferAddress">Address of the buffer with the draw parameters, such as count, first index, etc</param>
|
||||
/// <param name="parameterBufferAddress">Address of the buffer with the draw count</param>
|
||||
/// <param name="maxDrawCount">Maximum number of draws that can be made</param>
|
||||
/// <param name="stride">Distance in bytes between each entry on the data pointed to by <paramref name="indirectBufferAddress"/></param>
|
||||
/// <param name="indexCount">Maximum number of indices that the draw can consume</param>
|
||||
/// <param name="drawType">Type of the indirect draw, which can be indexed or non-indexed, with or without a draw count</param>
|
||||
public void DrawIndirect(
|
||||
ThreedClass engine,
|
||||
PrimitiveTopology topology,
|
||||
ulong indirectBufferAddress,
|
||||
ulong parameterBufferAddress,
|
||||
int maxDrawCount,
|
||||
int stride,
|
||||
int indexCount,
|
||||
IndirectDrawType drawType)
|
||||
{
|
||||
UpdateTopology(topology);
|
||||
|
||||
ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable(
|
||||
_context,
|
||||
_channel.MemoryManager,
|
||||
_state.State.RenderEnableAddress,
|
||||
_state.State.RenderEnableCondition);
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.False)
|
||||
{
|
||||
_drawState.DrawIndexed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
PhysicalMemory memory = _channel.MemoryManager.Physical;
|
||||
|
||||
bool hasCount = (drawType & IndirectDrawType.Count) != 0;
|
||||
bool indexed = (drawType & IndirectDrawType.Indexed) != 0;
|
||||
|
||||
if (indexed)
|
||||
{
|
||||
indexCount = Math.Clamp(indexCount, MinIndirectIndexCount, MaxIndirectIndexCount);
|
||||
_drawState.FirstIndex = 0;
|
||||
_drawState.IndexCount = indexCount;
|
||||
engine.ForceStateDirty(IndexBufferCountMethodOffset * 4);
|
||||
}
|
||||
|
||||
_drawState.DrawIndexed = indexed;
|
||||
_drawState.DrawIndirect = true;
|
||||
_drawState.HasConstantBufferDrawParameters = true;
|
||||
|
||||
engine.UpdateState();
|
||||
|
||||
if (hasCount)
|
||||
{
|
||||
var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferAddress, (ulong)maxDrawCount * (ulong)stride);
|
||||
var parameterBuffer = memory.BufferCache.GetBufferRange(parameterBufferAddress, 4);
|
||||
|
||||
if (indexed)
|
||||
{
|
||||
_context.Renderer.Pipeline.DrawIndexedIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.Renderer.Pipeline.DrawIndirectCount(indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferAddress, (ulong)stride);
|
||||
|
||||
if (indexed)
|
||||
{
|
||||
_context.Renderer.Pipeline.DrawIndexedIndirect(indirectBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.Renderer.Pipeline.DrawIndirect(indirectBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
_drawState.DrawIndexed = false;
|
||||
_drawState.DrawIndirect = false;
|
||||
_drawState.HasConstantBufferDrawParameters = false;
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
|
@ -22,6 +22,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
public bool DrawIndexed;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the next draw will be a indirect draw.
|
||||
/// </summary>
|
||||
public bool DrawIndirect;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if any of the currently used vertex shaders reads the instance ID.
|
||||
/// </summary>
|
||||
@ -32,6 +37,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
public bool IsAnyVbInstanced;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0.
|
||||
/// </summary>
|
||||
public bool HasConstantBufferDrawParameters;
|
||||
|
||||
/// <summary>
|
||||
/// Primitive topology for the next draw.
|
||||
/// </summary>
|
||||
|
38
Ryujinx.Graphics.Gpu/Engine/Threed/IndirectDrawType.cs
Normal file
38
Ryujinx.Graphics.Gpu/Engine/Threed/IndirectDrawType.cs
Normal file
@ -0,0 +1,38 @@
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
/// <summary>
|
||||
/// Indirect draw type, which can be indexed or non-indexed, with or without a draw count.
|
||||
/// </summary>
|
||||
enum IndirectDrawType
|
||||
{
|
||||
/// <summary>
|
||||
/// Non-indexed draw without draw count.
|
||||
/// </summary>
|
||||
DrawIndirect = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Indexed draw without draw count.
|
||||
/// </summary>
|
||||
DrawIndexedIndirect = Indexed,
|
||||
|
||||
/// <summary>
|
||||
/// Non-indexed draw with draw count.
|
||||
/// </summary>
|
||||
DrawIndirectCount = Count,
|
||||
|
||||
/// <summary>
|
||||
/// Indexed draw with draw count.
|
||||
/// </summary>
|
||||
DrawIndexedIndirectCount = Indexed | Count,
|
||||
|
||||
/// <summary>
|
||||
/// Indexed flag.
|
||||
/// </summary>
|
||||
Indexed = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// Draw count flag.
|
||||
/// </summary>
|
||||
Count = 1 << 1
|
||||
}
|
||||
}
|
@ -34,10 +34,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
private ProgramPipelineState _pipeline;
|
||||
|
||||
private bool _vsUsesDrawParameters;
|
||||
private bool _vtgWritesRtLayer;
|
||||
private byte _vsClipDistancesWritten;
|
||||
|
||||
private bool _prevDrawIndexed;
|
||||
private bool _prevDrawIndirect;
|
||||
private IndexType _prevIndexType;
|
||||
private uint _prevFirstVertex;
|
||||
private bool _prevTfEnable;
|
||||
@ -210,7 +212,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
// of the shader for the new state.
|
||||
if (_shaderSpecState != null)
|
||||
{
|
||||
if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState(), GetGraphicsState(), false))
|
||||
if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState(), GetGraphicsState(), _vsUsesDrawParameters, false))
|
||||
{
|
||||
ForceShaderUpdate();
|
||||
}
|
||||
@ -237,6 +239,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_prevDrawIndexed = _drawState.DrawIndexed;
|
||||
}
|
||||
|
||||
// Some draw parameters are used to restrict the vertex buffer size,
|
||||
// but they can't be used on indirect draws because their values are unknown in this case.
|
||||
// When switching between indirect and non-indirect draw, we need to
|
||||
// make sure the vertex buffer sizes are still correct.
|
||||
if (_drawState.DrawIndirect != _prevDrawIndirect)
|
||||
{
|
||||
_updateTracker.ForceDirty(VertexBufferStateIndex);
|
||||
}
|
||||
|
||||
// In some cases, the index type is also used to guess the
|
||||
// vertex buffer size, so we must update it if the type changed too.
|
||||
if (_drawState.DrawIndexed &&
|
||||
@ -282,9 +293,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
private void CommitBindings()
|
||||
{
|
||||
var buffers = _channel.BufferManager;
|
||||
var hasUnaligned = buffers.HasUnalignedStorageBuffers;
|
||||
|
||||
UpdateStorageBuffers();
|
||||
|
||||
if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState))
|
||||
if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState) || (buffers.HasUnalignedStorageBuffers != hasUnaligned))
|
||||
{
|
||||
// Shader must be reloaded.
|
||||
UpdateShaderState();
|
||||
@ -938,6 +952,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_drawState.IsAnyVbInstanced = false;
|
||||
|
||||
bool drawIndexed = _drawState.DrawIndexed;
|
||||
bool drawIndirect = _drawState.DrawIndirect;
|
||||
|
||||
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
|
||||
{
|
||||
var vertexBuffer = _state.State.VertexBufferState[index];
|
||||
@ -965,14 +982,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
ulong vbSize = endAddress.Pack() - address + 1;
|
||||
ulong size;
|
||||
|
||||
if (_drawState.IbStreamer.HasInlineIndexData || _drawState.DrawIndexed || stride == 0 || instanced)
|
||||
if (_drawState.IbStreamer.HasInlineIndexData || drawIndexed || stride == 0 || instanced)
|
||||
{
|
||||
// This size may be (much) larger than the real vertex buffer size.
|
||||
// Avoid calculating it this way, unless we don't have any other option.
|
||||
|
||||
size = vbSize;
|
||||
|
||||
if (stride > 0 && indexTypeSmall && _drawState.DrawIndexed && !instanced)
|
||||
if (stride > 0 && indexTypeSmall && drawIndexed && !drawIndirect && !instanced)
|
||||
{
|
||||
// If the index type is a small integer type, then we might be still able
|
||||
// to reduce the vertex buffer size based on the maximum possible index value.
|
||||
@ -1207,6 +1224,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
byte oldVsClipDistancesWritten = _vsClipDistancesWritten;
|
||||
|
||||
_drawState.VsUsesInstanceId = gs.Shaders[1]?.Info.UsesInstanceId ?? false;
|
||||
_vsUsesDrawParameters = gs.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||
_vsClipDistancesWritten = gs.Shaders[1]?.Info.ClipDistancesWritten ?? 0;
|
||||
|
||||
if (oldVsClipDistancesWritten != _vsClipDistancesWritten)
|
||||
@ -1222,6 +1240,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_context.Renderer.Pipeline.SetProgram(gs.HostProgram);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates bindings consumed by the shader stage on the texture and buffer managers.
|
||||
/// </summary>
|
||||
/// <param name="stage">Shader stage to have the bindings updated</param>
|
||||
/// <param name="info">Shader stage bindings info</param>
|
||||
private void UpdateStageBindings(int stage, ShaderProgramInfo info)
|
||||
{
|
||||
_currentProgramInfo[stage] = info;
|
||||
@ -1340,7 +1363,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_state.State.AlphaTestEnable,
|
||||
_state.State.AlphaTestFunc,
|
||||
_state.State.AlphaTestRef,
|
||||
ref attributeTypes);
|
||||
ref attributeTypes,
|
||||
_drawState.HasConstantBufferDrawParameters,
|
||||
_channel.BufferManager.HasUnalignedStorageBuffers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -497,6 +497,50 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed or non-indexed draw.
|
||||
/// </summary>
|
||||
/// <param name="topology">Primitive topology</param>
|
||||
/// <param name="count">Index count for indexed draws, vertex count for non-indexed draws</param>
|
||||
/// <param name="instanceCount">Instance count</param>
|
||||
/// <param name="firstIndex">First index on the index buffer for indexed draws, ignored for non-indexed draws</param>
|
||||
/// <param name="firstVertex">First vertex on the vertex buffer</param>
|
||||
/// <param name="firstInstance">First instance</param>
|
||||
/// <param name="indexed">True if the draw is indexed, false otherwise</param>
|
||||
public void Draw(
|
||||
PrimitiveTopology topology,
|
||||
int count,
|
||||
int instanceCount,
|
||||
int firstIndex,
|
||||
int firstVertex,
|
||||
int firstInstance,
|
||||
bool indexed)
|
||||
{
|
||||
_drawManager.Draw(this, topology, count, instanceCount, firstIndex, firstVertex, firstInstance, indexed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indirect draw, with parameters from a GPU buffer.
|
||||
/// </summary>
|
||||
/// <param name="topology">Primitive topology</param>
|
||||
/// <param name="indirectBufferAddress">Address of the buffer with the draw parameters, such as count, first index, etc</param>
|
||||
/// <param name="parameterBufferAddress">Address of the buffer with the draw count</param>
|
||||
/// <param name="maxDrawCount">Maximum number of draws that can be made</param>
|
||||
/// <param name="stride">Distance in bytes between each entry on the data pointed to by <paramref name="indirectBufferAddress"/></param>
|
||||
/// <param name="indexCount">Maximum number of indices that the draw can consume</param>
|
||||
/// <param name="drawType">Type of the indirect draw, which can be indexed or non-indexed, with or without a draw count</param>
|
||||
public void DrawIndirect(
|
||||
PrimitiveTopology topology,
|
||||
ulong indirectBufferAddress,
|
||||
ulong parameterBufferAddress,
|
||||
int maxDrawCount,
|
||||
int stride,
|
||||
int indexCount,
|
||||
IndirectDrawType drawType)
|
||||
{
|
||||
_drawManager.DrawIndirect(this, topology, indirectBufferAddress, parameterBufferAddress, maxDrawCount, stride, indexCount, drawType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the current color and depth-stencil buffers.
|
||||
/// Which buffers should be cleared can also specified with the arguments.
|
||||
@ -507,25 +551,5 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
_drawManager.Clear(this, argument, layerCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indirect multi-draw, with parameters from a GPU buffer.
|
||||
/// </summary>
|
||||
/// <param name="indexCount">Index Buffer Count</param>
|
||||
/// <param name="topology">Primitive topology</param>
|
||||
/// <param name="indirectBuffer">GPU buffer with the draw parameters, such as count, first index, etc</param>
|
||||
/// <param name="parameterBuffer">GPU buffer with the draw count</param>
|
||||
/// <param name="maxDrawCount">Maximum number of draws that can be made</param>
|
||||
/// <param name="stride">Distance in bytes between each element on the <paramref name="indirectBuffer"/> array</param>
|
||||
public void MultiDrawIndirectCount(
|
||||
int indexCount,
|
||||
PrimitiveTopology topology,
|
||||
BufferRange indirectBuffer,
|
||||
BufferRange parameterBuffer,
|
||||
int maxDrawCount,
|
||||
int stride)
|
||||
{
|
||||
_drawManager.MultiDrawIndirectCount(this, indexCount, topology, indirectBuffer, parameterBuffer, maxDrawCount, stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||
|
||||
// Since the memory manager changed, make sure we will get pools from addresses of the new memory manager.
|
||||
TextureManager.ReloadPools();
|
||||
MemoryManager.Physical.BufferCache.QueuePrune();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -77,6 +78,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||
private void MemoryUnmappedHandler(object sender, UnmapEventArgs e)
|
||||
{
|
||||
TextureManager.ReloadPools();
|
||||
MemoryManager.Physical.BufferCache.QueuePrune();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -131,6 +133,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
oldMemoryManager.Physical.BufferCache.NotifyBuffersModified -= BufferManager.Rebind;
|
||||
oldMemoryManager.Physical.DecrementReferenceCount();
|
||||
oldMemoryManager.MemoryUnmapped -= MemoryUnmappedHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,11 +22,17 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
private readonly GpuContext _context;
|
||||
private readonly PhysicalMemory _physicalMemory;
|
||||
|
||||
/// <remarks>
|
||||
/// Only modified from the GPU thread. Must lock for add/remove.
|
||||
/// Must lock for any access from other threads.
|
||||
/// </remarks>
|
||||
private readonly RangeList<Buffer> _buffers;
|
||||
|
||||
private Buffer[] _bufferOverlaps;
|
||||
|
||||
private readonly Dictionary<ulong, BufferCacheEntry> _dirtyCache;
|
||||
private readonly Dictionary<ulong, BufferCacheEntry> _modifiedCache;
|
||||
private bool _pruneCaches;
|
||||
|
||||
public event Action NotifyBuffersModified;
|
||||
|
||||
@ -45,6 +51,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
_bufferOverlaps = new Buffer[OverlapsBufferInitialCapacity];
|
||||
|
||||
_dirtyCache = new Dictionary<ulong, BufferCacheEntry>();
|
||||
|
||||
// There are a lot more entries on the modified cache, so it is separate from the one for ForceDirty.
|
||||
_modifiedCache = new Dictionary<ulong, BufferCacheEntry>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -132,6 +141,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="size">Size in bytes of the buffer</param>
|
||||
public void ForceDirty(MemoryManager memoryManager, ulong gpuVa, ulong size)
|
||||
{
|
||||
if (_pruneCaches)
|
||||
{
|
||||
Prune();
|
||||
}
|
||||
|
||||
if (!_dirtyCache.TryGetValue(gpuVa, out BufferCacheEntry result) ||
|
||||
result.EndGpuAddress < gpuVa + size ||
|
||||
result.UnmappedSequence != result.Buffer.UnmappedSequence)
|
||||
@ -145,6 +159,42 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
result.Buffer.ForceDirty(result.Address, size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the given buffer range has been GPU modifed.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">GPU memory manager where the buffer is mapped</param>
|
||||
/// <param name="gpuVa">Start GPU virtual address of the buffer</param>
|
||||
/// <param name="size">Size in bytes of the buffer</param>
|
||||
/// <returns>True if modified, false otherwise</returns>
|
||||
public bool CheckModified(MemoryManager memoryManager, ulong gpuVa, ulong size, out ulong outAddr)
|
||||
{
|
||||
if (_pruneCaches)
|
||||
{
|
||||
Prune();
|
||||
}
|
||||
|
||||
// Align the address to avoid creating too many entries on the quick lookup dictionary.
|
||||
ulong mask = BufferAlignmentMask;
|
||||
ulong alignedGpuVa = gpuVa & (~mask);
|
||||
ulong alignedEndGpuVa = (gpuVa + size + mask) & (~mask);
|
||||
|
||||
size = alignedEndGpuVa - alignedGpuVa;
|
||||
|
||||
if (!_modifiedCache.TryGetValue(alignedGpuVa, out BufferCacheEntry result) ||
|
||||
result.EndGpuAddress < alignedEndGpuVa ||
|
||||
result.UnmappedSequence != result.Buffer.UnmappedSequence)
|
||||
{
|
||||
ulong address = TranslateAndCreateBuffer(memoryManager, alignedGpuVa, size);
|
||||
result = new BufferCacheEntry(address, alignedGpuVa, GetBuffer(address, size));
|
||||
|
||||
_modifiedCache[alignedGpuVa] = result;
|
||||
}
|
||||
|
||||
outAddr = result.Address | (gpuVa & mask);
|
||||
|
||||
return result.Buffer.IsModified(result.Address, size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new buffer for the specified range, if needed.
|
||||
/// If a buffer where this range can be fully contained already exists,
|
||||
@ -154,12 +204,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="size">Size in bytes of the buffer</param>
|
||||
private void CreateBufferAligned(ulong address, ulong size)
|
||||
{
|
||||
int overlapsCount;
|
||||
|
||||
lock (_buffers)
|
||||
{
|
||||
overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref _bufferOverlaps);
|
||||
}
|
||||
int overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref _bufferOverlaps);
|
||||
|
||||
if (overlapsCount != 0)
|
||||
{
|
||||
@ -326,18 +371,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
buffer.SignalModified(address, size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a buffer sub-range for a given GPU memory range.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">GPU memory manager where the buffer is mapped</param>
|
||||
/// <param name="gpuVa">Start GPU virtual address of the buffer</param>
|
||||
/// <param name="size">Size in bytes of the buffer</param>
|
||||
/// <returns>The buffer sub-range for the given range</returns>
|
||||
public BufferRange GetGpuBufferRange(MemoryManager memoryManager, ulong gpuVa, ulong size)
|
||||
{
|
||||
return GetBufferRange(TranslateAndCreateBuffer(memoryManager, gpuVa, size), size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a buffer sub-range starting at a given memory address.
|
||||
/// </summary>
|
||||
@ -375,11 +408,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
Buffer buffer;
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
lock (_buffers)
|
||||
{
|
||||
buffer = _buffers.FindFirstOverlap(address, size);
|
||||
}
|
||||
|
||||
buffer.SynchronizeMemory(address, size);
|
||||
|
||||
@ -389,12 +419,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (_buffers)
|
||||
{
|
||||
buffer = _buffers.FindFirstOverlap(address, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
@ -408,17 +435,60 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
if (size != 0)
|
||||
{
|
||||
Buffer buffer;
|
||||
|
||||
lock (_buffers)
|
||||
{
|
||||
buffer = _buffers.FindFirstOverlap(address, size);
|
||||
}
|
||||
Buffer buffer = _buffers.FindFirstOverlap(address, size);
|
||||
|
||||
buffer.SynchronizeMemory(address, size);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prune any invalid entries from a quick access dictionary.
|
||||
/// </summary>
|
||||
/// <param name="dictionary">Dictionary to prune</param>
|
||||
/// <param name="toDelete">List used to track entries to delete</param>
|
||||
private void Prune(Dictionary<ulong, BufferCacheEntry> dictionary, ref List<ulong> toDelete)
|
||||
{
|
||||
foreach (var entry in dictionary)
|
||||
{
|
||||
if (entry.Value.UnmappedSequence != entry.Value.Buffer.UnmappedSequence)
|
||||
{
|
||||
(toDelete ??= new()).Add(entry.Key);
|
||||
}
|
||||
}
|
||||
|
||||
if (toDelete != null)
|
||||
{
|
||||
foreach (ulong entry in toDelete)
|
||||
{
|
||||
dictionary.Remove(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prune any invalid entries from the quick access dictionaries.
|
||||
/// </summary>
|
||||
private void Prune()
|
||||
{
|
||||
List<ulong> toDelete = null;
|
||||
|
||||
Prune(_dirtyCache, ref toDelete);
|
||||
|
||||
toDelete?.Clear();
|
||||
|
||||
Prune(_modifiedCache, ref toDelete);
|
||||
|
||||
_pruneCaches = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queues a prune of invalid entries the next time a dictionary cache is accessed.
|
||||
/// </summary>
|
||||
public void QueuePrune()
|
||||
{
|
||||
_pruneCaches = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes all buffers in the cache.
|
||||
/// It's an error to use the buffer manager after disposal.
|
||||
|
@ -17,11 +17,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
private readonly GpuContext _context;
|
||||
private readonly GpuChannel _channel;
|
||||
|
||||
private int _unalignedStorageBuffers;
|
||||
public bool HasUnalignedStorageBuffers => _unalignedStorageBuffers > 0;
|
||||
|
||||
private IndexBuffer _indexBuffer;
|
||||
private readonly VertexBuffer[] _vertexBuffers;
|
||||
private readonly BufferBounds[] _transformFeedbackBuffers;
|
||||
private readonly List<BufferTextureBinding> _bufferTextures;
|
||||
private readonly BufferRange[] _ranges;
|
||||
private readonly BufferAssignment[] _ranges;
|
||||
|
||||
/// <summary>
|
||||
/// Holds shader stage buffer state and binding information.
|
||||
@ -38,6 +41,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// </summary>
|
||||
public BufferBounds[] Buffers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating if this binding is unaligned.
|
||||
/// </summary>
|
||||
public bool[] Unaligned { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Total amount of buffers used on the shader.
|
||||
/// </summary>
|
||||
@ -51,6 +59,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
Bindings = new BufferDescriptor[count];
|
||||
Buffers = new BufferBounds[count];
|
||||
Unaligned = new bool[count];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -125,7 +134,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
_bufferTextures = new List<BufferTextureBinding>();
|
||||
|
||||
_ranges = new BufferRange[Constants.TotalGpUniformBuffers * Constants.ShaderStages];
|
||||
_ranges = new BufferAssignment[Constants.TotalGpUniformBuffers * Constants.ShaderStages];
|
||||
}
|
||||
|
||||
|
||||
@ -202,6 +211,31 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
_transformFeedbackBuffersDirty = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Records the alignment of a storage buffer.
|
||||
/// Unaligned storage buffers disable some optimizations on the shader.
|
||||
/// </summary>
|
||||
/// <param name="buffers">The binding list to modify</param>
|
||||
/// <param name="index">Index of the storage buffer</param>
|
||||
/// <param name="gpuVa">Start GPU virtual address of the buffer</param>
|
||||
private void RecordStorageAlignment(BuffersPerStage buffers, int index, ulong gpuVa)
|
||||
{
|
||||
bool unaligned = (gpuVa & (Constants.StorageAlignment - 1)) != 0;
|
||||
|
||||
if (unaligned || HasUnalignedStorageBuffers)
|
||||
{
|
||||
// Check if the alignment changed for this binding.
|
||||
|
||||
ref bool currentUnaligned = ref buffers.Unaligned[index];
|
||||
|
||||
if (currentUnaligned != unaligned)
|
||||
{
|
||||
currentUnaligned = unaligned;
|
||||
_unalignedStorageBuffers += unaligned ? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a storage buffer on the compute pipeline.
|
||||
/// Storage buffers can be read and written to on shaders.
|
||||
@ -214,6 +248,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
size += gpuVa & ((ulong)_context.Capabilities.StorageBufferOffsetAlignment - 1);
|
||||
|
||||
RecordStorageAlignment(_cpStorageBuffers, index, gpuVa);
|
||||
|
||||
gpuVa = BitUtils.AlignDown(gpuVa, _context.Capabilities.StorageBufferOffsetAlignment);
|
||||
|
||||
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
||||
@ -234,17 +270,21 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
size += gpuVa & ((ulong)_context.Capabilities.StorageBufferOffsetAlignment - 1);
|
||||
|
||||
BuffersPerStage buffers = _gpStorageBuffers[stage];
|
||||
|
||||
RecordStorageAlignment(buffers, index, gpuVa);
|
||||
|
||||
gpuVa = BitUtils.AlignDown(gpuVa, _context.Capabilities.StorageBufferOffsetAlignment);
|
||||
|
||||
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
||||
|
||||
if (_gpStorageBuffers[stage].Buffers[index].Address != address ||
|
||||
_gpStorageBuffers[stage].Buffers[index].Size != size)
|
||||
if (buffers.Buffers[index].Address != address ||
|
||||
buffers.Buffers[index].Size != size)
|
||||
{
|
||||
_gpStorageBuffersDirty = true;
|
||||
}
|
||||
|
||||
_gpStorageBuffers[stage].SetBounds(index, address, size, flags);
|
||||
buffers.SetBounds(index, address, size, flags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -578,10 +618,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bool isStorage)
|
||||
{
|
||||
int rangesFirst = 0;
|
||||
int rangesCount = 0;
|
||||
|
||||
Span<BufferRange> ranges = _ranges;
|
||||
Span<BufferAssignment> ranges = _ranges;
|
||||
|
||||
for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
|
||||
{
|
||||
@ -600,25 +639,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
|
||||
: bufferCache.GetBufferRange(bounds.Address, bounds.Size);
|
||||
|
||||
if (rangesCount == 0)
|
||||
{
|
||||
rangesFirst = bindingInfo.Binding;
|
||||
}
|
||||
else if (bindingInfo.Binding != rangesFirst + rangesCount)
|
||||
{
|
||||
SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
|
||||
rangesFirst = bindingInfo.Binding;
|
||||
rangesCount = 0;
|
||||
}
|
||||
|
||||
ranges[rangesCount++] = range;
|
||||
ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rangesCount != 0)
|
||||
{
|
||||
SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
|
||||
SetHostBuffers(ranges, rangesCount, isStorage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -631,10 +659,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void BindBuffers(BufferCache bufferCache, BuffersPerStage buffers, bool isStorage)
|
||||
{
|
||||
int rangesFirst = 0;
|
||||
int rangesCount = 0;
|
||||
|
||||
Span<BufferRange> ranges = _ranges;
|
||||
Span<BufferAssignment> ranges = _ranges;
|
||||
|
||||
for (int index = 0; index < buffers.Count; index++)
|
||||
{
|
||||
@ -649,24 +676,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
|
||||
: bufferCache.GetBufferRange(bounds.Address, bounds.Size);
|
||||
|
||||
if (rangesCount == 0)
|
||||
{
|
||||
rangesFirst = bindingInfo.Binding;
|
||||
}
|
||||
else if (bindingInfo.Binding != rangesFirst + rangesCount)
|
||||
{
|
||||
SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
|
||||
rangesFirst = bindingInfo.Binding;
|
||||
rangesCount = 0;
|
||||
}
|
||||
|
||||
ranges[rangesCount++] = range;
|
||||
ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range);
|
||||
}
|
||||
}
|
||||
|
||||
if (rangesCount != 0)
|
||||
{
|
||||
SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
|
||||
SetHostBuffers(ranges, rangesCount, isStorage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -678,15 +694,15 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="count">Number of bindings</param>
|
||||
/// <param name="isStorage">Indicates if the buffers are storage or uniform buffers</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void SetHostBuffers(ReadOnlySpan<BufferRange> ranges, int first, int count, bool isStorage)
|
||||
private void SetHostBuffers(ReadOnlySpan<BufferAssignment> ranges, int count, bool isStorage)
|
||||
{
|
||||
if (isStorage)
|
||||
{
|
||||
_context.Renderer.Pipeline.SetStorageBuffers(first, ranges.Slice(0, count));
|
||||
_context.Renderer.Pipeline.SetStorageBuffers(ranges.Slice(0, count));
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.Renderer.Pipeline.SetUniformBuffers(first, ranges.Slice(0, count));
|
||||
_context.Renderer.Pipeline.SetUniformBuffers(ranges.Slice(0, count));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -325,13 +325,15 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
public void ReregisterRanges(Action<ulong, ulong> rangeAction)
|
||||
{
|
||||
ref var ranges = ref ThreadStaticArray<BufferModifiedRange>.Get();
|
||||
int count;
|
||||
|
||||
// Range list must be consistent for this operation.
|
||||
lock (_lock)
|
||||
{
|
||||
if (ranges.Length < Count)
|
||||
count = Count;
|
||||
if (ranges.Length < count)
|
||||
{
|
||||
Array.Resize(ref ranges, Count);
|
||||
Array.Resize(ref ranges, count);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
@ -342,7 +344,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
}
|
||||
|
||||
ulong currentSync = _context.SyncNumber;
|
||||
for (int i = 0; i < Count; i++)
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
BufferModifiedRange range = ranges[i];
|
||||
if (range.SyncNumber != currentSync)
|
||||
|
@ -36,6 +36,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
/// <param name="channel">GPU channel</param>
|
||||
/// <param name="poolState">Texture pool state</param>
|
||||
/// <param name="computeState">Compute state</param>
|
||||
/// <param name="gpuVa">GPU virtual address of the compute shader</param>
|
||||
/// <param name="program">Cached host program for the given state, if found</param>
|
||||
/// <param name="cachedGuestCode">Cached guest code, if any found</param>
|
||||
@ -43,6 +44,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
public bool TryFind(
|
||||
GpuChannel channel,
|
||||
GpuChannelPoolState poolState,
|
||||
GpuChannelComputeState computeState,
|
||||
ulong gpuVa,
|
||||
out CachedShaderProgram program,
|
||||
out byte[] cachedGuestCode)
|
||||
@ -50,7 +52,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
program = null;
|
||||
ShaderCodeAccessor codeAccessor = new ShaderCodeAccessor(channel.MemoryManager, gpuVa);
|
||||
bool hasSpecList = _cache.TryFindItem(codeAccessor, out var specList, out cachedGuestCode);
|
||||
return hasSpecList && specList.TryFindForCompute(channel, poolState, out program);
|
||||
return hasSpecList && specList.TryFindForCompute(channel, poolState, computeState, out program);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -129,6 +129,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
return _oldSpecState.ConstantBufferUse[_stageIndex];
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHasConstantBufferDrawParameters()
|
||||
{
|
||||
return _oldSpecState.GraphicsState.HasConstantBufferDrawParameters;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public InputTopology QueryPrimitiveTopology()
|
||||
{
|
||||
@ -219,6 +225,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
return _oldSpecState.GraphicsState.EarlyZForce;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHasUnalignedStorageBuffer()
|
||||
{
|
||||
return _oldSpecState.GraphicsState.HasUnalignedStorageBuffer || _oldSpecState.ComputeState.HasUnalignedStorageBuffer;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryViewportTransformDisable()
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 3807;
|
||||
private const uint CodeGenVersion = 3868;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
@ -159,6 +159,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
/// Bit mask of the render target components written by the fragment stage.
|
||||
/// </summary>
|
||||
public int FragmentOutputMap;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the vertex shader accesses draw parameters.
|
||||
/// </summary>
|
||||
public bool UsesDrawParameters;
|
||||
}
|
||||
|
||||
private readonly DiskCacheGuestStorage _guestStorage;
|
||||
@ -374,7 +379,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
|
||||
if (context.Capabilities.Api == TargetApi.Vulkan)
|
||||
{
|
||||
ShaderSource[] shaderSources = ShaderBinarySerializer.Unpack(shaders, hostCode, isCompute);
|
||||
ShaderSource[] shaderSources = ShaderBinarySerializer.Unpack(shaders, hostCode);
|
||||
|
||||
hostProgram = context.Renderer.CreateProgram(shaderSources, shaderInfo);
|
||||
}
|
||||
@ -771,6 +776,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
images,
|
||||
dataInfo.Stage,
|
||||
dataInfo.UsesInstanceId,
|
||||
dataInfo.UsesDrawParameters,
|
||||
dataInfo.UsesRtLayer,
|
||||
dataInfo.ClipDistancesWritten,
|
||||
dataInfo.FragmentOutputMap);
|
||||
@ -796,6 +802,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
dataInfo.ImagesCount = (ushort)info.Images.Count;
|
||||
dataInfo.Stage = info.Stage;
|
||||
dataInfo.UsesInstanceId = info.UsesInstanceId;
|
||||
dataInfo.UsesDrawParameters = info.UsesDrawParameters;
|
||||
dataInfo.UsesRtLayer = info.UsesRtLayer;
|
||||
dataInfo.ClipDistancesWritten = info.ClipDistancesWritten;
|
||||
dataInfo.FragmentOutputMap = info.FragmentOutputMap;
|
||||
|
@ -636,6 +636,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
CachedShaderStage[] shaders = new CachedShaderStage[guestShaders.Length];
|
||||
List<ShaderProgram> translatedStages = new List<ShaderProgram>();
|
||||
|
||||
TranslatorContext previousStage = null;
|
||||
|
||||
for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++)
|
||||
{
|
||||
TranslatorContext currentStage = translatorContexts[stageIndex + 1];
|
||||
@ -668,6 +670,16 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
{
|
||||
translatedStages.Add(program);
|
||||
}
|
||||
|
||||
previousStage = currentStage;
|
||||
}
|
||||
else if (
|
||||
previousStage != null &&
|
||||
previousStage.LayerOutputWritten &&
|
||||
stageIndex == 3 &&
|
||||
!_context.Capabilities.SupportsLayerVertexTessellation)
|
||||
{
|
||||
translatedStages.Add(previousStage.GenerateGeometryPassthrough());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
@ -12,8 +14,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
using MemoryStream output = new MemoryStream();
|
||||
using BinaryWriter writer = new BinaryWriter(output);
|
||||
|
||||
writer.Write(sources.Length);
|
||||
|
||||
for (int i = 0; i < sources.Length; i++)
|
||||
{
|
||||
writer.Write((int)sources[i].Stage);
|
||||
writer.Write(sources[i].BinaryCode.Length);
|
||||
writer.Write(sources[i].BinaryCode);
|
||||
}
|
||||
@ -21,29 +26,40 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
return output.ToArray();
|
||||
}
|
||||
|
||||
public static ShaderSource[] Unpack(CachedShaderStage[] stages, byte[] code, bool compute)
|
||||
public static ShaderSource[] Unpack(CachedShaderStage[] stages, byte[] code)
|
||||
{
|
||||
using MemoryStream input = new MemoryStream(code);
|
||||
using BinaryReader reader = new BinaryReader(input);
|
||||
|
||||
List<ShaderSource> output = new List<ShaderSource>();
|
||||
|
||||
for (int i = compute ? 0 : 1; i < stages.Length; i++)
|
||||
{
|
||||
CachedShaderStage stage = stages[i];
|
||||
int count = reader.ReadInt32();
|
||||
|
||||
if (stage == null)
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ShaderStage stage = (ShaderStage)reader.ReadInt32();
|
||||
int binaryCodeLength = reader.ReadInt32();
|
||||
byte[] binaryCode = reader.ReadBytes(binaryCodeLength);
|
||||
|
||||
output.Add(new ShaderSource(binaryCode, ShaderCache.GetBindings(stage.Info), stage.Info.Stage, TargetLanguage.Spirv));
|
||||
output.Add(new ShaderSource(binaryCode, GetBindings(stages, stage), stage, TargetLanguage.Spirv));
|
||||
}
|
||||
|
||||
return output.ToArray();
|
||||
}
|
||||
|
||||
private static ShaderBindings GetBindings(CachedShaderStage[] stages, ShaderStage stage)
|
||||
{
|
||||
for (int i = 0; i < stages.Length; i++)
|
||||
{
|
||||
CachedShaderStage currentStage = stages[i];
|
||||
|
||||
if (currentStage != null && currentStage.Info.Stage == stage && currentStage.Info != null)
|
||||
{
|
||||
return ShaderCache.GetBindings(currentStage.Info);
|
||||
}
|
||||
}
|
||||
|
||||
return new ShaderBindings(Array.Empty<int>(), Array.Empty<int>(), Array.Empty<int>(), Array.Empty<int>());
|
||||
}
|
||||
}
|
||||
}
|
@ -139,6 +139,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
return useMask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHasConstantBufferDrawParameters()
|
||||
{
|
||||
return _state.GraphicsState.HasConstantBufferDrawParameters;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHasUnalignedStorageBuffer()
|
||||
{
|
||||
return _state.GraphicsState.HasUnalignedStorageBuffer || _state.ComputeState.HasUnalignedStorageBuffer;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public InputTopology QueryPrimitiveTopology()
|
||||
{
|
||||
|
@ -128,6 +128,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
public bool QueryHostSupportsImageLoadFormatted() => _context.Capabilities.SupportsImageLoadFormatted;
|
||||
|
||||
public bool QueryHostSupportsLayerVertexTessellation() => _context.Capabilities.SupportsLayerVertexTessellation;
|
||||
|
||||
public bool QueryHostSupportsNonConstantTextureOffset() => _context.Capabilities.SupportsNonConstantTextureOffset;
|
||||
|
||||
public bool QueryHostSupportsShaderBallot() => _context.Capabilities.SupportsShaderBallot;
|
||||
|
@ -32,6 +32,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
public readonly int SharedMemorySize;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that any storage buffer use is unaligned.
|
||||
/// </summary>
|
||||
public readonly bool HasUnalignedStorageBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GPU compute state.
|
||||
/// </summary>
|
||||
@ -40,18 +45,21 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <param name="localSizeZ">Local group size Z of the compute shader</param>
|
||||
/// <param name="localMemorySize">Local memory size of the compute shader</param>
|
||||
/// <param name="sharedMemorySize">Shared memory size of the compute shader</param>
|
||||
/// <param name="hasUnalignedStorageBuffer">Indicates that any storage buffer use is unaligned</param>
|
||||
public GpuChannelComputeState(
|
||||
int localSizeX,
|
||||
int localSizeY,
|
||||
int localSizeZ,
|
||||
int localMemorySize,
|
||||
int sharedMemorySize)
|
||||
int sharedMemorySize,
|
||||
bool hasUnalignedStorageBuffer)
|
||||
{
|
||||
LocalSizeX = localSizeX;
|
||||
LocalSizeY = localSizeY;
|
||||
LocalSizeZ = localSizeZ;
|
||||
LocalMemorySize = localMemorySize;
|
||||
SharedMemorySize = sharedMemorySize;
|
||||
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
|
||||
}
|
||||
}
|
||||
}
|
@ -77,6 +77,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
public Array32<AttributeType> AttributeTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0.
|
||||
/// </summary>
|
||||
public readonly bool HasConstantBufferDrawParameters;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that any storage buffer use is unaligned.
|
||||
/// </summary>
|
||||
public readonly bool HasUnalignedStorageBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GPU graphics state.
|
||||
/// </summary>
|
||||
@ -93,6 +103,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <param name="alphaTestCompare">When alpha test is enabled, indicates the comparison that decides if the fragment should be discarded</param>
|
||||
/// <param name="alphaTestReference">When alpha test is enabled, indicates the value to compare with the fragment output alpha</param>
|
||||
/// <param name="attributeTypes">Type of the vertex attributes consumed by the shader</param>
|
||||
/// <param name="hasConstantBufferDrawParameters">Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0</param>
|
||||
/// <param name="hasUnalignedStorageBuffer">Indicates that any storage buffer use is unaligned</param>
|
||||
public GpuChannelGraphicsState(
|
||||
bool earlyZForce,
|
||||
PrimitiveTopology topology,
|
||||
@ -106,7 +118,9 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
bool alphaTestEnable,
|
||||
CompareOp alphaTestCompare,
|
||||
float alphaTestReference,
|
||||
ref Array32<AttributeType> attributeTypes)
|
||||
ref Array32<AttributeType> attributeTypes,
|
||||
bool hasConstantBufferDrawParameters,
|
||||
bool hasUnalignedStorageBuffer)
|
||||
{
|
||||
EarlyZForce = earlyZForce;
|
||||
Topology = topology;
|
||||
@ -121,6 +135,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
AlphaTestCompare = alphaTestCompare;
|
||||
AlphaTestReference = alphaTestReference;
|
||||
AttributeTypes = attributeTypes;
|
||||
HasConstantBufferDrawParameters = hasConstantBufferDrawParameters;
|
||||
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
|
||||
}
|
||||
}
|
||||
}
|
@ -203,12 +203,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
GpuChannelComputeState computeState,
|
||||
ulong gpuVa)
|
||||
{
|
||||
if (_cpPrograms.TryGetValue(gpuVa, out var cpShader) && IsShaderEqual(channel, poolState, cpShader, gpuVa))
|
||||
if (_cpPrograms.TryGetValue(gpuVa, out var cpShader) && IsShaderEqual(channel, poolState, computeState, cpShader, gpuVa))
|
||||
{
|
||||
return cpShader;
|
||||
}
|
||||
|
||||
if (_computeShaderCache.TryFind(channel, poolState, gpuVa, out cpShader, out byte[] cachedGuestCode))
|
||||
if (_computeShaderCache.TryFind(channel, poolState, computeState, gpuVa, out cpShader, out byte[] cachedGuestCode))
|
||||
{
|
||||
_cpPrograms[gpuVa] = cpShader;
|
||||
return cpShader;
|
||||
@ -356,6 +356,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
CachedShaderStage[] shaders = new CachedShaderStage[Constants.ShaderStages + 1];
|
||||
List<ShaderSource> shaderSources = new List<ShaderSource>();
|
||||
|
||||
TranslatorContext previousStage = null;
|
||||
|
||||
for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++)
|
||||
{
|
||||
TranslatorContext currentStage = translatorContexts[stageIndex + 1];
|
||||
@ -392,6 +394,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
shaderSources.Add(CreateShaderSource(program));
|
||||
}
|
||||
|
||||
previousStage = currentStage;
|
||||
}
|
||||
else if (
|
||||
previousStage != null &&
|
||||
previousStage.LayerOutputWritten &&
|
||||
stageIndex == 3 &&
|
||||
!_context.Capabilities.SupportsLayerVertexTessellation)
|
||||
{
|
||||
shaderSources.Add(CreateShaderSource(previousStage.GenerateGeometryPassthrough()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -473,18 +485,20 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
/// <param name="channel">GPU channel using the shader</param>
|
||||
/// <param name="poolState">GPU channel state to verify shader compatibility</param>
|
||||
/// <param name="computeState">GPU channel compute state to verify shader compatibility</param>
|
||||
/// <param name="cpShader">Cached compute shader</param>
|
||||
/// <param name="gpuVa">GPU virtual address of the shader code in memory</param>
|
||||
/// <returns>True if the code is different, false otherwise</returns>
|
||||
private static bool IsShaderEqual(
|
||||
GpuChannel channel,
|
||||
GpuChannelPoolState poolState,
|
||||
GpuChannelComputeState computeState,
|
||||
CachedShaderProgram cpShader,
|
||||
ulong gpuVa)
|
||||
{
|
||||
if (IsShaderEqual(channel.MemoryManager, cpShader.Shaders[0], gpuVa))
|
||||
{
|
||||
return cpShader.SpecializationState.MatchesCompute(channel, poolState, true);
|
||||
return cpShader.SpecializationState.MatchesCompute(channel, poolState, computeState, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -520,7 +534,9 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
}
|
||||
}
|
||||
|
||||
return gpShaders.SpecializationState.MatchesGraphics(channel, poolState, graphicsState, true);
|
||||
bool usesDrawParameters = gpShaders.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||
|
||||
return gpShaders.SpecializationState.MatchesGraphics(channel, poolState, graphicsState, usesDrawParameters, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -35,7 +35,9 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
foreach (var entry in _entries)
|
||||
{
|
||||
if (entry.SpecializationState.MatchesGraphics(channel, poolState, graphicsState, true))
|
||||
bool usesDrawParameters = entry.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||
|
||||
if (entry.SpecializationState.MatchesGraphics(channel, poolState, graphicsState, usesDrawParameters, true))
|
||||
{
|
||||
program = entry;
|
||||
return true;
|
||||
@ -51,13 +53,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
/// <param name="channel">GPU channel</param>
|
||||
/// <param name="poolState">Texture pool state</param>
|
||||
/// <param name="computeState">Compute state</param>
|
||||
/// <param name="program">Cached program, if found</param>
|
||||
/// <returns>True if a compatible program is found, false otherwise</returns>
|
||||
public bool TryFindForCompute(GpuChannel channel, GpuChannelPoolState poolState, out CachedShaderProgram program)
|
||||
public bool TryFindForCompute(GpuChannel channel, GpuChannelPoolState poolState, GpuChannelComputeState computeState, out CachedShaderProgram program)
|
||||
{
|
||||
foreach (var entry in _entries)
|
||||
{
|
||||
if (entry.SpecializationState.MatchesCompute(channel, poolState, true))
|
||||
if (entry.SpecializationState.MatchesCompute(channel, poolState, computeState, true))
|
||||
{
|
||||
program = entry;
|
||||
return true;
|
||||
|
@ -481,9 +481,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <param name="channel">GPU channel</param>
|
||||
/// <param name="poolState">Texture pool state</param>
|
||||
/// <param name="graphicsState">Graphics state</param>
|
||||
/// <param name="usesDrawParameters">Indicates whether the vertex shader accesses draw parameters</param>
|
||||
/// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
|
||||
/// <returns>True if the state matches, false otherwise</returns>
|
||||
public bool MatchesGraphics(GpuChannel channel, GpuChannelPoolState poolState, GpuChannelGraphicsState graphicsState, bool checkTextures)
|
||||
public bool MatchesGraphics(
|
||||
GpuChannel channel,
|
||||
GpuChannelPoolState poolState,
|
||||
GpuChannelGraphicsState graphicsState,
|
||||
bool usesDrawParameters,
|
||||
bool checkTextures)
|
||||
{
|
||||
if (graphicsState.ViewportTransformDisable != GraphicsState.ViewportTransformDisable)
|
||||
{
|
||||
@ -520,6 +526,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
return false;
|
||||
}
|
||||
|
||||
if (usesDrawParameters && graphicsState.HasConstantBufferDrawParameters != GraphicsState.HasConstantBufferDrawParameters)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (graphicsState.HasUnalignedStorageBuffer != GraphicsState.HasUnalignedStorageBuffer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Matches(channel, poolState, checkTextures, isCompute: false);
|
||||
}
|
||||
|
||||
@ -528,10 +544,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
/// <param name="channel">GPU channel</param>
|
||||
/// <param name="poolState">Texture pool state</param>
|
||||
/// <param name="computeState">Compute state</param>
|
||||
/// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
|
||||
/// <returns>True if the state matches, false otherwise</returns>
|
||||
public bool MatchesCompute(GpuChannel channel, GpuChannelPoolState poolState, bool checkTextures)
|
||||
public bool MatchesCompute(GpuChannel channel, GpuChannelPoolState poolState, GpuChannelComputeState computeState, bool checkTextures)
|
||||
{
|
||||
if (computeState.HasUnalignedStorageBuffer != ComputeState.HasUnalignedStorageBuffer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Matches(channel, poolState, checkTextures, isCompute: true);
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
short dqv = dq[0];
|
||||
ReadOnlySpan<byte> cat6Prob = (xd.Bd == 12)
|
||||
? Luts.Vp9Cat6ProbHigh12
|
||||
: (xd.Bd == 10) ? new ReadOnlySpan<byte>(Luts.Vp9Cat6ProbHigh12).Slice(2) : Luts.Vp9Cat6Prob;
|
||||
: (xd.Bd == 10) ? Luts.Vp9Cat6ProbHigh12.Slice(2) : Luts.Vp9Cat6Prob;
|
||||
int cat6Bits = (xd.Bd == 12) ? 18 : (xd.Bd == 10) ? 16 : 14;
|
||||
// Keep value, range, and count as locals. The compiler produces better
|
||||
// results with the locals than using r directly.
|
||||
|
@ -1,14 +1,12 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.Nvdec.Vp9.Types;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
internal static class Luts
|
||||
{
|
||||
public static readonly byte[] SizeGroupLookup = new byte[]
|
||||
{
|
||||
0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3
|
||||
};
|
||||
public static ReadOnlySpan<byte> SizeGroupLookup => new byte[] { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3 };
|
||||
|
||||
public static readonly BlockSize[][] SubsizeLookup = new BlockSize[][]
|
||||
{
|
||||
@ -1070,18 +1068,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
-(sbyte)MvClassType.MvClass10,
|
||||
};
|
||||
|
||||
public static readonly sbyte[] Vp9MvFPTree = new sbyte[] { -0, 2, -1, 4, -2, -3 };
|
||||
public static ReadOnlySpan<sbyte> Vp9MvFPTree => new sbyte[] { -0, 2, -1, 4, -2, -3 };
|
||||
|
||||
// Entropy
|
||||
|
||||
public static readonly byte[] Vp9Cat1Prob = new byte[] { 159 };
|
||||
public static readonly byte[] Vp9Cat2Prob = new byte[] { 165, 145 };
|
||||
public static readonly byte[] Vp9Cat3Prob = new byte[] { 173, 148, 140 };
|
||||
public static readonly byte[] Vp9Cat4Prob = new byte[] { 176, 155, 140, 135 };
|
||||
public static readonly byte[] Vp9Cat5Prob = new byte[] { 180, 157, 141, 134, 130 };
|
||||
public static readonly byte[] Vp9Cat6Prob = new byte[] { 254, 254, 254, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129 };
|
||||
public static ReadOnlySpan<byte> Vp9Cat1Prob => new byte[] { 159 };
|
||||
public static ReadOnlySpan<byte> Vp9Cat2Prob => new byte[] { 165, 145 };
|
||||
public static ReadOnlySpan<byte> Vp9Cat3Prob => new byte[] { 173, 148, 140 };
|
||||
public static ReadOnlySpan<byte> Vp9Cat4Prob => new byte[] { 176, 155, 140, 135 };
|
||||
public static ReadOnlySpan<byte> Vp9Cat5Prob => new byte[] { 180, 157, 141, 134, 130 };
|
||||
public static ReadOnlySpan<byte> Vp9Cat6Prob => new byte[] { 254, 254, 254, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129 };
|
||||
|
||||
public static readonly byte[] Vp9Cat6ProbHigh12 = new byte[]
|
||||
public static ReadOnlySpan<byte> Vp9Cat6ProbHigh12 => new byte[]
|
||||
{
|
||||
255, 255, 255, 255, 254, 254, 54, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129
|
||||
};
|
||||
@ -1131,12 +1129,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
};
|
||||
|
||||
private static readonly byte[] Vp9CoefbandTrans4X4 = new byte[]
|
||||
private static ReadOnlySpan<byte> Vp9CoefbandTrans4X4 => new byte[]
|
||||
{
|
||||
0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5,
|
||||
};
|
||||
|
||||
public static byte[] get_band_translate(TxSize txSize)
|
||||
public static ReadOnlySpan<byte> get_band_translate(TxSize txSize)
|
||||
{
|
||||
return txSize == TxSize.Tx4x4 ? Vp9CoefbandTrans4X4 : Vp9CoefbandTrans8X8Plus;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
private static readonly Lazy<bool> _supportsQuads = new Lazy<bool>(SupportsQuadsCheck);
|
||||
private static readonly Lazy<bool> _supportsSeamlessCubemapPerTexture = new Lazy<bool>(() => HasExtension("GL_ARB_seamless_cubemap_per_texture"));
|
||||
private static readonly Lazy<bool> _supportsShaderBallot = new Lazy<bool>(() => HasExtension("GL_ARB_shader_ballot"));
|
||||
private static readonly Lazy<bool> _supportsShaderViewportLayerArray = new Lazy<bool>(() => HasExtension("GL_ARB_shader_viewport_layer_array"));
|
||||
private static readonly Lazy<bool> _supportsTextureCompressionBptc = new Lazy<bool>(() => HasExtension("GL_EXT_texture_compression_bptc"));
|
||||
private static readonly Lazy<bool> _supportsTextureCompressionRgtc = new Lazy<bool>(() => HasExtension("GL_EXT_texture_compression_rgtc"));
|
||||
private static readonly Lazy<bool> _supportsTextureCompressionS3tc = new Lazy<bool>(() => HasExtension("GL_EXT_texture_compression_s3tc"));
|
||||
@ -61,6 +62,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
public static bool SupportsQuads => _supportsQuads.Value;
|
||||
public static bool SupportsSeamlessCubemapPerTexture => _supportsSeamlessCubemapPerTexture.Value;
|
||||
public static bool SupportsShaderBallot => _supportsShaderBallot.Value;
|
||||
public static bool SupportsShaderViewportLayerArray => _supportsShaderViewportLayerArray.Value;
|
||||
public static bool SupportsTextureCompressionBptc => _supportsTextureCompressionBptc.Value;
|
||||
public static bool SupportsTextureCompressionRgtc => _supportsTextureCompressionRgtc.Value;
|
||||
public static bool SupportsTextureCompressionS3tc => _supportsTextureCompressionS3tc.Value;
|
||||
|
@ -117,12 +117,13 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
supportsFragmentShaderOrderingIntel: HwCapabilities.SupportsFragmentShaderOrdering,
|
||||
supportsGeometryShaderPassthrough: HwCapabilities.SupportsGeometryShaderPassthrough,
|
||||
supportsImageLoadFormatted: HwCapabilities.SupportsImageLoadFormatted,
|
||||
supportsLayerVertexTessellation: HwCapabilities.SupportsShaderViewportLayerArray,
|
||||
supportsMismatchingViewFormat: HwCapabilities.SupportsMismatchingViewFormat,
|
||||
supportsCubemapView: true,
|
||||
supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
|
||||
supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
|
||||
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
|
||||
supportsViewportIndex: true,
|
||||
supportsViewportIndex: HwCapabilities.SupportsShaderViewportLayerArray,
|
||||
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
|
||||
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
|
||||
maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver?
|
||||
|
@ -586,6 +586,95 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawIndexedIndirect(BufferRange indirectBuffer)
|
||||
{
|
||||
if (!_program.IsLinked)
|
||||
{
|
||||
Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked.");
|
||||
return;
|
||||
}
|
||||
|
||||
PreDrawVbUnbounded();
|
||||
|
||||
_vertexArray.SetRangeOfIndexBuffer();
|
||||
|
||||
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
|
||||
|
||||
GL.DrawElementsIndirect(_primitiveType, _elementsType, (IntPtr)indirectBuffer.Offset);
|
||||
|
||||
_vertexArray.RestoreIndexBuffer();
|
||||
|
||||
PostDraw();
|
||||
}
|
||||
|
||||
public void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
||||
{
|
||||
if (!_program.IsLinked)
|
||||
{
|
||||
Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked.");
|
||||
return;
|
||||
}
|
||||
|
||||
PreDrawVbUnbounded();
|
||||
|
||||
_vertexArray.SetRangeOfIndexBuffer();
|
||||
|
||||
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
|
||||
GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32());
|
||||
|
||||
GL.MultiDrawElementsIndirectCount(
|
||||
_primitiveType,
|
||||
(All)_elementsType,
|
||||
(IntPtr)indirectBuffer.Offset,
|
||||
(IntPtr)parameterBuffer.Offset,
|
||||
maxDrawCount,
|
||||
stride);
|
||||
|
||||
_vertexArray.RestoreIndexBuffer();
|
||||
|
||||
PostDraw();
|
||||
}
|
||||
|
||||
public void DrawIndirect(BufferRange indirectBuffer)
|
||||
{
|
||||
if (!_program.IsLinked)
|
||||
{
|
||||
Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked.");
|
||||
return;
|
||||
}
|
||||
|
||||
PreDrawVbUnbounded();
|
||||
|
||||
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
|
||||
|
||||
GL.DrawArraysIndirect(_primitiveType, (IntPtr)indirectBuffer.Offset);
|
||||
|
||||
PostDraw();
|
||||
}
|
||||
|
||||
public void DrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
||||
{
|
||||
if (!_program.IsLinked)
|
||||
{
|
||||
Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked.");
|
||||
return;
|
||||
}
|
||||
|
||||
PreDrawVbUnbounded();
|
||||
|
||||
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
|
||||
GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32());
|
||||
|
||||
GL.MultiDrawArraysIndirectCount(
|
||||
_primitiveType,
|
||||
(IntPtr)indirectBuffer.Offset,
|
||||
(IntPtr)parameterBuffer.Offset,
|
||||
maxDrawCount,
|
||||
stride);
|
||||
|
||||
PostDraw();
|
||||
}
|
||||
|
||||
public void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion)
|
||||
{
|
||||
if (texture is TextureView view && sampler is Sampler samp)
|
||||
@ -683,57 +772,6 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
_tfEnabled = false;
|
||||
}
|
||||
|
||||
public void MultiDrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
||||
{
|
||||
if (!_program.IsLinked)
|
||||
{
|
||||
Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked.");
|
||||
return;
|
||||
}
|
||||
|
||||
PreDrawVbUnbounded();
|
||||
|
||||
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
|
||||
GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32());
|
||||
|
||||
GL.MultiDrawArraysIndirectCount(
|
||||
_primitiveType,
|
||||
(IntPtr)indirectBuffer.Offset,
|
||||
(IntPtr)parameterBuffer.Offset,
|
||||
maxDrawCount,
|
||||
stride);
|
||||
|
||||
PostDraw();
|
||||
}
|
||||
|
||||
public void MultiDrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
||||
{
|
||||
if (!_program.IsLinked)
|
||||
{
|
||||
Logger.Debug?.Print(LogClass.Gpu, "Draw error, shader not linked.");
|
||||
return;
|
||||
}
|
||||
|
||||
PreDrawVbUnbounded();
|
||||
|
||||
_vertexArray.SetRangeOfIndexBuffer();
|
||||
|
||||
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
|
||||
GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32());
|
||||
|
||||
GL.MultiDrawElementsIndirectCount(
|
||||
_primitiveType,
|
||||
(All)_elementsType,
|
||||
(IntPtr)indirectBuffer.Offset,
|
||||
(IntPtr)parameterBuffer.Offset,
|
||||
maxDrawCount,
|
||||
stride);
|
||||
|
||||
_vertexArray.RestoreIndexBuffer();
|
||||
|
||||
PostDraw();
|
||||
}
|
||||
|
||||
public void SetAlphaTest(bool enable, float reference, CompareOp op)
|
||||
{
|
||||
if (!enable)
|
||||
@ -1258,9 +1296,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
_stencilFrontMask = stencilTest.FrontMask;
|
||||
}
|
||||
|
||||
public void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers)
|
||||
public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
||||
{
|
||||
SetBuffers(first, buffers, isStorage: true);
|
||||
SetBuffers(buffers, isStorage: true);
|
||||
}
|
||||
|
||||
public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
|
||||
@ -1328,9 +1366,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers)
|
||||
public void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
||||
{
|
||||
SetBuffers(first, buffers, isStorage: false);
|
||||
SetBuffers(buffers, isStorage: false);
|
||||
}
|
||||
|
||||
public void SetUserClipDistance(int index, bool enableClip)
|
||||
@ -1422,21 +1460,22 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
GL.MemoryBarrier(MemoryBarrierFlags.TextureFetchBarrierBit);
|
||||
}
|
||||
|
||||
private void SetBuffers(int first, ReadOnlySpan<BufferRange> buffers, bool isStorage)
|
||||
private void SetBuffers(ReadOnlySpan<BufferAssignment> buffers, bool isStorage)
|
||||
{
|
||||
BufferRangeTarget target = isStorage ? BufferRangeTarget.ShaderStorageBuffer : BufferRangeTarget.UniformBuffer;
|
||||
|
||||
for (int index = 0; index < buffers.Length; index++)
|
||||
{
|
||||
BufferRange buffer = buffers[index];
|
||||
BufferAssignment assignment = buffers[index];
|
||||
BufferRange buffer = assignment.Range;
|
||||
|
||||
if (buffer.Handle == BufferHandle.Null)
|
||||
{
|
||||
GL.BindBufferRange(target, first + index, 0, IntPtr.Zero, 0);
|
||||
GL.BindBufferRange(target, assignment.Binding, 0, IntPtr.Zero, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
GL.BindBufferRange(target, first + index, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
|
||||
GL.BindBufferRange(target, assignment.Binding, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,12 +10,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
public StructuredFunction CurrentFunction { get; set; }
|
||||
|
||||
public StructuredProgramInfo Info { get; }
|
||||
|
||||
public ShaderConfig Config { get; }
|
||||
|
||||
public OperandManager OperandManager { get; }
|
||||
|
||||
private readonly StructuredProgramInfo _info;
|
||||
|
||||
private readonly StringBuilder _sb;
|
||||
|
||||
private int _level;
|
||||
@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
public CodeGenContext(StructuredProgramInfo info, ShaderConfig config)
|
||||
{
|
||||
_info = info;
|
||||
Info = info;
|
||||
Config = config;
|
||||
|
||||
OperandManager = new OperandManager();
|
||||
@ -72,19 +72,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
public StructuredFunction GetFunction(int id)
|
||||
{
|
||||
return _info.Functions[id];
|
||||
}
|
||||
|
||||
public TransformFeedbackOutput GetTransformFeedbackOutput(int location, int component)
|
||||
{
|
||||
int index = (AttributeConsts.UserAttributeBase / 4) + location * 4 + component;
|
||||
return _info.TransformFeedbackOutputs[index];
|
||||
}
|
||||
|
||||
public TransformFeedbackOutput GetTransformFeedbackOutput(int location)
|
||||
{
|
||||
int index = location / 4;
|
||||
return _info.TransformFeedbackOutputs[index];
|
||||
return Info.Functions[id];
|
||||
}
|
||||
|
||||
private void UpdateIndentation()
|
||||
|
@ -46,6 +46,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
}
|
||||
else
|
||||
{
|
||||
if (context.Config.Stage == ShaderStage.Vertex)
|
||||
{
|
||||
context.AppendLine("#extension GL_ARB_shader_draw_parameters : enable");
|
||||
}
|
||||
|
||||
context.AppendLine("#extension GL_ARB_shader_viewport_layer_array : enable");
|
||||
}
|
||||
|
||||
@ -210,7 +215,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline)
|
||||
{
|
||||
var tfOutput = context.GetTransformFeedbackOutput(AttributeConsts.PositionX);
|
||||
var tfOutput = context.Info.GetTransformFeedbackOutput(AttributeConsts.PositionX);
|
||||
if (tfOutput.Valid)
|
||||
{
|
||||
context.AppendLine($"layout (xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}) out gl_PerVertex");
|
||||
@ -520,7 +525,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
private static void DeclareInputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
|
||||
{
|
||||
foreach (int attr in attrs.OrderBy(x => x))
|
||||
foreach (int attr in attrs.Order())
|
||||
{
|
||||
DeclareInputAttributePerPatch(context, attr);
|
||||
}
|
||||
@ -603,6 +608,31 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
string name = $"{DefaultNames.OAttributePrefix}{attr}{suffix}";
|
||||
|
||||
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline)
|
||||
{
|
||||
int attrOffset = AttributeConsts.UserAttributeBase + attr * 16;
|
||||
int components = context.Config.LastInPipeline ? context.Info.GetTransformFeedbackOutputComponents(attrOffset) : 1;
|
||||
|
||||
if (components > 1)
|
||||
{
|
||||
string type = components switch
|
||||
{
|
||||
2 => "vec2",
|
||||
3 => "vec3",
|
||||
4 => "vec4",
|
||||
_ => "float"
|
||||
};
|
||||
|
||||
string xfb = string.Empty;
|
||||
|
||||
var tfOutput = context.Info.GetTransformFeedbackOutput(attrOffset);
|
||||
if (tfOutput.Valid)
|
||||
{
|
||||
xfb = $", xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}";
|
||||
}
|
||||
|
||||
context.AppendLine($"layout (location = {attr}{xfb}) out {type} {name};");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int c = 0; c < 4; c++)
|
||||
{
|
||||
@ -610,7 +640,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
string xfb = string.Empty;
|
||||
|
||||
var tfOutput = context.GetTransformFeedbackOutput(attr, c);
|
||||
var tfOutput = context.Info.GetTransformFeedbackOutput(attrOffset + c * 4);
|
||||
if (tfOutput.Valid)
|
||||
{
|
||||
xfb = $", xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}";
|
||||
@ -619,6 +649,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
context.AppendLine($"layout (location = {attr}, component = {c}{xfb}) out float {name}_{swzMask};");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.AppendLine($"layout (location = {attr}) out vec4 {name};");
|
||||
@ -627,7 +658,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
private static void DeclareUsedOutputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
|
||||
{
|
||||
foreach (int attr in attrs.OrderBy(x => x))
|
||||
foreach (int attr in attrs.Order())
|
||||
{
|
||||
DeclareOutputAttributePerPatch(context, attr);
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
if (assignment.Destination is AstOperand operand && operand.Type.IsAttribute())
|
||||
{
|
||||
bool perPatch = operand.Type == OperandType.AttributePerPatch;
|
||||
dest = OperandManager.GetOutAttributeName(operand.Value, context.Config, perPatch);
|
||||
dest = OperandManager.GetOutAttributeName(context, operand.Value, perPatch);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
}
|
||||
else if (node is AstOperand operand)
|
||||
{
|
||||
return context.OperandManager.GetExpression(operand, context.Config);
|
||||
return context.OperandManager.GetExpression(context, operand);
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Invalid node type \"{node?.GetType().Name ?? "null"}\".");
|
||||
|
@ -205,7 +205,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
if (src2 is AstOperand operand && operand.Type == OperandType.Constant)
|
||||
{
|
||||
int attrOffset = baseAttr.Value + (operand.Value << 2);
|
||||
return OperandManager.GetAttributeName(attrOffset, context.Config, perPatch: false, isOutAttr: false, indexExpr);
|
||||
return OperandManager.GetAttributeName(context, attrOffset, perPatch: false, isOutAttr: false, indexExpr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -332,7 +332,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
if (src2 is AstOperand operand && operand.Type == OperandType.Constant)
|
||||
{
|
||||
int attrOffset = baseAttr.Value + (operand.Value << 2);
|
||||
attrName = OperandManager.GetAttributeName(attrOffset, context.Config, perPatch: false, isOutAttr: true);
|
||||
attrName = OperandManager.GetAttributeName(context, attrOffset, perPatch: false, isOutAttr: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -48,6 +48,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
{ AttributeConsts.TessCoordY, new BuiltInAttribute("gl_TessCoord.y", VariableType.F32) },
|
||||
{ AttributeConsts.InstanceId, new BuiltInAttribute("gl_InstanceID", VariableType.S32) },
|
||||
{ AttributeConsts.VertexId, new BuiltInAttribute("gl_VertexID", VariableType.S32) },
|
||||
{ AttributeConsts.BaseInstance, new BuiltInAttribute("gl_BaseInstanceARB", VariableType.S32) },
|
||||
{ AttributeConsts.BaseVertex, new BuiltInAttribute("gl_BaseVertexARB", VariableType.S32) },
|
||||
{ AttributeConsts.InstanceIndex, new BuiltInAttribute("gl_InstanceIndex", VariableType.S32) },
|
||||
{ AttributeConsts.VertexIndex, new BuiltInAttribute("gl_VertexIndex", VariableType.S32) },
|
||||
{ AttributeConsts.DrawIndex, new BuiltInAttribute("gl_DrawIDARB", VariableType.S32) },
|
||||
{ AttributeConsts.FrontFacing, new BuiltInAttribute("gl_FrontFacing", VariableType.Bool) },
|
||||
|
||||
// Special.
|
||||
@ -99,15 +104,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
return name;
|
||||
}
|
||||
|
||||
public string GetExpression(AstOperand operand, ShaderConfig config)
|
||||
public string GetExpression(CodeGenContext context, AstOperand operand)
|
||||
{
|
||||
return operand.Type switch
|
||||
{
|
||||
OperandType.Argument => GetArgumentName(operand.Value),
|
||||
OperandType.Attribute => GetAttributeName(operand.Value, config, perPatch: false),
|
||||
OperandType.AttributePerPatch => GetAttributeName(operand.Value, config, perPatch: true),
|
||||
OperandType.Attribute => GetAttributeName(context, operand.Value, perPatch: false),
|
||||
OperandType.AttributePerPatch => GetAttributeName(context, operand.Value, perPatch: true),
|
||||
OperandType.Constant => NumberFormatter.FormatInt(operand.Value),
|
||||
OperandType.ConstantBuffer => GetConstantBufferName(operand, config),
|
||||
OperandType.ConstantBuffer => GetConstantBufferName(operand, context.Config),
|
||||
OperandType.LocalVariable => _locals[operand],
|
||||
OperandType.Undefined => DefaultNames.UndefinedName,
|
||||
_ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\".")
|
||||
@ -149,13 +154,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
return GetVec4Indexed(GetUbName(stage, slotExpr) + $"[{offsetExpr} >> 2]", offsetExpr + " & 3", indexElement);
|
||||
}
|
||||
|
||||
public static string GetOutAttributeName(int value, ShaderConfig config, bool perPatch)
|
||||
public static string GetOutAttributeName(CodeGenContext context, int value, bool perPatch)
|
||||
{
|
||||
return GetAttributeName(value, config, perPatch, isOutAttr: true);
|
||||
return GetAttributeName(context, value, perPatch, isOutAttr: true);
|
||||
}
|
||||
|
||||
public static string GetAttributeName(int value, ShaderConfig config, bool perPatch, bool isOutAttr = false, string indexExpr = "0")
|
||||
public static string GetAttributeName(CodeGenContext context, int value, bool perPatch, bool isOutAttr = false, string indexExpr = "0")
|
||||
{
|
||||
ShaderConfig config = context.Config;
|
||||
|
||||
if ((value & AttributeConsts.LoadOutputMask) != 0)
|
||||
{
|
||||
isOutAttr = true;
|
||||
@ -188,6 +195,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
}
|
||||
else if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd)
|
||||
{
|
||||
int attrOffset = value;
|
||||
value -= AttributeConsts.UserAttributeBase;
|
||||
|
||||
string prefix = isOutAttr
|
||||
@ -211,14 +219,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
((config.LastInVertexPipeline && isOutAttr) ||
|
||||
(config.Stage == ShaderStage.Fragment && !isOutAttr)))
|
||||
{
|
||||
string name = $"{prefix}{(value >> 4)}_{swzMask}";
|
||||
int components = config.LastInPipeline ? context.Info.GetTransformFeedbackOutputComponents(attrOffset) : 1;
|
||||
string name = components > 1 ? $"{prefix}{(value >> 4)}" : $"{prefix}{(value >> 4)}_{swzMask}";
|
||||
|
||||
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
||||
{
|
||||
name += isOutAttr ? "[gl_InvocationID]" : $"[{indexExpr}]";
|
||||
}
|
||||
|
||||
return name;
|
||||
return components > 1 ? name + '.' + swzMask : name;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
private const uint SpirvVersionRevision = 0;
|
||||
private const uint SpirvVersionPacked = (SpirvVersionMajor << 16) | (SpirvVersionMinor << 8) | SpirvVersionRevision;
|
||||
|
||||
private readonly StructuredProgramInfo _info;
|
||||
public StructuredProgramInfo Info { get; }
|
||||
|
||||
public ShaderConfig Config { get; }
|
||||
|
||||
@ -85,7 +85,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
GeneratorPool<Instruction> instPool,
|
||||
GeneratorPool<LiteralInteger> integerPool) : base(SpirvVersionPacked, instPool, integerPool)
|
||||
{
|
||||
_info = info;
|
||||
Info = info;
|
||||
Config = config;
|
||||
|
||||
if (config.Stage == ShaderStage.Geometry)
|
||||
@ -317,6 +317,18 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
attrOffset = attr;
|
||||
type = elemType;
|
||||
|
||||
if (Config.LastInPipeline && isOutAttr)
|
||||
{
|
||||
int components = Info.GetTransformFeedbackOutputComponents(attr);
|
||||
|
||||
if (components > 1)
|
||||
{
|
||||
attrOffset &= ~0xf;
|
||||
type = AggregateType.Vector | AggregateType.FP32;
|
||||
attrInfo = new AttributeInfo(attrOffset, (attr - attrOffset) / 4, components, type, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ioVariable = isOutAttr ? Outputs[attrOffset] : Inputs[attrOffset];
|
||||
@ -536,18 +548,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
return _functions[funcIndex];
|
||||
}
|
||||
|
||||
public TransformFeedbackOutput GetTransformFeedbackOutput(int location, int component)
|
||||
{
|
||||
int index = (AttributeConsts.UserAttributeBase / 4) + location * 4 + component;
|
||||
return _info.TransformFeedbackOutputs[index];
|
||||
}
|
||||
|
||||
public TransformFeedbackOutput GetTransformFeedbackOutput(int location)
|
||||
{
|
||||
int index = location / 4;
|
||||
return _info.TransformFeedbackOutputs[index];
|
||||
}
|
||||
|
||||
public Instruction GetType(AggregateType type, int length = 1)
|
||||
{
|
||||
if (type.HasFlag(AggregateType.Array))
|
||||
|
@ -440,12 +440,23 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
PixelImap iq = PixelImap.Unused;
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Fragment &&
|
||||
attr >= AttributeConsts.UserAttributeBase &&
|
||||
attr < AttributeConsts.UserAttributeEnd)
|
||||
if (context.Config.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
|
||||
{
|
||||
iq = context.Config.ImapTypes[(attr - AttributeConsts.UserAttributeBase) / 16].GetFirstUsedType();
|
||||
}
|
||||
else
|
||||
{
|
||||
AttributeInfo attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr: false);
|
||||
AggregateType elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||
|
||||
if (attrInfo.IsBuiltin && (elemType == AggregateType.S32 || elemType == AggregateType.U32))
|
||||
{
|
||||
iq = PixelImap.Constant;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeclareInputOrOutput(context, attr, perPatch, isOutAttr: false, iq);
|
||||
}
|
||||
@ -516,7 +527,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
((isOutAttr && context.Config.LastInVertexPipeline) ||
|
||||
(!isOutAttr && context.Config.Stage == ShaderStage.Fragment)))
|
||||
{
|
||||
DeclareInputOrOutput(context, attr, (attr >> 2) & 3, isOutAttr, iq);
|
||||
DeclareTransformFeedbackInputOrOutput(context, attr, isOutAttr, iq);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -572,7 +583,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline && isOutAttr)
|
||||
{
|
||||
var tfOutput = context.GetTransformFeedbackOutput(attrInfo.BaseValue);
|
||||
var tfOutput = context.Info.GetTransformFeedbackOutput(attrInfo.BaseValue);
|
||||
if (tfOutput.Valid)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)tfOutput.Buffer);
|
||||
@ -595,15 +606,22 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||
|
||||
if (!isOutAttr)
|
||||
{
|
||||
if (!perPatch &&
|
||||
if (!isOutAttr &&
|
||||
!perPatch &&
|
||||
(context.Config.PassthroughAttributes & (1 << location)) != 0 &&
|
||||
context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.PassthroughNV);
|
||||
}
|
||||
}
|
||||
else if (attr >= AttributeConsts.FragmentOutputColorBase && attr < AttributeConsts.FragmentOutputColorEnd)
|
||||
{
|
||||
int location = (attr - AttributeConsts.FragmentOutputColorBase) / 16;
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||
}
|
||||
|
||||
if (!isOutAttr)
|
||||
{
|
||||
switch (iq)
|
||||
{
|
||||
case PixelImap.Constant:
|
||||
@ -614,29 +632,40 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (attr >= AttributeConsts.FragmentOutputColorBase && attr < AttributeConsts.FragmentOutputColorEnd)
|
||||
{
|
||||
int location = (attr - AttributeConsts.FragmentOutputColorBase) / 16;
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||
}
|
||||
|
||||
context.AddGlobalVariable(spvVar);
|
||||
dict.Add(attrInfo.BaseValue, spvVar);
|
||||
}
|
||||
|
||||
private static void DeclareInputOrOutput(CodeGenContext context, int attr, int component, bool isOutAttr, PixelImap iq = PixelImap.Unused)
|
||||
private static void DeclareTransformFeedbackInputOrOutput(CodeGenContext context, int attr, bool isOutAttr, PixelImap iq = PixelImap.Unused)
|
||||
{
|
||||
var dict = isOutAttr ? context.Outputs : context.Inputs;
|
||||
var attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr);
|
||||
|
||||
bool hasComponent = true;
|
||||
int component = (attr >> 2) & 3;
|
||||
int components = 1;
|
||||
var type = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||
|
||||
if (context.Config.LastInPipeline && isOutAttr)
|
||||
{
|
||||
components = context.Info.GetTransformFeedbackOutputComponents(attr);
|
||||
|
||||
if (components > 1)
|
||||
{
|
||||
attr &= ~0xf;
|
||||
type = AggregateType.Vector | AggregateType.FP32;
|
||||
hasComponent = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (dict.ContainsKey(attr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||
var attrType = context.GetType(attrInfo.Type & AggregateType.ElementTypeMask);
|
||||
var attrType = context.GetType(type, components);
|
||||
|
||||
if (AttributeInfo.IsArrayAttributeSpirv(context.Config.Stage, isOutAttr) && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr)))
|
||||
{
|
||||
@ -656,11 +685,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
int location = (attr - AttributeConsts.UserAttributeBase) / 16;
|
||||
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||
|
||||
if (hasComponent)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.Component, (LiteralInteger)component);
|
||||
}
|
||||
|
||||
if (isOutAttr)
|
||||
{
|
||||
var tfOutput = context.GetTransformFeedbackOutput(location, component);
|
||||
var tfOutput = context.Info.GetTransformFeedbackOutput(attr);
|
||||
if (tfOutput.Valid)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)tfOutput.Buffer);
|
||||
@ -704,8 +737,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
AttributeConsts.ClipDistance0 => BuiltIn.ClipDistance,
|
||||
AttributeConsts.PointCoordX => BuiltIn.PointCoord,
|
||||
AttributeConsts.TessCoordX => BuiltIn.TessCoord,
|
||||
AttributeConsts.InstanceId => BuiltIn.InstanceId, // FIXME: Invalid
|
||||
AttributeConsts.VertexId => BuiltIn.VertexId, // FIXME: Invalid
|
||||
AttributeConsts.InstanceId => BuiltIn.InstanceId,
|
||||
AttributeConsts.VertexId => BuiltIn.VertexId,
|
||||
AttributeConsts.BaseInstance => BuiltIn.BaseInstance,
|
||||
AttributeConsts.BaseVertex => BuiltIn.BaseVertex,
|
||||
AttributeConsts.InstanceIndex => BuiltIn.InstanceIndex,
|
||||
AttributeConsts.VertexIndex => BuiltIn.VertexIndex,
|
||||
AttributeConsts.DrawIndex => BuiltIn.DrawIndex,
|
||||
AttributeConsts.FrontFacing => BuiltIn.FrontFacing,
|
||||
AttributeConsts.FragmentOutputDepth => BuiltIn.FragDepth,
|
||||
AttributeConsts.ThreadKill => BuiltIn.HelperInvocation,
|
||||
|
@ -1829,7 +1829,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
if (texOp.Index < 2 || (type & SamplerType.Mask) == SamplerType.Texture3D)
|
||||
{
|
||||
result = ScalingHelpers.ApplyUnscaling(context, texOp, result, isBindless, isIndexed);
|
||||
result = ScalingHelpers.ApplyUnscaling(context, texOp.WithType(type), result, isBindless, isIndexed);
|
||||
}
|
||||
|
||||
return new OperationResult(AggregateType.S32, result);
|
||||
|
@ -62,11 +62,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
context.AddCapability(Capability.TransformFeedback);
|
||||
}
|
||||
|
||||
if (config.Stage == ShaderStage.Fragment && context.Config.GpuAccessor.QueryHostSupportsFragmentShaderInterlock())
|
||||
if (config.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
if (context.Info.Inputs.Contains(AttributeConsts.Layer))
|
||||
{
|
||||
context.AddCapability(Capability.Geometry);
|
||||
}
|
||||
|
||||
if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderInterlock())
|
||||
{
|
||||
context.AddCapability(Capability.FragmentShaderPixelInterlockEXT);
|
||||
context.AddExtension("SPV_EXT_fragment_shader_interlock");
|
||||
}
|
||||
}
|
||||
else if (config.Stage == ShaderStage.Geometry)
|
||||
{
|
||||
context.AddCapability(Capability.Geometry);
|
||||
@ -81,6 +89,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
context.AddCapability(Capability.Tessellation);
|
||||
}
|
||||
else if (config.Stage == ShaderStage.Vertex)
|
||||
{
|
||||
context.AddCapability(Capability.DrawParameters);
|
||||
}
|
||||
|
||||
context.AddExtension("SPV_KHR_shader_ballot");
|
||||
context.AddExtension("SPV_KHR_subgroup_vote");
|
||||
|
@ -6,5 +6,11 @@ namespace Ryujinx.Graphics.Shader
|
||||
|
||||
public const int MaxAttributes = 16;
|
||||
public const int AllAttributesMask = (int)(uint.MaxValue >> (32 - MaxAttributes));
|
||||
|
||||
public const int NvnBaseVertexByteOffset = 0x640;
|
||||
public const int NvnBaseInstanceByteOffset = 0x644;
|
||||
public const int NvnDrawIndexByteOffset = 0x648;
|
||||
|
||||
public const int StorageAlignment = 16;
|
||||
}
|
||||
}
|
@ -168,6 +168,24 @@ namespace Ryujinx.Graphics.Shader
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries whenever the current draw has written the base vertex and base instance into Constant Buffer 0.
|
||||
/// </summary>
|
||||
/// <returns>True if the shader translator can assume that the constant buffer contains the base IDs, false otherwise</returns>
|
||||
bool QueryHasConstantBufferDrawParameters()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries whenever the current draw uses unaligned storage buffer addresses.
|
||||
/// </summary>
|
||||
/// <returns>True if any storage buffer address is not aligned to 16 bytes, false otherwise</returns>
|
||||
bool QueryHasUnalignedStorageBuffer()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries host about the presence of the FrontFacing built-in variable bug.
|
||||
/// </summary>
|
||||
@ -240,6 +258,15 @@ namespace Ryujinx.Graphics.Shader
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries host support for writes to Layer from vertex or tessellation shader stages.
|
||||
/// </summary>
|
||||
/// <returns>True if writes to layer from vertex or tessellation are supported, false otherwise</returns>
|
||||
bool QueryHostSupportsLayerVertexTessellation()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries host GPU non-constant texture offset support.
|
||||
/// </summary>
|
||||
|
@ -51,7 +51,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
offset |= AttributeConsts.LoadOutputMask;
|
||||
}
|
||||
|
||||
Operand src = op.P ? AttributePerPatch(offset) : Attribute(offset);
|
||||
Operand src = op.P ? AttributePerPatch(offset) : CreateInputAttribute(context, offset);
|
||||
|
||||
context.Copy(Register(rd), src);
|
||||
}
|
||||
@ -278,13 +278,21 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
|
||||
private static int FixedFuncToUserAttribute(ShaderConfig config, int attr, bool isOutput)
|
||||
{
|
||||
if (attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.ClipDistance0)
|
||||
bool supportsLayerFromVertexOrTess = config.GpuAccessor.QueryHostSupportsLayerVertexTessellation();
|
||||
int fixedStartAttr = supportsLayerFromVertexOrTess ? 0 : 1;
|
||||
|
||||
if (attr == AttributeConsts.Layer && config.Stage != ShaderStage.Geometry && !supportsLayerFromVertexOrTess)
|
||||
{
|
||||
attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.FrontColorDiffuseR, 0, isOutput);
|
||||
attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.Layer, 0, isOutput);
|
||||
config.SetLayerOutputAttribute(attr);
|
||||
}
|
||||
else if (attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.ClipDistance0)
|
||||
{
|
||||
attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.FrontColorDiffuseR, fixedStartAttr, isOutput);
|
||||
}
|
||||
else if (attr >= AttributeConsts.TexCoordBase && attr < AttributeConsts.TexCoordEnd)
|
||||
{
|
||||
attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.TexCoordBase, 4, isOutput);
|
||||
attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.TexCoordBase, fixedStartAttr + 4, isOutput);
|
||||
}
|
||||
|
||||
return attr;
|
||||
@ -312,5 +320,22 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
private static Operand CreateInputAttribute(EmitterContext context, int attr)
|
||||
{
|
||||
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
||||
{
|
||||
if (attr == AttributeConsts.InstanceId)
|
||||
{
|
||||
return context.ISubtract(Attribute(AttributeConsts.InstanceIndex), Attribute(AttributeConsts.BaseInstance));
|
||||
}
|
||||
else if (attr == AttributeConsts.VertexId)
|
||||
{
|
||||
return Attribute(AttributeConsts.VertexIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return Attribute(attr);
|
||||
}
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
|
||||
public ShaderStage Stage { get; }
|
||||
public bool UsesInstanceId { get; }
|
||||
public bool UsesDrawParameters { get; }
|
||||
public bool UsesRtLayer { get; }
|
||||
public byte ClipDistancesWritten { get; }
|
||||
public int FragmentOutputMap { get; }
|
||||
@ -23,6 +24,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
TextureDescriptor[] images,
|
||||
ShaderStage stage,
|
||||
bool usesInstanceId,
|
||||
bool usesDrawParameters,
|
||||
bool usesRtLayer,
|
||||
byte clipDistancesWritten,
|
||||
int fragmentOutputMap)
|
||||
@ -34,6 +36,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
|
||||
Stage = stage;
|
||||
UsesInstanceId = usesInstanceId;
|
||||
UsesDrawParameters = usesDrawParameters;
|
||||
UsesRtLayer = usesRtLayer;
|
||||
ClipDistancesWritten = clipDistancesWritten;
|
||||
FragmentOutputMap = fragmentOutputMap;
|
||||
|
@ -27,5 +27,10 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
CbufSlot = cbufSlot;
|
||||
Handle = handle;
|
||||
}
|
||||
|
||||
public AstTextureOperation WithType(SamplerType type)
|
||||
{
|
||||
return new AstTextureOperation(Inst, type, Format, Flags, CbufSlot, Handle, Index);
|
||||
}
|
||||
}
|
||||
}
|
@ -71,12 +71,12 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
var locations = config.GpuAccessor.QueryTransformFeedbackVaryingLocations(tfbIndex);
|
||||
var stride = config.GpuAccessor.QueryTransformFeedbackStride(tfbIndex);
|
||||
|
||||
for (int j = 0; j < locations.Length; j++)
|
||||
for (int i = 0; i < locations.Length; i++)
|
||||
{
|
||||
byte location = locations[j];
|
||||
byte location = locations[i];
|
||||
if (location < 0xc0)
|
||||
{
|
||||
context.Info.TransformFeedbackOutputs[location] = new TransformFeedbackOutput(tfbIndex, j * 4, stride);
|
||||
context.Info.TransformFeedbackOutputs[location] = new TransformFeedbackOutput(tfbIndex, i * 4, stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,5 +42,40 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
|
||||
TransformFeedbackOutputs = new TransformFeedbackOutput[0xc0];
|
||||
}
|
||||
|
||||
public TransformFeedbackOutput GetTransformFeedbackOutput(int attr)
|
||||
{
|
||||
int index = attr / 4;
|
||||
return TransformFeedbackOutputs[index];
|
||||
}
|
||||
|
||||
public int GetTransformFeedbackOutputComponents(int attr)
|
||||
{
|
||||
int index = attr / 4;
|
||||
int baseIndex = index & ~3;
|
||||
|
||||
int count = 1;
|
||||
|
||||
for (; count < 4; count++)
|
||||
{
|
||||
ref var prev = ref TransformFeedbackOutputs[baseIndex + count - 1];
|
||||
ref var curr = ref TransformFeedbackOutputs[baseIndex + count];
|
||||
|
||||
int prevOffset = prev.Offset;
|
||||
int currOffset = curr.Offset;
|
||||
|
||||
if (!prev.Valid || !curr.Valid || prevOffset + 4 != currOffset)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (baseIndex + count <= index)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user