diff options
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.cpp | 20 | ||||
| -rw-r--r-- | src/core/frontend/framebuffer_layout.cpp | 7 | ||||
| -rw-r--r-- | src/core/frontend/framebuffer_layout.h | 11 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 22 | ||||
| -rw-r--r-- | src/core/hle/service/pm/pm.cpp | 47 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/blit_image.cpp | 38 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/blit_image.h | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_texture_cache.cpp | 6 | ||||
| -rw-r--r-- | src/video_core/video_core.cpp | 6 | ||||
| -rw-r--r-- | src/video_core/video_core.h | 2 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.cpp | 11 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.h | 6 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 99 | ||||
| -rw-r--r-- | src/yuzu/main.h | 5 | ||||
| -rw-r--r-- | src/yuzu/main.ui | 90 |
15 files changed, 248 insertions, 125 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 4e73cc03a..56836bd05 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -86,6 +86,26 @@ public: | |||
| 86 | num_instructions, MemoryReadCode(pc)); | 86 | num_instructions, MemoryReadCode(pc)); |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, | ||
| 90 | VAddr value) override { | ||
| 91 | switch (op) { | ||
| 92 | case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: { | ||
| 93 | static constexpr u64 ICACHE_LINE_SIZE = 64; | ||
| 94 | |||
| 95 | const u64 cache_line_start = value & ~(ICACHE_LINE_SIZE - 1); | ||
| 96 | parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE); | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU: | ||
| 100 | parent.ClearInstructionCache(); | ||
| 101 | break; | ||
| 102 | case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable: | ||
| 103 | default: | ||
| 104 | LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation: {}", op); | ||
| 105 | break; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 89 | void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { | 109 | void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { |
| 90 | switch (exception) { | 110 | switch (exception) { |
| 91 | case Dynarmic::A64::Exception::WaitForInterrupt: | 111 | case Dynarmic::A64::Exception::WaitForInterrupt: |
diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index 4b58b672a..26a5b12aa 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp | |||
| @@ -25,7 +25,12 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) { | |||
| 25 | ASSERT(height > 0); | 25 | ASSERT(height > 0); |
| 26 | // The drawing code needs at least somewhat valid values for both screens | 26 | // The drawing code needs at least somewhat valid values for both screens |
| 27 | // so just calculate them both even if the other isn't showing. | 27 | // so just calculate them both even if the other isn't showing. |
| 28 | FramebufferLayout res{width, height, false, {}}; | 28 | FramebufferLayout res{ |
| 29 | .width = width, | ||
| 30 | .height = height, | ||
| 31 | .screen = {}, | ||
| 32 | .is_srgb = false, | ||
| 33 | }; | ||
| 29 | 34 | ||
| 30 | const float window_aspect_ratio = static_cast<float>(height) / static_cast<float>(width); | 35 | const float window_aspect_ratio = static_cast<float>(height) / static_cast<float>(width); |
| 31 | const float emulation_aspect_ratio = EmulationAspectRatio( | 36 | const float emulation_aspect_ratio = EmulationAspectRatio( |
diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index 2e36c0163..8e341e4e2 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h | |||
| @@ -35,17 +35,8 @@ enum class AspectRatio { | |||
| 35 | struct FramebufferLayout { | 35 | struct FramebufferLayout { |
| 36 | u32 width{ScreenUndocked::Width}; | 36 | u32 width{ScreenUndocked::Width}; |
| 37 | u32 height{ScreenUndocked::Height}; | 37 | u32 height{ScreenUndocked::Height}; |
| 38 | bool is_srgb{}; | ||
| 39 | |||
| 40 | Common::Rectangle<u32> screen; | 38 | Common::Rectangle<u32> screen; |
| 41 | 39 | bool is_srgb{}; | |
| 42 | /** | ||
| 43 | * Returns the ration of pixel size of the screen, compared to the native size of the undocked | ||
| 44 | * Switch screen. | ||
| 45 | */ | ||
| 46 | float GetScalingRatio() const { | ||
| 47 | return static_cast<float>(screen.GetWidth()) / ScreenUndocked::Width; | ||
| 48 | } | ||
| 49 | }; | 40 | }; |
| 50 | 41 | ||
| 51 | /** | 42 | /** |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e42a6d36f..45e86a677 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -300,15 +300,16 @@ struct KernelCore::Impl { | |||
| 300 | // Gets the dummy KThread for the caller, allocating a new one if this is the first time | 300 | // Gets the dummy KThread for the caller, allocating a new one if this is the first time |
| 301 | KThread* GetHostDummyThread() { | 301 | KThread* GetHostDummyThread() { |
| 302 | auto make_thread = [this]() { | 302 | auto make_thread = [this]() { |
| 303 | std::unique_ptr<KThread> thread = std::make_unique<KThread>(system.Kernel()); | 303 | std::lock_guard lk(dummy_thread_lock); |
| 304 | auto& thread = dummy_threads.emplace_back(std::make_unique<KThread>(system.Kernel())); | ||
| 304 | KAutoObject::Create(thread.get()); | 305 | KAutoObject::Create(thread.get()); |
| 305 | ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess()); | 306 | ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess()); |
| 306 | thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); | 307 | thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); |
| 307 | return thread; | 308 | return thread.get(); |
| 308 | }; | 309 | }; |
| 309 | 310 | ||
| 310 | thread_local auto thread = make_thread(); | 311 | thread_local KThread* saved_thread = make_thread(); |
| 311 | return thread.get(); | 312 | return saved_thread; |
| 312 | } | 313 | } |
| 313 | 314 | ||
| 314 | /// Registers a CPU core thread by allocating a host thread ID for it | 315 | /// Registers a CPU core thread by allocating a host thread ID for it |
| @@ -695,6 +696,12 @@ struct KernelCore::Impl { | |||
| 695 | return port; | 696 | return port; |
| 696 | } | 697 | } |
| 697 | 698 | ||
| 699 | std::mutex server_ports_lock; | ||
| 700 | std::mutex server_sessions_lock; | ||
| 701 | std::mutex registered_objects_lock; | ||
| 702 | std::mutex registered_in_use_objects_lock; | ||
| 703 | std::mutex dummy_thread_lock; | ||
| 704 | |||
| 698 | std::atomic<u32> next_object_id{0}; | 705 | std::atomic<u32> next_object_id{0}; |
| 699 | std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin}; | 706 | std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin}; |
| 700 | std::atomic<u64> next_user_process_id{KProcess::ProcessIDMin}; | 707 | std::atomic<u64> next_user_process_id{KProcess::ProcessIDMin}; |
| @@ -725,10 +732,6 @@ struct KernelCore::Impl { | |||
| 725 | std::unordered_set<KServerSession*> server_sessions; | 732 | std::unordered_set<KServerSession*> server_sessions; |
| 726 | std::unordered_set<KAutoObject*> registered_objects; | 733 | std::unordered_set<KAutoObject*> registered_objects; |
| 727 | std::unordered_set<KAutoObject*> registered_in_use_objects; | 734 | std::unordered_set<KAutoObject*> registered_in_use_objects; |
| 728 | std::mutex server_ports_lock; | ||
| 729 | std::mutex server_sessions_lock; | ||
| 730 | std::mutex registered_objects_lock; | ||
| 731 | std::mutex registered_in_use_objects_lock; | ||
| 732 | 735 | ||
| 733 | std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; | 736 | std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; |
| 734 | std::vector<Kernel::PhysicalCore> cores; | 737 | std::vector<Kernel::PhysicalCore> cores; |
| @@ -753,6 +756,9 @@ struct KernelCore::Impl { | |||
| 753 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; | 756 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; |
| 754 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; | 757 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; |
| 755 | 758 | ||
| 759 | // Specifically tracked to be automatically destroyed with kernel | ||
| 760 | std::vector<std::unique_ptr<KThread>> dummy_threads; | ||
| 761 | |||
| 756 | bool is_multicore{}; | 762 | bool is_multicore{}; |
| 757 | bool is_phantom_mode_for_singlecore{}; | 763 | bool is_phantom_mode_for_singlecore{}; |
| 758 | u32 single_core_thread_id{}; | 764 | u32 single_core_thread_id{}; |
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index 88fc5b5cc..277abc17a 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp | |||
| @@ -13,7 +13,12 @@ namespace Service::PM { | |||
| 13 | 13 | ||
| 14 | namespace { | 14 | namespace { |
| 15 | 15 | ||
| 16 | constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1}; | 16 | constexpr ResultCode ResultProcessNotFound{ErrorModule::PM, 1}; |
| 17 | [[maybe_unused]] constexpr ResultCode ResultAlreadyStarted{ErrorModule::PM, 2}; | ||
| 18 | [[maybe_unused]] constexpr ResultCode ResultNotTerminated{ErrorModule::PM, 3}; | ||
| 19 | [[maybe_unused]] constexpr ResultCode ResultDebugHookInUse{ErrorModule::PM, 4}; | ||
| 20 | [[maybe_unused]] constexpr ResultCode ResultApplicationRunning{ErrorModule::PM, 5}; | ||
| 21 | [[maybe_unused]] constexpr ResultCode ResultInvalidSize{ErrorModule::PM, 6}; | ||
| 17 | 22 | ||
| 18 | constexpr u64 NO_PROCESS_FOUND_PID{0}; | 23 | constexpr u64 NO_PROCESS_FOUND_PID{0}; |
| 19 | 24 | ||
| @@ -95,18 +100,18 @@ public: | |||
| 95 | private: | 100 | private: |
| 96 | void GetProcessId(Kernel::HLERequestContext& ctx) { | 101 | void GetProcessId(Kernel::HLERequestContext& ctx) { |
| 97 | IPC::RequestParser rp{ctx}; | 102 | IPC::RequestParser rp{ctx}; |
| 98 | const auto title_id = rp.PopRaw<u64>(); | 103 | const auto program_id = rp.PopRaw<u64>(); |
| 99 | 104 | ||
| 100 | LOG_DEBUG(Service_PM, "called, title_id={:016X}", title_id); | 105 | LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); |
| 101 | 106 | ||
| 102 | const auto process = | 107 | const auto process = |
| 103 | SearchProcessList(kernel.GetProcessList(), [title_id](const auto& proc) { | 108 | SearchProcessList(kernel.GetProcessList(), [program_id](const auto& proc) { |
| 104 | return proc->GetProgramID() == title_id; | 109 | return proc->GetProgramID() == program_id; |
| 105 | }); | 110 | }); |
| 106 | 111 | ||
| 107 | if (!process.has_value()) { | 112 | if (!process.has_value()) { |
| 108 | IPC::ResponseBuilder rb{ctx, 2}; | 113 | IPC::ResponseBuilder rb{ctx, 2}; |
| 109 | rb.Push(ERROR_PROCESS_NOT_FOUND); | 114 | rb.Push(ResultProcessNotFound); |
| 110 | return; | 115 | return; |
| 111 | } | 116 | } |
| 112 | 117 | ||
| @@ -128,13 +133,16 @@ public: | |||
| 128 | explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_) | 133 | explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_) |
| 129 | : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { | 134 | : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { |
| 130 | static const FunctionInfo functions[] = { | 135 | static const FunctionInfo functions[] = { |
| 131 | {0, &Info::GetTitleId, "GetTitleId"}, | 136 | {0, &Info::GetProgramId, "GetProgramId"}, |
| 137 | {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"}, | ||
| 138 | {65001, nullptr, "AtmosphereHasLaunchedProgram"}, | ||
| 139 | {65002, nullptr, "AtmosphereGetProcessInfo"}, | ||
| 132 | }; | 140 | }; |
| 133 | RegisterHandlers(functions); | 141 | RegisterHandlers(functions); |
| 134 | } | 142 | } |
| 135 | 143 | ||
| 136 | private: | 144 | private: |
| 137 | void GetTitleId(Kernel::HLERequestContext& ctx) { | 145 | void GetProgramId(Kernel::HLERequestContext& ctx) { |
| 138 | IPC::RequestParser rp{ctx}; | 146 | IPC::RequestParser rp{ctx}; |
| 139 | const auto process_id = rp.PopRaw<u64>(); | 147 | const auto process_id = rp.PopRaw<u64>(); |
| 140 | 148 | ||
| @@ -146,7 +154,7 @@ private: | |||
| 146 | 154 | ||
| 147 | if (!process.has_value()) { | 155 | if (!process.has_value()) { |
| 148 | IPC::ResponseBuilder rb{ctx, 2}; | 156 | IPC::ResponseBuilder rb{ctx, 2}; |
| 149 | rb.Push(ERROR_PROCESS_NOT_FOUND); | 157 | rb.Push(ResultProcessNotFound); |
| 150 | return; | 158 | return; |
| 151 | } | 159 | } |
| 152 | 160 | ||
| @@ -155,6 +163,27 @@ private: | |||
| 155 | rb.Push((*process)->GetProgramID()); | 163 | rb.Push((*process)->GetProgramID()); |
| 156 | } | 164 | } |
| 157 | 165 | ||
| 166 | void AtmosphereGetProcessId(Kernel::HLERequestContext& ctx) { | ||
| 167 | IPC::RequestParser rp{ctx}; | ||
| 168 | const auto program_id = rp.PopRaw<u64>(); | ||
| 169 | |||
| 170 | LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); | ||
| 171 | |||
| 172 | const auto process = SearchProcessList(process_list, [program_id](const auto& proc) { | ||
| 173 | return proc->GetProgramID() == program_id; | ||
| 174 | }); | ||
| 175 | |||
| 176 | if (!process.has_value()) { | ||
| 177 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 178 | rb.Push(ResultProcessNotFound); | ||
| 179 | return; | ||
| 180 | } | ||
| 181 | |||
| 182 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 183 | rb.Push(ResultSuccess); | ||
| 184 | rb.Push((*process)->GetProcessID()); | ||
| 185 | } | ||
| 186 | |||
| 158 | const std::vector<Kernel::KProcess*>& process_list; | 187 | const std::vector<Kernel::KProcess*>& process_list; |
| 159 | }; | 188 | }; |
| 160 | 189 | ||
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 28b631f73..a63d4d222 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp | |||
| @@ -749,8 +749,9 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend | |||
| 749 | }); | 749 | }); |
| 750 | } | 750 | } |
| 751 | 751 | ||
| 752 | void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | 752 | void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass, |
| 753 | vk::ShaderModule& module, bool single_texture) { | 753 | vk::ShaderModule& module, bool is_target_depth, |
| 754 | bool single_texture) { | ||
| 754 | if (pipeline) { | 755 | if (pipeline) { |
| 755 | return; | 756 | return; |
| 756 | } | 757 | } |
| @@ -767,7 +768,7 @@ void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRen | |||
| 767 | .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, | 768 | .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, |
| 768 | .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | 769 | .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, |
| 769 | .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | 770 | .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, |
| 770 | .pDepthStencilState = nullptr, | 771 | .pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr, |
| 771 | .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO, | 772 | .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO, |
| 772 | .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | 773 | .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, |
| 773 | .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout, | 774 | .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout, |
| @@ -778,33 +779,14 @@ void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRen | |||
| 778 | }); | 779 | }); |
| 779 | } | 780 | } |
| 780 | 781 | ||
| 782 | void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | ||
| 783 | vk::ShaderModule& module, bool single_texture) { | ||
| 784 | ConvertPipelineEx(pipeline, renderpass, module, false, single_texture); | ||
| 785 | } | ||
| 786 | |||
| 781 | void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | 787 | void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, |
| 782 | vk::ShaderModule& module, bool single_texture) { | 788 | vk::ShaderModule& module, bool single_texture) { |
| 783 | if (pipeline) { | 789 | ConvertPipelineEx(pipeline, renderpass, module, true, single_texture); |
| 784 | return; | ||
| 785 | } | ||
| 786 | const std::array stages = MakeStages(*full_screen_vert, *module); | ||
| 787 | pipeline = device.GetLogical().CreateGraphicsPipeline({ | ||
| 788 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 789 | .pNext = nullptr, | ||
| 790 | .flags = 0, | ||
| 791 | .stageCount = static_cast<u32>(stages.size()), | ||
| 792 | .pStages = stages.data(), | ||
| 793 | .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 794 | .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 795 | .pTessellationState = nullptr, | ||
| 796 | .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 797 | .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 798 | .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 799 | .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, | ||
| 800 | .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO, | ||
| 801 | .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 802 | .layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout, | ||
| 803 | .renderPass = renderpass, | ||
| 804 | .subpass = 0, | ||
| 805 | .basePipelineHandle = VK_NULL_HANDLE, | ||
| 806 | .basePipelineIndex = 0, | ||
| 807 | }); | ||
| 808 | } | 790 | } |
| 809 | 791 | ||
| 810 | } // namespace Vulkan | 792 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index cec095341..3455c75f4 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h | |||
| @@ -89,6 +89,9 @@ private: | |||
| 89 | 89 | ||
| 90 | void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); | 90 | void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); |
| 91 | 91 | ||
| 92 | void ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | ||
| 93 | vk::ShaderModule& module, bool is_target_depth, bool single_texture); | ||
| 94 | |||
| 92 | void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | 95 | void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, |
| 93 | vk::ShaderModule& module, bool single_texture); | 96 | vk::ShaderModule& module, bool single_texture); |
| 94 | 97 | ||
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 3964424af..c72f0c897 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -787,9 +787,9 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { | |||
| 787 | return *buffers[level]; | 787 | return *buffers[level]; |
| 788 | } | 788 | } |
| 789 | const auto new_size = Common::NextPow2(needed_size); | 789 | const auto new_size = Common::NextPow2(needed_size); |
| 790 | VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | 790 | static constexpr VkBufferUsageFlags flags = |
| 791 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | | 791 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | |
| 792 | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; | 792 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; |
| 793 | buffers[level] = device.GetLogical().CreateBuffer({ | 793 | buffers[level] = device.GetLogical().CreateBuffer({ |
| 794 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 794 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 795 | .pNext = nullptr, | 795 | .pNext = nullptr, |
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index e852c817e..329bf4def 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp | |||
| @@ -55,10 +55,4 @@ std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Cor | |||
| 55 | } | 55 | } |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | float GetResolutionScaleFactor(const RendererBase& renderer) { | ||
| 59 | return Settings::values.resolution_info.active | ||
| 60 | ? Settings::values.resolution_info.up_factor | ||
| 61 | : renderer.GetRenderWindow().GetFramebufferLayout().GetScalingRatio(); | ||
| 62 | } | ||
| 63 | |||
| 64 | } // namespace VideoCore | 58 | } // namespace VideoCore |
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index f86877e86..084df641f 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h | |||
| @@ -25,6 +25,4 @@ class RendererBase; | |||
| 25 | /// Creates an emulated GPU instance using the given system context. | 25 | /// Creates an emulated GPU instance using the given system context. |
| 26 | std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system); | 26 | std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system); |
| 27 | 27 | ||
| 28 | float GetResolutionScaleFactor(const RendererBase& renderer); | ||
| 29 | |||
| 30 | } // namespace VideoCore | 28 | } // namespace VideoCore |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 976acd176..fd0a130a3 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -303,6 +303,7 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, | |||
| 303 | connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram, | 303 | connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram, |
| 304 | Qt::QueuedConnection); | 304 | Qt::QueuedConnection); |
| 305 | connect(this, &GRenderWindow::ExitSignal, parent, &GMainWindow::OnExit, Qt::QueuedConnection); | 305 | connect(this, &GRenderWindow::ExitSignal, parent, &GMainWindow::OnExit, Qt::QueuedConnection); |
| 306 | connect(this, &GRenderWindow::TasPlaybackStateChanged, parent, &GMainWindow::OnTasStateChanged); | ||
| 306 | } | 307 | } |
| 307 | 308 | ||
| 308 | void GRenderWindow::ExecuteProgram(std::size_t program_index) { | 309 | void GRenderWindow::ExecuteProgram(std::size_t program_index) { |
| @@ -319,10 +320,18 @@ GRenderWindow::~GRenderWindow() { | |||
| 319 | 320 | ||
| 320 | void GRenderWindow::OnFrameDisplayed() { | 321 | void GRenderWindow::OnFrameDisplayed() { |
| 321 | input_subsystem->GetTas()->UpdateThread(); | 322 | input_subsystem->GetTas()->UpdateThread(); |
| 323 | const TasInput::TasState new_tas_state = std::get<0>(input_subsystem->GetTas()->GetStatus()); | ||
| 324 | |||
| 322 | if (!first_frame) { | 325 | if (!first_frame) { |
| 326 | last_tas_state = new_tas_state; | ||
| 323 | first_frame = true; | 327 | first_frame = true; |
| 324 | emit FirstFrameDisplayed(); | 328 | emit FirstFrameDisplayed(); |
| 325 | } | 329 | } |
| 330 | |||
| 331 | if (new_tas_state != last_tas_state) { | ||
| 332 | last_tas_state = new_tas_state; | ||
| 333 | emit TasPlaybackStateChanged(); | ||
| 334 | } | ||
| 326 | } | 335 | } |
| 327 | 336 | ||
| 328 | bool GRenderWindow::IsShown() const { | 337 | bool GRenderWindow::IsShown() const { |
| @@ -630,7 +639,7 @@ void GRenderWindow::ReleaseRenderTarget() { | |||
| 630 | 639 | ||
| 631 | void GRenderWindow::CaptureScreenshot(const QString& screenshot_path) { | 640 | void GRenderWindow::CaptureScreenshot(const QString& screenshot_path) { |
| 632 | auto& renderer = system.Renderer(); | 641 | auto& renderer = system.Renderer(); |
| 633 | const f32 res_scale = VideoCore::GetResolutionScaleFactor(renderer); | 642 | const f32 res_scale = Settings::values.resolution_info.up_factor; |
| 634 | 643 | ||
| 635 | const Layout::FramebufferLayout layout{Layout::FrameLayoutFromResolutionScale(res_scale)}; | 644 | const Layout::FramebufferLayout layout{Layout::FrameLayoutFromResolutionScale(res_scale)}; |
| 636 | screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32); | 645 | screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32); |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 40fd4a9d6..061e3605f 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -41,6 +41,10 @@ enum class LoadCallbackStage; | |||
| 41 | class RendererBase; | 41 | class RendererBase; |
| 42 | } // namespace VideoCore | 42 | } // namespace VideoCore |
| 43 | 43 | ||
| 44 | namespace TasInput { | ||
| 45 | enum class TasState; | ||
| 46 | } | ||
| 47 | |||
| 44 | class EmuThread final : public QThread { | 48 | class EmuThread final : public QThread { |
| 45 | Q_OBJECT | 49 | Q_OBJECT |
| 46 | 50 | ||
| @@ -203,6 +207,7 @@ signals: | |||
| 203 | void ExecuteProgramSignal(std::size_t program_index); | 207 | void ExecuteProgramSignal(std::size_t program_index); |
| 204 | void ExitSignal(); | 208 | void ExitSignal(); |
| 205 | void MouseActivity(); | 209 | void MouseActivity(); |
| 210 | void TasPlaybackStateChanged(); | ||
| 206 | 211 | ||
| 207 | private: | 212 | private: |
| 208 | void TouchBeginEvent(const QTouchEvent* event); | 213 | void TouchBeginEvent(const QTouchEvent* event); |
| @@ -236,6 +241,7 @@ private: | |||
| 236 | QWidget* child_widget = nullptr; | 241 | QWidget* child_widget = nullptr; |
| 237 | 242 | ||
| 238 | bool first_frame = false; | 243 | bool first_frame = false; |
| 244 | TasInput::TasState last_tas_state; | ||
| 239 | 245 | ||
| 240 | std::array<std::size_t, 16> touch_ids{}; | 246 | std::array<std::size_t, 16> touch_ids{}; |
| 241 | 247 | ||
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index c4c76b094..5058c3e4e 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -965,6 +965,9 @@ void GMainWindow::InitializeHotkeys() { | |||
| 965 | const QString toggle_status_bar = QStringLiteral("Toggle Status Bar"); | 965 | const QString toggle_status_bar = QStringLiteral("Toggle Status Bar"); |
| 966 | const QString fullscreen = QStringLiteral("Fullscreen"); | 966 | const QString fullscreen = QStringLiteral("Fullscreen"); |
| 967 | const QString capture_screenshot = QStringLiteral("Capture Screenshot"); | 967 | const QString capture_screenshot = QStringLiteral("Capture Screenshot"); |
| 968 | const QString tas_start_stop = QStringLiteral("TAS Start/Stop"); | ||
| 969 | const QString tas_record = QStringLiteral("TAS Record"); | ||
| 970 | const QString tas_reset = QStringLiteral("TAS Reset"); | ||
| 968 | 971 | ||
| 969 | ui->action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file)); | 972 | ui->action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file)); |
| 970 | ui->action_Load_File->setShortcutContext( | 973 | ui->action_Load_File->setShortcutContext( |
| @@ -1005,6 +1008,18 @@ void GMainWindow::InitializeHotkeys() { | |||
| 1005 | ui->action_Fullscreen->setShortcutContext( | 1008 | ui->action_Fullscreen->setShortcutContext( |
| 1006 | hotkey_registry.GetShortcutContext(main_window, fullscreen)); | 1009 | hotkey_registry.GetShortcutContext(main_window, fullscreen)); |
| 1007 | 1010 | ||
| 1011 | ui->action_TAS_Start->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_start_stop)); | ||
| 1012 | ui->action_TAS_Start->setShortcutContext( | ||
| 1013 | hotkey_registry.GetShortcutContext(main_window, tas_start_stop)); | ||
| 1014 | |||
| 1015 | ui->action_TAS_Record->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_record)); | ||
| 1016 | ui->action_TAS_Record->setShortcutContext( | ||
| 1017 | hotkey_registry.GetShortcutContext(main_window, tas_record)); | ||
| 1018 | |||
| 1019 | ui->action_TAS_Reset->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_reset)); | ||
| 1020 | ui->action_TAS_Reset->setShortcutContext( | ||
| 1021 | hotkey_registry.GetShortcutContext(main_window, tas_reset)); | ||
| 1022 | |||
| 1008 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this), | 1023 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this), |
| 1009 | &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile); | 1024 | &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile); |
| 1010 | connect( | 1025 | connect( |
| @@ -1095,28 +1110,6 @@ void GMainWindow::InitializeHotkeys() { | |||
| 1095 | render_window->setAttribute(Qt::WA_Hover, true); | 1110 | render_window->setAttribute(Qt::WA_Hover, true); |
| 1096 | } | 1111 | } |
| 1097 | }); | 1112 | }); |
| 1098 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Start/Stop"), this), | ||
| 1099 | &QShortcut::activated, this, [&] { | ||
| 1100 | if (!emulation_running) { | ||
| 1101 | return; | ||
| 1102 | } | ||
| 1103 | input_subsystem->GetTas()->StartStop(); | ||
| 1104 | }); | ||
| 1105 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Reset"), this), | ||
| 1106 | &QShortcut::activated, this, [&] { input_subsystem->GetTas()->Reset(); }); | ||
| 1107 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Record"), this), | ||
| 1108 | &QShortcut::activated, this, [&] { | ||
| 1109 | if (!emulation_running) { | ||
| 1110 | return; | ||
| 1111 | } | ||
| 1112 | bool is_recording = input_subsystem->GetTas()->Record(); | ||
| 1113 | if (!is_recording) { | ||
| 1114 | const auto res = QMessageBox::question(this, tr("TAS Recording"), | ||
| 1115 | tr("Overwrite file of player 1?"), | ||
| 1116 | QMessageBox::Yes | QMessageBox::No); | ||
| 1117 | input_subsystem->GetTas()->SaveRecording(res == QMessageBox::Yes); | ||
| 1118 | } | ||
| 1119 | }); | ||
| 1120 | } | 1113 | } |
| 1121 | 1114 | ||
| 1122 | void GMainWindow::SetDefaultUIGeometry() { | 1115 | void GMainWindow::SetDefaultUIGeometry() { |
| @@ -1236,11 +1229,11 @@ void GMainWindow::ConnectMenuEvents() { | |||
| 1236 | connect(ui->action_Restart, &QAction::triggered, this, | 1229 | connect(ui->action_Restart, &QAction::triggered, this, |
| 1237 | [this] { BootGame(QString(game_path)); }); | 1230 | [this] { BootGame(QString(game_path)); }); |
| 1238 | connect(ui->action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure); | 1231 | connect(ui->action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure); |
| 1239 | connect(ui->action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas); | ||
| 1240 | connect(ui->action_Configure_Current_Game, &QAction::triggered, this, | 1232 | connect(ui->action_Configure_Current_Game, &QAction::triggered, this, |
| 1241 | &GMainWindow::OnConfigurePerGame); | 1233 | &GMainWindow::OnConfigurePerGame); |
| 1242 | 1234 | ||
| 1243 | // View | 1235 | // View |
| 1236 | connect(ui->action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); | ||
| 1244 | connect(ui->action_Single_Window_Mode, &QAction::triggered, this, | 1237 | connect(ui->action_Single_Window_Mode, &QAction::triggered, this, |
| 1245 | &GMainWindow::ToggleWindowMode); | 1238 | &GMainWindow::ToggleWindowMode); |
| 1246 | connect(ui->action_Display_Dock_Widget_Headers, &QAction::triggered, this, | 1239 | connect(ui->action_Display_Dock_Widget_Headers, &QAction::triggered, this, |
| @@ -1258,17 +1251,20 @@ void GMainWindow::ConnectMenuEvents() { | |||
| 1258 | ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_900); | 1251 | ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_900); |
| 1259 | ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_1080); | 1252 | ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_1080); |
| 1260 | 1253 | ||
| 1261 | // Fullscreen | 1254 | // Tools |
| 1262 | connect(ui->action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); | 1255 | connect(ui->action_Rederive, &QAction::triggered, this, |
| 1263 | 1256 | std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning)); | |
| 1264 | // Movie | ||
| 1265 | connect(ui->action_Capture_Screenshot, &QAction::triggered, this, | 1257 | connect(ui->action_Capture_Screenshot, &QAction::triggered, this, |
| 1266 | &GMainWindow::OnCaptureScreenshot); | 1258 | &GMainWindow::OnCaptureScreenshot); |
| 1267 | 1259 | ||
| 1260 | // TAS | ||
| 1261 | connect(ui->action_TAS_Start, &QAction::triggered, this, &GMainWindow::OnTasStartStop); | ||
| 1262 | connect(ui->action_TAS_Record, &QAction::triggered, this, &GMainWindow::OnTasRecord); | ||
| 1263 | connect(ui->action_TAS_Reset, &QAction::triggered, this, &GMainWindow::OnTasReset); | ||
| 1264 | connect(ui->action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas); | ||
| 1265 | |||
| 1268 | // Help | 1266 | // Help |
| 1269 | connect(ui->action_Open_yuzu_Folder, &QAction::triggered, this, &GMainWindow::OnOpenYuzuFolder); | 1267 | connect(ui->action_Open_yuzu_Folder, &QAction::triggered, this, &GMainWindow::OnOpenYuzuFolder); |
| 1270 | connect(ui->action_Rederive, &QAction::triggered, this, | ||
| 1271 | std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning)); | ||
| 1272 | connect(ui->action_About, &QAction::triggered, this, &GMainWindow::OnAbout); | 1268 | connect(ui->action_About, &QAction::triggered, this, &GMainWindow::OnAbout); |
| 1273 | } | 1269 | } |
| 1274 | 1270 | ||
| @@ -1582,6 +1578,7 @@ void GMainWindow::ShutdownGame() { | |||
| 1582 | game_list->SetFilterFocus(); | 1578 | game_list->SetFilterFocus(); |
| 1583 | tas_label->clear(); | 1579 | tas_label->clear(); |
| 1584 | input_subsystem->GetTas()->Stop(); | 1580 | input_subsystem->GetTas()->Stop(); |
| 1581 | OnTasStateChanged(); | ||
| 1585 | 1582 | ||
| 1586 | render_window->removeEventFilter(render_window); | 1583 | render_window->removeEventFilter(render_window); |
| 1587 | render_window->setAttribute(Qt::WA_Hover, false); | 1584 | render_window->setAttribute(Qt::WA_Hover, false); |
| @@ -2509,6 +2506,7 @@ void GMainWindow::OnStartGame() { | |||
| 2509 | ui->action_Restart->setEnabled(true); | 2506 | ui->action_Restart->setEnabled(true); |
| 2510 | ui->action_Configure_Current_Game->setEnabled(true); | 2507 | ui->action_Configure_Current_Game->setEnabled(true); |
| 2511 | ui->action_Report_Compatibility->setEnabled(true); | 2508 | ui->action_Report_Compatibility->setEnabled(true); |
| 2509 | OnTasStateChanged(); | ||
| 2512 | 2510 | ||
| 2513 | discord_rpc->Update(); | 2511 | discord_rpc->Update(); |
| 2514 | ui->action_Load_Amiibo->setEnabled(true); | 2512 | ui->action_Load_Amiibo->setEnabled(true); |
| @@ -2821,6 +2819,32 @@ void GMainWindow::OnConfigureTas() { | |||
| 2821 | } | 2819 | } |
| 2822 | } | 2820 | } |
| 2823 | 2821 | ||
| 2822 | void GMainWindow::OnTasStartStop() { | ||
| 2823 | if (!emulation_running) { | ||
| 2824 | return; | ||
| 2825 | } | ||
| 2826 | input_subsystem->GetTas()->StartStop(); | ||
| 2827 | OnTasStateChanged(); | ||
| 2828 | } | ||
| 2829 | |||
| 2830 | void GMainWindow::OnTasRecord() { | ||
| 2831 | if (!emulation_running) { | ||
| 2832 | return; | ||
| 2833 | } | ||
| 2834 | const bool is_recording = input_subsystem->GetTas()->Record(); | ||
| 2835 | if (!is_recording) { | ||
| 2836 | const auto res = | ||
| 2837 | QMessageBox::question(this, tr("TAS Recording"), tr("Overwrite file of player 1?"), | ||
| 2838 | QMessageBox::Yes | QMessageBox::No); | ||
| 2839 | input_subsystem->GetTas()->SaveRecording(res == QMessageBox::Yes); | ||
| 2840 | } | ||
| 2841 | OnTasStateChanged(); | ||
| 2842 | } | ||
| 2843 | |||
| 2844 | void GMainWindow::OnTasReset() { | ||
| 2845 | input_subsystem->GetTas()->Reset(); | ||
| 2846 | } | ||
| 2847 | |||
| 2824 | void GMainWindow::OnConfigurePerGame() { | 2848 | void GMainWindow::OnConfigurePerGame() { |
| 2825 | const u64 title_id = system->GetCurrentProcessProgramID(); | 2849 | const u64 title_id = system->GetCurrentProcessProgramID(); |
| 2826 | OpenPerGameConfiguration(title_id, game_path.toStdString()); | 2850 | OpenPerGameConfiguration(title_id, game_path.toStdString()); |
| @@ -3014,6 +3038,23 @@ QString GMainWindow::GetTasStateDescription() const { | |||
| 3014 | } | 3038 | } |
| 3015 | } | 3039 | } |
| 3016 | 3040 | ||
| 3041 | void GMainWindow::OnTasStateChanged() { | ||
| 3042 | bool is_running = false; | ||
| 3043 | bool is_recording = false; | ||
| 3044 | if (emulation_running) { | ||
| 3045 | const TasInput::TasState tas_status = std::get<0>(input_subsystem->GetTas()->GetStatus()); | ||
| 3046 | is_running = tas_status == TasInput::TasState::Running; | ||
| 3047 | is_recording = tas_status == TasInput::TasState::Recording; | ||
| 3048 | } | ||
| 3049 | |||
| 3050 | ui->action_TAS_Start->setText(is_running ? tr("&Stop Running") : tr("&Start")); | ||
| 3051 | ui->action_TAS_Record->setText(is_recording ? tr("Stop R&ecording") : tr("R&ecord")); | ||
| 3052 | |||
| 3053 | ui->action_TAS_Start->setEnabled(emulation_running); | ||
| 3054 | ui->action_TAS_Record->setEnabled(emulation_running); | ||
| 3055 | ui->action_TAS_Reset->setEnabled(emulation_running); | ||
| 3056 | } | ||
| 3057 | |||
| 3017 | void GMainWindow::UpdateStatusBar() { | 3058 | void GMainWindow::UpdateStatusBar() { |
| 3018 | if (emu_thread == nullptr) { | 3059 | if (emu_thread == nullptr) { |
| 3019 | status_bar_update_timer.stop(); | 3060 | status_bar_update_timer.stop(); |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 24633ff2d..556cbbaf7 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -177,6 +177,7 @@ public slots: | |||
| 177 | void WebBrowserOpenWebPage(const std::string& main_url, const std::string& additional_args, | 177 | void WebBrowserOpenWebPage(const std::string& main_url, const std::string& additional_args, |
| 178 | bool is_local); | 178 | bool is_local); |
| 179 | void OnAppFocusStateChanged(Qt::ApplicationState state); | 179 | void OnAppFocusStateChanged(Qt::ApplicationState state); |
| 180 | void OnTasStateChanged(); | ||
| 180 | 181 | ||
| 181 | private: | 182 | private: |
| 182 | void RegisterMetaTypes(); | 183 | void RegisterMetaTypes(); |
| @@ -268,6 +269,9 @@ private slots: | |||
| 268 | void OnMenuRecentFile(); | 269 | void OnMenuRecentFile(); |
| 269 | void OnConfigure(); | 270 | void OnConfigure(); |
| 270 | void OnConfigureTas(); | 271 | void OnConfigureTas(); |
| 272 | void OnTasStartStop(); | ||
| 273 | void OnTasRecord(); | ||
| 274 | void OnTasReset(); | ||
| 271 | void OnConfigurePerGame(); | 275 | void OnConfigurePerGame(); |
| 272 | void OnLoadAmiibo(); | 276 | void OnLoadAmiibo(); |
| 273 | void OnOpenYuzuFolder(); | 277 | void OnOpenYuzuFolder(); |
| @@ -313,6 +317,7 @@ private: | |||
| 313 | void OpenURL(const QUrl& url); | 317 | void OpenURL(const QUrl& url); |
| 314 | void LoadTranslation(); | 318 | void LoadTranslation(); |
| 315 | void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); | 319 | void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); |
| 320 | |||
| 316 | QString GetTasStateDescription() const; | 321 | QString GetTasStateDescription() const; |
| 317 | 322 | ||
| 318 | std::unique_ptr<Ui::MainWindow> ui; | 323 | std::unique_ptr<Ui::MainWindow> ui; |
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index a62e39a06..c58aa2866 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui | |||
| @@ -79,39 +79,39 @@ | |||
| 79 | <string>&View</string> | 79 | <string>&View</string> |
| 80 | </property> | 80 | </property> |
| 81 | <widget class="QMenu" name="menu_Reset_Window_Size"> | 81 | <widget class="QMenu" name="menu_Reset_Window_Size"> |
| 82 | <property name="title"> | 82 | <property name="title"> |
| 83 | <string>&Reset Window Size</string> | 83 | <string>&Reset Window Size</string> |
| 84 | </property> | 84 | </property> |
| 85 | </widget> | ||
| 86 | <widget class="QMenu" name="menu_View_Debugging"> | ||
| 87 | <property name="title"> | ||
| 88 | <string>&Debugging</string> | ||
| 89 | </property> | ||
| 85 | </widget> | 90 | </widget> |
| 86 | <action name="action_Reset_Window_Size_720"> | 91 | <action name="action_Reset_Window_Size_720"> |
| 87 | <property name="text"> | 92 | <property name="text"> |
| 88 | <string>Reset Window Size to &720p</string> | 93 | <string>Reset Window Size to &720p</string> |
| 89 | </property> | 94 | </property> |
| 90 | <property name="iconText"> | 95 | <property name="iconText"> |
| 91 | <string>Reset Window Size to 720p</string> | 96 | <string>Reset Window Size to 720p</string> |
| 92 | </property> | 97 | </property> |
| 93 | </action> | 98 | </action> |
| 94 | <action name="action_Reset_Window_Size_900"> | 99 | <action name="action_Reset_Window_Size_900"> |
| 95 | <property name="text"> | 100 | <property name="text"> |
| 96 | <string>Reset Window Size to &900p</string> | 101 | <string>Reset Window Size to &900p</string> |
| 97 | </property> | 102 | </property> |
| 98 | <property name="iconText"> | 103 | <property name="iconText"> |
| 99 | <string>Reset Window Size to 900p</string> | 104 | <string>Reset Window Size to 900p</string> |
| 100 | </property> | 105 | </property> |
| 101 | </action> | 106 | </action> |
| 102 | <action name="action_Reset_Window_Size_1080"> | 107 | <action name="action_Reset_Window_Size_1080"> |
| 103 | <property name="text"> | 108 | <property name="text"> |
| 104 | <string>Reset Window Size to &1080p</string> | 109 | <string>Reset Window Size to &1080p</string> |
| 105 | </property> | ||
| 106 | <property name="iconText"> | ||
| 107 | <string>Reset Window Size to 1080p</string> | ||
| 108 | </property> | ||
| 109 | </action> | ||
| 110 | <widget class="QMenu" name="menu_View_Debugging"> | ||
| 111 | <property name="title"> | ||
| 112 | <string>&Debugging</string> | ||
| 113 | </property> | 110 | </property> |
| 114 | </widget> | 111 | <property name="iconText"> |
| 112 | <string>Reset Window Size to 1080p</string> | ||
| 113 | </property> | ||
| 114 | </action> | ||
| 115 | <addaction name="action_Fullscreen"/> | 115 | <addaction name="action_Fullscreen"/> |
| 116 | <addaction name="action_Single_Window_Mode"/> | 116 | <addaction name="action_Single_Window_Mode"/> |
| 117 | <addaction name="action_Display_Dock_Widget_Headers"/> | 117 | <addaction name="action_Display_Dock_Widget_Headers"/> |
| @@ -125,10 +125,20 @@ | |||
| 125 | <property name="title"> | 125 | <property name="title"> |
| 126 | <string>&Tools</string> | 126 | <string>&Tools</string> |
| 127 | </property> | 127 | </property> |
| 128 | <widget class="QMenu" name="menuTAS"> | ||
| 129 | <property name="title"> | ||
| 130 | <string>&TAS</string> | ||
| 131 | </property> | ||
| 132 | <addaction name="action_TAS_Start"/> | ||
| 133 | <addaction name="action_TAS_Record"/> | ||
| 134 | <addaction name="action_TAS_Reset"/> | ||
| 135 | <addaction name="separator"/> | ||
| 136 | <addaction name="action_Configure_Tas"/> | ||
| 137 | </widget> | ||
| 128 | <addaction name="action_Rederive"/> | 138 | <addaction name="action_Rederive"/> |
| 129 | <addaction name="separator"/> | 139 | <addaction name="separator"/> |
| 130 | <addaction name="action_Capture_Screenshot"/> | 140 | <addaction name="action_Capture_Screenshot"/> |
| 131 | <addaction name="action_Configure_Tas"/> | 141 | <addaction name="menuTAS"/> |
| 132 | </widget> | 142 | </widget> |
| 133 | <widget class="QMenu" name="menu_Help"> | 143 | <widget class="QMenu" name="menu_Help"> |
| 134 | <property name="title"> | 144 | <property name="title"> |
| @@ -309,7 +319,7 @@ | |||
| 309 | </action> | 319 | </action> |
| 310 | <action name="action_Configure_Tas"> | 320 | <action name="action_Configure_Tas"> |
| 311 | <property name="text"> | 321 | <property name="text"> |
| 312 | <string>Configure &TAS...</string> | 322 | <string>&Configure TAS...</string> |
| 313 | </property> | 323 | </property> |
| 314 | </action> | 324 | </action> |
| 315 | <action name="action_Configure_Current_Game"> | 325 | <action name="action_Configure_Current_Game"> |
| @@ -320,6 +330,30 @@ | |||
| 320 | <string>Configure C&urrent Game...</string> | 330 | <string>Configure C&urrent Game...</string> |
| 321 | </property> | 331 | </property> |
| 322 | </action> | 332 | </action> |
| 333 | <action name="action_TAS_Start"> | ||
| 334 | <property name="enabled"> | ||
| 335 | <bool>false</bool> | ||
| 336 | </property> | ||
| 337 | <property name="text"> | ||
| 338 | <string>&Start</string> | ||
| 339 | </property> | ||
| 340 | </action> | ||
| 341 | <action name="action_TAS_Reset"> | ||
| 342 | <property name="enabled"> | ||
| 343 | <bool>false</bool> | ||
| 344 | </property> | ||
| 345 | <property name="text"> | ||
| 346 | <string>&Reset</string> | ||
| 347 | </property> | ||
| 348 | </action> | ||
| 349 | <action name="action_TAS_Record"> | ||
| 350 | <property name="enabled"> | ||
| 351 | <bool>false</bool> | ||
| 352 | </property> | ||
| 353 | <property name="text"> | ||
| 354 | <string>R&ecord</string> | ||
| 355 | </property> | ||
| 356 | </action> | ||
| 323 | </widget> | 357 | </widget> |
| 324 | <resources> | 358 | <resources> |
| 325 | <include location="yuzu.qrc"/> | 359 | <include location="yuzu.qrc"/> |