diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index b4c29c98..de9f64b2 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -105,6 +105,7 @@ add_library(skyline SHARED ${source_DIR}/skyline/services/nvdrv/devices/nvhost_ctrl.cpp ${source_DIR}/skyline/services/nvdrv/devices/nvhost_channel.cpp ${source_DIR}/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp + ${source_DIR}/skyline/services/nvdrv/devices/nvhost_syncpoint.cpp ${source_DIR}/skyline/services/hosbinder/IHOSBinderDriver.cpp ${source_DIR}/skyline/services/visrv/IDisplayService.cpp ${source_DIR}/skyline/services/visrv/IApplicationDisplayService.cpp diff --git a/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.cpp b/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.cpp index 21f3b819..2ffe6d1f 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.cpp @@ -54,7 +54,7 @@ namespace skyline::service::nvdrv { return fdIndex++; } - INvDrvServices::INvDrvServices(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::nvdrv_INvDrvServices, "INvDrvServices", { + INvDrvServices::INvDrvServices(const DeviceState &state, ServiceManager &manager) : hostSyncpoint(state), BaseService(state, manager, Service::nvdrv_INvDrvServices, "INvDrvServices", { {0x0, SFUNC(INvDrvServices::Open)}, {0x1, SFUNC(INvDrvServices::Ioctl)}, {0x2, SFUNC(INvDrvServices::Close)}, diff --git a/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.h b/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.h index 299de948..e1cbb01c 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.h +++ b/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.h @@ -8,6 +8,7 @@ #include #include #include "devices/nvdevice.h" +#include "devices/nvhost_syncpoint.h" namespace skyline::service::nvdrv { /** @@ -43,6 +44,8 @@ namespace skyline::service::nvdrv { } public: + NvHostSyncpoint hostSyncpoint; + /** * @brief Returns a particular device with a specific type * @tparam objectClass The class of the device to return diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvfence.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvfence.h new file mode 100644 index 00000000..e421ac14 --- /dev/null +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvfence.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include "nvhost_syncpoint.h" + +namespace skyline::service::nvdrv::device { + /** + * @brief This holds information about a fence + */ + struct NvFence { + u32 id{}; + u32 value{}; + + /** + * @brief Synchronizes the fence's value with its underlying syncpoint + */ + static inline void UpdateValue(const NvHostSyncpoint &hostSyncpoint) { + //TODO: Implement this + } + }; + static_assert(sizeof(NvFence) == 0x8); +} diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_syncpoint.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_syncpoint.cpp new file mode 100644 index 00000000..a5be5c3e --- /dev/null +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_syncpoint.cpp @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include "nvhost_syncpoint.h" + +namespace skyline::service::nvdrv { + NvHostSyncpoint::NvHostSyncpoint(const DeviceState &state) : state(state) { + constexpr u32 VBlank0SyncpointId{26}; + constexpr u32 VBlank1SyncpointId{27}; + + // Reserve both vblank syncpoints as client managed since the userspace driver has direct access to them + ReserveSyncpoint(VBlank0SyncpointId, true); + ReserveSyncpoint(VBlank1SyncpointId, true); + } + + u32 NvHostSyncpoint::ReserveSyncpoint(u32 id, bool clientManaged) { + if (id >= constant::MaxHwSyncpointCount) + throw exception("Requested syncpoint ID is too high"); + + if (syncpoints.at(id).assigned) + throw exception("Requested syncpoint is in use"); + + syncpoints.at(id).assigned = true; + syncpoints.at(id).clientManaged = clientManaged; + + return id; + } + + u32 NvHostSyncpoint::FindFreeSyncpoint() { + for (u32 i = 0; i < constant::MaxHwSyncpointCount; i++) + if (!syncpoints[i].assigned) + return i; + + throw exception("Failed to find a free syncpoint!"); + } + + u32 NvHostSyncpoint::AllocateSyncpoint(bool clientManaged) { + std::lock_guard lock(reservationLock); + return ReserveSyncpoint(FindFreeSyncpoint(), clientManaged); + } + + bool NvHostSyncpoint::HasSyncpointExpired(u32 id, u32 threshold) { + const SyncpointInfo &syncpoint = syncpoints.at(id); + + if (syncpoint.clientManaged) + return static_cast(syncpoint.counterMin - threshold) >= 0; + else + return (syncpoint.counterMax - threshold) >= (syncpoint.counterMin - threshold); + } + + u32 NvHostSyncpoint::IncrementSyncpointMaxExt(u32 id, u32 amount) { + return syncpoints.at(id).counterMax += amount; + } +} diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_syncpoint.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_syncpoint.h new file mode 100644 index 00000000..43426056 --- /dev/null +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_syncpoint.h @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include + +namespace skyline { + namespace constant { + constexpr size_t MaxHwSyncpointCount = 192; + } + + namespace service::nvdrv { + /** + * @todo Implement the GPU side of this + * @brief NvHostSyncpoint handles allocating and accessing host1x syncpoints + * @url https://http.download.nvidia.com/tegra-public-appnotes/host1x.html + * @url https://github.com/Jetson-TX1-AndroidTV/android_kernel_jetson_tx1_hdmi_primary/blob/jetson-tx1/drivers/video/tegra/host/nvhost_syncpt.c + */ + class NvHostSyncpoint { + private: + /** + * @brief This holds information about a single syncpoint + */ + struct SyncpointInfo { + std::atomic counterMin; + std::atomic counterMax; + bool clientManaged; + bool assigned; + }; + + const DeviceState &state; + std::array syncpoints{}; + Mutex reservationLock; + + /** + * @note reservationLock should be locked when calling this + */ + u32 ReserveSyncpoint(u32 id, bool clientManaged); + + /** + * @return The ID of the first free syncpoint + */ + u32 FindFreeSyncpoint(); + + public: + NvHostSyncpoint(const DeviceState &state); + + /** + * @brief Finds a free syncpoint and reserves it + * @return The ID of the reserved syncpoint + */ + u32 AllocateSyncpoint(bool clientManaged); + + /** + * @url https://github.com/Jetson-TX1-AndroidTV/android_kernel_jetson_tx1_hdmi_primary/blob/8f74a72394efb871cb3f886a3de2998cd7ff2990/drivers/gpu/host1x/syncpt.c#L259 + */ + bool HasSyncpointExpired(u32 id, u32 threshold); + + /** + * @brief Atomically increments the maximum value of a syncpoint by the given amount + * @return The new value of the syncpoint + */ + u32 IncrementSyncpointMaxExt(u32 id, u32 amount); + }; + } +}