summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/nvdrv/core/syncpoint_manager.h
blob: da456f206262687f30f9e4b918c179b05a1db1a7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// 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"

namespace Tegra {

namespace Host1x {
class Host1x;
} // namespace Host1x

} // namespace Tegra

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();

    /**
     * @brief Checks if the given syncpoint is both allocated and below the number of HW syncpoints
     */
    bool IsSyncpointAllocated(u32 id);

    /**
     * @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);

    bool IsFenceSignalled(NvFence fence) {
        return HasSyncpointExpired(fence.id, fence.value);
    }

    /**
     * @brief Atomically increments the maximum value of a syncpoint by the given amount
     * @return The new max value of the syncpoint
     */
    u32 IncrementSyncpointMaxExt(u32 id, u32 amount);

    /**
     * @return The minimum value of the syncpoint
     */
    u32 ReadSyncpointMinValue(u32 id);

    /**
     * @brief Synchronises the minimum value of the syncpoint to with the GPU
     * @return The new minimum value of the syncpoint
     */
    u32 UpdateMin(u32 id);

    /**
     * @brief Frees the usage of a syncpoint.
     */
    void FreeSyncpoint(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:
    /**
     * @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
    };

    constexpr static std::size_t SyncpointCount{192};
    std::array<SyncpointInfo, SyncpointCount> syncpoints{};
    std::mutex reservation_lock;

    Tegra::Host1x::Host1x& host1x;
};

} // namespace Service::Nvidia::NvCore