|
|
|
@ -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; |
|
|
|
}; |
|
|
|
|