diff --git a/dependencies/vcpkg b/dependencies/vcpkg index c3867e71..9849e070 160000 --- a/dependencies/vcpkg +++ b/dependencies/vcpkg @@ -1 +1 @@ -Subproject commit c3867e714dd3a51c272826eea77267876517ed99 +Subproject commit 9849e070ad4c3383890fb1c80ae0c54325e2484a diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index fc0d1ae6..096d90f4 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -165,7 +165,7 @@ void LoadMainExecutable() else { // RPX - RPLLoader_AddDependency(_pathToExecutable.c_str()); + RPLLoader_AddDependency(_pathToExecutable.c_str(), true); applicationRPX = RPLLoader_LoadFromMemory(rpxData, rpxSize, (char*)_pathToExecutable.c_str()); if (!applicationRPX) { diff --git a/src/Cafe/GraphicPack/GraphicPack2PatchesApply.cpp b/src/Cafe/GraphicPack/GraphicPack2PatchesApply.cpp index 5b3f53dc..00080022 100644 --- a/src/Cafe/GraphicPack/GraphicPack2PatchesApply.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2PatchesApply.cpp @@ -420,7 +420,7 @@ void PatchEntryInstruction::undoPatch() uint8* patchAddr = (uint8*)memory_base + addr; memcpy(patchAddr, m_dataBackup, m_length); PPCRecompiler_invalidateRange(addr, addr + m_length); - rplSymbolStorage_removeRange(addr, m_length); + rplSymbolStorage_removeRange(addr, m_length, RPL_STORED_SYMBOL_PATCH); DebugSymbolStorage::ClearRange(addr, m_length); } @@ -434,7 +434,7 @@ bool registerU32Variable(PatchContext_t& ctx, std::string& name, uint32 value, P } ctx.map_values[name] = value; // keep track of address symbols for the debugger - rplSymbolStorage_store(ctx.graphicPack->GetName().data(), name.data(), value); + rplSymbolStorage_store(ctx.graphicPack->GetName().data(), name.data(), value, RPL_STORED_SYMBOL_PATCH); return true; } @@ -688,7 +688,7 @@ void GraphicPack2::UndoPatchGroups(std::vector& groups, const RPLMo void GraphicPack2::NotifyModuleLoaded(const RPLModule* rpl) { - cemuLog_log(LogType::Force, "Loaded module \'{}\' with checksum 0x{:08x}", rpl->moduleName2, rpl->patchCRC); + cemuLog_log(LogType::Force, "Loaded module \'{}\' with checksum 0x{:08x}", rpl->moduleName, rpl->patchCRC); std::lock_guard lock(mtx_patches); list_modules.emplace_back(rpl); diff --git a/src/Cafe/HW/Espresso/Debugger/Debugger.cpp b/src/Cafe/HW/Espresso/Debugger/Debugger.cpp index e4a22387..3670cc1e 100644 --- a/src/Cafe/HW/Espresso/Debugger/Debugger.cpp +++ b/src/Cafe/HW/Espresso/Debugger/Debugger.cpp @@ -756,7 +756,7 @@ void debugger_addParserSymbols(class ExpressionParser& ep) if (module) { moduleTmp[i] = (double)module->regionMappingBase_text.GetMPTR(); - ep.AddConstant(module->moduleName2, moduleTmp[i]); + ep.AddConstant(module->moduleName, moduleTmp[i]); } } PPCInterpreter_t* hCPU = debugger_lockDebugSession(); diff --git a/src/Cafe/HW/Espresso/Debugger/GDBStub.cpp b/src/Cafe/HW/Espresso/Debugger/GDBStub.cpp index e7cb2257..bb584f0a 100644 --- a/src/Cafe/HW/Espresso/Debugger/GDBStub.cpp +++ b/src/Cafe/HW/Espresso/Debugger/GDBStub.cpp @@ -556,7 +556,7 @@ void GDBServer::HandleQuery(std::unique_ptr& context) const const auto module_list = RPLLoader_GetModuleList(); for (sint32 i = 0; i < module_count; i++) { - library_list += fmt::format(R"()", CommandContext::EscapeXMLString(module_list[i]->moduleName2), module_list[i]->regionMappingBase_text.GetMPTR()); + library_list += fmt::format(R"()", CommandContext::EscapeXMLString(module_list[i]->moduleName), module_list[i]->regionMappingBase_text.GetMPTR()); } library_list += ""; diff --git a/src/Cafe/HW/Latte/Core/LatteTextureReadback.cpp b/src/Cafe/HW/Latte/Core/LatteTextureReadback.cpp index a6690a3f..003360b6 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureReadback.cpp +++ b/src/Cafe/HW/Latte/Core/LatteTextureReadback.cpp @@ -21,6 +21,8 @@ void LatteTextureReadback_StartTransfer(LatteTextureView* textureView) HRTick currentTick = HighResolutionTimer().now().getTick(); // create info entry and store in ordered linked list LatteTextureReadbackInfo* readbackInfo = g_renderer->texture_createReadback(textureView); + if (!readbackInfo) + return; sTextureActiveReadbackQueue.push(readbackInfo); readbackInfo->StartTransfer(); readbackInfo->transferStartTime = currentTick; diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSLHeader.hpp b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSLHeader.hpp index add25195..0c98418a 100644 --- a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSLHeader.hpp +++ b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSLHeader.hpp @@ -243,7 +243,7 @@ namespace LatteDecompiler cemu_assert_debug(decompilerContext->output->resourceMappingVK.attributeMapping[i] >= 0); cemu_assert_debug(decompilerContext->output->resourceMappingGL.attributeMapping[i] == decompilerContext->output->resourceMappingVK.attributeMapping[i]); - shaderSrc->addFmt("ATTR_LAYOUT({}, {}) in uvec4 attrDataSem{};" _CRLF, (sint32)decompilerContext->output->resourceMappingVK.setIndex, (sint32)decompilerContext->output->resourceMappingVK.attributeMapping[i], i); + shaderSrc->addFmt("ATTR_LAYOUT({}) in uvec4 attrDataSem{};" _CRLF, (sint32)decompilerContext->output->resourceMappingVK.attributeMapping[i], i); } } } @@ -255,7 +255,7 @@ namespace LatteDecompiler // OpenGL/Vulkan ifdefs src->add("#ifdef VULKAN" _CRLF); // Vulkan defines - src->add("#define ATTR_LAYOUT(__vkSet, __location) layout(set = __vkSet, location = __location)" _CRLF); + src->add("#define ATTR_LAYOUT(__location) layout(location = __location)" _CRLF); src->add("#define UNIFORM_BUFFER_LAYOUT(__glLocation, __vkSet, __vkLocation) layout(set = __vkSet, binding = __vkLocation, std140)" _CRLF); src->add("#define TEXTURE_LAYOUT(__glLocation, __vkSet, __vkLocation) layout(set = __vkSet, binding = __vkLocation)" _CRLF); if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry) @@ -293,7 +293,7 @@ namespace LatteDecompiler } src->add("#else" _CRLF); // OpenGL defines - src->add("#define ATTR_LAYOUT(__vkSet, __location) layout(location = __location)" _CRLF); + src->add("#define ATTR_LAYOUT(__location) layout(location = __location)" _CRLF); src->add("#define UNIFORM_BUFFER_LAYOUT(__glLocation, __vkSet, __vkLocation) layout(binding = __glLocation, std140) " _CRLF); src->add("#define TEXTURE_LAYOUT(__glLocation, __vkSet, __vkLocation) layout(binding = __glLocation)" _CRLF); if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry) diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h index e670cbd1..c44a7b1c 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h @@ -192,11 +192,6 @@ VKFUNC_DEVICE(vkCmdEndRenderingKHR); // khr_present_wait VKFUNC_DEVICE(vkWaitForPresentKHR); -// transform feedback extension -VKFUNC_DEVICE(vkCmdBindTransformFeedbackBuffersEXT); -VKFUNC_DEVICE(vkCmdBeginTransformFeedbackEXT); -VKFUNC_DEVICE(vkCmdEndTransformFeedbackEXT); - // query VKFUNC_DEVICE(vkCreateQueryPool); VKFUNC_DEVICE(vkDestroyQueryPool); diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index fe2a1e4d..b4d99e35 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -646,10 +646,7 @@ VulkanRenderer::VulkanRenderer() deviceFeatures.robustBufferAccess = VK_TRUE; } - if (m_featureControl.mode.useTFEmulationViaSSBO) - { - deviceFeatures.vertexPipelineStoresAndAtomics = true; - } + deviceFeatures.vertexPipelineStoresAndAtomics = true; void* deviceExtensionFeatures = nullptr; @@ -787,7 +784,8 @@ VulkanRenderer::VulkanRenderer() m_textureReadbackBufferPtr = (uint8*)bufferPtr; // transform feedback ringbuffer - memoryManager->CreateBuffer(LatteStreamout_GetRingBufferSize(), VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | (m_featureControl.mode.useTFEmulationViaSSBO ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : 0), 0, m_xfbRingBuffer, m_xfbRingBufferMemory); + VkBufferUsageFlags xfbRingBufferUsage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + memoryManager->CreateBuffer(LatteStreamout_GetRingBufferSize(), xfbRingBufferUsage, 0, m_xfbRingBuffer, m_xfbRingBufferMemory); // occlusion query result buffer if (!memoryManager->CreateBuffer(OCCLUSION_QUERY_POOL_SIZE * sizeof(uint64), VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_occlusionQueries.bufferQueryResults, m_occlusionQueries.memoryQueryResults)) @@ -1367,7 +1365,6 @@ bool VulkanRenderer::CheckDeviceExtensionSupport(const VkPhysicalDevice device, } info.deviceExtensions.tooling_info = isExtensionAvailable(VK_EXT_TOOLING_INFO_EXTENSION_NAME); - info.deviceExtensions.transform_feedback = isExtensionAvailable(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME); info.deviceExtensions.depth_range_unrestricted = isExtensionAvailable(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME); info.deviceExtensions.nv_fill_rectangle = isExtensionAvailable(VK_NV_FILL_RECTANGLE_EXTENSION_NAME); info.deviceExtensions.pipeline_feedback = isExtensionAvailable(VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME); @@ -3673,14 +3670,14 @@ void VulkanRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, LatteTextureReadbackInfo* VulkanRenderer::texture_createReadback(LatteTextureView* textureView) { auto* result = new LatteTextureReadbackInfoVk(m_logicalDevice, textureView); - - LatteTextureVk* vkTex = (LatteTextureVk*)textureView->baseTexture; - - VkMemoryRequirements memRequirements; - vkGetImageMemoryRequirements(m_logicalDevice, vkTex->GetImageObj()->m_image, &memRequirements); - const uint32 linearImageSize = result->GetImageSize(); - const uint32 uploadSize = (linearImageSize == 0) ? memRequirements.size : linearImageSize; + if (linearImageSize == 0) + { + delete result; + return nullptr; + } + + const uint32 uploadSize = linearImageSize; const uint32 uploadAlignment = 256; // todo - use Vk optimalBufferCopyOffsetAlignment m_textureReadbackBufferWriteIndex = (m_textureReadbackBufferWriteIndex + uploadAlignment - 1) & ~(uploadAlignment - 1); @@ -3714,46 +3711,14 @@ void VulkanRenderer::streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBuf void VulkanRenderer::streamout_begin() { - if (m_featureControl.mode.useTFEmulationViaSSBO) - return; - if (m_state.hasActiveXfb == false) - m_state.hasActiveXfb = true; -} - -void VulkanRenderer::streamout_applyTransformFeedbackState() -{ - if (m_featureControl.mode.useTFEmulationViaSSBO) - return; - cemu_assert_debug(m_state.hasActiveXfb == false); - if (m_state.hasActiveXfb) - { - // set buffers - for (sint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++) - { - if (m_streamoutState.buffer[i].enabled) - { - VkBuffer tfBuffer = m_xfbRingBuffer; - VkDeviceSize tfBufferOffset = m_streamoutState.buffer[i].ringBufferOffset; - VkDeviceSize tfBufferSize = VK_WHOLE_SIZE; - vkCmdBindTransformFeedbackBuffersEXT(m_state.currentCommandBuffer, i, 1, &tfBuffer, &tfBufferOffset, &tfBufferSize); - } - } - // begin transform feedback - vkCmdBeginTransformFeedbackEXT(m_state.currentCommandBuffer, 0, 0, nullptr, nullptr); - } } void VulkanRenderer::streamout_rendererFinishDrawcall() { - if (m_state.hasActiveXfb) - { - vkCmdEndTransformFeedbackEXT(m_state.currentCommandBuffer, 0, 0, nullptr, nullptr); - m_streamoutState.buffer[0].enabled = false; - m_streamoutState.buffer[1].enabled = false; - m_streamoutState.buffer[2].enabled = false; - m_streamoutState.buffer[3].enabled = false; - m_state.hasActiveXfb = false; - } + m_streamoutState.buffer[0].enabled = false; + m_streamoutState.buffer[1].enabled = false; + m_streamoutState.buffer[2].enabled = false; + m_streamoutState.buffer[3].enabled = false; } diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h index 2c7af53b..62ecd797 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h @@ -380,9 +380,6 @@ private: uint32 offset; }currentVertexBinding[LATTE_MAX_VERTEX_BUFFERS]{}; - // transform feedback - bool hasActiveXfb{}; - // index buffer Renderer::INDEX_TYPE activeIndexType{}; uint32 activeIndexBufferIndex{}; @@ -442,7 +439,6 @@ private: { // if using new optional extensions add to CheckDeviceExtensionSupport and CreateDeviceCreateInfo bool tooling_info = false; // VK_EXT_tooling_info - bool transform_feedback = false; bool depth_range_unrestricted = false; bool nv_fill_rectangle = false; // NV_fill_rectangle bool pipeline_feedback = false; @@ -470,11 +466,6 @@ private: bool debug_utils = false; // VK_EXT_DEBUG_UTILS }instanceExtensions; - struct - { - bool useTFEmulationViaSSBO = true; // emulate transform feedback via shader writes to a storage buffer - }mode; - struct { uint32 minUniformBufferOffsetAlignment = 256; @@ -521,7 +512,10 @@ private: void DeleteFontTextures() override; bool BeginFrame(bool mainWindow) override; - bool UseTFViaSSBO() const override { return m_featureControl.mode.useTFEmulationViaSSBO; } + bool UseTFViaSSBO() const override + { + return true; + } // drawcall emulation PipelineInfo* draw_createGraphicsPipeline(uint32 indexCount); @@ -567,7 +561,6 @@ private: // streamout void streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) override; void streamout_begin() override; - void streamout_applyTransformFeedbackState(); void bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size) override; void streamout_rendererFinishDrawcall() override; diff --git a/src/Cafe/OS/RPL/rpl.cpp b/src/Cafe/OS/RPL/rpl.cpp index b906b6b1..19455e4e 100644 --- a/src/Cafe/OS/RPL/rpl.cpp +++ b/src/Cafe/OS/RPL/rpl.cpp @@ -5,7 +5,6 @@ #include "Cafe/OS/RPL/rpl.h" #include "Cafe/OS/RPL/rpl_structs.h" #include "Cafe/OS/RPL/rpl_symbol_storage.h" -#include "util/VirtualHeap/VirtualHeap.h" #include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h" #include "Cafe/HW/Espresso/Debugger/Debugger.h" #include "Cafe/GraphicPack/GraphicPack2.h" @@ -272,10 +271,7 @@ bool RPLLoader_ProcessHeaders(std::string_view moduleName, uint8* rplData, uint3 // init section address table rplLoaderContext->sectionAddressTable2.resize(sectionCount); // init modulename - rplLoaderContext->moduleName2.assign(moduleName); - // convert modulename to lower-case - for(auto& c : rplLoaderContext->moduleName2) - c = _ansiToLower(c); + rplLoaderContext->moduleName.assign(moduleName); // load CRC section uint32 crcTableExpectedSize = sectionCount * sizeof(uint32be); @@ -525,7 +521,7 @@ bool RPLLoader_LoadSections(sint32 aProcId, RPLModule* rplLoaderContext) PPCRecompiler_allocateRange(rplLoaderContext->regionMappingBase_text.GetMPTR(), regionTextSize + 0x1000); // workaround for DKC Tropical Freeze - if (boost::iequals(rplLoaderContext->moduleName2, "rs10_production")) + if (rplLoaderContext->moduleName == "rs10_production") { // allocate additional 12MB of unused data to get below a size of 0x3E200000 for the main ExpHeap // otherwise the game will assume it's running on a Devkit unit with 2GB of RAM and subtract 1GB from available space @@ -536,6 +532,10 @@ bool RPLLoader_LoadSections(sint32 aProcId, RPLModule* rplLoaderContext) rplLoaderContext->regionSize_loaderInfo = regionLoaderinfoSize; rplLoaderContext->regionSize_text = regionTextSize; + // set original base addresses + rplLoaderContext->regionOrigAddr_text = regionMappingTable.region[RPL_MAPPING_REGION_TEXT].baseAddress; + rplLoaderContext->regionOrigAddr_data = regionMappingTable.region[RPL_MAPPING_REGION_DATA].baseAddress; + // load data sections for (sint32 i = 0; i < (sint32)rplLoaderContext->rplHeader.sectionTableEntryCount; i++) { @@ -844,7 +844,7 @@ MPTR _findHLEExport(RPLModule* rplLoaderContext, RPLSharedImportTracking* shared MPTR weakExportAddr = osLib_getPointer(libname, symbolName); if (weakExportAddr != 0xFFFFFFFF) return weakExportAddr; - cemuLog_logDebug(LogType::Force, "Unsupported data export ({}): {}.{}", rplLoaderContext->moduleName2, libname, symbolName); + cemuLog_logDebug(LogType::Force, "Unsupported data export ({}): {}.{}", rplLoaderContext->moduleName, libname, symbolName); return MPTR_NULL; } else @@ -1281,7 +1281,7 @@ bool RPLLoader_ApplyRelocs(RPLModule* rplLoaderContext, sint32 relaSectionIndex, uint32 crc = rplLoaderContext->GetSectionCRC(relaSectionIndex); if (calcCRC != crc) { - cemuLog_log(LogType::Force, "RPLLoader {} - Relocation section {} has CRC mismatch - Calc: {:08x} Actual: {:08x}", rplLoaderContext->moduleName2.c_str(), relaSectionIndex, calcCRC, crc); + cemuLog_log(LogType::Force, "RPLLoader {} - Relocation section {} has CRC mismatch - Calc: {:08x} Actual: {:08x}", rplLoaderContext->moduleName.c_str(), relaSectionIndex, calcCRC, crc); } // process relocations sint32 relocCount = relocSize / sizeof(rplRelocNew_t); @@ -1379,7 +1379,7 @@ bool RPLLoader_HandleRelocs(RPLModule* rplLoaderContext, std::span(nameLen, RPL_MODULE_NAME_LENGTH-1); - memcpy(output, input.data() + startIndex, nameLen); - output[nameLen] = '\0'; + std::string output; + output.append(input.data() + startIndex, nameLen); // convert to lower case - std::for_each(output, output + nameLen, [](char& c) {c = _ansiToLower(c);}); + std::for_each(output.begin(), output.end(), [](char& c) {c = _ansiToLower(c);}); + return output; } void RPLLoader_InitState() @@ -1581,8 +1582,7 @@ void RPLLoader_InitModuleAllocator(RPLModule* rpl) // map rpl into memory, but do not resolve relocs and imports yet RPLModule* RPLLoader_LoadFromMemory(uint8* rplData, sint32 size, std::string_view name) { - char moduleName[RPL_MODULE_NAME_LENGTH]; - _RPLLoader_ExtractModuleNameFromPath(moduleName, name); + std::string moduleName = _RPLLoader_ExtractModuleNameFromPath(name); RPLModule* rpl = nullptr; if (RPLLoader_ProcessHeaders({ moduleName }, rplData, size, &rpl) == false) { @@ -1596,9 +1596,7 @@ RPLModule* RPLLoader_LoadFromMemory(uint8* rplData, sint32 size, std::string_vie delete rpl; return nullptr; } - cemuLog_logDebug(LogType::Force, "Load {} Code-Offset: -0x{:x}", name, rpl->regionMappingBase_text.GetMPTR() - 0x02000000); - // sdata (r2/r13) uint32 sdataBaseAddress = rpl->fileInfo.sdataBase1; // base + 0x8000 uint32 sdataBaseAddress2 = rpl->fileInfo.sdataBase2; // base + 0x8000 @@ -1693,16 +1691,14 @@ void RPLLoader_LinkSingleModule(RPLModule* rplLoaderContext, bool resolveOnlyExp { if( rplLoaderContext->sectionTablePtr[i].type != (uint32be)SHT_RPL_IMPORTS ) continue; + cemu_assert(rplLoaderContext->sectionTablePtr[i].sectionSize >= 9); char* libName = (char*)((uint8*)rplLoaderContext->sectionAddressTable2[i].ptr + 8); // make module name - char _importModuleName[RPL_MODULE_NAME_LENGTH]; - _RPLLoader_ExtractModuleNameFromPath(_importModuleName, libName); - // find in loaded module list - std::string importModuleName{_importModuleName}; + std::string importModuleName = _RPLLoader_ExtractModuleNameFromPath(libName); bool foundModule = false; for (sint32 f = 0; f < rplModuleCount; f++) { - if (boost::iequals(rplModuleList[f]->moduleName2, importModuleName)) + if (rplModuleList[f]->moduleName == importModuleName) { sharedImportTracking[i].rplLoaderContext = rplModuleList[f]; memset(sharedImportTracking[i].modulename, 0, sizeof(sharedImportTracking[i].modulename)); @@ -1766,7 +1762,7 @@ void RPLLoader_LoadSectionDebugSymbols(RPLModule* rplLoaderContext, rplSectionEn char* symbolName = (char*)strtabData + nameOffset; if (sym->info == 0x12) { - rplSymbolStorage_store(rplLoaderContext->moduleName2.c_str(), symbolName, sym->symbolAddress); + rplSymbolStorage_store(rplLoaderContext->moduleName.c_str(), symbolName, sym->symbolAddress); } } } @@ -1860,7 +1856,7 @@ void RPLLoader_FixModuleTLSIndex(RPLModule* rplLoaderContext) sint16 tlsModuleIndex = -1; for (auto& dep : rplDependencyList) { - if (boost::iequals(rplLoaderContext->moduleName2, dep->modulename)) + if (rplLoaderContext->moduleName == dep->moduleName) { tlsModuleIndex = dep->tlsModuleIndex; break; @@ -1928,23 +1924,21 @@ COSModule* RPLLoader_GetHLECafeOSModule(std::string_view moduleName) std::span cosModules = GetCOSModules(); for (auto& module : cosModules) { - if (boost::iequals(module->GetName(), moduleName)) + if (module->GetName() == moduleName) return module; } return nullptr; } // increment reference counter for module -void RPLLoader_AddDependency(std::string_view name) +void RPLLoader_AddDependency(std::string_view name, bool isMainExecutable) { cemu_assert(!name.empty()); - // get module name from path - char moduleName[RPL_MODULE_NAME_LENGTH]; - _RPLLoader_ExtractModuleNameFromPath(moduleName, name); + std::string moduleName = _RPLLoader_ExtractModuleNameFromPath(name); // check if dependency already exists for (auto& dep : rplDependencyList) { - if (strcmp(moduleName, dep->modulename) == 0) + if (moduleName == dep->moduleName) { dep->referenceCount++; return; @@ -1952,7 +1946,8 @@ void RPLLoader_AddDependency(std::string_view name) } // add new entry RPLDependency* newDependency = new RPLDependency(); - strcpy(newDependency->modulename, moduleName); + newDependency->isMainExecutable = isMainExecutable; + newDependency->moduleName = moduleName; newDependency->referenceCount = 1; newDependency->coreinitHandle = rplLoader_currentHandleCounter; newDependency->tlsModuleIndex = rplLoader_currentTlsModuleIndex; @@ -1961,21 +1956,13 @@ void RPLLoader_AddDependency(std::string_view name) rplLoader_currentHandleCounter++; if (rplLoader_currentTlsModuleIndex == 0x7FFF) cemuLog_log(LogType::Force, "RPLLoader: Exhausted TLS module indices pool"); - // convert name to path/filename if it isn't already one - if (name.find_first_of('.') != std::string_view::npos) - { - newDependency->filepath = name; - } - else - { - newDependency->filepath = name; - newDependency->filepath.append(".rpl"); - } - if (newDependency->filepath.size() >= RPL_MODULE_PATH_LENGTH) - cemuLog_log(LogType::Force, "RPLLoader_AddDependency(): RPL path too long \"{}\"", newDependency->filepath); + if (moduleName.size() >= RPL_MODULE_PATH_LENGTH) + cemuLog_log(LogType::Force, "RPLLoader_AddDependency(): RPL module name too long \"{}\"", moduleName); + std::string fileName = moduleName; + fileName.append(isMainExecutable ? ".rpx" : ".rpl"); // if no CafeLibs RPL is present then try to load as a HLE module // we dont check for isCafeOSModule == true here because the user might want to replace application RPLs in some cases - const auto cafeLibsFilePath = ActiveSettings::GetUserDataPath("cafeLibs/{}", newDependency->filepath); + const auto cafeLibsFilePath = ActiveSettings::GetUserDataPath("cafeLibs/{}", fileName); std::error_code ec; if (!fs::exists(cafeLibsFilePath, ec)) newDependency->rplHLEModule = RPLLoader_GetHLECafeOSModule(moduleName); @@ -1985,14 +1972,14 @@ void RPLLoader_AddDependency(std::string_view name) // decrement reference counter for dependency by module path void RPLLoader_RemoveDependency(std::string_view name) { - cemu_assert(!name.empty()); - // get module name from path - char moduleName[RPL_MODULE_NAME_LENGTH]; - _RPLLoader_ExtractModuleNameFromPath(moduleName, name); + cemu_assert_debug(!name.empty()); + if (name.empty()) + return; + std::string moduleName = _RPLLoader_ExtractModuleNameFromPath(name); // find dependency and decrement ref count for (auto& dep : rplDependencyList) { - if (strcmp(moduleName, dep->modulename) == 0) + if (dep->moduleName == moduleName) { dep->referenceCount--; return; @@ -2002,11 +1989,12 @@ void RPLLoader_RemoveDependency(std::string_view name) bool RPLLoader_HasDependency(std::string_view name) { - char moduleName[RPL_MODULE_NAME_LENGTH]; - _RPLLoader_ExtractModuleNameFromPath(moduleName, name); + if (name.empty()) + return false; + std::string moduleName = _RPLLoader_ExtractModuleNameFromPath(name); for (const auto& dep : rplDependencyList) { - if (strcmp(moduleName, dep->modulename) == 0) + if (dep->moduleName == moduleName) return true; } return false; @@ -2041,13 +2029,11 @@ RPLDependency* RPLLoader_GetDependencyByRPLModule(RPLModule* rpl) uint32 RPLLoader_GetHandleByModuleName(const char* name) { - // get module name from path - char moduleName[RPL_MODULE_NAME_LENGTH]; - _RPLLoader_ExtractModuleNameFromPath(moduleName, name); + std::string moduleName = _RPLLoader_ExtractModuleNameFromPath(name); // search for existing dependency for (auto& dep : rplDependencyList) { - if (strcmp(moduleName, dep->modulename) == 0) + if (dep->moduleName == moduleName) { cemu_assert_debug(dep->loadAttempted); if (!dep->isCafeOSModule && !dep->rplLoaderContext) @@ -2107,7 +2093,7 @@ void RPLLoader_LoadDependency(RPLDependency* dependency) { dependency->rplHLEModule->RPLMapped(); // load chained dependencies - // this is necessary for something like GX2.rpl which uses TCL.rpl functions + // this is necessary for something like HLE GX2.rpl which uses TCL.rpl functions auto depList = dependency->rplHLEModule->GetDependencies(); for (const auto& dep : depList) RPLLoader_AddDependency(dep); @@ -2116,43 +2102,36 @@ void RPLLoader_LoadDependency(RPLDependency* dependency) // check if module is already loaded for (sint32 i = 0; i < rplModuleCount; i++) { - if(!boost::iequals(rplModuleList[i]->moduleName2, dependency->modulename)) + if (rplModuleList[i]->moduleName != dependency->moduleName) continue; dependency->rplLoaderContext = rplModuleList[i]; return; } - //char filePath[RPL_MODULE_PATH_LENGTH]; - std::string rplPath; - // check if path is absolute - if (!dependency->filepath.empty() && dependency->filepath.front() == '/') - { - rplPath = dependency->filepath; - RPLLoader_LoadFromVirtualPath(dependency, rplPath); - return; - } // attempt to load rpl from code directory of current title - rplPath = "/internal/current_title/code/"; - rplPath.append(dependency->filepath); + std::string rplFilename = dependency->moduleName; + rplFilename.append(dependency->isMainExecutable ? ".rpx" : ".rpl"); + std::string rplPath = "/internal/current_title/code/"; + rplPath.append(rplFilename); // except if it is blacklisted bool isBlacklisted = false; - if (boost::iequals(dependency->filepath, "erreula.rpl")) + if (dependency->moduleName == "erreula") { if (fsc_doesFileExist(rplPath.c_str())) isBlacklisted = true; } if (isBlacklisted) - cemuLog_log(LogType::Force, fmt::format("Game tried to load \"{}\" but it is blacklisted (using Cemu's implementation instead)", rplPath)); + cemuLog_log(LogType::Force, "Game tried to load code/{} but it is blacklisted (using Cemu's implementation instead)", rplFilename); else if (RPLLoader_LoadFromVirtualPath(dependency, rplPath)) return; // attempt to load rpl from Cemu's /cafeLibs/ directory if (ActiveSettings::LoadSharedLibrariesEnabled()) { - const auto cafeLibsFilePath = ActiveSettings::GetUserDataPath("cafeLibs/{}", dependency->filepath); + const auto cafeLibsFilePath = ActiveSettings::GetUserDataPath("cafeLibs/{}", rplFilename); auto fileData = FileStream::LoadIntoMemory(cafeLibsFilePath); if (fileData) { - cemuLog_log(LogType::Force, "Loading RPL: /cafeLibs/{}", dependency->filepath); - dependency->rplLoaderContext = RPLLoader_LoadFromMemory(fileData->data(), fileData->size(), dependency->filepath); + cemuLog_log(LogType::Force, "Loading RPL: /cafeLibs/{}", rplFilename); + dependency->rplLoaderContext = RPLLoader_LoadFromMemory(fileData->data(), fileData->size(), rplFilename); return; } } @@ -2213,7 +2192,7 @@ void RPLLoader_LoadCoreinit() RPLLoader_AddDependency("coreinit"); for (auto& dep : rplDependencyList) { - if (strcmp(dep->modulename, "coreinit") == 0) + if (dep->moduleName == "coreinit") { dep->loadAttempted = true; RPLLoader_LoadDependency(dep); @@ -2276,7 +2255,7 @@ RPLModule* RPLLoader_FindModuleByName(std::string module) { for (sint32 i = 0; i < rplModuleCount; i++) { - if (rplModuleList[i]->moduleName2 == module) return rplModuleList[i]; + if (rplModuleList[i]->moduleName == module) return rplModuleList[i]; } return nullptr; } @@ -2298,7 +2277,7 @@ void RPLLoader_CallEntrypoints() { if (rplModuleList[i]->entrypointCalled) continue; - uint32 moduleHandle = RPLLoader_GetHandleByModuleName(rplModuleList[i]->moduleName2.c_str()); + uint32 moduleHandle = RPLLoader_GetHandleByModuleName(rplModuleList[i]->moduleName.c_str()); MPTR entryPoint = RPLLoader_GetModuleEntrypoint(rplModuleList[i]); PPCCoreCallback(entryPoint, moduleHandle, 1); // 1 -> load, 2 -> unload rplModuleList[i]->entrypointCalled = true; @@ -2311,7 +2290,7 @@ void RPLLoader_CallCoreinitEntrypoint() // for HLE modules we need to check the dependency list for (auto& dependency : rplDependencyList) { - if (strcmp(dependency->modulename, "coreinit") != 0) + if (dependency->moduleName != "coreinit") continue; if (!dependency->rplHLEModule) continue; @@ -2354,13 +2333,13 @@ uint32 RPLLoader_FindModuleOrHLEExport(uint32 moduleHandle, bool isData, const c // attempt to find HLE export if (isData) { - MPTR weakExportAddr = osLib_getPointer(dependency->modulename, exportName); + MPTR weakExportAddr = osLib_getPointer(dependency->moduleName.c_str(), exportName); cemu_assert_debug(weakExportAddr != 0xFFFFFFFF); exportResult = weakExportAddr; } else { - exportResult = rpl_mapHLEImport(rplLoaderContext, dependency->modulename, exportName, true); + exportResult = rpl_mapHLEImport(rplLoaderContext, dependency->moduleName.c_str(), exportName, true); } } @@ -2482,8 +2461,6 @@ void RPLLoader_UnloadAll() cemu_assert_debug(dependency->referenceCount >= 0); // sanity check for ref count if (!dependency->rplHLEModule) continue; - if (dependency->referenceCount <= 0) - continue; cemu_assert_debug(dependency->hleEntrypointCalled); // entrypoint should have been called dependency->rplHLEModule->rpl_entry(dependency->coreinitHandle, coreinit::RplEntryReason::Unloaded); dependency->rplHLEModule->RPLUnmapped(); diff --git a/src/Cafe/OS/RPL/rpl.h b/src/Cafe/OS/RPL/rpl.h index 6d161d2b..1f7205bc 100644 --- a/src/Cafe/OS/RPL/rpl.h +++ b/src/Cafe/OS/RPL/rpl.h @@ -28,7 +28,7 @@ void RPLLoader_CallEntrypoints(); void RPLLoader_CallCoreinitEntrypoint(); void RPLLoader_NotifyControlPassedToApplication(); -void RPLLoader_AddDependency(std::string_view name); +void RPLLoader_AddDependency(std::string_view name, bool isMainExecutable = false); void RPLLoader_RemoveDependency(uint32 handle); bool RPLLoader_HasDependency(std::string_view name); void RPLLoader_UpdateDependencies(); diff --git a/src/Cafe/OS/RPL/rpl_structs.h b/src/Cafe/OS/RPL/rpl_structs.h index aa734dae..8dd126b0 100644 --- a/src/Cafe/OS/RPL/rpl_structs.h +++ b/src/Cafe/OS/RPL/rpl_structs.h @@ -164,14 +164,16 @@ struct RPLModule uint32 exportFCount; rplExportTableEntry_t* exportFDataPtr; - std::string moduleName2; + std::string moduleName; std::vector sectionAddressTable2; uint32 tlsStartAddress; uint32 tlsEndAddress; uint32 regionSize_text; + uint32 regionOrigAddr_text; uint32 regionSize_data; + uint32 regionOrigAddr_data; uint32 regionSize_loaderInfo; uint32 patchCRC; // Cemuhook style module crc for patches.txt @@ -234,11 +236,11 @@ struct RPLModule struct RPLDependency { - char modulename[RPL_MODULE_NAME_LENGTH]; - std::string filepath; - bool loadAttempted; + std::string moduleName; + bool isMainExecutable{false}; + bool loadAttempted{false}; bool hleEntrypointCalled{false}; - bool isCafeOSModule; // name is a known Cafe OS system RPL + bool isCafeOSModule{false}; // name is a known Cafe OS system RPL RPLModule* rplLoaderContext{}; // context of loaded module, can be nullptr for HLE COS modules class COSModule* rplHLEModule{}; // set if this is a HLE module sint32 referenceCount; diff --git a/src/Cafe/OS/RPL/rpl_symbol_storage.cpp b/src/Cafe/OS/RPL/rpl_symbol_storage.cpp index 5d3046e3..3910640e 100644 --- a/src/Cafe/OS/RPL/rpl_symbol_storage.cpp +++ b/src/Cafe/OS/RPL/rpl_symbol_storage.cpp @@ -63,7 +63,7 @@ char* rplSymbolStorage_storeLibname(const char* libName) return libEntry->libName; } -RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolName, MPTR address) +RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolName, MPTR address, uint32 type) { std::unique_lock lck(rplSymbolStorage.m_symbolStorageMutex); char* libNameStorage = rplSymbolStorage_storeLibname(libName); @@ -72,7 +72,11 @@ RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolN storedSymbol->address = address; storedSymbol->libName = libNameStorage; storedSymbol->symbolName = symbolNameStorage; - storedSymbol->flags = 0; + storedSymbol->flags = type; + storedSymbol->previous = nullptr; + auto it = rplSymbolStorage.map_symbolByAddress.find(address); + if (it != rplSymbolStorage.map_symbolByAddress.end()) + storedSymbol->previous = it->second; rplSymbolStorage.map_symbolByAddress[address] = storedSymbol; return storedSymbol; } @@ -80,7 +84,10 @@ RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolN RPLStoredSymbol* rplSymbolStorage_getByAddress(MPTR address) { std::unique_lock lck(rplSymbolStorage.m_symbolStorageMutex); - return rplSymbolStorage.map_symbolByAddress[address]; + auto it = rplSymbolStorage.map_symbolByAddress.find(address); + if (it == rplSymbolStorage.map_symbolByAddress.end()) + return nullptr; + return it->second; } RPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address) @@ -89,7 +96,8 @@ RPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address) std::unique_lock lck(rplSymbolStorage.m_symbolStorageMutex); for(uint32 i=0; i<4096; i++) { - RPLStoredSymbol* symbol = rplSymbolStorage.map_symbolByAddress[address]; + auto it = rplSymbolStorage.map_symbolByAddress.find(address); + RPLStoredSymbol* symbol = (it == rplSymbolStorage.map_symbolByAddress.end()) ? nullptr : it->second; if(symbol) return symbol; address -= 4; @@ -100,18 +108,63 @@ RPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address) void rplSymbolStorage_remove(RPLStoredSymbol* storedSymbol) { std::unique_lock lck(rplSymbolStorage.m_symbolStorageMutex); - if (rplSymbolStorage.map_symbolByAddress[storedSymbol->address] == storedSymbol) - rplSymbolStorage.map_symbolByAddress[storedSymbol->address] = nullptr; + auto it = rplSymbolStorage.map_symbolByAddress.find(storedSymbol->address); + if (it != rplSymbolStorage.map_symbolByAddress.end()) + { + if (it->second == storedSymbol) + { + if (storedSymbol->previous) + it->second = storedSymbol->previous; + else + rplSymbolStorage.map_symbolByAddress.erase(it); + } + else + { + RPLStoredSymbol* parentSymbol = it->second; + while (parentSymbol && parentSymbol->previous != storedSymbol) + parentSymbol = parentSymbol->previous; + if (parentSymbol) + parentSymbol->previous = storedSymbol->previous; + } + } delete storedSymbol; } -void rplSymbolStorage_removeRange(MPTR address, sint32 length) + +void rplSymbolStorage_removeRange(MPTR address, sint32 length, uint32 type) { + std::unique_lock lck(rplSymbolStorage.m_symbolStorageMutex); while (length > 0) { - RPLStoredSymbol* symbol = rplSymbolStorage_getByAddress(address); - if (symbol) - rplSymbolStorage_remove(symbol); + auto it = rplSymbolStorage.map_symbolByAddress.find(address); + if (it != rplSymbolStorage.map_symbolByAddress.end()) + { + RPLStoredSymbol* current = it->second; + RPLStoredSymbol* newHead = current; + RPLStoredSymbol* previousKept = nullptr; + while (current) + { + RPLStoredSymbol* next = current->previous; + if ((current->flags & type) == type) + { + if (previousKept) + previousKept->previous = next; + else + newHead = next; + delete current; + } + else + { + previousKept = current; + } + current = next; + } + + if (newHead) + it->second = newHead; + else + rplSymbolStorage.map_symbolByAddress.erase(it); + } address += 4; length -= 4; } @@ -145,7 +198,15 @@ void rplSymbolStorage_unloadAll() { // free symbols for (auto& it : rplSymbolStorage.map_symbolByAddress) - delete it.second; + { + RPLStoredSymbol* symbol = it.second; + while (symbol) + { + RPLStoredSymbol* previous = symbol->previous; + delete symbol; + symbol = previous; + } + } rplSymbolStorage.map_symbolByAddress.clear(); // free libs rplSymbolLib_t* lib = rplSymbolStorage.libs; diff --git a/src/Cafe/OS/RPL/rpl_symbol_storage.h b/src/Cafe/OS/RPL/rpl_symbol_storage.h index d940186a..59592c6c 100644 --- a/src/Cafe/OS/RPL/rpl_symbol_storage.h +++ b/src/Cafe/OS/RPL/rpl_symbol_storage.h @@ -1,19 +1,27 @@ +enum RPLStoredSymbolType : uint32 +{ + RPL_STORED_SYMBOL_NONE = 0, + RPL_STORED_SYMBOL_MAP = 1 << 0, + RPL_STORED_SYMBOL_PATCH = 1 << 1, +}; + struct RPLStoredSymbol { MPTR address; void* libName; void* symbolName; uint32 flags; + RPLStoredSymbol* previous; }; void rplSymbolStorage_init(); void rplSymbolStorage_unloadAll(); -RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolName, MPTR address); +RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolName, MPTR address, uint32 type = RPL_STORED_SYMBOL_NONE); void rplSymbolStorage_remove(RPLStoredSymbol* storedSymbol); -void rplSymbolStorage_removeRange(MPTR address, sint32 length); +void rplSymbolStorage_removeRange(MPTR address, sint32 length, uint32 type = RPL_STORED_SYMBOL_NONE); RPLStoredSymbol* rplSymbolStorage_getByAddress(MPTR address); RPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address); void rplSymbolStorage_createJumpProxySymbol(MPTR jumpAddress, MPTR destAddress); std::unordered_map& rplSymbolStorage_lockSymbolMap(); -void rplSymbolStorage_unlockSymbolMap(); \ No newline at end of file +void rplSymbolStorage_unlockSymbolMap(); diff --git a/src/Cafe/OS/libs/nn_ac/nn_ac.cpp b/src/Cafe/OS/libs/nn_ac/nn_ac.cpp index 61e7a677..fcc712d1 100644 --- a/src/Cafe/OS/libs/nn_ac/nn_ac.cpp +++ b/src/Cafe/OS/libs/nn_ac/nn_ac.cpp @@ -5,6 +5,9 @@ #if BOOST_OS_WINDOWS #include +#elif BOOST_OS_LINUX +#include +#include #endif // AC lib (manages internet connection) @@ -81,6 +84,40 @@ void _GetLocalIPAndSubnetMask(uint32& localIp, uint32& subnetMask) cemuLog_logDebug(LogType::Force, "_GetLocalIPAndSubnetMask(): Failed to find network IP and subnet mask"); _GetLocalIPAndSubnetMaskFallback(localIp, subnetMask); } +#elif BOOST_OS_LINUX +void _GetLocalIPAndSubnetMask(uint32& localIp, uint32& subnetMask) +{ + struct ifaddrs *ifaddr; + if (getifaddrs(&ifaddr) == -1) + { + cemuLog_log(LogType::Force, "Failed to acquire local IP and subnet mask"); + _GetLocalIPAndSubnetMaskFallback(localIp, subnetMask); + } + stdx::scope_exit _ifa([&]{ freeifaddrs(ifaddr); }); + + for (const struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr == nullptr || ifa->ifa_addr->sa_family != AF_INET) + continue; + + if (!(ifa->ifa_flags & IFF_UP) || !(ifa->ifa_flags & IFF_RUNNING)) + continue; + + if (ifa->ifa_flags & IFF_LOOPBACK || ifa->ifa_flags & IFF_POINTOPOINT) + continue; + + if (boost::starts_with(ifa->ifa_name, "br-") || boost::starts_with(ifa->ifa_name, "docker")) + continue; + + const auto* addr_in = reinterpret_cast(ifa->ifa_addr); + localIp = ntohl(addr_in->sin_addr.s_addr); + const auto* mask_in = reinterpret_cast(ifa->ifa_netmask); + subnetMask = ntohl(mask_in->sin_addr.s_addr); + return; + } + cemuLog_logDebug(LogType::Force, "_GetLocalIPAndSubnetMask(): Failed to find network IP and subnet mask"); + _GetLocalIPAndSubnetMaskFallback(localIp, subnetMask); +} #else void _GetLocalIPAndSubnetMask(uint32& localIp, uint32& subnetMask) { diff --git a/src/Cafe/OS/libs/proc_ui/proc_ui.cpp b/src/Cafe/OS/libs/proc_ui/proc_ui.cpp index 11516470..061886ca 100644 --- a/src/Cafe/OS/libs/proc_ui/proc_ui.cpp +++ b/src/Cafe/OS/libs/proc_ui/proc_ui.cpp @@ -355,6 +355,8 @@ namespace proc_ui { if (!s_isInitialized.exchange(false)) return; + if (!OSIsSchedulerActive()) + return; // CafeSystem shutdown in progress, OS functions shouldn't be called anymore. reset() will clean up state on next re-init if ( !s_isInForeground ) CancelBackgroundAlarms(); for (sint32 i = 0; i < Espresso::CORE_COUNT; i++) diff --git a/src/gui/wxgui/DownloadCustomGraphicPackWindow.cpp b/src/gui/wxgui/DownloadCustomGraphicPackWindow.cpp index d136b07f..f261061d 100644 --- a/src/gui/wxgui/DownloadCustomGraphicPackWindow.cpp +++ b/src/gui/wxgui/DownloadCustomGraphicPackWindow.cpp @@ -121,12 +121,6 @@ DownloadCustomGraphicPackWindow::~DownloadCustomGraphicPackWindow() int DownloadCustomGraphicPackWindow::ShowModal() { - if (CafeSystem::IsTitleRunning()) - { - wxMessageBox(_("Graphic packs cannot be updated while a game is running."), _("Graphic packs"), 5, this); - return wxID_CANCEL; - } - wxDialog::ShowModal(); return wxID_OK; } diff --git a/src/gui/wxgui/GraphicPacksWindow2.cpp b/src/gui/wxgui/GraphicPacksWindow2.cpp index 9ac52304..21e25b07 100644 --- a/src/gui/wxgui/GraphicPacksWindow2.cpp +++ b/src/gui/wxgui/GraphicPacksWindow2.cpp @@ -304,13 +304,13 @@ GraphicPacksWindow2::GraphicPacksWindow2(wxWindow* parent, uint64_t title_id_fil auto* row = new wxBoxSizer(wxHORIZONTAL); - m_download_from_url = new wxButton(m_right_panel, wxID_ANY, _("Download pack from URL")); - m_download_from_url->Bind(wxEVT_BUTTON, &GraphicPacksWindow2::OnClickCustomDownload, this); - row->Add(m_download_from_url, 0, wxALL, 5); - m_update_graphicPacks = new wxButton(m_right_panel, wxID_ANY, _("Download latest community graphic packs")); m_update_graphicPacks->Bind(wxEVT_BUTTON, &GraphicPacksWindow2::OnCheckForUpdates, this); - row->Add(m_update_graphicPacks, 0, wxALL, 5); + row->Add(m_update_graphicPacks, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + + m_download_from_url = new wxHyperlinkCtrl(m_right_panel, wxID_ANY, _("Or download pack from URL..."), _("")); + m_download_from_url->Bind(wxEVT_HYPERLINK, &GraphicPacksWindow2::OnClickCustomDownload, this); + row->Add(m_download_from_url, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); sizer->Add(row, 0, wxALL | wxEXPAND, 5); @@ -608,7 +608,7 @@ void GraphicPacksWindow2::OnReloadShaders(wxCommandEvent& event) void GraphicPacksWindow2::OnClickCustomDownload(wxCommandEvent& event) { DownloadCustomGraphicPackWindow frame(this); - if (frame.ShowModal() == wxID_OK && !CafeSystem::IsTitleRunning()) + if (frame.ShowModal() == wxID_OK) { RefreshGraphicPacks(); FillGraphicPackList(); @@ -700,10 +700,17 @@ void GraphicPacksWindow2::OnInstalledGamesChanged(wxCommandEvent& event) void GraphicPacksWindow2::UpdateTitleRunning(bool running) { m_update_graphicPacks->Enable(!running); + m_download_from_url->Enable(!running); if(running) + { + m_download_from_url->SetToolTip(_("Graphic packs cannot be updated while a game is running.")); m_update_graphicPacks->SetToolTip(_("Graphic packs cannot be updated while a game is running.")); + } else + { m_update_graphicPacks->SetToolTip(nullptr); + m_download_from_url->SetToolTip(nullptr); + } } void GraphicPacksWindow2::ReloadPack(const GraphicPackPtr& graphic_pack) const diff --git a/src/gui/wxgui/GraphicPacksWindow2.h b/src/gui/wxgui/GraphicPacksWindow2.h index 0d24e87b..bf8647de 100644 --- a/src/gui/wxgui/GraphicPacksWindow2.h +++ b/src/gui/wxgui/GraphicPacksWindow2.h @@ -1,9 +1,9 @@ #pragma once -#include #include #include #include +#include #include "wxcomponents/checktree.h" @@ -46,7 +46,7 @@ private: wxBoxSizer* m_preset_sizer; std::vector m_active_preset; wxButton* m_reload_shaders; - wxButton* m_download_from_url; + wxHyperlinkCtrl* m_download_from_url; wxButton* m_update_graphicPacks; wxInfoBar* m_info_bar; diff --git a/src/gui/wxgui/debugger/DebuggerWindow2.cpp b/src/gui/wxgui/debugger/DebuggerWindow2.cpp index e91bc1e0..a4b46d6a 100644 --- a/src/gui/wxgui/debugger/DebuggerWindow2.cpp +++ b/src/gui/wxgui/debugger/DebuggerWindow2.cpp @@ -3,11 +3,12 @@ #include "wxHelper.h" -#include - +#include "Common/FileStream.h" #include "config/ActiveSettings.h" +#include "Cafe/HW/MMU/MMU.h" #include "Cafe/OS/RPL/rpl_structs.h" #include "Cafe/OS/RPL/rpl_debug_symbols.h" +#include "Cafe/OS/RPL/rpl_symbol_storage.h" #include "wxgui/debugger/RegisterWindow.h" #include "wxgui/debugger/DumpWindow.h" @@ -20,6 +21,7 @@ #include "wxgui/debugger/BreakpointWindow.h" #include "wxgui/debugger/ModuleWindow.h" #include "util/helpers/helpers.h" +#include "util/helpers/StringHelpers.h" #include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h" #include "Cemu/Logging/CemuLogging.h" @@ -81,13 +83,14 @@ wxEND_EVENT_TABLE() DebuggerModuleInfo::DebuggerModuleInfo(RPLModule* module) { - moduleName = module->moduleName2; + moduleName = module->moduleName; patchCRC = module->patchCRC; textArea.base = module->regionMappingBase_text.GetMPTR(); + textArea.origBase = module->regionOrigAddr_text; textArea.size = module->regionSize_text; dataArea.base = module->regionMappingBase_data; + dataArea.origBase = module->regionOrigAddr_data; dataArea.size = module->regionSize_data; - } struct DebuggerModuleInfoNotify : public wxClientData @@ -99,6 +102,65 @@ struct DebuggerModuleInfoNotify : public wxClientData DebuggerWindow2* s_debuggerWindow; +static bool TryParseMapAddress(std::string_view token, uint32& value) +{ + trim(token, "\t\n\v\f\r ,:;()[]"); + if (const auto colonIndex = token.find_last_of(':'); colonIndex != std::string_view::npos) + token = token.substr(colonIndex + 1); + trim(token, "\t\n\v\f\r ,:;()[]"); + if (!token.empty() && (token.back() == 'h' || token.back() == 'H')) + token.remove_suffix(1); + if (token.size() > 2 && token[0] == '0' && (token[1] == 'x' || token[1] == 'X')) + token.remove_prefix(2); + if (token.empty()) + return false; + + uint64 parsedValue = 0; + const auto result = std::from_chars(token.data(), token.data() + token.size(), parsedValue, 16); + if (result.ec != std::errc() || result.ptr != (token.data() + token.size()) || parsedValue > std::numeric_limits::max()) + return false; + + value = static_cast(parsedValue); + return true; +} + +static bool TryParseMapSymbolLine(std::string_view rawLine, uint32& address, std::string& symbolName) +{ + auto line = rawLine; + trim(line); + if (line.empty()) + return false; + + const auto addressEnd = line.find_first_of(" \t"); + if (addressEnd == std::string_view::npos) + return false; + if (!TryParseMapAddress(line.substr(0, addressEnd), address)) + return false; + + line = line.substr(addressEnd + 1); + trim(line); + if (line.empty()) + return false; + + const auto symbolEnd = line.find_first_of(" \t"); + auto symbolToken = symbolEnd == std::string_view::npos ? line : line.substr(0, symbolEnd); + trim(symbolToken); + if (symbolToken.empty()) + return false; + + symbolName.assign(symbolToken); + return true; +} + +static std::optional GetRelocatedMapAddress(const DebuggerModuleInfo& moduleInfo, uint32 mapAddress) +{ + if (moduleInfo.textArea.ContainsOriginalAddress(mapAddress)) + return moduleInfo.textArea.base + (mapAddress - moduleInfo.textArea.origBase); + if (moduleInfo.dataArea.ContainsOriginalAddress(mapAddress)) + return moduleInfo.dataArea.base + (mapAddress - moduleInfo.dataArea.origBase); + return std::nullopt; +} + void DebuggerConfig::Load(XMLConfigParser& parser) { pin_to_main = parser.get("PinToMainWindow", true); @@ -282,26 +344,79 @@ void DebuggerWindow2::LoadModuleStorage(const DebuggerModuleInfo& moduleInfo) bool already_loaded = std::any_of(m_modulesStorage.begin(), m_modulesStorage.end(), [path](const std::unique_ptr& debug) { return debug->GetFilename() == path; }); if (!path.empty() && !already_loaded) { - m_modulesStorage.emplace_back(new XMLDebuggerModuleConfig(path, { moduleInfo, false }))->Load(); + auto& moduleStorage = m_modulesStorage.emplace_back(new XMLDebuggerModuleConfig(path, { moduleInfo, false })); + moduleStorage->Load(); + LoadModuleMap(moduleStorage->data()); } } void DebuggerWindow2::SaveModuleStorage(const DebuggerModuleInfo& moduleInfo, bool deleteModuleStorage) { auto path = GetModuleStoragePath(moduleInfo.moduleName, moduleInfo.patchCRC); - for (auto& moduleStorage : m_modulesStorage) + for (auto it = m_modulesStorage.begin(); it != m_modulesStorage.end(); ++it) { + auto& moduleStorage = *it; if (moduleStorage->data().moduleInfo.moduleName == moduleInfo.moduleName && moduleStorage->data().moduleInfo.patchCRC == moduleInfo.patchCRC) { moduleStorage->data().delete_breakpoints_after_saving = deleteModuleStorage; // make sure breakpoints are deleted when the storage is removed moduleStorage->Save(path); if (deleteModuleStorage) - m_modulesStorage.erase(std::find(m_modulesStorage.begin(), m_modulesStorage.end(), moduleStorage)); - break; + { + UnloadModuleMap(moduleStorage->data()); + m_modulesStorage.erase(it); + } + return; } } } +void DebuggerWindow2::LoadModuleMap(DebuggerModuleStorage& moduleStorage) +{ + UnloadModuleMap(moduleStorage); + + const auto mapPath = GetModuleMapPath(moduleStorage.moduleInfo.moduleName, moduleStorage.moduleInfo.patchCRC); + if (mapPath.empty()) + return; + + std::unique_ptr fileStream(FileStream::openFile(mapPath.c_str())); + if (!fileStream) + return; + + const auto fileSize = fileStream->GetSize(); + if (fileSize == 0 || fileSize > std::numeric_limits::max()) + return; + + const auto readSize = static_cast(fileSize); + std::vector fileData(readSize); + if (fileStream->readData(fileData.data(), readSize) != readSize) + return; + + std::string_view fileView(fileData.data(), fileData.size()); + for (const auto& line : StringHelpers::StringLineIterator(fileView)) + { + uint32 mapAddress = 0; + std::string symbolName; + if (TryParseMapSymbolLine(line, mapAddress, symbolName)) + { + const auto relocatedAddress = GetRelocatedMapAddress(moduleStorage.moduleInfo, mapAddress); + if (relocatedAddress) + { + moduleStorage.loaded_map_symbols.emplace_back(rplSymbolStorage_store(moduleStorage.moduleInfo.moduleName.c_str(), symbolName.c_str(), *relocatedAddress, RPL_STORED_SYMBOL_MAP)); + } + } + } +} + +void DebuggerWindow2::UnloadModuleMap(DebuggerModuleStorage& moduleStorage) +{ + for (auto* symbol : moduleStorage.loaded_map_symbols) + { + if (symbol) + rplSymbolStorage_remove(symbol); + } + moduleStorage.loaded_map_symbols.clear(); +} + DebuggerWindow2::DebuggerWindow2(wxFrame& parent, const wxRect& display_size) : wxFrame(&parent, wxID_ANY, _("PPC Debugger"), wxDefaultPosition, wxSize(1280, 300), wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT), m_module_address(0) @@ -341,7 +456,7 @@ DebuggerWindow2::DebuggerWindow2(wxFrame& parent, const wxRect& display_size) { RPLModule* currentModule = RPLLoader_FindModuleByCodeAddr(MEMORY_CODEAREA_ADDR); if (currentModule) - label_text = wxString::Format("> %s", currentModule->moduleName2.c_str()); + label_text = wxString::Format("> %s", currentModule->moduleName.c_str()); else label_text = _("> unknown module"); } @@ -497,7 +612,7 @@ void DebuggerWindow2::OnGameLoaded() RPLModule* current_rpl_module = RPLLoader_FindModuleByCodeAddr(MEMORY_CODEAREA_ADDR); if(current_rpl_module) - m_module_label->SetLabel(wxString::Format("> %s", current_rpl_module->moduleName2.c_str())); + m_module_label->SetLabel(wxString::Format("> %s", current_rpl_module->moduleName.c_str())); this->SendSizeEvent(); } @@ -537,6 +652,12 @@ std::wstring DebuggerWindow2::GetModuleStoragePath(std::string module_name, uint return ActiveSettings::GetConfigPath("debugger/{}_{:#10x}.xml", module_name, crc_hash).generic_wstring(); } +std::wstring DebuggerWindow2::GetModuleMapPath(std::string module_name, uint32_t crc_hash) const +{ + if (module_name.empty() || crc_hash == 0) return {}; + return ActiveSettings::GetConfigPath("debugger/{}_{:#10x}.map", module_name, crc_hash).generic_wstring(); +} + void DebuggerWindow2::OnBreakpointHit(wxCommandEvent& event) { PPCInterpreter_t* hCPU = debugger_lockDebugSession(); @@ -758,7 +879,7 @@ void DebuggerWindow2::UpdateModuleLabel(uint32 address) RPLModule* module = RPLLoader_FindModuleByCodeAddr(address); if (module && m_module_address != module->regionMappingBase_text.GetMPTR()) { - m_module_label->SetLabel(wxString::Format("> %s", module->moduleName2.c_str())); + m_module_label->SetLabel(wxString::Format("> %s", module->moduleName.c_str())); m_module_address = module->regionMappingBase_text.GetMPTR(); } else if (address >= mmuRange_CODECAVE.getBase() && address < mmuRange_CODECAVE.getEnd()) diff --git a/src/gui/wxgui/debugger/DebuggerWindow2.h b/src/gui/wxgui/debugger/DebuggerWindow2.h index 1b4d3c72..83cc5edb 100644 --- a/src/gui/wxgui/debugger/DebuggerWindow2.h +++ b/src/gui/wxgui/debugger/DebuggerWindow2.h @@ -16,6 +16,7 @@ class DumpWindow; class ModuleWindow; class SymbolWindow; class wxStaticText; +struct RPLStoredSymbol; wxDECLARE_EVENT(wxEVT_UPDATE_VIEW, wxCommandEvent); wxDECLARE_EVENT(wxEVT_BREAKPOINT_HIT, wxCommandEvent); @@ -54,12 +55,18 @@ struct DebuggerModuleInfo struct ModuleArea { MPTR base; + MPTR origBase; uint32 size; - bool ContainsAddress(MPTR addr) + bool ContainsAddress(MPTR addr) const { return addr >= base && (addr < (base+size)); } + + bool ContainsOriginalAddress(MPTR addr) const + { + return addr >= origBase && (addr < (origBase + size)); + } }; std::string moduleName; @@ -74,6 +81,7 @@ struct DebuggerModuleStorage { DebuggerModuleInfo moduleInfo; bool delete_breakpoints_after_saving; + std::vector loaded_map_symbols; void Load(XMLConfigParser& parser); void Save(XMLConfigParser& parser); @@ -126,6 +134,9 @@ private: void CreateMenuBar(); void UpdateModuleLabel(uint32 address = 0); + void LoadModuleMap(DebuggerModuleStorage& moduleStorage); + void UnloadModuleMap(DebuggerModuleStorage& moduleStorage); + std::wstring GetModuleMapPath(std::string module_name, uint32_t crc_hash) const; void UpdateViewThreadsafe() override; void NotifyDebugBreakpointHit() override; diff --git a/src/gui/wxgui/debugger/DisasmCtrl.cpp b/src/gui/wxgui/debugger/DisasmCtrl.cpp index 33da4774..913df026 100644 --- a/src/gui/wxgui/debugger/DisasmCtrl.cpp +++ b/src/gui/wxgui/debugger/DisasmCtrl.cpp @@ -14,6 +14,8 @@ #include "Cemu/ExpressionParser/ExpressionParser.h" #include "Cafe/HW/Espresso/Debugger/DebugSymbolStorage.h" +#include + wxDEFINE_EVENT(wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS, wxCommandEvent); #define MAX_SYMBOL_LEN (120) @@ -699,20 +701,11 @@ void DisasmCtrl::OnMouseDClick(const wxPoint& position, uint32 line) void DisasmCtrl::CopyToClipboard(std::string text) { -#if BOOST_OS_WINDOWS - if (OpenClipboard(nullptr)) + if (wxClipboard::Get()->Open()) { - EmptyClipboard(); - const HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, text.size() + 1); - if (hGlobal) - { - memcpy(GlobalLock(hGlobal), text.c_str(), text.size() + 1); - GlobalUnlock(hGlobal); - SetClipboardData(CF_TEXT, hGlobal); - } - CloseClipboard(); + wxClipboard::Get()->SetData(new wxTextDataObject(text)); + wxClipboard::Get()->Close(); } -#endif } static uint32 GetUnrelocatedAddress(MPTR address) diff --git a/src/gui/wxgui/debugger/ModuleWindow.cpp b/src/gui/wxgui/debugger/ModuleWindow.cpp index cadf2e6a..02e43805 100644 --- a/src/gui/wxgui/debugger/ModuleWindow.cpp +++ b/src/gui/wxgui/debugger/ModuleWindow.cpp @@ -89,7 +89,7 @@ void ModuleWindow::OnGameLoaded() { wxListItem item; item.SetId(i); - item.SetText(module->moduleName2); + item.SetText(module->moduleName); const auto index = m_modules->InsertItem(item); m_modules->SetItem(index, ColumnAddress, wxString::Format("%08x", module->regionMappingBase_text.GetMPTR())); diff --git a/src/gui/wxgui/debugger/RegisterWindow.cpp b/src/gui/wxgui/debugger/RegisterWindow.cpp index 17167176..e8a136b9 100644 --- a/src/gui/wxgui/debugger/RegisterWindow.cpp +++ b/src/gui/wxgui/debugger/RegisterWindow.cpp @@ -222,7 +222,7 @@ void RegisterWindow::UpdateIntegerRegister(wxTextCtrl* label, wxTextCtrl* value, RPLModule* code_module = RPLLoader_FindModuleByCodeAddr(registerValue); if (code_module) { - label->ChangeValue(wxString::Format("<%s> + %x", code_module->moduleName2.c_str(), registerValue - code_module->regionMappingBase_text.GetMPTR())); + label->ChangeValue(wxString::Format("<%s> + %x", code_module->moduleName.c_str(), registerValue - code_module->regionMappingBase_text.GetMPTR())); return; } diff --git a/src/gui/wxgui/debugger/SymbolCtrl.cpp b/src/gui/wxgui/debugger/SymbolCtrl.cpp index 77f55529..8675259c 100644 --- a/src/gui/wxgui/debugger/SymbolCtrl.cpp +++ b/src/gui/wxgui/debugger/SymbolCtrl.cpp @@ -2,6 +2,7 @@ #include "Cafe/OS/RPL/rpl_symbol_storage.h" #include "Cafe/HW/Espresso/Debugger/Debugger.h" #include +#include enum ItemColumns { @@ -38,13 +39,12 @@ SymbolListCtrl::SymbolListCtrl(wxWindow* parent, const wxWindowID& id, const wxP m_list_filter.Clear(); OnGameLoaded(); - - SetItemCount(m_data.size()); } void SymbolListCtrl::OnGameLoaded() { m_data.clear(); + m_visible_items.clear(); const auto symbol_map = rplSymbolStorage_lockSymbolMap(); for (auto const& [address, symbol_info] : symbol_map) { @@ -56,48 +56,30 @@ void SymbolListCtrl::OnGameLoaded() wxString searchNameWX = libNameWX + symbolNameWX; searchNameWX.MakeLower(); - auto new_entry = m_data.try_emplace( - symbol_info->address, - symbolNameWX, + m_data.try_emplace( + address, + symbolNameWX, libNameWX, - searchNameWX, - false + searchNameWX ); - - if (m_list_filter.IsEmpty()) - new_entry.first->second.visible = true; - else if (new_entry.first->second.searchName.Contains(m_list_filter)) - new_entry.first->second.visible = true; } rplSymbolStorage_unlockSymbolMap(); - SetItemCount(m_data.size()); - if (m_data.size() > 0) - RefreshItems(GetTopItem(), std::min(m_data.size() - 1, GetTopItem() + GetCountPerPage() + 1)); + RebuildVisibleItems(); } wxString SymbolListCtrl::OnGetItemText(long item, long column) const { - if (item >= GetItemCount()) + if (item < 0 || item >= static_cast(m_visible_items.size())) return wxEmptyString; - long visible_idx = 0; - for (const auto& [address, symbol] : m_data) - { - if (!symbol.visible) - continue; - - if (item == visible_idx) - { - if (column == ColumnName) - return wxString(symbol.name); - if (column == ColumnAddress) - return wxString::Format("%08x", address); - if (column == ColumnModule) - return wxString(symbol.libName); - } - visible_idx++; - } + const auto& [address, symbol] = *m_visible_items[item]; + if (column == ColumnName) + return symbol.name; + if (column == ColumnAddress) + return wxString::Format("%08x", address); + if (column == ColumnModule) + return symbol.libName; return wxEmptyString; } @@ -106,10 +88,9 @@ wxString SymbolListCtrl::OnGetItemText(long item, long column) const void SymbolListCtrl::OnLeftDClick(wxListEvent& event) { long selected = GetFirstSelected(); - if (selected == wxNOT_FOUND) + if (selected == wxNOT_FOUND || selected >= static_cast(m_visible_items.size())) return; - const auto text = GetItemText(selected, ColumnAddress); - const auto address = std::stoul(text.ToStdString(), nullptr, 16); + const auto address = m_visible_items[selected]->first; if (address == 0) return; debugger_jumpToAddressInDisasm(address); @@ -118,46 +99,40 @@ void SymbolListCtrl::OnLeftDClick(wxListEvent& event) void SymbolListCtrl::OnRightClick(wxListEvent& event) { long selected = GetFirstSelected(); - if (selected == wxNOT_FOUND) + if (selected == wxNOT_FOUND || selected >= static_cast(m_visible_items.size())) return; - auto text = GetItemText(selected, ColumnAddress); - text = "0x" + text; -#if BOOST_OS_WINDOWS - if (OpenClipboard(nullptr)) + if (wxClipboard::Get()->Open()) { - EmptyClipboard(); - const HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, text.size()+1); - if (hGlobal) - { - memcpy(GlobalLock(hGlobal), text.c_str(), text.size() + 1); - GlobalUnlock(hGlobal); - - SetClipboardData(CF_TEXT, hGlobal); - GlobalFree(hGlobal); - } - CloseClipboard(); + wxClipboard::Get()->SetData(new wxTextDataObject(wxString::Format("0x%08x", m_visible_items[selected]->first))); + wxClipboard::Get()->Close(); } -#endif +} + +void SymbolListCtrl::RebuildVisibleItems() +{ + m_visible_items.clear(); + m_visible_items.reserve(m_data.size()); + const bool has_filter = !m_list_filter.IsEmpty(); + for (auto it = m_data.cbegin(); it != m_data.cend(); ++it) + { + if (has_filter && !it->second.searchName.Contains(m_list_filter)) + continue; + + m_visible_items.emplace_back(it); + } + + SetItemCount(static_cast(m_visible_items.size())); + if (!m_visible_items.empty()) + { + const auto top_item = std::min(GetTopItem(), static_cast(m_visible_items.size() - 1)); + RefreshItems(top_item, std::min(static_cast(m_visible_items.size() - 1), top_item + GetCountPerPage() + 1)); + } + else + Refresh(); } void SymbolListCtrl::ChangeListFilter(wxString filter) { m_list_filter = filter.MakeLower(); - - size_t visible_entries = m_data.size(); - for (auto& [address, symbol] : m_data) - { - if (m_list_filter.IsEmpty()) - symbol.visible = true; - else if (symbol.searchName.Contains(m_list_filter)) - symbol.visible = true; - else - { - visible_entries--; - symbol.visible = false; - } - } - SetItemCount(visible_entries); - if (visible_entries > 0) - RefreshItems(GetTopItem(), std::min(visible_entries - 1, GetTopItem() + GetCountPerPage() + 1)); + RebuildVisibleItems(); } diff --git a/src/gui/wxgui/debugger/SymbolCtrl.h b/src/gui/wxgui/debugger/SymbolCtrl.h index cb592ee7..938361c0 100644 --- a/src/gui/wxgui/debugger/SymbolCtrl.h +++ b/src/gui/wxgui/debugger/SymbolCtrl.h @@ -10,22 +10,23 @@ public: void ChangeListFilter(wxString filter); - private: +private: struct SymbolItem { - SymbolItem() = default; - SymbolItem(wxString name, wxString libName, wxString searchName, bool visible) : name(name), libName(libName), searchName(searchName), visible(visible) {} - + SymbolItem() = default; + SymbolItem(const wxString& name, const wxString& libName, const wxString& searchName) : name(name), libName(libName), searchName(searchName) {} wxString name; wxString libName; wxString searchName; - bool visible; }; + using SymbolMap = std::map; - std::map m_data; + SymbolMap m_data; wxString m_list_filter; + std::vector m_visible_items; - wxString OnGetItemText(long item, long column) const; + wxString OnGetItemText(long item, long column) const override; + void RebuildVisibleItems(); void OnLeftDClick(wxListEvent& event); void OnRightClick(wxListEvent& event); }; diff --git a/src/gui/wxgui/windows/TextureRelationViewer/TextureRelationWindow.cpp b/src/gui/wxgui/windows/TextureRelationViewer/TextureRelationWindow.cpp index 52f9b19e..b49adb14 100644 --- a/src/gui/wxgui/windows/TextureRelationViewer/TextureRelationWindow.cpp +++ b/src/gui/wxgui/windows/TextureRelationViewer/TextureRelationWindow.cpp @@ -244,7 +244,7 @@ void TextureRelationViewerWindow::_setTextureRelationListItemTexture(wxListCtrl* uiList->SetItem(rowIndex, columnIndex, texInfo->mipLevels == 1 ? "1 mip" : wxString::Format("%d mips", texInfo->mipLevels)); columnIndex++; // last access - uiList->SetItem(rowIndex, columnIndex, wxString::Format("%lus", (GetTickCount() - texInfo->lastAccessTick + 499) / 1000)); + uiList->SetItem(rowIndex, columnIndex, wxString::Format("%uus", (GetTickCount() - texInfo->lastAccessTick + 499) / 1000)); columnIndex++; // overwrite resolution wxString overwriteResLabel; diff --git a/src/input/InputManager.cpp b/src/input/InputManager.cpp index 071b43dc..44973d8d 100644 --- a/src/input/InputManager.cpp +++ b/src/input/InputManager.cpp @@ -696,7 +696,7 @@ std::shared_ptr InputManager::get_vpad_controller(size_t index) return {}; std::shared_lock lock(m_mutex); - return std::static_pointer_cast(m_vpad[index]); + return std::dynamic_pointer_cast(m_vpad[index]); } std::shared_ptr InputManager::get_wpad_controller(size_t index) const @@ -705,7 +705,7 @@ std::shared_ptr InputManager::get_wpad_controller(size_t index) return {}; std::shared_lock lock(m_mutex); - return std::static_pointer_cast(m_wpad[index]); + return std::dynamic_pointer_cast(m_wpad[index]); } std::pair InputManager::get_controller_count() const diff --git a/src/input/emulated/EmulatedController.cpp b/src/input/emulated/EmulatedController.cpp index ad9b6ac1..bfb94b9a 100644 --- a/src/input/emulated/EmulatedController.cpp +++ b/src/input/emulated/EmulatedController.cpp @@ -263,6 +263,7 @@ void EmulatedController::clear_controllers() float EmulatedController::get_axis_value(uint64 mapping) const { + std::shared_lock lock(m_mutex); const auto it = m_mappings.find(mapping); if (it != m_mappings.cend()) { @@ -276,6 +277,7 @@ float EmulatedController::get_axis_value(uint64 mapping) const bool EmulatedController::is_mapping_down(uint64 mapping) const { + std::shared_lock lock(m_mutex); const auto it = m_mappings.find(mapping); if (it != m_mappings.cend()) { @@ -288,6 +290,7 @@ bool EmulatedController::is_mapping_down(uint64 mapping) const std::string EmulatedController::get_mapping_name(uint64 mapping) const { + std::shared_lock lock(m_mutex); const auto it = m_mappings.find(mapping); if (it != m_mappings.cend()) { @@ -301,6 +304,7 @@ std::string EmulatedController::get_mapping_name(uint64 mapping) const std::shared_ptr EmulatedController::get_mapping_controller(uint64 mapping) const { + std::shared_lock lock(m_mutex); const auto it = m_mappings.find(mapping); if (it != m_mappings.cend()) { @@ -314,17 +318,20 @@ std::shared_ptr EmulatedController::get_mapping_controller(uint6 void EmulatedController::delete_mapping(uint64 mapping) { + std::scoped_lock lock(m_mutex); m_mappings.erase(mapping); } void EmulatedController::clear_mappings() { + std::scoped_lock lock(m_mutex); m_mappings.clear(); } void EmulatedController::set_mapping(uint64 mapping, const std::shared_ptr& controller, uint64 button) { + std::scoped_lock lock(m_mutex); m_mappings[mapping] = { controller, button }; } diff --git a/vcpkg.json b/vcpkg.json index 576c7b27..3687d2b3 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -76,7 +76,7 @@ }, { "name": "sdl3", - "version": "3.4.2" + "version": "3.4.10" }, { "name": "wxwidgets",