|
|
@@ -1,10 +1,13 @@
|
|
|
-// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
|
|
-// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
+// SPDX-FileCopyrightText: 2022 yuzu emulator team and Skyline Team and Contributors
|
|
|
+// (https://github.com/skyline-emu/)
|
|
|
+// SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3
|
|
|
+// or any later version Refer to the license.txt file included.
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
#include <array>
|
|
|
#include <atomic>
|
|
|
+#include <mutex>
|
|
|
|
|
|
#include "common/common_types.h"
|
|
|
#include "core/hle/service/nvdrv/nvdata.h"
|
|
|
@@ -19,68 +22,111 @@ class Host1x;
|
|
|
|
|
|
namespace Service::Nvidia::NvCore {
|
|
|
|
|
|
+enum class ChannelType : u32 {
|
|
|
+ MsEnc = 0,
|
|
|
+ VIC = 1,
|
|
|
+ GPU = 2,
|
|
|
+ NvDec = 3,
|
|
|
+ Display = 4,
|
|
|
+ NvJpg = 5,
|
|
|
+ TSec = 6,
|
|
|
+ Max = 7
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * @brief SyncpointManager handles allocating and accessing host1x syncpoints, these are cached
|
|
|
+ * versions of the HW syncpoints which are intermittently synced
|
|
|
+ * @note Refer to Chapter 14 of the Tegra X1 TRM for an exhaustive overview of them
|
|
|
+ * @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 SyncpointManager final {
|
|
|
public:
|
|
|
explicit SyncpointManager(Tegra::Host1x::Host1x& host1x);
|
|
|
~SyncpointManager();
|
|
|
|
|
|
/**
|
|
|
- * Returns true if the specified syncpoint is expired for the given value.
|
|
|
- * @param syncpoint_id Syncpoint ID to check.
|
|
|
- * @param value Value to check against the specified syncpoint.
|
|
|
- * @returns True if the specified syncpoint is expired for the given value, otherwise False.
|
|
|
+ * @brief Checks if the given syncpoint is both allocated and below the number of HW syncpoints
|
|
|
*/
|
|
|
- bool IsSyncpointExpired(u32 syncpoint_id, u32 value) const {
|
|
|
- return (GetSyncpointMax(syncpoint_id) - value) >= (GetSyncpointMin(syncpoint_id) - value);
|
|
|
- }
|
|
|
+ bool IsSyncpointAllocated(u32 id);
|
|
|
|
|
|
/**
|
|
|
- * Gets the lower bound for the specified syncpoint.
|
|
|
- * @param syncpoint_id Syncpoint ID to get the lower bound for.
|
|
|
- * @returns The lower bound for the specified syncpoint.
|
|
|
+ * @brief Finds a free syncpoint and reserves it
|
|
|
+ * @return The ID of the reserved syncpoint
|
|
|
*/
|
|
|
- u32 GetSyncpointMin(u32 syncpoint_id) const {
|
|
|
- return syncpoints.at(syncpoint_id).min.load(std::memory_order_relaxed);
|
|
|
- }
|
|
|
+ u32 AllocateSyncpoint(bool clientManaged);
|
|
|
|
|
|
/**
|
|
|
- * Gets the uper bound for the specified syncpoint.
|
|
|
- * @param syncpoint_id Syncpoint ID to get the upper bound for.
|
|
|
- * @returns The upper bound for the specified syncpoint.
|
|
|
+ * @url
|
|
|
+ * https://github.com/Jetson-TX1-AndroidTV/android_kernel_jetson_tx1_hdmi_primary/blob/8f74a72394efb871cb3f886a3de2998cd7ff2990/drivers/gpu/host1x/syncpt.c#L259
|
|
|
*/
|
|
|
- u32 GetSyncpointMax(u32 syncpoint_id) const {
|
|
|
- return syncpoints.at(syncpoint_id).max.load(std::memory_order_relaxed);
|
|
|
+ bool HasSyncpointExpired(u32 id, u32 threshold);
|
|
|
+
|
|
|
+ bool IsFenceSignalled(NvFence fence) {
|
|
|
+ return HasSyncpointExpired(fence.id, fence.value);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Refreshes the minimum value for the specified syncpoint.
|
|
|
- * @param syncpoint_id Syncpoint ID to be refreshed.
|
|
|
- * @returns The new syncpoint minimum value.
|
|
|
+ * @brief Atomically increments the maximum value of a syncpoint by the given amount
|
|
|
+ * @return The new max value of the syncpoint
|
|
|
*/
|
|
|
- u32 RefreshSyncpoint(u32 syncpoint_id);
|
|
|
+ u32 IncrementSyncpointMaxExt(u32 id, u32 amount);
|
|
|
|
|
|
/**
|
|
|
- * Allocates a new syncoint.
|
|
|
- * @returns The syncpoint ID for the newly allocated syncpoint.
|
|
|
+ * @return The minimum value of the syncpoint
|
|
|
*/
|
|
|
- u32 AllocateSyncpoint();
|
|
|
+ u32 ReadSyncpointMinValue(u32 id);
|
|
|
|
|
|
/**
|
|
|
- * Increases the maximum value for the specified syncpoint.
|
|
|
- * @param syncpoint_id Syncpoint ID to be increased.
|
|
|
- * @param value Value to increase the specified syncpoint by.
|
|
|
- * @returns The new syncpoint maximum value.
|
|
|
+ * @brief Synchronises the minimum value of the syncpoint to with the GPU
|
|
|
+ * @return The new minimum value of the syncpoint
|
|
|
*/
|
|
|
- u32 IncreaseSyncpoint(u32 syncpoint_id, u32 value);
|
|
|
+ u32 UpdateMin(u32 id);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @return A fence that will be signalled once this syncpoint hits its maximum value
|
|
|
+ */
|
|
|
+ NvFence GetSyncpointFence(u32 id);
|
|
|
+
|
|
|
+ static constexpr std::array<u32, static_cast<u32>(ChannelType::Max)> channel_syncpoints{
|
|
|
+ 0x0, // `MsEnc` is unimplemented
|
|
|
+ 0xC, // `VIC`
|
|
|
+ 0x0, // `GPU` syncpoints are allocated per-channel instead
|
|
|
+ 0x36, // `NvDec`
|
|
|
+ 0x0, // `Display` is unimplemented
|
|
|
+ 0x37, // `NvJpg`
|
|
|
+ 0x0, // `TSec` is unimplemented
|
|
|
+ }; //!< Maps each channel ID to a constant syncpoint
|
|
|
|
|
|
private:
|
|
|
- struct Syncpoint {
|
|
|
- std::atomic<u32> min;
|
|
|
- std::atomic<u32> max;
|
|
|
- std::atomic<bool> is_allocated;
|
|
|
+ /**
|
|
|
+ * @note reservation_lock should be locked when calling this
|
|
|
+ */
|
|
|
+ u32 ReserveSyncpoint(u32 id, bool clientManaged);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @return The ID of the first free syncpoint
|
|
|
+ */
|
|
|
+ u32 FindFreeSyncpoint();
|
|
|
+
|
|
|
+ struct SyncpointInfo {
|
|
|
+ std::atomic<u32> counterMin; //!< The least value the syncpoint can be (The value it was
|
|
|
+ //!< when it was last synchronized with host1x)
|
|
|
+ std::atomic<u32> counterMax; //!< The maximum value the syncpoint can reach according to the
|
|
|
+ //!< current usage
|
|
|
+ bool interfaceManaged; //!< If the syncpoint is managed by a host1x client interface, a
|
|
|
+ //!< client interface is a HW block that can handle host1x
|
|
|
+ //!< transactions on behalf of a host1x client (Which would otherwise
|
|
|
+ //!< need to be manually synced using PIO which is synchronous and
|
|
|
+ //!< requires direct cooperation of the CPU)
|
|
|
+ bool reserved; //!< If the syncpoint is reserved or not, not to be confused with a reserved
|
|
|
+ //!< value
|
|
|
};
|
|
|
|
|
|
- std::array<Syncpoint, MaxSyncPoints> syncpoints{};
|
|
|
+ constexpr static std::size_t SyncpointCount{192};
|
|
|
+ std::array<SyncpointInfo, SyncpointCount> syncpoints{};
|
|
|
+ std::mutex reservation_lock;
|
|
|
|
|
|
Tegra::Host1x::Host1x& host1x;
|
|
|
};
|