Bios now boots without opening games to fix crashes on some devices

This commit is contained in:
izzy2lost
2025-11-02 00:27:56 -04:00
parent f98decb8f9
commit 5b30d94c1b
6 changed files with 83 additions and 41 deletions
@@ -1457,9 +1457,17 @@ static VkResult VULKAN_FindPhysicalDevice(VULKAN_RenderData *rendererData)
VkPhysicalDevice physicalDevice = physicalDevices[physicalDeviceIndex];
vkGetPhysicalDeviceProperties(physicalDevice, &rendererData->physicalDeviceProperties);
// Accept Vulkan 1.0 and above (was checking for < 1 which would never be true)
// Some devices report 1.0.x which is valid
if (VK_VERSION_MAJOR(rendererData->physicalDeviceProperties.apiVersion) < 1) {
SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "Skipping device with API version < 1.0");
continue;
}
SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "Found device: %s (API version %d.%d.%d)",
rendererData->physicalDeviceProperties.deviceName,
VK_VERSION_MAJOR(rendererData->physicalDeviceProperties.apiVersion),
VK_VERSION_MINOR(rendererData->physicalDeviceProperties.apiVersion),
VK_VERSION_PATCH(rendererData->physicalDeviceProperties.apiVersion));
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &rendererData->physicalDeviceMemoryProperties);
vkGetPhysicalDeviceFeatures(physicalDevice, &rendererData->physicalDeviceFeatures);
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamiliesCount, NULL);
@@ -1507,9 +1515,13 @@ static VkResult VULKAN_FindPhysicalDevice(VULKAN_RenderData *rendererData)
}
if (rendererData->graphicsQueueFamilyIndex == queueFamiliesCount) { // no good queues found
SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "Device %s: No graphics queue found",
rendererData->physicalDeviceProperties.deviceName);
continue;
}
if (rendererData->presentQueueFamilyIndex == queueFamiliesCount) { // no good queues found
SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "Device %s: No present queue found",
rendererData->physicalDeviceProperties.deviceName);
continue;
}
result = vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &deviceExtensionCount, NULL);
@@ -1548,8 +1560,12 @@ static VkResult VULKAN_FindPhysicalDevice(VULKAN_RenderData *rendererData)
}
}
if (!hasSwapchainExtension) {
SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "Device %s: Missing VK_KHR_swapchain extension",
rendererData->physicalDeviceProperties.deviceName);
continue;
}
SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "Device %s: Selected as suitable Vulkan device",
rendererData->physicalDeviceProperties.deviceName);
rendererData->physicalDevice = physicalDevice;
break;
}
@@ -1557,9 +1573,12 @@ static VkResult VULKAN_FindPhysicalDevice(VULKAN_RenderData *rendererData)
SDL_free(queueFamiliesProperties);
SDL_free(deviceExtensions);
if (!rendererData->physicalDevice) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "No viable Vulkan physical devices found. Checked %d device(s).", physicalDeviceCount);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Devices must support: Vulkan 1.0+, VK_KHR_swapchain, graphics queue, and present queue");
SET_ERROR_MESSAGE("No viable physical devices found");
return VK_ERROR_UNKNOWN;
}
SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "Selected Vulkan device: %s", rendererData->physicalDeviceProperties.deviceName);
return VK_SUCCESS;
}
+10
View File
@@ -1172,6 +1172,16 @@ Java_com_izzy2lost_psx2_NativeApp_runVMThread(JNIEnv *env, jclass clazz,
// fast_boot : (false:bios->game, true:game)
VMBootParameters boot_params;
boot_params.filename = _szPath;
// Enable fast boot when booting BIOS-only (no game loaded)
// This skips the BIOS animation and goes straight to the PS2 menu
Console.WriteLn("runVMThread: path='%s', length=%zu", _szPath.c_str(), _szPath.length());
if (_szPath.empty()) {
boot_params.fast_boot = true;
Console.WriteLn("BIOS-only boot: Fast boot ENABLED to skip animation");
} else {
Console.WriteLn("Game boot: path=%s, fast_boot will use default behavior", _szPath.c_str());
}
// Apply per-game settings (if any) before applying core settings
ApplyPerGameSettingsForPath(_szPath);
+12 -2
View File
@@ -1406,10 +1406,20 @@ bool VMManager::Initialize(VMBootParameters boot_params)
// Read fast boot setting late so it can be overridden per-game.
// ELFs must be fast booted, and GS dumps are never fast booted.
// Allow fast boot for BIOS-only boots if explicitly requested via boot_params
const bool has_disc = (CDVDsys_GetSourceType() != CDVD_SourceType::NoDisc);
const bool has_elf = !s_elf_override.empty();
const bool fast_boot_requested = boot_params.fast_boot.value_or(static_cast<bool>(EmuConfig.EnableFastBoot));
Console.WriteLn("VMManager::Initialize - Fast boot check: has_disc=%d, has_elf=%d, fast_boot_requested=%d",
has_disc, has_elf, fast_boot_requested);
s_fast_boot_requested =
(boot_params.fast_boot.value_or(static_cast<bool>(EmuConfig.EnableFastBoot)) || !s_elf_override.empty()) &&
(CDVDsys_GetSourceType() != CDVD_SourceType::NoDisc || !s_elf_override.empty()) &&
(fast_boot_requested || has_elf) &&
(has_disc || has_elf || fast_boot_requested) && // Allow fast boot for BIOS-only if explicitly requested
!GSDumpReplayer::IsReplayingDump();
Console.WriteLn("VMManager::Initialize - s_fast_boot_requested=%d", s_fast_boot_requested);
if (!s_elf_override.empty())
{
+12
View File
@@ -328,6 +328,18 @@ bool LoadBIOS()
return false;
}
// Check if BIOS is already loaded and matches the current path
// This avoids reloading the same BIOS file on every game launch
if (!BiosRom.empty() && !BiosPath.empty() && BiosPath == path)
{
Console.WriteLn("BIOS already loaded from cache: %s", path.c_str());
// Just copy the cached BIOS to memory instead of reloading from disk
CopyBIOSToMemory();
return true;
}
Console.WriteLn("Loading BIOS from disk: %s", path.c_str());
auto fp = FileSystem::OpenManagedCFile(path.c_str(), "rb");
if (!fp)
return false;
@@ -496,20 +496,13 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
f.setCancelable(false);
f.show(getSupportFragmentManager(), "setup_wizard");
} else {
// Only auto-open games dialog if this is NOT the first boot after setup
// (Setup wizard handles opening the games dialog on first completion)
// Don't auto-open games dialog on app start
// User can open it manually via home button or controller
// This prevents crashes on devices where BIOS boot + dialog opening is too much at once
boolean hasOpenedGamesAfterSetup = prefs.getBoolean("has_opened_games_after_setup", false);
if (hasOpenedGamesAfterSetup) {
try {
final View decor = (getWindow() != null) ? getWindow().getDecorView() : null;
if (decor != null) {
decor.postDelayed(() -> {
if (!isFinishing() && !mSetupWizardActive) {
openGamesDialog();
}
}, 1600); // small delay to let BIOS boot briefly
}
} catch (Throwable ignored) {}
if (!hasOpenedGamesAfterSetup) {
// Mark as opened so we don't show this message again
prefs.edit().putBoolean("has_opened_games_after_setup", true).apply();
}
}
@@ -574,6 +567,17 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
if (btn_settings != null) {
btn_settings.setOnClickListener(v -> {
try {
// Pause the emulation (BIOS or game) before opening drawer
// This prevents crashes on some devices when drawer opens during emulation
if (isThread() && !NativeApp.isPaused()) {
try {
NativeApp.pause();
android.util.Log.d("MainActivity", "Paused emulation before opening drawer");
} catch (Throwable e) {
android.util.Log.e("MainActivity", "Error pausing before drawer open: " + e.getMessage());
}
}
// Open the drawer via post() to avoid reentrancy/layout timing issues
// (programmatic open can sometimes race with layout/insets handling)
DrawerLayout drawer = findViewById(R.id.drawer_layout);
@@ -2501,20 +2505,21 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
mDrawerOpen = false;
android.util.Log.d("DrawerTracking", "Drawer closed. Dialog count: " + mOpenDialogCount);
if (mOpenDialogCount == 0 && !mDrawerOpen) {
// All dialogs closed and no drawers open, resume the game with a small delay
// All dialogs closed and no drawers open, resume the emulation (game or BIOS) with a small delay
View root = findViewById(android.R.id.content);
if (root != null) {
root.postDelayed(() -> {
try {
if (hasSelectedGame() && isThread() && NativeApp.isPaused()) {
android.util.Log.d("DrawerTracking", "Resuming game on drawer close");
// Resume if emulation thread is running and paused (works for both game and BIOS)
if (isThread() && NativeApp.isPaused()) {
android.util.Log.d("DrawerTracking", "Resuming emulation on drawer close");
NativeApp.resume();
updatePausePlayButton();
} else {
android.util.Log.d("DrawerTracking", "Not resuming - hasGame: " + hasSelectedGame() + ", isThread: " + isThread() + ", isPaused: " + (isThread() ? NativeApp.isPaused() : "N/A"));
android.util.Log.d("DrawerTracking", "Not resuming - isThread: " + isThread() + ", isPaused: " + (isThread() ? NativeApp.isPaused() : "N/A"));
}
} catch (Throwable e) {
android.util.Log.e("DrawerTracking", "Error resuming game: " + e.getMessage());
android.util.Log.e("DrawerTracking", "Error resuming emulation: " + e.getMessage());
}
}, 100); // Small delay to let drawer fully close
}
@@ -197,20 +197,10 @@ public class SetupWizardDialogFragment extends DialogFragment {
dismissAllowingStateLoss();
if (a != null) {
// Use adaptive delay based on device capabilities
long manualDelay = getTimeoutForDevice(2000, 4000); // 2s normal, 4s lower-end
android.util.Log.d("SetupWizard", "Using manual delay: " + manualDelay + "ms");
final MainActivity act = a;
View decor = act.getWindow() != null ? act.getWindow().getDecorView() : null;
if (decor != null) {
decor.postDelayed(() -> {
act.openGamesDialog();
}, manualDelay);
} else {
act.runOnUiThread(() -> {
act.openGamesDialog();
});
}
// Don't auto-open games dialog after setup wizard
// This prevents crashes when BIOS is still booting
// User can open it manually via home button when ready
android.util.Log.d("SetupWizard", "Setup complete - user can open games dialog via home button");
}
}
});
@@ -389,13 +379,9 @@ public class SetupWizardDialogFragment extends DialogFragment {
MainActivity a = (MainActivity) requireActivity();
a.setSetupWizardActive(false);
dismissAllowingStateLoss();
// Add adaptive delay before opening games dialog
View mainDecor = a.getWindow() != null ? a.getWindow().getDecorView() : null;
if (mainDecor != null) {
mainDecor.postDelayed(() -> {
a.openGamesDialog();
}, gamesDialogDelay);
}
// Don't auto-open games dialog after setup wizard
// This prevents crashes when BIOS is still booting
// User can open it manually via home button when ready
} catch (Throwable ignored) {}
}, autoAdvanceDelay);
}