summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp
blob: b34481b486bd7e90e5e23b26b507546a7690d52e (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
// 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.

#include "common/assert.h"
#include "core/hle/service/nvdrv/core/syncpoint_manager.h"
#include "video_core/host1x/host1x.h"

namespace Service::Nvidia::NvCore {

SyncpointManager::SyncpointManager(Tegra::Host1x::Host1x& host1x_) : host1x{host1x_} {
    constexpr u32 VBlank0SyncpointId{26};
    constexpr u32 VBlank1SyncpointId{27};

    // Reserve both vblank syncpoints as client managed as they use Continuous Mode
    // Refer to section 14.3.5.3 of the TRM for more information on Continuous Mode
    // https://github.com/Jetson-TX1-AndroidTV/android_kernel_jetson_tx1_hdmi_primary/blob/8f74a72394efb871cb3f886a3de2998cd7ff2990/drivers/gpu/host1x/drm/dc.c#L660
    ReserveSyncpoint(VBlank0SyncpointId, true);
    ReserveSyncpoint(VBlank1SyncpointId, true);

    for (u32 syncpointId : channel_syncpoints) {
        if (syncpointId) {
            ReserveSyncpoint(syncpointId, false);
        }
    }
}

SyncpointManager::~SyncpointManager() = default;

u32 SyncpointManager::ReserveSyncpoint(u32 id, bool clientManaged) {
    if (syncpoints.at(id).reserved) {
        UNREACHABLE_MSG("Requested syncpoint is in use");
        return 0;
    }

    syncpoints.at(id).reserved = true;
    syncpoints.at(id).interfaceManaged = clientManaged;

    return id;
}

u32 SyncpointManager::FindFreeSyncpoint() {
    for (u32 i{1}; i < syncpoints.size(); i++) {
        if (!syncpoints[i].reserved) {
            return i;
        }
    }
    UNREACHABLE_MSG("Failed to find a free syncpoint!");
    return 0;
}

u32 SyncpointManager::AllocateSyncpoint(bool clientManaged) {
    std::lock_guard lock(reservation_lock);
    return ReserveSyncpoint(FindFreeSyncpoint(), clientManaged);
}

bool SyncpointManager::IsSyncpointAllocated(u32 id) {
    return (id <= SyncpointCount) && syncpoints[id].reserved;
}

bool SyncpointManager::HasSyncpointExpired(u32 id, u32 threshold) {
    const SyncpointInfo& syncpoint{syncpoints.at(id)};

    if (!syncpoint.reserved) {
        UNREACHABLE();
        return 0;
    }

    // If the interface manages counters then we don't keep track of the maximum value as it handles
    // sanity checking the values then
    if (syncpoint.interfaceManaged) {
        return static_cast<s32>(syncpoint.counterMin - threshold) >= 0;
    } else {
        return (syncpoint.counterMax - threshold) >= (syncpoint.counterMin - threshold);
    }
}

u32 SyncpointManager::IncrementSyncpointMaxExt(u32 id, u32 amount) {
    if (!syncpoints.at(id).reserved) {
        UNREACHABLE();
        return 0;
    }

    return syncpoints.at(id).counterMax += amount;
}

u32 SyncpointManager::ReadSyncpointMinValue(u32 id) {
    if (!syncpoints.at(id).reserved) {
        UNREACHABLE();
        return 0;
    }

    return syncpoints.at(id).counterMin;
}

u32 SyncpointManager::UpdateMin(u32 id) {
    if (!syncpoints.at(id).reserved) {
        UNREACHABLE();
        return 0;
    }

    syncpoints.at(id).counterMin = host1x.GetSyncpointManager().GetHostSyncpointValue(id);
    return syncpoints.at(id).counterMin;
}

NvFence SyncpointManager::GetSyncpointFence(u32 id) {
    if (!syncpoints.at(id).reserved) {
        UNREACHABLE();
        return NvFence{};
    }

    return {.id = static_cast<s32>(id), .value = syncpoints.at(id).counterMax};
}

} // namespace Service::Nvidia::NvCore