diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 7eab85ade5..a08bd2d828 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -1363,12 +1363,13 @@ void OpenGLContext::BindPipeline(Pipeline *pipeline) { } void OpenGLContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) { - if (curPipeline_->dynamicUniforms.uniformBufferSize != size) { + const auto &dynamicUniforms = curPipeline_->dynamicUniforms; + if (dynamicUniforms.uniformBufferSize != size) { Crash(); } - for (size_t i = 0; i < curPipeline_->dynamicUniforms.uniforms.size(); ++i) { - const auto &uniform = curPipeline_->dynamicUniforms.uniforms[i]; + for (size_t i = 0; i < dynamicUniforms.uniforms.size(); ++i) { + const auto &uniform = dynamicUniforms.uniforms[i]; const GLint &loc = curPipeline_->locs_->dynamicUniformLocs_[i]; const float *data = (const float *)((uint8_t *)ub + uniform.offset); switch (uniform.type) { diff --git a/Common/GPU/Vulkan/VulkanMemory.cpp b/Common/GPU/Vulkan/VulkanMemory.cpp index c853a5aa10..c18e9719da 100644 --- a/Common/GPU/Vulkan/VulkanMemory.cpp +++ b/Common/GPU/Vulkan/VulkanMemory.cpp @@ -118,8 +118,9 @@ void VulkanPushPool::BeginFrame() { // Still, let's keep around a few big ones (6 - 3). if (blocks_.size() > 6 && blocks_.back().lastUsed < now - PUSH_GARBAGE_COLLECTION_DELAY) { double start = time_now_d(); - size_t size = blocks_.back().size; - blocks_.back().Destroy(vulkan_); + Block &last = blocks_.back(); + size_t size = last.size; + last.Destroy(vulkan_); blocks_.pop_back(); DEBUG_LOG(Log::G3D, "%s: Garbage collected block of size %s in %0.2f ms", name_, NiceSizeFormat(size).c_str(), time_now_d() - start); } @@ -149,9 +150,10 @@ void VulkanPushPool::NextBlock(VkDeviceSize allocationSize) { // We're still here and ran off the end of blocks. Create a new one. blocks_.push_back(CreateBlock(newBlockSize)); - blocks_.back().frameIndex = curFrameIndex; - blocks_.back().used = allocationSize; - blocks_.back().lastUsed = time_now_d(); + Block &newBlock = blocks_.back(); + newBlock.frameIndex = curFrameIndex; + newBlock.used = allocationSize; + newBlock.lastUsed = time_now_d(); // curBlockIndex_ is already set correctly here. DEBUG_LOG(Log::G3D, "%s: Created new block of size %s in %0.2f ms", name_, NiceSizeFormat(newBlockSize).c_str(), 1000.0 * (time_now_d() - start)); } diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 93afd39957..e134b34d49 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -213,51 +213,54 @@ void VulkanQueueRunner::PreprocessSteps(std::vector &steps) { // substitute descriptors, alternatively using texture array layers creatively. for (int j = 0; j < (int)steps.size(); j++) { + decltype(steps[j]->render) &render = steps[j]->render; if (steps[j]->stepType == VKRStepType::RENDER && - steps[j]->render.framebuffer) { - if (steps[j]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) { - steps[j]->render.finalColorLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + render.framebuffer) { + if (render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) { + render.finalColorLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } - if (steps[j]->render.finalDepthStencilLayout == VK_IMAGE_LAYOUT_UNDEFINED) { - steps[j]->render.finalDepthStencilLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + if (render.finalDepthStencilLayout == VK_IMAGE_LAYOUT_UNDEFINED) { + render.finalDepthStencilLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } } } for (int j = 0; j < (int)steps.size() - 1; j++) { // Push down empty "Clear/Store" renderpasses, and merge them with the first "Load/Store" to the same framebuffer. + decltype(steps[j]->render) &render_j = steps[j]->render; if (steps.size() > 1 && steps[j]->stepType == VKRStepType::RENDER && - steps[j]->render.numDraws == 0 && - steps[j]->render.numReads == 0 && - steps[j]->render.colorLoad == VKRRenderPassLoadAction::CLEAR && - steps[j]->render.stencilLoad == VKRRenderPassLoadAction::CLEAR && - steps[j]->render.depthLoad == VKRRenderPassLoadAction::CLEAR) { + render_j.numDraws == 0 && + render_j.numReads == 0 && + render_j.colorLoad == VKRRenderPassLoadAction::CLEAR && + render_j.stencilLoad == VKRRenderPassLoadAction::CLEAR && + render_j.depthLoad == VKRRenderPassLoadAction::CLEAR) { // Drop the clear step, and merge it into the next step that touches the same framebuffer. for (int i = j + 1; i < (int)steps.size(); i++) { + decltype(steps[i]->render) &render_i = steps[i]->render; if (steps[i]->stepType == VKRStepType::RENDER && - steps[i]->render.framebuffer == steps[j]->render.framebuffer) { - if (steps[i]->render.colorLoad != VKRRenderPassLoadAction::CLEAR) { - steps[i]->render.colorLoad = VKRRenderPassLoadAction::CLEAR; - steps[i]->render.clearColor = steps[j]->render.clearColor; + render_i.framebuffer == render_j.framebuffer) { + if (render_i.colorLoad != VKRRenderPassLoadAction::CLEAR) { + render_i.colorLoad = VKRRenderPassLoadAction::CLEAR; + render_i.clearColor = render_j.clearColor; } - if (steps[i]->render.depthLoad != VKRRenderPassLoadAction::CLEAR) { - steps[i]->render.depthLoad = VKRRenderPassLoadAction::CLEAR; - steps[i]->render.clearDepth = steps[j]->render.clearDepth; + if (render_i.depthLoad != VKRRenderPassLoadAction::CLEAR) { + render_i.depthLoad = VKRRenderPassLoadAction::CLEAR; + render_i.clearDepth = render_j.clearDepth; } - if (steps[i]->render.stencilLoad != VKRRenderPassLoadAction::CLEAR) { - steps[i]->render.stencilLoad = VKRRenderPassLoadAction::CLEAR; - steps[i]->render.clearStencil = steps[j]->render.clearStencil; + if (render_i.stencilLoad != VKRRenderPassLoadAction::CLEAR) { + render_i.stencilLoad = VKRRenderPassLoadAction::CLEAR; + render_i.clearStencil = render_j.clearStencil; } - MergeRenderAreaRectInto(&steps[i]->render.renderArea, steps[j]->render.renderArea); - steps[i]->render.renderPassType = MergeRPTypes(steps[i]->render.renderPassType, steps[j]->render.renderPassType); - steps[i]->render.numDraws += steps[j]->render.numDraws; - steps[i]->render.numReads += steps[j]->render.numReads; + MergeRenderAreaRectInto(&render_i.renderArea, render_j.renderArea); + render_i.renderPassType = MergeRPTypes(render_i.renderPassType, render_j.renderPassType); + render_i.numDraws += render_j.numDraws; + render_i.numReads += render_j.numReads; // Cheaply skip the first step. steps[j]->stepType = VKRStepType::RENDER_SKIP; break; } else if (steps[i]->stepType == VKRStepType::COPY && - steps[i]->copy.src == steps[j]->render.framebuffer) { + steps[i]->copy.src == render_j.framebuffer) { // Can't eliminate the clear if a game copies from it before it's // rendered to. However this should be rare. // TODO: This should never happen when we check numReads now. @@ -404,17 +407,19 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector &steps) { for (int i = 0; i < (int)steps.size() - 3; i++) { int last = -1; + const decltype(steps[i + 1]->render) &render_i_plus_1 = steps[i + 1]->render; if (!(steps[i]->stepType == VKRStepType::COPY && steps[i + 1]->stepType == VKRStepType::RENDER && steps[i + 2]->stepType == VKRStepType::COPY && - steps[i + 1]->render.numDraws == 1 && + render_i_plus_1.numDraws == 1 && steps[i]->copy.dst == steps[i + 2]->copy.dst)) continue; // Looks promising! Let's start by finding the last one. for (int j = i; j < (int)steps.size(); j++) { + const decltype(steps[j]->render) &render_j = steps[j]->render; switch (steps[j]->stepType) { case VKRStepType::RENDER: - if (steps[j]->render.numDraws > 1) + if (render_j.numDraws > 1) last = j - 1; // should really also check descriptor sets... if (steps[j]->commands.size()) { @@ -480,41 +485,45 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector &steps) { // of the game. for (int i = 0; i < (int)steps.size() - 3; i++) { int last = -1; + const decltype(steps[i]->render) &render_i = steps[i]->render; + const decltype(steps[i + 1]->render) &render_i_plus_1 = steps[i + 1]->render; + const decltype(steps[i + 2]->render) &render_i_plus_2 = steps[i + 2]->render; if (!(steps[i]->stepType == VKRStepType::RENDER && steps[i + 1]->stepType == VKRStepType::RENDER && steps[i + 2]->stepType == VKRStepType::RENDER && - steps[i]->render.numDraws == 1 && - steps[i + 1]->render.numDraws == 1 && - steps[i + 2]->render.numDraws == 1 && - steps[i]->render.colorLoad == VKRRenderPassLoadAction::DONT_CARE && - steps[i + 1]->render.colorLoad == VKRRenderPassLoadAction::KEEP && - steps[i + 2]->render.colorLoad == VKRRenderPassLoadAction::DONT_CARE)) { + render_i.numDraws == 1 && + render_i_plus_1.numDraws == 1 && + render_i_plus_2.numDraws == 1 && + render_i.colorLoad == VKRRenderPassLoadAction::DONT_CARE && + render_i_plus_1.colorLoad == VKRRenderPassLoadAction::KEEP && + render_i_plus_2.colorLoad == VKRRenderPassLoadAction::DONT_CARE)) { continue; } - VKRFramebuffer *depalFramebuffer = steps[i]->render.framebuffer; - VKRFramebuffer *targetFramebuffer = steps[i + 1]->render.framebuffer; + VKRFramebuffer *depalFramebuffer = render_i.framebuffer; + VKRFramebuffer *targetFramebuffer = render_i_plus_1.framebuffer; // OK, found the start of a post-process sequence. Let's scan until we find the end. for (int j = i; j < (int)steps.size() - 3; j++) { + const decltype(steps[j]->render) &render_j = steps[j]->render; if (((j - i) & 1) == 0) { // This should be a depal draw. - if (steps[j]->render.numDraws != 1) + if (render_j.numDraws != 1) break; - if (steps[j]->commands.size() > 5) // TODO: Not the greatest heuristic! This may change if we merge commands. + if (steps[j]->commands.size() > 5) break; - if (steps[j]->render.colorLoad != VKRRenderPassLoadAction::DONT_CARE) + if (render_j.colorLoad != VKRRenderPassLoadAction::DONT_CARE) break; - if (steps[j]->render.framebuffer != depalFramebuffer) + if (render_j.framebuffer != depalFramebuffer) break; last = j; } else { // This should be a target draw. - if (steps[j]->render.numDraws != 1) + if (render_j.numDraws != 1) break; - if (steps[j]->commands.size() > 5) // TODO: Not the greatest heuristic! This may change if we merge commands. + if (steps[j]->commands.size() > 5) break; - if (steps[j]->render.colorLoad != VKRRenderPassLoadAction::KEEP) + if (render_j.colorLoad != VKRRenderPassLoadAction::KEEP) break; - if (steps[j]->render.framebuffer != targetFramebuffer) + if (render_j.framebuffer != targetFramebuffer) break; last = j; } @@ -536,6 +545,7 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector &steps) { // Combine the depal renders. Also record scissor bounds. for (int j = i + 2; j <= last + 1; j += 2) { + const decltype(steps[j]->render) &render_j = steps[j]->render; for (int k = 0; k < (int)steps[j]->commands.size(); k++) { switch (steps[j]->commands[k].cmd) { case VKRRenderCommand::DRAW: @@ -564,7 +574,7 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector &steps) { break; } } - MergeRenderAreaRectInto(&steps[i]->render.renderArea, steps[j]->render.renderArea); + MergeRenderAreaRectInto(&steps[i]->render.renderArea, render_j.renderArea); steps[j]->stepType = VKRStepType::RENDER_SKIP; } @@ -586,6 +596,7 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector &steps) { // Combine the target renders. for (int j = i + 3; j <= last; j += 2) { + const decltype(steps[j]->render) &render_j = steps[j]->render; for (int k = 0; k < (int)steps[j]->commands.size(); k++) { switch (steps[j]->commands[k].cmd) { case VKRRenderCommand::DRAW: @@ -596,7 +607,7 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector &steps) { break; } } - MergeRenderAreaRectInto(&steps[i + 1]->render.renderArea, steps[j]->render.renderArea); + MergeRenderAreaRectInto(&steps[i + 1]->render.renderArea, render_j.renderArea); steps[j]->stepType = VKRStepType::RENDER_SKIP; } @@ -613,35 +624,39 @@ void VulkanQueueRunner::ApplySonicHack(std::vector &steps) { for (int i = 0; i < (int)steps.size() - 4; i++) { int last = -1; + const decltype(steps[i]->render) &render_i = steps[i]->render; + const decltype(steps[i + 1]->render) &render_i_plus_1 = steps[i + 1]->render; + const decltype(steps[i + 2]->render) &render_i_plus_2 = steps[i + 2]->render; + const decltype(steps[i + 3]->render) &render_i_plus_3 = steps[i + 3]->render; if (!(steps[i]->stepType == VKRStepType::RENDER && steps[i + 1]->stepType == VKRStepType::RENDER && steps[i + 2]->stepType == VKRStepType::RENDER && steps[i + 3]->stepType == VKRStepType::RENDER && - steps[i]->render.numDraws == 3 && - steps[i + 1]->render.numDraws == 1 && - steps[i + 2]->render.numDraws == 6 && - steps[i + 3]->render.numDraws == 1 && - steps[i]->render.framebuffer == steps[i + 2]->render.framebuffer && - steps[i + 1]->render.framebuffer == steps[i + 3]->render.framebuffer)) + render_i.numDraws == 3 && + render_i_plus_1.numDraws == 1 && + render_i_plus_2.numDraws == 6 && + render_i_plus_3.numDraws == 1 && + render_i.framebuffer == render_i_plus_2.framebuffer && + render_i_plus_1.framebuffer == render_i_plus_3.framebuffer)) continue; // Looks promising! Let's start by finding the last one. for (int j = i; j < (int)steps.size(); j++) { - switch (steps[j]->stepType) { - case VKRStepType::RENDER: + const decltype(steps[j]->render) &render_j = steps[j]->render; + if (steps[j]->stepType == VKRStepType::RENDER) { if ((j - i) & 1) { - if (steps[j]->render.framebuffer != steps[i + 1]->render.framebuffer) + if (render_j.framebuffer != render_i_plus_1.framebuffer) last = j - 1; - if (steps[j]->render.numDraws != 1) + if (render_j.numDraws != 1) last = j - 1; } else { - if (steps[j]->render.framebuffer != steps[i]->render.framebuffer) + if (render_j.framebuffer != render_i.framebuffer) last = j - 1; - if (steps[j]->render.numDraws != 3 && steps[j]->render.numDraws != 6) + if (render_j.numDraws != 3 && render_j.numDraws != 6) last = j - 1; } - break; - default: - break; + } else { + // Not a render step, so break. + last = j - 1; } if (last != -1) break; @@ -769,8 +784,9 @@ void VulkanQueueRunner::ApplyRenderPassMerge(std::vector &steps) { // Now, let's go through the steps. If we find one that is rendered to more than once, // we'll scan forward and slurp up any rendering that can be merged across. for (int i = 0; i < (int)steps.size(); i++) { - if (steps[i]->stepType == VKRStepType::RENDER && counts[steps[i]->render.framebuffer] > 1) { - auto fb = steps[i]->render.framebuffer; + decltype(steps[i]->render) &render_i = steps[i]->render; + if (steps[i]->stepType == VKRStepType::RENDER && counts[render_i.framebuffer] > 1) { + auto fb = render_i.framebuffer; TinySet touchedFramebuffers; // must be the same fast-size as the dependencies TinySet for annoying reasons. for (int j = i + 1; j < (int)steps.size(); j++) { // If any other passes are reading from this framebuffer as-is, we cancel the scan. @@ -890,7 +906,8 @@ void VulkanQueueRunner::LogRenderPass(const VKRStep &pass, bool verbose) { INFO_LOG(Log::G3D, "RENDER %s Begin(%s, draws: %d, %dx%d, %s, %s, %s)", pass.tag, framebuf, r.numDraws, w, h, RenderPassActionName(r.colorLoad), RenderPassActionName(r.depthLoad), RenderPassActionName(r.stencilLoad)); // TODO: Log these in detail. for (int i = 0; i < (int)pass.preTransitions.size(); i++) { - INFO_LOG(Log::G3D, " PRETRANSITION: %s %s -> %s", pass.preTransitions[i].fb->Tag(), AspectToString(pass.preTransitions[i].aspect), ImageLayoutToString(pass.preTransitions[i].targetLayout)); + const TransitionRequest &preTransition = pass.preTransitions[i]; + INFO_LOG(Log::G3D, " PRETRANSITION: %s %s -> %s", preTransition.fb->Tag(), AspectToString(preTransition.aspect), ImageLayoutToString(preTransition.targetLayout)); } if (verbose) { @@ -1871,4 +1888,4 @@ const char *VKRRenderCommandToString(VKRRenderCommand cmd) { } else { return "N/A"; } -} +} \ No newline at end of file diff --git a/Common/UI/IconCache.cpp b/Common/UI/IconCache.cpp index 6b2db7f201..85e0270097 100644 --- a/Common/UI/IconCache.cpp +++ b/Common/UI/IconCache.cpp @@ -47,12 +47,13 @@ void IconCache::SaveToFile(FILE *file) { for (auto &iter : cache_) { DiskCacheEntry entryHeader{}; entryHeader.keyLen = (uint32_t)iter.first.size(); - entryHeader.dataLen = (uint32_t)iter.second.data.size(); - entryHeader.format = iter.second.format; - entryHeader.insertedTimestamp = iter.second.insertedTimeStamp; + const auto &entry = iter.second; + entryHeader.dataLen = (uint32_t)entry.data.size(); + entryHeader.format = entry.format; + entryHeader.insertedTimestamp = entry.insertedTimeStamp; fwrite(&entryHeader, 1, sizeof(entryHeader), file); fwrite(iter.first.c_str(), 1, iter.first.size(), file); - fwrite(iter.second.data.data(), 1, iter.second.data.size(), file); + fwrite(entry.data.data(), 1, entry.data.size(), file); } } @@ -134,13 +135,14 @@ void IconCache::FrameUpdate() { double now = time_now_d(); if (now > lastUpdate_ + 2.0) { for (auto &iter : cache_) { - double useAge = now - iter.second.usedTimeStamp; + auto &entry = iter.second; + double useAge = now - entry.usedTimeStamp; if (useAge > 5.0) { // Release the texture after a few seconds of no use. // Still, keep the png data loaded, it's small. - if (iter.second.texture) { - iter.second.texture->Release(); - iter.second.texture = nullptr; + if (entry.texture) { + entry.texture->Release(); + entry.texture = nullptr; } } } @@ -175,7 +177,8 @@ void IconCache::Decimate(int64_t maxSize) { std::vector sortEntries; sortEntries.reserve(cache_.size()); for (const auto &iter : cache_) { - sortEntries.push_back({ iter.first, iter.second.usedTimeStamp, iter.second.data.size() }); + const auto &entry = iter.second; + sortEntries.push_back({ iter.first, entry.usedTimeStamp, entry.data.size() }); } std::sort(sortEntries.begin(), sortEntries.end(), [](const SortEntry &a, const SortEntry &b) { @@ -204,10 +207,11 @@ bool IconCache::GetDimensions(std::string_view key, int *width, int *height) { return false; } - if (iter->second.texture) { + const auto &entry = iter->second; + if (entry.texture) { // TODO: Store the width/height in the cache. - *width = iter->second.texture->Width(); - *height = iter->second.texture->Height(); + *width = entry.texture->Width(); + *height = entry.texture->Height(); return true; } else { return false; @@ -286,13 +290,15 @@ Draw::Texture *IconCache::BindIconTexture(UIContext *context, std::string_view k return nullptr; } - if (iter->second.texture) { - context->GetDrawContext()->BindTexture(0, iter->second.texture); - iter->second.usedTimeStamp = time_now_d(); - return iter->second.texture; + auto &entry = iter->second; + + if (entry.texture) { + context->GetDrawContext()->BindTexture(0, entry.texture); + entry.usedTimeStamp = time_now_d(); + return entry.texture; } - if (iter->second.badData) { + if (entry.badData) { return nullptr; } @@ -302,15 +308,15 @@ Draw::Texture *IconCache::BindIconTexture(UIContext *context, std::string_view k Draw::DataFormat dataFormat; unsigned char *buffer = nullptr; - switch (iter->second.format) { + switch (entry.format) { case IconFormat::PNG: { - int result = pngLoadPtr((const unsigned char *)iter->second.data.data(), iter->second.data.size(), &width, - &height, &buffer); + const std::string &data = entry.data; + int result = pngLoadPtr((const unsigned char *)data.data(), data.size(), &width, &height, &buffer); if (result != 1) { - ERROR_LOG(Log::G3D, "IconCache: Failed to load png (%d bytes) for key %.*s", (int)iter->second.data.size(), STR_VIEW(key)); - iter->second.badData = true; + ERROR_LOG(Log::G3D, "IconCache: Failed to load png (%d bytes) for key %.*s", (int)data.size(), STR_VIEW(key)); + entry.badData = true; return nullptr; } dataFormat = Draw::DataFormat::R8G8B8A8_UNORM; @@ -333,8 +339,8 @@ Draw::Texture *IconCache::BindIconTexture(UIContext *context, std::string_view k iconDesc.type = Draw::TextureType::LINEAR2D; Draw::Texture *texture = context->GetDrawContext()->CreateTexture(iconDesc); - iter->second.texture = texture; - iter->second.usedTimeStamp = time_now_d(); + entry.texture = texture; + entry.usedTimeStamp = time_now_d(); free(buffer); @@ -348,9 +354,10 @@ IconCacheStats IconCache::GetStats() { for (auto &iter : cache_) { stats.cachedCount++; - if (iter.second.texture) + const auto &entry = iter.second; + if (entry.texture) stats.textureCount++; - stats.dataSize += iter.second.data.size(); + stats.dataSize += entry.data.size(); } stats.pending = pending_.size(); diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index 480a4c667f..6c379d75fe 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -198,7 +198,7 @@ namespace MainWindow { wcex.hInstance = hInstance; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // or NULL? - wcex.lpszMenuName = (LPCWSTR)IDR_MENU1; + wcex.lpszMenuName = g_Config.bShowMenuBar ? (LPCWSTR)IDR_MENU1 : NULL; wcex.lpszClassName = szWindowClass; wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_PPSSPP); wcex.hIconSm = (HICON)LoadImage(hInstance, (LPCTSTR)IDI_PPSSPP, IMAGE_ICON, 16, 16, LR_SHARED); @@ -375,7 +375,9 @@ namespace MainWindow { // Transitioning to Windowed SetWindowLong(hWnd, GWL_STYLE, (prevStyle & ~WS_POPUP) | WS_OVERLAPPEDWINDOW); - SetMenu(hWnd, g_hMenu); + if (g_Config.bShowMenuBar) { + SetMenu(hWnd, g_hMenu); + } WINDOWPLACEMENT wp = {sizeof(WINDOWPLACEMENT)}; wp.showCmd = WindowSizeStateToShowCmd((WindowSizeState)g_Config.iWindowSizeState); @@ -529,7 +531,10 @@ namespace MainWindow { DwmSetWindowAttribute(hwndMain, DWMWA_WINDOW_CORNER_PREFERENCE, &pref, sizeof(pref)); ApplyFullscreenState(hwndMain, g_Config.bFullScreen); - MainMenuInit(hwndMain, g_hMenu); + if (!g_Config.bShowMenuBar) { + MainMenuInit(hwndMain, g_hMenu); + SetMenu(hwndMain, NULL); + } // Accept dragged files. DragAcceptFiles(hwndMain, TRUE); @@ -909,7 +914,7 @@ namespace MainWindow { // and recalculate window decorations without actually changing the size of the window). if (pos->cx != monWidth || pos->cy != monHeight) { g_Config.bFullScreen = false; - if (GetMenu(hWnd) == NULL) { + if (GetMenu(hWnd) == NULL && g_Config.bShowMenuBar) { SetMenu(hWnd, g_hMenu); } const DWORD style = GetWindowLong(hWnd, GWL_STYLE);