diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/file_sys/vfs_real.cpp | 14 | ||||
| -rw-r--r-- | src/core/frontend/emu_window.cpp | 43 | ||||
| -rw-r--r-- | src/core/frontend/emu_window.h | 13 | ||||
| -rw-r--r-- | src/core/frontend/input.h | 7 | ||||
| -rw-r--r-- | src/core/hle/service/acc/acc.cpp | 61 | ||||
| -rw-r--r-- | src/core/hle/service/acc/acc.h | 5 | ||||
| -rw-r--r-- | src/core/hle/service/acc/acc_su.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/acc/acc_u0.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/acc/acc_u1.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/am/am.cpp | 9 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/touchscreen.cpp | 127 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/touchscreen.h | 32 | ||||
| -rw-r--r-- | src/core/hle/service/lbl/lbl.cpp | 283 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 8 | 
14 files changed, 519 insertions, 89 deletions
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index a287eebe3..a44ce6288 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -133,8 +133,11 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_          }          cache.erase(old_path); -        file->Open(new_path, "r+b"); -        cache.insert_or_assign(new_path, std::move(file)); +        if (file->Open(new_path, "r+b")) { +            cache.insert_or_assign(new_path, std::move(file)); +        } else { +            LOG_ERROR(Service_FS, "Failed to open path {} in order to re-cache it", new_path); +        }      } else {          UNREACHABLE();          return nullptr; @@ -214,9 +217,12 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,          }          auto file = cached.lock(); -        file->Open(file_new_path, "r+b");          cache.erase(file_old_path); -        cache.insert_or_assign(std::move(file_new_path), std::move(file)); +        if (file->Open(file_new_path, "r+b")) { +            cache.insert_or_assign(std::move(file_new_path), std::move(file)); +        } else { +            LOG_ERROR(Service_FS, "Failed to open path {} in order to re-cache it", file_new_path); +        }      }      return OpenDirectory(new_path, Mode::ReadWrite); diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 8c1193894..ee7a58b1c 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -21,21 +21,18 @@ public:      std::mutex mutex; -    bool touch_pressed = false; ///< True if touchpad area is currently pressed, otherwise false - -    float touch_x = 0.0f; ///< Touchpad X-position -    float touch_y = 0.0f; ///< Touchpad Y-position +    Input::TouchStatus status;  private:      class Device : public Input::TouchDevice {      public:          explicit Device(std::weak_ptr<TouchState>&& touch_state) : touch_state(touch_state) {} -        std::tuple<float, float, bool> GetStatus() const override { +        Input::TouchStatus GetStatus() const override {              if (auto state = touch_state.lock()) {                  std::lock_guard guard{state->mutex}; -                return std::make_tuple(state->touch_x, state->touch_y, state->touch_pressed); +                return state->status;              } -            return std::make_tuple(0.0f, 0.0f, false); +            return {};          }      private: @@ -79,36 +76,44 @@ std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsi      return std::make_tuple(new_x, new_y);  } -void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { -    if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) +void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id) { +    if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) {          return; +    } +    if (id >= touch_state->status.size()) { +        return; +    }      std::lock_guard guard{touch_state->mutex}; -    touch_state->touch_x = +    const float x =          static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /          static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left); -    touch_state->touch_y = +    const float y =          static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /          static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); -    touch_state->touch_pressed = true; +    touch_state->status[id] = std::make_tuple(x, y, true);  } -void EmuWindow::TouchReleased() { +void EmuWindow::TouchReleased(std::size_t id) { +    if (id >= touch_state->status.size()) { +        return; +    }      std::lock_guard guard{touch_state->mutex}; -    touch_state->touch_pressed = false; -    touch_state->touch_x = 0; -    touch_state->touch_y = 0; +    touch_state->status[id] = std::make_tuple(0.0f, 0.0f, false);  } -void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { -    if (!touch_state->touch_pressed) +void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id) { +    if (id >= touch_state->status.size()) { +        return; +    } +    if (!std::get<2>(touch_state->status[id]))          return;      if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))          std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); -    TouchPressed(framebuffer_x, framebuffer_y); +    TouchPressed(framebuffer_x, framebuffer_y, id);  }  void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) { diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 276d2b906..2436c6580 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -117,18 +117,23 @@ public:       * Signal that a touch pressed event has occurred (e.g. mouse click pressed)       * @param framebuffer_x Framebuffer x-coordinate that was pressed       * @param framebuffer_y Framebuffer y-coordinate that was pressed +     * @param id Touch event ID       */ -    void TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y); +    void TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id); -    /// Signal that a touch released event has occurred (e.g. mouse click released) -    void TouchReleased(); +    /** +     * Signal that a touch released event has occurred (e.g. mouse click released) +     * @param id Touch event ID +     */ +    void TouchReleased(std::size_t id);      /**       * Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window)       * @param framebuffer_x Framebuffer x-coordinate       * @param framebuffer_y Framebuffer y-coordinate +     * @param id Touch event ID       */ -    void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y); +    void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y, std::size_t id);      /**       * Returns currently active configuration. diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index de51a754e..f014dfea3 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h @@ -163,10 +163,11 @@ using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common  using MotionDevice = InputDevice<MotionStatus>;  /** - * A touch status is an object that returns a tuple of two floats and a bool. The floats are - * x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed. + * A touch status is an object that returns an array of 16 tuple elements of two floats and a bool. + * The floats are x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is + * pressed.   */ -using TouchStatus = std::tuple<float, float, bool>; +using TouchStatus = std::array<std::tuple<float, float, bool>, 16>;  /**   * A touch device is an input device that returns a touch status object diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index bb07f6ccc..3ec0e1eca 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -32,9 +32,15 @@  namespace Service::Account { -constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 30}; +constexpr ResultCode ERR_INVALID_USER_ID{ErrorModule::Account, 20}; +constexpr ResultCode ERR_INVALID_APPLICATION_ID{ErrorModule::Account, 22}; +constexpr ResultCode ERR_INVALID_BUFFER{ErrorModule::Account, 30}; +constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 31};  constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100}; +// Thumbnails are hard coded to be at least this size +constexpr std::size_t THUMBNAIL_SIZE = 0x24000; +  static std::string GetImagePath(Common::UUID uuid) {      return Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +             "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; @@ -369,7 +375,7 @@ protected:          if (user_data.size() < sizeof(ProfileData)) {              LOG_ERROR(Service_ACC, "ProfileData buffer too small!");              IPC::ResponseBuilder rb{ctx, 2}; -            rb.Push(ERR_INVALID_BUFFER_SIZE); +            rb.Push(ERR_INVALID_BUFFER);              return;          } @@ -402,7 +408,7 @@ protected:          if (user_data.size() < sizeof(ProfileData)) {              LOG_ERROR(Service_ACC, "ProfileData buffer too small!");              IPC::ResponseBuilder rb{ctx, 2}; -            rb.Push(ERR_INVALID_BUFFER_SIZE); +            rb.Push(ERR_INVALID_BUFFER);              return;          } @@ -811,6 +817,55 @@ void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ct      rb.Push(RESULT_SUCCESS);  } +void Module::Interface::StoreSaveDataThumbnailApplication(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto uuid = rp.PopRaw<Common::UUID>(); + +    LOG_WARNING(Service_ACC, "(STUBBED) called, uuid={}", uuid.Format()); + +    // TODO(ogniK): Check if application ID is zero on acc initialize. As we don't have a reliable +    // way of confirming things like the TID, we're going to assume a non zero value for the time +    // being. +    constexpr u64 tid{1}; +    StoreSaveDataThumbnail(ctx, uuid, tid); +} + +void Module::Interface::StoreSaveDataThumbnailSystem(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto uuid = rp.PopRaw<Common::UUID>(); +    const auto tid = rp.Pop<u64_le>(); + +    LOG_WARNING(Service_ACC, "(STUBBED) called, uuid={}, tid={:016X}", uuid.Format(), tid); +    StoreSaveDataThumbnail(ctx, uuid, tid); +} + +void Module::Interface::StoreSaveDataThumbnail(Kernel::HLERequestContext& ctx, +                                               const Common::UUID& uuid, const u64 tid) { +    IPC::ResponseBuilder rb{ctx, 2}; + +    if (tid == 0) { +        LOG_ERROR(Service_ACC, "TitleID is not valid!"); +        rb.Push(ERR_INVALID_APPLICATION_ID); +        return; +    } + +    if (!uuid) { +        LOG_ERROR(Service_ACC, "User ID is not valid!"); +        rb.Push(ERR_INVALID_USER_ID); +        return; +    } +    const auto thumbnail_size = ctx.GetReadBufferSize(); +    if (thumbnail_size != THUMBNAIL_SIZE) { +        LOG_ERROR(Service_ACC, "Buffer size is empty! size={:X} expecting {:X}", thumbnail_size, +                  THUMBNAIL_SIZE); +        rb.Push(ERR_INVALID_BUFFER_SIZE); +        return; +    } + +    // TODO(ogniK): Construct save data thumbnail +    rb.Push(RESULT_SUCCESS); +} +  void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {      LOG_DEBUG(Service_ACC, "called");      // A u8 is passed into this function which we can safely ignore. It's to determine if we have diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index ab8edc049..0e3ad8ec6 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h @@ -4,6 +4,7 @@  #pragma once +#include "common/uuid.h"  #include "core/hle/service/glue/manager.h"  #include "core/hle/service/service.h" @@ -36,9 +37,13 @@ public:          void ListQualifiedUsers(Kernel::HLERequestContext& ctx);          void LoadOpenContext(Kernel::HLERequestContext& ctx);          void ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx); +        void StoreSaveDataThumbnailApplication(Kernel::HLERequestContext& ctx); +        void StoreSaveDataThumbnailSystem(Kernel::HLERequestContext& ctx);      private:          ResultCode InitializeApplicationInfoBase(); +        void StoreSaveDataThumbnail(Kernel::HLERequestContext& ctx, const Common::UUID& uuid, +                                    const u64 tid);          enum class ApplicationType : u32_le {              GameCard = 0, diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index d2bb8c2c8..49b22583e 100644 --- a/src/core/hle/service/acc/acc_su.cpp +++ b/src/core/hle/service/acc/acc_su.cpp @@ -29,7 +29,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p          {104, nullptr, "GetProfileUpdateNotifier"},          {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+          {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+ -        {110, nullptr, "StoreSaveDataThumbnail"}, +        {110, &ACC_SU::StoreSaveDataThumbnailSystem, "StoreSaveDataThumbnail"},          {111, nullptr, "ClearSaveDataThumbnail"},          {112, nullptr, "LoadSaveDataThumbnail"},          {113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+ diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index 75a24f8f5..8d66d180d 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp @@ -26,7 +26,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p          {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"},          {102, nullptr, "AuthenticateApplicationAsync"},          {103, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+ -        {110, nullptr, "StoreSaveDataThumbnail"}, +        {110, &ACC_U0::StoreSaveDataThumbnailApplication, "StoreSaveDataThumbnail"},          {111, nullptr, "ClearSaveDataThumbnail"},          {120, nullptr, "CreateGuestLoginRequest"},          {130, &ACC_U0::LoadOpenContext, "LoadOpenContext"}, // 5.0.0+ diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp index a4aa5316a..951081cd0 100644 --- a/src/core/hle/service/acc/acc_u1.cpp +++ b/src/core/hle/service/acc/acc_u1.cpp @@ -29,7 +29,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p          {104, nullptr, "GetProfileUpdateNotifier"},          {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+          {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+ -        {110, nullptr, "StoreSaveDataThumbnail"}, +        {110, &ACC_U1::StoreSaveDataThumbnailApplication, "StoreSaveDataThumbnail"},          {111, nullptr, "ClearSaveDataThumbnail"},          {112, nullptr, "LoadSaveDataThumbnail"},          {113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+ diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index c9808060a..1743bcb2b 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -856,7 +856,7 @@ public:              {25, nullptr, "Terminate"},              {30, &ILibraryAppletAccessor::GetResult, "GetResult"},              {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, -            {60, nullptr, "PresetLibraryAppletGpuTimeSliceZero"}, +            {60, &ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero, "PresetLibraryAppletGpuTimeSliceZero"},              {100, &ILibraryAppletAccessor::PushInData, "PushInData"},              {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},              {102, nullptr, "PushExtraStorage"}, @@ -900,6 +900,13 @@ private:          rb.Push(applet->GetStatus());      } +    void PresetLibraryAppletGpuTimeSliceZero(Kernel::HLERequestContext& ctx) { +        LOG_WARNING(Service_AM, "(STUBBED) called"); + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } +      void Start(Kernel::HLERequestContext& ctx) {          LOG_DEBUG(Service_AM, "called"); diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 0df395e85..5219f2dad 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -2,6 +2,7 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. +#include <algorithm>  #include <cstring>  #include "common/common_types.h"  #include "core/core_timing.h" @@ -16,7 +17,13 @@ constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;  Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(system) {}  Controller_Touchscreen::~Controller_Touchscreen() = default; -void Controller_Touchscreen::OnInit() {} +void Controller_Touchscreen::OnInit() { +    for (std::size_t id = 0; id < MAX_FINGERS; ++id) { +        mouse_finger_id[id] = MAX_FINGERS; +        keyboard_finger_id[id] = MAX_FINGERS; +        udp_finger_id[id] = MAX_FINGERS; +    } +}  void Controller_Touchscreen::OnRelease() {} @@ -40,38 +47,106 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin      cur_entry.sampling_number = last_entry.sampling_number + 1;      cur_entry.sampling_number2 = cur_entry.sampling_number; -    bool pressed = false; -    float x, y; -    std::tie(x, y, pressed) = touch_device->GetStatus(); -    auto& touch_entry = cur_entry.states[0]; -    touch_entry.attribute.raw = 0; -    if (!pressed && touch_btn_device) { -        std::tie(x, y, pressed) = touch_btn_device->GetStatus(); +    const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); +    const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); +    for (std::size_t id = 0; id < mouse_status.size(); ++id) { +        mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); +        udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]);      } -    if (pressed && Settings::values.touchscreen.enabled) { -        touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width); -        touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height); -        touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; -        touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; -        touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; -        const u64 tick = core_timing.GetCPUTicks(); -        touch_entry.delta_time = tick - last_touch; -        last_touch = tick; -        touch_entry.finger = Settings::values.touchscreen.finger; -        cur_entry.entry_count = 1; -    } else { -        cur_entry.entry_count = 0; + +    if (Settings::values.use_touch_from_button) { +        const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); +        for (std::size_t id = 0; id < mouse_status.size(); ++id) { +            keyboard_finger_id[id] = +                UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); +        }      } +    std::array<Finger, 16> active_fingers; +    const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), +                                       [](const auto& finger) { return finger.pressed; }); +    const auto active_fingers_count = +        static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); + +    const u64 tick = core_timing.GetCPUTicks(); +    cur_entry.entry_count = static_cast<s32_le>(active_fingers_count); +    for (std::size_t id = 0; id < MAX_FINGERS; ++id) { +        auto& touch_entry = cur_entry.states[id]; +        if (id < active_fingers_count) { +            touch_entry.x = static_cast<u16>(active_fingers[id].x * Layout::ScreenUndocked::Width); +            touch_entry.y = static_cast<u16>(active_fingers[id].y * Layout::ScreenUndocked::Height); +            touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; +            touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; +            touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; +            touch_entry.delta_time = tick - active_fingers[id].last_touch; +            fingers[active_fingers[id].id].last_touch = tick; +            touch_entry.finger = active_fingers[id].id; +            touch_entry.attribute.raw = active_fingers[id].attribute.raw; +        } else { +            // Clear touch entry +            touch_entry.attribute.raw = 0; +            touch_entry.x = 0; +            touch_entry.y = 0; +            touch_entry.diameter_x = 0; +            touch_entry.diameter_y = 0; +            touch_entry.rotation_angle = 0; +            touch_entry.delta_time = 0; +            touch_entry.finger = 0; +        } +    }      std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory));  }  void Controller_Touchscreen::OnLoadInputDevices() { -    touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touchscreen.device); -    if (Settings::values.use_touch_from_button) { -        touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button"); -    } else { -        touch_btn_device.reset(); +    touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); +    touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); +    touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button"); +} + +std::optional<std::size_t> Controller_Touchscreen::GetUnusedFingerID() const { +    std::size_t first_free_id = 0; +    while (first_free_id < MAX_FINGERS) { +        if (!fingers[first_free_id].pressed) { +            return first_free_id; +        } else { +            first_free_id++; +        } +    } +    return std::nullopt; +} + +std::size_t Controller_Touchscreen::UpdateTouchInputEvent( +    const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) { +    const auto& [x, y, pressed] = touch_input; +    if (pressed) { +        Attributes attribute{}; +        if (finger_id == MAX_FINGERS) { +            const auto first_free_id = GetUnusedFingerID(); +            if (!first_free_id) { +                // Invalid finger id do nothing +                return MAX_FINGERS; +            } +            finger_id = first_free_id.value(); +            fingers[finger_id].pressed = true; +            fingers[finger_id].id = static_cast<u32_le>(finger_id); +            attribute.start_touch.Assign(1); +        } +        fingers[finger_id].x = x; +        fingers[finger_id].y = y; +        fingers[finger_id].attribute = attribute; +        return finger_id;      } + +    if (finger_id != MAX_FINGERS) { +        if (!fingers[finger_id].attribute.end_touch) { +            fingers[finger_id].attribute.end_touch.Assign(1); +            fingers[finger_id].attribute.start_touch.Assign(0); +            return finger_id; +        } +        fingers[finger_id].pressed = false; +    } + +    return MAX_FINGERS;  } +  } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 4d9042adc..784124e25 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -30,6 +30,18 @@ public:      void OnLoadInputDevices() override;  private: +    static constexpr std::size_t MAX_FINGERS = 16; + +    // Returns an unused finger id, if there is no fingers available std::nullopt will be returned +    std::optional<std::size_t> GetUnusedFingerID() const; + +    // If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no +    // changes will be made. Updates the coordinates if the finger id it's already set. If the touch +    // ends delays the output by one frame to set the end_touch flag before finally freeing the +    // finger id +    std::size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input, +                                      std::size_t finger_id); +      struct Attributes {          union {              u32 raw{}; @@ -55,7 +67,7 @@ private:          s64_le sampling_number;          s64_le sampling_number2;          s32_le entry_count; -        std::array<TouchState, 16> states; +        std::array<TouchState, MAX_FINGERS> states;      };      static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size"); @@ -66,9 +78,23 @@ private:      };      static_assert(sizeof(TouchScreenSharedMemory) == 0x3000,                    "TouchScreenSharedMemory is an invalid size"); + +    struct Finger { +        u64_le last_touch{}; +        float x{}; +        float y{}; +        u32_le id{}; +        bool pressed{}; +        Attributes attribute; +    }; +      TouchScreenSharedMemory shared_memory{}; -    std::unique_ptr<Input::TouchDevice> touch_device; +    std::unique_ptr<Input::TouchDevice> touch_mouse_device; +    std::unique_ptr<Input::TouchDevice> touch_udp_device;      std::unique_ptr<Input::TouchDevice> touch_btn_device; -    s64_le last_touch{}; +    std::array<std::size_t, MAX_FINGERS> mouse_finger_id; +    std::array<std::size_t, MAX_FINGERS> keyboard_finger_id; +    std::array<std::size_t, MAX_FINGERS> udp_finger_id; +    std::array<Finger, MAX_FINGERS> fingers;  };  } // namespace Service::HID diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp index 6ad3a2877..f4490f3d9 100644 --- a/src/core/hle/service/lbl/lbl.cpp +++ b/src/core/hle/service/lbl/lbl.cpp @@ -20,30 +20,30 @@ public:          static const FunctionInfo functions[] = {              {0, nullptr, "SaveCurrentSetting"},              {1, nullptr, "LoadCurrentSetting"}, -            {2, nullptr, "SetCurrentBrightnessSetting"}, -            {3, nullptr, "GetCurrentBrightnessSetting"}, +            {2, &LBL::SetCurrentBrightnessSetting, "SetCurrentBrightnessSetting"}, +            {3, &LBL::GetCurrentBrightnessSetting, "GetCurrentBrightnessSetting"},              {4, nullptr, "ApplyCurrentBrightnessSettingToBacklight"},              {5, nullptr, "GetBrightnessSettingAppliedToBacklight"}, -            {6, nullptr, "SwitchBacklightOn"}, -            {7, nullptr, "SwitchBacklightOff"}, -            {8, nullptr, "GetBacklightSwitchStatus"}, -            {9, nullptr, "EnableDimming"}, -            {10, nullptr, "DisableDimming"}, -            {11, nullptr, "IsDimmingEnabled"}, -            {12, nullptr, "EnableAutoBrightnessControl"}, -            {13, nullptr, "DisableAutoBrightnessControl"}, -            {14, nullptr, "IsAutoBrightnessControlEnabled"}, -            {15, nullptr, "SetAmbientLightSensorValue"}, -            {16, nullptr, "GetAmbientLightSensorValue"}, -            {17, nullptr, "SetBrightnessReflectionDelayLevel"}, -            {18, nullptr, "GetBrightnessReflectionDelayLevel"}, -            {19, nullptr, "SetCurrentBrightnessMapping"}, -            {20, nullptr, "GetCurrentBrightnessMapping"}, -            {21, nullptr, "SetCurrentAmbientLightSensorMapping"}, -            {22, nullptr, "GetCurrentAmbientLightSensorMapping"}, -            {23, nullptr, "IsAmbientLightSensorAvailable"}, -            {24, nullptr, "SetCurrentBrightnessSettingForVrMode"}, -            {25, nullptr, "GetCurrentBrightnessSettingForVrMode"}, +            {6, &LBL::SwitchBacklightOn, "SwitchBacklightOn"}, +            {7, &LBL::SwitchBacklightOff, "SwitchBacklightOff"}, +            {8, &LBL::GetBacklightSwitchStatus, "GetBacklightSwitchStatus"}, +            {9, &LBL::EnableDimming, "EnableDimming"}, +            {10, &LBL::DisableDimming, "DisableDimming"}, +            {11, &LBL::IsDimmingEnabled, "IsDimmingEnabled"}, +            {12, &LBL::EnableAutoBrightnessControl, "EnableAutoBrightnessControl"}, +            {13, &LBL::DisableAutoBrightnessControl, "DisableAutoBrightnessControl"}, +            {14, &LBL::IsAutoBrightnessControlEnabled, "IsAutoBrightnessControlEnabled"}, +            {15, &LBL::SetAmbientLightSensorValue, "SetAmbientLightSensorValue"}, +            {16, &LBL::GetAmbientLightSensorValue, "GetAmbientLightSensorValue"}, +            {17, &LBL::SetBrightnessReflectionDelayLevel, "SetBrightnessReflectionDelayLevel"}, +            {18, &LBL::GetBrightnessReflectionDelayLevel, "GetBrightnessReflectionDelayLevel"}, +            {19, &LBL::SetCurrentBrightnessMapping, "SetCurrentBrightnessMapping"}, +            {20, &LBL::GetCurrentBrightnessMapping, "GetCurrentBrightnessMapping"}, +            {21, &LBL::SetCurrentAmbientLightSensorMapping, "SetCurrentAmbientLightSensorMapping"}, +            {22, &LBL::GetCurrentAmbientLightSensorMapping, "GetCurrentAmbientLightSensorMapping"}, +            {23, &LBL::IsAmbientLightSensorAvailable, "IsAmbientLightSensorAvailable"}, +            {24, &LBL::SetCurrentBrightnessSettingForVrMode, "SetCurrentBrightnessSettingForVrMode"}, +            {25, &LBL::GetCurrentBrightnessSettingForVrMode, "GetCurrentBrightnessSettingForVrMode"},              {26, &LBL::EnableVrMode, "EnableVrMode"},              {27, &LBL::DisableVrMode, "DisableVrMode"},              {28, &LBL::IsVrModeEnabled, "IsVrModeEnabled"}, @@ -55,6 +55,237 @@ public:      }  private: +    enum class BacklightSwitchStatus : u32 { +        Off = 0, +        On = 1, +    }; + +    void SetCurrentBrightnessSetting(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        auto brightness = rp.Pop<float>(); + +        if (!std::isfinite(brightness)) { +            LOG_ERROR(Service_LBL, "Brightness is infinite!"); +            brightness = 0.0f; +        } + +        LOG_DEBUG(Service_LBL, "called brightness={}", brightness); + +        current_brightness = brightness; +        update_instantly = true; + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void GetCurrentBrightnessSetting(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        auto brightness = current_brightness; +        if (!std::isfinite(brightness)) { +            LOG_ERROR(Service_LBL, "Brightness is infinite!"); +            brightness = 0.0f; +        } + +        LOG_DEBUG(Service_LBL, "called brightness={}", brightness); + +        IPC::ResponseBuilder rb{ctx, 3}; +        rb.Push(RESULT_SUCCESS); +        rb.Push(brightness); +    } + +    void SwitchBacklightOn(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        const auto fade_time = rp.Pop<u64_le>(); +        LOG_WARNING(Service_LBL, "(STUBBED) called, fade_time={}", fade_time); + +        backlight_enabled = true; + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void SwitchBacklightOff(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        const auto fade_time = rp.Pop<u64_le>(); +        LOG_WARNING(Service_LBL, "(STUBBED) called, fade_time={}", fade_time); + +        backlight_enabled = false; + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void GetBacklightSwitchStatus(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_LBL, "called"); + +        IPC::ResponseBuilder rb{ctx, 3}; +        rb.Push(RESULT_SUCCESS); +        rb.PushEnum<BacklightSwitchStatus>(backlight_enabled ? BacklightSwitchStatus::On +                                                             : BacklightSwitchStatus::Off); +    } + +    void EnableDimming(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_LBL, "called"); + +        dimming = true; + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void DisableDimming(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_LBL, "called"); + +        dimming = false; + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void IsDimmingEnabled(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_LBL, "called"); + +        IPC::ResponseBuilder rb{ctx, 3}; +        rb.Push(RESULT_SUCCESS); +        rb.Push(dimming); +    } + +    void EnableAutoBrightnessControl(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_LBL, "called"); +        auto_brightness = true; +        update_instantly = true; + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void DisableAutoBrightnessControl(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_LBL, "called"); +        auto_brightness = false; + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void IsAutoBrightnessControlEnabled(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_LBL, "called"); + +        IPC::ResponseBuilder rb{ctx, 3}; +        rb.Push(RESULT_SUCCESS); +        rb.Push(auto_brightness); +    } + +    void SetAmbientLightSensorValue(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        const auto light_value = rp.Pop<float>(); + +        LOG_DEBUG(Service_LBL, "called light_value={}", light_value); + +        ambient_light_value = light_value; + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void GetAmbientLightSensorValue(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_LBL, "called"); + +        IPC::ResponseBuilder rb{ctx, 3}; +        rb.Push(RESULT_SUCCESS); +        rb.Push(ambient_light_value); +    } + +    void SetBrightnessReflectionDelayLevel(Kernel::HLERequestContext& ctx) { +        // This is Intentional, this function does absolutely nothing +        LOG_DEBUG(Service_LBL, "called"); + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void GetBrightnessReflectionDelayLevel(Kernel::HLERequestContext& ctx) { +        // This is intentional, the function is hard coded to return 0.0f on hardware +        LOG_DEBUG(Service_LBL, "called"); + +        IPC::ResponseBuilder rb{ctx, 3}; +        rb.Push(RESULT_SUCCESS); +        rb.Push(0.0f); +    } + +    void SetCurrentBrightnessMapping(Kernel::HLERequestContext& ctx) { +        // This is Intentional, this function does absolutely nothing +        LOG_DEBUG(Service_LBL, "called"); + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void GetCurrentBrightnessMapping(Kernel::HLERequestContext& ctx) { +        // This is Intentional, this function does absolutely nothing +        LOG_DEBUG(Service_LBL, "called"); + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +        // This function is suppose to return something but it seems like it doesn't +    } + +    void SetCurrentAmbientLightSensorMapping(Kernel::HLERequestContext& ctx) { +        // This is Intentional, this function does absolutely nothing +        LOG_DEBUG(Service_LBL, "called"); + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void GetCurrentAmbientLightSensorMapping(Kernel::HLERequestContext& ctx) { +        // This is Intentional, this function does absolutely nothing +        LOG_DEBUG(Service_LBL, "called"); + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +        // This function is suppose to return something but it seems like it doesn't +    } + +    void IsAmbientLightSensorAvailable(Kernel::HLERequestContext& ctx) { +        LOG_WARNING(Service_LBL, "(STUBBED) called"); +        IPC::ResponseBuilder rb{ctx, 3}; +        rb.Push(RESULT_SUCCESS); +        // TODO(ogniK): Only return true if there's no device error +        rb.Push(true); +    } + +    void SetCurrentBrightnessSettingForVrMode(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        auto brightness = rp.Pop<float>(); + +        if (!std::isfinite(brightness)) { +            LOG_ERROR(Service_LBL, "Brightness is infinite!"); +            brightness = 0.0f; +        } + +        LOG_DEBUG(Service_LBL, "called brightness={}", brightness); + +        current_vr_brightness = brightness; + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void GetCurrentBrightnessSettingForVrMode(Kernel::HLERequestContext& ctx) { +        IPC::RequestParser rp{ctx}; +        auto brightness = current_vr_brightness; +        if (!std::isfinite(brightness)) { +            LOG_ERROR(Service_LBL, "Brightness is infinite!"); +            brightness = 0.0f; +        } + +        LOG_DEBUG(Service_LBL, "called brightness={}", brightness); + +        IPC::ResponseBuilder rb{ctx, 3}; +        rb.Push(RESULT_SUCCESS); +        rb.Push(brightness); +    } +      void EnableVrMode(Kernel::HLERequestContext& ctx) {          LOG_DEBUG(Service_LBL, "called"); @@ -82,6 +313,14 @@ private:      }      bool vr_mode_enabled = false; +    float current_brightness = 1.0f; +    float backlight_brightness = 1.0f; +    float ambient_light_value = 0.0f; +    float current_vr_brightness = 1.0f; +    bool dimming = true; +    bool backlight_enabled = true; +    bool update_instantly = false; +    bool auto_brightness = false; // TODO(ogniK): Move to system settings  };  void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index fea3b7b9f..060599bab 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -155,7 +155,13 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::ve          return NvResult::BadParameter;      }      if (events_interface.registered[event_id]) { -        return NvResult::BadParameter; +        const auto event_state = events_interface.status[event_id]; +        if (event_state != EventState::Free) { +            LOG_WARNING(Service_NVDRV, "Event already registered! Unregistering previous event"); +            events_interface.UnregisterEvent(event_id); +        } else { +            return NvResult::BadParameter; +        }      }      events_interface.RegisterEvent(event_id);      return NvResult::Success;  | 
