From 0104e28fe4215468b8c444500e24b62d1ec0cc56 Mon Sep 17 00:00:00 2001 From: FernandoS27 Date: Thu, 25 Nov 2021 11:42:20 +0100 Subject: [PATCH 01/24] Vulkan: Add support for VK_EXT_depth_clip_control. --- .../spirv/emit_spirv_context_get_set.cpp | 2 +- .../backend/spirv/emit_spirv_special.cpp | 5 ++-- src/shader_recompiler/profile.h | 1 + .../renderer_opengl/gl_shader_cache.cpp | 1 + .../renderer_vulkan/vk_graphics_pipeline.cpp | 18 ++++++++++--- .../renderer_vulkan/vk_pipeline_cache.cpp | 1 + .../vulkan_common/vulkan_device.cpp | 25 +++++++++++++++++++ src/video_core/vulkan_common/vulkan_device.h | 6 +++++ 8 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index 01f6ec9b5e..73b67f0af6 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp @@ -461,7 +461,7 @@ void EmitSetSampleMask(EmitContext& ctx, Id value) { } void EmitSetFragDepth(EmitContext& ctx, Id value) { - if (!ctx.runtime_info.convert_depth_mode) { + if (!ctx.runtime_info.convert_depth_mode || ctx.profile.support_native_ndc) { ctx.OpStore(ctx.frag_depth, value); return; } diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp index 00be1f1276..9f7b6bb4be 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp @@ -116,7 +116,8 @@ void EmitPrologue(EmitContext& ctx) { } void EmitEpilogue(EmitContext& ctx) { - if (ctx.stage == Stage::VertexB && ctx.runtime_info.convert_depth_mode) { + if (ctx.stage == Stage::VertexB && ctx.runtime_info.convert_depth_mode && + !ctx.profile.support_native_ndc) { ConvertDepthMode(ctx); } if (ctx.stage == Stage::Fragment) { @@ -125,7 +126,7 @@ void EmitEpilogue(EmitContext& ctx) { } void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) { - if (ctx.runtime_info.convert_depth_mode) { + if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) { ConvertDepthMode(ctx); } if (stream.IsImmediate()) { diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h index 21d3d236b7..b8841a5367 100644 --- a/src/shader_recompiler/profile.h +++ b/src/shader_recompiler/profile.h @@ -35,6 +35,7 @@ struct Profile { bool support_int64_atomics{}; bool support_derivative_control{}; bool support_geometry_shader_passthrough{}; + bool support_native_ndc{}; bool support_gl_nv_gpu_shader_5{}; bool support_gl_amd_gpu_shader_half_float{}; bool support_gl_texture_shadow_lod{}; diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index a59d0d24e0..b12ecd4786 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -203,6 +203,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo .support_int64_atomics = false, .support_derivative_control = device.HasDerivativeControl(), .support_geometry_shader_passthrough = device.HasGeometryShaderPassthrough(), + .support_native_ndc = true, .support_gl_nv_gpu_shader_5 = device.HasNvGpuShader5(), .support_gl_amd_gpu_shader_half_float = device.HasAmdShaderHalfFloat(), .support_gl_texture_shadow_lod = device.HasTextureShadowLod(), diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 006128638d..00d7dbeeae 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -634,23 +634,33 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { }; std::array swizzles; std::ranges::transform(key.state.viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle); - const VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ + VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV, .pNext = nullptr, .flags = 0, .viewportCount = Maxwell::NumViewports, .pViewportSwizzles = swizzles.data(), }; - const VkPipelineViewportStateCreateInfo viewport_ci{ + VkPipelineViewportDepthClipControlCreateInfoEXT ndc_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT, + .pNext = nullptr, + .negativeOneToOne = key.state.ndc_minus_one_to_one.Value() != 0 ? VK_TRUE : VK_FALSE, + }; + VkPipelineViewportStateCreateInfo viewport_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, - .pNext = device.IsNvViewportSwizzleSupported() ? &swizzle_ci : nullptr, + .pNext = nullptr, .flags = 0, .viewportCount = Maxwell::NumViewports, .pViewports = nullptr, .scissorCount = Maxwell::NumViewports, .pScissors = nullptr, }; - + if (device.IsNvViewportSwizzleSupported()) { + swizzle_ci.pNext = std::exchange(viewport_ci.pNext, &swizzle_ci); + } + if (device.IsExtDepthClipControlSupported()) { + ndc_info.pNext = std::exchange(viewport_ci.pNext, &ndc_info); + } VkPipelineRasterizationStateCreateInfo rasterization_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pNext = nullptr, diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 81f5f3e11b..66c9f959a8 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -321,6 +321,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device .support_int64_atomics = device.IsExtShaderAtomicInt64Supported(), .support_derivative_control = true, .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), + .support_native_ndc = device.IsExtDepthClipControlSupported(), .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 6a2ad4b1d7..3604c83c16 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -660,6 +660,16 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted"); } + VkPhysicalDeviceDepthClipControlFeaturesEXT depth_clip_control_features; + if (ext_depth_clip_control) { + depth_clip_control_features = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT, + .pNext = nullptr, + .depthClipControl = VK_TRUE, + }; + SetNext(next, depth_clip_control_features); + } + VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv; if (Settings::values.enable_nsight_aftermath && nv_device_diagnostics_config) { nsight_aftermath_tracker = std::make_unique(); @@ -1083,6 +1093,7 @@ std::vector Device::LoadExtensions(bool requires_surface) { bool has_ext_vertex_input_dynamic_state{}; bool has_ext_line_rasterization{}; bool has_ext_primitive_topology_list_restart{}; + bool has_ext_depth_clip_control{}; for (const std::string& extension : supported_extensions) { const auto test = [&](std::optional> status, const char* name, bool push) { @@ -1116,6 +1127,7 @@ std::vector Device::LoadExtensions(bool requires_surface) { test(ext_shader_stencil_export, VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, true); test(ext_conservative_rasterization, VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME, true); + test(has_ext_depth_clip_control, VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME, false); test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false); test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false); test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); @@ -1279,6 +1291,19 @@ std::vector Device::LoadExtensions(bool requires_surface) { ext_line_rasterization = true; } } + if (has_ext_depth_clip_control) { + VkPhysicalDeviceDepthClipControlFeaturesEXT depth_clip_control_features; + depth_clip_control_features.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT; + depth_clip_control_features.pNext = nullptr; + features.pNext = &depth_clip_control_features; + physical.GetFeatures2(features); + + if (depth_clip_control_features.depthClipControl) { + extensions.push_back(VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME); + ext_depth_clip_control = true; + } + } if (has_khr_workgroup_memory_explicit_layout) { VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR layout; layout.sType = diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index db802437cb..3755275c32 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -256,6 +256,11 @@ public: return ext_depth_range_unrestricted; } + /// Returns true if the device supports VK_EXT_depth_clip_control. + bool IsExtDepthClipControlSupported() const { + return ext_depth_clip_control; + } + /// Returns true if the device supports VK_EXT_shader_viewport_index_layer. bool IsExtShaderViewportIndexLayerSupported() const { return ext_shader_viewport_index_layer; @@ -446,6 +451,7 @@ private: bool khr_swapchain_mutable_format{}; ///< Support for VK_KHR_swapchain_mutable_format. bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8. bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax. + bool ext_depth_clip_control{}; ///< Support for VK_EXT_depth_clip_control bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer. bool ext_tooling_info{}; ///< Support for VK_EXT_tooling_info. From b1d633532f25efedd8c89f2a18d47921d33d6088 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Thu, 15 Dec 2022 23:22:11 -0500 Subject: [PATCH 02/24] hle_ipc: Refactor ReadBuffer to set buffer size upon initialization Initializing the vector size during initialization is more efficient than a later call to resize() --- src/core/hle/kernel/hle_ipc.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 06010b8d18..286e3f0782 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -318,25 +318,23 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa } std::vector HLERequestContext::ReadBuffer(std::size_t buffer_index) const { - std::vector buffer{}; const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && BufferDescriptorA()[buffer_index].Size()}; - if (is_buffer_a) { ASSERT_OR_EXECUTE_MSG( - BufferDescriptorA().size() > buffer_index, { return buffer; }, + BufferDescriptorA().size() > buffer_index, { return {}; }, "BufferDescriptorA invalid buffer_index {}", buffer_index); - buffer.resize(BufferDescriptorA()[buffer_index].Size()); + std::vector buffer(BufferDescriptorA()[buffer_index].Size()); memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); + return buffer; } else { ASSERT_OR_EXECUTE_MSG( - BufferDescriptorX().size() > buffer_index, { return buffer; }, + BufferDescriptorX().size() > buffer_index, { return {}; }, "BufferDescriptorX invalid buffer_index {}", buffer_index); - buffer.resize(BufferDescriptorX()[buffer_index].Size()); + std::vector buffer(BufferDescriptorX()[buffer_index].Size()); memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); + return buffer; } - - return buffer; } std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, From b81caf1879125ecf63b8d43b4b87850e90ead71d Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 16 Dec 2022 08:47:22 -0500 Subject: [PATCH 03/24] qt: handle wayland-egl platform name --- src/yuzu/bootmanager.cpp | 7 +++++-- src/yuzu/main.cpp | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 1a47fb9c96..7c89228415 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -269,12 +269,14 @@ static Core::Frontend::WindowSystemType GetWindowSystemType() { return Core::Frontend::WindowSystemType::X11; else if (platform_name == QStringLiteral("wayland")) return Core::Frontend::WindowSystemType::Wayland; + else if (platform_name == QStringLiteral("wayland-egl")) + return Core::Frontend::WindowSystemType::Wayland; else if (platform_name == QStringLiteral("cocoa")) return Core::Frontend::WindowSystemType::Cocoa; else if (platform_name == QStringLiteral("android")) return Core::Frontend::WindowSystemType::Android; - LOG_CRITICAL(Frontend, "Unknown Qt platform!"); + LOG_CRITICAL(Frontend, "Unknown Qt platform {}!", platform_name.toStdString()); return Core::Frontend::WindowSystemType::Windows; } @@ -314,7 +316,8 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, input_subsystem->Initialize(); this->setMouseTracking(true); - strict_context_required = QGuiApplication::platformName() == QStringLiteral("wayland"); + strict_context_required = QGuiApplication::platformName() == QStringLiteral("wayland") || + QGuiApplication::platformName() == QStringLiteral("wayland-egl"); connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram, diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 885e24990c..e68b4f7993 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2917,7 +2917,8 @@ static QScreen* GuessCurrentScreen(QWidget* window) { bool GMainWindow::UsingExclusiveFullscreen() { return Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive || - QGuiApplication::platformName() == QStringLiteral("wayland"); + QGuiApplication::platformName() == QStringLiteral("wayland") || + QGuiApplication::platformName() == QStringLiteral("wayland-egl"); } void GMainWindow::ShowFullscreen() { From 6a56f42f5d94e2be405a736a74b86ffe3ab1b37b Mon Sep 17 00:00:00 2001 From: Kelebek1 Date: Fri, 16 Dec 2022 16:01:35 +0000 Subject: [PATCH 04/24] Signal buffer event on audio in/out system stop, and force remove all registered audio buffers --- src/audio_core/device/audio_buffers.h | 8 +++++--- src/audio_core/device/device_session.cpp | 6 ++++++ src/audio_core/device/device_session.h | 5 +++++ src/audio_core/in/audio_in_system.cpp | 7 +++++-- src/audio_core/out/audio_out_system.cpp | 7 +++++-- 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/audio_core/device/audio_buffers.h b/src/audio_core/device/audio_buffers.h index 3dae1a3b71..15082f6c62 100644 --- a/src/audio_core/device/audio_buffers.h +++ b/src/audio_core/device/audio_buffers.h @@ -91,9 +91,10 @@ public: * @param core_timing - The CoreTiming instance * @param session - The device session * - * @return Is the buffer was released. + * @return If any buffer was released. */ - bool ReleaseBuffers(const Core::Timing::CoreTiming& core_timing, const DeviceSession& session) { + bool ReleaseBuffers(const Core::Timing::CoreTiming& core_timing, const DeviceSession& session, + bool force) { std::scoped_lock l{lock}; bool buffer_released{false}; while (registered_count > 0) { @@ -103,7 +104,8 @@ public: } // Check with the backend if this buffer can be released yet. - if (!session.IsBufferConsumed(buffers[index])) { + // If we're shutting down, we don't care if it's been played or not. + if (!force && !session.IsBufferConsumed(buffers[index])) { break; } diff --git a/src/audio_core/device/device_session.cpp b/src/audio_core/device/device_session.cpp index 9950604147..5a327a6068 100644 --- a/src/audio_core/device/device_session.cpp +++ b/src/audio_core/device/device_session.cpp @@ -73,6 +73,12 @@ void DeviceSession::Stop() { } } +void DeviceSession::ClearBuffers() { + if (stream) { + stream->ClearQueue(); + } +} + void DeviceSession::AppendBuffers(std::span buffers) const { for (const auto& buffer : buffers) { Sink::SinkBuffer new_buffer{ diff --git a/src/audio_core/device/device_session.h b/src/audio_core/device/device_session.h index 74f4dc0850..75f766c68f 100644 --- a/src/audio_core/device/device_session.h +++ b/src/audio_core/device/device_session.h @@ -90,6 +90,11 @@ public: */ void Stop(); + /** + * Clear out the underlying audio buffers in the backend stream. + */ + void ClearBuffers(); + /** * Set this device session's volume. * diff --git a/src/audio_core/in/audio_in_system.cpp b/src/audio_core/in/audio_in_system.cpp index 4324cafd84..934ef8c1c6 100644 --- a/src/audio_core/in/audio_in_system.cpp +++ b/src/audio_core/in/audio_in_system.cpp @@ -23,7 +23,6 @@ System::~System() { void System::Finalize() { Stop(); session->Finalize(); - buffer_event->Signal(); } void System::StartSession() { @@ -102,6 +101,10 @@ Result System::Stop() { if (state == State::Started) { session->Stop(); session->SetVolume(0.0f); + session->ClearBuffers(); + if (buffers.ReleaseBuffers(system.CoreTiming(), *session, true)) { + buffer_event->Signal(); + } state = State::Stopped; } @@ -138,7 +141,7 @@ void System::RegisterBuffers() { } void System::ReleaseBuffers() { - bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session)}; + bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session, false)}; if (signal) { // Signal if any buffer was released, or if none are registered, we need more. diff --git a/src/audio_core/out/audio_out_system.cpp b/src/audio_core/out/audio_out_system.cpp index a66208ed9c..e096a1dac0 100644 --- a/src/audio_core/out/audio_out_system.cpp +++ b/src/audio_core/out/audio_out_system.cpp @@ -24,7 +24,6 @@ System::~System() { void System::Finalize() { Stop(); session->Finalize(); - buffer_event->Signal(); } std::string_view System::GetDefaultOutputDeviceName() const { @@ -102,6 +101,10 @@ Result System::Stop() { if (state == State::Started) { session->Stop(); session->SetVolume(0.0f); + session->ClearBuffers(); + if (buffers.ReleaseBuffers(system.CoreTiming(), *session, true)) { + buffer_event->Signal(); + } state = State::Stopped; } @@ -138,7 +141,7 @@ void System::RegisterBuffers() { } void System::ReleaseBuffers() { - bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session)}; + bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session, false)}; if (signal) { // Signal if any buffer was released, or if none are registered, we need more. buffer_event->Signal(); From f7d95d0a3a41eb91b084f9c9d7c5c9c51d4131fb Mon Sep 17 00:00:00 2001 From: Kelebek1 Date: Fri, 16 Dec 2022 22:52:29 +0000 Subject: [PATCH 05/24] Remove unimplemented transform feedback geometry spam, it should be implemented --- src/video_core/renderer_vulkan/vk_rasterizer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index a8b82abaef..4b7126c305 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -658,8 +658,7 @@ void RasterizerVulkan::BeginTransformFeedback() { return; } UNIMPLEMENTED_IF(regs.IsShaderConfigEnabled(Maxwell::ShaderType::TessellationInit) || - regs.IsShaderConfigEnabled(Maxwell::ShaderType::Tessellation) || - regs.IsShaderConfigEnabled(Maxwell::ShaderType::Geometry)); + regs.IsShaderConfigEnabled(Maxwell::ShaderType::Tessellation)); scheduler.Record( [](vk::CommandBuffer cmdbuf) { cmdbuf.BeginTransformFeedbackEXT(0, 0, nullptr, nullptr); }); } From 7bf4bec257dffb633d818fb1a7ade6b899ec79a5 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Thu, 15 Dec 2022 22:50:36 -0500 Subject: [PATCH 06/24] camera: Use pre-allocated vector for camera data And avoid an unnecessary copy --- src/input_common/drivers/camera.cpp | 2 +- src/input_common/drivers/camera.h | 4 +++- src/yuzu/bootmanager.cpp | 12 +++++------- src/yuzu/bootmanager.h | 3 +++ 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/input_common/drivers/camera.cpp b/src/input_common/drivers/camera.cpp index dceea67e04..fad9177dcb 100644 --- a/src/input_common/drivers/camera.cpp +++ b/src/input_common/drivers/camera.cpp @@ -17,7 +17,7 @@ Camera::Camera(std::string input_engine_) : InputEngine(std::move(input_engine_) PreSetController(identifier); } -void Camera::SetCameraData(std::size_t width, std::size_t height, std::vector data) { +void Camera::SetCameraData(std::size_t width, std::size_t height, std::span data) { const std::size_t desired_width = getImageWidth(); const std::size_t desired_height = getImageHeight(); status.data.resize(desired_width * desired_height); diff --git a/src/input_common/drivers/camera.h b/src/input_common/drivers/camera.h index b8a7c75e55..38fb1ae4c9 100644 --- a/src/input_common/drivers/camera.h +++ b/src/input_common/drivers/camera.h @@ -3,6 +3,8 @@ #pragma once +#include + #include "input_common/input_engine.h" namespace InputCommon { @@ -15,7 +17,7 @@ class Camera final : public InputEngine { public: explicit Camera(std::string input_engine_); - void SetCameraData(std::size_t width, std::size_t height, std::vector data); + void SetCameraData(std::size_t width, std::size_t height, std::span data); std::size_t getImageWidth() const; std::size_t getImageHeight() const; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 1a47fb9c96..09959d154e 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -752,6 +752,7 @@ void GRenderWindow::InitializeCamera() { return; } + camera_data.resize(CAMERA_WIDTH * CAMERA_HEIGHT); camera_capture->setCaptureDestination(QCameraImageCapture::CaptureDestination::CaptureToBuffer); connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this, &GRenderWindow::OnCameraCapture); @@ -807,16 +808,13 @@ void GRenderWindow::RequestCameraCapture() { } void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) { - constexpr std::size_t camera_width = 320; - constexpr std::size_t camera_height = 240; + // TODO: Capture directly in the format and resolution needed const auto converted = - img.scaled(camera_width, camera_height, Qt::AspectRatioMode::IgnoreAspectRatio, + img.scaled(CAMERA_WIDTH, CAMERA_HEIGHT, Qt::AspectRatioMode::IgnoreAspectRatio, Qt::TransformationMode::SmoothTransformation) .mirrored(false, true); - std::vector camera_data{}; - camera_data.resize(camera_width * camera_height); - std::memcpy(camera_data.data(), converted.bits(), camera_width * camera_height * sizeof(u32)); - input_subsystem->GetCamera()->SetCameraData(camera_width, camera_height, camera_data); + std::memcpy(camera_data.data(), converted.bits(), CAMERA_WIDTH * CAMERA_HEIGHT * sizeof(u32)); + input_subsystem->GetCamera()->SetCameraData(CAMERA_WIDTH, CAMERA_HEIGHT, camera_data); pending_camera_snapshots = 0; } diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index f4deae4ee3..4dec2da2ad 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -246,6 +246,9 @@ private: #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA std::unique_ptr camera; std::unique_ptr camera_capture; + static constexpr std::size_t CAMERA_WIDTH = 320; + static constexpr std::size_t CAMERA_HEIGHT = 240; + std::vector camera_data; #endif std::unique_ptr camera_timer; From 243404bf34b1470369e1d0f5f2dd18ac02435273 Mon Sep 17 00:00:00 2001 From: german77 Date: Fri, 16 Dec 2022 16:16:54 -0600 Subject: [PATCH 07/24] input_common: Add virtual gamepad --- src/core/hid/emulated_controller.cpp | 82 ++++++++++++++++++++ src/core/hid/emulated_controller.h | 9 +++ src/input_common/CMakeLists.txt | 2 + src/input_common/drivers/virtual_gamepad.cpp | 78 +++++++++++++++++++ src/input_common/drivers/virtual_gamepad.h | 73 +++++++++++++++++ src/input_common/main.cpp | 23 ++++++ src/input_common/main.h | 7 ++ 7 files changed, 274 insertions(+) create mode 100644 src/input_common/drivers/virtual_gamepad.cpp create mode 100644 src/input_common/drivers/virtual_gamepad.h diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 67969e938a..f238d6ccd7 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -145,6 +145,7 @@ void EmulatedController::LoadDevices() { output_params[3].Set("output", true); LoadTASParams(); + LoadVirtualGamepadParams(); std::ranges::transform(button_params, button_devices.begin(), Common::Input::CreateInputDevice); std::ranges::transform(stick_params, stick_devices.begin(), Common::Input::CreateInputDevice); @@ -163,6 +164,12 @@ void EmulatedController::LoadDevices() { Common::Input::CreateInputDevice); std::ranges::transform(tas_stick_params, tas_stick_devices.begin(), Common::Input::CreateInputDevice); + + // Initialize virtual gamepad devices + std::ranges::transform(virtual_button_params, virtual_button_devices.begin(), + Common::Input::CreateInputDevice); + std::ranges::transform(virtual_stick_params, virtual_stick_devices.begin(), + Common::Input::CreateInputDevice); } void EmulatedController::LoadTASParams() { @@ -205,6 +212,46 @@ void EmulatedController::LoadTASParams() { tas_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3); } +void EmulatedController::LoadVirtualGamepadParams() { + const auto player_index = NpadIdTypeToIndex(npad_id_type); + Common::ParamPackage common_params{}; + common_params.Set("engine", "virtual_gamepad"); + common_params.Set("port", static_cast(player_index)); + for (auto& param : virtual_button_params) { + param = common_params; + } + for (auto& param : virtual_stick_params) { + param = common_params; + } + + // TODO(german77): Replace this with an input profile or something better + virtual_button_params[Settings::NativeButton::A].Set("button", 0); + virtual_button_params[Settings::NativeButton::B].Set("button", 1); + virtual_button_params[Settings::NativeButton::X].Set("button", 2); + virtual_button_params[Settings::NativeButton::Y].Set("button", 3); + virtual_button_params[Settings::NativeButton::LStick].Set("button", 4); + virtual_button_params[Settings::NativeButton::RStick].Set("button", 5); + virtual_button_params[Settings::NativeButton::L].Set("button", 6); + virtual_button_params[Settings::NativeButton::R].Set("button", 7); + virtual_button_params[Settings::NativeButton::ZL].Set("button", 8); + virtual_button_params[Settings::NativeButton::ZR].Set("button", 9); + virtual_button_params[Settings::NativeButton::Plus].Set("button", 10); + virtual_button_params[Settings::NativeButton::Minus].Set("button", 11); + virtual_button_params[Settings::NativeButton::DLeft].Set("button", 12); + virtual_button_params[Settings::NativeButton::DUp].Set("button", 13); + virtual_button_params[Settings::NativeButton::DRight].Set("button", 14); + virtual_button_params[Settings::NativeButton::DDown].Set("button", 15); + virtual_button_params[Settings::NativeButton::SL].Set("button", 16); + virtual_button_params[Settings::NativeButton::SR].Set("button", 17); + virtual_button_params[Settings::NativeButton::Home].Set("button", 18); + virtual_button_params[Settings::NativeButton::Screenshot].Set("button", 19); + + virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0); + virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1); + virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_x", 2); + virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3); +} + void EmulatedController::ReloadInput() { // If you load any device here add the equivalent to the UnloadInput() function LoadDevices(); @@ -322,6 +369,35 @@ void EmulatedController::ReloadInput() { }, }); } + + // Use a common UUID for Virtual Gamepad + static constexpr Common::UUID VIRTUAL_UUID = Common::UUID{ + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; + + // Register virtual devices. No need to force update + for (std::size_t index = 0; index < virtual_button_devices.size(); ++index) { + if (!virtual_button_devices[index]) { + continue; + } + virtual_button_devices[index]->SetCallback({ + .on_change = + [this, index](const Common::Input::CallbackStatus& callback) { + SetButton(callback, index, VIRTUAL_UUID); + }, + }); + } + + for (std::size_t index = 0; index < virtual_stick_devices.size(); ++index) { + if (!virtual_stick_devices[index]) { + continue; + } + virtual_stick_devices[index]->SetCallback({ + .on_change = + [this, index](const Common::Input::CallbackStatus& callback) { + SetStick(callback, index, VIRTUAL_UUID); + }, + }); + } } void EmulatedController::UnloadInput() { @@ -349,6 +425,12 @@ void EmulatedController::UnloadInput() { for (auto& stick : tas_stick_devices) { stick.reset(); } + for (auto& button : virtual_button_devices) { + button.reset(); + } + for (auto& stick : virtual_stick_devices) { + stick.reset(); + } camera_devices.reset(); nfc_devices.reset(); } diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index fa7a342787..a398543a64 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -385,6 +385,9 @@ private: /// Set the params for TAS devices void LoadTASParams(); + /// Set the params for virtual pad devices + void LoadVirtualGamepadParams(); + /** * @param use_temporary_value If true tmp_npad_type will be used * @return true if the controller style is fullkey @@ -500,6 +503,12 @@ private: ButtonDevices tas_button_devices; StickDevices tas_stick_devices; + // Virtual gamepad related variables + ButtonParams virtual_button_params; + StickParams virtual_stick_params; + ButtonDevices virtual_button_devices; + StickDevices virtual_stick_devices; + mutable std::mutex mutex; mutable std::mutex callback_mutex; std::unordered_map callback_list; diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 7932aaab02..f24c89b04c 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -20,6 +20,8 @@ add_library(input_common STATIC drivers/udp_client.h drivers/virtual_amiibo.cpp drivers/virtual_amiibo.h + drivers/virtual_gamepad.cpp + drivers/virtual_gamepad.h helpers/stick_from_buttons.cpp helpers/stick_from_buttons.h helpers/touch_from_buttons.cpp diff --git a/src/input_common/drivers/virtual_gamepad.cpp b/src/input_common/drivers/virtual_gamepad.cpp new file mode 100644 index 0000000000..7db945aa64 --- /dev/null +++ b/src/input_common/drivers/virtual_gamepad.cpp @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "input_common/drivers/virtual_gamepad.h" + +namespace InputCommon { +constexpr std::size_t PlayerIndexCount = 10; + +VirtualGamepad::VirtualGamepad(std::string input_engine_) : InputEngine(std::move(input_engine_)) { + for (std::size_t i = 0; i < PlayerIndexCount; i++) { + PreSetController(GetIdentifier(i)); + } +} + +void VirtualGamepad::SetButtonState(std::size_t player_index, int button_id, bool value) { + if (player_index > PlayerIndexCount) { + return; + } + const auto identifier = GetIdentifier(player_index); + SetButton(identifier, button_id, value); +} + +void VirtualGamepad::SetButtonState(std::size_t player_index, VirtualButton button_id, bool value) { + SetButtonState(player_index, static_cast(button_id), value); +} + +void VirtualGamepad::SetStickPosition(std::size_t player_index, int axis_id, float x_value, + float y_value) { + if (player_index > PlayerIndexCount) { + return; + } + const auto identifier = GetIdentifier(player_index); + SetAxis(identifier, axis_id * 2, x_value); + SetAxis(identifier, (axis_id * 2) + 1, y_value); +} + +void VirtualGamepad::SetStickPosition(std::size_t player_index, VirtualStick axis_id, float x_value, + float y_value) { + SetStickPosition(player_index, static_cast(axis_id), x_value, y_value); +} + +void VirtualGamepad::ResetControllers() { + for (std::size_t i = 0; i < PlayerIndexCount; i++) { + SetStickPosition(i, VirtualStick::Left, 0.0f, 0.0f); + SetStickPosition(i, VirtualStick::Right, 0.0f, 0.0f); + + SetButtonState(i, VirtualButton::ButtonA, false); + SetButtonState(i, VirtualButton::ButtonB, false); + SetButtonState(i, VirtualButton::ButtonX, false); + SetButtonState(i, VirtualButton::ButtonY, false); + SetButtonState(i, VirtualButton::StickL, false); + SetButtonState(i, VirtualButton::StickR, false); + SetButtonState(i, VirtualButton::TriggerL, false); + SetButtonState(i, VirtualButton::TriggerR, false); + SetButtonState(i, VirtualButton::TriggerZL, false); + SetButtonState(i, VirtualButton::TriggerZR, false); + SetButtonState(i, VirtualButton::ButtonPlus, false); + SetButtonState(i, VirtualButton::ButtonMinus, false); + SetButtonState(i, VirtualButton::ButtonLeft, false); + SetButtonState(i, VirtualButton::ButtonUp, false); + SetButtonState(i, VirtualButton::ButtonRight, false); + SetButtonState(i, VirtualButton::ButtonDown, false); + SetButtonState(i, VirtualButton::ButtonSL, false); + SetButtonState(i, VirtualButton::ButtonSR, false); + SetButtonState(i, VirtualButton::ButtonHome, false); + SetButtonState(i, VirtualButton::ButtonCapture, false); + } +} + +PadIdentifier VirtualGamepad::GetIdentifier(std::size_t player_index) const { + return { + .guid = Common::UUID{}, + .port = player_index, + .pad = 0, + }; +} + +} // namespace InputCommon diff --git a/src/input_common/drivers/virtual_gamepad.h b/src/input_common/drivers/virtual_gamepad.h new file mode 100644 index 0000000000..3df91cc6fa --- /dev/null +++ b/src/input_common/drivers/virtual_gamepad.h @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "input_common/input_engine.h" + +namespace InputCommon { + +/** + * A virtual controller that is always assigned to the game input + */ +class VirtualGamepad final : public InputEngine { +public: + enum class VirtualButton { + ButtonA, + ButtonB, + ButtonX, + ButtonY, + StickL, + StickR, + TriggerL, + TriggerR, + TriggerZL, + TriggerZR, + ButtonPlus, + ButtonMinus, + ButtonLeft, + ButtonUp, + ButtonRight, + ButtonDown, + ButtonSL, + ButtonSR, + ButtonHome, + ButtonCapture, + }; + + enum class VirtualStick { + Left = 0, + Right = 1, + }; + + explicit VirtualGamepad(std::string input_engine_); + + /** + * Sets the status of all buttons bound with the key to pressed + * @param player_index the player number that will take this action + * @param button_id the id of the button + * @param value indicates if the button is pressed or not + */ + void SetButtonState(std::size_t player_index, int button_id, bool value); + void SetButtonState(std::size_t player_index, VirtualButton button_id, bool value); + + /** + * Sets the status of all buttons bound with the key to released + * @param player_index the player number that will take this action + * @param axis_id the id of the axis to move + * @param x_value the position of the stick in the x axis + * @param y_value the position of the stick in the y axis + */ + void SetStickPosition(std::size_t player_index, int axis_id, float x_value, float y_value); + void SetStickPosition(std::size_t player_index, VirtualStick axis_id, float x_value, + float y_value); + + /// Restores all inputs into the neutral position + void ResetControllers(); + +private: + /// Returns the correct identifier corresponding to the player index + PadIdentifier GetIdentifier(std::size_t player_index) const; +}; + +} // namespace InputCommon diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 942a135359..75b856c959 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -12,6 +12,7 @@ #include "input_common/drivers/touch_screen.h" #include "input_common/drivers/udp_client.h" #include "input_common/drivers/virtual_amiibo.h" +#include "input_common/drivers/virtual_gamepad.h" #include "input_common/helpers/stick_from_buttons.h" #include "input_common/helpers/touch_from_buttons.h" #include "input_common/input_engine.h" @@ -85,6 +86,12 @@ struct InputSubsystem::Impl { Common::Input::RegisterOutputFactory(virtual_amiibo->GetEngineName(), virtual_amiibo_output_factory); + virtual_gamepad = std::make_shared("virtual_gamepad"); + virtual_gamepad->SetMappingCallback(mapping_callback); + virtual_gamepad_input_factory = std::make_shared(virtual_gamepad); + Common::Input::RegisterInputFactory(virtual_gamepad->GetEngineName(), + virtual_gamepad_input_factory); + #ifdef HAVE_SDL2 sdl = std::make_shared("sdl"); sdl->SetMappingCallback(mapping_callback); @@ -132,6 +139,9 @@ struct InputSubsystem::Impl { Common::Input::UnregisterOutputFactory(virtual_amiibo->GetEngineName()); virtual_amiibo.reset(); + Common::Input::UnregisterInputFactory(virtual_gamepad->GetEngineName()); + virtual_gamepad.reset(); + #ifdef HAVE_SDL2 Common::Input::UnregisterInputFactory(sdl->GetEngineName()); Common::Input::UnregisterOutputFactory(sdl->GetEngineName()); @@ -290,6 +300,9 @@ struct InputSubsystem::Impl { if (engine == tas_input->GetEngineName()) { return true; } + if (engine == virtual_gamepad->GetEngineName()) { + return true; + } #ifdef HAVE_SDL2 if (engine == sdl->GetEngineName()) { return true; @@ -338,6 +351,7 @@ struct InputSubsystem::Impl { std::shared_ptr udp_client; std::shared_ptr camera; std::shared_ptr virtual_amiibo; + std::shared_ptr virtual_gamepad; std::shared_ptr keyboard_factory; std::shared_ptr mouse_factory; @@ -347,6 +361,7 @@ struct InputSubsystem::Impl { std::shared_ptr tas_input_factory; std::shared_ptr camera_input_factory; std::shared_ptr virtual_amiibo_input_factory; + std::shared_ptr virtual_gamepad_input_factory; std::shared_ptr keyboard_output_factory; std::shared_ptr mouse_output_factory; @@ -423,6 +438,14 @@ const VirtualAmiibo* InputSubsystem::GetVirtualAmiibo() const { return impl->virtual_amiibo.get(); } +VirtualGamepad* InputSubsystem::GetVirtualGamepad() { + return impl->virtual_gamepad.get(); +} + +const VirtualGamepad* InputSubsystem::GetVirtualGamepad() const { + return impl->virtual_gamepad.get(); +} + std::vector InputSubsystem::GetInputDevices() const { return impl->GetInputDevices(); } diff --git a/src/input_common/main.h b/src/input_common/main.h index 6218c37f64..1207d786cb 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -34,6 +34,7 @@ class Keyboard; class Mouse; class TouchScreen; class VirtualAmiibo; +class VirtualGamepad; struct MappingData; } // namespace InputCommon @@ -108,6 +109,12 @@ public: /// Retrieves the underlying virtual amiibo input device. [[nodiscard]] const VirtualAmiibo* GetVirtualAmiibo() const; + /// Retrieves the underlying virtual gamepad input device. + [[nodiscard]] VirtualGamepad* GetVirtualGamepad(); + + /// Retrieves the underlying virtual gamepad input device. + [[nodiscard]] const VirtualGamepad* GetVirtualGamepad() const; + /** * Returns all available input devices that this Factory can create a new device with. * Each returned ParamPackage should have a `display` field used for display, a `engine` field From 45672d43e3a88b735dffab36e4e503b76055e59d Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 17 Dec 2022 10:19:18 -0500 Subject: [PATCH 08/24] qt: avoid setting WA_DontCreateNativeAncestors on all platforms --- src/yuzu/bootmanager.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 642f966908..7147c6aaa0 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -44,6 +44,8 @@ #include "yuzu/bootmanager.h" #include "yuzu/main.h" +static Core::Frontend::WindowSystemType GetWindowSystemType(); + EmuThread::EmuThread(Core::System& system_) : system{system_} {} EmuThread::~EmuThread() = default; @@ -228,8 +230,10 @@ class RenderWidget : public QWidget { public: explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { setAttribute(Qt::WA_NativeWindow); - setAttribute(Qt::WA_DontCreateNativeAncestors); setAttribute(Qt::WA_PaintOnScreen); + if (GetWindowSystemType() == Core::Frontend::WindowSystemType::Wayland) { + setAttribute(Qt::WA_DontCreateNativeAncestors); + } } virtual ~RenderWidget() = default; From d3123079e887710580b622b444a642ae298ddec0 Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 17 Dec 2022 14:34:03 -0500 Subject: [PATCH 09/24] EmuThread: refactor --- src/core/core.cpp | 18 +++------ src/core/core.h | 4 +- src/yuzu/bootmanager.cpp | 82 ++++++++++++++-------------------------- src/yuzu/bootmanager.h | 51 ++++++++++++------------- src/yuzu/main.cpp | 80 ++------------------------------------- src/yuzu/main.h | 1 - 6 files changed, 64 insertions(+), 172 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index a738f221ff..47292cd78f 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -183,26 +183,20 @@ struct System::Impl { Initialize(system); } - SystemResultStatus Run() { + void Run() { std::unique_lock lk(suspend_guard); - status = SystemResultStatus::Success; kernel.Suspend(false); core_timing.SyncPause(false); is_paused.store(false, std::memory_order_relaxed); - - return status; } - SystemResultStatus Pause() { + void Pause() { std::unique_lock lk(suspend_guard); - status = SystemResultStatus::Success; core_timing.SyncPause(true); kernel.Suspend(true); is_paused.store(true, std::memory_order_relaxed); - - return status; } bool IsPaused() const { @@ -553,12 +547,12 @@ void System::Initialize() { impl->Initialize(*this); } -SystemResultStatus System::Run() { - return impl->Run(); +void System::Run() { + impl->Run(); } -SystemResultStatus System::Pause() { - return impl->Pause(); +void System::Pause() { + impl->Pause(); } bool System::IsPaused() const { diff --git a/src/core/core.h b/src/core/core.h index 4ebedffd91..fb5cda2f56 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -152,13 +152,13 @@ public: * Run the OS and Application * This function will start emulation and run the relevant devices */ - [[nodiscard]] SystemResultStatus Run(); + void Run(); /** * Pause the OS and Application * This function will pause emulation and stop the relevant devices */ - [[nodiscard]] SystemResultStatus Pause(); + void Pause(); /// Check if the core is currently paused. [[nodiscard]] bool IsPaused() const; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 682b37f47b..40b3d91fcc 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -46,30 +46,28 @@ static Core::Frontend::WindowSystemType GetWindowSystemType(); -EmuThread::EmuThread(Core::System& system_) : system{system_} {} +EmuThread::EmuThread(Core::System& system) : m_system{system} {} EmuThread::~EmuThread() = default; void EmuThread::run() { - std::string name = "EmuControlThread"; - MicroProfileOnThreadCreate(name.c_str()); - Common::SetCurrentThreadName(name.c_str()); + const char* name = "EmuControlThread"; + MicroProfileOnThreadCreate(name); + Common::SetCurrentThreadName(name); - auto& gpu = system.GPU(); - auto stop_token = stop_source.get_token(); - bool debugger_should_start = system.DebuggerEnabled(); + auto& gpu = m_system.GPU(); + auto stop_token = m_stop_source.get_token(); - system.RegisterHostThread(); + m_system.RegisterHostThread(); // Main process has been loaded. Make the context current to this thread and begin GPU and CPU // execution. gpu.ObtainContext(); emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); - if (Settings::values.use_disk_shader_cache.GetValue()) { - system.Renderer().ReadRasterizer()->LoadDiskResources( - system.GetCurrentProcessProgramID(), stop_token, + m_system.Renderer().ReadRasterizer()->LoadDiskResources( + m_system.GetCurrentProcessProgramID(), stop_token, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { emit LoadProgress(stage, value, total); }); @@ -79,57 +77,35 @@ void EmuThread::run() { gpu.ReleaseContext(); gpu.Start(); - system.GetCpuManager().OnGpuReady(); + m_system.GetCpuManager().OnGpuReady(); + m_system.RegisterExitCallback([this] { m_stop_source.request_stop(); }); - system.RegisterExitCallback([this]() { - stop_source.request_stop(); - SetRunning(false); - }); + if (m_system.DebuggerEnabled()) { + m_system.InitializeDebugger(); + } - // Holds whether the cpu was running during the last iteration, - // so that the DebugModeLeft signal can be emitted before the - // next execution step - bool was_active = false; while (!stop_token.stop_requested()) { - if (running) { - if (was_active) { - emit DebugModeLeft(); - } + std::unique_lock lk{m_should_run_mutex}; + if (m_should_run) { + m_system.Run(); + m_is_running.store(true); + m_is_running.notify_all(); - running_guard = true; - Core::SystemResultStatus result = system.Run(); - if (result != Core::SystemResultStatus::Success) { - running_guard = false; - this->SetRunning(false); - emit ErrorThrown(result, system.GetStatusDetails()); - } - - if (debugger_should_start) { - system.InitializeDebugger(); - debugger_should_start = false; - } - - running_wait.Wait(); - result = system.Pause(); - if (result != Core::SystemResultStatus::Success) { - running_guard = false; - this->SetRunning(false); - emit ErrorThrown(result, system.GetStatusDetails()); - } - running_guard = false; - - if (!stop_token.stop_requested()) { - was_active = true; - emit DebugModeEntered(); - } + Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return !m_should_run; }); } else { - std::unique_lock lock{running_mutex}; - Common::CondvarWait(running_cv, lock, stop_token, [&] { return IsRunning(); }); + m_system.Pause(); + m_is_running.store(false); + m_is_running.notify_all(); + + emit DebugModeEntered(); + Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return m_should_run; }); + emit DebugModeLeft(); } } // Shutdown the main emulated process - system.ShutdownMainProcess(); + m_system.DetachDebugger(); + m_system.ShutdownMainProcess(); #if MICROPROFILE_ENABLED MicroProfileOnThreadExit(); diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 5bbcf61f74..52867d628b 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -47,7 +47,7 @@ class EmuThread final : public QThread { Q_OBJECT public: - explicit EmuThread(Core::System& system_); + explicit EmuThread(Core::System& system); ~EmuThread() override; /** @@ -57,30 +57,30 @@ public: void run() override; /** - * Sets whether the emulation thread is running or not - * @param running_ Boolean value, set the emulation thread to running if true - * @note This function is thread-safe + * Sets whether the emulation thread should run or not + * @param should_run Boolean value, set the emulation thread to running if true */ - void SetRunning(bool running_) { - std::unique_lock lock{running_mutex}; - running = running_; - lock.unlock(); - running_cv.notify_all(); - if (!running) { - running_wait.Set(); - /// Wait until effectively paused - while (running_guard) - ; + void SetRunning(bool should_run) { + // TODO: Prevent other threads from modifying the state until we finish. + { + // Notify the running thread to change state. + std::unique_lock run_lk{m_should_run_mutex}; + m_should_run = should_run; + m_should_run_cv.notify_one(); + } + + // Wait until paused, if pausing. + if (!should_run) { + m_is_running.wait(true); } } /** * Check if the emulation thread is running or not * @return True if the emulation thread is running, otherwise false - * @note This function is thread-safe */ bool IsRunning() const { - return running; + return m_is_running.load(); } /** @@ -88,18 +88,17 @@ public: */ void ForceStop() { LOG_WARNING(Frontend, "Force stopping EmuThread"); - stop_source.request_stop(); - SetRunning(false); + m_stop_source.request_stop(); } private: - bool running = false; - std::stop_source stop_source; - std::mutex running_mutex; - std::condition_variable_any running_cv; - Common::Event running_wait{}; - std::atomic_bool running_guard{false}; - Core::System& system; + Core::System& m_system; + + std::stop_source m_stop_source; + std::mutex m_should_run_mutex; + std::condition_variable_any m_should_run_cv; + std::atomic m_is_running{false}; + bool m_should_run{true}; signals: /** @@ -120,8 +119,6 @@ signals: */ void DebugModeLeft(); - void ErrorThrown(Core::SystemResultStatus, std::string); - void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total); }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 2e6c2311ac..c5285ffc96 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1794,15 +1794,16 @@ void GMainWindow::ShutdownGame() { Settings::values.use_speed_limit.SetValue(true); system->SetShuttingDown(true); - system->DetachDebugger(); discord_rpc->Pause(); RequestGameExit(); + emu_thread->disconnect(); + emu_thread->SetRunning(true); emit EmulationStopping(); // Wait for emulation thread to complete and delete it - if (!emu_thread->wait(5000)) { + if (system->DebuggerEnabled() || !emu_thread->wait(5000)) { emu_thread->ForceStop(); emu_thread->wait(); } @@ -2916,8 +2917,6 @@ void GMainWindow::OnStartGame() { emu_thread->SetRunning(true); - connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); - UpdateMenuState(); OnTasStateChanged(); @@ -3901,79 +3900,6 @@ void GMainWindow::OnMouseActivity() { mouse_center_timer.stop(); } -void GMainWindow::OnCoreError(Core::SystemResultStatus result, std::string details) { - QMessageBox::StandardButton answer; - QString status_message; - const QString common_message = - tr("The game you are trying to load requires additional files from your Switch to be " - "dumped " - "before playing.

For more information on dumping these files, please see the " - "following wiki page: Dumping System " - "Archives and the Shared Fonts from a Switch Console.

Would you like to " - "quit " - "back to the game list? Continuing emulation may result in crashes, corrupted save " - "data, or other bugs."); - switch (result) { - case Core::SystemResultStatus::ErrorSystemFiles: { - QString message; - if (details.empty()) { - message = - tr("yuzu was unable to locate a Switch system archive. %1").arg(common_message); - } else { - message = tr("yuzu was unable to locate a Switch system archive: %1. %2") - .arg(QString::fromStdString(details), common_message); - } - - answer = QMessageBox::question(this, tr("System Archive Not Found"), message, - QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - status_message = tr("System Archive Missing"); - break; - } - - case Core::SystemResultStatus::ErrorSharedFont: { - const QString message = - tr("yuzu was unable to locate the Switch shared fonts. %1").arg(common_message); - answer = QMessageBox::question(this, tr("Shared Fonts Not Found"), message, - QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - status_message = tr("Shared Font Missing"); - break; - } - - default: - answer = QMessageBox::question( - this, tr("Fatal Error"), - tr("yuzu has encountered a fatal error, please see the log for more details. " - "For more information on accessing the log, please see the following page: " - "How " - "to " - "Upload the Log File.

Would you like to quit back to the game " - "list? " - "Continuing emulation may result in crashes, corrupted save data, or other " - "bugs."), - QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - status_message = tr("Fatal Error encountered"); - break; - } - - if (answer == QMessageBox::Yes) { - if (emu_thread) { - ShutdownGame(); - - Settings::RestoreGlobalState(system->IsPoweredOn()); - system->HIDCore().ReloadInputDevices(); - UpdateStatusButtons(); - } - } else { - // Only show the message if the game is still running. - if (emu_thread) { - emu_thread->SetRunning(true); - message_label->setText(status_message); - } - } -} - void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { if (behavior == ReinitializeKeyBehavior::Warning) { const auto res = QMessageBox::information( diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 1047ba276e..5b84c7a007 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -332,7 +332,6 @@ private slots: void ResetWindowSize900(); void ResetWindowSize1080(); void OnCaptureScreenshot(); - void OnCoreError(Core::SystemResultStatus, std::string); void OnReinitializeKeys(ReinitializeKeyBehavior behavior); void OnLanguageChanged(const QString& locale); void OnMouseActivity(); From 92ce241d4d49baaefb610480f65db73271f0c015 Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 17 Dec 2022 15:54:34 -0500 Subject: [PATCH 10/24] qt: use _exit instead of exit on SIGINT --- src/yuzu/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index c5285ffc96..c6f285dc26 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1498,7 +1498,7 @@ void GMainWindow::SetupSigInterrupts() { void GMainWindow::HandleSigInterrupt(int sig) { if (sig == SIGINT) { - exit(1); + _exit(1); } // Calling into Qt directly from a signal handler is not safe, From fd1ea0fd8463c65f3d266512cba04a5c9d0863da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Locatti?= <42481638+goldenx86@users.noreply.github.com> Date: Sat, 17 Dec 2022 22:16:52 -0300 Subject: [PATCH 11/24] Enable compiler optimizations and enforce x86-64-v2 on GCC/Clang (#9442) * Testing LTO (#4) * Testing LTO * clang * linux * Added the rest of Blinkhawk's optimizations * Unlikely asserts * Removing LTO from Linux builds - GCC * Removing LTO from Linux builds - Clang --- .ci/scripts/clang/docker.sh | 1 + .ci/scripts/linux/docker.sh | 1 + .ci/templates/build-msvc.yml | 2 +- src/common/assert.h | 4 ++-- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.ci/scripts/clang/docker.sh b/.ci/scripts/clang/docker.sh index 7d3ae4a1aa..51769545eb 100755 --- a/.ci/scripts/clang/docker.sh +++ b/.ci/scripts/clang/docker.sh @@ -11,6 +11,7 @@ ccache -s mkdir build || true && cd build cmake .. \ -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_CXX_FLAGS="-march=x86-64-v2" \ -DCMAKE_CXX_COMPILER=/usr/lib/ccache/clang++ \ -DCMAKE_C_COMPILER=/usr/lib/ccache/clang \ -DCMAKE_INSTALL_PREFIX="/usr" \ diff --git a/.ci/scripts/linux/docker.sh b/.ci/scripts/linux/docker.sh index 35c4a43687..c8bc56c9a5 100755 --- a/.ci/scripts/linux/docker.sh +++ b/.ci/scripts/linux/docker.sh @@ -12,6 +12,7 @@ mkdir build || true && cd build cmake .. \ -DBoost_USE_STATIC_LIBS=ON \ -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_CXX_FLAGS="-march=x86-64-v2" \ -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ \ -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc \ -DCMAKE_INSTALL_PREFIX="/usr" \ diff --git a/.ci/templates/build-msvc.yml b/.ci/templates/build-msvc.yml index ea405e5dc6..c379dd7575 100644 --- a/.ci/templates/build-msvc.yml +++ b/.ci/templates/build-msvc.yml @@ -9,7 +9,7 @@ parameters: steps: - script: choco install vulkan-sdk displayName: 'Install vulkan-sdk' -- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 17 2022" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd .. +- script: refreshenv && mkdir build && cd build && cmake -E env CXXFLAGS="/Gw /GA /Gr /Ob2" cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_POLICY_DEFAULT_CMP0069=NEW -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd .. displayName: 'Configure CMake' - task: MSBuild@1 displayName: 'Build' diff --git a/src/common/assert.h b/src/common/assert.h index 8c927fcc04..67e7e93751 100644 --- a/src/common/assert.h +++ b/src/common/assert.h @@ -69,7 +69,7 @@ void assert_fail_impl(); #define ASSERT_OR_EXECUTE(_a_, _b_) \ do { \ ASSERT(_a_); \ - if (!(_a_)) { \ + if (!(_a_)) [[unlikely]] { \ _b_ \ } \ } while (0) @@ -78,7 +78,7 @@ void assert_fail_impl(); #define ASSERT_OR_EXECUTE_MSG(_a_, _b_, ...) \ do { \ ASSERT_MSG(_a_, __VA_ARGS__); \ - if (!(_a_)) { \ + if (!(_a_)) [[unlikely]] { \ _b_ \ } \ } while (0) From dffeca66fa932cc6f89b2174009306366f66872a Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 17 Dec 2022 23:54:36 -0600 Subject: [PATCH 12/24] yuzu: fix device name setting --- src/yuzu/configuration/config.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index a8d47a2f9f..2ea4f367b0 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -783,8 +783,6 @@ void Config::ReadSystemValues() { } } - ReadBasicSetting(Settings::values.device_name); - if (global) { ReadBasicSetting(Settings::values.current_user); Settings::values.current_user = std::clamp(Settings::values.current_user.GetValue(), 0, @@ -797,6 +795,7 @@ void Config::ReadSystemValues() { } else { Settings::values.custom_rtc = std::nullopt; } + ReadBasicSetting(Settings::values.device_name); } ReadGlobalSetting(Settings::values.sound_index); @@ -1407,7 +1406,6 @@ void Config::SaveSystemValues() { Settings::values.rng_seed.UsingGlobal()); WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.GetValue(global).value_or(0), 0, Settings::values.rng_seed.UsingGlobal()); - WriteBasicSetting(Settings::values.device_name); if (global) { WriteBasicSetting(Settings::values.current_user); @@ -1416,6 +1414,7 @@ void Config::SaveSystemValues() { false); WriteSetting(QStringLiteral("custom_rtc"), QVariant::fromValue(Settings::values.custom_rtc.value_or(0)), 0); + WriteBasicSetting(Settings::values.device_name); } WriteGlobalSetting(Settings::values.sound_index); From c489cbee29102404c86502834ac842c75a815b40 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 17 Dec 2022 23:54:47 -0600 Subject: [PATCH 13/24] bootmanager: Encapsulate all QCamera code --- src/yuzu/bootmanager.cpp | 2 ++ src/yuzu/bootmanager.h | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 682b37f47b..ffd3f00287 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -820,6 +820,7 @@ void GRenderWindow::RequestCameraCapture() { } void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) { +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA // TODO: Capture directly in the format and resolution needed const auto converted = img.scaled(CAMERA_WIDTH, CAMERA_HEIGHT, Qt::AspectRatioMode::IgnoreAspectRatio, @@ -828,6 +829,7 @@ void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) { std::memcpy(camera_data.data(), converted.bits(), CAMERA_WIDTH * CAMERA_HEIGHT * sizeof(u32)); input_subsystem->GetCamera()->SetCameraData(CAMERA_WIDTH, CAMERA_HEIGHT, camera_data); pending_camera_snapshots = 0; +#endif } bool GRenderWindow::event(QEvent* event) { diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 5bbcf61f74..514437359d 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -242,16 +242,16 @@ private: bool first_frame = false; InputCommon::TasInput::TasState last_tas_state; - bool is_virtual_camera; - int pending_camera_snapshots; #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA - std::unique_ptr camera; - std::unique_ptr camera_capture; static constexpr std::size_t CAMERA_WIDTH = 320; static constexpr std::size_t CAMERA_HEIGHT = 240; + bool is_virtual_camera; + int pending_camera_snapshots; std::vector camera_data; -#endif + std::unique_ptr camera; + std::unique_ptr camera_capture; std::unique_ptr camera_timer; +#endif Core::System& system; From f999d268f99b77e35a5f83933765de62c52d1cb1 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 18 Dec 2022 00:10:20 -0600 Subject: [PATCH 14/24] bootmanager: Use proper camera size --- src/input_common/drivers/camera.h | 1 + src/yuzu/bootmanager.cpp | 16 ++++++++++++---- src/yuzu/bootmanager.h | 2 -- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/input_common/drivers/camera.h b/src/input_common/drivers/camera.h index 38fb1ae4c9..ead3e0fdee 100644 --- a/src/input_common/drivers/camera.h +++ b/src/input_common/drivers/camera.h @@ -25,6 +25,7 @@ public: Common::Input::CameraError SetCameraFormat(const PadIdentifier& identifier_, Common::Input::CameraFormat camera_format) override; +private: Common::Input::CameraStatus status{}; }; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index ffd3f00287..1368b20d5a 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -764,7 +764,9 @@ void GRenderWindow::InitializeCamera() { return; } - camera_data.resize(CAMERA_WIDTH * CAMERA_HEIGHT); + const auto camera_width = input_subsystem->GetCamera()->getImageWidth(); + const auto camera_height = input_subsystem->GetCamera()->getImageHeight(); + camera_data.resize(camera_width * camera_height); camera_capture->setCaptureDestination(QCameraImageCapture::CaptureDestination::CaptureToBuffer); connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this, &GRenderWindow::OnCameraCapture); @@ -822,12 +824,18 @@ void GRenderWindow::RequestCameraCapture() { void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) { #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA // TODO: Capture directly in the format and resolution needed + const auto camera_width = input_subsystem->GetCamera()->getImageWidth(); + const auto camera_height = input_subsystem->GetCamera()->getImageHeight(); const auto converted = - img.scaled(CAMERA_WIDTH, CAMERA_HEIGHT, Qt::AspectRatioMode::IgnoreAspectRatio, + img.scaled(static_cast(camera_width), static_cast(camera_height), + Qt::AspectRatioMode::IgnoreAspectRatio, Qt::TransformationMode::SmoothTransformation) .mirrored(false, true); - std::memcpy(camera_data.data(), converted.bits(), CAMERA_WIDTH * CAMERA_HEIGHT * sizeof(u32)); - input_subsystem->GetCamera()->SetCameraData(CAMERA_WIDTH, CAMERA_HEIGHT, camera_data); + if (camera_data.size() != camera_width * camera_height) { + camera_data.resize(camera_width * camera_height); + } + std::memcpy(camera_data.data(), converted.bits(), camera_width * camera_height * sizeof(u32)); + input_subsystem->GetCamera()->SetCameraData(camera_width, camera_height, camera_data); pending_camera_snapshots = 0; #endif } diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 514437359d..b24141fd9f 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -243,8 +243,6 @@ private: InputCommon::TasInput::TasState last_tas_state; #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA - static constexpr std::size_t CAMERA_WIDTH = 320; - static constexpr std::size_t CAMERA_HEIGHT = 240; bool is_virtual_camera; int pending_camera_snapshots; std::vector camera_data; From c218c7d4da427a924bf935d8e5e6be04f7e43da5 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 18 Dec 2022 00:36:21 -0600 Subject: [PATCH 15/24] yuzu: Remember last selected directory --- src/yuzu/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 2e6c2311ac..fe140dce02 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2661,6 +2661,9 @@ void GMainWindow::OnMenuInstallToNAND() { return; } + // Save folder location of the first selected file + UISettings::values.roms_path = QFileInfo(filenames[0]).path(); + int remaining = filenames.size(); // This would only overflow above 2^43 bytes (8.796 TB) From 56b0f979ebb3b1164a0e5d11fae186570c73e015 Mon Sep 17 00:00:00 2001 From: Marco Rubin <20150305+Rubo3@users.noreply.github.com> Date: Sun, 18 Dec 2022 14:03:26 +0000 Subject: [PATCH 16/24] Use execlp instead of execl to avoid failure --- src/yuzu/startup_checks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp index 5638183629..9f702fe95e 100644 --- a/src/yuzu/startup_checks.cpp +++ b/src/yuzu/startup_checks.cpp @@ -186,7 +186,7 @@ pid_t SpawnChild(const char* arg0) { return pid; } else if (pid == 0) { // child - execl(arg0, arg0, nullptr); + execlp(arg0, arg0, nullptr); const int err = errno; fmt::print(stderr, "execl failed with error {}\n", err); _exit(0); From 79f1f326c753663fc87ee01eb512dea69072ee19 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 18 Dec 2022 11:57:15 -0600 Subject: [PATCH 17/24] service: nfc: Silence ListDevices --- src/core/hle/service/nfc/nfc_user.cpp | 2 +- src/core/hle/service/nfp/nfp_user.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/hle/service/nfc/nfc_user.cpp b/src/core/hle/service/nfc/nfc_user.cpp index 4615697e28..89aa6b3f59 100644 --- a/src/core/hle/service/nfc/nfc_user.cpp +++ b/src/core/hle/service/nfc/nfc_user.cpp @@ -97,7 +97,7 @@ void IUser::IsNfcEnabled(Kernel::HLERequestContext& ctx) { } void IUser::ListDevices(Kernel::HLERequestContext& ctx) { - LOG_INFO(Service_NFC, "called"); + LOG_DEBUG(Service_NFC, "called"); if (state == State::NonInitialized) { IPC::ResponseBuilder rb{ctx, 2}; diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp index 49816b4c76..a4d3d1bc7f 100644 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ b/src/core/hle/service/nfp/nfp_user.cpp @@ -83,7 +83,7 @@ void IUser::Finalize(Kernel::HLERequestContext& ctx) { } void IUser::ListDevices(Kernel::HLERequestContext& ctx) { - LOG_INFO(Service_NFP, "called"); + LOG_DEBUG(Service_NFP, "called"); if (state == State::NonInitialized) { IPC::ResponseBuilder rb{ctx, 2}; From cf01a507fb3c49791daf2420eec9e7e9e41a9d6b Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 18 Dec 2022 13:24:02 -0600 Subject: [PATCH 18/24] input_common: Cleanup project --- src/input_common/input_mapping.cpp | 6 - src/input_common/main.cpp | 279 +++++++++-------------------- 2 files changed, 81 insertions(+), 204 deletions(-) diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp index 0fa4b1ddb0..edd5287c1e 100644 --- a/src/input_common/input_mapping.cpp +++ b/src/input_common/input_mapping.cpp @@ -200,12 +200,6 @@ bool MappingFactory::IsDriverValid(const MappingData& data) const { return false; } // The following drivers don't need to be mapped - if (data.engine == "tas") { - return false; - } - if (data.engine == "touch") { - return false; - } if (data.engine == "touch_from_button") { return false; } diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 75b856c959..86deb4c7c8 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -26,79 +26,33 @@ namespace InputCommon { struct InputSubsystem::Impl { - void Initialize() { - mapping_factory = std::make_shared(); + template + void RegisterEngine(std::string name, std::shared_ptr& engine) { MappingCallback mapping_callback{[this](const MappingData& data) { RegisterInput(data); }}; - keyboard = std::make_shared("keyboard"); - keyboard->SetMappingCallback(mapping_callback); - keyboard_factory = std::make_shared(keyboard); - keyboard_output_factory = std::make_shared(keyboard); - Common::Input::RegisterInputFactory(keyboard->GetEngineName(), keyboard_factory); - Common::Input::RegisterOutputFactory(keyboard->GetEngineName(), keyboard_output_factory); + engine = std::make_shared(name); + engine->SetMappingCallback(mapping_callback); - mouse = std::make_shared("mouse"); - mouse->SetMappingCallback(mapping_callback); - mouse_factory = std::make_shared(mouse); - mouse_output_factory = std::make_shared(mouse); - Common::Input::RegisterInputFactory(mouse->GetEngineName(), mouse_factory); - Common::Input::RegisterOutputFactory(mouse->GetEngineName(), mouse_output_factory); + std::shared_ptr input_factory = std::make_shared(engine); + std::shared_ptr output_factory = std::make_shared(engine); + Common::Input::RegisterInputFactory(engine->GetEngineName(), std::move(input_factory)); + Common::Input::RegisterOutputFactory(engine->GetEngineName(), std::move(output_factory)); + } - touch_screen = std::make_shared("touch"); - touch_screen_factory = std::make_shared(touch_screen); - Common::Input::RegisterInputFactory(touch_screen->GetEngineName(), touch_screen_factory); - - gcadapter = std::make_shared("gcpad"); - gcadapter->SetMappingCallback(mapping_callback); - gcadapter_input_factory = std::make_shared(gcadapter); - gcadapter_output_factory = std::make_shared(gcadapter); - Common::Input::RegisterInputFactory(gcadapter->GetEngineName(), gcadapter_input_factory); - Common::Input::RegisterOutputFactory(gcadapter->GetEngineName(), gcadapter_output_factory); - - udp_client = std::make_shared("cemuhookudp"); - udp_client->SetMappingCallback(mapping_callback); - udp_client_input_factory = std::make_shared(udp_client); - udp_client_output_factory = std::make_shared(udp_client); - Common::Input::RegisterInputFactory(udp_client->GetEngineName(), udp_client_input_factory); - Common::Input::RegisterOutputFactory(udp_client->GetEngineName(), - udp_client_output_factory); - - tas_input = std::make_shared("tas"); - tas_input->SetMappingCallback(mapping_callback); - tas_input_factory = std::make_shared(tas_input); - tas_output_factory = std::make_shared(tas_input); - Common::Input::RegisterInputFactory(tas_input->GetEngineName(), tas_input_factory); - Common::Input::RegisterOutputFactory(tas_input->GetEngineName(), tas_output_factory); - - camera = std::make_shared("camera"); - camera->SetMappingCallback(mapping_callback); - camera_input_factory = std::make_shared(camera); - camera_output_factory = std::make_shared(camera); - Common::Input::RegisterInputFactory(camera->GetEngineName(), camera_input_factory); - Common::Input::RegisterOutputFactory(camera->GetEngineName(), camera_output_factory); - - virtual_amiibo = std::make_shared("virtual_amiibo"); - virtual_amiibo->SetMappingCallback(mapping_callback); - virtual_amiibo_input_factory = std::make_shared(virtual_amiibo); - virtual_amiibo_output_factory = std::make_shared(virtual_amiibo); - Common::Input::RegisterInputFactory(virtual_amiibo->GetEngineName(), - virtual_amiibo_input_factory); - Common::Input::RegisterOutputFactory(virtual_amiibo->GetEngineName(), - virtual_amiibo_output_factory); - - virtual_gamepad = std::make_shared("virtual_gamepad"); - virtual_gamepad->SetMappingCallback(mapping_callback); - virtual_gamepad_input_factory = std::make_shared(virtual_gamepad); - Common::Input::RegisterInputFactory(virtual_gamepad->GetEngineName(), - virtual_gamepad_input_factory); + void Initialize() { + mapping_factory = std::make_shared(); + RegisterEngine("keyboard", keyboard); + RegisterEngine("mouse", mouse); + RegisterEngine("touch", touch_screen); + RegisterEngine("gcpad", gcadapter); + RegisterEngine("cemuhookudp", udp_client); + RegisterEngine("tas", tas_input); + RegisterEngine("camera", camera); + RegisterEngine("virtual_amiibo", virtual_amiibo); + RegisterEngine("virtual_gamepad", virtual_gamepad); #ifdef HAVE_SDL2 - sdl = std::make_shared("sdl"); - sdl->SetMappingCallback(mapping_callback); - sdl_input_factory = std::make_shared(sdl); - sdl_output_factory = std::make_shared(sdl); - Common::Input::RegisterInputFactory(sdl->GetEngineName(), sdl_input_factory); - Common::Input::RegisterOutputFactory(sdl->GetEngineName(), sdl_output_factory); + RegisterEngine("sdl", sdl); #endif Common::Input::RegisterInputFactory("touch_from_button", @@ -107,45 +61,25 @@ struct InputSubsystem::Impl { std::make_shared()); } + template + void UnregisterEngine(std::shared_ptr& engine) { + Common::Input::UnregisterInputFactory(engine->GetEngineName()); + Common::Input::UnregisterOutputFactory(engine->GetEngineName()); + engine.reset(); + } + void Shutdown() { - Common::Input::UnregisterInputFactory(keyboard->GetEngineName()); - Common::Input::UnregisterOutputFactory(keyboard->GetEngineName()); - keyboard.reset(); - - Common::Input::UnregisterInputFactory(mouse->GetEngineName()); - Common::Input::UnregisterOutputFactory(mouse->GetEngineName()); - mouse.reset(); - - Common::Input::UnregisterInputFactory(touch_screen->GetEngineName()); - touch_screen.reset(); - - Common::Input::UnregisterInputFactory(gcadapter->GetEngineName()); - Common::Input::UnregisterOutputFactory(gcadapter->GetEngineName()); - gcadapter.reset(); - - Common::Input::UnregisterInputFactory(udp_client->GetEngineName()); - Common::Input::UnregisterOutputFactory(udp_client->GetEngineName()); - udp_client.reset(); - - Common::Input::UnregisterInputFactory(tas_input->GetEngineName()); - Common::Input::UnregisterOutputFactory(tas_input->GetEngineName()); - tas_input.reset(); - - Common::Input::UnregisterInputFactory(camera->GetEngineName()); - Common::Input::UnregisterOutputFactory(camera->GetEngineName()); - camera.reset(); - - Common::Input::UnregisterInputFactory(virtual_amiibo->GetEngineName()); - Common::Input::UnregisterOutputFactory(virtual_amiibo->GetEngineName()); - virtual_amiibo.reset(); - - Common::Input::UnregisterInputFactory(virtual_gamepad->GetEngineName()); - virtual_gamepad.reset(); - + UnregisterEngine(keyboard); + UnregisterEngine(mouse); + UnregisterEngine(touch_screen); + UnregisterEngine(gcadapter); + UnregisterEngine(udp_client); + UnregisterEngine(tas_input); + UnregisterEngine(camera); + UnregisterEngine(virtual_amiibo); + UnregisterEngine(virtual_gamepad); #ifdef HAVE_SDL2 - Common::Input::UnregisterInputFactory(sdl->GetEngineName()); - Common::Input::UnregisterOutputFactory(sdl->GetEngineName()); - sdl.reset(); + UnregisterEngine(sdl); #endif Common::Input::UnregisterInputFactory("touch_from_button"); @@ -173,117 +107,86 @@ struct InputSubsystem::Impl { return devices; } - [[nodiscard]] AnalogMapping GetAnalogMappingForDevice( + [[nodiscard]] std::shared_ptr GetInputEngine( const Common::ParamPackage& params) const { if (!params.Has("engine") || params.Get("engine", "") == "any") { - return {}; + return nullptr; } const std::string engine = params.Get("engine", ""); + if (engine == keyboard->GetEngineName()) { + return keyboard; + } if (engine == mouse->GetEngineName()) { - return mouse->GetAnalogMappingForDevice(params); + return mouse; } if (engine == gcadapter->GetEngineName()) { - return gcadapter->GetAnalogMappingForDevice(params); + return gcadapter; } if (engine == udp_client->GetEngineName()) { - return udp_client->GetAnalogMappingForDevice(params); - } - if (engine == tas_input->GetEngineName()) { - return tas_input->GetAnalogMappingForDevice(params); + return udp_client; } #ifdef HAVE_SDL2 if (engine == sdl->GetEngineName()) { - return sdl->GetAnalogMappingForDevice(params); + return sdl; } #endif - return {}; + return nullptr; + } + + [[nodiscard]] AnalogMapping GetAnalogMappingForDevice( + const Common::ParamPackage& params) const { + const auto input_engine = GetInputEngine(params); + + if (input_engine == nullptr) { + return {}; + } + + return input_engine->GetAnalogMappingForDevice(params); } [[nodiscard]] ButtonMapping GetButtonMappingForDevice( const Common::ParamPackage& params) const { - if (!params.Has("engine") || params.Get("engine", "") == "any") { + const auto input_engine = GetInputEngine(params); + + if (input_engine == nullptr) { return {}; } - const std::string engine = params.Get("engine", ""); - if (engine == gcadapter->GetEngineName()) { - return gcadapter->GetButtonMappingForDevice(params); - } - if (engine == udp_client->GetEngineName()) { - return udp_client->GetButtonMappingForDevice(params); - } - if (engine == tas_input->GetEngineName()) { - return tas_input->GetButtonMappingForDevice(params); - } -#ifdef HAVE_SDL2 - if (engine == sdl->GetEngineName()) { - return sdl->GetButtonMappingForDevice(params); - } -#endif - return {}; + + return input_engine->GetButtonMappingForDevice(params); } [[nodiscard]] MotionMapping GetMotionMappingForDevice( const Common::ParamPackage& params) const { - if (!params.Has("engine") || params.Get("engine", "") == "any") { + const auto input_engine = GetInputEngine(params); + + if (input_engine == nullptr) { return {}; } - const std::string engine = params.Get("engine", ""); - if (engine == udp_client->GetEngineName()) { - return udp_client->GetMotionMappingForDevice(params); - } -#ifdef HAVE_SDL2 - if (engine == sdl->GetEngineName()) { - return sdl->GetMotionMappingForDevice(params); - } -#endif - return {}; + + return input_engine->GetMotionMappingForDevice(params); } Common::Input::ButtonNames GetButtonName(const Common::ParamPackage& params) const { if (!params.Has("engine") || params.Get("engine", "") == "any") { return Common::Input::ButtonNames::Undefined; } - const std::string engine = params.Get("engine", ""); - if (engine == mouse->GetEngineName()) { - return mouse->GetUIName(params); + const auto input_engine = GetInputEngine(params); + + if (input_engine == nullptr) { + return Common::Input::ButtonNames::Invalid; } - if (engine == gcadapter->GetEngineName()) { - return gcadapter->GetUIName(params); - } - if (engine == udp_client->GetEngineName()) { - return udp_client->GetUIName(params); - } - if (engine == tas_input->GetEngineName()) { - return tas_input->GetUIName(params); - } -#ifdef HAVE_SDL2 - if (engine == sdl->GetEngineName()) { - return sdl->GetUIName(params); - } -#endif - return Common::Input::ButtonNames::Invalid; + + return input_engine->GetUIName(params); } bool IsStickInverted(const Common::ParamPackage& params) { - const std::string engine = params.Get("engine", ""); - if (engine == mouse->GetEngineName()) { - return mouse->IsStickInverted(params); + const auto input_engine = GetInputEngine(params); + + if (input_engine == nullptr) { + return false; } - if (engine == gcadapter->GetEngineName()) { - return gcadapter->IsStickInverted(params); - } - if (engine == udp_client->GetEngineName()) { - return udp_client->IsStickInverted(params); - } - if (engine == tas_input->GetEngineName()) { - return tas_input->IsStickInverted(params); - } -#ifdef HAVE_SDL2 - if (engine == sdl->GetEngineName()) { - return sdl->IsStickInverted(params); - } -#endif - return false; + + return input_engine->IsStickInverted(params); } bool IsController(const Common::ParamPackage& params) { @@ -353,28 +256,8 @@ struct InputSubsystem::Impl { std::shared_ptr virtual_amiibo; std::shared_ptr virtual_gamepad; - std::shared_ptr keyboard_factory; - std::shared_ptr mouse_factory; - std::shared_ptr gcadapter_input_factory; - std::shared_ptr touch_screen_factory; - std::shared_ptr udp_client_input_factory; - std::shared_ptr tas_input_factory; - std::shared_ptr camera_input_factory; - std::shared_ptr virtual_amiibo_input_factory; - std::shared_ptr virtual_gamepad_input_factory; - - std::shared_ptr keyboard_output_factory; - std::shared_ptr mouse_output_factory; - std::shared_ptr gcadapter_output_factory; - std::shared_ptr udp_client_output_factory; - std::shared_ptr tas_output_factory; - std::shared_ptr camera_output_factory; - std::shared_ptr virtual_amiibo_output_factory; - #ifdef HAVE_SDL2 std::shared_ptr sdl; - std::shared_ptr sdl_input_factory; - std::shared_ptr sdl_output_factory; #endif }; From 67c0d714c5b6e93ddb00d0807147b5673c011ac6 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 18 Dec 2022 16:37:19 -0500 Subject: [PATCH 19/24] kernel: add KHardwareTimer --- src/core/CMakeLists.txt | 4 + src/core/hle/kernel/k_hardware_timer.cpp | 75 +++++++++++++++++ src/core/hle/kernel/k_hardware_timer.h | 50 +++++++++++ src/core/hle/kernel/k_hardware_timer_base.h | 92 +++++++++++++++++++++ src/core/hle/kernel/k_thread.h | 16 ++-- src/core/hle/kernel/k_timer_task.h | 40 +++++++++ 6 files changed, 271 insertions(+), 6 deletions(-) create mode 100644 src/core/hle/kernel/k_hardware_timer.cpp create mode 100644 src/core/hle/kernel/k_hardware_timer.h create mode 100644 src/core/hle/kernel/k_hardware_timer_base.h create mode 100644 src/core/hle/kernel/k_timer_task.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c6b5ac1969..dcccd04358 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -201,6 +201,9 @@ add_library(core STATIC hle/kernel/k_event_info.h hle/kernel/k_handle_table.cpp hle/kernel/k_handle_table.h + hle/kernel/k_hardware_timer_base.h + hle/kernel/k_hardware_timer.cpp + hle/kernel/k_hardware_timer.h hle/kernel/k_interrupt_manager.cpp hle/kernel/k_interrupt_manager.h hle/kernel/k_light_condition_variable.cpp @@ -268,6 +271,7 @@ add_library(core STATIC hle/kernel/k_thread_local_page.h hle/kernel/k_thread_queue.cpp hle/kernel/k_thread_queue.h + hle/kernel/k_timer_task.h hle/kernel/k_trace.h hle/kernel/k_transfer_memory.cpp hle/kernel/k_transfer_memory.h diff --git a/src/core/hle/kernel/k_hardware_timer.cpp b/src/core/hle/kernel/k_hardware_timer.cpp new file mode 100644 index 0000000000..afa777f9a5 --- /dev/null +++ b/src/core/hle/kernel/k_hardware_timer.cpp @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/kernel/k_hardware_timer.h" +#include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/time_manager.h" + +namespace Kernel { + +void KHardwareTimer::Initialize() { + // Create the timing callback to register with CoreTiming. + m_event_type = Core::Timing::CreateEvent( + "KHardwareTimer::Callback", + [this](std::uintptr_t timer_handle, s64, std::chrono::nanoseconds) { + reinterpret_cast(timer_handle)->DoTask(); + return std::nullopt; + }); +} + +void KHardwareTimer::Finalize() { + this->DisableInterrupt(); +} + +void KHardwareTimer::DoTask() { + // Handle the interrupt. + { + KScopedSchedulerLock slk{m_kernel}; + KScopedSpinLock lk(this->GetLock()); + + //! Ignore this event if needed. + if (!this->GetInterruptEnabled()) { + return; + } + + // Disable the timer interrupt while we handle this. + this->DisableInterrupt(); + + if (const s64 next_time = this->DoInterruptTaskImpl(GetTick()); + 0 < next_time && next_time <= m_wakeup_time) { + // We have a next time, so we should set the time to interrupt and turn the interrupt + // on. + this->EnableInterrupt(next_time); + } + } + + // Clear the timer interrupt. + // Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_NonSecurePhysicalTimer, + // GetCurrentCoreId()); +} + +void KHardwareTimer::EnableInterrupt(s64 wakeup_time) { + this->DisableInterrupt(); + + m_wakeup_time = wakeup_time; + m_kernel.System().CoreTiming().ScheduleEvent(std::chrono::nanoseconds{m_wakeup_time}, + m_event_type, reinterpret_cast(this), + true); +} + +void KHardwareTimer::DisableInterrupt() { + m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast(this)); + m_wakeup_time = std::numeric_limits::max(); +} + +s64 KHardwareTimer::GetTick() { + return m_kernel.System().CoreTiming().GetGlobalTimeNs().count(); +} + +bool KHardwareTimer::GetInterruptEnabled() { + return m_wakeup_time != std::numeric_limits::max(); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_hardware_timer.h b/src/core/hle/kernel/k_hardware_timer.h new file mode 100644 index 0000000000..2c88876b3b --- /dev/null +++ b/src/core/hle/kernel/k_hardware_timer.h @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/kernel/k_hardware_timer_base.h" + +namespace Core::Timing { +struct EventType; +} // namespace Core::Timing + +namespace Kernel { + +class KHardwareTimer : /* public KInterruptTask, */ public KHardwareTimerBase { +public: + explicit KHardwareTimer(KernelCore& kernel) : KHardwareTimerBase{kernel} {} + + // Public API. + void Initialize(); + void Finalize(); + + s64 GetCount() { + return GetTick(); + } + + void RegisterAbsoluteTask(KTimerTask* task, s64 task_time) { + KScopedDisableDispatch dd{m_kernel}; + KScopedSpinLock lk{this->GetLock()}; + + if (this->RegisterAbsoluteTaskImpl(task, task_time)) { + if (task_time <= m_wakeup_time) { + this->EnableInterrupt(task_time); + } + } + } + +private: + void EnableInterrupt(s64 wakeup_time); + void DisableInterrupt(); + bool GetInterruptEnabled(); + s64 GetTick(); + void DoTask(); + +private: + // Absolute time in nanoseconds + s64 m_wakeup_time{std::numeric_limits::max()}; + std::shared_ptr m_event_type{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_hardware_timer_base.h b/src/core/hle/kernel/k_hardware_timer_base.h new file mode 100644 index 0000000000..6318b35bdd --- /dev/null +++ b/src/core/hle/kernel/k_hardware_timer_base.h @@ -0,0 +1,92 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/kernel/k_spin_lock.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_timer_task.h" + +namespace Kernel { + +class KHardwareTimerBase { +public: + explicit KHardwareTimerBase(KernelCore& kernel) : m_kernel{kernel} {} + + void CancelTask(KTimerTask* task) { + KScopedDisableDispatch dd{m_kernel}; + KScopedSpinLock lk{m_lock}; + + if (const s64 task_time = task->GetTime(); task_time > 0) { + this->RemoveTaskFromTree(task); + } + } + +protected: + KSpinLock& GetLock() { + return m_lock; + } + + s64 DoInterruptTaskImpl(s64 cur_time) { + // We want to handle all tasks, returning the next time that a task is scheduled. + while (true) { + // Get the next task. If there isn't one, return 0. + KTimerTask* task = m_next_task; + if (task == nullptr) { + return 0; + } + + // If the task needs to be done in the future, do it in the future and not now. + if (const s64 task_time = task->GetTime(); task_time > cur_time) { + return task_time; + } + + // Remove the task from the tree of tasks, and update our next task. + this->RemoveTaskFromTree(task); + + // Handle the task. + task->OnTimer(); + } + } + + bool RegisterAbsoluteTaskImpl(KTimerTask* task, s64 task_time) { + ASSERT(task_time > 0); + + // Set the task's time, and insert it into our tree. + task->SetTime(task_time); + m_task_tree.insert(*task); + + // Update our next task if relevant. + if (m_next_task != nullptr && m_next_task->GetTime() <= task_time) { + return false; + } + m_next_task = task; + return true; + } + +private: + void RemoveTaskFromTree(KTimerTask* task) { + // Erase from the tree. + auto it = m_task_tree.erase(m_task_tree.iterator_to(*task)); + + // Clear the task's scheduled time. + task->SetTime(0); + + // Update our next task if relevant. + if (m_next_task == task) { + m_next_task = (it != m_task_tree.end()) ? std::addressof(*it) : nullptr; + } + } + +protected: + KernelCore& m_kernel; + +private: + using TimerTaskTree = Common::IntrusiveRedBlackTreeBaseTraits::TreeType; + + KSpinLock m_lock{}; + TimerTaskTree m_task_tree{}; + KTimerTask* m_next_task{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index dc52b4ed3c..1320451c08 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -22,6 +22,7 @@ #include "core/hle/kernel/k_light_lock.h" #include "core/hle/kernel/k_spin_lock.h" #include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/k_timer_task.h" #include "core/hle/kernel/k_worker_task.h" #include "core/hle/kernel/slab_helpers.h" #include "core/hle/kernel/svc_common.h" @@ -112,7 +113,8 @@ void SetCurrentThread(KernelCore& kernel, KThread* thread); [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); class KThread final : public KAutoObjectWithSlabHeapAndContainer, - public boost::intrusive::list_base_hook<> { + public boost::intrusive::list_base_hook<>, + public KTimerTask { KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); private: @@ -660,7 +662,7 @@ private: union SyncObjectBuffer { std::array sync_objects{}; std::array + Svc::ArgumentHandleCountMax * (sizeof(KSynchronizationObject*) / sizeof(Handle))> handles; constexpr SyncObjectBuffer() {} }; @@ -681,10 +683,8 @@ private: }; template - requires( - std::same_as || - std::same_as) static constexpr int Compare(const T& lhs, - const KThread& rhs) { + requires(std::same_as || std::same_as) + static constexpr int Compare(const T& lhs, const KThread& rhs) { const u64 l_key = lhs.GetConditionVariableKey(); const u64 r_key = rhs.GetConditionVariableKey(); @@ -840,4 +840,8 @@ private: KernelCore& kernel; }; +inline void KTimerTask::OnTimer() { + static_cast(this)->OnTimer(); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/k_timer_task.h b/src/core/hle/kernel/k_timer_task.h new file mode 100644 index 0000000000..66f0a5a908 --- /dev/null +++ b/src/core/hle/kernel/k_timer_task.h @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/intrusive_red_black_tree.h" + +namespace Kernel { + +class KTimerTask : public Common::IntrusiveRedBlackTreeBaseNode { +public: + static constexpr int Compare(const KTimerTask& lhs, const KTimerTask& rhs) { + if (lhs.GetTime() < rhs.GetTime()) { + return -1; + } else { + return 1; + } + } + + constexpr explicit KTimerTask() = default; + + constexpr void SetTime(s64 t) { + m_time = t; + } + + constexpr s64 GetTime() const { + return m_time; + } + + // NOTE: This is virtual in Nintendo's kernel. Prior to 13.0.0, KWaitObject was also a + // TimerTask; this is no longer the case. Since this is now KThread exclusive, we have + // devirtualized (see inline declaration for this inside k_thread.h). + void OnTimer(); + +private: + // Absolute time in nanoseconds + s64 m_time{}; +}; + +} // namespace Kernel From c770f25ccb4755f6a6861037fbfdfdac55191348 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 18 Dec 2022 16:50:02 -0500 Subject: [PATCH 20/24] kernel: remove TimeManager --- src/core/CMakeLists.txt | 2 - src/core/hle/kernel/k_address_arbiter.cpp | 1 - src/core/hle/kernel/k_hardware_timer.cpp | 7 ++- src/core/hle/kernel/k_hardware_timer.h | 8 +++- .../k_scoped_scheduler_lock_and_sleep.h | 4 +- src/core/hle/kernel/k_thread.h | 8 ++-- src/core/hle/kernel/k_thread_queue.cpp | 6 +-- src/core/hle/kernel/kernel.cpp | 20 +++++---- src/core/hle/kernel/kernel.h | 9 ++-- src/core/hle/kernel/time_manager.cpp | 44 ------------------- src/core/hle/kernel/time_manager.h | 41 ----------------- 11 files changed, 33 insertions(+), 117 deletions(-) delete mode 100644 src/core/hle/kernel/time_manager.cpp delete mode 100644 src/core/hle/kernel/time_manager.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index dcccd04358..0252c8c31a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -294,8 +294,6 @@ add_library(core STATIC hle/kernel/svc_common.h hle/kernel/svc_types.h hle/kernel/svc_wrap.h - hle/kernel/time_manager.cpp - hle/kernel/time_manager.h hle/result.h hle/service/acc/acc.cpp hle/service/acc/acc.h diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index f85b11557a..a442a3b985 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp @@ -10,7 +10,6 @@ #include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/svc_results.h" -#include "core/hle/kernel/time_manager.h" #include "core/memory.h" namespace Kernel { diff --git a/src/core/hle/kernel/k_hardware_timer.cpp b/src/core/hle/kernel/k_hardware_timer.cpp index afa777f9a5..6bba79ea06 100644 --- a/src/core/hle/kernel/k_hardware_timer.cpp +++ b/src/core/hle/kernel/k_hardware_timer.cpp @@ -5,15 +5,13 @@ #include "core/core_timing.h" #include "core/hle/kernel/k_hardware_timer.h" #include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/time_manager.h" namespace Kernel { void KHardwareTimer::Initialize() { // Create the timing callback to register with CoreTiming. m_event_type = Core::Timing::CreateEvent( - "KHardwareTimer::Callback", - [this](std::uintptr_t timer_handle, s64, std::chrono::nanoseconds) { + "KHardwareTimer::Callback", [](std::uintptr_t timer_handle, s64, std::chrono::nanoseconds) { reinterpret_cast(timer_handle)->DoTask(); return std::nullopt; }); @@ -21,6 +19,7 @@ void KHardwareTimer::Initialize() { void KHardwareTimer::Finalize() { this->DisableInterrupt(); + m_event_type.reset(); } void KHardwareTimer::DoTask() { @@ -64,7 +63,7 @@ void KHardwareTimer::DisableInterrupt() { m_wakeup_time = std::numeric_limits::max(); } -s64 KHardwareTimer::GetTick() { +s64 KHardwareTimer::GetTick() const { return m_kernel.System().CoreTiming().GetGlobalTimeNs().count(); } diff --git a/src/core/hle/kernel/k_hardware_timer.h b/src/core/hle/kernel/k_hardware_timer.h index 2c88876b3b..00bef6ea15 100644 --- a/src/core/hle/kernel/k_hardware_timer.h +++ b/src/core/hle/kernel/k_hardware_timer.h @@ -19,10 +19,14 @@ public: void Initialize(); void Finalize(); - s64 GetCount() { + s64 GetCount() const { return GetTick(); } + void RegisterTask(KTimerTask* task, s64 time_from_now) { + this->RegisterAbsoluteTask(task, GetTick() + time_from_now); + } + void RegisterAbsoluteTask(KTimerTask* task, s64 task_time) { KScopedDisableDispatch dd{m_kernel}; KScopedSpinLock lk{this->GetLock()}; @@ -38,7 +42,7 @@ private: void EnableInterrupt(s64 wakeup_time); void DisableInterrupt(); bool GetInterruptEnabled(); - s64 GetTick(); + s64 GetTick() const; void DoTask(); private: diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h index 76c095e69b..76db65a4d9 100644 --- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h +++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h @@ -5,9 +5,9 @@ #include "common/common_types.h" #include "core/hle/kernel/global_scheduler_context.h" +#include "core/hle/kernel/k_hardware_timer.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/time_manager.h" namespace Kernel { @@ -22,7 +22,7 @@ public: ~KScopedSchedulerLockAndSleep() { // Register the sleep. if (timeout_tick > 0) { - kernel.TimeManager().ScheduleTimeEvent(thread, timeout_tick); + kernel.HardwareTimer().RegisterTask(thread, timeout_tick); } // Unlock the scheduler. diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 1320451c08..7cd94a340e 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -662,7 +662,7 @@ private: union SyncObjectBuffer { std::array sync_objects{}; std::array + Svc::ArgumentHandleCountMax*(sizeof(KSynchronizationObject*) / sizeof(Handle))> handles; constexpr SyncObjectBuffer() {} }; @@ -683,8 +683,10 @@ private: }; template - requires(std::same_as || std::same_as) - static constexpr int Compare(const T& lhs, const KThread& rhs) { + requires( + std::same_as || + std::same_as) static constexpr int Compare(const T& lhs, + const KThread& rhs) { const u64 l_key = lhs.GetConditionVariableKey(); const u64 r_key = rhs.GetConditionVariableKey(); diff --git a/src/core/hle/kernel/k_thread_queue.cpp b/src/core/hle/kernel/k_thread_queue.cpp index 9f4e081ba4..5f1dc97eb6 100644 --- a/src/core/hle/kernel/k_thread_queue.cpp +++ b/src/core/hle/kernel/k_thread_queue.cpp @@ -1,9 +1,9 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "core/hle/kernel/k_hardware_timer.h" #include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/time_manager.h" namespace Kernel { @@ -22,7 +22,7 @@ void KThreadQueue::EndWait(KThread* waiting_thread, Result wait_result) { waiting_thread->ClearWaitQueue(); // Cancel the thread task. - kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); + kernel.HardwareTimer().CancelTask(waiting_thread); } void KThreadQueue::CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) { @@ -37,7 +37,7 @@ void KThreadQueue::CancelWait(KThread* waiting_thread, Result wait_result, bool // Cancel the thread task. if (cancel_timer_task) { - kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); + kernel.HardwareTimer().CancelTask(waiting_thread); } } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 0eb74a422b..b75bac5dfa 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -26,6 +26,7 @@ #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_dynamic_resource_manager.h" #include "core/hle/kernel/k_handle_table.h" +#include "core/hle/kernel/k_hardware_timer.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_page_buffer.h" @@ -39,7 +40,6 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/service_thread.h" -#include "core/hle/kernel/time_manager.h" #include "core/hle/result.h" #include "core/hle/service/sm/sm.h" #include "core/memory.h" @@ -55,7 +55,7 @@ struct KernelCore::Impl { static constexpr size_t ReservedDynamicPageCount = 64; explicit Impl(Core::System& system_, KernelCore& kernel_) - : time_manager{system_}, service_threads_manager{1, "ServiceThreadsManager"}, + : service_threads_manager{1, "ServiceThreadsManager"}, service_thread_barrier{2}, system{system_} {} void SetMulticore(bool is_multi) { @@ -63,6 +63,9 @@ struct KernelCore::Impl { } void Initialize(KernelCore& kernel) { + hardware_timer = std::make_unique(kernel); + hardware_timer->Initialize(); + global_object_list_container = std::make_unique(kernel); global_scheduler_context = std::make_unique(kernel); global_handle_table = std::make_unique(kernel); @@ -193,6 +196,9 @@ struct KernelCore::Impl { // Ensure that the object list container is finalized and properly shutdown. global_object_list_container->Finalize(); global_object_list_container.reset(); + + hardware_timer->Finalize(); + hardware_timer.reset(); } void CloseServices() { @@ -832,7 +838,7 @@ struct KernelCore::Impl { std::vector process_list; std::atomic current_process{}; std::unique_ptr global_scheduler_context; - Kernel::TimeManager time_manager; + std::unique_ptr hardware_timer; Init::KSlabResourceCounts slab_resource_counts{}; KResourceLimit* system_resource_limit{}; @@ -1019,12 +1025,8 @@ Kernel::KScheduler* KernelCore::CurrentScheduler() { return impl->schedulers[core_id].get(); } -Kernel::TimeManager& KernelCore::TimeManager() { - return impl->time_manager; -} - -const Kernel::TimeManager& KernelCore::TimeManager() const { - return impl->time_manager; +Kernel::KHardwareTimer& KernelCore::HardwareTimer() { + return *impl->hardware_timer; } Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 2e22fe0f64..8d22f8d2c1 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -39,6 +39,7 @@ class KDynamicPageManager; class KEvent; class KEventInfo; class KHandleTable; +class KHardwareTimer; class KLinkedListNode; class KMemoryLayout; class KMemoryManager; @@ -63,7 +64,6 @@ class KCodeMemory; class PhysicalCore; class ServiceThread; class Synchronization; -class TimeManager; using ServiceInterfaceFactory = std::function; @@ -175,11 +175,8 @@ public: /// Gets the an instance of the current physical CPU core. const Kernel::PhysicalCore& CurrentPhysicalCore() const; - /// Gets the an instance of the TimeManager Interface. - Kernel::TimeManager& TimeManager(); - - /// Gets the an instance of the TimeManager Interface. - const Kernel::TimeManager& TimeManager() const; + /// Gets the an instance of the hardware timer. + Kernel::KHardwareTimer& HardwareTimer(); /// Stops execution of 'id' core, in order to reschedule a new thread. void PrepareReschedule(std::size_t id); diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp deleted file mode 100644 index 5ee72c432a..0000000000 --- a/src/core/hle/kernel/time_manager.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/assert.h" -#include "core/core.h" -#include "core/core_timing.h" -#include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/time_manager.h" - -namespace Kernel { - -TimeManager::TimeManager(Core::System& system_) : system{system_} { - time_manager_event_type = Core::Timing::CreateEvent( - "Kernel::TimeManagerCallback", - [this](std::uintptr_t thread_handle, s64 time, - std::chrono::nanoseconds) -> std::optional { - KThread* thread = reinterpret_cast(thread_handle); - { - KScopedSchedulerLock sl(system.Kernel()); - thread->OnTimer(); - } - return std::nullopt; - }); -} - -void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { - std::scoped_lock lock{mutex}; - if (nanoseconds > 0) { - ASSERT(thread); - ASSERT(thread->GetState() != ThreadState::Runnable); - system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{nanoseconds}, - time_manager_event_type, - reinterpret_cast(thread)); - } -} - -void TimeManager::UnscheduleTimeEvent(KThread* thread) { - std::scoped_lock lock{mutex}; - system.CoreTiming().UnscheduleEvent(time_manager_event_type, - reinterpret_cast(thread)); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h deleted file mode 100644 index 94d16b3b43..0000000000 --- a/src/core/hle/kernel/time_manager.h +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include - -namespace Core { -class System; -} // namespace Core - -namespace Core::Timing { -struct EventType; -} // namespace Core::Timing - -namespace Kernel { - -class KThread; - -/** - * The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp - * method when the event is triggered. - */ -class TimeManager { -public: - explicit TimeManager(Core::System& system); - - /// Schedule a time event on `timetask` thread that will expire in 'nanoseconds' - void ScheduleTimeEvent(KThread* time_task, s64 nanoseconds); - - /// Unschedule an existing time event - void UnscheduleTimeEvent(KThread* thread); - -private: - Core::System& system; - std::shared_ptr time_manager_event_type; - std::mutex mutex; -}; - -} // namespace Kernel From 190ded7f485695870aadd391591da93c6cf01af0 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sun, 18 Dec 2022 23:54:56 -0500 Subject: [PATCH 21/24] overlay_dialog: Hide button dialog box when both buttons are hidden This allows for the creation of a non-interactive dialog overlay to display system messages. --- src/yuzu/util/overlay_dialog.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/yuzu/util/overlay_dialog.cpp b/src/yuzu/util/overlay_dialog.cpp index b279545128..e6ca8dc3bb 100644 --- a/src/yuzu/util/overlay_dialog.cpp +++ b/src/yuzu/util/overlay_dialog.cpp @@ -83,6 +83,10 @@ void OverlayDialog::InitializeRegularTextDialog(const QString& title_text, const ui->button_ok_label->setEnabled(false); } + if (ui->button_cancel->isHidden() && ui->button_ok_label->isHidden()) { + ui->buttonsDialog->hide(); + } + connect( ui->button_cancel, &QPushButton::clicked, this, [this](bool) { @@ -130,6 +134,10 @@ void OverlayDialog::InitializeRichTextDialog(const QString& title_text, const QS ui->button_ok_rich->setEnabled(false); } + if (ui->button_cancel_rich->isHidden() && ui->button_ok_rich->isHidden()) { + ui->buttonsRichDialog->hide(); + } + connect( ui->button_cancel_rich, &QPushButton::clicked, this, [this](bool) { From 690a4c94382f76d39ce2bba4b3ed4c83e9c03050 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Mon, 19 Dec 2022 00:00:03 -0500 Subject: [PATCH 22/24] overlay_dialog: Avoid starting the input thread if non-interactive --- src/yuzu/util/overlay_dialog.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/yuzu/util/overlay_dialog.cpp b/src/yuzu/util/overlay_dialog.cpp index e6ca8dc3bb..3fa3d0afb1 100644 --- a/src/yuzu/util/overlay_dialog.cpp +++ b/src/yuzu/util/overlay_dialog.cpp @@ -42,7 +42,7 @@ OverlayDialog::OverlayDialog(QWidget* parent, Core::System& system, const QStrin MoveAndResizeWindow(); // TODO (Morph): Remove this when InputInterpreter no longer relies on the HID backend - if (system.IsPoweredOn()) { + if (system.IsPoweredOn() && !ui->buttonsDialog->isHidden()) { input_interpreter = std::make_unique(system); StartInputThread(); @@ -85,6 +85,7 @@ void OverlayDialog::InitializeRegularTextDialog(const QString& title_text, const if (ui->button_cancel->isHidden() && ui->button_ok_label->isHidden()) { ui->buttonsDialog->hide(); + return; } connect( @@ -136,6 +137,7 @@ void OverlayDialog::InitializeRichTextDialog(const QString& title_text, const QS if (ui->button_cancel_rich->isHidden() && ui->button_ok_rich->isHidden()) { ui->buttonsRichDialog->hide(); + return; } connect( From b60a93a9363da143c070887a5ddf741eb8dda544 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 19 Dec 2022 17:10:51 +0000 Subject: [PATCH 23/24] externals: update Vulkan-Headers to v1.3.238 --- externals/Vulkan-Headers | 2 +- src/video_core/vulkan_common/vulkan_wrapper.cpp | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/externals/Vulkan-Headers b/externals/Vulkan-Headers index 2826791bed..00671c64ba 160000 --- a/externals/Vulkan-Headers +++ b/externals/Vulkan-Headers @@ -1 +1 @@ -Subproject commit 2826791bed6a793f164bf534cd859968f13df8a9 +Subproject commit 00671c64ba5c488ade22ad572a0ef81d5e64c803 diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 483b534a01..7dca7341cd 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -314,6 +314,18 @@ const char* ToString(VkResult result) noexcept { return "VK_ERROR_VALIDATION_FAILED_EXT"; case VkResult::VK_ERROR_INVALID_SHADER_NV: return "VK_ERROR_INVALID_SHADER_NV"; + case VkResult::VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR: + return "VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR"; + case VkResult::VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR: + return "VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR"; + case VkResult::VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR: + return "VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR"; + case VkResult::VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR: + return "VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR"; + case VkResult::VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR: + return "VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR"; + case VkResult::VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR: + return "VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR"; case VkResult::VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; case VkResult::VK_ERROR_FRAGMENTATION_EXT: From 9f199c8b0b37cfb84084f4ee543e3829ab085b1a Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 19 Dec 2022 21:57:46 -0500 Subject: [PATCH 24/24] CMakeLists: bump required Vulkan package version to 1.3.238 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47eddf99e9..f71a8b3e38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -208,7 +208,7 @@ find_package(libusb 1.0.24) find_package(lz4 REQUIRED) find_package(nlohmann_json 3.8 REQUIRED) find_package(Opus 1.3) -find_package(Vulkan 1.3.213) +find_package(Vulkan 1.3.238) find_package(ZLIB 1.2 REQUIRED) find_package(zstd 1.5 REQUIRED)