mirror of
https://github.com/par274/sharpemu.git
synced 2026-08-24 18:16:57 +08:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a7a45d1b3 | |||
| 3a744c991e | |||
| 35a28f0143 | |||
| e79a1cc70a | |||
| a2241d0e83 | |||
| fe6521f617 | |||
| 034ddcc092 |
@@ -3200,7 +3200,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
||||
{
|
||||
nint address = (nint)(ptr + i);
|
||||
int remainingBytes = scanBytes - i;
|
||||
if (TryPatchTlsLoadInstruction(address, ptr + i, remainingBytes))
|
||||
if (TryPatchTlsLoadInstruction(address, ptr + i, remainingBytes, i))
|
||||
{
|
||||
num3++;
|
||||
}
|
||||
@@ -3343,13 +3343,21 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
||||
return true;
|
||||
}
|
||||
|
||||
private unsafe bool TryPatchTlsLoadInstruction(nint address, byte* source, int availableLength)
|
||||
private unsafe bool TryPatchTlsLoadInstruction(nint address, byte* source, int availableLength, int regionOffset)
|
||||
{
|
||||
if (availableLength < MinTlsPatchInstructionBytes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// A bare 0xEB (JMP rel8) always owns a disp8 after it, so it can
|
||||
// never be the last byte of a valid instruction. If it precedes our
|
||||
// candidate, we're mid-instruction: reject and let the scan retry.
|
||||
if (regionOffset >= 1 && source[-1] == 0xEB)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var offset = 0;
|
||||
while (offset < availableLength && source[offset] == 0x66)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (C) 2026 SharpEmu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.InteropServices;
|
||||
using SharpEmu.Core.Loader;
|
||||
using SharpEmu.HLE;
|
||||
@@ -18,7 +19,7 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IGuestMemoryA
|
||||
private readonly object _allocationSearchHintGate = new();
|
||||
private readonly List<MemoryRegion> _regions = new();
|
||||
private readonly Dictionary<(ulong DesiredAddress, ulong Alignment, bool Executable), ulong> _allocationSearchHints = new();
|
||||
private readonly Dictionary<ulong, ProgramHeaderFlags> _pageProtections = new();
|
||||
private readonly ConcurrentDictionary<ulong, ProgramHeaderFlags> _pageProtections = new();
|
||||
private bool _disposed;
|
||||
|
||||
[ThreadStatic]
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
{
|
||||
"_languageName": "Eesti",
|
||||
|
||||
"Page.Library": "Teek",
|
||||
"Page.Options": "Seaded",
|
||||
"Page.GameCount.One": "1 mäng",
|
||||
"Page.GameCount.Other": "{0} mängu",
|
||||
|
||||
"Library.SearchWatermark": "Otsi teegist…",
|
||||
"Library.AddFolder": "Lisa kaust",
|
||||
"Library.OpenFile": "Ava fail…",
|
||||
"Library.View.Grid": "Ruudustikvaade",
|
||||
"Library.View.Carousel": "Karussellvaade",
|
||||
|
||||
"Library.Context.Launch": "Käivita",
|
||||
"Library.Context.OpenFolder": "Ava mängukaust",
|
||||
"Library.Context.CopyPath": "Kopeeri tee",
|
||||
"Library.Context.CopyTitleId": "Kopeeri Title ID",
|
||||
"Library.Context.GameSettings": "Mängu seaded…",
|
||||
"Library.Context.Remove": "Eemalda teegist",
|
||||
|
||||
"Library.Empty.Title": "Sinu teek on tühi",
|
||||
"Library.Empty.Hint": "Alustamiseks lisa kaust, kus sinu mängud asuvad.",
|
||||
"Library.Empty.SearchTitle": "Otsingule ei vasta ükski mäng",
|
||||
"Library.Empty.SearchHint": "Ükski teegis olev mäng ei vasta otsingule “{0}”.",
|
||||
"Library.Empty.AddFolder": "+ Lisa mängukaust",
|
||||
|
||||
"Library.Loading": "Teeki laaditakse…",
|
||||
"Library.Stat.Version": "Versioon",
|
||||
"Library.Stat.Installed": "Paigaldatud",
|
||||
"Library.Stat.TitleId": "Title ID",
|
||||
"Common.Back": "Tagasi",
|
||||
|
||||
"Options.General": "Üldine",
|
||||
"Options.Logging": "Logimine",
|
||||
"Options.Env.Tab": "Keskkond",
|
||||
"Options.Section.Environment": "KESKKONNAMUUTUJAD",
|
||||
"Options.Env.Desc": "Lülitid, mis edastatakse emulaatorile käivitamisel keskkonnamuutujatena.",
|
||||
"Options.Env.Bthid.Desc": "Märgi Bluetooth HID kättesaamatuks mängude puhul, mille rooli/FFB-vahetarkvara küsib andmeid lõputult.\nTavaliselt jäta välja lülitatuks. Mõni mäng hangub, kui initsialiseerimine ebaõnnestub.",
|
||||
"Options.Env.LoopGuard.Desc": "Ära sulge sundkorras mänge, mis kordavad sama kutset liiga kaua.\nProovi seda, kui mäng laadimise ajal iseenesest sulgub.",
|
||||
"Options.Env.WritableApp0.Desc": "Luba mängudel luua ja kirjutada faile oma paigalduskausta.\nVajalik pakendamata koopiatele, mis salvestavad oma andmed või seadistused kausta /app0.",
|
||||
"Options.Env.VkValidation.Desc": "Luba Vulkani valideerimiskihid GPU silumiseks.\nAeglane. Nõuab paigaldatud Vulkan SDK-d.",
|
||||
"Options.Env.DumpSpirv.Desc": "Salvesta AGC-shaderid ja nende SPIR-V tõlked kausta shader-dumps.\nKasuta shaderi- või kuvamisvea teatamisel.",
|
||||
"Options.Env.LogDirectMemory.Desc": "Logi konsooli otsese mälu eraldamised ja tõrked.\nKasuta siis, kui mäng katkeb või sulgub käivitamise ajal.",
|
||||
"Options.Env.LogIo.Desc": "Logi konsooli failide avamise, lugemise ja tee lahendamise tegevused.\nKasuta siis, kui mäng ei leia käivitamisel oma andmefaile.",
|
||||
"Options.Env.LogNp.Desc": "Logi konsooli NP (PlayStation Network) teegi kutsed.",
|
||||
"Options.Env.Group.Debug": "Silumine",
|
||||
"Options.Env.Group.General": "Üldine",
|
||||
"Options.Env.RenderDoc.Desc": "Laadib RenderDoc'i rakendusesisese API, et kaadreid saaks hõivata otse emulaatorist.\nVajuta mängu käigus F10 ühe kaadri hõivamiseks; hõivatised salvestatakse kausta user/logs/capture_logs/<TITLE_ID>.\nNõuab paigaldatud RenderDoc'i. Aeglustab GPU-d ja põhjustab mõningate mängude hangumist, seega hoia välja lülitatuna, kui sa ei silu.",
|
||||
"Options.Env.GuestImageCpuSync.Desc": "Laadi uuesti üles mängupinnad, mida selle enda CPU-kood ümber kirjutab.\nTavaliselt jäta välja lülitatuks. Lülita sisse mängude puhul, mille CPU-ga joonistatud pinnad ei jõua kunagi ekraanile.\nVähendab jõudlust ja halvendab mõne mängu töökindlust (nt GTA V).",
|
||||
"Options.Env.ForceSubmitOrphanPreambles.Desc": "Edasta GPU käsupuhvrite preambulid isegi siis, kui nende sihtjärjekord neid kunagi ei võta.\nTavaliselt jäta välja lülitatuks. Lülita sisse mängude puhul, mis hanguvad oodates GPU-fence'i, mis kunagi ei rakendu.",
|
||||
"Options.DefaultProfile.Label": "Vaikimisi profiili nimi",
|
||||
"Options.DefaultProfile.Desc": "Nimi, mida kasutatakse, kui mäng küsib tekstisisestust. Vaikimisi Sharp.",
|
||||
"Options.Section.Emulation": "EMULATSIOON",
|
||||
"Options.Section.Logging": "LOGIMINE",
|
||||
"Options.Section.Launcher": "KÄIVITI",
|
||||
"Options.Section.Rendering": "RENDERDAMINE",
|
||||
"Options.Section.Display": "KUVA",
|
||||
"Options.Graphics": "Graafika",
|
||||
|
||||
"Options.RenderResolution.Label": "Sisemine eraldusvõime",
|
||||
"Options.RenderResolution.Desc": "Renderdab ekraanivälised sihid natiivsest madalamal eraldusvõimel ja skaleerib kuvamisel üles. Madalamad väärtused annavad pildikvaliteedi arvelt GPU-le jõudlusvaru; rakendub järgmisel käivitamisel.",
|
||||
"Options.RenderResolution.Native": "100% (natiivne)",
|
||||
"Options.WindowMode.Label": "Aknarežiim",
|
||||
"Options.WindowMode.Desc": "Tavaline aken, äärteta töölauavaade või eksklusiivne täisekraan.",
|
||||
"Options.WindowMode.Windowed": "Aken",
|
||||
"Options.WindowMode.Borderless": "Äärteta",
|
||||
"Options.WindowMode.Exclusive": "Eksklusiivne",
|
||||
"Options.Resolution.Label": "Eraldusvõime",
|
||||
"Options.Resolution.Desc": "Algne akna suurus või eksklusiivse täisekraani eraldusvõime.",
|
||||
"Options.Display.Label": "Kuvar",
|
||||
"Options.Display.Desc": "Monitor, mida kasutatakse tsentreerimiseks ja täisekraanrežiimiks.",
|
||||
"Options.RefreshRate.Label": "Värskendussagedus",
|
||||
"Options.RefreshRate.Desc": "Eksklusiivse täisekraani värskendussagedus. Automaatne valib lähima režiimi.",
|
||||
"Options.RefreshRate.Automatic": "Automaatne",
|
||||
"Options.Scaling.Label": "Skaleerimine",
|
||||
"Options.Scaling.Desc": "Skaleeri algset mängupilti muutmata selle sisemist eraldusvõimet.",
|
||||
"Options.Scaling.Fit": "Mahuta",
|
||||
"Options.Scaling.Cover": "Kata",
|
||||
"Options.Scaling.Stretch": "Venita",
|
||||
"Options.Scaling.Integer": "Täisarvuline",
|
||||
"Options.VSync.Label": "VSync",
|
||||
"Options.VSync.Desc": "Kasuta FIFO-esitust pildi rebimise vältimiseks.",
|
||||
"Options.Hdr.Label": "HDR-väljund",
|
||||
"Options.Hdr.Desc": "Kasuta HDR-i, kui valitud kuvar ja graafikaliides seda toetavad. Automaatrežiim lülitub tagasi SDR-ile.",
|
||||
"Options.Hdr.Auto": "Automaatne",
|
||||
|
||||
"Options.CpuEngine.Label": "CPU-mootor",
|
||||
"Options.CpuEngine.Desc": "Käitusmootor, mida kasutatakse mängukoodi käivitamiseks.",
|
||||
"Options.CpuEngine.Native": "Natiivne",
|
||||
|
||||
"Options.Strict.Label": "Range dynlib-lahendamine",
|
||||
"Options.Strict.Desc": "Katkesta käivitamine, kui imporditud sümbolit ei õnnestu lahendada.",
|
||||
|
||||
"Options.LogLevel.Label": "Logimise tase",
|
||||
"Options.LogLevel.Desc": "Emulaatori konsooliväljundi üksikasjalikkus.",
|
||||
"Options.LogLevel.Trace": "Trace (Jälitus)",
|
||||
"Options.LogLevel.Debug": "Debug (Silumine)",
|
||||
"Options.LogLevel.Info": "Info",
|
||||
"Options.LogLevel.Warning": "Hoiatus",
|
||||
"Options.LogLevel.Error": "Viga",
|
||||
"Options.LogLevel.Critical": "Kriitiline",
|
||||
|
||||
"Options.TraceImports.Label": "Impordi jälituse piir",
|
||||
"Options.TraceImports.Desc": "Jälita iga mooduli esimesi N importi (0 = väljas).",
|
||||
|
||||
"Options.LogToFile.Label": "Logi faili",
|
||||
"Options.LogToFile.Desc": "Kopeeri emulaatori väljund logifaili.",
|
||||
|
||||
"Options.LogFilePath.Label": "Logifaili tee",
|
||||
"Options.LogFilePath.Default": "Kohandatud tee puudub — logid salvestatakse emulaatori kõrvale kausta user/logs.",
|
||||
"Options.LogFilePath.Select": "Vali…",
|
||||
|
||||
"Options.OverrideLogFile.Label": "Kirjuta logifail üle",
|
||||
"Options.OverrideLogFile.Desc": "Kasuta täpset failiteed selle asemel, et lisada Title ID ja ajatempel.",
|
||||
|
||||
"Options.TitleMusic.Label": "Mängu muusika",
|
||||
"Options.TitleMusic.Desc": "Esita valitud mängu eelvaatemuusikat teegis korduvalt.",
|
||||
|
||||
"Options.Discord.Label": "Discordi olek",
|
||||
"Options.Discord.Desc": "Näita käimasolevat mängu oma Discordi profiilis.",
|
||||
|
||||
"Options.Language.Label": "Emulaatori keel",
|
||||
"Options.Language.Desc": "Käivitis kasutatav keel. Rakendub kohe.",
|
||||
|
||||
"Common.On": "Sisse",
|
||||
"Common.Off": "Välja",
|
||||
"Common.Save": "Salvesta",
|
||||
"Common.Cancel": "Tühista",
|
||||
|
||||
|
||||
"Console.Title": "KONSOOL",
|
||||
"Console.SearchWatermark": "Otsi…",
|
||||
"Console.AutoScroll": "Automaatne kerimine",
|
||||
"Console.Split": "Poolita",
|
||||
"Console.Copy": "Kopeeri",
|
||||
"Console.Clear": "Tühjenda",
|
||||
"Console.WindowTitle": "SharpEmu konsool",
|
||||
|
||||
"Launch.NoGameSelected": "Mäng pole valitud",
|
||||
"Launch.NoGameHint": "Vali mäng teegist või ava eboot.bin fail otse.",
|
||||
"Launch.Idle": "Ootel",
|
||||
"Launch.Console": "≡ Konsool",
|
||||
"Launch.Launch": "▶ Käivita",
|
||||
"Launch.Stop": "■ Peata",
|
||||
"Launch.Running": "Käib — {0}",
|
||||
"Launch.Stopping": "Peatamine…",
|
||||
"Launch.Exited": "Väljus koodiga {0} ({1})",
|
||||
"Launch.ExeNotFound": "SharpEmu käivitavat faili ei leitud. Ehita esmalt SharpEmu.CLI projekt (dotnet build).",
|
||||
"Launch.LogFile": "Logifail: {0}",
|
||||
"Launch.Command": "$ SharpEmu {0}",
|
||||
"Launch.StartFailed": "Emulaatori käivitamine nurjus: {0}",
|
||||
"Launch.ProcessExited": "Protsess väljus koodiga {0} ({1}).",
|
||||
|
||||
"Exit.Ok": "OK",
|
||||
"Exit.InvalidArguments": "vigased argumendid",
|
||||
"Exit.EbootNotFound": "eboot-faili ei leitud",
|
||||
"Exit.RuntimeException": "käitusaegne erand",
|
||||
"Exit.EmulationError": "emulatsioonitõrge",
|
||||
"Exit.Unknown": "tundmatu",
|
||||
|
||||
"Status.EmulatorLocating": "Emulaator: otsimine…",
|
||||
"Status.EmulatorPath": "Emulaator: {0}",
|
||||
"Status.EmulatorNotFound": "Emulaator: SharpEmu käivitavat faili ei leitud — ehita esmalt SharpEmu.CLI.",
|
||||
"Status.ScanningLibrary": "Teegi skaneerimine…",
|
||||
"Status.AddFolderPrompt": "Lisa mängukaust teegi täitmiseks.",
|
||||
"Status.LibraryScanned": "Teek skaneeritud: {0} mängu {1} kaustas.",
|
||||
"Status.CouldNotOpenFolder": "Kausta ei saanud avada: {0}",
|
||||
"Status.CopiedToClipboard": "{0} kopeeritud lõikelauale.",
|
||||
"Status.RemovedFromLibrary": "Eemaldati “{0}” teegist. Taastamiseks lisa selle kaust uuesti.",
|
||||
"Status.Running": "Käib: {0}",
|
||||
"Status.Stopping": "Peatamine…",
|
||||
"Status.Idle": "Ootel",
|
||||
|
||||
"Clipboard.Path": "Asukoht",
|
||||
"Clipboard.TitleId": "Title ID",
|
||||
|
||||
"Discord.Playing": "Mängib: {0}",
|
||||
"Discord.Browsing": "Sirvib teeki",
|
||||
|
||||
"Dialog.ChooseGameFolder": "Vali mänge sisaldav kaust",
|
||||
"Dialog.OpenExecutable": "Ava käivitatav fail käivitamiseks",
|
||||
"Dialog.PsExecutables": "PS käivitusfailid",
|
||||
"Dialog.SaveLogFile": "Vali logifaili salvestamiskoht",
|
||||
"Dialog.PlainTextFiles": "Tavatekstifailid",
|
||||
"Dialog.LogFiles": "Logifailid",
|
||||
|
||||
"Options.About": "Teave",
|
||||
"About.Github.Label": "GitHub",
|
||||
"About.Github.Desc": "Lähtekood, vearaportid ja projekti arendus.",
|
||||
"About.Github.LatestCommitLabel": "Viimane muudatus (commit)",
|
||||
"About.Github.LatestCommitDescription": "Viimane muudatus peaharul",
|
||||
"About.Discord.Label": "Discord",
|
||||
"About.Discord.Desc": "Liitu kogukonnaga, saa tuge ja jälgi arendust.",
|
||||
"About.GithubButton": "Löö GitHubis kaasa!",
|
||||
"About.DiscordComingSoon": "Tulekul",
|
||||
|
||||
"Updater.Auto.Label": "Kontrolli värskendusi käivitamisel",
|
||||
"Updater.Auto.Desc": "Kontrollib GitHubist värskendusi käivitamist viivitamata.",
|
||||
"Updater.Label": "Värskendused",
|
||||
"Updater.Check": "Kontrolli värskendusi",
|
||||
"Updater.DownloadRestart": "Laadi alla ja taaskäivita",
|
||||
"Updater.Status.Ready": "Praegune versioon: {0}",
|
||||
"Updater.Status.Checking": "Värskenduste kontrollimine…",
|
||||
"Updater.Status.Current": "Sinu versioon on ajakohane ({0}).",
|
||||
"Updater.Status.Available": "Uus versioon on saadaval: {0}",
|
||||
"Updater.Status.Downloading": "Värskenduse allalaadimine… {0}%",
|
||||
"Updater.Status.Installing": "Värskenduse paigaldamine…",
|
||||
"Updater.Status.Timeout": "Värskenduste kontroll aegus 10 sekundi järel.",
|
||||
"Updater.Status.Failed": "Värskendusi ei saanud kontrollida.",
|
||||
"Updater.Status.ChecksumFailed": "Allalaaditud värskendus ei läbinud SHA-256 kontrolli.",
|
||||
"Updater.Status.Unsupported": "Automaatne värskendamine nõuab Windowsi, Linuxi või macOS-i x64 versiooni."
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
{
|
||||
"_languageName": "Polski",
|
||||
|
||||
"Page.Library": "Biblioteka",
|
||||
"Page.Options": "Opcje",
|
||||
"Page.GameCount.One": "1 gra",
|
||||
"Page.GameCount.Other": "{0} gier",
|
||||
|
||||
"Library.SearchWatermark": "Szukaj w bibliotece…",
|
||||
"Library.AddFolder": "Dodaj folder",
|
||||
"Library.OpenFile": "Otwórz plik…",
|
||||
"Library.View.Grid": "Widok siatki",
|
||||
"Library.View.Carousel": "Widok listy",
|
||||
|
||||
"Library.Context.Launch": "Uruchom",
|
||||
"Library.Context.OpenFolder": "Otwórz folder gry",
|
||||
"Library.Context.CopyPath": "Kopiuj ścieżkę",
|
||||
"Library.Context.CopyTitleId": "Kopiuj numer seryjny",
|
||||
"Library.Context.GameSettings": "Ustawienia gry…",
|
||||
"Library.Context.Remove": "Usuń z biblioteki",
|
||||
|
||||
"Library.Empty.Title": "Twoja biblioteka jest pusta",
|
||||
"Library.Empty.Hint": "Dodaj folder zawierający twoje gry, aby rozpocząć.",
|
||||
"Library.Empty.SearchTitle": "Brak gier pasujących do twojego wyszukiwania",
|
||||
"Library.Empty.SearchHint": "Nic w bibliotece nie pasuje do “{0}”.",
|
||||
"Library.Empty.AddFolder": "+ Dodaj folder z grami",
|
||||
|
||||
"Library.Loading": "Ładowanie biblioteki…",
|
||||
"Library.Stat.Version": "Wersja",
|
||||
"Library.Stat.Installed": "Zainstalowano",
|
||||
"Library.Stat.TitleId": "Numer seryjny",
|
||||
"Common.Back": "Wstecz",
|
||||
|
||||
"Options.General": "Ogólne",
|
||||
"Options.Logging": "Dziennik zdarzeń",
|
||||
"Options.Env.Tab": "Środowisko",
|
||||
"Options.Section.Environment": "ZMIENNE ŚRODOWISKOWE",
|
||||
"Options.Env.Desc": "Przełączniki przekazywane emulatorowi jako zmienne środowiskowe przy uruchomieniu.",
|
||||
"Options.Env.Bthid.Desc": "Zgłaszaj Bluetooth HID jako niedostępny dla tytułów, których middleware kierownicy/FFB odpytuje w nieskończoność.\nZostaw wyłączone normalnie. Niektóre tytuły zawieszają się, gdy inicjalizacja zawiedzie.",
|
||||
"Options.Env.LoopGuard.Desc": "Nie wymuszaj zamknięcia tytułów, które powtarzają to samo wywołanie zbyt długo.\nSpróbuj tego, gdy gra zamyka się sama podczas ładowania.",
|
||||
"Options.Env.WritableApp0.Desc": "Pozwól tytułom tworzyć i zapisywać pliki wewnątrz folderu instalacji.\nPotrzebne w przypadku niespakowanych zrzutów, które zapisują dane zapisu lub konfiguracji w /app0.",
|
||||
"Options.Env.VkValidation.Desc": "Włącz warstwy walidacji Vulkan do debugowania GPU.\nWolne. Wymaga zainstalowanego Vulkan SDK.",
|
||||
"Options.Env.DumpSpirv.Desc": "Zrzuć shadery AGC i ich translacje SPIR-V do folderu shader-dumps.\nUżyj przy zgłaszaniu błędów shaderów lub renderowania.",
|
||||
"Options.Env.LogDirectMemory.Desc": "Loguj alokacje pamięci bezpośredniej i błędy do konsoli.\nUżyj, gdy gra przerywa działanie lub zamyka się podczas uruchamiania.",
|
||||
"Options.Env.LogIo.Desc": "Loguj otwieranie plików, odczyt i rozwiązywanie ścieżek do konsoli.\nUżyj, gdy gra nie może znaleźć swoich plików danych podczas uruchamiania.",
|
||||
"Options.Env.LogNp.Desc": "Loguj wywołania biblioteki NP (PlayStation Network) do konsoli.",
|
||||
"Options.Env.Group.Debug": "Debugowanie",
|
||||
"Options.Env.Group.General": "Ogólne",
|
||||
"Options.Env.RenderDoc.Desc": "Załaduj API RenderDoc w aplikacji, aby można było przechwytywać klatki z wnętrza emulatora.\nNaciśnij F10 podczas działania gry, aby przechwycić jedną klatkę; przechwycone klatki trafiają do user/logs/capture_logs/<TITLE_ID>.\nWymaga zainstalowanego RenderDoc. Spowalnia GPU i zawiesza niektóre tytuły, więc zostaw wyłączone, chyba że debugujesz.",
|
||||
"Options.Env.GuestImageCpuSync.Desc": "Ponownie przesyłaj powierzchnie gościa, które procesor gry nadpisuje.\nZostaw wyłączone normalnie. Włącz dla tytułów, których powierzchnie rysowane przez CPU nigdy nie docierają na ekran.\nKosztuje wydajność i pogarsza działanie niektórych tytułów, takich jak GTA V.",
|
||||
"Options.Env.ForceSubmitOrphanPreambles.Desc": "Dostarczaj preambuły buforów poleceń GPU nawet gdy ich docelowa kolejka ich nie odbiera.\nZostaw wyłączone normalnie. Włącz dla tytułów, które zawieszają się w oczekiwaniu na sygnał z GPU.",
|
||||
"Options.DefaultProfile.Label": "Domyślna nazwa profilu",
|
||||
"Options.DefaultProfile.Desc": "Nazwa używana, gdy gra prosi o wprowadzenie tekstu. Domyślnie Sharp.",
|
||||
"Options.Section.Emulation": "EMULACJA",
|
||||
"Options.Section.Logging": "DZIENNIK ZDARZEŃ",
|
||||
"Options.Section.Launcher": "LAUNCHER",
|
||||
"Options.Section.Rendering": "RENDEROWANIE",
|
||||
"Options.Section.Display": "WYŚWIETLANIE",
|
||||
"Options.Graphics": "Grafika",
|
||||
|
||||
"Options.RenderResolution.Label": "Rozdzielczość wewnętrzna",
|
||||
"Options.RenderResolution.Desc": "Renderuj cele pozaekranowe poniżej natywnej rozdzielczości i skaluj w górę przy prezentacji. Niższe wartości zamieniają jakość obrazu na zapas GPU; działa od następnego uruchomienia.",
|
||||
"Options.RenderResolution.Native": "100% (natywna)",
|
||||
"Options.WindowMode.Label": "Tryb okna",
|
||||
"Options.WindowMode.Desc": "Zwykłe okno, bezramkowe na pulpicie lub pełny ekran wyłączny.",
|
||||
"Options.WindowMode.Windowed": "W oknie",
|
||||
"Options.WindowMode.Borderless": "Bezramkowe",
|
||||
"Options.WindowMode.Exclusive": "Wyłączne",
|
||||
"Options.Resolution.Label": "Rozdzielczość",
|
||||
"Options.Resolution.Desc": "Początkowy rozmiar okna lub rozdzielczość pełnego ekranu wyłącznego.",
|
||||
"Options.Display.Label": "Wyświetlacz",
|
||||
"Options.Display.Desc": "Monitor używany do centrowania i trybu pełnoekranowego.",
|
||||
"Options.RefreshRate.Label": "Częstotliwość odświeżania",
|
||||
"Options.RefreshRate.Desc": "Częstotliwość odświeżania w trybie pełnego ekranu wyłącznego. Automatyczna wybiera najbliższy tryb.",
|
||||
"Options.RefreshRate.Automatic": "Automatyczna",
|
||||
"Options.Scaling.Label": "Skalowanie",
|
||||
"Options.Scaling.Desc": "Skaluj natywny obraz gościa bez zmiany jego wewnętrznej rozdzielczości.",
|
||||
"Options.Scaling.Fit": "Dopasuj",
|
||||
"Options.Scaling.Cover": "Wypełnij",
|
||||
"Options.Scaling.Stretch": "Rozciągnij",
|
||||
"Options.Scaling.Integer": "Całkowitoliczbowe",
|
||||
"Options.VSync.Label": "VSync",
|
||||
"Options.VSync.Desc": "Używaj prezentacji FIFO dla obrazu bez rozrywania.",
|
||||
"Options.Hdr.Label": "Wyjście HDR",
|
||||
"Options.Hdr.Desc": "Używaj HDR, gdy wybrany wyświetlacz i backend graficzny to obsługują. Automatyczny przełącza na SDR.",
|
||||
"Options.Hdr.Auto": "Automatyczny",
|
||||
|
||||
"Options.CpuEngine.Label": "Silnik CPU",
|
||||
"Options.CpuEngine.Desc": "Silnik wykonawczy używany do uruchamiania kodu gry.",
|
||||
"Options.CpuEngine.Native": "Natywny",
|
||||
|
||||
"Options.Strict.Label": "Ścisłe rozwiązywanie dynlib",
|
||||
"Options.Strict.Desc": "Przerwij uruchomienie, gdy importowany symbol nie może zostać rozwiązany.",
|
||||
|
||||
"Options.LogLevel.Label": "Poziom logowania",
|
||||
"Options.LogLevel.Desc": "Szczegółowość wyjścia konsoli emulatora.",
|
||||
"Options.LogLevel.Trace": "Śledzenie",
|
||||
"Options.LogLevel.Debug": "Debugowanie",
|
||||
"Options.LogLevel.Info": "Informacja",
|
||||
"Options.LogLevel.Warning": "Ostrzeżenie",
|
||||
"Options.LogLevel.Error": "Błąd",
|
||||
"Options.LogLevel.Critical": "Krytyczny",
|
||||
|
||||
"Options.TraceImports.Label": "Limit śledzenia importów",
|
||||
"Options.TraceImports.Desc": "Śledź pierwszych N importów na moduł (0 = wyłączone).",
|
||||
|
||||
"Options.LogToFile.Label": "Loguj do pliku",
|
||||
"Options.LogToFile.Desc": "Kopiuj wyjście emulatora do pliku logu.",
|
||||
|
||||
"Options.LogFilePath.Label": "Ścieżka pliku logu",
|
||||
"Options.LogFilePath.Default": "Brak niestandardowej ścieżki — logi trafiają do user/logs obok emulatora.",
|
||||
"Options.LogFilePath.Select": "Wybierz…",
|
||||
|
||||
"Options.OverrideLogFile.Label": "Nadpisz plik logu",
|
||||
"Options.OverrideLogFile.Desc": "Użyj dokładnej ścieżki pliku zamiast dopisywania ID tytułu i znacznika czasu.",
|
||||
|
||||
"Options.TitleMusic.Label": "Muzyka tytułowa",
|
||||
"Options.TitleMusic.Desc": "Odtwarzaj w pętli muzykę podglądu wybranej gry w bibliotece.",
|
||||
|
||||
"Options.Discord.Label": "Discord Rich Presence",
|
||||
"Options.Discord.Desc": "Pokazuj uruchomioną grę na swoim profilu Discord.",
|
||||
|
||||
"Options.Language.Label": "Język emulatora",
|
||||
"Options.Language.Desc": "Język używany w całym launcherze. Działa natychmiast.",
|
||||
|
||||
"Common.On": "Włącz",
|
||||
"Common.Off": "Wyłącz",
|
||||
"Common.Save": "Zapisz",
|
||||
"Common.Cancel": "Anuluj",
|
||||
|
||||
|
||||
"Console.Title": "KONSOLA",
|
||||
"Console.SearchWatermark": "Szukaj...",
|
||||
"Console.AutoScroll": "Autoprzewijanie",
|
||||
"Console.Split": "Podziel",
|
||||
"Console.Copy": "Kopiuj",
|
||||
"Console.Clear": "Wyczyść",
|
||||
"Console.WindowTitle": "Konsola SharpEmu",
|
||||
|
||||
"Launch.NoGameSelected": "Nie wybrano gry",
|
||||
"Launch.NoGameHint": "Wybierz grę z biblioteki lub otwórz bezpośrednio plik eboot.bin.",
|
||||
"Launch.Idle": "Bezczynny",
|
||||
"Launch.Console": "≡ Konsola",
|
||||
"Launch.Launch": "▶ Uruchom",
|
||||
"Launch.Stop": "■ Zatrzymaj",
|
||||
"Launch.Running": "Działa — {0}",
|
||||
"Launch.Stopping": "Zatrzymywanie…",
|
||||
"Launch.Exited": "Zakończono z kodem {0} ({1})",
|
||||
"Launch.ExeNotFound": "Nie znaleziono pliku wykonywalnego SharpEmu. Najpierw zbuduj projekt SharpEmu.CLI (dotnet build).",
|
||||
"Launch.LogFile": "Plik logu: {0}",
|
||||
"Launch.Command": "$ SharpEmu {0}",
|
||||
"Launch.StartFailed": "Nie udało się uruchomić emulatora: {0}",
|
||||
"Launch.ProcessExited": "Proces zakończony z kodem {0} ({1}).",
|
||||
|
||||
"Exit.Ok": "OK",
|
||||
"Exit.InvalidArguments": "nieprawidłowe argumenty",
|
||||
"Exit.EbootNotFound": "nie znaleziono eboot",
|
||||
"Exit.RuntimeException": "wyjątek czasu wykonania",
|
||||
"Exit.EmulationError": "błąd emulacji",
|
||||
"Exit.Unknown": "nieznany",
|
||||
|
||||
"Status.EmulatorLocating": "Emulator: lokalizowanie…",
|
||||
"Status.EmulatorPath": "Emulator: {0}",
|
||||
"Status.EmulatorNotFound": "Emulator: nie znaleziono pliku wykonywalnego SharpEmu — najpierw zbuduj SharpEmu.CLI.",
|
||||
"Status.ScanningLibrary": "Skanowanie biblioteki…",
|
||||
"Status.AddFolderPrompt": "Dodaj folder z grami, aby wypełnić bibliotekę.",
|
||||
"Status.LibraryScanned": "Biblioteka przeskanowana: {0} gier w {1} folderach.",
|
||||
"Status.CouldNotOpenFolder": "Nie można otworzyć folderu: {0}",
|
||||
"Status.CopiedToClipboard": "{0} skopiowano do schowka.",
|
||||
"Status.RemovedFromLibrary": "Usunięto \u201c{0}\u201d z biblioteki. Dodaj ponownie folder, aby przywrócić.",
|
||||
"Status.Running": "Uruchomiono {0}",
|
||||
"Status.Stopping": "Zatrzymywanie…",
|
||||
"Status.Idle": "Bezczynny",
|
||||
|
||||
"Clipboard.Path": "Ścieżka",
|
||||
"Clipboard.TitleId": "ID tytułu",
|
||||
|
||||
"Discord.Playing": "Gra w {0}",
|
||||
"Discord.Browsing": "Przegląda bibliotekę",
|
||||
|
||||
"Dialog.ChooseGameFolder": "Wybierz folder zawierający gry",
|
||||
"Dialog.OpenExecutable": "Otwórz plik wykonywalny do uruchomienia",
|
||||
"Dialog.PsExecutables": "Pliki wykonywalne PS",
|
||||
"Dialog.SaveLogFile": "Wybierz, gdzie zapisać plik logu",
|
||||
"Dialog.PlainTextFiles": "Pliki tekstowe",
|
||||
"Dialog.LogFiles": "Pliki logów",
|
||||
|
||||
"Options.About" : "O programie",
|
||||
"About.Github.Label": "GitHub",
|
||||
"About.Github.Desc": "Kod źródłowy, zgłoszenia i rozwój projektu.",
|
||||
"About.Github.LatestCommitLabel": "Najnowszy commit",
|
||||
"About.Github.LatestCommitDescription": "Najnowszy commit na gałęzi głównej",
|
||||
"About.Discord.Label": "Discord",
|
||||
"About.Discord.Desc": "Dołącz do społeczności, uzyskaj wsparcie i śledź rozwój.",
|
||||
"About.GithubButton": "Wspieraj na GitHubie!",
|
||||
"About.DiscordComingSoon": "Wkrótce",
|
||||
|
||||
"Updater.Auto.Label": "Sprawdzaj aktualizacje przy uruchomieniu",
|
||||
"Updater.Auto.Desc": "Sprawdza GitHub bez opóźniania uruchomienia.",
|
||||
"Updater.Label": "Aktualizacje",
|
||||
"Updater.Check": "Sprawdź aktualizacje",
|
||||
"Updater.DownloadRestart": "Pobierz i uruchom ponownie",
|
||||
"Updater.Status.Ready": "Obecna wersja: {0}",
|
||||
"Updater.Status.Checking": "Sprawdzanie aktualizacji…",
|
||||
"Updater.Status.Current": "Masz najnowszą wersję ({0}).",
|
||||
"Updater.Status.Available": "Dostępna nowa wersja: {0}",
|
||||
"Updater.Status.Downloading": "Pobieranie aktualizacji… {0}%",
|
||||
"Updater.Status.Installing": "Instalowanie aktualizacji…",
|
||||
"Updater.Status.Timeout": "Sprawdzanie aktualizacji przekroczyło limit 10 sekund.",
|
||||
"Updater.Status.Failed": "Nie udało się sprawdzić aktualizacji.",
|
||||
"Updater.Status.ChecksumFailed": "Pobrana aktualizacja nie przeszła weryfikacji SHA-256.",
|
||||
"Updater.Status.Unsupported": "Automatyczna aktualizacja wymaga wersji dla Windows, Linux lub macOS x64."
|
||||
}
|
||||
@@ -6478,6 +6478,25 @@ public static partial class AgcExports
|
||||
var targetAddress = destinationAddress +
|
||||
(incrementAddress ? (ulong)index * sizeof(uint) : 0);
|
||||
wroteData = TryWriteUInt32(ctx, targetAddress, values[index]);
|
||||
if (wroteData)
|
||||
{
|
||||
GpuWaitRegistry.RecordProduced(
|
||||
ctx.Memory, targetAddress, values[index]);
|
||||
}
|
||||
}
|
||||
|
||||
// Like ReleaseMem dataSel=2: a 64-bit WAIT_REG_MEM watches an
|
||||
// 8-byte label written as two 32-bit dwords. Record the combined
|
||||
// 64-bit value so a 64-bit EQ can latch even though the writes
|
||||
// landed as two 32-bit stores.
|
||||
if (wroteData && dwordCount >= 2 && incrementAddress)
|
||||
{
|
||||
var combined = ((ulong)values[1] << 32) | values[0];
|
||||
GpuWaitRegistry.RecordProduced(
|
||||
ctx.Memory, destinationAddress, combined);
|
||||
// Also latch the high half's address for symmetry: a stray
|
||||
// 32-bit wait on the high dword should not be confused, but
|
||||
// recording it does not hurt and mirrors the per-dword stores.
|
||||
}
|
||||
|
||||
if (tracePacket)
|
||||
@@ -12174,15 +12193,18 @@ public static partial class AgcExports
|
||||
|
||||
if (dispatchEndX == 0 || dispatchEndY == 0 || dispatchEndZ == 0)
|
||||
{
|
||||
// Indirect dispatches read their dimensions from a guest buffer a
|
||||
// prior GPU dispatch fills. Zero here means that producer has not run
|
||||
// yet — signal the caller to suspend on the dims buffer and retry,
|
||||
// rather than dropping the work (which black-screens GPU-driven games
|
||||
// like Astro Bot). Direct dispatches carry dims inline, so a zero is
|
||||
// genuinely malformed and still rejected.
|
||||
if (opcode == ItDispatchIndirect)
|
||||
// For indirect dispatches (both absolute and base), zero dimensions are a valid outcome
|
||||
// of GPU culling passes (0 workgroups). VulkanVideoPresenter handles groupCount = 0 as a clean no-op.
|
||||
if (opcode == ItDispatchIndirect || dispatchSource is "absolute-indirect" or "base-indirect")
|
||||
{
|
||||
indirectDimsRetryAddress = dimensionsAddress;
|
||||
var waveCount = (initiator & (1u << 15)) != 0 ? 32u : 64u;
|
||||
dispatch = new ComputeDispatch(
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
waveCount,
|
||||
IsIndirect: true,
|
||||
0, 0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return RejectComputeDispatch(
|
||||
|
||||
@@ -13828,16 +13828,10 @@ internal static unsafe class VulkanVideoPresenter
|
||||
existing.LogicalDepth == depth &&
|
||||
existing.Type == type &&
|
||||
existing.MipLevels == mipLevels &&
|
||||
(!requiresStorage || existing.SupportsStorageUsage) &&
|
||||
(exactFormatMatch ||
|
||||
(IsAliasableGuestImageFormat(existing.Format, format) &&
|
||||
(!requiresStorage || existing.SupportsStorageUsage))))
|
||||
IsAliasableGuestImageFormat(existing.Format, format)))
|
||||
{
|
||||
if (requiresStorage && !existing.SupportsStorageUsage)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Guest image 0x{target.Address:X16} was created without storage usage.");
|
||||
}
|
||||
|
||||
existing.IsCpuBacked = false;
|
||||
existing.CpuContentFingerprint = 0;
|
||||
if (existing.RenderPass.Handle == 0 &&
|
||||
@@ -13870,14 +13864,9 @@ internal static unsafe class VulkanVideoPresenter
|
||||
if (existing.Width == target.Width &&
|
||||
existing.Height == target.Height &&
|
||||
existing.MipLevels == mipLevels &&
|
||||
(!requiresStorage || existing.SupportsStorageUsage) &&
|
||||
IsCompatibleViewFormat(existing.Format, format))
|
||||
{
|
||||
if (requiresStorage && !existing.SupportsStorageUsage)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Guest image 0x{target.Address:X16} was created without storage usage.");
|
||||
}
|
||||
|
||||
if (_traceGuestImageEvents)
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
@@ -13952,50 +13941,52 @@ internal static unsafe class VulkanVideoPresenter
|
||||
{
|
||||
if (requiresStorage && !retained.SupportsStorageUsage)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Retained guest image 0x{target.Address:X16} was created without storage usage.");
|
||||
// Do not reuse retained image if it lacks required storage usage
|
||||
DestroyGuestImage(retained);
|
||||
}
|
||||
|
||||
retained.IsCpuBacked = false;
|
||||
retained.CpuContentFingerprint = 0;
|
||||
_guestImages.Add(target.Address, retained);
|
||||
var retainedByteCount = GetTextureByteCount(
|
||||
target.Format,
|
||||
target.Width,
|
||||
target.Height,
|
||||
depth);
|
||||
lock (_gate)
|
||||
else
|
||||
{
|
||||
_cpuBackedUploadGenerations.Remove(target.Address);
|
||||
_guestImageExtents[target.Address] = (
|
||||
retained.IsCpuBacked = false;
|
||||
retained.CpuContentFingerprint = 0;
|
||||
_guestImages.Add(target.Address, retained);
|
||||
var retainedByteCount = GetTextureByteCount(
|
||||
target.Format,
|
||||
target.Width,
|
||||
target.Height,
|
||||
retainedByteCount);
|
||||
}
|
||||
depth);
|
||||
lock (_gate)
|
||||
{
|
||||
_cpuBackedUploadGenerations.Remove(target.Address);
|
||||
_guestImageExtents[target.Address] = (
|
||||
target.Width,
|
||||
target.Height,
|
||||
retainedByteCount);
|
||||
}
|
||||
|
||||
// Arm the exact extent the flip/acquire sync path would read
|
||||
// back, budgeted by bytes rather than by resolution: the old
|
||||
// 1920x1080 cap left every 4K surface permanently
|
||||
// un-invalidated, so a guest CPU rewrite of one was never
|
||||
// reflected and the sample served stale bytes.
|
||||
if (ShouldTrackGuestImageWrites(retainedByteCount))
|
||||
{
|
||||
SharpEmu.HLE.GuestImageWriteTracker.Track(
|
||||
target.Address,
|
||||
retainedByteCount,
|
||||
CurrentGuestWorkSequenceForDiagnostics,
|
||||
"vulkan.render-target");
|
||||
}
|
||||
// Arm the exact extent the flip/acquire sync path would read
|
||||
// back, budgeted by bytes rather than by resolution: the old
|
||||
// 1920x1080 cap left every 4K surface permanently
|
||||
// un-invalidated, so a guest CPU rewrite of one was never
|
||||
// reflected and the sample served stale bytes.
|
||||
if (ShouldTrackGuestImageWrites(retainedByteCount))
|
||||
{
|
||||
SharpEmu.HLE.GuestImageWriteTracker.Track(
|
||||
target.Address,
|
||||
retainedByteCount,
|
||||
CurrentGuestWorkSequenceForDiagnostics,
|
||||
"vulkan.render-target");
|
||||
}
|
||||
|
||||
if (_traceGuestImageEvents)
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
$"[GIMG] retained addr=0x{target.Address:X} " +
|
||||
$"{target.Width}x{target.Height} fmt={format} " +
|
||||
$"initialized={retained.Initialized}");
|
||||
}
|
||||
if (_traceGuestImageEvents)
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
$"[GIMG] retained addr=0x{target.Address:X} " +
|
||||
$"{target.Width}x{target.Height} fmt={format} " +
|
||||
$"initialized={retained.Initialized}");
|
||||
}
|
||||
|
||||
return retained;
|
||||
return retained;
|
||||
}
|
||||
}
|
||||
|
||||
var imageInfo = new ImageCreateInfo
|
||||
|
||||
@@ -2366,17 +2366,16 @@ public static partial class Gen5SpirvTranslator
|
||||
return;
|
||||
}
|
||||
|
||||
// GLOBAL_STORE/LOAD_DWORD(x2/x3/x4) are dword-aligned by the GCN ISA, so read/write dwords directly instead of the per-byte loop.
|
||||
for (uint index = 0; index < control.DwordCount; index++)
|
||||
{
|
||||
var address = index == 0
|
||||
? byteAddress
|
||||
: IAdd(byteAddress, UInt(index * sizeof(uint)));
|
||||
StoreBufferBytes(
|
||||
var indexedDwordAddress = index == 0
|
||||
? dwordAddress
|
||||
: IAdd(dwordAddress, UInt(index));
|
||||
StoreBufferWord(
|
||||
bindingIndex,
|
||||
address,
|
||||
LoadV(control.VectorData + index),
|
||||
sizeof(uint),
|
||||
0);
|
||||
indexedDwordAddress,
|
||||
LoadV(control.VectorData + index));
|
||||
}
|
||||
});
|
||||
return true;
|
||||
@@ -2404,12 +2403,12 @@ public static partial class Gen5SpirvTranslator
|
||||
|
||||
for (uint index = 0; index < control.DwordCount; index++)
|
||||
{
|
||||
var address = index == 0
|
||||
? byteAddress
|
||||
: IAdd(byteAddress, UInt(index * sizeof(uint)));
|
||||
var indexedDwordAddress = index == 0
|
||||
? dwordAddress
|
||||
: IAdd(dwordAddress, UInt(index));
|
||||
StoreV(
|
||||
control.VectorData + index,
|
||||
LoadUnalignedBufferWord(bindingIndex, address));
|
||||
LoadBufferWord(bindingIndex, indexedDwordAddress));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -2510,17 +2509,16 @@ public static partial class Gen5SpirvTranslator
|
||||
return;
|
||||
}
|
||||
|
||||
// BUFFER_STORE/LOAD_DWORD(x2/x3/x4) are dword-aligned by the GCN ISA, same as the GLOBAL case above — no per-byte reassembly needed.
|
||||
for (uint index = 0; index < control.DwordCount; index++)
|
||||
{
|
||||
var address = index == 0
|
||||
? byteAddress
|
||||
: IAdd(byteAddress, UInt(index * sizeof(uint)));
|
||||
StoreBufferBytes(
|
||||
var indexedDwordAddress = index == 0
|
||||
? dwordAddress
|
||||
: IAdd(dwordAddress, UInt(index));
|
||||
StoreBufferWord(
|
||||
bindingIndex,
|
||||
address,
|
||||
LoadV(control.VectorData + index),
|
||||
sizeof(uint),
|
||||
0);
|
||||
indexedDwordAddress,
|
||||
LoadV(control.VectorData + index));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2576,12 +2574,12 @@ public static partial class Gen5SpirvTranslator
|
||||
|
||||
for (uint index = 0; index < control.DwordCount; index++)
|
||||
{
|
||||
var address = index == 0
|
||||
? byteAddress
|
||||
: IAdd(byteAddress, UInt(index * sizeof(uint)));
|
||||
var indexedDwordAddress = index == 0
|
||||
? dwordAddress
|
||||
: IAdd(dwordAddress, UInt(index));
|
||||
StoreV(
|
||||
control.VectorData + index,
|
||||
LoadUnalignedBufferWord(bindingIndex, address));
|
||||
LoadBufferWord(bindingIndex, indexedDwordAddress));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user