diff options
55 files changed, 432 insertions, 91 deletions
| diff --git a/src/audio_core/renderer/performance/performance_manager.cpp b/src/audio_core/renderer/performance/performance_manager.cpp index fd5873e1e..8aa0f5ed0 100644 --- a/src/audio_core/renderer/performance/performance_manager.cpp +++ b/src/audio_core/renderer/performance/performance_manager.cpp @@ -26,6 +26,7 @@ void PerformanceManager::CreateImpl(const size_t version) {          impl = std::make_unique<              PerformanceManagerImpl<PerformanceVersion::Version1, PerformanceFrameHeaderVersion1,                                     PerformanceEntryVersion1, PerformanceDetailVersion1>>(); +        break;      }  } diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index c0555f840..b7c15c191 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -34,6 +34,8 @@ add_library(common STATIC      bit_util.h      cityhash.cpp      cityhash.h +    cache_management.cpp +    cache_management.h      common_funcs.h      common_types.h      concepts.h diff --git a/src/common/atomic_helpers.h b/src/common/atomic_helpers.h index bef5015c1..aef3b66a4 100644 --- a/src/common/atomic_helpers.h +++ b/src/common/atomic_helpers.h @@ -156,6 +156,7 @@ AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN {          break;      default:          assert(false); +        break;      }  } diff --git a/src/common/cache_management.cpp b/src/common/cache_management.cpp new file mode 100644 index 000000000..57810b76a --- /dev/null +++ b/src/common/cache_management.cpp @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <cstring> + +#include "alignment.h" +#include "cache_management.h" +#include "common_types.h" + +namespace Common { + +#if defined(ARCHITECTURE_x86_64) + +// Most cache operations are no-ops on x86 + +void DataCacheLineCleanByVAToPoU(void* start, size_t size) {} +void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size) {} +void DataCacheLineCleanByVAToPoC(void* start, size_t size) {} +void DataCacheZeroByVA(void* start, size_t size) { +    std::memset(start, 0, size); +} + +#elif defined(ARCHITECTURE_arm64) + +// BS/DminLine is log2(cache size in words), we want size in bytes +#define EXTRACT_DMINLINE(ctr_el0) (1 << ((((ctr_el0) >> 16) & 0xf) + 2)) +#define EXTRACT_BS(dczid_el0) (1 << (((dczid_el0)&0xf) + 2)) + +#define DEFINE_DC_OP(op_name, function_name)                                                       \ +    void function_name(void* start, size_t size) {                                                 \ +        size_t ctr_el0;                                                                            \ +        asm volatile("mrs %[ctr_el0], ctr_el0\n\t" : [ctr_el0] "=r"(ctr_el0));                     \ +        size_t cacheline_size = EXTRACT_DMINLINE(ctr_el0);                                         \ +        uintptr_t va_start = reinterpret_cast<uintptr_t>(start);                                   \ +        uintptr_t va_end = va_start + size;                                                        \ +        for (uintptr_t va = va_start; va < va_end; va += cacheline_size) {                         \ +            asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory");                \ +        }                                                                                          \ +    } + +#define DEFINE_DC_OP_DCZID(op_name, function_name)                                                 \ +    void function_name(void* start, size_t size) {                                                 \ +        size_t dczid_el0;                                                                          \ +        asm volatile("mrs %[dczid_el0], dczid_el0\n\t" : [dczid_el0] "=r"(dczid_el0));             \ +        size_t cacheline_size = EXTRACT_BS(dczid_el0);                                             \ +        uintptr_t va_start = reinterpret_cast<uintptr_t>(start);                                   \ +        uintptr_t va_end = va_start + size;                                                        \ +        for (uintptr_t va = va_start; va < va_end; va += cacheline_size) {                         \ +            asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory");                \ +        }                                                                                          \ +    } + +DEFINE_DC_OP(cvau, DataCacheLineCleanByVAToPoU); +DEFINE_DC_OP(civac, DataCacheLineCleanAndInvalidateByVAToPoC); +DEFINE_DC_OP(cvac, DataCacheLineCleanByVAToPoC); +DEFINE_DC_OP_DCZID(zva, DataCacheZeroByVA); + +#endif + +} // namespace Common diff --git a/src/common/cache_management.h b/src/common/cache_management.h new file mode 100644 index 000000000..e467b87e4 --- /dev/null +++ b/src/common/cache_management.h @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "stdlib.h" + +namespace Common { + +// Data cache instructions enabled at EL0 by SCTLR_EL1.UCI. +// VA = virtual address +// PoC = point of coherency +// PoU = point of unification + +// dc cvau +void DataCacheLineCleanByVAToPoU(void* start, size_t size); + +// dc civac +void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size); + +// dc cvac +void DataCacheLineCleanByVAToPoC(void* start, size_t size); + +// dc zva +void DataCacheZeroByVA(void* start, size_t size); + +} // namespace Common diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index aac45907d..fb7e5802a 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -19,27 +19,26 @@ void EmulatedConsole::ReloadFromSettings() {  }  void EmulatedConsole::SetTouchParams() { -    // TODO(german77): Support any number of fingers      std::size_t index = 0; -    // Hardcode mouse, touchscreen and cemuhook parameters +    // We can't use mouse as touch if native mouse is enabled      if (!Settings::values.mouse_enabled) { -        // We can't use mouse as touch if native mouse is enabled          touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"};      }      touch_params[index++] = -        Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0,touch_id:0"}; +        Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"};      touch_params[index++] = -        Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1,touch_id:1"}; -    touch_params[index++] = -        Common::ParamPackage{"engine:touch,axis_x:4,axis_y:5,button:2,touch_id:2"}; -    touch_params[index++] = -        Common::ParamPackage{"engine:touch,axis_x:6,axis_y:7,button:3,touch_id:3"}; -    touch_params[index++] = -        Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536,touch_id:0"}; -    touch_params[index++] = -        Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072,touch_id:1"}; +        Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"}; + +    for (int i = 0; i < static_cast<int>(MaxActiveTouchInputs); i++) { +        Common::ParamPackage touchscreen_param{}; +        touchscreen_param.Set("engine", "touch"); +        touchscreen_param.Set("axis_x", i * 2); +        touchscreen_param.Set("axis_y", (i * 2) + 1); +        touchscreen_param.Set("button", i); +        touch_params[index++] = touchscreen_param; +    }      const auto button_index =          static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue()); @@ -47,7 +46,7 @@ void EmulatedConsole::SetTouchParams() {      // Map the rest of the fingers from touch from button configuration      for (const auto& config_entry : touch_buttons) { -        if (index >= touch_params.size()) { +        if (index >= MaxTouchDevices) {              continue;          }          Common::ParamPackage params{config_entry}; @@ -60,7 +59,6 @@ void EmulatedConsole::SetTouchParams() {          touch_button_params.Set("button", params.Serialize());          touch_button_params.Set("x", x);          touch_button_params.Set("y", y); -        touch_button_params.Set("touch_id", static_cast<int>(index));          touch_params[index] = touch_button_params;          index++;      } @@ -178,12 +176,38 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {  }  void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) { -    if (index >= console.touch_values.size()) { +    if (index >= MaxTouchDevices) {          return;      }      std::unique_lock lock{mutex}; -    console.touch_values[index] = TransformToTouch(callback); +    const auto touch_input = TransformToTouch(callback); +    auto touch_index = GetIndexFromFingerId(index); +    bool is_new_input = false; + +    if (!touch_index.has_value() && touch_input.pressed.value) { +        touch_index = GetNextFreeIndex(); +        is_new_input = true; +    } + +    // No free entries or invalid state. Ignore input +    if (!touch_index.has_value()) { +        return; +    } + +    auto& touch_value = console.touch_values[touch_index.value()]; + +    if (is_new_input) { +        touch_value.pressed.value = true; +        touch_value.id = static_cast<u32>(index); +    } + +    touch_value.x = touch_input.x; +    touch_value.y = touch_input.y; + +    if (!touch_input.pressed.value) { +        touch_value.pressed.value = false; +    }      if (is_configuring) {          lock.unlock(); @@ -191,11 +215,15 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st          return;      } -    // TODO(german77): Remap touch id in sequential order -    console.touch_state[index] = { -        .position = {console.touch_values[index].x.value, console.touch_values[index].y.value}, -        .id = static_cast<u32>(console.touch_values[index].id), -        .pressed = console.touch_values[index].pressed.value, +    // Touch outside allowed range. Ignore input +    if (touch_index.value() >= MaxActiveTouchInputs) { +        return; +    } + +    console.touch_state[touch_index.value()] = { +        .position = {touch_value.x.value, touch_value.y.value}, +        .id = static_cast<u32>(touch_index.value()), +        .pressed = touch_input.pressed.value,      };      lock.unlock(); @@ -222,6 +250,28 @@ TouchFingerState EmulatedConsole::GetTouch() const {      return console.touch_state;  } +std::optional<std::size_t> EmulatedConsole::GetIndexFromFingerId(std::size_t finger_id) const { +    for (std::size_t index = 0; index < MaxTouchDevices; ++index) { +        const auto& finger = console.touch_values[index]; +        if (!finger.pressed.value) { +            continue; +        } +        if (finger.id == static_cast<int>(finger_id)) { +            return index; +        } +    } +    return std::nullopt; +} + +std::optional<std::size_t> EmulatedConsole::GetNextFreeIndex() const { +    for (std::size_t index = 0; index < MaxTouchDevices; ++index) { +        if (!console.touch_values[index].pressed.value) { +            return index; +        } +    } +    return std::nullopt; +} +  void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {      std::scoped_lock lock{callback_mutex};      for (const auto& poller_pair : callback_list) { diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index 1c510cd19..697ecd2d6 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -7,6 +7,7 @@  #include <functional>  #include <memory>  #include <mutex> +#include <optional>  #include <unordered_map>  #include "common/common_funcs.h" @@ -20,6 +21,8 @@  #include "core/hid/motion_input.h"  namespace Core::HID { +static constexpr std::size_t MaxTouchDevices = 32; +static constexpr std::size_t MaxActiveTouchInputs = 16;  struct ConsoleMotionInfo {      Common::Input::MotionStatus raw_status{}; @@ -27,13 +30,13 @@ struct ConsoleMotionInfo {  };  using ConsoleMotionDevices = std::unique_ptr<Common::Input::InputDevice>; -using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, 16>; +using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, MaxTouchDevices>;  using ConsoleMotionParams = Common::ParamPackage; -using TouchParams = std::array<Common::ParamPackage, 16>; +using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>;  using ConsoleMotionValues = ConsoleMotionInfo; -using TouchValues = std::array<Common::Input::TouchStatus, 16>; +using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>;  struct TouchFinger {      u64 last_touch{}; @@ -55,7 +58,7 @@ struct ConsoleMotion {      bool is_at_rest{};  }; -using TouchFingerState = std::array<TouchFinger, 16>; +using TouchFingerState = std::array<TouchFinger, MaxActiveTouchInputs>;  struct ConsoleStatus {      // Data from input_common @@ -166,6 +169,10 @@ private:       */      void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index); +    std::optional<std::size_t> GetIndexFromFingerId(std::size_t finger_id) const; + +    std::optional<std::size_t> GetNextFreeIndex() const; +      /**       * Triggers a callback that something has changed on the console status       * @param type Input type of the event to trigger diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 5d8b75b50..502692875 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -200,9 +200,6 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus&      x = std::clamp(x, 0.0f, 1.0f);      y = std::clamp(y, 0.0f, 1.0f); -    // Limit id to maximum number of fingers -    status.id = std::clamp(status.id, 0, 16); -      if (status.pressed.inverted) {          status.pressed.value = !status.pressed.value;      } diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index bda098511..7b363eb1e 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -243,6 +243,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) {              // If we somehow get an invalid type, abort.          default:              ASSERT_MSG(false, "Unknown slab type: {}", slab_types[i]); +            break;          }          // If we've hit the end of a gap, free it. diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 5387bf5fe..612fc76fa 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -2301,6 +2301,7 @@ Result KPageTable::SetProcessMemoryPermission(VAddr addr, size_t size,              break;          default:              ASSERT(false); +            break;          }      } @@ -2803,6 +2804,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, const KPageGroup& page_              break;          default:              ASSERT(false); +            break;          }          addr += size; @@ -2838,6 +2840,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, KMemoryPermission perm,          break;      default:          ASSERT(false); +        break;      }      R_SUCCEED();  } diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 55a9c5fae..d1dc62401 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -395,6 +395,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:      default:          ASSERT(false); +        break;      }      // Create TLS region diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9962ad171..e520cab47 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2701,14 +2701,24 @@ static Result GetThreadList(Core::System& system, u32* out_num_threads, VAddr ou      return ResultSuccess;  } -static Result FlushProcessDataCache32([[maybe_unused]] Core::System& system, -                                      [[maybe_unused]] Handle handle, [[maybe_unused]] u32 address, -                                      [[maybe_unused]] u32 size) { -    // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a no-op, -    // as all emulation is done in the same cache level in host architecture, thus data cache -    // does not need flushing. -    LOG_DEBUG(Kernel_SVC, "called"); -    return ResultSuccess; +static Result FlushProcessDataCache32(Core::System& system, Handle process_handle, u64 address, +                                      u64 size) { +    // Validate address/size. +    R_UNLESS(size > 0, ResultInvalidSize); +    R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory); +    R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory); + +    // Get the process from its handle. +    KScopedAutoObject process = +        system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KProcess>(process_handle); +    R_UNLESS(process.IsNotNull(), ResultInvalidHandle); + +    // Verify the region is within range. +    auto& page_table = process->PageTable(); +    R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); + +    // Perform the operation. +    R_RETURN(system.Memory().FlushDataCache(*process, address, size));  }  namespace { diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 272c54cf7..3730937fe 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -722,4 +722,12 @@ void SvcWrap32(Core::System& system) {      FuncReturn(system, retval);  } +// Used by Invalidate/Store/FlushProcessDataCache32 +template <Result func(Core::System&, Handle, u64, u64)> +void SvcWrap32(Core::System& system) { +    const u64 address = (Param(system, 3) << 32) | Param(system, 2); +    const u64 size = (Param(system, 4) << 32) | Param(system, 1); +    FuncReturn32(system, func(system, Param32(system, 0), address, size).raw); +} +  } // namespace Kernel diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp index fcf34bf7e..bae0d99a6 100644 --- a/src/core/hle/service/am/applets/applet_error.cpp +++ b/src/core/hle/service/am/applets/applet_error.cpp @@ -144,6 +144,7 @@ void Error::Initialize() {          break;      default:          UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode); +        break;      }  } diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp index c34ef08b3..e50acdaf6 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.cpp +++ b/src/core/hle/service/am/applets/applet_general_backend.cpp @@ -129,6 +129,7 @@ void Auth::Execute() {      }      default:          unimplemented_log(); +        break;      }  } @@ -192,6 +193,7 @@ void PhotoViewer::Execute() {          break;      default:          UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode); +        break;      }  } diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 79375bd2f..bf28440c6 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -36,8 +36,9 @@ namespace Service::HID {  // Updating period for each HID device.  // Period time is obtained by measuring the number of samples in a second on HW using a homebrew -// Correct pad_update_ns is 4ms this is overclocked to lower input lag -constexpr auto pad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz) +// Correct npad_update_ns is 4ms this is overclocked to lower input lag +constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000};    // (1ms, 1000Hz) +constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz)  constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)  constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000};         // (5ms, 200Hz) @@ -75,11 +76,19 @@ IAppletResource::IAppletResource(Core::System& system_,      GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);      // Register update callbacks -    pad_update_event = Core::Timing::CreateEvent( +    npad_update_event = Core::Timing::CreateEvent(          "HID::UpdatePadCallback",          [this](std::uintptr_t user_data, s64 time,                 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {              const auto guard = LockService(); +            UpdateNpad(user_data, ns_late); +            return std::nullopt; +        }); +    default_update_event = Core::Timing::CreateEvent( +        "HID::UpdateDefaultCallback", +        [this](std::uintptr_t user_data, s64 time, +               std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { +            const auto guard = LockService();              UpdateControllers(user_data, ns_late);              return std::nullopt;          }); @@ -100,7 +109,9 @@ IAppletResource::IAppletResource(Core::System& system_,              return std::nullopt;          }); -    system.CoreTiming().ScheduleLoopingEvent(pad_update_ns, pad_update_ns, pad_update_event); +    system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event); +    system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns, +                                             default_update_event);      system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,                                               mouse_keyboard_update_event);      system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns, @@ -118,7 +129,8 @@ void IAppletResource::DeactivateController(HidController controller) {  }  IAppletResource::~IAppletResource() { -    system.CoreTiming().UnscheduleEvent(pad_update_event, 0); +    system.CoreTiming().UnscheduleEvent(npad_update_event, 0); +    system.CoreTiming().UnscheduleEvent(default_update_event, 0);      system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);      system.CoreTiming().UnscheduleEvent(motion_update_event, 0);  } @@ -144,10 +156,20 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,          if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) {              continue;          } +        // Npad has it's own update event +        if (controller == controllers[static_cast<size_t>(HidController::NPad)]) { +            continue; +        }          controller->OnUpdate(core_timing);      }  } +void IAppletResource::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { +    auto& core_timing = system.CoreTiming(); + +    controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing); +} +  void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,                                            std::chrono::nanoseconds ns_late) {      auto& core_timing = system.CoreTiming(); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 340d26fdc..b7c2a23ef 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -71,12 +71,14 @@ private:      void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);      void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); +    void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);      void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);      void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);      KernelHelpers::ServiceContext& service_context; -    std::shared_ptr<Core::Timing::EventType> pad_update_event; +    std::shared_ptr<Core::Timing::EventType> npad_update_event; +    std::shared_ptr<Core::Timing::EventType> default_update_event;      std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;      std::shared_ptr<Core::Timing::EventType> motion_update_event; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index ced57dfe6..b97813fbc 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -300,11 +300,10 @@ Kernel::KEvent* nvhost_ctrl_gpu::QueryEvent(u32 event_id) {          return error_notifier_event;      case 2:          return unknown_event; -    default: { +    default:          LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); +        return nullptr;      } -    } -    return nullptr;  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 45a759fa8..e123564c6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -364,11 +364,10 @@ Kernel::KEvent* nvhost_gpu::QueryEvent(u32 event_id) {          return sm_exception_breakpoint_pause_report_event;      case 3:          return error_notifier_event; -    default: { +    default:          LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); +        return nullptr;      } -    } -    return nullptr;  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp index ea4a14ea4..3d1338e66 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp @@ -23,15 +23,17 @@ void BufferQueueCore::NotifyShutdown() {  }  void BufferQueueCore::SignalDequeueCondition() { +    dequeue_possible.store(true);      dequeue_condition.notify_all();  } -bool BufferQueueCore::WaitForDequeueCondition() { +bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) {      if (is_shutting_down) {          return false;      } -    dequeue_condition.wait(mutex); +    dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); }); +    dequeue_possible.store(false);      return true;  } diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h index ca6baefaf..85b3bc4c1 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.h +++ b/src/core/hle/service/nvflinger/buffer_queue_core.h @@ -38,7 +38,7 @@ public:  private:      void SignalDequeueCondition(); -    bool WaitForDequeueCondition(); +    bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk);      s32 GetMinUndequeuedBufferCountLocked(bool async) const;      s32 GetMinMaxBufferCountLocked(bool async) const; @@ -60,7 +60,8 @@ private:      BufferQueueDefs::SlotsType slots{};      std::vector<BufferItem> queue;      s32 override_max_buffer_count{}; -    mutable std::condition_variable_any dequeue_condition; +    std::condition_variable dequeue_condition; +    std::atomic<bool> dequeue_possible{};      const bool use_async_buffer{}; // This is always disabled on HOS      bool dequeue_buffer_cannot_block{};      PixelFormat default_buffer_format{PixelFormat::Rgba8888}; diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index 41ba44b21..e601b5da1 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -121,8 +121,8 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {      return Status::NoError;  } -Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, -                                                      Status* return_flags) const { +Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags, +                                                      std::unique_lock<std::mutex>& lk) const {      bool try_again = true;      while (try_again) { @@ -214,7 +214,7 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found,                  return Status::WouldBlock;              } -            if (!core->WaitForDequeueCondition()) { +            if (!core->WaitForDequeueCondition(lk)) {                  // We are no longer running                  return Status::NoError;              } @@ -237,7 +237,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool      Status return_flags = Status::NoError;      bool attached_by_consumer = false;      { -        std::scoped_lock lock{core->mutex}; +        std::unique_lock lock{core->mutex};          core->WaitWhileAllocatingLocked();          if (format == PixelFormat::NoFormat) { @@ -248,7 +248,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool          usage |= core->consumer_usage_bit;          s32 found{}; -        Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags); +        Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags, lock);          if (status != Status::NoError) {              return status;          } @@ -400,13 +400,13 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot,          return Status::BadValue;      } -    std::scoped_lock lock{core->mutex}; +    std::unique_lock lock{core->mutex};      core->WaitWhileAllocatingLocked();      Status return_flags = Status::NoError;      s32 found{}; -    const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags); +    const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags, lock);      if (status != Status::NoError) {          return status;      } diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h index 7526bf8ec..1d380480f 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.h +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.h @@ -70,7 +70,8 @@ public:  private:      BufferQueueProducer(const BufferQueueProducer&) = delete; -    Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags) const; +    Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags, +                                     std::unique_lock<std::mutex>& lk) const;      Kernel::KEvent* buffer_wait_event{};      Service::KernelHelpers::ServiceContext& service_context; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 5ab41c0c4..0de67f1e1 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -228,6 +228,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,          }          UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType()); +        break;      }      // If emulation was shutdown, we are closing service threads, do not write the response back to diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 2aa675df9..f9ada7c93 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp @@ -280,6 +280,7 @@ static constexpr int TransitionTime(int year, Rule rule, int offset) {      }      default:          ASSERT(false); +        break;      }      return value + rule.transition_time + offset;  } diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 3ca80c8ff..3141122f1 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -6,6 +6,7 @@  #include "common/assert.h"  #include "common/atomic_ops.h" +#include "common/cache_management.h"  #include "common/common_types.h"  #include "common/logging/log.h"  #include "common/page_table.h" @@ -329,6 +330,55 @@ struct Memory::Impl {              });      } +    template <typename Callback> +    Result PerformCacheOperation(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size, +                                 Callback&& cb) { +        class InvalidMemoryException : public std::exception {}; + +        try { +            WalkBlock( +                process, dest_addr, size, +                [&](const std::size_t block_size, const VAddr current_vaddr) { +                    LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}", current_vaddr); +                    throw InvalidMemoryException(); +                }, +                [&](const std::size_t block_size, u8* const host_ptr) { cb(block_size, host_ptr); }, +                [&](const VAddr current_vaddr, const std::size_t block_size, u8* const host_ptr) { +                    system.GPU().FlushRegion(current_vaddr, block_size); +                    cb(block_size, host_ptr); +                }, +                [](const std::size_t block_size) {}); +        } catch (InvalidMemoryException&) { +            return Kernel::ResultInvalidCurrentMemory; +        } + +        return ResultSuccess; +    } + +    Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { +        auto perform = [&](const std::size_t block_size, u8* const host_ptr) { +            // Do nothing; this operation (dc ivac) cannot be supported +            // from EL0 +        }; +        return PerformCacheOperation(process, dest_addr, size, perform); +    } + +    Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { +        auto perform = [&](const std::size_t block_size, u8* const host_ptr) { +            // dc cvac: Store to point of coherency +            Common::DataCacheLineCleanByVAToPoC(host_ptr, block_size); +        }; +        return PerformCacheOperation(process, dest_addr, size, perform); +    } + +    Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { +        auto perform = [&](const std::size_t block_size, u8* const host_ptr) { +            // dc civac: Store to point of coherency, and invalidate from cache +            Common::DataCacheLineCleanAndInvalidateByVAToPoC(host_ptr, block_size); +        }; +        return PerformCacheOperation(process, dest_addr, size, perform); +    } +      void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) {          if (vaddr == 0) {              return; @@ -786,6 +836,21 @@ void Memory::ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, const s      impl->ZeroBlock(process, dest_addr, size);  } +Result Memory::InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, +                                   const std::size_t size) { +    return impl->InvalidateDataCache(process, dest_addr, size); +} + +Result Memory::StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, +                              const std::size_t size) { +    return impl->StoreDataCache(process, dest_addr, size); +} + +Result Memory::FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, +                              const std::size_t size) { +    return impl->FlushDataCache(process, dest_addr, size); +} +  void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {      impl->RasterizerMarkRegionCached(vaddr, size, cached);  } diff --git a/src/core/memory.h b/src/core/memory.h index 81eac448b..31fe699d8 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -7,6 +7,7 @@  #include <memory>  #include <string>  #include "common/common_types.h" +#include "core/hle/result.h"  namespace Common {  struct PageTable; @@ -450,6 +451,39 @@ public:      void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);      /** +     * Invalidates a range of bytes within the current process' address space at the specified +     * virtual address. +     * +     * @param process   The process that will have data invalidated within its address space. +     * @param dest_addr The destination virtual address to invalidate the data from. +     * @param size      The size of the range to invalidate, in bytes. +     * +     */ +    Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); + +    /** +     * Stores a range of bytes within the current process' address space at the specified +     * virtual address. +     * +     * @param process   The process that will have data stored within its address space. +     * @param dest_addr The destination virtual address to store the data from. +     * @param size      The size of the range to store, in bytes. +     * +     */ +    Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); + +    /** +     * Flushes a range of bytes within the current process' address space at the specified +     * virtual address. +     * +     * @param process   The process that will have data flushed within its address space. +     * @param dest_addr The destination virtual address to flush the data from. +     * @param size      The size of the range to flush, in bytes. +     * +     */ +    Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); + +    /**       * Marks each page within the specified address range as cached or uncached.       *       * @param vaddr  The virtual address indicating the start of the address range. diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index da4a3dca5..003a38da5 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -10,8 +10,8 @@ namespace InputCommon {  class TouchFromButtonDevice final : public Common::Input::InputDevice {  public:      using Button = std::unique_ptr<Common::Input::InputDevice>; -    TouchFromButtonDevice(Button button_, int touch_id_, float x_, float y_) -        : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) { +    TouchFromButtonDevice(Button button_, float x_, float y_) +        : button(std::move(button_)), x(x_), y(y_) {          last_button_value = false;          button->SetCallback({              .on_change = @@ -34,7 +34,6 @@ public:              .pressed = button_status,              .x = {},              .y = {}, -            .id = touch_id,          };          status.x.properties = properties;          status.y.properties = properties; @@ -62,7 +61,6 @@ public:  private:      Button button;      bool last_button_value; -    const int touch_id;      const float x;      const float y;      const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; @@ -73,10 +71,9 @@ std::unique_ptr<Common::Input::InputDevice> TouchFromButton::Create(      const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize();      auto button = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>(          params.Get("button", null_engine)); -    const auto touch_id = params.Get("touch_id", 0);      const float x = params.Get("x", 0.0f) / 1280.0f;      const float y = params.Get("y", 0.0f) / 720.0f; -    return std::make_unique<TouchFromButtonDevice>(std::move(button), touch_id, x, y); +    return std::make_unique<TouchFromButtonDevice>(std::move(button), x, y);  }  } // namespace InputCommon diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 4ac182147..fb8be42e2 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -229,13 +229,12 @@ private:  class InputFromTouch final : public Common::Input::InputDevice {  public: -    explicit InputFromTouch(PadIdentifier identifier_, int touch_id_, int button_, bool toggle_, -                            bool inverted_, int axis_x_, int axis_y_, -                            Common::Input::AnalogProperties properties_x_, +    explicit InputFromTouch(PadIdentifier identifier_, int button_, bool toggle_, bool inverted_, +                            int axis_x_, int axis_y_, Common::Input::AnalogProperties properties_x_,                              Common::Input::AnalogProperties properties_y_,                              InputEngine* input_engine_) -        : identifier(identifier_), touch_id(touch_id_), button(button_), toggle(toggle_), -          inverted(inverted_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_), +        : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_), +          axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_),            properties_y(properties_y_), input_engine(input_engine_) {          UpdateCallback engine_callback{[this]() { OnChange(); }};          const InputIdentifier button_input_identifier{ @@ -271,8 +270,7 @@ public:      }      Common::Input::TouchStatus GetStatus() const { -        Common::Input::TouchStatus status; -        status.id = touch_id; +        Common::Input::TouchStatus status{};          status.pressed = {              .value = input_engine->GetButton(identifier, button),              .inverted = inverted, @@ -307,7 +305,6 @@ public:  private:      const PadIdentifier identifier; -    const int touch_id;      const int button;      const bool toggle;      const bool inverted; @@ -919,7 +916,6 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTriggerDevice(  std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice(      const Common::ParamPackage& params) { -    const auto touch_id = params.Get("touch_id", 0);      const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);      const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f);      const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f); @@ -954,8 +950,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice(      input_engine->PreSetAxis(identifier, axis_x);      input_engine->PreSetAxis(identifier, axis_y);      input_engine->PreSetButton(identifier, button); -    return std::make_unique<InputFromTouch>(identifier, touch_id, button, toggle, inverted, axis_x, -                                            axis_y, properties_x, properties_y, input_engine.get()); +    return std::make_unique<InputFromTouch>(identifier, button, toggle, inverted, axis_x, axis_y, +                                            properties_x, properties_y, input_engine.get());  }  std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateBatteryDevice( diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp index 3b0176bf6..0cb1e193e 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp @@ -320,6 +320,7 @@ void SetupOptions(const IR::Program& program, const Profile& profile,      }      if (stage == Stage::Fragment) {          header += "OPTION ARB_draw_buffers;"; +        header += "OPTION ARB_fragment_layer_viewport;";      }  } diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp index d6562c842..f0bd84ab2 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp @@ -104,6 +104,9 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal      case IR::Attribute::PrimitiveId:          ctx.Add("MOV.F {}.x,primitive.id;", inst);          break; +    case IR::Attribute::Layer: +        ctx.Add("MOV.F {}.x,fragment.layer;", inst); +        break;      case IR::Attribute::PositionX:      case IR::Attribute::PositionY:      case IR::Attribute::PositionZ: diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp index c1671c37b..39579cf5d 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp @@ -205,6 +205,9 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,      case IR::Attribute::PrimitiveId:          ctx.AddF32("{}=itof(gl_PrimitiveID);", inst);          break; +    case IR::Attribute::Layer: +        ctx.AddF32("{}=itof(gl_Layer);", inst); +        break;      case IR::Attribute::PositionX:      case IR::Attribute::PositionY:      case IR::Attribute::PositionZ: 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 5b3b5d1f3..01f6ec9b5 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 @@ -315,6 +315,8 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {      switch (attr) {      case IR::Attribute::PrimitiveId:          return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.primitive_id)); +    case IR::Attribute::Layer: +        return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.layer));      case IR::Attribute::PositionX:      case IR::Attribute::PositionY:      case IR::Attribute::PositionZ: diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 0bfc2dd89..8e3e40cd5 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -1359,6 +1359,11 @@ void EmitContext::DefineInputs(const IR::Program& program) {      if (loads[IR::Attribute::PrimitiveId]) {          primitive_id = DefineInput(*this, U32[1], false, spv::BuiltIn::PrimitiveId);      } +    if (loads[IR::Attribute::Layer]) { +        AddCapability(spv::Capability::Geometry); +        layer = DefineInput(*this, U32[1], false, spv::BuiltIn::Layer); +        Decorate(layer, spv::Decoration::Flat); +    }      if (loads.AnyComponent(IR::Attribute::PositionX)) {          const bool is_fragment{stage != Stage::Fragment};          const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::Position : spv::BuiltIn::FragCoord}; diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index d502d181c..5bb1427c1 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -232,7 +232,7 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume          use_topology_override = true;          return;      case MAXWELL3D_REG_INDEX(clear_surface): -        return ProcessClearBuffers(); +        return ProcessClearBuffers(1);      case MAXWELL3D_REG_INDEX(report_semaphore.query):          return ProcessQueryGet();      case MAXWELL3D_REG_INDEX(render_enable.mode): @@ -596,8 +596,8 @@ u32 Maxwell3D::GetRegisterValue(u32 method) const {      return regs.reg_array[method];  } -void Maxwell3D::ProcessClearBuffers() { -    rasterizer->Clear(); +void Maxwell3D::ProcessClearBuffers(u32 layer_count) { +    rasterizer->Clear(layer_count);  }  void Maxwell3D::ProcessDraw(u32 instance_count) { diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 34b085388..c3099f9a6 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -3086,6 +3086,9 @@ public:      std::vector<u8> inline_index_draw_indexes; +    /// Handles a write to the CLEAR_BUFFERS register. +    void ProcessClearBuffers(u32 layer_count); +  private:      void InitializeRegisterDefaults(); @@ -3120,9 +3123,6 @@ private:      /// Handles firmware blob 4      void ProcessFirmwareCall4(); -    /// Handles a write to the CLEAR_BUFFERS register. -    void ProcessClearBuffers(); -      /// Handles a write to the QUERY_GET register.      void ProcessQueryGet(); diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index 54523a4b2..1bf6ca2dd 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp @@ -314,6 +314,7 @@ void MaxwellDMA::ReleaseSemaphore() {      }      default:          ASSERT_MSG(false, "Unknown semaphore type: {}", static_cast<u32>(type.Value())); +        break;      }  } diff --git a/src/video_core/engines/puller.cpp b/src/video_core/engines/puller.cpp index 3977bb0fb..4d2278811 100644 --- a/src/video_core/engines/puller.cpp +++ b/src/video_core/engines/puller.cpp @@ -50,6 +50,7 @@ void Puller::ProcessBindMethod(const MethodCall& method_call) {          break;      default:          UNIMPLEMENTED_MSG("Unimplemented engine {:04X}", engine_id); +        break;      }  } @@ -65,6 +66,7 @@ void Puller::ProcessFenceActionMethod() {          break;      default:          UNIMPLEMENTED_MSG("Unimplemented operation {}", regs.fence_action.op.Value()); +        break;      }  } @@ -228,6 +230,7 @@ void Puller::CallEngineMethod(const MethodCall& method_call) {          break;      default:          UNIMPLEMENTED_MSG("Unimplemented engine"); +        break;      }  } @@ -254,6 +257,7 @@ void Puller::CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_s          break;      default:          UNIMPLEMENTED_MSG("Unimplemented engine"); +        break;      }  } diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index f896591bf..0f3262edb 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp @@ -126,11 +126,25 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&      }  } -constexpr std::array<std::pair<u64, HLEFunction>, 4> hle_funcs{{ +// Multi-layer Clear +void HLE_EAD26C3E2109B06B(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { +    ASSERT(parameters.size() == 1); + +    const Engines::Maxwell3D::Regs::ClearSurface clear_params{parameters[0]}; +    const u32 rt_index = clear_params.RT; +    const u32 num_layers = maxwell3d.regs.rt[rt_index].depth; +    ASSERT(clear_params.layer == 0); + +    maxwell3d.regs.clear_surface.raw = clear_params.raw; +    maxwell3d.ProcessClearBuffers(num_layers); +} + +constexpr std::array<std::pair<u64, HLEFunction>, 5> hle_funcs{{      {0x771BB18C62444DA0, &HLE_771BB18C62444DA0},      {0x0D61FC9FAAC9FCAD, &HLE_0D61FC9FAAC9FCAD},      {0x0217920100488FF7, &HLE_0217920100488FF7},      {0x3F5E74B9C9A50164, &HLE_3F5E74B9C9A50164}, +    {0xEAD26C3E2109B06B, &HLE_EAD26C3E2109B06B},  }};  class HLEMacroImpl final : public CachedMacro { diff --git a/src/video_core/macro/macro_interpreter.cpp b/src/video_core/macro/macro_interpreter.cpp index c0d32c112..0d63495a9 100644 --- a/src/video_core/macro/macro_interpreter.cpp +++ b/src/video_core/macro/macro_interpreter.cpp @@ -201,6 +201,7 @@ bool MacroInterpreterImpl::Step(bool is_delay_slot) {      }      default:          UNIMPLEMENTED_MSG("Unimplemented macro operation {}", opcode.operation.Value()); +        break;      }      // An instruction with the Exit flag will not actually @@ -297,6 +298,7 @@ void MacroInterpreterImpl::ProcessResult(Macro::ResultOperation operation, u32 r          break;      default:          UNIMPLEMENTED_MSG("Unimplemented result operation {}", operation); +        break;      }  } diff --git a/src/video_core/macro/macro_jit_x64.cpp b/src/video_core/macro/macro_jit_x64.cpp index 25c1ce798..7347cbd88 100644 --- a/src/video_core/macro/macro_jit_x64.cpp +++ b/src/video_core/macro/macro_jit_x64.cpp @@ -652,6 +652,7 @@ void MacroJITx64Impl::Compile_ProcessResult(Macro::ResultOperation operation, u3          break;      default:          UNIMPLEMENTED_MSG("Unimplemented macro operation {}", operation); +        break;      }  } diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 1cbfef090..cfd872a40 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -43,7 +43,7 @@ public:      virtual void Draw(bool is_indexed, u32 instance_count) = 0;      /// Clear the current framebuffer -    virtual void Clear() = 0; +    virtual void Clear(u32 layer_count) = 0;      /// Dispatches a compute shader invocation      virtual void DispatchCompute() = 0; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index d05a5f60b..115a5e010 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -136,7 +136,7 @@ void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_load      shader_cache.LoadDiskResources(title_id, stop_loading, callback);  } -void RasterizerOpenGL::Clear() { +void RasterizerOpenGL::Clear(u32 layer_count) {      MICROPROFILE_SCOPE(OpenGL_Clears);      if (!maxwell3d->ShouldExecute()) {          return; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 793e0d608..449a14f12 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -69,7 +69,7 @@ public:      ~RasterizerOpenGL() override;      void Draw(bool is_indexed, u32 instance_count) override; -    void Clear() override; +    void Clear(u32 layer_count) override;      void DispatchCompute() override;      void ResetCounter(VideoCore::QueryType type) override;      void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) override; diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 99cd11d1e..9f7ce7414 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -891,6 +891,7 @@ void Image::CopyBufferToImage(const VideoCommon::BufferImageCopy& copy, size_t b          break;      default:          ASSERT(false); +        break;      }  } @@ -927,6 +928,7 @@ void Image::CopyImageToBuffer(const VideoCommon::BufferImageCopy& copy, size_t b          break;      default:          ASSERT(false); +        break;      }      // Compressed formats don't have a pixel format or type      const bool is_compressed = gl_format == GL_NONE; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 8bd5eba7e..f29462f7c 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -340,6 +340,7 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,          texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;          // UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}",          //                   static_cast<u32>(framebuffer.pixel_format)); +        break;      }      texture.resource.Release(); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f69c0c50f..67b88621a 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -213,7 +213,7 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) {      EndTransformFeedback();  } -void RasterizerVulkan::Clear() { +void RasterizerVulkan::Clear(u32 layer_count) {      MICROPROFILE_SCOPE(Vulkan_Clearing);      if (!maxwell3d->ShouldExecute()) { @@ -256,7 +256,7 @@ void RasterizerVulkan::Clear() {          .rect = regs.clear_control.use_scissor ? GetScissorState(regs, 0, up_scale, down_shift)                                                 : default_scissor,          .baseArrayLayer = regs.clear_surface.layer, -        .layerCount = 1, +        .layerCount = layer_count,      };      if (clear_rect.rect.extent.width == 0 || clear_rect.rect.extent.height == 0) {          return; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index b0bc306f5..70f36d58a 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -65,7 +65,7 @@ public:      ~RasterizerVulkan() override;      void Draw(bool is_indexed, u32 instance_count) override; -    void Clear() override; +    void Clear(u32 layer_count) override;      void DispatchCompute() override;      void ResetCounter(VideoCore::QueryType type) override;      void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) override; diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 7934f2a51..4a7b633b7 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -221,6 +221,7 @@ void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_s              [[fallthrough]];          default:              vk::Check(result); +            break;          }      });      chunk->MarkSubmit(); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 853b80d8a..a65bbeb1c 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -108,6 +108,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {              break;          default:              ASSERT_MSG(false, "Invalid surface type"); +            break;          }      }      if (info.storage) { diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index fd1a4b987..59120cd09 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -170,6 +170,7 @@ void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixe  #undef BPP_CASE      default:          ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); +        break;      }  } @@ -217,6 +218,7 @@ void SwizzleSubrect(std::span<u8> output, std::span<const u8> input, u32 bytes_p  #undef BPP_CASE      default:          ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); +        break;      }  } @@ -240,6 +242,7 @@ void UnswizzleSubrect(std::span<u8> output, std::span<const u8> input, u32 bytes  #undef BPP_CASE      default:          ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); +        break;      }  } diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp index b03e71248..05f49c0d2 100644 --- a/src/yuzu/compatdb.cpp +++ b/src/yuzu/compatdb.cpp @@ -126,6 +126,7 @@ void CompatDB::Submit() {          break;      default:          LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); +        break;      }  } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 72498f52a..7ee2302cc 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1956,6 +1956,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target      }      default:          UNIMPLEMENTED(); +        break;      }      const QString qpath = QString::fromStdString(Common::FS::PathToUTF8String(path)); @@ -3199,6 +3200,7 @@ void GMainWindow::OnToggleGpuAccuracy() {      case Settings::GPUAccuracy::Extreme:      default: {          Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::High); +        break;      }      } @@ -3531,6 +3533,7 @@ void GMainWindow::UpdateGPUAccuracyButton() {      default: {          gpu_accuracy_button->setText(tr("GPU ERROR"));          gpu_accuracy_button->setChecked(true); +        break;      }      }  } diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp index 65455c86e..25948328c 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp @@ -84,6 +84,7 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste      default:          LOG_CRITICAL(Frontend, "Window manager subsystem not implemented");          std::exit(EXIT_FAILURE); +        break;      }      OnResize(); diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index e16f79eb4..dfe5a30ea 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -351,6 +351,7 @@ int main(int argc, char** argv) {                           "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",                           loader_id, error_id, static_cast<Loader::ResultStatus>(error_id));          } +        break;      }      system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "SDL"); | 
