diff options
Diffstat (limited to 'src')
20 files changed, 203 insertions, 35 deletions
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 631aa6ad2..6d5a3dead 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -957,7 +957,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback | |||
| 957 | raw_status.gyro.y.value, | 957 | raw_status.gyro.y.value, |
| 958 | raw_status.gyro.z.value, | 958 | raw_status.gyro.z.value, |
| 959 | }); | 959 | }); |
| 960 | emulated.SetGyroThreshold(raw_status.gyro.x.properties.threshold); | 960 | emulated.SetUserGyroThreshold(raw_status.gyro.x.properties.threshold); |
| 961 | emulated.UpdateRotation(raw_status.delta_timestamp); | 961 | emulated.UpdateRotation(raw_status.delta_timestamp); |
| 962 | emulated.UpdateOrientation(raw_status.delta_timestamp); | 962 | emulated.UpdateOrientation(raw_status.delta_timestamp); |
| 963 | force_update_motion = raw_status.force_update; | 963 | force_update_motion = raw_status.force_update; |
| @@ -1284,6 +1284,26 @@ void EmulatedController::SetLedPattern() { | |||
| 1284 | } | 1284 | } |
| 1285 | } | 1285 | } |
| 1286 | 1286 | ||
| 1287 | void EmulatedController::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode mode) { | ||
| 1288 | for (auto& motion : controller.motion_values) { | ||
| 1289 | switch (mode) { | ||
| 1290 | case GyroscopeZeroDriftMode::Loose: | ||
| 1291 | motion_sensitivity = motion.emulated.IsAtRestLoose; | ||
| 1292 | motion.emulated.SetGyroThreshold(motion.emulated.ThresholdLoose); | ||
| 1293 | break; | ||
| 1294 | case GyroscopeZeroDriftMode::Tight: | ||
| 1295 | motion_sensitivity = motion.emulated.IsAtRestThight; | ||
| 1296 | motion.emulated.SetGyroThreshold(motion.emulated.ThresholdThight); | ||
| 1297 | break; | ||
| 1298 | case GyroscopeZeroDriftMode::Standard: | ||
| 1299 | default: | ||
| 1300 | motion_sensitivity = motion.emulated.IsAtRestStandard; | ||
| 1301 | motion.emulated.SetGyroThreshold(motion.emulated.ThresholdStandard); | ||
| 1302 | break; | ||
| 1303 | } | ||
| 1304 | } | ||
| 1305 | } | ||
| 1306 | |||
| 1287 | void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) { | 1307 | void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) { |
| 1288 | supported_style_tag = supported_styles; | 1308 | supported_style_tag = supported_styles; |
| 1289 | if (!is_connected) { | 1309 | if (!is_connected) { |
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index b02bf35c4..a9da465a2 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h | |||
| @@ -398,6 +398,9 @@ public: | |||
| 398 | /// Asks the output device to change the player led pattern | 398 | /// Asks the output device to change the player led pattern |
| 399 | void SetLedPattern(); | 399 | void SetLedPattern(); |
| 400 | 400 | ||
| 401 | /// Changes sensitivity of the motion sensor | ||
| 402 | void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode mode); | ||
| 403 | |||
| 401 | /** | 404 | /** |
| 402 | * Adds a callback to the list of events | 405 | * Adds a callback to the list of events |
| 403 | * @param update_callback A ConsoleUpdateCallback that will be triggered | 406 | * @param update_callback A ConsoleUpdateCallback that will be triggered |
| @@ -523,7 +526,7 @@ private: | |||
| 523 | bool is_connected{false}; | 526 | bool is_connected{false}; |
| 524 | bool is_configuring{false}; | 527 | bool is_configuring{false}; |
| 525 | bool system_buttons_enabled{true}; | 528 | bool system_buttons_enabled{true}; |
| 526 | f32 motion_sensitivity{0.01f}; | 529 | f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; |
| 527 | bool force_update_motion{false}; | 530 | bool force_update_motion{false}; |
| 528 | u32 turbo_button_state{0}; | 531 | u32 turbo_button_state{0}; |
| 529 | 532 | ||
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index e3b1cfbc6..6b35f448c 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h | |||
| @@ -282,6 +282,13 @@ enum class VibrationGcErmCommand : u64 { | |||
| 282 | StopHard = 2, | 282 | StopHard = 2, |
| 283 | }; | 283 | }; |
| 284 | 284 | ||
| 285 | // This is nn::hid::GyroscopeZeroDriftMode | ||
| 286 | enum class GyroscopeZeroDriftMode : u32 { | ||
| 287 | Loose = 0, | ||
| 288 | Standard = 1, | ||
| 289 | Tight = 2, | ||
| 290 | }; | ||
| 291 | |||
| 285 | // This is nn::hid::NpadStyleTag | 292 | // This is nn::hid::NpadStyleTag |
| 286 | struct NpadStyleTag { | 293 | struct NpadStyleTag { |
| 287 | union { | 294 | union { |
diff --git a/src/core/hid/motion_input.cpp b/src/core/hid/motion_input.cpp index b1f658e62..eef6edf4b 100644 --- a/src/core/hid/motion_input.cpp +++ b/src/core/hid/motion_input.cpp | |||
| @@ -9,7 +9,7 @@ namespace Core::HID { | |||
| 9 | MotionInput::MotionInput() { | 9 | MotionInput::MotionInput() { |
| 10 | // Initialize PID constants with default values | 10 | // Initialize PID constants with default values |
| 11 | SetPID(0.3f, 0.005f, 0.0f); | 11 | SetPID(0.3f, 0.005f, 0.0f); |
| 12 | SetGyroThreshold(0.007f); | 12 | SetGyroThreshold(ThresholdStandard); |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) { | 15 | void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) { |
| @@ -26,11 +26,11 @@ void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) { | |||
| 26 | gyro = gyroscope - gyro_bias; | 26 | gyro = gyroscope - gyro_bias; |
| 27 | 27 | ||
| 28 | // Auto adjust drift to minimize drift | 28 | // Auto adjust drift to minimize drift |
| 29 | if (!IsMoving(0.1f)) { | 29 | if (!IsMoving(IsAtRestRelaxed)) { |
| 30 | gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f); | 30 | gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | if (gyro.Length() < gyro_threshold) { | 33 | if (gyro.Length() < gyro_threshold * user_gyro_threshold) { |
| 34 | gyro = {}; | 34 | gyro = {}; |
| 35 | } else { | 35 | } else { |
| 36 | only_accelerometer = false; | 36 | only_accelerometer = false; |
| @@ -49,6 +49,10 @@ void MotionInput::SetGyroThreshold(f32 threshold) { | |||
| 49 | gyro_threshold = threshold; | 49 | gyro_threshold = threshold; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | void MotionInput::SetUserGyroThreshold(f32 threshold) { | ||
| 53 | user_gyro_threshold = threshold / ThresholdStandard; | ||
| 54 | } | ||
| 55 | |||
| 52 | void MotionInput::EnableReset(bool reset) { | 56 | void MotionInput::EnableReset(bool reset) { |
| 53 | reset_enabled = reset; | 57 | reset_enabled = reset; |
| 54 | } | 58 | } |
| @@ -208,7 +212,7 @@ void MotionInput::ResetOrientation() { | |||
| 208 | if (!reset_enabled || only_accelerometer) { | 212 | if (!reset_enabled || only_accelerometer) { |
| 209 | return; | 213 | return; |
| 210 | } | 214 | } |
| 211 | if (!IsMoving(0.5f) && accel.z <= -0.9f) { | 215 | if (!IsMoving(IsAtRestRelaxed) && accel.z <= -0.9f) { |
| 212 | ++reset_counter; | 216 | ++reset_counter; |
| 213 | if (reset_counter > 900) { | 217 | if (reset_counter > 900) { |
| 214 | quat.w = 0; | 218 | quat.w = 0; |
diff --git a/src/core/hid/motion_input.h b/src/core/hid/motion_input.h index f5fd90db5..9180bb9aa 100644 --- a/src/core/hid/motion_input.h +++ b/src/core/hid/motion_input.h | |||
| @@ -11,6 +11,15 @@ namespace Core::HID { | |||
| 11 | 11 | ||
| 12 | class MotionInput { | 12 | class MotionInput { |
| 13 | public: | 13 | public: |
| 14 | static constexpr float ThresholdLoose = 0.01f; | ||
| 15 | static constexpr float ThresholdStandard = 0.007f; | ||
| 16 | static constexpr float ThresholdThight = 0.002f; | ||
| 17 | |||
| 18 | static constexpr float IsAtRestRelaxed = 0.05f; | ||
| 19 | static constexpr float IsAtRestLoose = 0.02f; | ||
| 20 | static constexpr float IsAtRestStandard = 0.01f; | ||
| 21 | static constexpr float IsAtRestThight = 0.005f; | ||
| 22 | |||
| 14 | explicit MotionInput(); | 23 | explicit MotionInput(); |
| 15 | 24 | ||
| 16 | MotionInput(const MotionInput&) = default; | 25 | MotionInput(const MotionInput&) = default; |
| @@ -26,6 +35,9 @@ public: | |||
| 26 | void SetGyroBias(const Common::Vec3f& bias); | 35 | void SetGyroBias(const Common::Vec3f& bias); |
| 27 | void SetGyroThreshold(f32 threshold); | 36 | void SetGyroThreshold(f32 threshold); |
| 28 | 37 | ||
| 38 | /// Applies a modifier on top of the normal gyro threshold | ||
| 39 | void SetUserGyroThreshold(f32 threshold); | ||
| 40 | |||
| 29 | void EnableReset(bool reset); | 41 | void EnableReset(bool reset); |
| 30 | void ResetRotations(); | 42 | void ResetRotations(); |
| 31 | 43 | ||
| @@ -74,6 +86,9 @@ private: | |||
| 74 | // Minimum gyro amplitude to detect if the device is moving | 86 | // Minimum gyro amplitude to detect if the device is moving |
| 75 | f32 gyro_threshold = 0.0f; | 87 | f32 gyro_threshold = 0.0f; |
| 76 | 88 | ||
| 89 | // Multiplies gyro_threshold by this value | ||
| 90 | f32 user_gyro_threshold = 0.0f; | ||
| 91 | |||
| 77 | // Number of invalid sequential data | 92 | // Number of invalid sequential data |
| 78 | u32 reset_counter = 0; | 93 | u32 reset_counter = 0; |
| 79 | 94 | ||
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 80eba22e8..ba6f04d8d 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -1132,7 +1132,8 @@ Result Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { | |||
| 1132 | return ResultSuccess; | 1132 | return ResultSuccess; |
| 1133 | } | 1133 | } |
| 1134 | Result Controller_NPad::SetGyroscopeZeroDriftMode( | 1134 | Result Controller_NPad::SetGyroscopeZeroDriftMode( |
| 1135 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, GyroscopeZeroDriftMode drift_mode) { | 1135 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 1136 | Core::HID::GyroscopeZeroDriftMode drift_mode) { | ||
| 1136 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); | 1137 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); |
| 1137 | if (is_valid.IsError()) { | 1138 | if (is_valid.IsError()) { |
| 1138 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); | 1139 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); |
| @@ -1140,14 +1141,16 @@ Result Controller_NPad::SetGyroscopeZeroDriftMode( | |||
| 1140 | } | 1141 | } |
| 1141 | 1142 | ||
| 1142 | auto& sixaxis = GetSixaxisState(sixaxis_handle); | 1143 | auto& sixaxis = GetSixaxisState(sixaxis_handle); |
| 1144 | auto& controller = GetControllerFromHandle(sixaxis_handle); | ||
| 1143 | sixaxis.gyroscope_zero_drift_mode = drift_mode; | 1145 | sixaxis.gyroscope_zero_drift_mode = drift_mode; |
| 1146 | controller.device->SetGyroscopeZeroDriftMode(drift_mode); | ||
| 1144 | 1147 | ||
| 1145 | return ResultSuccess; | 1148 | return ResultSuccess; |
| 1146 | } | 1149 | } |
| 1147 | 1150 | ||
| 1148 | Result Controller_NPad::GetGyroscopeZeroDriftMode( | 1151 | Result Controller_NPad::GetGyroscopeZeroDriftMode( |
| 1149 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, | 1152 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 1150 | GyroscopeZeroDriftMode& drift_mode) const { | 1153 | Core::HID::GyroscopeZeroDriftMode& drift_mode) const { |
| 1151 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); | 1154 | const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); |
| 1152 | if (is_valid.IsError()) { | 1155 | if (is_valid.IsError()) { |
| 1153 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); | 1156 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 02cc00920..a5998c453 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -52,13 +52,6 @@ public: | |||
| 52 | // When the controller is requesting a motion update for the shared memory | 52 | // When the controller is requesting a motion update for the shared memory |
| 53 | void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) override; | 53 | void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) override; |
| 54 | 54 | ||
| 55 | // This is nn::hid::GyroscopeZeroDriftMode | ||
| 56 | enum class GyroscopeZeroDriftMode : u32 { | ||
| 57 | Loose = 0, | ||
| 58 | Standard = 1, | ||
| 59 | Tight = 2, | ||
| 60 | }; | ||
| 61 | |||
| 62 | // This is nn::hid::NpadJoyHoldType | 55 | // This is nn::hid::NpadJoyHoldType |
| 63 | enum class NpadJoyHoldType : u64 { | 56 | enum class NpadJoyHoldType : u64 { |
| 64 | Vertical = 0, | 57 | Vertical = 0, |
| @@ -146,9 +139,9 @@ public: | |||
| 146 | Result DisconnectNpad(Core::HID::NpadIdType npad_id); | 139 | Result DisconnectNpad(Core::HID::NpadIdType npad_id); |
| 147 | 140 | ||
| 148 | Result SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, | 141 | Result SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 149 | GyroscopeZeroDriftMode drift_mode); | 142 | Core::HID::GyroscopeZeroDriftMode drift_mode); |
| 150 | Result GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, | 143 | Result GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 151 | GyroscopeZeroDriftMode& drift_mode) const; | 144 | Core::HID::GyroscopeZeroDriftMode& drift_mode) const; |
| 152 | Result IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle, | 145 | Result IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 153 | bool& is_at_rest) const; | 146 | bool& is_at_rest) const; |
| 154 | Result IsFirmwareUpdateAvailableForSixAxisSensor( | 147 | Result IsFirmwareUpdateAvailableForSixAxisSensor( |
| @@ -489,7 +482,8 @@ private: | |||
| 489 | Core::HID::SixAxisSensorFusionParameters fusion{}; | 482 | Core::HID::SixAxisSensorFusionParameters fusion{}; |
| 490 | Core::HID::SixAxisSensorCalibrationParameter calibration{}; | 483 | Core::HID::SixAxisSensorCalibrationParameter calibration{}; |
| 491 | Core::HID::SixAxisSensorIcInformation ic_information{}; | 484 | Core::HID::SixAxisSensorIcInformation ic_information{}; |
| 492 | GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; | 485 | Core::HID::GyroscopeZeroDriftMode gyroscope_zero_drift_mode{ |
| 486 | Core::HID::GyroscopeZeroDriftMode::Standard}; | ||
| 493 | }; | 487 | }; |
| 494 | 488 | ||
| 495 | struct NpadControllerData { | 489 | struct NpadControllerData { |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index ac2c0c76d..5a1aa0903 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -712,7 +712,7 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { | |||
| 712 | void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | 712 | void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { |
| 713 | IPC::RequestParser rp{ctx}; | 713 | IPC::RequestParser rp{ctx}; |
| 714 | const auto sixaxis_handle{rp.PopRaw<Core::HID::SixAxisSensorHandle>()}; | 714 | const auto sixaxis_handle{rp.PopRaw<Core::HID::SixAxisSensorHandle>()}; |
| 715 | const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()}; | 715 | const auto drift_mode{rp.PopEnum<Core::HID::GyroscopeZeroDriftMode>()}; |
| 716 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 716 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 717 | 717 | ||
| 718 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | 718 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); |
| @@ -739,7 +739,7 @@ void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | |||
| 739 | 739 | ||
| 740 | const auto parameters{rp.PopRaw<Parameters>()}; | 740 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 741 | 741 | ||
| 742 | auto drift_mode{Controller_NPad::GyroscopeZeroDriftMode::Standard}; | 742 | auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard}; |
| 743 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | 743 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); |
| 744 | const auto result = controller.GetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); | 744 | const auto result = controller.GetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); |
| 745 | 745 | ||
| @@ -764,7 +764,7 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | |||
| 764 | 764 | ||
| 765 | const auto parameters{rp.PopRaw<Parameters>()}; | 765 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 766 | 766 | ||
| 767 | const auto drift_mode{Controller_NPad::GyroscopeZeroDriftMode::Standard}; | 767 | const auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard}; |
| 768 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | 768 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); |
| 769 | const auto result = controller.SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); | 769 | const auto result = controller.SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); |
| 770 | 770 | ||
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 52cd5bb81..2442c3c29 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt | |||
| @@ -22,6 +22,8 @@ set(SHADER_FILES | |||
| 22 | convert_d24s8_to_abgr8.frag | 22 | convert_d24s8_to_abgr8.frag |
| 23 | convert_depth_to_float.frag | 23 | convert_depth_to_float.frag |
| 24 | convert_float_to_depth.frag | 24 | convert_float_to_depth.frag |
| 25 | convert_msaa_to_non_msaa.comp | ||
| 26 | convert_non_msaa_to_msaa.comp | ||
| 25 | convert_s8d24_to_abgr8.frag | 27 | convert_s8d24_to_abgr8.frag |
| 26 | full_screen_triangle.vert | 28 | full_screen_triangle.vert |
| 27 | fxaa.frag | 29 | fxaa.frag |
diff --git a/src/video_core/host_shaders/convert_msaa_to_non_msaa.comp b/src/video_core/host_shaders/convert_msaa_to_non_msaa.comp new file mode 100644 index 000000000..fc3854d18 --- /dev/null +++ b/src/video_core/host_shaders/convert_msaa_to_non_msaa.comp | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #version 450 core | ||
| 5 | layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; | ||
| 6 | |||
| 7 | layout (binding = 0, rgba8) uniform readonly restrict image2DMSArray msaa_in; | ||
| 8 | layout (binding = 1, rgba8) uniform writeonly restrict image2DArray output_img; | ||
| 9 | |||
| 10 | void main() { | ||
| 11 | const ivec3 coords = ivec3(gl_GlobalInvocationID); | ||
| 12 | if (any(greaterThanEqual(coords, imageSize(msaa_in)))) { | ||
| 13 | return; | ||
| 14 | } | ||
| 15 | |||
| 16 | // TODO: Specialization constants for num_samples? | ||
| 17 | const int num_samples = imageSamples(msaa_in); | ||
| 18 | for (int curr_sample = 0; curr_sample < num_samples; ++curr_sample) { | ||
| 19 | const vec4 pixel = imageLoad(msaa_in, coords, curr_sample); | ||
| 20 | |||
| 21 | const int single_sample_x = 2 * coords.x + (curr_sample & 1); | ||
| 22 | const int single_sample_y = 2 * coords.y + ((curr_sample / 2) & 1); | ||
| 23 | const ivec3 dest_coords = ivec3(single_sample_x, single_sample_y, coords.z); | ||
| 24 | |||
| 25 | if (any(greaterThanEqual(dest_coords, imageSize(output_img)))) { | ||
| 26 | continue; | ||
| 27 | } | ||
| 28 | imageStore(output_img, dest_coords, pixel); | ||
| 29 | } | ||
| 30 | } | ||
diff --git a/src/video_core/host_shaders/convert_non_msaa_to_msaa.comp b/src/video_core/host_shaders/convert_non_msaa_to_msaa.comp new file mode 100644 index 000000000..dedd962f1 --- /dev/null +++ b/src/video_core/host_shaders/convert_non_msaa_to_msaa.comp | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #version 450 core | ||
| 5 | layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; | ||
| 6 | |||
| 7 | layout (binding = 0, rgba8) uniform readonly restrict image2DArray img_in; | ||
| 8 | layout (binding = 1, rgba8) uniform writeonly restrict image2DMSArray output_msaa; | ||
| 9 | |||
| 10 | void main() { | ||
| 11 | const ivec3 coords = ivec3(gl_GlobalInvocationID); | ||
| 12 | if (any(greaterThanEqual(coords, imageSize(output_msaa)))) { | ||
| 13 | return; | ||
| 14 | } | ||
| 15 | |||
| 16 | // TODO: Specialization constants for num_samples? | ||
| 17 | const int num_samples = imageSamples(output_msaa); | ||
| 18 | for (int curr_sample = 0; curr_sample < num_samples; ++curr_sample) { | ||
| 19 | const int single_sample_x = 2 * coords.x + (curr_sample & 1); | ||
| 20 | const int single_sample_y = 2 * coords.y + ((curr_sample / 2) & 1); | ||
| 21 | const ivec3 single_coords = ivec3(single_sample_x, single_sample_y, coords.z); | ||
| 22 | |||
| 23 | if (any(greaterThanEqual(single_coords, imageSize(img_in)))) { | ||
| 24 | continue; | ||
| 25 | } | ||
| 26 | const vec4 pixel = imageLoad(img_in, single_coords); | ||
| 27 | imageStore(output_msaa, coords, curr_sample, pixel); | ||
| 28 | } | ||
| 29 | } | ||
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 9f7ce7414..eb6e43a08 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -557,6 +557,14 @@ void TextureCacheRuntime::CopyImage(Image& dst_image, Image& src_image, | |||
| 557 | } | 557 | } |
| 558 | } | 558 | } |
| 559 | 559 | ||
| 560 | void TextureCacheRuntime::CopyImageMSAA(Image& dst_image, Image& src_image, | ||
| 561 | std::span<const VideoCommon::ImageCopy> copies) { | ||
| 562 | LOG_DEBUG(Render_OpenGL, "Copying from {} samples to {} samples", src_image.info.num_samples, | ||
| 563 | dst_image.info.num_samples); | ||
| 564 | // TODO: Leverage the format conversion pass if possible/accurate. | ||
| 565 | util_shaders.CopyMSAA(dst_image, src_image, copies); | ||
| 566 | } | ||
| 567 | |||
| 560 | void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src, | 568 | void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src, |
| 561 | std::span<const VideoCommon::ImageCopy> copies) { | 569 | std::span<const VideoCommon::ImageCopy> copies) { |
| 562 | LOG_DEBUG(Render_OpenGL, "Converting {} to {}", src.info.format, dst.info.format); | 570 | LOG_DEBUG(Render_OpenGL, "Converting {} to {}", src.info.format, dst.info.format); |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 5d9d370f2..e30875496 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h | |||
| @@ -93,12 +93,19 @@ public: | |||
| 93 | return device.CanReportMemoryUsage(); | 93 | return device.CanReportMemoryUsage(); |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | bool ShouldReinterpret([[maybe_unused]] Image& dst, [[maybe_unused]] Image& src) { | 96 | bool ShouldReinterpret([[maybe_unused]] Image& dst, |
| 97 | [[maybe_unused]] Image& src) const noexcept { | ||
| 98 | return true; | ||
| 99 | } | ||
| 100 | |||
| 101 | bool CanUploadMSAA() const noexcept { | ||
| 97 | return true; | 102 | return true; |
| 98 | } | 103 | } |
| 99 | 104 | ||
| 100 | void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); | 105 | void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); |
| 101 | 106 | ||
| 107 | void CopyImageMSAA(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); | ||
| 108 | |||
| 102 | void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); | 109 | void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); |
| 103 | 110 | ||
| 104 | void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) { | 111 | void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) { |
diff --git a/src/video_core/renderer_opengl/util_shaders.cpp b/src/video_core/renderer_opengl/util_shaders.cpp index 404def62e..2c7ac210b 100644 --- a/src/video_core/renderer_opengl/util_shaders.cpp +++ b/src/video_core/renderer_opengl/util_shaders.cpp | |||
| @@ -12,6 +12,8 @@ | |||
| 12 | #include "video_core/host_shaders/astc_decoder_comp.h" | 12 | #include "video_core/host_shaders/astc_decoder_comp.h" |
| 13 | #include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h" | 13 | #include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h" |
| 14 | #include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h" | 14 | #include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h" |
| 15 | #include "video_core/host_shaders/convert_msaa_to_non_msaa_comp.h" | ||
| 16 | #include "video_core/host_shaders/convert_non_msaa_to_msaa_comp.h" | ||
| 15 | #include "video_core/host_shaders/opengl_convert_s8d24_comp.h" | 17 | #include "video_core/host_shaders/opengl_convert_s8d24_comp.h" |
| 16 | #include "video_core/host_shaders/opengl_copy_bc4_comp.h" | 18 | #include "video_core/host_shaders/opengl_copy_bc4_comp.h" |
| 17 | #include "video_core/host_shaders/pitch_unswizzle_comp.h" | 19 | #include "video_core/host_shaders/pitch_unswizzle_comp.h" |
| @@ -51,7 +53,9 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_) | |||
| 51 | block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)), | 53 | block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)), |
| 52 | pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)), | 54 | pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)), |
| 53 | copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)), | 55 | copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)), |
| 54 | convert_s8d24_program(MakeProgram(OPENGL_CONVERT_S8D24_COMP)) { | 56 | convert_s8d24_program(MakeProgram(OPENGL_CONVERT_S8D24_COMP)), |
| 57 | convert_ms_to_nonms_program(MakeProgram(CONVERT_MSAA_TO_NON_MSAA_COMP)), | ||
| 58 | convert_nonms_to_ms_program(MakeProgram(CONVERT_NON_MSAA_TO_MSAA_COMP)) { | ||
| 55 | const auto swizzle_table = Tegra::Texture::MakeSwizzleTable(); | 59 | const auto swizzle_table = Tegra::Texture::MakeSwizzleTable(); |
| 56 | swizzle_table_buffer.Create(); | 60 | swizzle_table_buffer.Create(); |
| 57 | glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0); | 61 | glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0); |
| @@ -269,6 +273,33 @@ void UtilShaders::ConvertS8D24(Image& dst_image, std::span<const ImageCopy> copi | |||
| 269 | program_manager.RestoreGuestCompute(); | 273 | program_manager.RestoreGuestCompute(); |
| 270 | } | 274 | } |
| 271 | 275 | ||
| 276 | void UtilShaders::CopyMSAA(Image& dst_image, Image& src_image, | ||
| 277 | std::span<const VideoCommon::ImageCopy> copies) { | ||
| 278 | const bool is_ms_to_non_ms = src_image.info.num_samples > 1 && dst_image.info.num_samples == 1; | ||
| 279 | const auto program_handle = | ||
| 280 | is_ms_to_non_ms ? convert_ms_to_nonms_program.handle : convert_nonms_to_ms_program.handle; | ||
| 281 | program_manager.BindComputeProgram(program_handle); | ||
| 282 | |||
| 283 | for (const ImageCopy& copy : copies) { | ||
| 284 | ASSERT(copy.src_subresource.base_layer == 0); | ||
| 285 | ASSERT(copy.src_subresource.num_layers == 1); | ||
| 286 | ASSERT(copy.dst_subresource.base_layer == 0); | ||
| 287 | ASSERT(copy.dst_subresource.num_layers == 1); | ||
| 288 | |||
| 289 | glBindImageTexture(0, src_image.StorageHandle(), copy.src_subresource.base_level, GL_TRUE, | ||
| 290 | 0, GL_READ_ONLY, GL_RGBA8); | ||
| 291 | glBindImageTexture(1, dst_image.StorageHandle(), copy.dst_subresource.base_level, GL_TRUE, | ||
| 292 | 0, GL_WRITE_ONLY, GL_RGBA8); | ||
| 293 | |||
| 294 | const u32 num_dispatches_x = Common::DivCeil(copy.extent.width, 8U); | ||
| 295 | const u32 num_dispatches_y = Common::DivCeil(copy.extent.height, 8U); | ||
| 296 | const u32 num_dispatches_z = copy.extent.depth; | ||
| 297 | |||
| 298 | glDispatchCompute(num_dispatches_x, num_dispatches_y, num_dispatches_z); | ||
| 299 | } | ||
| 300 | program_manager.RestoreGuestCompute(); | ||
| 301 | } | ||
| 302 | |||
| 272 | GLenum StoreFormat(u32 bytes_per_block) { | 303 | GLenum StoreFormat(u32 bytes_per_block) { |
| 273 | switch (bytes_per_block) { | 304 | switch (bytes_per_block) { |
| 274 | case 1: | 305 | case 1: |
diff --git a/src/video_core/renderer_opengl/util_shaders.h b/src/video_core/renderer_opengl/util_shaders.h index 44efb6ecf..9013808e7 100644 --- a/src/video_core/renderer_opengl/util_shaders.h +++ b/src/video_core/renderer_opengl/util_shaders.h | |||
| @@ -40,6 +40,9 @@ public: | |||
| 40 | 40 | ||
| 41 | void ConvertS8D24(Image& dst_image, std::span<const VideoCommon::ImageCopy> copies); | 41 | void ConvertS8D24(Image& dst_image, std::span<const VideoCommon::ImageCopy> copies); |
| 42 | 42 | ||
| 43 | void CopyMSAA(Image& dst_image, Image& src_image, | ||
| 44 | std::span<const VideoCommon::ImageCopy> copies); | ||
| 45 | |||
| 43 | private: | 46 | private: |
| 44 | ProgramManager& program_manager; | 47 | ProgramManager& program_manager; |
| 45 | 48 | ||
| @@ -51,6 +54,8 @@ private: | |||
| 51 | OGLProgram pitch_unswizzle_program; | 54 | OGLProgram pitch_unswizzle_program; |
| 52 | OGLProgram copy_bc4_program; | 55 | OGLProgram copy_bc4_program; |
| 53 | OGLProgram convert_s8d24_program; | 56 | OGLProgram convert_s8d24_program; |
| 57 | OGLProgram convert_ms_to_nonms_program; | ||
| 58 | OGLProgram convert_nonms_to_ms_program; | ||
| 54 | }; | 59 | }; |
| 55 | 60 | ||
| 56 | GLenum StoreFormat(u32 bytes_per_block); | 61 | GLenum StoreFormat(u32 bytes_per_block); |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index d39372ec4..9b85dfb5e 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -1230,6 +1230,11 @@ void TextureCacheRuntime::CopyImage(Image& dst, Image& src, | |||
| 1230 | }); | 1230 | }); |
| 1231 | } | 1231 | } |
| 1232 | 1232 | ||
| 1233 | void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src, | ||
| 1234 | std::span<const VideoCommon::ImageCopy> copies) { | ||
| 1235 | UNIMPLEMENTED_MSG("Copying images with different samples is not implemented in Vulkan."); | ||
| 1236 | } | ||
| 1237 | |||
| 1233 | u64 TextureCacheRuntime::GetDeviceLocalMemory() const { | 1238 | u64 TextureCacheRuntime::GetDeviceLocalMemory() const { |
| 1234 | return device.GetDeviceLocalMemory(); | 1239 | return device.GetDeviceLocalMemory(); |
| 1235 | } | 1240 | } |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 1f27a3589..b9ee83de7 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -70,6 +70,8 @@ public: | |||
| 70 | 70 | ||
| 71 | void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); | 71 | void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); |
| 72 | 72 | ||
| 73 | void CopyImageMSAA(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); | ||
| 74 | |||
| 73 | bool ShouldReinterpret(Image& dst, Image& src); | 75 | bool ShouldReinterpret(Image& dst, Image& src); |
| 74 | 76 | ||
| 75 | void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); | 77 | void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); |
| @@ -80,6 +82,11 @@ public: | |||
| 80 | return false; | 82 | return false; |
| 81 | } | 83 | } |
| 82 | 84 | ||
| 85 | bool CanUploadMSAA() const noexcept { | ||
| 86 | // TODO: Implement buffer to MSAA uploads | ||
| 87 | return false; | ||
| 88 | } | ||
| 89 | |||
| 83 | void AccelerateImageUpload(Image&, const StagingBufferRef&, | 90 | void AccelerateImageUpload(Image&, const StagingBufferRef&, |
| 84 | std::span<const VideoCommon::SwizzleParameters>); | 91 | std::span<const VideoCommon::SwizzleParameters>); |
| 85 | 92 | ||
diff --git a/src/video_core/texture_cache/formatter.cpp b/src/video_core/texture_cache/formatter.cpp index 418890126..30f72361d 100644 --- a/src/video_core/texture_cache/formatter.cpp +++ b/src/video_core/texture_cache/formatter.cpp | |||
| @@ -22,6 +22,9 @@ std::string Name(const ImageBase& image) { | |||
| 22 | const u32 num_layers = image.info.resources.layers; | 22 | const u32 num_layers = image.info.resources.layers; |
| 23 | const u32 num_levels = image.info.resources.levels; | 23 | const u32 num_levels = image.info.resources.levels; |
| 24 | std::string resource; | 24 | std::string resource; |
| 25 | if (image.info.num_samples > 1) { | ||
| 26 | resource += fmt::format(":{}xMSAA", image.info.num_samples); | ||
| 27 | } | ||
| 25 | if (num_layers > 1) { | 28 | if (num_layers > 1) { |
| 26 | resource += fmt::format(":L{}", num_layers); | 29 | resource += fmt::format(":L{}", num_layers); |
| 27 | } | 30 | } |
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 1b01990a4..3e2cbb0b0 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -773,7 +773,7 @@ void TextureCache<P>::RefreshContents(Image& image, ImageId image_id) { | |||
| 773 | image.flags &= ~ImageFlagBits::CpuModified; | 773 | image.flags &= ~ImageFlagBits::CpuModified; |
| 774 | TrackImage(image, image_id); | 774 | TrackImage(image, image_id); |
| 775 | 775 | ||
| 776 | if (image.info.num_samples > 1) { | 776 | if (image.info.num_samples > 1 && !runtime.CanUploadMSAA()) { |
| 777 | LOG_WARNING(HW_GPU, "MSAA image uploads are not implemented"); | 777 | LOG_WARNING(HW_GPU, "MSAA image uploads are not implemented"); |
| 778 | return; | 778 | return; |
| 779 | } | 779 | } |
| @@ -1167,14 +1167,14 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA | |||
| 1167 | if (True(overlap.flags & ImageFlagBits::GpuModified)) { | 1167 | if (True(overlap.flags & ImageFlagBits::GpuModified)) { |
| 1168 | new_image.flags |= ImageFlagBits::GpuModified; | 1168 | new_image.flags |= ImageFlagBits::GpuModified; |
| 1169 | } | 1169 | } |
| 1170 | const auto& resolution = Settings::values.resolution_info; | ||
| 1171 | const SubresourceBase base = new_image.TryFindBase(overlap.gpu_addr).value(); | ||
| 1172 | const u32 up_scale = can_rescale ? resolution.up_scale : 1; | ||
| 1173 | const u32 down_shift = can_rescale ? resolution.down_shift : 0; | ||
| 1174 | auto copies = MakeShrinkImageCopies(new_info, overlap.info, base, up_scale, down_shift); | ||
| 1170 | if (overlap.info.num_samples != new_image.info.num_samples) { | 1175 | if (overlap.info.num_samples != new_image.info.num_samples) { |
| 1171 | LOG_WARNING(HW_GPU, "Copying between images with different samples is not implemented"); | 1176 | runtime.CopyImageMSAA(new_image, overlap, std::move(copies)); |
| 1172 | } else { | 1177 | } else { |
| 1173 | const auto& resolution = Settings::values.resolution_info; | ||
| 1174 | const SubresourceBase base = new_image.TryFindBase(overlap.gpu_addr).value(); | ||
| 1175 | const u32 up_scale = can_rescale ? resolution.up_scale : 1; | ||
| 1176 | const u32 down_shift = can_rescale ? resolution.down_shift : 0; | ||
| 1177 | auto copies = MakeShrinkImageCopies(new_info, overlap.info, base, up_scale, down_shift); | ||
| 1178 | runtime.CopyImage(new_image, overlap, std::move(copies)); | 1178 | runtime.CopyImage(new_image, overlap, std::move(copies)); |
| 1179 | } | 1179 | } |
| 1180 | if (True(overlap.flags & ImageFlagBits::Tracked)) { | 1180 | if (True(overlap.flags & ImageFlagBits::Tracked)) { |
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 03acc68d9..697f86641 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp | |||
| @@ -573,10 +573,6 @@ u32 CalculateUnswizzledSizeBytes(const ImageInfo& info) noexcept { | |||
| 573 | if (info.type == ImageType::Buffer) { | 573 | if (info.type == ImageType::Buffer) { |
| 574 | return info.size.width * BytesPerBlock(info.format); | 574 | return info.size.width * BytesPerBlock(info.format); |
| 575 | } | 575 | } |
| 576 | if (info.num_samples > 1) { | ||
| 577 | // Multisample images can't be uploaded or downloaded to the host | ||
| 578 | return 0; | ||
| 579 | } | ||
| 580 | if (info.type == ImageType::Linear) { | 576 | if (info.type == ImageType::Linear) { |
| 581 | return info.pitch * Common::DivCeil(info.size.height, DefaultBlockHeight(info.format)); | 577 | return info.pitch * Common::DivCeil(info.size.height, DefaultBlockHeight(info.format)); |
| 582 | } | 578 | } |
| @@ -703,7 +699,6 @@ ImageViewType RenderTargetImageViewType(const ImageInfo& info) noexcept { | |||
| 703 | std::vector<ImageCopy> MakeShrinkImageCopies(const ImageInfo& dst, const ImageInfo& src, | 699 | std::vector<ImageCopy> MakeShrinkImageCopies(const ImageInfo& dst, const ImageInfo& src, |
| 704 | SubresourceBase base, u32 up_scale, u32 down_shift) { | 700 | SubresourceBase base, u32 up_scale, u32 down_shift) { |
| 705 | ASSERT(dst.resources.levels >= src.resources.levels); | 701 | ASSERT(dst.resources.levels >= src.resources.levels); |
| 706 | ASSERT(dst.num_samples == src.num_samples); | ||
| 707 | 702 | ||
| 708 | const bool is_dst_3d = dst.type == ImageType::e3D; | 703 | const bool is_dst_3d = dst.type == ImageType::e3D; |
| 709 | if (is_dst_3d) { | 704 | if (is_dst_3d) { |