From 33b557e68b33ff34820fdb6a316305e2cd277a26 Mon Sep 17 00:00:00 2001 From: "Skyth (Asilkan)" <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Fri, 28 Mar 2025 22:38:07 +0300 Subject: [PATCH] Check if the 4 GB memory allocation failed. (#1459) * Check if the 4 GB memory allocation failed. * Update UnleashedRecomp/locale/locale.cpp Co-authored-by: Hyper <34012267+hyperbx@users.noreply.github.com> * Update locale.cpp * Add localizations. * Fix installer not booting with the changes. * Fix stale reference crash. --------- Co-authored-by: Hyper <34012267+hyperbx@users.noreply.github.com> --- UnleashedRecomp/gpu/video.cpp | 17 ++++++++++++++++- UnleashedRecomp/kernel/memory.cpp | 6 ++++++ UnleashedRecomp/locale/locale.cpp | 11 +++++++++++ UnleashedRecomp/main.cpp | 10 ++++++++-- 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index 2b693adb..6028de94 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -322,6 +322,7 @@ static constexpr RenderFormat BACKBUFFER_FORMAT = RenderFormat::B8G8R8A8_UNORM; static std::unique_ptr g_acquireSemaphores[NUM_FRAMES]; static std::unique_ptr g_renderSemaphores[NUM_FRAMES]; static uint32_t g_backBufferIndex; +static std::unique_ptr g_backBufferHolder; static GuestSurface* g_backBuffer; static std::unique_ptr g_intermediaryBackBufferTexture; @@ -1968,7 +1969,10 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver) desc.renderTargetCount = 1; g_gammaCorrectionPipeline = g_device->createGraphicsPipeline(desc); - g_backBuffer = g_userHeap.AllocPhysical(ResourceType::RenderTarget); + // NOTE: We initially allocate this on host memory to make the installer work, even if the 4 GB memory allocation fails. + g_backBufferHolder = std::make_unique(ResourceType::RenderTarget); + + g_backBuffer = g_backBufferHolder.get(); g_backBuffer->width = 1280; g_backBuffer->height = 720; g_backBuffer->format = BACKBUFFER_FORMAT; @@ -2026,6 +2030,17 @@ static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, LoadTexture((uint8_t *)achievement.pImageBuffer, achievement.ImageBufferSize).release(); } + // Move backbuffer to guest memory. + assert(!g_memory.IsInMemoryRange(g_backBuffer) && g_backBufferHolder != nullptr); + g_backBuffer = g_userHeap.AllocPhysical(std::move(*g_backBufferHolder)); + + // Check for stale reference. BeginCommandList() gets called before CreateDevice() which is where the assignment happens. + if (g_renderTarget == g_backBufferHolder.get()) g_renderTarget = g_backBuffer; + if (g_depthStencil == g_backBufferHolder.get()) g_depthStencil = g_backBuffer; + + // Free the host backbuffer. + g_backBufferHolder = nullptr; + auto device = g_userHeap.AllocPhysical(); memset(device, 0, sizeof(*device)); diff --git a/UnleashedRecomp/kernel/memory.cpp b/UnleashedRecomp/kernel/memory.cpp index c2aa18a2..a52b7e7a 100644 --- a/UnleashedRecomp/kernel/memory.cpp +++ b/UnleashedRecomp/kernel/memory.cpp @@ -9,6 +9,9 @@ Memory::Memory() if (base == nullptr) base = (uint8_t*)VirtualAlloc(nullptr, PPC_MEMORY_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if (base == nullptr) + return; + DWORD oldProtect; VirtualProtect(base, 4096, PAGE_NOACCESS, &oldProtect); #else @@ -17,6 +20,9 @@ Memory::Memory() if (base == (uint8_t*)MAP_FAILED) base = (uint8_t*)mmap(NULL, PPC_MEMORY_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (base == nullptr) + return; + mprotect(base, 4096, PROT_NONE); #endif diff --git a/UnleashedRecomp/locale/locale.cpp b/UnleashedRecomp/locale/locale.cpp index 8d1e74d1..27bf6f22 100644 --- a/UnleashedRecomp/locale/locale.cpp +++ b/UnleashedRecomp/locale/locale.cpp @@ -703,6 +703,17 @@ std::unordered_map> { ELanguage::Italian, "Impossibile trovare il modulo \"%s\".\n\nAssicurati che:\n\n- Hai estratto questa copia di Unleashed Recompiled correttamente e non solo il file *.exe.\n- Non stai eseguendo Unleashed Recompiled da un file *.zip." } } }, + { + "System_MemoryAllocationFailed", + { + { ELanguage::English, "Failed to allocate game memory.\n\nPlease make sure that:\n\n- You meet the minimum system requirements (8 GB).\n- Your page file is configured with at least 4-8 GB of virtual memory." }, + { ELanguage::Japanese, "ゲームメモリの割り当てに失敗しました\n\n次の点を確認してください:\n\n※最小システム要件(8 GB)を満たしていること。\n※ページファイルに少なくとも4~8 GBの仮想メモリが設定されていること" }, + { ELanguage::German, "Fehler beim Zuweisen des Spielspeichers.\n\nBitte stelle sicher, dass:\n\n- Die Mindestanforderungen für das System erfüllt sind (8 GB).\n- Die Auslagerungsdatei mit mindestens 4-8 GB virtuellem Speicher konfiguriert ist." }, + { ELanguage::French, "Échec d'allocation de la mémoire du jeu.\n\nVeuillez vous assurer que :\n\n- Vous disposez de la configuration minimale requise (8 Go).\n- Votre fichier d’échange est configuré avec au moins 4 à 8 Go de mémoire virtuelle." }, + { ELanguage::Spanish, "Fallo al asignar memoria del juego.\n\nPor favor, asegúrate de que:\n\n- Cumples los requisitos mínimos del sistema (8 GB).\n- Tu archivo de páginación está configurado con al menos 4 u 8 GB de memoria virtual." }, + { ELanguage::Italian, "Impossibile allocare la memoria per il gioco.\n\nAssicurati che:\n\n- Soddisfi i requisiti minimi di sistema (8 GB).\n- Il tuo file di paging sia configurato con almeno 4 o 8 GB di memoria virtuale." } + } + }, { "IntegrityCheck_Success", { diff --git a/UnleashedRecomp/main.cpp b/UnleashedRecomp/main.cpp index 3c73f93d..7cf07475 100644 --- a/UnleashedRecomp/main.cpp +++ b/UnleashedRecomp/main.cpp @@ -53,14 +53,20 @@ void HostStartup() CoInitializeEx(nullptr, COINIT_MULTITHREADED); #endif - g_userHeap.Init(); - hid::Init(); } // Name inspired from nt's entry point void KiSystemStartup() { + if (g_memory.base == nullptr) + { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("System_MemoryAllocationFailed").c_str(), GameWindow::s_pWindow); + std::_Exit(1); + } + + g_userHeap.Init(); + const auto gameContent = XamMakeContent(XCONTENTTYPE_RESERVED, "Game"); const auto updateContent = XamMakeContent(XCONTENTTYPE_RESERVED, "Update"); XamRegisterContent(gameContent, GAME_INSTALL_DIRECTORY "/game");