From 77c6a56290078b1ba84f25e1f468f4237edb99e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 Nov 2017 00:01:44 +0100 Subject: [PATCH 01/27] Update the README for 1.5. --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index f1ce17e963..93556856c7 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,20 @@ For the latest source code, see [our github page](https://github.com/hrydgard/pp For build instructions and other development tutorials, see the [wiki](https://github.com/hrydgard/ppsspp/wiki). + +What's new in 1.5.0 +------------------- +* Multithreaded Vulkan support, now fully featured and FAST. +* Vulkan support for Android. Very fast compared to OpenGL. +* Smarter graphics state management, reduced CPU consumption on all backends +* Geometry problems fixed in Medal of Honor +* Android: Support for Arabic and other scripts we couldn't support before +* Fix Android widgets, screen scaling +* Fixes to video dumping +* Software rendering improvements, speed and accuracy +* Hardware tesselation of PSP Beziers and Splines (used by a few games) +* Partial sceUsbGps and sceUsbCam support (Android) + What's new in 1.4.2 ------------------- * Fixed longstanding bug causing games to crash on ARM64 From 23b0d6304de52893bc357880b3f1243a55919699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 Nov 2017 09:46:21 +0100 Subject: [PATCH 02/27] More 1.5 README fixes --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 93556856c7..8a7a5dc2bc 100644 --- a/README.md +++ b/README.md @@ -21,16 +21,19 @@ For build instructions and other development tutorials, see the [wiki](https://g What's new in 1.5.0 ------------------- -* Multithreaded Vulkan support, now fully featured and FAST. -* Vulkan support for Android. Very fast compared to OpenGL. -* Smarter graphics state management, reduced CPU consumption on all backends +* Multithreaded Vulkan support, now fully featured and FAST on supported devices. (#10033, #10049) +* Vulkan support now enabled for Android. +* Smarter graphics state management, reduced CPU consumption on all backends (#9899) * Geometry problems fixed in Medal of Honor * Android: Support for Arabic and other scripts we couldn't support before -* Fix Android widgets, screen scaling +* Fix Android widgets, screen scaling (#10145) * Fixes to video dumping * Software rendering improvements, speed and accuracy * Hardware tesselation of PSP Beziers and Splines (used by a few games) * Partial sceUsbGps and sceUsbCam support (Android) +* Android "Sustained performance mode" to avoid thermal throttling (#9901) +* Assorted bugfixes and compatibility improvements +* Linux controller mapping fixes (#9997) What's new in 1.4.2 ------------------- From b6ef91363b1da5d0259cd23cc708762158f4392d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 27 Nov 2017 13:42:53 +0100 Subject: [PATCH 03/27] More README updates --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8a7a5dc2bc..75b4c04aaa 100644 --- a/README.md +++ b/README.md @@ -22,18 +22,19 @@ For build instructions and other development tutorials, see the [wiki](https://g What's new in 1.5.0 ------------------- * Multithreaded Vulkan support, now fully featured and FAST on supported devices. (#10033, #10049) -* Vulkan support now enabled for Android. +* Vulkan support now enabled for Android. Recommended if available! * Smarter graphics state management, reduced CPU consumption on all backends (#9899) -* Geometry problems fixed in Medal of Honor * Android: Support for Arabic and other scripts we couldn't support before * Fix Android widgets, screen scaling (#10145) * Fixes to video dumping +* Geometry problems fixed in Medal of Honor +* Implement immediate draws, fixing Thrillville (#7459) * Software rendering improvements, speed and accuracy * Hardware tesselation of PSP Beziers and Splines (used by a few games) * Partial sceUsbGps and sceUsbCam support (Android) * Android "Sustained performance mode" to avoid thermal throttling (#9901) -* Assorted bugfixes and compatibility improvements * Linux controller mapping fixes (#9997) +* Assorted bugfixes and compatibility improvements What's new in 1.4.2 ------------------- From 2c1496f2f6ab71eed8bb05d78224b0602d3f533c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 28 Nov 2017 10:54:48 +0100 Subject: [PATCH 04/27] Readme for 1.5: Small rewording --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 75b4c04aaa..a850967b68 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,7 @@ For build instructions and other development tutorials, see the [wiki](https://g What's new in 1.5.0 ------------------- -* Multithreaded Vulkan support, now fully featured and FAST on supported devices. (#10033, #10049) -* Vulkan support now enabled for Android. Recommended if available! +* Full Vulkan support, also for Android now. Very fast on supported devices. (#10033, #10049) * Smarter graphics state management, reduced CPU consumption on all backends (#9899) * Android: Support for Arabic and other scripts we couldn't support before * Fix Android widgets, screen scaling (#10145) From 598514189f2dd7501e0878c71119c406dee8a0d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 29 Nov 2017 12:17:32 +0100 Subject: [PATCH 05/27] Update lang submodule --- assets/lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/lang b/assets/lang index 4fddbc9d30..c37028e6b6 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit 4fddbc9d3032113bdfed5186de73545e19340b4f +Subproject commit c37028e6b60e416ca52382ae8fdd76b6e77bede7 From bdbe2549d0ca8c6c494e41a46964c4edbaac2d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 29 Nov 2017 12:19:11 +0100 Subject: [PATCH 06/27] Update AndroidManifest.xml to 1.5.0 --- android/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 8ef8b5c6a5..e145a623e2 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="15000000" + android:versionName="1.5.0.0"> Date: Wed, 29 Nov 2017 14:33:28 +0100 Subject: [PATCH 07/27] Add privacy policy link to app, as required by Google Play since we use the CAMERA permission now. --- UI/MiscScreens.cpp | 6 ++++++ UI/MiscScreens.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 272201c143..b3b6c56151 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -534,6 +534,7 @@ void CreditsScreen::CreateViews() { } root_->Add(new Button(cr->T("PPSSPP Forums"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 84, false)))->OnClick.Handle(this, &CreditsScreen::OnForums); root_->Add(new Button("www.ppsspp.org", new AnchorLayoutParams(260, 64, 10, NONE, NONE, 158, false)))->OnClick.Handle(this, &CreditsScreen::OnPPSSPPOrg); + root_->Add(new Button(cr->T("Privacy Policy"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 232, false)))->OnClick.Handle(this, &CreditsScreen::OnPrivacy); #ifdef __ANDROID__ root_->Add(new Button(cr->T("Share PPSSPP"), new AnchorLayoutParams(260, 64, NONE, NONE, 10, 84, false)))->OnClick.Handle(this, &CreditsScreen::OnShare); root_->Add(new Button(cr->T("Twitter @PPSSPP_emu"), new AnchorLayoutParams(260, 64, NONE, NONE, 10, 154, false)))->OnClick.Handle(this, &CreditsScreen::OnTwitter); @@ -568,6 +569,11 @@ UI::EventReturn CreditsScreen::OnPPSSPPOrg(UI::EventParams &e) { return UI::EVENT_DONE; } +UI::EventReturn CreditsScreen::OnPrivacy(UI::EventParams &e) { + LaunchBrowser("https://www.ppsspp.org/privacy.html"); + return UI::EVENT_DONE; +} + UI::EventReturn CreditsScreen::OnForums(UI::EventParams &e) { LaunchBrowser("https://forums.ppsspp.org"); return UI::EVENT_DONE; diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index d189121d7d..9e412d932b 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -142,8 +142,8 @@ private: UI::EventReturn OnSupport(UI::EventParams &e); UI::EventReturn OnPPSSPPOrg(UI::EventParams &e); + UI::EventReturn OnPrivacy(UI::EventParams &e); UI::EventReturn OnForums(UI::EventParams &e); - UI::EventReturn OnChineseForum(UI::EventParams &e); UI::EventReturn OnShare(UI::EventParams &e); UI::EventReturn OnTwitter(UI::EventParams &e); From e9303fd1cdf8490f2cc56d201b25480538366c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 29 Nov 2017 15:44:16 +0100 Subject: [PATCH 08/27] Try to get androidgitversion to behave. It thinks the build is dirty when it's not. --- android/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 9d9bb9c4d1..dd2e9ecc3c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gladed.androidgitversion' version '0.3.4' + id 'com.gladed.androidgitversion' version '0.4.3' } apply plugin: 'com.android.application' @@ -7,6 +7,7 @@ androidGitVersion { codeFormat = "MNPPBBBB" format = "%tag%%-count%%-branch%%-dirty%" prefix = "v" // Only tags beginning with v are considered. + untrackedIsDirty = false } android { From 6ea669368c147d517cbde6915cfc8f48ef5b672d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 29 Nov 2017 18:53:52 +0100 Subject: [PATCH 09/27] Crash reports from 5% rollout of 1.5: Make some asserts dbg_asserts for now, try to fix an issue with framebuffers when postproc is enabled. --- Core/HLE/HLE.cpp | 4 ++-- GPU/Common/FramebufferCommon.cpp | 5 ++++- GPU/GLES/FramebufferManagerGLES.cpp | 1 - UI/NativeApp.cpp | 5 ++++- android/jni/app-android.cpp | 1 + ext/native/base/NativeApp.h | 2 +- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index e36a8c4109..8b63cfc401 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -635,7 +635,7 @@ size_t hleFormatLogArgs(char *message, size_t sz, const char *argmask) { // TODO: Double? Does it ever happen? default: - _assert_msg_(HLE, false, "Invalid argmask character: %c", argmask[i]); + _dbg_assert_msg_(HLE, false, "Invalid argmask character: %c", argmask[i]); APPEND_FMT(" -- invalid arg format: %c -- %08x", argmask[i], regval); break; } @@ -673,7 +673,7 @@ void hleDoLogInternal(LogTypes::LOG_TYPE t, LogTypes::LOG_LEVELS level, u64 res, // TODO: For now, floats are just shown as bits. fmt = "%s%08x=%s(%s)%s"; } else { - _assert_msg_(HLE, false, "Invalid return format: %c", retmask); + _dbg_assert_msg_(HLE, false, "Invalid return format: %c", retmask); fmt = "%s%08llx=%s(%s)%s"; } diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 66d01f0e84..b0b2ac7eea 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -136,6 +136,8 @@ FramebufferManagerCommon::~FramebufferManagerCommon() { DestroyFramebuf(vfb); } bvfbs_.clear(); + + SetNumExtraFBOs(0); } void FramebufferManagerCommon::Init() { @@ -207,7 +209,8 @@ void FramebufferManagerCommon::SetNumExtraFBOs(int num) { extraFBOs_.push_back(fbo); } currentRenderVfb_ = 0; - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + if (num != 0) + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP }); } // Heuristics to figure out the size of FBO to create. diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index e62cc79463..9faa2a7622 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -250,7 +250,6 @@ FramebufferManagerGLES::~FramebufferManagerGLES() { if (stencilUploadProgram_) { glsl_destroy(stencilUploadProgram_); } - SetNumExtraFBOs(0); for (auto it = tempFBOs_.begin(), end = tempFBOs_.end(); it != end; ++it) { it->second.fbo->Release(); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 7667bcab39..a14699de59 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -613,12 +613,14 @@ static void UIThemeInit() { void RenderOverlays(UIContext *dc, void *userdata); -void NativeInitGraphics(GraphicsContext *graphicsContext) { +bool NativeInitGraphics(GraphicsContext *graphicsContext) { ILOG("NativeInitGraphics"); + _assert_msg_(G3D, graphicsContext, "No graphics context!"); using namespace Draw; Core_SetGraphicsContext(graphicsContext); g_draw = graphicsContext->GetDrawContext(); + _assert_msg_(G3D, g_draw, "No draw context available!"); ui_draw2d.SetAtlas(&ui_atlas); ui_draw2d_front.SetAtlas(&ui_atlas); @@ -694,6 +696,7 @@ void NativeInitGraphics(GraphicsContext *graphicsContext) { g_graphicsInited = true; ILOG("NativeInitGraphics completed"); + return true; } void NativeShutdownGraphics() { diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 44c4e7cef7..22b086cc0d 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -1139,6 +1139,7 @@ retry: } delete graphicsContext; + graphicsContext = nullptr; return false; } diff --git a/ext/native/base/NativeApp.h b/ext/native/base/NativeApp.h index 0db94e68d2..a4540dd869 100644 --- a/ext/native/base/NativeApp.h +++ b/ext/native/base/NativeApp.h @@ -49,7 +49,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch // Runs after NativeInit() at some point. May (and probably should) call OpenGL. // Should not initialize anything screen-size-dependent - do that in NativeResized. -void NativeInitGraphics(GraphicsContext *graphicsContext); +bool NativeInitGraphics(GraphicsContext *graphicsContext); // Signals that you need to forget all buffered OpenGL resources, // like textures, vbo etc. From bc959470e5eb5f5d0a3212988c26cc9c3f5a792b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 29 Nov 2017 19:07:07 +0100 Subject: [PATCH 10/27] Loosen up some asserts that seem to trigger unexpectedly... need investigation. --- GPU/Common/FramebufferCommon.cpp | 2 +- ext/native/thin3d/VulkanQueueRunner.cpp | 21 ++++++++++++--------- ext/native/thin3d/thin3d.cpp | 16 ++++++++++++++++ ext/native/thin3d/thin3d.h | 1 + 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index b0b2ac7eea..957ab9861e 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -200,7 +200,7 @@ bool FramebufferManagerCommon::ShouldDownloadFramebuffer(const VirtualFramebuffe void FramebufferManagerCommon::SetNumExtraFBOs(int num) { for (size_t i = 0; i < extraFBOs_.size(); i++) { - extraFBOs_[i]->Release(); + extraFBOs_[i]->ReleaseAssertLast(); } extraFBOs_.clear(); for (int i = 0; i < num; i++) { diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index eec033bc6e..d34cca692d 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -517,8 +517,8 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step // Now, if the image needs transitioning, let's transition. // The backbuffer does not, that's handled by VulkanContext. if (step.render.framebuffer->color.layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { - VkAccessFlags srcAccessMask; - VkPipelineStageFlags srcStage; + VkAccessFlags srcAccessMask = 0; + VkPipelineStageFlags srcStage = 0; switch (fb->color.layout) { case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: srcAccessMask = VK_ACCESS_SHADER_READ_BIT; @@ -533,7 +533,7 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; break; default: - Crash(); + _dbg_assert_msg_(G3D, false, "PerformBindRT: Unexpected color layout %d", (int)fb->color.layout); break; } @@ -545,8 +545,8 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step fb->color.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } if (fb->depth.layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { - VkAccessFlags srcAccessMask; - VkPipelineStageFlags srcStage; + VkAccessFlags srcAccessMask = 0; + VkPipelineStageFlags srcStage = 0; switch (fb->depth.layout) { case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: @@ -562,7 +562,7 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; break; default: - Crash(); + _dbg_assert_msg_(G3D, false, "PerformBindRT: Unexpected depth layout %d", (int)fb->color.layout); break; } @@ -791,7 +791,8 @@ void VulkanQueueRunner::SetupTransitionToTransferSrc(VKRImage &img, VkImageMemor stage |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; break; default: - Crash(); + _dbg_assert_msg_(G3D, false, "Transition from this layout to transfer src not supported (%d)", (int)img.layout); + break; } barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; @@ -826,7 +827,8 @@ void VulkanQueueRunner::SetupTransitionToTransferDst(VKRImage &img, VkImageMemor stage |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; break; default: - Crash(); + _dbg_assert_msg_(G3D, false, "Transition from this layout to transfer dst not supported (%d)", (int)img.layout); + break; } barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; @@ -869,7 +871,8 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd srcImage = &step.readback.src->depth; } else { - assert(false); + _dbg_assert_msg_(G3D, false, "No image aspect to readback?"); + return; } VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; diff --git a/ext/native/thin3d/thin3d.cpp b/ext/native/thin3d/thin3d.cpp index add987548d..0cde248021 100644 --- a/ext/native/thin3d/thin3d.cpp +++ b/ext/native/thin3d/thin3d.cpp @@ -4,6 +4,7 @@ #include "base/logging.h" #include "thin3d/thin3d.h" +#include "Common/Log.h" #include "Common/ColorConv.h" namespace Draw { @@ -75,11 +76,26 @@ bool RefCountedObject::Release() { } } else { + _dbg_assert_msg_(G3D, false, "Refcount (%d) invalid for object %p - corrupt?", refcount_, this); + } + return false; +} + +bool RefCountedObject::ReleaseAssertLast() { + _dbg_assert_msg_(G3D, refcount_ == 1, "RefCountedObject: Expected to be the last reference, but isn't!"); + if (refcount_ > 0 && refcount_ < 10000) { + refcount_--; + if (refcount_ == 0) { + delete this; + return true; + } + } else { ELOG("Refcount (%d) invalid for object %p - corrupt?", refcount_, this); } return false; } + // ================================== PIXEL/FRAGMENT SHADERS // The Vulkan ones can be re-used with modern GL later if desired, as they're just GLSL. diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 16f5493801..916cc97f7e 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -346,6 +346,7 @@ public: void AddRef() { refcount_++; } bool Release(); + bool ReleaseAssertLast(); private: int refcount_; From 5fff54e8046f913fc0f4e5e8cb94a8018658e2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 29 Nov 2017 19:15:08 +0100 Subject: [PATCH 11/27] Fix another possible Vulkan shutdown bug --- GPU/Vulkan/DrawEngineVulkan.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 82908e0048..73fb6afe4e 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -247,9 +247,11 @@ void DrawEngineVulkan::DestroyDeviceObjects() { delete nullTexture_; nullTexture_ = nullptr; } - vertexCache_->Destroy(vulkan_); - delete vertexCache_; - vertexCache_ = nullptr; + if (vertexCache_) { + vertexCache_->Destroy(vulkan_); + delete vertexCache_; + vertexCache_ = nullptr; + } // Need to clear this to get rid of all remaining references to the dead buffers. vai_.Iterate([](uint32_t hash, VertexArrayInfoVulkan *vai) { delete vai; From 51a6c675023727066190aa67ef0337bc2c3d4d1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 29 Nov 2017 19:29:53 +0100 Subject: [PATCH 12/27] Crash in a more appropriate place if missing a drawcontext (happens on really weak devices only) --- android/jni/app-android.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 22b086cc0d..8174b1ab53 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -742,6 +742,8 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, if (javaGL && !graphicsContext) { graphicsContext = new AndroidJavaEGLGraphicsContext(); + } else if (!graphicsContext) { + _assert_msg_(G3D, false, "No graphics context in displayInit?"); } if (renderer_inited) { @@ -750,7 +752,6 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, NativeShutdownGraphics(); NativeDeviceRestore(); NativeInitGraphics(graphicsContext); - ILOG("Restored."); } else { ILOG("NativeApp.displayInit() first time"); From 04913be779cf30a37196863bd92d9c701ee6137d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 29 Nov 2017 20:13:38 +0100 Subject: [PATCH 13/27] Move pushbuffer map/unmap to the .cpp file to avoid inlining (for stack traces) --- Common/Vulkan/VulkanMemory.cpp | 21 +++++++++++++++++++++ Common/Vulkan/VulkanMemory.h | 21 ++------------------- GPU/Vulkan/PipelineManagerVulkan.cpp | 3 +-- ext/native/thin3d/thin3d_vulkan.cpp | 1 - 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/Common/Vulkan/VulkanMemory.cpp b/Common/Vulkan/VulkanMemory.cpp index 67d300dc44..c46195db30 100644 --- a/Common/Vulkan/VulkanMemory.cpp +++ b/Common/Vulkan/VulkanMemory.cpp @@ -134,6 +134,27 @@ size_t VulkanPushBuffer::GetTotalSize() const { return sum; } +void VulkanPushBuffer::Map() { + assert(!writePtr_); + VkResult res = vkMapMemory(device_, buffers_[buf_].deviceMemory, 0, size_, 0, (void **)(&writePtr_)); + assert(writePtr_); + assert(VK_SUCCESS == res); +} + +void VulkanPushBuffer::Unmap() { + assert(writePtr_); + /* + // Should not need this since we use coherent memory. + VkMappedMemoryRange range = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE }; + range.offset = 0; + range.size = offset_; + range.memory = buffers_[buf_].deviceMemory; + vkFlushMappedMemoryRanges(device_, 1, &range); + */ + vkUnmapMemory(device_, buffers_[buf_].deviceMemory); + writePtr_ = nullptr; +} + VulkanDeviceAllocator::VulkanDeviceAllocator(VulkanContext *vulkan, size_t minSlabSize, size_t maxSlabSize) : vulkan_(vulkan), lastSlab_(0), minSlabSize_(minSlabSize), maxSlabSize_(maxSlabSize), memoryTypeIndex_(UNDEFINED_MEMORY_TYPE), destroyed_(false) { assert((minSlabSize_ & (SLAB_GRAIN_SIZE - 1)) == 0); diff --git a/Common/Vulkan/VulkanMemory.h b/Common/Vulkan/VulkanMemory.h index 96f5833340..15f09d1265 100644 --- a/Common/Vulkan/VulkanMemory.h +++ b/Common/Vulkan/VulkanMemory.h @@ -46,26 +46,9 @@ public: Unmap(); } - void Map() { - assert(!writePtr_); - VkResult res = vkMapMemory(device_, buffers_[buf_].deviceMemory, 0, size_, 0, (void **)(&writePtr_)); - assert(writePtr_); - assert(VK_SUCCESS == res); - } + void Map(); - void Unmap() { - assert(writePtr_); - /* - // Should not need this since we use coherent memory. - VkMappedMemoryRange range = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE }; - range.offset = 0; - range.size = offset_; - range.memory = buffers_[buf_].deviceMemory; - vkFlushMappedMemoryRanges(device_, 1, &range); - */ - vkUnmapMemory(device_, buffers_[buf_].deviceMemory); - writePtr_ = nullptr; - } + void Unmap(); // When using the returned memory, make sure to bind the returned vkbuf. // This will later allow for handling overflow correctly. diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 1b27f135b4..dbf3e1e130 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -301,8 +301,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) { VulkanPipelineKey key{}; - if (!renderPass) - Crash(); + _assert_msg_(G3D, renderPass, "Can't create a pipeline with a null renderpass"); key.raster = rasterKey; key.renderPass = renderPass; diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 0044b3f234..8e38776b6d 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -1298,7 +1298,6 @@ uint32_t VKContext::GetDataFormatSupport(DataFormat fmt) const { // use this frame's init command buffer. class VKFramebuffer : public Framebuffer { public: - // Inherits ownership so no AddRef. VKFramebuffer(VKRFramebuffer *fb) : buf_(fb) {} ~VKFramebuffer() { buf_->vulkan_->Delete().QueueCallback([](void *fb) { From 4129459495072e54d3e7f4c0a2628b7080aaab6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 29 Nov 2017 21:31:42 +0100 Subject: [PATCH 14/27] Avoid an assert in ARM64 emitter, seen in Google Play crash logs --- Common/Arm64Emitter.cpp | 6 ++++-- GPU/Common/VertexDecoderArm64.cpp | 7 ++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Common/Arm64Emitter.cpp b/Common/Arm64Emitter.cpp index 17771d19cc..b3ef8540db 100644 --- a/Common/Arm64Emitter.cpp +++ b/Common/Arm64Emitter.cpp @@ -733,9 +733,11 @@ void ARM64XEmitter::EncodeLoadStoreIndexedInst(u32 op, ARM64Reg Rt, ARM64Reg Rn, else if (size == 16) shift = 1; - _assert_msg_(DYNA_REC, ((imm >> shift) << shift) == imm, "%s(INDEX_UNSIGNED): offset must be aligned %d", __FUNCTION__, imm); + if (shift) { + _assert_msg_(DYNA_REC, ((imm >> shift) << shift) == imm, "%s(INDEX_UNSIGNED): offset must be aligned %d", __FUNCTION__, imm); + imm >>= shift; + } - imm >>= shift; _assert_msg_(DYNA_REC, imm >= 0, "%s(INDEX_UNSIGNED): offset must be positive %d", __FUNCTION__, imm); _assert_msg_(DYNA_REC, !(imm & ~0xFFF), "%s(INDEX_UNSIGNED): offset too large %d", __FUNCTION__, imm); diff --git a/GPU/Common/VertexDecoderArm64.cpp b/GPU/Common/VertexDecoderArm64.cpp index 37e3cb9bdd..0e31dd80c2 100644 --- a/GPU/Common/VertexDecoderArm64.cpp +++ b/GPU/Common/VertexDecoderArm64.cpp @@ -698,7 +698,12 @@ void VertexDecoderJitCache::Jit_PosS16Through() { } void VertexDecoderJitCache::Jit_NormalS8() { - LDRH(INDEX_UNSIGNED, tempReg1, srcReg, dec_->nrmoff); + // nrmoff can be odd in case of byte-only vertices! odd unsigned offsets are not allowed for LDRH. + // Switching to LDRB. + // Only seen this in a crash log. + LDRB(INDEX_UNSIGNED, tempReg1, srcReg, dec_->nrmoff); + LDRB(INDEX_UNSIGNED, tempReg3, srcReg, dec_->nrmoff + 1); + ORR(tempReg1, tempReg1, tempReg3, ArithOption(tempReg3, ST_LSL, 8)); LDRB(INDEX_UNSIGNED, tempReg3, srcReg, dec_->nrmoff + 2); ORR(tempReg1, tempReg1, tempReg3, ArithOption(tempReg3, ST_LSL, 16)); STR(INDEX_UNSIGNED, tempReg1, dstReg, dec_->decFmt.nrmoff); From 168d89284c146156b694cb73f8678387fda115b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 29 Nov 2017 22:14:01 +0100 Subject: [PATCH 15/27] Vulkan transitions after render: Add a missing case that seems like it could be common? --- ext/native/thin3d/VulkanQueueRunner.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index d34cca692d..628d95150b 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -467,7 +467,8 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c vkCmdEndRenderPass(cmd); // Transition the framebuffer if requested. - if (fb && step.render.finalColorLayout != VK_IMAGE_LAYOUT_UNDEFINED) { + // Don't need to transition it if VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL. + if (fb && step.render.finalColorLayout != VK_IMAGE_LAYOUT_UNDEFINED && step.render.finalColorLayout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { VkImageMemoryBarrier barrier{}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barrier.oldLayout = fb->color.layout; @@ -490,6 +491,9 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; break; + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + break; default: Crash(); } From b52285287d67cc0092ccedde8b2343dbb5da3e38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 30 Nov 2017 00:40:55 +0100 Subject: [PATCH 16/27] Vulkan: Avoid duplicate image pre-transitions (actually eliminated later anyway, but a small saving) --- ext/native/thin3d/VulkanRenderManager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 23f48aba9d..9f310b2b4e 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -687,6 +687,12 @@ VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, in } } + if (!curRenderStep_->preTransitions.empty() && + curRenderStep_->preTransitions.back().fb == fb && + curRenderStep_->preTransitions.back().targetLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + // We're done. + return fb->color.imageView; + } curRenderStep_->preTransitions.push_back({ fb, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }); return fb->color.imageView; } From b0c42f708199a3b02837fcc015ffb456fec6865f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 30 Nov 2017 00:59:54 +0100 Subject: [PATCH 17/27] Fix a java exception around the GPS stuff --- android/src/org/ppsspp/ppsspp/LocationHelper.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/android/src/org/ppsspp/ppsspp/LocationHelper.java b/android/src/org/ppsspp/ppsspp/LocationHelper.java index 9a7b231c8f..c6f4797d61 100644 --- a/android/src/org/ppsspp/ppsspp/LocationHelper.java +++ b/android/src/org/ppsspp/ppsspp/LocationHelper.java @@ -20,17 +20,18 @@ class LocationHelper implements LocationListener { void startLocationUpdates() { Log.d(TAG, "startLocationUpdates"); if (!mLocationEnable) { - boolean isGPSEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); - boolean isNetworkEnabled = mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); - + boolean isGPSEnabled = false; + boolean isNetworkEnabled = false; try { + isGPSEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); + isNetworkEnabled = mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, this); mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 0, this); mLocationEnable = true; } catch (SecurityException e) { Log.e(TAG, "Cannot start location updates: " + e.toString()); } - if(!isGPSEnabled && !isNetworkEnabled) { + if (!isGPSEnabled && !isNetworkEnabled) { Log.i(TAG, "No location provider found"); // TODO: notify user } From 0207739d76b475ae295af49eca42fe351cd387c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 30 Nov 2017 01:07:03 +0100 Subject: [PATCH 18/27] Can't call functions through known-nil pointers, even if they don't touch local data - LLVM's optimizer might have done something stupid. --- Core/MIPS/ARM/ArmJit.cpp | 15 --------------- Core/MIPS/ARM/ArmJit.h | 1 - Core/MIPS/ARM64/Arm64Jit.cpp | 14 -------------- Core/MIPS/ARM64/Arm64Jit.h | 1 - Core/MIPS/IR/IRJit.cpp | 14 -------------- Core/MIPS/IR/IRJit.h | 1 - Core/MIPS/JitCommon/JitCommon.cpp | 16 ++++++++++++++++ Core/MIPS/JitCommon/JitCommon.h | 3 ++- Core/MIPS/MIPS.cpp | 2 +- Core/MIPS/MIPS/MipsJit.cpp | 15 --------------- Core/MIPS/MIPS/MipsJit.h | 1 - Core/MIPS/x86/Jit.cpp | 15 --------------- Core/MIPS/x86/Jit.h | 1 - 13 files changed, 19 insertions(+), 80 deletions(-) diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index 507238f459..0a7c3ad538 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -106,21 +106,6 @@ void ArmJit::DoState(PointerWrap &p) } } -// This is here so the savestate matches between jit and non-jit. -void ArmJit::DoDummyState(PointerWrap &p) -{ - auto s = p.Section("Jit", 1, 2); - if (!s) - return; - - bool dummy = false; - p.Do(dummy); - if (s >= 2) { - dummy = true; - p.Do(dummy); - } -} - void ArmJit::FlushAll() { gpr.FlushAll(); diff --git a/Core/MIPS/ARM/ArmJit.h b/Core/MIPS/ARM/ArmJit.h index 511ce5fce1..77b4c9ea51 100644 --- a/Core/MIPS/ARM/ArmJit.h +++ b/Core/MIPS/ARM/ArmJit.h @@ -39,7 +39,6 @@ public: virtual ~ArmJit(); void DoState(PointerWrap &p) override; - void DoDummyState(PointerWrap &p) override; const JitOptions &GetJitOptions() { return jo; } diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp index fab227f303..ae9b6b8f4e 100644 --- a/Core/MIPS/ARM64/Arm64Jit.cpp +++ b/Core/MIPS/ARM64/Arm64Jit.cpp @@ -98,20 +98,6 @@ void Arm64Jit::DoState(PointerWrap &p) { } } -// This is here so the savestate matches between jit and non-jit. -void Arm64Jit::DoDummyState(PointerWrap &p) { - auto s = p.Section("Jit", 1, 2); - if (!s) - return; - - bool dummy = false; - p.Do(dummy); - if (s >= 2) { - dummy = true; - p.Do(dummy); - } -} - void Arm64Jit::FlushAll() { gpr.FlushAll(); diff --git a/Core/MIPS/ARM64/Arm64Jit.h b/Core/MIPS/ARM64/Arm64Jit.h index b2d853c3b2..e8874fa0b5 100644 --- a/Core/MIPS/ARM64/Arm64Jit.h +++ b/Core/MIPS/ARM64/Arm64Jit.h @@ -39,7 +39,6 @@ public: virtual ~Arm64Jit(); void DoState(PointerWrap &p) override; - void DoDummyState(PointerWrap &p) override; const JitOptions &GetJitOptions() { return jo; } diff --git a/Core/MIPS/IR/IRJit.cpp b/Core/MIPS/IR/IRJit.cpp index 26f66bc6ad..b36c40f110 100644 --- a/Core/MIPS/IR/IRJit.cpp +++ b/Core/MIPS/IR/IRJit.cpp @@ -50,20 +50,6 @@ void IRJit::DoState(PointerWrap &p) { frontend_.DoState(p); } -// This is here so the savestate matches between jit and non-jit. -void IRJit::DoDummyState(PointerWrap &p) { - auto s = p.Section("Jit", 1, 2); - if (!s) - return; - - bool dummy = false; - p.Do(dummy); - if (s >= 2) { - dummy = true; - p.Do(dummy); - } -} - void IRJit::ClearCache() { ILOG("IRJit: Clearing the cache!"); blocks_.Clear(); diff --git a/Core/MIPS/IR/IRJit.h b/Core/MIPS/IR/IRJit.h index 84851df7f3..67fa3a993c 100644 --- a/Core/MIPS/IR/IRJit.h +++ b/Core/MIPS/IR/IRJit.h @@ -127,7 +127,6 @@ public: virtual ~IRJit(); void DoState(PointerWrap &p) override; - void DoDummyState(PointerWrap &p) override; const JitOptions &GetJitOptions() { return jo; } diff --git a/Core/MIPS/JitCommon/JitCommon.cpp b/Core/MIPS/JitCommon/JitCommon.cpp index 55409c77c6..f7792a110c 100644 --- a/Core/MIPS/JitCommon/JitCommon.cpp +++ b/Core/MIPS/JitCommon/JitCommon.cpp @@ -21,6 +21,8 @@ #include "ext/udis86/udis86.h" #include "Common/StringUtils.h" +#include "Common/ChunkFile.h" + #include "Core/Util/DisArm64.h" #include "Core/Config.h" @@ -46,6 +48,20 @@ namespace MIPSComp { jit->Compile(currentMIPS->pc); } + void DoDummyJitState(PointerWrap &p) { + // This is here so the savestate matches between jit and non-jit. + auto s = p.Section("Jit", 1, 2); + if (!s) + return; + + bool dummy = false; + p.Do(dummy); + if (s >= 2) { + dummy = true; + p.Do(dummy); + } + } + JitInterface *CreateNativeJit(MIPSState *mips) { #if PPSSPP_ARCH(ARM) return new MIPSComp::ArmJit(mips); diff --git a/Core/MIPS/JitCommon/JitCommon.h b/Core/MIPS/JitCommon/JitCommon.h index 9e91664713..6296506a01 100644 --- a/Core/MIPS/JitCommon/JitCommon.h +++ b/Core/MIPS/JitCommon/JitCommon.h @@ -125,7 +125,6 @@ namespace MIPSComp { virtual JitBlockCache *GetBlockCache() = 0; virtual void InvalidateCacheAt(u32 em_address, int length = 4) = 0; virtual void DoState(PointerWrap &p) = 0; - virtual void DoDummyState(PointerWrap &p) = 0; virtual void RunLoopUntil(u64 globalticks) = 0; virtual void Compile(u32 em_address) = 0; virtual void ClearCache() = 0; @@ -147,5 +146,7 @@ namespace MIPSComp { extern JitInterface *jit; + void DoDummyJitState(PointerWrap &p); + JitInterface *CreateNativeJit(MIPSState *mips); } diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index f046d05271..2302928968 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -262,7 +262,7 @@ void MIPSState::DoState(PointerWrap &p) { if (MIPSComp::jit) MIPSComp::jit->DoState(p); else - MIPSComp::jit->DoDummyState(p); + MIPSComp::DoDummyJitState(p); p.DoArray(r, sizeof(r) / sizeof(r[0])); p.DoArray(f, sizeof(f) / sizeof(f[0])); diff --git a/Core/MIPS/MIPS/MipsJit.cpp b/Core/MIPS/MIPS/MipsJit.cpp index b669109899..48637e8f23 100644 --- a/Core/MIPS/MIPS/MipsJit.cpp +++ b/Core/MIPS/MIPS/MipsJit.cpp @@ -66,21 +66,6 @@ void MipsJit::DoState(PointerWrap &p) } } -// This is here so the savestate matches between jit and non-jit. -void MipsJit::DoDummyState(PointerWrap &p) -{ - auto s = p.Section("Jit", 1, 2); - if (!s) - return; - - bool dummy = false; - p.Do(dummy); - if (s >= 2) { - dummy = true; - p.Do(dummy); - } -} - void MipsJit::FlushAll() { //gpr.FlushAll(); diff --git a/Core/MIPS/MIPS/MipsJit.h b/Core/MIPS/MIPS/MipsJit.h index ad158f5de0..c0ff28582d 100644 --- a/Core/MIPS/MIPS/MipsJit.h +++ b/Core/MIPS/MIPS/MipsJit.h @@ -38,7 +38,6 @@ public: MipsJit(MIPSState *mips); void DoState(PointerWrap &p) override; - void DoDummyState(PointerWrap &p) override; // Compiled ops should ignore delay slots // the compiler will take care of them by itself diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index 6a6b196aec..6e2ceae75e 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -142,21 +142,6 @@ void Jit::DoState(PointerWrap &p) { CBreakPoints::SetSkipFirst(0); } -// This is here so the savestate matches between jit and non-jit. -void Jit::DoDummyState(PointerWrap &p) { - auto s = p.Section("Jit", 1, 2); - if (!s) - return; - - bool dummy = false; - p.Do(dummy); - if (s >= 2) { - dummy = true; - p.Do(dummy); - } -} - - void Jit::GetStateAndFlushAll(RegCacheState &state) { gpr.GetState(state.gpr); fpr.GetState(state.fpr); diff --git a/Core/MIPS/x86/Jit.h b/Core/MIPS/x86/Jit.h index de8ef4d8f1..2a35212140 100644 --- a/Core/MIPS/x86/Jit.h +++ b/Core/MIPS/x86/Jit.h @@ -52,7 +52,6 @@ public: const JitOptions &GetJitOptions() { return jo; } void DoState(PointerWrap &p) override; - void DoDummyState(PointerWrap &p) override; // Compiled ops should ignore delay slots // the compiler will take care of them by itself From 0d60c3f386810b26c1744217bbb3357d5509a13f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 30 Nov 2017 01:21:03 +0100 Subject: [PATCH 19/27] Fix UI crash when keyboard navigating out of popup list. --- ext/native/ui/ui_screen.h | 2 +- ext/native/ui/viewgroup.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ext/native/ui/ui_screen.h b/ext/native/ui/ui_screen.h index cb894999f5..fee88ce255 100644 --- a/ext/native/ui/ui_screen.h +++ b/ext/native/ui/ui_screen.h @@ -264,7 +264,7 @@ private: const char *category_; ScreenManager *screenManager_; std::string valueText_; - bool restoreFocus_; + bool restoreFocus_ = false; std::set hidden_; }; diff --git a/ext/native/ui/viewgroup.cpp b/ext/native/ui/viewgroup.cpp index 50dabcead2..5c93a4c4c3 100644 --- a/ext/native/ui/viewgroup.cpp +++ b/ext/native/ui/viewgroup.cpp @@ -1314,8 +1314,10 @@ EventReturn ListView::OnItemCallback(int num, EventParams &e) { View *focused = GetFocusedView(); OnChoice.Trigger(ev); CreateAllItems(); - if (focused) - SetFocusedView(e.v); + // TODO: At this point, focused may no longer exist, depending on what OnChoice.Trigger does. + // Disable the refocus feature for now. + // if (focused) + // SetFocusedView(e.v); return EVENT_DONE; } From b4bca7d7a0738df44f8675e2b26c4bd57cdd92cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 30 Nov 2017 01:26:59 +0100 Subject: [PATCH 20/27] VKRFramebufer: Just some checks to be slightly safer in case creation failed.. --- ext/native/thin3d/VulkanRenderManager.h | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/ext/native/thin3d/VulkanRenderManager.h b/ext/native/thin3d/VulkanRenderManager.h index b8257cac86..c5e13130af 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/ext/native/thin3d/VulkanRenderManager.h @@ -51,13 +51,20 @@ public: } ~VKRFramebuffer() { - vulkan_->Delete().QueueDeleteImage(color.image); - vulkan_->Delete().QueueDeleteImage(depth.image); - vulkan_->Delete().QueueDeleteImageView(color.imageView); - vulkan_->Delete().QueueDeleteImageView(depth.imageView); - vulkan_->Delete().QueueDeleteDeviceMemory(color.memory); - vulkan_->Delete().QueueDeleteDeviceMemory(depth.memory); - vulkan_->Delete().QueueDeleteFramebuffer(framebuf); + if (color.image) + vulkan_->Delete().QueueDeleteImage(color.image); + if (depth.image) + vulkan_->Delete().QueueDeleteImage(depth.image); + if (color.imageView) + vulkan_->Delete().QueueDeleteImageView(color.imageView); + if (depth.imageView) + vulkan_->Delete().QueueDeleteImageView(depth.imageView); + if (color.memory) + vulkan_->Delete().QueueDeleteDeviceMemory(color.memory); + if (depth.memory) + vulkan_->Delete().QueueDeleteDeviceMemory(depth.memory); + if (framebuf) + vulkan_->Delete().QueueDeleteFramebuffer(framebuf); } int numShadows = 1; // TODO: Support this. From 16057eda39ff383898c916b587d52d83be9ab823 Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Thu, 30 Nov 2017 01:32:19 +0100 Subject: [PATCH 21/27] Fix a cheat menu crash with invalid cheat name. Also stop #comments from being removed by cheat menu. --- Core/CwCheat.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Core/CwCheat.cpp b/Core/CwCheat.cpp index b277414422..2aa258b0a9 100644 --- a/Core/CwCheat.cpp +++ b/Core/CwCheat.cpp @@ -87,7 +87,7 @@ bool CheatFileParser::Parse() { getline(file_, line, '\n'); line = TrimString(line); - if (line.length() > 2 && line[0] == '_') { + if (line.length() >= 5 && line[0] == '_') { ParseLine(line); } else if (line.length() >= 2 && line[0] == '/' && line[1] == '/') { // Comment, ignore. @@ -340,7 +340,17 @@ std::vector CWCheatEngine::GetCodesList() { std::string line; getline(list, line, '\n'); - if (line.length() > 3 && (line.substr(0, 1) == "_" || line.substr(0, 2) == "//")) { + bool validCheatLine = false; + // This code is used by cheat menu which doesn't support empty names + if (line.length() >= 5 && line.substr(0, 1) == "_") { + for (int i = 4; i < line.length(); i++) { + if (line.substr(i, 1) != " ") { + validCheatLine = true; + break; + } + } + } + if (validCheatLine || (line.length() >= 2 && line.substr(0, 2) == "//") || (line.length() >= 1 && line.substr(0, 1) == "#")) { codesList.push_back(TrimString(line)); } } From be18f2c3cc6a8e2ca63ee8bb38a6e39683b7183a Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Thu, 30 Nov 2017 02:23:44 +0100 Subject: [PATCH 22/27] Change str.substr(x, 1) == "y" to str[x] == 'y' --- Core/CwCheat.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/CwCheat.cpp b/Core/CwCheat.cpp index 2aa258b0a9..e388bd7ee0 100644 --- a/Core/CwCheat.cpp +++ b/Core/CwCheat.cpp @@ -342,15 +342,15 @@ std::vector CWCheatEngine::GetCodesList() { bool validCheatLine = false; // This code is used by cheat menu which doesn't support empty names - if (line.length() >= 5 && line.substr(0, 1) == "_") { + if (line.length() >= 5 && line[0] == '_') { for (int i = 4; i < line.length(); i++) { - if (line.substr(i, 1) != " ") { + if (line[i] != ' ') { validCheatLine = true; break; } } } - if (validCheatLine || (line.length() >= 2 && line.substr(0, 2) == "//") || (line.length() >= 1 && line.substr(0, 1) == "#")) { + if (validCheatLine || (line.length() >= 2 && line[0] == '/' && line[1] == '/') || (line.length() >= 1 && line[0] == '#')) { codesList.push_back(TrimString(line)); } } From 5805cba7360e5c5d9e2ae4d83acabb7a070bca4e Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Thu, 30 Nov 2017 05:05:52 +0100 Subject: [PATCH 23/27] Change some other substr used with cheats and smuggle a fix for another problem --- UI/CwCheatScreen.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index 0fa131e4a0..976477e0b3 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -65,9 +65,9 @@ void CwCheatScreen::CreateCodeList() { bEnableCheat.clear(); formattedList_.clear(); for (size_t i = 0; i < cheatList.size(); i++) { - if (cheatList[i].substr(0, 2) == "_C") { + if (cheatList[i][0] == '_' && cheatList[i][1] == 'C') { formattedList_.push_back(cheatList[i].substr(4)); - if (cheatList[i].substr(2, 1) == "0") { + if (cheatList[i][2] == '0') { bEnableCheat.push_back(false); } else { bEnableCheat.push_back(true); @@ -136,11 +136,11 @@ UI::EventReturn CwCheatScreen::OnEnableAll(UI::EventParams ¶ms) { enableAll = !enableAll; File::OpenCPPFile(fs, activeCheatFile, std::ios::out); for (int j = 0; j < (int)cheatList.size(); j++) { - if (cheatList[j].substr(0, 2) == "_C") { - if (cheatList[j].substr(2, 1) == "0" && enableAll) { - cheatList[j].replace(2, 1, "1"); - } else if (cheatList[j].substr(2, 1) != "0" && !enableAll) { - cheatList[j].replace(2, 1, "0"); + if (cheatList[j][0] == '_' && cheatList[j][1] == 'C') { + if (cheatList[j][2] == '0' && enableAll) { + cheatList[j][2] = '1'; + } else if (cheatList[j][2] != '0' && !enableAll) { + cheatList[j][2] = '0'; } } } @@ -190,6 +190,7 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { std::vector newList; std::string cheatFile = GetSysDirectory(DIRECTORY_CHEATS) + "cheat.db"; + std::string gameID = StringFromFormat("_S %s-%s", gameTitle.substr(0, 4), gameTitle.substr(4)); std::fstream fs; File::OpenCPPFile(fs, cheatFile, std::ios::in); @@ -200,7 +201,7 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { while (fs.good()) { getline(fs, line); // get line from file - if (line == "_S " + gameTitle.substr(0, 4) + "-" + gameTitle.substr(4)) { + if (line == gameID) { title.push_back(line); getline(fs, line); title.push_back(line); @@ -208,7 +209,7 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { if (finished == false){ getline(fs, line); } - if (line.substr(0, 2) == "_C") { + if (line[0] == '_' && line[1] == 'C') { //Test if cheat already exists in cheatList for (size_t j = 0; j < formattedList_.size(); j++) { if (line.substr(4) == formattedList_[j]) { @@ -222,13 +223,13 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { do { newList.push_back(line); getline(fs, line); - } while (line.substr(0, 2) == "_L"); + } while (line[0] == '_' && line[1] == 'L'); finished = true; } else { continue; } loop:; - } while (line.substr(0, 2) != "_S"); + } while (fs.good() && line[0] != '_' && line[1] != 'S'); finished = true; } if (finished == true) @@ -242,7 +243,7 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { File::OpenCPPFile(fs, activeCheatFile, std::ios::out | std::ios::app); auto it = title.begin(); - if (title2.substr(0, 2) != "_S" && it != title.end() && (++it) != title.end()) { + if (title2[0] != '_' && title2[1] != 'S' && it != title.end() && (++it) != title.end()) { fs << title[0] << "\n" << title[1]; } From 689637ca5a4be0e9cad5e40d08e9d6ede7283ddf Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Thu, 30 Nov 2017 06:14:36 +0100 Subject: [PATCH 24/27] Oops;p, I always mess this up. --- UI/CwCheatScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index 976477e0b3..3911b28353 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -190,7 +190,7 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { std::vector newList; std::string cheatFile = GetSysDirectory(DIRECTORY_CHEATS) + "cheat.db"; - std::string gameID = StringFromFormat("_S %s-%s", gameTitle.substr(0, 4), gameTitle.substr(4)); + std::string gameID = StringFromFormat("_S %s-%s", gameTitle.substr(0, 4).c_str(), gameTitle.substr(4).c_str()); std::fstream fs; File::OpenCPPFile(fs, cheatFile, std::ios::in); From 80b6686d89d974760cbb57baa70f97d76a7050b9 Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Thu, 30 Nov 2017 07:51:15 +0100 Subject: [PATCH 25/27] Add some comments. --- Core/CwCheat.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Core/CwCheat.cpp b/Core/CwCheat.cpp index e388bd7ee0..0b14aa764a 100644 --- a/Core/CwCheat.cpp +++ b/Core/CwCheat.cpp @@ -87,6 +87,11 @@ bool CheatFileParser::Parse() { getline(file_, line, '\n'); line = TrimString(line); + // Minimum length is set to 5 just to match GetCodesList() function + // which discards anything shorter when called anyway. + // It's decided from shortest possible _ lines name of the game "_G N+" + // and a minimum of 1 displayable character in cheat name string "_C0 1" + // which both equal to 5 characters. if (line.length() >= 5 && line[0] == '_') { ParseLine(line); } else if (line.length() >= 2 && line[0] == '/' && line[1] == '/') { @@ -341,7 +346,10 @@ std::vector CWCheatEngine::GetCodesList() { getline(list, line, '\n'); bool validCheatLine = false; - // This code is used by cheat menu which doesn't support empty names + // This function is called by cheat menu(UI) which doesn't support empty names + // minimum 1 non space character is required starting from 5 position. + // It also goes through other "_" lines, but they all have to meet this requirement anyway + // so we don't have to specify any syntax checks here that are made by cheat engine. if (line.length() >= 5 && line[0] == '_') { for (int i = 4; i < line.length(); i++) { if (line[i] != ' ') { @@ -350,6 +358,7 @@ std::vector CWCheatEngine::GetCodesList() { } } } + // Any lines not passing this check are discarded when we save changes to the cheat ini file if (validCheatLine || (line.length() >= 2 && line[0] == '/' && line[1] == '/') || (line.length() >= 1 && line[0] == '#')) { codesList.push_back(TrimString(line)); } From d884eeda99d73fd8634543da0a3d47253e7f7bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 30 Nov 2017 15:28:15 +0100 Subject: [PATCH 26/27] DX9: Revert a bad optimization, hopefully fixing #10205. Vulkan: Add a missing check. --- GPU/Directx9/ShaderManagerDX9.cpp | 10 +++++++--- GPU/Vulkan/DepalettizeShaderVulkan.cpp | 3 ++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 78988911cc..9588053b55 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -147,9 +147,13 @@ void ShaderManagerDX9::PSSetColorUniform3(int creg, u32 color) { } void ShaderManagerDX9::PSSetColorUniform3Alpha255(int creg, u32 color, u8 alpha) { - float f[4]; - Uint8x3ToFloat4_AlphaUint8(f, color, alpha); - device_->SetPixelShaderConstantF(creg, f, 1); + const float col[4] = { + (float)((color & 0xFF)), + (float)((color & 0xFF00) >> 8), + (float)((color & 0xFF0000) >> 16), + (float)alpha, + }; + device_->SetPixelShaderConstantF(creg, col, 1); } void ShaderManagerDX9::PSSetFloat(int creg, float value) { diff --git a/GPU/Vulkan/DepalettizeShaderVulkan.cpp b/GPU/Vulkan/DepalettizeShaderVulkan.cpp index a080b27416..b7dec11221 100644 --- a/GPU/Vulkan/DepalettizeShaderVulkan.cpp +++ b/GPU/Vulkan/DepalettizeShaderVulkan.cpp @@ -69,7 +69,8 @@ DepalShaderCacheVulkan::~DepalShaderCacheVulkan() { void DepalShaderCacheVulkan::DeviceLost() { Clear(); - vulkan_->Delete().QueueDeleteShaderModule(vshader_); + if (vshader_) + vulkan_->Delete().QueueDeleteShaderModule(vshader_); draw_ = nullptr; vulkan_ = nullptr; } From 407812916d9cdab05a57ffeb69b6a5e254b5b21f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 30 Nov 2017 18:22:25 +0100 Subject: [PATCH 27/27] Avoid wrapping when shifting down the audio after scaling by a 20-bit value. Fixes #9967 --- Core/Util/AudioFormat.cpp | 19 +++++++++++++++---- Core/Util/AudioFormat.h | 6 ++++++ Core/Util/AudioFormatNEON.cpp | 13 ++++++++++--- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/Core/Util/AudioFormat.cpp b/Core/Util/AudioFormat.cpp index 5806c2c51c..2424b405d5 100644 --- a/Core/Util/AudioFormat.cpp +++ b/Core/Util/AudioFormat.cpp @@ -37,7 +37,10 @@ void AdjustVolumeBlockStandard(s16 *out, s16 *in, size_t size, int leftVol, int out += 16; size -= 16; } - } else { + } +#if 0 + // This path wraps instead of clamps in _mm_slli_epi16. Needs fixing. + else { // We have to shift inside the loop to avoid the signed 16-bit multiply issue. int leftShift = 0; int leftVol16 = leftVol; @@ -63,9 +66,17 @@ void AdjustVolumeBlockStandard(s16 *out, s16 *in, size_t size, int leftVol, int } } #endif - for (size_t i = 0; i < size; i += 2) { - out[i] = ApplySampleVolume(in[i], leftVol); - out[i + 1] = ApplySampleVolume(in[i + 1], rightVol); +#endif + if (leftVol <= 0x7fff && -leftVol <= 0x8000 && rightVol <= 0x7fff && -rightVol <= 0x8000) { + for (size_t i = 0; i < size; i += 2) { + out[i] = ApplySampleVolume(in[i], leftVol); + out[i + 1] = ApplySampleVolume(in[i + 1], rightVol); + } + } else { + for (size_t i = 0; i < size; i += 2) { + out[i] = ApplySampleVolume20Bit(in[i], leftVol); + out[i + 1] = ApplySampleVolume20Bit(in[i + 1], rightVol); + } } } diff --git a/Core/Util/AudioFormat.h b/Core/Util/AudioFormat.h index 841b8e634a..7fc20eaf83 100644 --- a/Core/Util/AudioFormat.h +++ b/Core/Util/AudioFormat.h @@ -59,6 +59,12 @@ static inline s16 ApplySampleVolume(s16 sample, int vol) { #endif } +// We sacrifice a little volume precision to fit in 32 bits, for speed. +// Probably not worth it to make a special path for 64-bit CPUs. +static inline s16 ApplySampleVolume20Bit(s16 sample, int vol20) { + return clamp_s16((sample * (vol20 >> 4)) >> 12); +} + void SetupAudioFormats(); void AdjustVolumeBlockStandard(s16 *out, s16 *in, size_t size, int leftVol, int rightVol); void ConvertS16ToF32(float *ou, const s16 *in, size_t size); diff --git a/Core/Util/AudioFormatNEON.cpp b/Core/Util/AudioFormatNEON.cpp index 4eafe47ba7..4653764b49 100644 --- a/Core/Util/AudioFormatNEON.cpp +++ b/Core/Util/AudioFormatNEON.cpp @@ -58,9 +58,16 @@ void AdjustVolumeBlockNEON(s16 *out, s16 *in, size_t size, int leftVol, int righ } } - for (size_t i = 0; i < size; i += 2) { - out[i] = ApplySampleVolume(in[i], leftVol); - out[i + 1] = ApplySampleVolume(in[i + 1], rightVol); + if (leftVol <= 0x7fff && -leftVol <= 0x8000 && rightVol <= 0x7fff && -rightVol <= 0x8000) { + for (size_t i = 0; i < size; i += 2) { + out[i] = ApplySampleVolume(in[i], leftVol); + out[i + 1] = ApplySampleVolume(in[i + 1], rightVol); + } + } else { + for (size_t i = 0; i < size; i += 2) { + out[i] = ApplySampleVolume20Bit(in[i], leftVol); + out[i + 1] = ApplySampleVolume20Bit(in[i + 1], rightVol); + } } }