changed comments to english

This commit is contained in:
BeZide93 2025-11-01 23:39:44 +01:00
parent d28cfb1c94
commit 77dea2787f
10 changed files with 79 additions and 81 deletions

View file

@ -17,7 +17,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Notifications + special-use Foreground Service (Android 14+) -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- Erforderlich für startForeground() -->
<!-- Required for startForeground() -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
@ -88,8 +88,6 @@
android:exported="false"
android:stopWithTask="true"
android:foregroundServiceType="mediaPlayback" />
</application>
</manifest>

View file

@ -40,7 +40,7 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
private val mainHandler = Handler(Looper.getMainLooper())
// ---- Foreground-Service Binding ----
// ---- Foreground service binding ----
private var emuBound = false
private var emuBinder: EmulationService.LocalBinder? = null
private var _startedViaService = false
@ -52,7 +52,7 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
emuBound = true
ghLog("EmulationService bound")
// Falls Start bereits vorbereitet wurde und noch kein Loop läuft → jetzt im Service starten
// If startup is already prepared and no loop is running yet → start it in the service now
if (_isStarted && !_startedViaService && _guestThread == null) {
startRunLoopInService()
}
@ -66,7 +66,7 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
}
}
// Resize-Stabilizer
// Resize stabilizer
private var stabilizerActive = false
// last known Android rotation (0,1,2,3)
@ -143,7 +143,7 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
override fun surfaceCreated(holder: SurfaceHolder) {
ghLog("surfaceCreated")
// Früh binden, damit der Service schon steht, bevor wir starten
// Bind early so the service is ready before we start
ensureServiceStartedAndBound()
rebindNativeWindow(force = true)
}
@ -152,26 +152,26 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
ghLog("surfaceChanged ${width}x$height")
if (_isClosed) return
// IMMER neu binden auch wenn die Größe gleich bleibt
// ALWAYS rebind—even if the size stays the same
rebindNativeWindow(force = true)
val sizeChanged = (_width != width || _height != height)
_width = width
_height = height
// Service sicherstellen & Renderstart
// Ensure service is running & start rendering
ensureServiceStartedAndBound()
start(holder)
// Resize stabilisieren (übernimmt plausibles final size set)
// Stabilize resize (applies plausible final size)
startStabilizedResize(expectedRotation = lastRotation)
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
ghLog("surfaceDestroyed → shutdownBinding()")
// Immer binden lösen (verhindert Leaks beim Task-Swipe)
// Always unbind (prevents leaks when swiping away the task)
shutdownBinding()
// Eigentliche Emu-Beendigung passiert via close() / Exit Game
// Actual emulation shutdown happens via close() / Exit Game
}
override fun onWindowVisibilityChanged(visibility: Int) {
@ -214,12 +214,12 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
private fun start(surfaceHolder: SurfaceHolder) {
if (_isStarted) return
// NICHT gleich _isStarted = true → erst alles vorbereiten
// Do NOT set _isStarted = true immediately → prepare everything first
rebindNativeWindow(force = true)
game = if (mainViewModel.isMiiEditorLaunched) null else mainViewModel.gameModel
// Input initialisieren
// Initialize input
KenjinxNative.inputInitialize(width, height)
_inputInitialized = true
@ -235,7 +235,7 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
KenjinxNative.setSurfaceRotationByAndroidRotation(currentRot ?: 0)
try { KenjinxNative.deviceSetWindowHandle(currentWindowHandle) } catch (_: Throwable) {}
// Sanfter Kick nur wenn Renderer READY **und** Input init
// Gentle kick only when renderer is READY **and** input is initialized
if (width > 0 && height > 0 &&
MainActivity.mainViewModel?.rendererReady == true &&
_inputInitialized
@ -247,10 +247,10 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
val qs = org.kenjinx.android.viewmodels.QuickSettings(mainViewModel.activity)
try { KenjinxNative.graphicsSetFullscreenStretch(qs.stretchToFullscreen) } catch (_: Throwable) {}
// Host gilt nun als „gestartet“
// Host is now considered 'started'
_isStarted = true
// Immer bevorzugt im Service starten; wenn Bind noch nicht fertig → kurz warten, dann fallback
// Prefer starting in the service; if binding isn't ready yet → wait briefly, then fall back
if (emuBound) {
startRunLoopInService()
} else {
@ -260,7 +260,7 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
if (emuBound) {
startRunLoopInService()
} else {
// Fallback: lokaler Thread (sollte selten passieren)
// Fallback: local thread (should be rare)
ghLog("Fallback: starting RunLoop in local thread")
_guestThread = thread(start = true, name = "KenjinxGuest") { runGame() }
}
@ -303,7 +303,7 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
KenjinxNative.uiHandlerSetResponse(false, "")
// Emulation im Service stoppen (falls dort gestartet)
// Stop emulation in the service (if started there)
try {
if (emuBound && _startedViaService) {
emuBinder?.stopEmulation {
@ -312,14 +312,14 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
}
} catch (_: Throwable) { }
// Fallback: lokaler Thread beenden
// Fallback: stop local thread
try { _updateThread?.join(200) } catch (_: Throwable) {}
try { _renderingThreadWatcher?.join(200) } catch (_: Throwable) {}
// Bindung lösen
// Unbind
shutdownBinding()
// Service explizit beenden (falls noch läuft)
// Explicitly stop the service (if still running)
try {
mainViewModel.activity.stopService(Intent(mainViewModel.activity, EmulationService::class.java))
} catch (_: Throwable) { }
@ -429,7 +429,7 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
attempts++
// 1 stabiler Tick oder max. 12 Versuche
// One stable tick or max. 12 attempts
if ((stableCount >= 1 || attempts >= 12) && w > 0 && h > 0) {
ghLog("resize stabilized after $attempts ticks → ${w}x$h")
safeSetSize(w, h)

View file

@ -99,7 +99,7 @@ interface KenjinxNativeJna : Library {
fun amiiboLoadBin(bytes: ByteArray, length: Int): Boolean
fun amiiboClear()
// AUDIO (neu): direkte JNA-Brücke zu C#-Exports
// AUDIO (new): direct JNA bridge to C# exports
fun audioSetPaused(paused: Boolean)
fun audioSetMuted(muted: Boolean)
}
@ -115,7 +115,7 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance {
fun loggingSetEnabled(logLevel: LogLevel, enabled: Boolean) =
loggingSetEnabled(logLevel.ordinal, enabled)
// --- Rendering: Single-Thread-Option & sichere Wrapper --------------------
// --- Rendering: single-thread option & safe wrappers --------------------
// 0 = Auto, 1 = SingleThread (Disable Threaded), 2 = Threaded
private const val THREADING_AUTO = 0
@ -142,7 +142,7 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance {
try { jnaInstance.graphicsSetPresentEnabled(enabled) } catch (_: Throwable) { /* ignore */ }
}
// Sichere deviceResize-Implementierung (reines Rendering)
// Safe deviceResize implementation (rendering-only)
override fun deviceResize(width: Int, height: Int) {
try {
graphicsRendererSetSize(width, height)
@ -150,7 +150,7 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance {
} catch (_: Throwable) { /* ignore */ }
}
// Robustes graphicsInitialize mit QCOM-Heuristik + Fallback → SingleThread
// Robust graphicsInitialize with QCOM heuristic + fallback → SingleThread
override fun graphicsInitialize(
rescale: Float,
maxAnisotropy: Float,
@ -165,8 +165,8 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance {
val requested = backendThreading
val isQcom = "qcom".equals(android.os.Build.HARDWARE, true)
// Heuristik: Auf QCOM bei „Auto“ zunächst SingleThread probieren,
// explizit gesetzte Werte bleiben unberührt.
// Heuristic: On QCOM with “Auto”, first try SingleThread;
// explicitly set values remain untouched.
val firstChoice =
if (isQcom && requested == THREADING_AUTO) THREADING_SINGLE else requested
@ -212,7 +212,7 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance {
}
}
// --- optionale Wrapper für Audio (safer logging) ---
// --- optional wrappers for audio (safer logging) ---
override fun audioSetPaused(paused: Boolean) {
try { jnaInstance.audioSetPaused(paused) }
catch (t: Throwable) { Log.w("KenjinxNative", "audioSetPaused unavailable", t) }

View file

@ -60,7 +60,7 @@ class MainActivity : BaseActivity() {
var storageHelper: SimpleStorageHelper? = null
lateinit var uiHandler: UiHandler
// Persistenz für Zombie-Erkennung
// Persistence for zombie detection
private val PREFS = "emu_core"
private val KEY_EMU_RUNNING = "emu_running"
@ -297,7 +297,7 @@ class MainActivity : BaseActivity() {
WindowCompat.setDecorFitsSystemWindows(window, false)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
// Apply alignment
// Apply orientation preference
applyOrientationPreference()
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
@ -361,9 +361,9 @@ class MainActivity : BaseActivity() {
// --- Audio foreground/background gating ---
private fun setAudioForegroundState(inForeground: Boolean) {
// bevorzugt: pausieren statt nur muten
// Prefer: pause instead of just mute
try { KenjinxNative.audioSetPaused(!inForeground) } catch (_: Throwable) {}
// fallback: Master-Mute
// Fallback: master mute
try { KenjinxNative.audioSetMuted(!inForeground) } catch (_: Throwable) {}
}
@ -392,7 +392,7 @@ class MainActivity : BaseActivity() {
setPresentEnabled(false, "onStop")
try { KenjinxNative.detachWindow() } catch (_: Throwable) {}
}
// WICHTIG: Bindung sicher lösen (verhindert Leak)
// IMPORTANT: unbind safely (prevents leak)
try { mainViewModel?.gameHost?.shutdownBinding() } catch (_: Throwable) {}
}
@ -472,7 +472,7 @@ class MainActivity : BaseActivity() {
if (hasFocus && isActive) {
setAudioForegroundState(true)
// NEU: zuerst sicherstellen, dass die Bindung existiert
// NEW: first ensure that the binding exists
try { mainViewModel?.gameHost?.ensureServiceStartedAndBound() } catch (_: Throwable) {}
setPresentEnabled(false, "focus gained → pre-rebind")
@ -506,7 +506,7 @@ class MainActivity : BaseActivity() {
try { displayManager.unregisterDisplayListener(displayListener) } catch (_: Throwable) {}
try { unregisterReceiver(serviceStopReceiver) } catch (_: Throwable) {}
// NEU: Bindung aufräumen (verhindert Leak beim Task-Swipe)
// NEW: clean up binding (prevents leak when swiping away the task)
try { mainViewModel?.gameHost?.shutdownBinding() } catch (_: Throwable) {}
}
@ -617,7 +617,7 @@ class MainActivity : BaseActivity() {
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
val legacyPath = prefs.getString("gameFolder", null)
if (!legacyPath.isNullOrEmpty()) {
// Ohne SAF-URI kein Tree-Listing möglich
// Without a SAF URI, tree listing is not possible
}
return null
}
@ -649,7 +649,7 @@ class MainActivity : BaseActivity() {
override fun onDestroy() {
handler.removeCallbacks(enablePresentWhenReady)
handler.removeCallbacks(reattachWindowWhenReady)
// NEU: falls die Activity stirbt → Bindung garantiert lösen
// NEW: if the activity dies → ensure unbinding
try { mainViewModel?.gameHost?.shutdownBinding() } catch (_: Throwable) {}
super.onDestroy()
}

View file

@ -20,7 +20,7 @@ import java.util.concurrent.Future
import java.util.concurrent.atomic.AtomicBoolean
/**
* Foreground-Service für stabile Emulation im Hintergrund.
* Foreground service for stable emulation in the background.
* Manifest: android:foregroundServiceType="mediaPlayback"
*/
class EmulationService : Service() {
@ -41,7 +41,7 @@ class EmulationService : Service() {
private lateinit var executor: ExecutorService
private var future: Future<*>? = null
private val running = AtomicBoolean(false)
// Nur wenn eine Emulation wirklich lief, dürfen wir nativ „hard close“ machen
// Only if an emulation actually ran, we are allowed to perform a native “hard close”
private val startedOnce = AtomicBoolean(false)
override fun onCreate() {
@ -70,7 +70,7 @@ class EmulationService : Service() {
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
try { future?.cancel(true) } catch (_: Throwable) {}
// Nur schließen, wenn zuvor gestartet
// Only close if it was previously started
hardCloseNativeIfStarted("onTaskRemoved")
running.set(false)
stopForeground(STOP_FOREGROUND_REMOVE)
@ -87,17 +87,17 @@ class EmulationService : Service() {
try { sendBroadcast(Intent(ACTION_STOPPED).setPackage(packageName)) } catch (_: Throwable) {}
}
// ---- Steuerung via Binder ----
// ---- Control via Binder ----
private fun startEmulation(runLoopBlock: () -> Unit) {
// Nur einen RunLoop zulassen
// Allow only a single run loop
if (!running.compareAndSet(false, true)) return
future = executor.submit {
try {
// *** Kein Preflight-HardClose mehr! *** (crasht beim allerersten Start)
// *** No preflight hard-close anymore! *** (crashes on the very first start)
startedOnce.set(true)
runLoopBlock() // blockiert bis Emulation endet
runLoopBlock() // blocks until emulation ends
} finally {
startedOnce.set(false)
running.set(false)
@ -125,12 +125,12 @@ class EmulationService : Service() {
stopSelf()
}
// ---- Native Cleanup nur wenn jemals gestartet ----
// ---- Native cleanup only if it was ever started ----
private fun hardCloseNativeIfStarted(reason: String) {
if (!startedOnce.get()) return
try { KenjinxNative.detachWindow() } catch (_: Throwable) {}
try { KenjinxNative.deviceCloseEmulation() } catch (_: Throwable) {}
// KEIN graphicsSetPresentEnabled(false) hier führt bei kaltem Start zu NRE in VulkanRenderer.ReleaseSurface()
// NO graphicsSetPresentEnabled(false) here — causes NRE in VulkanRenderer.ReleaseSurface() on a cold start
// android.util.Log.d("EmuService", "hardCloseNativeIfStarted: $reason")
}

View file

@ -188,7 +188,7 @@ class MainViewModel(val activity: MainActivity) {
runBlocking {
semaphore.acquire()
launchOnUiThread {
// We are only able to initialize the emulation context on the main thread
// We can only initialize the emulation context on the main thread
val tzId = TimeZone.getDefault().id
success = KenjinxNative.deviceInitialize(
settings.memoryManagerMode.ordinal,
@ -300,7 +300,7 @@ class MainViewModel(val activity: MainActivity) {
runBlocking {
semaphore.acquire()
launchOnUiThread {
// We are only able to initialize the emulation context on the main thread
// We can only initialize the emulation context on the main thread
val tzId = TimeZone.getDefault().id
success = KenjinxNative.deviceInitialize(
settings.memoryManagerMode.ordinal,

View file

@ -957,7 +957,7 @@ namespace LibKenjinx
// ===== PresentAllowed / Surface Control (JNI) =====
// alias für ältere Aufrufe, falls vorhanden
// alias for older calls, if present
[UnmanagedCallersOnly(EntryPoint = "graphicsRendererSetPresent")]
public static void JniGraphicsRendererSetPresent(bool enabled)
{
@ -975,7 +975,7 @@ namespace LibKenjinx
}
}
// neuer Name: passt zu KenjinxNative.graphicsSetPresentEnabled(...)
// new name: matches KenjinxNative.graphicsSetPresentEnabled(...)
[UnmanagedCallersOnly(EntryPoint = "graphicsSetPresentEnabled")]
public static void JniGraphicsSetPresentEnabled(bool enabled)
{
@ -1003,7 +1003,7 @@ namespace LibKenjinx
}
}
// von MainActivity/GameHost benutzt
// used by MainActivity/GameHost
[UnmanagedCallersOnly(EntryPoint = "reattachWindowIfReady")]
public static bool JniReattachWindowIfReady()
{

View file

@ -62,14 +62,14 @@ namespace LibKenjinx
else if (graphicsBackend == GraphicsBackend.Vulkan)
{
// Prefer the platform-provided Vulkan loader (if present), fall back to default.
var api = VulkanLoader?.GetApi() ?? Vk.GetApi();
var api = VulkanLoader?.GetApi() ?? Silk.NET.Vulkan.Vk.GetApi();
Renderer = new VulkanRenderer(
api,
(instance, _) =>
{
// use provided CreateSurface delegate (Android path will create ANativeWindow surface)
return new SurfaceKHR(createSurfaceFunc == null ? null : (ulong?)createSurfaceFunc(instance.Handle));
// Use provided CreateSurface delegate (Android path will create ANativeWindow surface)
return new Silk.NET.Vulkan.SurfaceKHR(createSurfaceFunc == null ? null : (ulong?)createSurfaceFunc(instance.Handle));
},
() => requiredExtensions,
null);
@ -226,7 +226,7 @@ namespace LibKenjinx
_swapBuffersCallback = swapBuffersCallback;
}
// ===== Convenience-Wrapper für Vulkan re-attach (von JNI nutzbar) =====
// ===== Convenience wrapper for Vulkan re-attach (usable from JNI) =====
public static bool TryReattachSurface()
{
if (Renderer is VulkanRenderer vr)

View file

@ -28,7 +28,7 @@ namespace Ryujinx.Graphics.Vulkan
private bool _initialized;
// JNI/Lifecycle-Flag
// JNI / lifecycle flag
internal volatile bool PresentAllowed = true;
public uint ProgramCount { get; set; } = 0;
@ -52,7 +52,7 @@ namespace Ryujinx.Graphics.Vulkan
internal Lock BackgroundQueueLock { get; private set; }
internal Lock QueueLock { get; private set; }
// NEU: SurfaceLock, um Create/Destroy/Queries zu serialisieren
// NEW: SurfaceLock to serialize create/destroy/queries
internal Lock SurfaceLock { get; private set; }
internal MemoryAllocator MemoryAllocator { get; private set; }
@ -506,7 +506,7 @@ namespace Ryujinx.Graphics.Vulkan
Queue = queue;
QueueLock = new();
// Init Locks
// Init locks
SurfaceLock = new();
if (maxQueueCount >= 2)
{
@ -1021,7 +1021,7 @@ namespace Ryujinx.Graphics.Vulkan
return !(IsMoltenVk || IsQualcommProprietary);
}
// ===== Surface/Present Lifecycle helpers =====
// ===== Surface/Present lifecycle helpers =====
public unsafe bool RecreateSurface()
{
@ -1052,7 +1052,7 @@ namespace Ryujinx.Graphics.Vulkan
}
catch
{
// retry später
// retry later
return false;
}
}

View file

@ -43,7 +43,7 @@ namespace Ryujinx.Graphics.Vulkan
private ScalingFilter _currentScalingFilter;
private bool _colorSpacePassthroughEnabled;
// Gate für alle vk*Surface*-Queries
// Gate for all vk*Surface* queries
private volatile bool _allowSurfaceQueries = true;
public unsafe Window(VulkanRenderer gd, SurfaceKHR surface, PhysicalDevice physicalDevice, Device device)
@ -221,7 +221,7 @@ namespace Ryujinx.Graphics.Vulkan
var surfaceFormat = ChooseSwapSurfaceFormat(surfaceFormats, _colorSpacePassthroughEnabled);
var extent = ChooseSwapExtent(capabilities);
// Guard gegen 0x0-Extent direkt nach Resume
// Guard against 0x0 extent right after resume
if (extent.Width == 0 || extent.Height == 0)
{
_swapchainIsDirty = true;
@ -239,10 +239,10 @@ namespace Ryujinx.Graphics.Vulkan
var usage = ImageUsageFlags.ColorAttachmentBit | ImageUsageFlags.TransferDstBit;
if (!PlatformInfo.IsBionic)
{
usage |= ImageUsageFlags.StorageBit; // nur Desktop erlaubt Storage für swapchain
usage |= ImageUsageFlags.StorageBit; // desktop only: allow storage on swapchain
}
// Auf Android: Identity; sonst der vom Treiber empfohlene CurrentTransform
// On Android: use identity; otherwise use the driver-recommended CurrentTransform
var preTransform = PlatformInfo.IsBionic
? SurfaceTransformFlagsKHR.IdentityBitKhr
: capabilities.CurrentTransform;
@ -411,7 +411,7 @@ namespace Ryujinx.Graphics.Vulkan
public unsafe override void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback)
{
// Falls Surface bereits neu ist, Queries aber noch gesperrt → freigeben.
// If the surface is already new but queries are still disabled → re-enable them.
if (!_allowSurfaceQueries && _surface.Handle != 0)
{
_allowSurfaceQueries = true;
@ -423,7 +423,7 @@ namespace Ryujinx.Graphics.Vulkan
return;
}
// Wenn Größe noch nicht da ist, Swapchain später neu aufbauen
// If size is not yet available, rebuild swapchain later
if (_width <= 0 || _height <= 0)
{
RecreateSwapchain();
@ -431,7 +431,7 @@ namespace Ryujinx.Graphics.Vulkan
return;
}
// Lazy-Init/Recovery
// Lazy init / recovery
if (_swapchain.Handle == 0 || _imageAvailableSemaphores == null || _renderFinishedSemaphores == null)
{
try { CreateSwapchain(); } catch { /* try again next frame */ }
@ -473,7 +473,7 @@ namespace Ryujinx.Graphics.Vulkan
}
else if (acquireResult == Result.ErrorSurfaceLostKhr)
{
// Im Hintergrund nicht sofort neu erstellen freigeben und zurück
// In background do not recreate immediately—release and return
_gd.ReleaseSurface();
swapBuffersCallback?.Invoke();
return;
@ -491,13 +491,13 @@ namespace Ryujinx.Graphics.Vulkan
var cbs = _gd.CommandBufferPool.Rent();
// --- Layout/Stages je nach Pfad korrekt setzen ---
bool allowStorageDst = !PlatformInfo.IsBionic; // Android: kein Storage auf Swapchain
// --- Set layout/stages correctly depending on path ---
bool allowStorageDst = !PlatformInfo.IsBionic; // Android: no storage on swapchain
bool useComputeDst = allowStorageDst && _scalingFilter != null;
if (useComputeDst)
{
// Compute schreibt in das Swapchain-Image → General + ShaderWrite
// Compute writes to the swapchain image → General + ShaderWrite
Transition(
cbs.CommandBuffer,
swapchainImage,
@ -510,7 +510,7 @@ namespace Ryujinx.Graphics.Vulkan
}
else
{
// Renderpass schreibt in das Swapchain-Image → ColorAttachmentOptimal
// Render pass writes to the swapchain image → ColorAttachmentOptimal
Transition(
cbs.CommandBuffer,
swapchainImage,
@ -616,7 +616,7 @@ namespace Ryujinx.Graphics.Vulkan
true);
}
// Transition zu Present Stages/Access je nach vorherigem Pfad
// Transition to Present — stages/access depending on previous path
if (useComputeDst)
{
Transition(
@ -643,7 +643,7 @@ namespace Ryujinx.Graphics.Vulkan
}
var waitSems = new Silk.NET.Vulkan.Semaphore[] { _imageAvailableSemaphores[semaphoreIndex] };
var waitStages = new PipelineStageFlags[] { PipelineStageFlags.ColorAttachmentOutputBit }; // wichtig auf Android
var waitStages = new PipelineStageFlags[] { PipelineStageFlags.ColorAttachmentOutputBit }; // important on Android
var signalSems = new Silk.NET.Vulkan.Semaphore[] { _renderFinishedSemaphores[semaphoreIndex] };
_gd.CommandBufferPool.Return(cbs, waitSems, waitStages, signalSems);
@ -835,8 +835,8 @@ namespace Ryujinx.Graphics.Vulkan
// We don't need to use width and height as we can get the size from the surface.
_swapchainIsDirty = true;
// Nach Resume sicherstellen, dass Surface-Queries wieder erlaubt sind,
// falls vorher OnSurfaceLost() das Gate geschlossen hat.
// After resume, ensure surface queries are enabled again
// if OnSurfaceLost() previously closed the gate.
if (_surface.Handle != 0)
{
SetSurfaceQueryAllowed(true);
@ -846,7 +846,7 @@ namespace Ryujinx.Graphics.Vulkan
public override void ChangeVSyncMode(VSyncMode vSyncMode)
{
_vSyncMode = vSyncMode;
//present mode may change, so mark the swapchain for recreation
// Present mode may change, so mark the swapchain for recreation
_swapchainIsDirty = true;
}
@ -904,7 +904,7 @@ namespace Ryujinx.Graphics.Vulkan
{
lock (_gd.SurfaceLock)
{
// harte Aufräumaktion, damit nach Resume nichts „altes“ übrig ist
// Hard cleanup so nothing stale remains after resume
_swapchainIsDirty = true;
SetSurfaceQueryAllowed(false);
@ -953,7 +953,7 @@ namespace Ryujinx.Graphics.Vulkan
}
_surface = new SurfaceKHR(0);
_width = _height = 0; // erzwingt späteren sauberen Recreate-Pfad
_width = _height = 0; // forces a clean recreate path later
}
}