From 7b7f6f1cb777aef0184169891b42ece902a616ae Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 30 Oct 2021 02:32:07 +0200 Subject: NvHost: Fix some regressions and correct signaling on timeout. --- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 44 ++++++++++------------ 1 file changed, 19 insertions(+), 25 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 527531f29..a3c11ad8a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -105,30 +105,32 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector auto& event = events_interface.events[event_id]; auto& gpu = system.GPU(); - - // This is mostly to take into account unimplemented features. As synced - // gpu is always synced. - if (!gpu.IsAsync()) { - event.event->GetWritableEvent().Signal(); - return NvResult::Success; - } const u32 current_syncpoint_value = event.fence.value; const s32 diff = current_syncpoint_value - params.threshold; - if (diff >= 0) { - event.event->GetWritableEvent().Signal(); - params.value = current_syncpoint_value; - std::memcpy(output.data(), ¶ms, sizeof(params)); - events_interface.failed[event_id] = false; - return NvResult::Success; - } - const u32 target_value = current_syncpoint_value - diff; + const u32 target_value = params.value; if (!is_async) { params.value = 0; } + const auto check_failing = [&]() { + if (events_interface.failed[event_id]) { + { + auto lk = system.StallProcesses(); + gpu.WaitFence(params.syncpt_id, target_value); + system.UnstallProcesses(); + } + std::memcpy(output.data(), ¶ms, sizeof(params)); + events_interface.failed[event_id] = false; + return true; + } + return false; + }; + if (params.timeout == 0) { - std::memcpy(output.data(), ¶ms, sizeof(params)); + if (check_failing()) { + return NvResult::Success; + } return NvResult::Timeout; } @@ -147,15 +149,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; } params.value |= event_id; - event.event->GetWritableEvent().Clear(); - if (events_interface.failed[event_id]) { - { - auto lk = system.StallProcesses(); - gpu.WaitFence(params.syncpt_id, target_value); - system.UnstallProcesses(); - } - std::memcpy(output.data(), ¶ms, sizeof(params)); - events_interface.failed[event_id] = false; + if (check_failing()) { return NvResult::Success; } gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); -- cgit v1.2.3 From ac104a24d11c5875e25daee5dd405ee9fe5f3a21 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 30 Oct 2021 11:35:05 +0200 Subject: NvHost: Try a different approach to blocking. --- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 15 ++++++--------- src/core/hle/service/nvdrv/nvdrv.h | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index a3c11ad8a..bfe1faf48 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -91,7 +91,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector if (syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { params.value = syncpoint_manager.GetSyncpointMin(params.syncpt_id); std::memcpy(output.data(), ¶ms, sizeof(params)); - events_interface.failed[event_id] = false; + events_interface.fails[event_id] = 0; return NvResult::Success; } @@ -99,29 +99,26 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { params.value = new_value; std::memcpy(output.data(), ¶ms, sizeof(params)); - events_interface.failed[event_id] = false; + events_interface.fails[event_id] = 0; return NvResult::Success; } - auto& event = events_interface.events[event_id]; auto& gpu = system.GPU(); - const u32 current_syncpoint_value = event.fence.value; - const s32 diff = current_syncpoint_value - params.threshold; - const u32 target_value = params.value; + const u32 target_value = syncpoint_manager.GetSyncpointMax(params.syncpt_id); if (!is_async) { params.value = 0; } const auto check_failing = [&]() { - if (events_interface.failed[event_id]) { + if (events_interface.fails[event_id] > 1) { { auto lk = system.StallProcesses(); gpu.WaitFence(params.syncpt_id, target_value); system.UnstallProcesses(); } std::memcpy(output.data(), ¶ms, sizeof(params)); - events_interface.failed[event_id] = false; + events_interface.fails[event_id] = 0; return true; } return false; @@ -207,7 +204,7 @@ NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector& input, std::v if (events_interface.status[event_id] == EventState::Waiting) { events_interface.LiberateEvent(event_id); } - events_interface.failed[event_id] = true; + events_interface.fails[event_id]++; syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id); diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index c929e5106..4c4aa7dab 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -50,7 +50,7 @@ struct EventInterface { // Tells if an NVEvent is registered or not std::array registered{}; // Tells the NVEvent that it has failed. - std::array failed{}; + std::array fails{}; // When an NVEvent is waiting on GPU interrupt, this is the sync_point // associated with it. std::array assigned_syncpt{}; -- cgit v1.2.3 From 39a5ce4e696716e48bdd1c980abc792827c68184 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 1 Nov 2021 00:51:29 +0100 Subject: NvHost: Remake Ctrl Implementation. --- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 178 +++++++++++++-------- src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 47 ++++-- src/core/hle/service/nvdrv/nvdata.h | 18 ++- src/core/hle/service/nvdrv/nvdrv.cpp | 128 +++++++++++++-- src/core/hle/service/nvdrv/nvdrv.h | 96 +++++------ src/core/hle/service/nvdrv/nvdrv_interface.cpp | 13 +- 6 files changed, 311 insertions(+), 169 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index bfe1faf48..f2b015c8f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -1,11 +1,14 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2021 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 #include #include "common/assert.h" #include "common/logging/log.h" +#include "common/scope_exit.h" #include "core/core.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_writable_event.h" @@ -30,9 +33,9 @@ NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& case 0x1c: return IocCtrlClearEventWait(input, output); case 0x1d: - return IocCtrlEventWait(input, output, false); - case 0x1e: return IocCtrlEventWait(input, output, true); + case 0x1e: + return IocCtrlEventWait(input, output, false); case 0x1f: return IocCtrlEventRegister(input, output); case 0x20: @@ -71,54 +74,65 @@ NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector& input, std::vector } NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector& output, - bool is_async) { + bool is_allocation) { IocCtrlEventWaitParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}", - params.syncpt_id, params.threshold, params.timeout, is_async); + LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_allocation={}", + params.fence.id, params.fence.value, params.timeout, is_allocation); - if (params.syncpt_id >= MaxSyncPoints) { - return NvResult::BadParameter; - } + bool must_unmark_fail = !is_allocation; + const u32 event_id = params.value.raw; + SCOPE_EXIT({ + std::memcpy(output.data(), ¶ms, sizeof(params)); + if (must_unmark_fail) { + events_interface.fails[event_id] = 0; + } + }); - u32 event_id = params.value & 0x00FF; + const u32 fence_id = static_cast(params.fence.id); - if (event_id >= MaxNvEvents) { - std::memcpy(output.data(), ¶ms, sizeof(params)); + if (fence_id >= MaxSyncPoints) { return NvResult::BadParameter; } - if (syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { - params.value = syncpoint_manager.GetSyncpointMin(params.syncpt_id); - std::memcpy(output.data(), ¶ms, sizeof(params)); - events_interface.fails[event_id] = 0; + if (params.fence.value == 0) { + params.value.raw = syncpoint_manager.GetSyncpointMin(fence_id); return NvResult::Success; } - if (const auto new_value = syncpoint_manager.RefreshSyncpoint(params.syncpt_id); - syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { - params.value = new_value; - std::memcpy(output.data(), ¶ms, sizeof(params)); - events_interface.fails[event_id] = 0; + if (syncpoint_manager.IsSyncpointExpired(fence_id, params.fence.value)) { + params.value.raw = syncpoint_manager.GetSyncpointMin(fence_id); + return NvResult::Success; + } + + if (const auto new_value = syncpoint_manager.RefreshSyncpoint(fence_id); + syncpoint_manager.IsSyncpointExpired(fence_id, params.fence.value)) { + params.value.raw = new_value; return NvResult::Success; } auto& gpu = system.GPU(); - const u32 target_value = syncpoint_manager.GetSyncpointMax(params.syncpt_id); + const u32 target_value = params.fence.value; - if (!is_async) { - params.value = 0; - } + auto lock = events_interface.Lock(); + + u32 slot = [&]() { + if (is_allocation) { + params.value.raw = 0; + return events_interface.FindFreeEvent(fence_id); + } else { + return params.value.raw; + } + }(); const auto check_failing = [&]() { - if (events_interface.fails[event_id] > 1) { + if (events_interface.fails[slot] > 1) { { auto lk = system.StallProcesses(); - gpu.WaitFence(params.syncpt_id, target_value); + gpu.WaitFence(fence_id, target_value); system.UnstallProcesses(); } - std::memcpy(output.data(), ¶ms, sizeof(params)); - events_interface.fails[event_id] = 0; + params.value.raw = target_value; return true; } return false; @@ -131,47 +145,76 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector return NvResult::Timeout; } - EventState status = events_interface.status[event_id]; - const bool bad_parameter = status == EventState::Busy; - if (bad_parameter) { - std::memcpy(output.data(), ¶ms, sizeof(params)); + if (slot >= MaxNvEvents) { return NvResult::BadParameter; } - events_interface.SetEventStatus(event_id, EventState::Waiting); - events_interface.assigned_syncpt[event_id] = params.syncpt_id; - events_interface.assigned_value[event_id] = target_value; - if (is_async) { - params.value = params.syncpt_id << 4; - } else { - params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; + + auto* event = events_interface.events[slot]; + + if (!event) { + return NvResult::BadParameter; } - params.value |= event_id; + + if (events_interface.IsBeingUsed(slot)) { + return NvResult::BadParameter; + } + if (check_failing()) { return NvResult::Success; } - gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); - std::memcpy(output.data(), ¶ms, sizeof(params)); + + params.value.raw = 0; + + events_interface.status[slot].store(EventState::Waiting, std::memory_order_release); + events_interface.assigned_syncpt[slot] = fence_id; + events_interface.assigned_value[slot] = target_value; + if (is_allocation) { + params.value.syncpoint_id_for_allocation.Assign(static_cast(fence_id)); + params.value.event_allocated.Assign(1); + } else { + params.value.syncpoint_id.Assign(fence_id); + } + params.value.raw |= slot; + + gpu.RegisterSyncptInterrupt(fence_id, target_value); return NvResult::Timeout; } +NvResult nvhost_ctrl::FreeEvent(u32 slot) { + if (slot >= MaxNvEvents) { + return NvResult::BadParameter; + } + + if (!events_interface.registered[slot]) { + return NvResult::Success; + } + + if (events_interface.IsBeingUsed(slot)) { + return NvResult::Busy; + } + + events_interface.Free(slot); + return NvResult::Success; +} + NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector& input, std::vector& output) { IocCtrlEventRegisterParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); - const u32 event_id = params.user_event_id & 0x00FF; + const u32 event_id = params.user_event_id; LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id); if (event_id >= MaxNvEvents) { return NvResult::BadParameter; } + + auto lock = events_interface.Lock(); + if (events_interface.registered[event_id]) { - const auto event_state = events_interface.status[event_id]; - if (event_state != EventState::Free) { - LOG_WARNING(Service_NVDRV, "Event already registered! Unregistering previous event"); - events_interface.UnregisterEvent(event_id); - } else { - return NvResult::BadParameter; + const auto result = FreeEvent(event_id); + if (result != NvResult::Success) { + return result; } } - events_interface.RegisterEvent(event_id); + events_interface.Create(event_id); return NvResult::Success; } @@ -181,32 +224,33 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector& input, std::memcpy(¶ms, input.data(), sizeof(params)); const u32 event_id = params.user_event_id & 0x00FF; LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id); - if (event_id >= MaxNvEvents) { - return NvResult::BadParameter; - } - if (!events_interface.registered[event_id]) { - return NvResult::BadParameter; - } - events_interface.UnregisterEvent(event_id); - return NvResult::Success; + + auto lock = events_interface.Lock(); + return FreeEvent(event_id); } NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector& input, std::vector& output) { - IocCtrlEventSignalParams params{}; + IocCtrlEventClearParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); - u32 event_id = params.event_id & 0x00FF; - LOG_WARNING(Service_NVDRV, "cleared event wait on, event_id: {:X}", event_id); + u32 event_id = params.event_id.slot; + LOG_DEBUG(Service_NVDRV, "called, event_id: {:X}", event_id); if (event_id >= MaxNvEvents) { return NvResult::BadParameter; } - if (events_interface.status[event_id] == EventState::Waiting) { - events_interface.LiberateEvent(event_id); + + auto lock = events_interface.Lock(); + + if (events_interface.status[event_id].exchange( + EventState::Cancelling, std::memory_order_acq_rel) == EventState::Waiting) { + system.GPU().CancelSyncptInterrupt(events_interface.assigned_syncpt[event_id], + events_interface.assigned_value[event_id]); + syncpoint_manager.RefreshSyncpoint(events_interface.assigned_syncpt[event_id]); } events_interface.fails[event_id]++; - - syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id); + events_interface.status[event_id].store(EventState::Cancelled, std::memory_order_release); + events_interface.events[event_id]->GetWritableEvent().Clear(); return NvResult::Success; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 4fbb89b15..0471c09b2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -5,6 +5,7 @@ #include #include +#include "common/bit_field.h" #include "common/common_types.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" #include "core/hle/service/nvdrv/nvdrv.h" @@ -27,6 +28,24 @@ public: void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; + union SyncpointEventValue { + u32 raw; + + union { + BitField<0, 4, u32> partial_slot; + BitField<4, 28, u32> syncpoint_id; + }; + + struct { + u16 slot; + union { + BitField<0, 12, u16> syncpoint_id_for_allocation; + BitField<12, 1, u16> event_allocated; + }; + }; + }; + static_assert(sizeof(SyncpointEventValue) == sizeof(u32)); + private: struct IocSyncptReadParams { u32_le id{}; @@ -83,27 +102,18 @@ private: }; static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size"); - struct IocCtrlEventSignalParams { - u32_le event_id{}; + struct IocCtrlEventClearParams { + SyncpointEventValue event_id{}; }; - static_assert(sizeof(IocCtrlEventSignalParams) == 4, - "IocCtrlEventSignalParams is incorrect size"); + static_assert(sizeof(IocCtrlEventClearParams) == 4, + "IocCtrlEventClearParams is incorrect size"); struct IocCtrlEventWaitParams { - u32_le syncpt_id{}; - u32_le threshold{}; - s32_le timeout{}; - u32_le value{}; - }; - static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size"); - - struct IocCtrlEventWaitAsyncParams { - u32_le syncpt_id{}; - u32_le threshold{}; + NvFence fence{}; u32_le timeout{}; - u32_le value{}; + SyncpointEventValue value{}; }; - static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16, + static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitAsyncParams is incorrect size"); struct IocCtrlEventRegisterParams { @@ -124,11 +134,14 @@ private: static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size"); NvResult NvOsGetConfigU32(const std::vector& input, std::vector& output); - NvResult IocCtrlEventWait(const std::vector& input, std::vector& output, bool is_async); + NvResult IocCtrlEventWait(const std::vector& input, std::vector& output, + bool is_allocation); NvResult IocCtrlEventRegister(const std::vector& input, std::vector& output); NvResult IocCtrlEventUnregister(const std::vector& input, std::vector& output); NvResult IocCtrlClearEventWait(const std::vector& input, std::vector& output); + NvResult FreeEvent(u32 slot); + EventInterface& events_interface; SyncpointManager& syncpoint_manager; }; diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 1d00394c8..2ee91f9c4 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h @@ -1,5 +1,7 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2021 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 @@ -78,11 +80,15 @@ enum class NvResult : u32 { ModuleNotPresent = 0xA000E, }; +// obtained from +// https://github.com/skyline-emu/skyline/blob/nvdec-dev/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/ctrl.h#L47 enum class EventState { - Free = 0, - Registered = 1, - Waiting = 2, - Busy = 3, + Available = 0, + Waiting = 1, + Cancelling = 2, + Signalling = 3, + Signalled = 4, + Cancelled = 5, }; union Ioctl { diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 756eb7453..fa259abed 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -1,6 +1,9 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2021 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 #include #include @@ -26,6 +29,73 @@ namespace Service::Nvidia { +std::unique_lock EventInterface::Lock() { + return std::unique_lock(events_mutex); +} + +void EventInterface::Signal(u32 event_id) { + if (status[event_id].exchange(EventState::Signalling, std::memory_order_acq_rel) == + EventState::Waiting) { + events[event_id]->GetWritableEvent().Signal(); + } + status[event_id].store(EventState::Signalled, std::memory_order_release); +} + +void EventInterface::Create(u32 event_id) { + ASSERT(!events[event_id]); + ASSERT(!registered[event_id]); + ASSERT(!IsBeingUsed(event_id)); + events[event_id] = backup[event_id]; + status[event_id] = EventState::Available; + registered[event_id] = true; + const u64 mask = 1ULL << event_id; + fails[event_id] = 0; + events_mask |= mask; + LOG_CRITICAL(Service_NVDRV, "Created Event {}", event_id); +} + +void EventInterface::Free(u32 event_id) { + ASSERT(events[event_id]); + ASSERT(registered[event_id]); + ASSERT(!IsBeingUsed(event_id)); + + backup[event_id]->GetWritableEvent().Clear(); + events[event_id] = nullptr; + status[event_id] = EventState::Available; + registered[event_id] = false; + const u64 mask = ~(1ULL << event_id); + events_mask &= mask; + LOG_CRITICAL(Service_NVDRV, "Freed Event {}", event_id); +} + +u32 EventInterface::FindFreeEvent(u32 syncpoint_id) { + u32 slot{MaxNvEvents}; + u32 free_slot{MaxNvEvents}; + for (u32 i = 0; i < MaxNvEvents; i++) { + if (registered[i]) { + if (!IsBeingUsed(i)) { + slot = i; + if (assigned_syncpt[i] == syncpoint_id) { + return slot; + } + } + } else if (free_slot == MaxNvEvents) { + free_slot = i; + } + } + if (free_slot < MaxNvEvents) { + Create(free_slot); + return free_slot; + } + + if (slot < MaxNvEvents) { + return slot; + } + + LOG_CRITICAL(Service_NVDRV, "Failed to allocate an event"); + return 0; +} + void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, Core::System& system) { auto module_ = std::make_shared(system); @@ -38,12 +108,14 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger } Module::Module(Core::System& system) - : syncpoint_manager{system.GPU()}, service_context{system, "nvdrv"} { + : syncpoint_manager{system.GPU()}, events_interface{*this}, service_context{system, "nvdrv"} { + events_interface.events_mask = 0; for (u32 i = 0; i < MaxNvEvents; i++) { - events_interface.events[i].event = - service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", i)); - events_interface.status[i] = EventState::Free; + events_interface.status[i] = EventState::Available; + events_interface.events[i] = nullptr; events_interface.registered[i] = false; + events_interface.backup[i] = + service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", i)); } auto nvmap_dev = std::make_shared(system); devices["/dev/nvhost-as-gpu"] = std::make_shared(system, nvmap_dev); @@ -62,8 +134,12 @@ Module::Module(Core::System& system) } Module::~Module() { + auto lock = events_interface.Lock(); for (u32 i = 0; i < MaxNvEvents; i++) { - service_context.CloseEvent(events_interface.events[i].event); + if (events_interface.registered[i]) { + events_interface.Free(i); + } + service_context.CloseEvent(events_interface.backup[i]); } } @@ -169,21 +245,41 @@ NvResult Module::Close(DeviceFD fd) { } void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { - for (u32 i = 0; i < MaxNvEvents; i++) { - if (events_interface.assigned_syncpt[i] == syncpoint_id && + const u32 max = MaxNvEvents - std::countl_zero(events_interface.events_mask); + const u32 min = std::countr_zero(events_interface.events_mask); + for (u32 i = min; i < max; i++) { + if (events_interface.registered[i] && events_interface.assigned_syncpt[i] == syncpoint_id && events_interface.assigned_value[i] == value) { - events_interface.LiberateEvent(i); - events_interface.events[i].event->GetWritableEvent().Signal(); + events_interface.Signal(i); } } } -Kernel::KReadableEvent& Module::GetEvent(const u32 event_id) { - return events_interface.events[event_id].event->GetReadableEvent(); -} +Kernel::KEvent* Module::GetEvent(u32 event_id) { + const auto event = Devices::nvhost_ctrl::SyncpointEventValue{.raw = event_id}; + + const bool allocated = event.event_allocated.Value() != 0; + const u32 slot{allocated ? event.partial_slot.Value() : static_cast(event.slot)}; + if (slot >= MaxNvEvents) { + ASSERT(false); + return nullptr; + } -Kernel::KWritableEvent& Module::GetEventWriteable(const u32 event_id) { - return events_interface.events[event_id].event->GetWritableEvent(); + const u32 syncpoint_id{allocated ? event.syncpoint_id_for_allocation.Value() + : event.syncpoint_id.Value()}; + + auto lock = events_interface.Lock(); + + if (events_interface.registered[slot] && + events_interface.assigned_syncpt[slot] == syncpoint_id) { + ASSERT(events_interface.events[slot]); + return events_interface.events[slot]; + } + // Temporary hack. + events_interface.Create(slot); + events_interface.assigned_syncpt[slot] = syncpoint_id; + ASSERT(false); + return events_interface.events[slot]; } } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 4c4aa7dab..8ce036508 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -1,5 +1,7 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2021 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 @@ -34,19 +36,20 @@ namespace Devices { class nvdevice; } -/// Represents an Nvidia event -struct NvEvent { - Kernel::KEvent* event{}; - NvFence fence{}; -}; +class Module; + +class EventInterface { +public: + EventInterface(Module& module_) : module{module_} {} -struct EventInterface { - // Mask representing currently busy events + // Mask representing registered events u64 events_mask{}; // Each kernel event associated to an NV event - std::array events; + std::array events{}; + // Backup NV event + std::array backup{}; // The status of the current NVEvent - std::array status{}; + std::array, MaxNvEvents> status{}; // Tells if an NVEvent is registered or not std::array registered{}; // Tells the NVEvent that it has failed. @@ -59,50 +62,26 @@ struct EventInterface { std::array assigned_value{}; // Constant to denote an unasigned syncpoint. static constexpr u32 unassigned_syncpt = 0xFFFFFFFF; - std::optional GetFreeEvent() const { - u64 mask = events_mask; - for (u32 i = 0; i < MaxNvEvents; i++) { - const bool is_free = (mask & 0x1) == 0; - if (is_free) { - if (status[i] == EventState::Registered || status[i] == EventState::Free) { - return {i}; - } - } - mask = mask >> 1; - } - return std::nullopt; - } - void SetEventStatus(const u32 event_id, EventState new_status) { - EventState old_status = status[event_id]; - if (old_status == new_status) { - return; - } - status[event_id] = new_status; - if (new_status == EventState::Registered) { - registered[event_id] = true; - } - if (new_status == EventState::Waiting || new_status == EventState::Busy) { - events_mask |= (1ULL << event_id); - } - } - void RegisterEvent(const u32 event_id) { - registered[event_id] = true; - if (status[event_id] == EventState::Free) { - status[event_id] = EventState::Registered; - } - } - void UnregisterEvent(const u32 event_id) { - registered[event_id] = false; - if (status[event_id] == EventState::Registered) { - status[event_id] = EventState::Free; - } - } - void LiberateEvent(const u32 event_id) { - status[event_id] = registered[event_id] ? EventState::Registered : EventState::Free; - events_mask &= ~(1ULL << event_id); - assigned_syncpt[event_id] = unassigned_syncpt; - assigned_value[event_id] = 0; + + bool IsBeingUsed(u32 event_id) { + const auto current_status = status[event_id].load(std::memory_order_acquire); + return current_status == EventState::Waiting || current_status == EventState::Cancelling || + current_status == EventState::Signalling; } + + std::unique_lock Lock(); + + void Signal(u32 event_id); + + void Create(u32 event_id); + + void Free(u32 event_id); + + u32 FindFreeEvent(u32 syncpoint_id); + +private: + std::mutex events_mutex; + Module& module; }; class Module final { @@ -139,11 +118,11 @@ public: void SignalSyncpt(const u32 syncpoint_id, const u32 value); - Kernel::KReadableEvent& GetEvent(u32 event_id); - - Kernel::KWritableEvent& GetEventWriteable(u32 event_id); + Kernel::KEvent* GetEvent(u32 event_id); private: + friend class EventInterface; + /// Manages syncpoints on the host SyncpointManager syncpoint_manager; @@ -159,6 +138,9 @@ private: EventInterface events_interface; KernelHelpers::ServiceContext service_context; + + void CreateEvent(u32 event_id); + void FreeEvent(u32 event_id); }; /// Registers all NVDRV services with the specified service manager. diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index b5a980384..07883feb2 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -5,6 +5,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/service/nvdrv/nvdata.h" #include "core/hle/service/nvdrv/nvdrv.h" @@ -164,8 +165,7 @@ void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto fd = rp.Pop(); - const auto event_id = rp.Pop() & 0x00FF; - LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); + const auto event_id = rp.Pop(); if (!is_initialized) { ServiceError(ctx, NvResult::NotInitialized); @@ -180,12 +180,13 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { return; } - if (event_id < MaxNvEvents) { + auto* event = nvdrv->GetEvent(event_id); + + if (event) { IPC::ResponseBuilder rb{ctx, 3, 1}; rb.Push(ResultSuccess); - auto& event = nvdrv->GetEvent(event_id); - event.Clear(); - rb.PushCopyObjects(event); + auto& readable_event = event->GetReadableEvent(); + rb.PushCopyObjects(readable_event); rb.PushEnum(NvResult::Success); } else { IPC::ResponseBuilder rb{ctx, 3}; -- cgit v1.2.3 From d30b885d713fa2b9393aeb3c515f4d881bf838f2 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 1 Nov 2021 15:02:47 +0100 Subject: NVDRV: Implement QueryEvent. --- src/core/hle/service/nvdrv/devices/nvdevice.h | 8 ++++ src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 23 +++++++++++ src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 2 + .../hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 20 +++++++++- .../hle/service/nvdrv/devices/nvhost_ctrl_gpu.h | 14 ++++++- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 26 +++++++++++- src/core/hle/service/nvdrv/devices/nvhost_gpu.h | 13 +++++- src/core/hle/service/nvdrv/nvdrv.cpp | 46 +++++++++++----------- src/core/hle/service/nvdrv/nvdrv.h | 6 ++- src/core/hle/service/nvdrv/nvdrv_interface.cpp | 15 +++---- 10 files changed, 133 insertions(+), 40 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index 696e8121e..204b0e757 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h @@ -11,6 +11,10 @@ namespace Core { class System; } +namespace Kernel { +class KEvent; +} + namespace Service::Nvidia::Devices { /// Represents an abstract nvidia device node. It is to be subclassed by concrete device nodes to @@ -64,6 +68,10 @@ public: */ virtual void OnClose(DeviceFD fd) = 0; + virtual Kernel::KEvent* QueryEvent(u32 event_id) { + return nullptr; + } + protected: Core::System& system; }; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index f2b015c8f..9b393521a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -255,4 +255,27 @@ NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector& input, std::v return NvResult::Success; } +Kernel::KEvent* nvhost_ctrl::QueryEvent(u32 event_id) { + const auto event = SyncpointEventValue{.raw = event_id}; + + const bool allocated = event.event_allocated.Value() != 0; + const u32 slot{allocated ? event.partial_slot.Value() : static_cast(event.slot)}; + if (slot >= MaxNvEvents) { + ASSERT(false); + return nullptr; + } + + const u32 syncpoint_id{allocated ? event.syncpoint_id_for_allocation.Value() + : event.syncpoint_id.Value()}; + + auto lock = events_interface.Lock(); + + if (events_interface.registered[slot] && + events_interface.assigned_syncpt[slot] == syncpoint_id) { + ASSERT(events_interface.events[slot]); + return events_interface.events[slot]; + } + return nullptr; +} + } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 0471c09b2..d548a7827 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -28,6 +28,8 @@ public: void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; + Kernel::KEvent* QueryEvent(u32 event_id) override; + union SyncpointEventValue { u32 raw; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 2b3b7efea..e353408eb 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -7,10 +7,15 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" +#include "core/hle/service/nvdrv/nvdrv.h" namespace Service::Nvidia::Devices { -nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_) : nvdevice{system_} {} +nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_) + : nvdevice{system_}, events_interface{events_interface_} { + error_notifier_event = events_interface.CreateNonCtrlEvent("CtrlGpuErrorNotifier"); + unknown_event = events_interface.CreateNonCtrlEvent("CtrlGpuUknownEvent"); +} nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -286,4 +291,17 @@ NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector& input, std::vector& input, @@ -27,6 +31,8 @@ public: void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; + Kernel::KEvent* QueryEvent(u32 event_id) override; + private: struct IoctlGpuCharacteristics { u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200) @@ -160,6 +166,12 @@ private: NvResult ZBCQueryTable(const std::vector& input, std::vector& output); NvResult FlushL2(const std::vector& input, std::vector& output); NvResult GetGpuTime(const std::vector& input, std::vector& output); + + EventInterface& events_interface; + + // Events + Kernel::KEvent* error_notifier_event; + Kernel::KEvent* unknown_event; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index b98e63011..e87fa5992 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -6,6 +6,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" +#include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvdrv/syncpoint_manager.h" #include "core/memory.h" #include "video_core/gpu.h" @@ -21,10 +22,16 @@ Tegra::CommandHeader BuildFenceAction(Tegra::GPU::FenceOperation op, u32 syncpoi } // namespace nvhost_gpu::nvhost_gpu(Core::System& system_, std::shared_ptr nvmap_dev_, - SyncpointManager& syncpoint_manager_) - : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, syncpoint_manager{syncpoint_manager_} { + EventInterface& events_interface_, SyncpointManager& syncpoint_manager_) + : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, events_interface{events_interface_}, + syncpoint_manager{syncpoint_manager_} { channel_fence.id = syncpoint_manager_.AllocateSyncpoint(); channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id); + sm_exception_breakpoint_int_report_event = + events_interface.CreateNonCtrlEvent("GpuChannelSMExceptionBreakpointInt"); + sm_exception_breakpoint_pause_report_event = + events_interface.CreateNonCtrlEvent("GpuChannelSMExceptionBreakpointPause"); + error_notifier_event = events_interface.CreateNonCtrlEvent("GpuChannelErrorNotifier"); } nvhost_gpu::~nvhost_gpu() = default; @@ -328,4 +335,19 @@ NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector& input, std::vect return NvResult::Success; } +Kernel::KEvent* nvhost_gpu::QueryEvent(u32 event_id) { + switch (event_id) { + case 1: + return sm_exception_breakpoint_int_report_event; + case 2: + return sm_exception_breakpoint_pause_report_event; + case 3: + return error_notifier_event; + default: { + LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); + } + } + return nullptr; +} + } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 8a9f7775a..eb4936df0 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -15,7 +15,8 @@ namespace Service::Nvidia { class SyncpointManager; -} +class EventInterface; +} // namespace Service::Nvidia namespace Service::Nvidia::Devices { @@ -23,7 +24,7 @@ class nvmap; class nvhost_gpu final : public nvdevice { public: explicit nvhost_gpu(Core::System& system_, std::shared_ptr nvmap_dev_, - SyncpointManager& syncpoint_manager_); + EventInterface& events_interface_, SyncpointManager& syncpoint_manager_); ~nvhost_gpu() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -36,6 +37,8 @@ public: void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; + Kernel::KEvent* QueryEvent(u32 event_id) override; + private: enum class CtxObjects : u32_le { Ctx2D = 0x902D, @@ -192,8 +195,14 @@ private: NvResult ChannelSetTimeslice(const std::vector& input, std::vector& output); std::shared_ptr nvmap_dev; + EventInterface& events_interface; SyncpointManager& syncpoint_manager; NvFence channel_fence; + + // Events + Kernel::KEvent* sm_exception_breakpoint_int_report_event; + Kernel::KEvent* sm_exception_breakpoint_pause_report_event; + Kernel::KEvent* error_notifier_event; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index fa259abed..7c0f89c12 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -96,6 +96,12 @@ u32 EventInterface::FindFreeEvent(u32 syncpoint_id) { return 0; } +Kernel::KEvent* EventInterface::CreateNonCtrlEvent(std::string name) { + Kernel::KEvent* new_event = module.service_context.CreateEvent(std::move(name)); + basic_events.push_back(new_event); + return new_event; +} + void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, Core::System& system) { auto module_ = std::make_shared(system); @@ -119,9 +125,10 @@ Module::Module(Core::System& system) } auto nvmap_dev = std::make_shared(system); devices["/dev/nvhost-as-gpu"] = std::make_shared(system, nvmap_dev); - devices["/dev/nvhost-gpu"] = - std::make_shared(system, nvmap_dev, syncpoint_manager); - devices["/dev/nvhost-ctrl-gpu"] = std::make_shared(system); + devices["/dev/nvhost-gpu"] = std::make_shared( + system, nvmap_dev, events_interface, syncpoint_manager); + devices["/dev/nvhost-ctrl-gpu"] = + std::make_shared(system, events_interface); devices["/dev/nvmap"] = nvmap_dev; devices["/dev/nvdisp_disp0"] = std::make_shared(system, nvmap_dev); devices["/dev/nvhost-ctrl"] = @@ -255,31 +262,24 @@ void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { } } -Kernel::KEvent* Module::GetEvent(u32 event_id) { - const auto event = Devices::nvhost_ctrl::SyncpointEventValue{.raw = event_id}; - - const bool allocated = event.event_allocated.Value() != 0; - const u32 slot{allocated ? event.partial_slot.Value() : static_cast(event.slot)}; - if (slot >= MaxNvEvents) { - ASSERT(false); - return nullptr; +NvResult Module::QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event) { + if (fd < 0) { + LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); + return NvResult::InvalidState; } - const u32 syncpoint_id{allocated ? event.syncpoint_id_for_allocation.Value() - : event.syncpoint_id.Value()}; + const auto itr = open_files.find(fd); - auto lock = events_interface.Lock(); + if (itr == open_files.end()) { + LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); + return NvResult::NotImplemented; + } - if (events_interface.registered[slot] && - events_interface.assigned_syncpt[slot] == syncpoint_id) { - ASSERT(events_interface.events[slot]); - return events_interface.events[slot]; + event = itr->second->QueryEvent(event_id); + if (!event) { + return NvResult::BadParameter; } - // Temporary hack. - events_interface.Create(slot); - events_interface.assigned_syncpt[slot] = syncpoint_id; - ASSERT(false); - return events_interface.events[slot]; + return NvResult::Success; } } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 8ce036508..be8813c97 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -6,6 +6,7 @@ #pragma once #include +#include #include #include @@ -79,9 +80,12 @@ public: u32 FindFreeEvent(u32 syncpoint_id); + Kernel::KEvent* CreateNonCtrlEvent(std::string name); + private: std::mutex events_mutex; Module& module; + std::vector basic_events; }; class Module final { @@ -118,7 +122,7 @@ public: void SignalSyncpt(const u32 syncpoint_id, const u32 value); - Kernel::KEvent* GetEvent(u32 event_id); + NvResult QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event); private: friend class EventInterface; diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index 07883feb2..81ee28f31 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -173,25 +173,20 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { return; } - const auto nv_result = nvdrv->VerifyFD(fd); - if (nv_result != NvResult::Success) { - LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd); - ServiceError(ctx, nv_result); - return; - } - - auto* event = nvdrv->GetEvent(event_id); + Kernel::KEvent* event = nullptr; + NvResult result = nvdrv->QueryEvent(fd, event_id, event); - if (event) { + if (result == NvResult::Success) { IPC::ResponseBuilder rb{ctx, 3, 1}; rb.Push(ResultSuccess); auto& readable_event = event->GetReadableEvent(); rb.PushCopyObjects(readable_event); rb.PushEnum(NvResult::Success); } else { + LOG_ERROR(Service_NVDRV, "Invalid event request!"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.PushEnum(NvResult::BadParameter); + rb.PushEnum(result); } } -- cgit v1.2.3 From a21b8824fb8a0bd7bcb44fd50559f26718f5dbc4 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 1 Nov 2021 15:25:06 +0100 Subject: NVDRV: Cleanup. --- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 4 +- src/core/hle/service/nvdrv/nvdrv.cpp | 53 ++++++++++++---------- src/core/hle/service/nvdrv/nvdrv.h | 9 ++-- src/core/hle/service/nvdrv/nvdrv_interface.cpp | 6 ++- 4 files changed, 40 insertions(+), 32 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 9b393521a..55acd4f78 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -125,8 +125,10 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector } }(); + must_unmark_fail = true; + const auto check_failing = [&]() { - if (events_interface.fails[slot] > 1) { + if (events_interface.fails[slot] > 2) { { auto lk = system.StallProcesses(); gpu.WaitFence(fence_id, target_value); diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 7c0f89c12..df4656240 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -29,6 +29,29 @@ namespace Service::Nvidia { +EventInterface::EventInterface(Module& module_) : module{module_} { + events_mask = 0; + for (u32 i = 0; i < MaxNvEvents; i++) { + status[i] = EventState::Available; + events[i] = nullptr; + registered[i] = false; + } +} + +EventInterface::~EventInterface() { + auto lk = Lock(); + for (u32 i = 0; i < MaxNvEvents; i++) { + if (registered[i]) { + module.service_context.CloseEvent(events[i]); + events[i] = nullptr; + registered[i] = false; + } + } + for (auto* event : basic_events) { + module.service_context.CloseEvent(event); + } +} + std::unique_lock EventInterface::Lock() { return std::unique_lock(events_mutex); } @@ -45,27 +68,25 @@ void EventInterface::Create(u32 event_id) { ASSERT(!events[event_id]); ASSERT(!registered[event_id]); ASSERT(!IsBeingUsed(event_id)); - events[event_id] = backup[event_id]; + events[event_id] = + module.service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", event_id)); status[event_id] = EventState::Available; registered[event_id] = true; const u64 mask = 1ULL << event_id; fails[event_id] = 0; events_mask |= mask; - LOG_CRITICAL(Service_NVDRV, "Created Event {}", event_id); } void EventInterface::Free(u32 event_id) { ASSERT(events[event_id]); ASSERT(registered[event_id]); ASSERT(!IsBeingUsed(event_id)); - - backup[event_id]->GetWritableEvent().Clear(); + module.service_context.CloseEvent(events[event_id]); events[event_id] = nullptr; status[event_id] = EventState::Available; registered[event_id] = false; const u64 mask = ~(1ULL << event_id); events_mask &= mask; - LOG_CRITICAL(Service_NVDRV, "Freed Event {}", event_id); } u32 EventInterface::FindFreeEvent(u32 syncpoint_id) { @@ -114,15 +135,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger } Module::Module(Core::System& system) - : syncpoint_manager{system.GPU()}, events_interface{*this}, service_context{system, "nvdrv"} { - events_interface.events_mask = 0; - for (u32 i = 0; i < MaxNvEvents; i++) { - events_interface.status[i] = EventState::Available; - events_interface.events[i] = nullptr; - events_interface.registered[i] = false; - events_interface.backup[i] = - service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", i)); - } + : syncpoint_manager{system.GPU()}, service_context{system, "nvdrv"}, events_interface{*this} { auto nvmap_dev = std::make_shared(system); devices["/dev/nvhost-as-gpu"] = std::make_shared(system, nvmap_dev); devices["/dev/nvhost-gpu"] = std::make_shared( @@ -140,15 +153,7 @@ Module::Module(Core::System& system) std::make_shared(system, nvmap_dev, syncpoint_manager); } -Module::~Module() { - auto lock = events_interface.Lock(); - for (u32 i = 0; i < MaxNvEvents; i++) { - if (events_interface.registered[i]) { - events_interface.Free(i); - } - service_context.CloseEvent(events_interface.backup[i]); - } -} +Module::~Module() = default; NvResult Module::VerifyFD(DeviceFD fd) const { if (fd < 0) { @@ -255,7 +260,7 @@ void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { const u32 max = MaxNvEvents - std::countl_zero(events_interface.events_mask); const u32 min = std::countr_zero(events_interface.events_mask); for (u32 i = min; i < max; i++) { - if (events_interface.registered[i] && events_interface.assigned_syncpt[i] == syncpoint_id && + if (events_interface.assigned_syncpt[i] == syncpoint_id && events_interface.assigned_value[i] == value) { events_interface.Signal(i); } diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index be8813c97..d24b57539 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -41,14 +41,13 @@ class Module; class EventInterface { public: - EventInterface(Module& module_) : module{module_} {} + EventInterface(Module& module_); + ~EventInterface(); // Mask representing registered events u64 events_mask{}; // Each kernel event associated to an NV event std::array events{}; - // Backup NV event - std::array backup{}; // The status of the current NVEvent std::array, MaxNvEvents> status{}; // Tells if an NVEvent is registered or not @@ -139,10 +138,10 @@ private: /// Mapping of device node names to their implementation. std::unordered_map> devices; - EventInterface events_interface; - KernelHelpers::ServiceContext service_context; + EventInterface events_interface; + void CreateEvent(u32 event_id); void FreeEvent(u32 event_id); }; diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index 81ee28f31..bd41205b8 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -1,5 +1,7 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2021 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 #include "common/logging/log.h" -- cgit v1.2.3 From 3cbe352c18f69596d91c4862382d61a3d6515140 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 1 Nov 2021 18:53:32 +0100 Subject: NVDRV: Refactor and add new NvMap. --- src/core/hle/service/nvdrv/core/container.cpp | 41 ++++ src/core/hle/service/nvdrv/core/container.h | 38 ++++ src/core/hle/service/nvdrv/core/nvmap.cpp | 245 +++++++++++++++++++++ src/core/hle/service/nvdrv/core/nvmap.h | 155 +++++++++++++ .../hle/service/nvdrv/core/syncpoint_manager.cpp | 38 ++++ .../hle/service/nvdrv/core/syncpoint_manager.h | 84 +++++++ src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 8 +- src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 10 +- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 9 +- src/core/hle/service/nvdrv/devices/nvhost_gpu.h | 10 +- .../hle/service/nvdrv/devices/nvhost_nvdec.cpp | 4 +- src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | 2 +- .../service/nvdrv/devices/nvhost_nvdec_common.cpp | 8 +- .../service/nvdrv/devices/nvhost_nvdec_common.h | 9 +- src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | 4 +- src/core/hle/service/nvdrv/devices/nvhost_vic.h | 2 +- src/core/hle/service/nvdrv/nvdrv.cpp | 16 +- src/core/hle/service/nvdrv/nvdrv.h | 11 +- src/core/hle/service/nvdrv/syncpoint_manager.cpp | 38 ---- src/core/hle/service/nvdrv/syncpoint_manager.h | 84 ------- 20 files changed, 661 insertions(+), 155 deletions(-) create mode 100644 src/core/hle/service/nvdrv/core/container.cpp create mode 100644 src/core/hle/service/nvdrv/core/container.h create mode 100644 src/core/hle/service/nvdrv/core/nvmap.cpp create mode 100644 src/core/hle/service/nvdrv/core/nvmap.h create mode 100644 src/core/hle/service/nvdrv/core/syncpoint_manager.cpp create mode 100644 src/core/hle/service/nvdrv/core/syncpoint_manager.h delete mode 100644 src/core/hle/service/nvdrv/syncpoint_manager.cpp delete mode 100644 src/core/hle/service/nvdrv/syncpoint_manager.h (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp new file mode 100644 index 000000000..97b5b2c86 --- /dev/null +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -0,0 +1,41 @@ +// Copyright 2021 yuzu emulator team +// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/core/nvmap.h" +#include "core/hle/service/nvdrv/core/syncpoint_manager.h" +#include "video_core/gpu.h" + +namespace Service::Nvidia::NvCore { + +struct ContainerImpl { + ContainerImpl(Tegra::GPU& gpu_) : file{}, manager{gpu_} {} + NvMap file; + SyncpointManager manager; +}; + +Container::Container(Tegra::GPU& gpu_) { + impl = std::make_unique(gpu_); +} + +Container::~Container() = default; + +NvMap& Container::GetNvMapFile() { + return impl->file; +} + +const NvMap& Container::GetNvMapFile() const { + return impl->file; +} + +SyncpointManager& Container::GetSyncpointManager() { + return impl->manager; +} + +const SyncpointManager& Container::GetSyncpointManager() const { + return impl->manager; +} + +} // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/container.h b/src/core/hle/service/nvdrv/core/container.h new file mode 100644 index 000000000..91ac2305a --- /dev/null +++ b/src/core/hle/service/nvdrv/core/container.h @@ -0,0 +1,38 @@ +// Copyright 2021 yuzu emulator team +// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +namespace Tegra { +class GPU; +} + +namespace Service::Nvidia::NvCore { + +class NvMap; +class SyncpointManager; + +struct ContainerImpl; + +class Container { +public: + Container(Tegra::GPU& gpu_); + ~Container(); + + NvMap& GetNvMapFile(); + + const NvMap& GetNvMapFile() const; + + SyncpointManager& GetSyncpointManager(); + + const SyncpointManager& GetSyncpointManager() const; + +private: + std::unique_ptr impl; +}; + +} // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp new file mode 100644 index 000000000..d3f227f52 --- /dev/null +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -0,0 +1,245 @@ +// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/hle/service/nvdrv/core/nvmap.h" +#include "core/memory.h" + +using Core::Memory::YUZU_PAGESIZE; + +namespace Service::Nvidia::NvCore { +NvMap::Handle::Handle(u64 size, Id id) : size(size), aligned_size(size), orig_size(size), id(id) {} + +NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) { + std::scoped_lock lock(mutex); + + // Handles cannot be allocated twice + if (allocated) [[unlikely]] + return NvResult::AccessDenied; + + flags = pFlags; + kind = pKind; + align = pAlign < YUZU_PAGESIZE ? YUZU_PAGESIZE : pAlign; + + // This flag is only applicable for handles with an address passed + if (pAddress) + flags.keep_uncached_after_free = 0; + else + LOG_CRITICAL(Service_NVDRV, + "Mapping nvmap handles without a CPU side address is unimplemented!"); + + size = Common::AlignUp(size, YUZU_PAGESIZE); + aligned_size = Common::AlignUp(size, align); + address = pAddress; + + // TODO: pin init + + allocated = true; + + return NvResult::Success; +} + +NvResult NvMap::Handle::Duplicate(bool internal_session) { + // Unallocated handles cannot be duplicated as duplication requires memory accounting (in HOS) + if (!allocated) [[unlikely]] + return NvResult::BadValue; + + std::scoped_lock lock(mutex); + + // If we internally use FromId the duplication tracking of handles won't work accurately due to + // us not implementing per-process handle refs. + if (internal_session) + internal_dupes++; + else + dupes++; + + return NvResult::Success; +} + +NvMap::NvMap() = default; + +void NvMap::AddHandle(std::shared_ptr handleDesc) { + std::scoped_lock lock(handles_lock); + + handles.emplace(handleDesc->id, std::move(handleDesc)); +} + +void NvMap::UnmapHandle(Handle& handleDesc) { + // Remove pending unmap queue entry if needed + if (handleDesc.unmap_queue_entry) { + unmap_queue.erase(*handleDesc.unmap_queue_entry); + handleDesc.unmap_queue_entry.reset(); + } + + // Free and unmap the handle from the SMMU + /* + state.soc->smmu.Unmap(handleDesc.pin_virt_address, static_cast(handleDesc.aligned_size)); + smmuAllocator.Free(handleDesc.pin_virt_address, static_cast(handleDesc.aligned_size)); + handleDesc.pin_virt_address = 0; + */ +} + +bool NvMap::TryRemoveHandle(const Handle& handleDesc) { + // No dupes left, we can remove from handle map + if (handleDesc.dupes == 0 && handleDesc.internal_dupes == 0) { + std::scoped_lock lock(handles_lock); + + auto it{handles.find(handleDesc.id)}; + if (it != handles.end()) + handles.erase(it); + + return true; + } else { + return false; + } +} + +NvResult NvMap::CreateHandle(u64 size, std::shared_ptr& result_out) { + if (!size) [[unlikely]] + return NvResult::BadValue; + + u32 id{next_handle_id.fetch_add(HandleIdIncrement, std::memory_order_relaxed)}; + auto handleDesc{std::make_shared(size, id)}; + AddHandle(handleDesc); + + result_out = handleDesc; + return NvResult::Success; +} + +std::shared_ptr NvMap::GetHandle(Handle::Id handle) { + std::scoped_lock lock(handles_lock); + try { + return handles.at(handle); + } catch ([[maybe_unused]] std::out_of_range& e) { + return nullptr; + } +} + +u32 NvMap::PinHandle(NvMap::Handle::Id handle) { + UNIMPLEMENTED_MSG("pinning"); + return 0; + /* + auto handleDesc{GetHandle(handle)}; + if (!handleDesc) + [[unlikely]] return 0; + + std::scoped_lock lock(handleDesc->mutex); + if (!handleDesc->pins) { + // If we're in the unmap queue we can just remove ourselves and return since we're already + // mapped + { + // Lock now to prevent our queue entry from being removed for allocation in-between the + // following check and erase + std::scoped_lock queueLock(unmap_queue_lock); + if (handleDesc->unmap_queue_entry) { + unmap_queue.erase(*handleDesc->unmap_queue_entry); + handleDesc->unmap_queue_entry.reset(); + + handleDesc->pins++; + return handleDesc->pin_virt_address; + } + } + + // If not then allocate some space and map it + u32 address{}; + while (!(address = smmuAllocator.Allocate(static_cast(handleDesc->aligned_size)))) { + // Free handles until the allocation succeeds + std::scoped_lock queueLock(unmap_queue_lock); + if (auto freeHandleDesc{unmap_queue.front()}) { + // Handles in the unmap queue are guaranteed not to be pinned so don't bother + // checking if they are before unmapping + std::scoped_lock freeLock(freeHandleDesc->mutex); + if (handleDesc->pin_virt_address) + UnmapHandle(*freeHandleDesc); + } else { + LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!"); + } + } + + state.soc->smmu.Map(address, handleDesc->GetPointer(), + static_cast(handleDesc->aligned_size)); + handleDesc->pin_virt_address = address; + } + + handleDesc->pins++; + return handleDesc->pin_virt_address; + */ +} + +void NvMap::UnpinHandle(Handle::Id handle) { + UNIMPLEMENTED_MSG("Unpinning"); + /* + auto handleDesc{GetHandle(handle)}; + if (!handleDesc) + return; + + std::scoped_lock lock(handleDesc->mutex); + if (--handleDesc->pins < 0) { + LOG_WARNING(Service_NVDRV, "Pin count imbalance detected!"); + } else if (!handleDesc->pins) { + std::scoped_lock queueLock(unmap_queue_lock); + + // Add to the unmap queue allowing this handle's memory to be freed if needed + unmap_queue.push_back(handleDesc); + handleDesc->unmap_queue_entry = std::prev(unmap_queue.end()); + } + */ +} + +std::optional NvMap::FreeHandle(Handle::Id handle, bool internal_session) { + std::weak_ptr hWeak{GetHandle(handle)}; + FreeInfo freeInfo; + + // We use a weak ptr here so we can tell when the handle has been freed and report that back to + // guest + if (auto handleDesc = hWeak.lock()) { + std::scoped_lock lock(handleDesc->mutex); + + if (internal_session) { + if (--handleDesc->internal_dupes < 0) + LOG_WARNING(Service_NVDRV, "Internal duplicate count imbalance detected!"); + } else { + if (--handleDesc->dupes < 0) { + LOG_WARNING(Service_NVDRV, "User duplicate count imbalance detected!"); + } else if (handleDesc->dupes == 0) { + // Force unmap the handle + if (handleDesc->pin_virt_address) { + std::scoped_lock queueLock(unmap_queue_lock); + UnmapHandle(*handleDesc); + } + + handleDesc->pins = 0; + } + } + + // Try to remove the shared ptr to the handle from the map, if nothing else is using the + // handle then it will now be freed when `handleDesc` goes out of scope + if (TryRemoveHandle(*handleDesc)) + LOG_ERROR(Service_NVDRV, "Removed nvmap handle: {}", handle); + else + LOG_ERROR(Service_NVDRV, + "Tried to free nvmap handle: {} but didn't as it still has duplicates", + handle); + + freeInfo = { + .address = handleDesc->address, + .size = handleDesc->size, + .was_uncached = handleDesc->flags.map_uncached.Value() != 0, + }; + } else { + return std::nullopt; + } + + // Handle hasn't been freed from memory, set address to 0 to mark that the handle wasn't freed + if (!hWeak.expired()) { + LOG_ERROR(Service_NVDRV, "nvmap handle: {} wasn't freed as it is still in use", handle); + freeInfo.address = 0; + } + + return freeInfo; +} + +} // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h new file mode 100644 index 000000000..e47aa755d --- /dev/null +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -0,0 +1,155 @@ +// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "common/bit_field.h" +#include "common/common_types.h" +#include "core/hle/service/nvdrv/nvdata.h" + +namespace Service::Nvidia::NvCore { +/** + * @brief The nvmap core class holds the global state for nvmap and provides methods to manage + * handles + */ +class NvMap { +public: + /** + * @brief A handle to a contiguous block of memory in an application's address space + */ + struct Handle { + std::mutex mutex; + + u64 align{}; //!< The alignment to use when pinning the handle onto the SMMU + u64 size; //!< Page-aligned size of the memory the handle refers to + u64 aligned_size; //!< `align`-aligned size of the memory the handle refers to + u64 orig_size; //!< Original unaligned size of the memory this handle refers to + + s32 dupes{1}; //!< How many guest references there are to this handle + s32 internal_dupes{0}; //!< How many emulator-internal references there are to this handle + + using Id = u32; + Id id; //!< A globally unique identifier for this handle + + s32 pins{}; + u32 pin_virt_address{}; + std::optional>::iterator> unmap_queue_entry{}; + + union Flags { + BitField<0, 1, u32> map_uncached; //!< If the handle should be mapped as uncached + BitField<2, 1, u32> keep_uncached_after_free; //!< Only applicable when the handle was + //!< allocated with a fixed address + BitField<4, 1, u32> _unk0_; //!< Passed to IOVMM for pins + } flags{}; + static_assert(sizeof(Flags) == sizeof(u32)); + + u64 address{}; //!< The memory location in the guest's AS that this handle corresponds to, + //!< this can also be in the nvdrv tmem + bool is_shared_mem_mapped{}; //!< If this nvmap has been mapped with the MapSharedMem IPC + //!< call + + u8 kind{}; //!< Used for memory compression + bool allocated{}; //!< If the handle has been allocated with `Alloc` + + Handle(u64 size, Id id); + + /** + * @brief Sets up the handle with the given memory config, can allocate memory from the tmem + * if a 0 address is passed + */ + [[nodiscard]] NvResult Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress); + + /** + * @brief Increases the dupe counter of the handle for the given session + */ + [[nodiscard]] NvResult Duplicate(bool internal_session); + + /** + * @brief Obtains a pointer to the handle's memory and marks the handle it as having been + * mapped + */ + u8* GetPointer() { + if (!address) { + return nullptr; + } + + is_shared_mem_mapped = true; + return reinterpret_cast(address); + } + }; + +private: + std::list> unmap_queue; + std::mutex unmap_queue_lock; //!< Protects access to `unmap_queue` + + std::unordered_map> handles; //!< Main owning map of handles + std::mutex handles_lock; //!< Protects access to `handles` + + static constexpr u32 HandleIdIncrement{ + 4}; //!< Each new handle ID is an increment of 4 from the previous + std::atomic next_handle_id{HandleIdIncrement}; + + void AddHandle(std::shared_ptr handle); + + /** + * @brief Unmaps and frees the SMMU memory region a handle is mapped to + * @note Both `unmap_queue_lock` and `handleDesc.mutex` MUST be locked when calling this + */ + void UnmapHandle(Handle& handleDesc); + + /** + * @brief Removes a handle from the map taking its dupes into account + * @note handleDesc.mutex MUST be locked when calling this + * @return If the handle was removed from the map + */ + bool TryRemoveHandle(const Handle& handleDesc); + +public: + /** + * @brief Encapsulates the result of a FreeHandle operation + */ + struct FreeInfo { + u64 address; //!< Address the handle referred to before deletion + u64 size; //!< Page-aligned handle size + bool was_uncached; //!< If the handle was allocated as uncached + }; + + NvMap(); + + /** + * @brief Creates an unallocated handle of the given size + */ + [[nodiscard]] NvResult CreateHandle(u64 size, std::shared_ptr& result_out); + + std::shared_ptr GetHandle(Handle::Id handle); + + /** + * @brief Maps a handle into the SMMU address space + * @note This operation is refcounted, the number of calls to this must eventually match the + * number of calls to `UnpinHandle` + * @return The SMMU virtual address that the handle has been mapped to + */ + u32 PinHandle(Handle::Id handle); + + /** + * @brief When this has been called an equal number of times to `PinHandle` for the supplied + * handle it will be added to a list of handles to be freed when necessary + */ + void UnpinHandle(Handle::Id handle); + + /** + * @brief Tries to free a handle and remove a single dupe + * @note If a handle has no dupes left and has no other users a FreeInfo struct will be returned + * describing the prior state of the handle + */ + std::optional FreeHandle(Handle::Id handle, bool internal_session); +}; +} // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp new file mode 100644 index 000000000..ff6cbb37e --- /dev/null +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "core/hle/service/nvdrv/core/syncpoint_manager.h" +#include "video_core/gpu.h" + +namespace Service::Nvidia::NvCore { + +SyncpointManager::SyncpointManager(Tegra::GPU& gpu_) : gpu{gpu_} {} + +SyncpointManager::~SyncpointManager() = default; + +u32 SyncpointManager::RefreshSyncpoint(u32 syncpoint_id) { + syncpoints[syncpoint_id].min = gpu.GetSyncpointValue(syncpoint_id); + return GetSyncpointMin(syncpoint_id); +} + +u32 SyncpointManager::AllocateSyncpoint() { + for (u32 syncpoint_id = 1; syncpoint_id < MaxSyncPoints; syncpoint_id++) { + if (!syncpoints[syncpoint_id].is_allocated) { + syncpoints[syncpoint_id].is_allocated = true; + return syncpoint_id; + } + } + ASSERT_MSG(false, "No more available syncpoints!"); + return {}; +} + +u32 SyncpointManager::IncreaseSyncpoint(u32 syncpoint_id, u32 value) { + for (u32 index = 0; index < value; ++index) { + syncpoints[syncpoint_id].max.fetch_add(1, std::memory_order_relaxed); + } + + return GetSyncpointMax(syncpoint_id); +} + +} // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.h b/src/core/hle/service/nvdrv/core/syncpoint_manager.h new file mode 100644 index 000000000..cf7f0b4be --- /dev/null +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.h @@ -0,0 +1,84 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +#include "common/common_types.h" +#include "core/hle/service/nvdrv/nvdata.h" + +namespace Tegra { +class GPU; +} + +namespace Service::Nvidia::NvCore { + +class SyncpointManager final { +public: + explicit SyncpointManager(Tegra::GPU& gpu_); + ~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. + */ + bool IsSyncpointExpired(u32 syncpoint_id, u32 value) const { + return (GetSyncpointMax(syncpoint_id) - value) >= (GetSyncpointMin(syncpoint_id) - value); + } + + /** + * 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. + */ + u32 GetSyncpointMin(u32 syncpoint_id) const { + return syncpoints.at(syncpoint_id).min.load(std::memory_order_relaxed); + } + + /** + * 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. + */ + u32 GetSyncpointMax(u32 syncpoint_id) const { + return syncpoints.at(syncpoint_id).max.load(std::memory_order_relaxed); + } + + /** + * Refreshes the minimum value for the specified syncpoint. + * @param syncpoint_id Syncpoint ID to be refreshed. + * @returns The new syncpoint minimum value. + */ + u32 RefreshSyncpoint(u32 syncpoint_id); + + /** + * Allocates a new syncoint. + * @returns The syncpoint ID for the newly allocated syncpoint. + */ + u32 AllocateSyncpoint(); + + /** + * 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. + */ + u32 IncreaseSyncpoint(u32 syncpoint_id, u32 value); + +private: + struct Syncpoint { + std::atomic min; + std::atomic max; + std::atomic is_allocated; + }; + + std::array syncpoints{}; + + Tegra::GPU& gpu; +}; + +} // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 55acd4f78..5e2155e6c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -12,15 +12,17 @@ #include "core/core.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_writable_event.h" +#include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/core/syncpoint_manager.h" #include "core/hle/service/nvdrv/devices/nvhost_ctrl.h" #include "video_core/gpu.h" namespace Service::Nvidia::Devices { nvhost_ctrl::nvhost_ctrl(Core::System& system_, EventInterface& events_interface_, - SyncpointManager& syncpoint_manager_) - : nvdevice{system_}, events_interface{events_interface_}, syncpoint_manager{ - syncpoint_manager_} {} + NvCore::Container& core_) + : nvdevice{system_}, events_interface{events_interface_}, core{core_}, + syncpoint_manager{core_.GetSyncpointManager()} {} nvhost_ctrl::~nvhost_ctrl() = default; NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index d548a7827..9fd46ea5f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -10,12 +10,17 @@ #include "core/hle/service/nvdrv/devices/nvdevice.h" #include "core/hle/service/nvdrv/nvdrv.h" +namespace Service::Nvidia::NvCore { +class Container; +class SyncpointManager; +} // namespace Service::Nvidia::NvCore + namespace Service::Nvidia::Devices { class nvhost_ctrl final : public nvdevice { public: explicit nvhost_ctrl(Core::System& system_, EventInterface& events_interface_, - SyncpointManager& syncpoint_manager_); + NvCore::Container& core); ~nvhost_ctrl() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -145,7 +150,8 @@ private: NvResult FreeEvent(u32 slot); EventInterface& events_interface; - SyncpointManager& syncpoint_manager; + NvCore::Container& core; + NvCore::SyncpointManager& syncpoint_manager; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index e87fa5992..a480bfc47 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -5,9 +5,10 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/core/syncpoint_manager.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" #include "core/hle/service/nvdrv/nvdrv.h" -#include "core/hle/service/nvdrv/syncpoint_manager.h" #include "core/memory.h" #include "video_core/gpu.h" @@ -22,10 +23,10 @@ Tegra::CommandHeader BuildFenceAction(Tegra::GPU::FenceOperation op, u32 syncpoi } // namespace nvhost_gpu::nvhost_gpu(Core::System& system_, std::shared_ptr nvmap_dev_, - EventInterface& events_interface_, SyncpointManager& syncpoint_manager_) + EventInterface& events_interface_, NvCore::Container& core_) : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, events_interface{events_interface_}, - syncpoint_manager{syncpoint_manager_} { - channel_fence.id = syncpoint_manager_.AllocateSyncpoint(); + core{core_}, syncpoint_manager{core_.GetSyncpointManager()} { + channel_fence.id = syncpoint_manager.AllocateSyncpoint(); channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id); sm_exception_breakpoint_int_report_event = events_interface.CreateNonCtrlEvent("GpuChannelSMExceptionBreakpointInt"); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index eb4936df0..4f73a7bae 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -14,7 +14,12 @@ #include "video_core/dma_pusher.h" namespace Service::Nvidia { + +namespace NvCore { +class Container; class SyncpointManager; +} // namespace NvCore + class EventInterface; } // namespace Service::Nvidia @@ -24,7 +29,7 @@ class nvmap; class nvhost_gpu final : public nvdevice { public: explicit nvhost_gpu(Core::System& system_, std::shared_ptr nvmap_dev_, - EventInterface& events_interface_, SyncpointManager& syncpoint_manager_); + EventInterface& events_interface_, NvCore::Container& core); ~nvhost_gpu() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -196,7 +201,8 @@ private: std::shared_ptr nvmap_dev; EventInterface& events_interface; - SyncpointManager& syncpoint_manager; + NvCore::Container& core; + NvCore::SyncpointManager& syncpoint_manager; NvFence channel_fence; // Events diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index a7385fce8..2c9158c7c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -11,8 +11,8 @@ namespace Service::Nvidia::Devices { nvhost_nvdec::nvhost_nvdec(Core::System& system_, std::shared_ptr nvmap_dev_, - SyncpointManager& syncpoint_manager_) - : nvhost_nvdec_common{system_, std::move(nvmap_dev_), syncpoint_manager_} {} + NvCore::Container& core) + : nvhost_nvdec_common{system_, std::move(nvmap_dev_), core} {} nvhost_nvdec::~nvhost_nvdec() = default; NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 29b3e6a36..04da4a913 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -11,7 +11,7 @@ namespace Service::Nvidia::Devices { class nvhost_nvdec final : public nvhost_nvdec_common { public: explicit nvhost_nvdec(Core::System& system_, std::shared_ptr nvmap_dev_, - SyncpointManager& syncpoint_manager_); + NvCore::Container& core); ~nvhost_nvdec() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 8b2cd9bf1..5a9c59f37 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -8,9 +8,10 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/core/syncpoint_manager.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h" #include "core/hle/service/nvdrv/devices/nvmap.h" -#include "core/hle/service/nvdrv/syncpoint_manager.h" #include "core/memory.h" #include "video_core/memory_manager.h" #include "video_core/renderer_base.h" @@ -45,8 +46,9 @@ std::size_t WriteVectors(std::vector& dst, const std::vector& src, std::s } // Anonymous namespace nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, std::shared_ptr nvmap_dev_, - SyncpointManager& syncpoint_manager_) - : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, syncpoint_manager{syncpoint_manager_} {} + NvCore::Container& core_) + : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, core{core_}, + syncpoint_manager{core.GetSyncpointManager()} {} nvhost_nvdec_common::~nvhost_nvdec_common() = default; NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector& input) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index 12d39946d..cccc94a58 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -9,7 +9,11 @@ #include "core/hle/service/nvdrv/devices/nvdevice.h" namespace Service::Nvidia { + +namespace NvCore { class SyncpointManager; +class Container; +} // namespace NvCore namespace Devices { class nvmap; @@ -17,7 +21,7 @@ class nvmap; class nvhost_nvdec_common : public nvdevice { public: explicit nvhost_nvdec_common(Core::System& system_, std::shared_ptr nvmap_dev_, - SyncpointManager& syncpoint_manager_); + NvCore::Container& core); ~nvhost_nvdec_common() override; protected: @@ -114,7 +118,8 @@ protected: s32_le nvmap_fd{}; u32_le submit_timeout{}; std::shared_ptr nvmap_dev; - SyncpointManager& syncpoint_manager; + NvCore::Container& core; + NvCore::SyncpointManager& syncpoint_manager; std::array device_syncpoints{}; }; }; // namespace Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index f58e8bada..66558c331 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -9,8 +9,8 @@ namespace Service::Nvidia::Devices { nvhost_vic::nvhost_vic(Core::System& system_, std::shared_ptr nvmap_dev_, - SyncpointManager& syncpoint_manager_) - : nvhost_nvdec_common{system_, std::move(nvmap_dev_), syncpoint_manager_} {} + NvCore::Container& core) + : nvhost_nvdec_common{system_, std::move(nvmap_dev_), core} {} nvhost_vic::~nvhost_vic() = default; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index b41b195ae..6f9838b2d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -10,7 +10,7 @@ namespace Service::Nvidia::Devices { class nvhost_vic final : public nvhost_nvdec_common { public: explicit nvhost_vic(Core::System& system_, std::shared_ptr nvmap_dev_, - SyncpointManager& syncpoint_manager_); + NvCore::Container& core); ~nvhost_vic(); NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index df4656240..824c0e290 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -11,6 +11,7 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_writable_event.h" +#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" @@ -24,8 +25,8 @@ #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvdrv/nvdrv_interface.h" #include "core/hle/service/nvdrv/nvmemp.h" -#include "core/hle/service/nvdrv/syncpoint_manager.h" #include "core/hle/service/nvflinger/nvflinger.h" +#include "video_core/gpu.h" namespace Service::Nvidia { @@ -75,6 +76,7 @@ void EventInterface::Create(u32 event_id) { const u64 mask = 1ULL << event_id; fails[event_id] = 0; events_mask |= mask; + assigned_syncpt[event_id] = 0; } void EventInterface::Free(u32 event_id) { @@ -135,22 +137,22 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger } Module::Module(Core::System& system) - : syncpoint_manager{system.GPU()}, service_context{system, "nvdrv"}, events_interface{*this} { + : service_context{system, "nvdrv"}, events_interface{*this}, container{system.GPU()} { auto nvmap_dev = std::make_shared(system); devices["/dev/nvhost-as-gpu"] = std::make_shared(system, nvmap_dev); - devices["/dev/nvhost-gpu"] = std::make_shared( - system, nvmap_dev, events_interface, syncpoint_manager); + devices["/dev/nvhost-gpu"] = + std::make_shared(system, nvmap_dev, events_interface, container); devices["/dev/nvhost-ctrl-gpu"] = std::make_shared(system, events_interface); devices["/dev/nvmap"] = nvmap_dev; devices["/dev/nvdisp_disp0"] = std::make_shared(system, nvmap_dev); devices["/dev/nvhost-ctrl"] = - std::make_shared(system, events_interface, syncpoint_manager); + std::make_shared(system, events_interface, container); devices["/dev/nvhost-nvdec"] = - std::make_shared(system, nvmap_dev, syncpoint_manager); + std::make_shared(system, nvmap_dev, container); devices["/dev/nvhost-nvjpg"] = std::make_shared(system); devices["/dev/nvhost-vic"] = - std::make_shared(system, nvmap_dev, syncpoint_manager); + std::make_shared(system, nvmap_dev, container); } Module::~Module() = default; diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index d24b57539..96adf2ffb 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -12,8 +12,8 @@ #include "common/common_types.h" #include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/nvdata.h" -#include "core/hle/service/nvdrv/syncpoint_manager.h" #include "core/hle/service/nvflinger/ui/fence.h" #include "core/hle/service/service.h" @@ -31,7 +31,10 @@ class NVFlinger; namespace Service::Nvidia { +namespace NvCore { +class Container; class SyncpointManager; +} // namespace NvCore namespace Devices { class nvdevice; @@ -126,9 +129,6 @@ public: private: friend class EventInterface; - /// Manages syncpoints on the host - SyncpointManager syncpoint_manager; - /// Id to use for the next open file descriptor. DeviceFD next_fd = 1; @@ -142,6 +142,9 @@ private: EventInterface events_interface; + /// Manages syncpoints on the host + NvCore::Container container; + void CreateEvent(u32 event_id); void FreeEvent(u32 event_id); }; diff --git a/src/core/hle/service/nvdrv/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/syncpoint_manager.cpp deleted file mode 100644 index a6fa943e8..000000000 --- a/src/core/hle/service/nvdrv/syncpoint_manager.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/assert.h" -#include "core/hle/service/nvdrv/syncpoint_manager.h" -#include "video_core/gpu.h" - -namespace Service::Nvidia { - -SyncpointManager::SyncpointManager(Tegra::GPU& gpu_) : gpu{gpu_} {} - -SyncpointManager::~SyncpointManager() = default; - -u32 SyncpointManager::RefreshSyncpoint(u32 syncpoint_id) { - syncpoints[syncpoint_id].min = gpu.GetSyncpointValue(syncpoint_id); - return GetSyncpointMin(syncpoint_id); -} - -u32 SyncpointManager::AllocateSyncpoint() { - for (u32 syncpoint_id = 1; syncpoint_id < MaxSyncPoints; syncpoint_id++) { - if (!syncpoints[syncpoint_id].is_allocated) { - syncpoints[syncpoint_id].is_allocated = true; - return syncpoint_id; - } - } - ASSERT_MSG(false, "No more available syncpoints!"); - return {}; -} - -u32 SyncpointManager::IncreaseSyncpoint(u32 syncpoint_id, u32 value) { - for (u32 index = 0; index < value; ++index) { - syncpoints[syncpoint_id].max.fetch_add(1, std::memory_order_relaxed); - } - - return GetSyncpointMax(syncpoint_id); -} - -} // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/syncpoint_manager.h b/src/core/hle/service/nvdrv/syncpoint_manager.h deleted file mode 100644 index 7f080f76e..000000000 --- a/src/core/hle/service/nvdrv/syncpoint_manager.h +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include - -#include "common/common_types.h" -#include "core/hle/service/nvdrv/nvdata.h" - -namespace Tegra { -class GPU; -} - -namespace Service::Nvidia { - -class SyncpointManager final { -public: - explicit SyncpointManager(Tegra::GPU& gpu_); - ~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. - */ - bool IsSyncpointExpired(u32 syncpoint_id, u32 value) const { - return (GetSyncpointMax(syncpoint_id) - value) >= (GetSyncpointMin(syncpoint_id) - value); - } - - /** - * 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. - */ - u32 GetSyncpointMin(u32 syncpoint_id) const { - return syncpoints.at(syncpoint_id).min.load(std::memory_order_relaxed); - } - - /** - * 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. - */ - u32 GetSyncpointMax(u32 syncpoint_id) const { - return syncpoints.at(syncpoint_id).max.load(std::memory_order_relaxed); - } - - /** - * Refreshes the minimum value for the specified syncpoint. - * @param syncpoint_id Syncpoint ID to be refreshed. - * @returns The new syncpoint minimum value. - */ - u32 RefreshSyncpoint(u32 syncpoint_id); - - /** - * Allocates a new syncoint. - * @returns The syncpoint ID for the newly allocated syncpoint. - */ - u32 AllocateSyncpoint(); - - /** - * 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. - */ - u32 IncreaseSyncpoint(u32 syncpoint_id, u32 value); - -private: - struct Syncpoint { - std::atomic min; - std::atomic max; - std::atomic is_allocated; - }; - - std::array syncpoints{}; - - Tegra::GPU& gpu; -}; - -} // namespace Service::Nvidia -- cgit v1.2.3 From de0e8eff429b4374c18e3325ad3747db55bddddd Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 4 Nov 2021 12:51:17 +0100 Subject: NVDRV: Implement new NvMap --- src/core/hle/service/nvdrv/core/nvmap.cpp | 119 ++++++----- src/core/hle/service/nvdrv/core/nvmap.h | 12 +- .../hle/service/nvdrv/devices/nvdisp_disp0.cpp | 14 +- src/core/hle/service/nvdrv/devices/nvdisp_disp0.h | 12 +- .../hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 54 ++--- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | 12 +- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 2 + src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 9 +- src/core/hle/service/nvdrv/devices/nvhost_gpu.h | 7 +- .../hle/service/nvdrv/devices/nvhost_nvdec.cpp | 5 +- src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | 3 +- .../service/nvdrv/devices/nvhost_nvdec_common.cpp | 26 ++- .../service/nvdrv/devices/nvhost_nvdec_common.h | 11 +- src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | 5 +- src/core/hle/service/nvdrv/devices/nvhost_vic.h | 3 +- src/core/hle/service/nvdrv/devices/nvmap.cpp | 220 ++++++++++----------- src/core/hle/service/nvdrv/devices/nvmap.h | 55 +++--- src/core/hle/service/nvdrv/nvdrv.cpp | 15 +- 18 files changed, 307 insertions(+), 277 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index d3f227f52..281381cc4 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -17,7 +17,7 @@ NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) std::scoped_lock lock(mutex); // Handles cannot be allocated twice - if (allocated) [[unlikely]] + if (allocated) return NvResult::AccessDenied; flags = pFlags; @@ -61,33 +61,34 @@ NvResult NvMap::Handle::Duplicate(bool internal_session) { NvMap::NvMap() = default; -void NvMap::AddHandle(std::shared_ptr handleDesc) { +void NvMap::AddHandle(std::shared_ptr handle_description) { std::scoped_lock lock(handles_lock); - handles.emplace(handleDesc->id, std::move(handleDesc)); + handles.emplace(handle_description->id, std::move(handle_description)); } -void NvMap::UnmapHandle(Handle& handleDesc) { +void NvMap::UnmapHandle(Handle& handle_description) { // Remove pending unmap queue entry if needed - if (handleDesc.unmap_queue_entry) { - unmap_queue.erase(*handleDesc.unmap_queue_entry); - handleDesc.unmap_queue_entry.reset(); + if (handle_description.unmap_queue_entry) { + unmap_queue.erase(*handle_description.unmap_queue_entry); + handle_description.unmap_queue_entry.reset(); } // Free and unmap the handle from the SMMU /* - state.soc->smmu.Unmap(handleDesc.pin_virt_address, static_cast(handleDesc.aligned_size)); - smmuAllocator.Free(handleDesc.pin_virt_address, static_cast(handleDesc.aligned_size)); - handleDesc.pin_virt_address = 0; + state.soc->smmu.Unmap(handle_description.pin_virt_address, + static_cast(handle_description.aligned_size)); + smmuAllocator.Free(handle_description.pin_virt_address, + static_cast(handle_description.aligned_size)); handle_description.pin_virt_address = 0; */ } -bool NvMap::TryRemoveHandle(const Handle& handleDesc) { +bool NvMap::TryRemoveHandle(const Handle& handle_description) { // No dupes left, we can remove from handle map - if (handleDesc.dupes == 0 && handleDesc.internal_dupes == 0) { + if (handle_description.dupes == 0 && handle_description.internal_dupes == 0) { std::scoped_lock lock(handles_lock); - auto it{handles.find(handleDesc.id)}; + auto it{handles.find(handle_description.id)}; if (it != handles.end()) handles.erase(it); @@ -102,10 +103,10 @@ NvResult NvMap::CreateHandle(u64 size, std::shared_ptr& result_ou return NvResult::BadValue; u32 id{next_handle_id.fetch_add(HandleIdIncrement, std::memory_order_relaxed)}; - auto handleDesc{std::make_shared(size, id)}; - AddHandle(handleDesc); + auto handle_description{std::make_shared(size, id)}; + AddHandle(handle_description); - result_out = handleDesc; + result_out = handle_description; return NvResult::Success; } @@ -118,73 +119,83 @@ std::shared_ptr NvMap::GetHandle(Handle::Id handle) { } } +VAddr NvMap::GetHandleAddress(Handle::Id handle) { + std::scoped_lock lock(handles_lock); + try { + return handles.at(handle)->address; + } catch ([[maybe_unused]] std::out_of_range& e) { + return 0; + } +} + u32 NvMap::PinHandle(NvMap::Handle::Id handle) { UNIMPLEMENTED_MSG("pinning"); return 0; /* - auto handleDesc{GetHandle(handle)}; - if (!handleDesc) + auto handle_description{GetHandle(handle)}; + if (!handle_description) [[unlikely]] return 0; - std::scoped_lock lock(handleDesc->mutex); - if (!handleDesc->pins) { + std::scoped_lock lock(handle_description->mutex); + if (!handle_description->pins) { // If we're in the unmap queue we can just remove ourselves and return since we're already // mapped { // Lock now to prevent our queue entry from being removed for allocation in-between the // following check and erase std::scoped_lock queueLock(unmap_queue_lock); - if (handleDesc->unmap_queue_entry) { - unmap_queue.erase(*handleDesc->unmap_queue_entry); - handleDesc->unmap_queue_entry.reset(); + if (handle_description->unmap_queue_entry) { + unmap_queue.erase(*handle_description->unmap_queue_entry); + handle_description->unmap_queue_entry.reset(); - handleDesc->pins++; - return handleDesc->pin_virt_address; + handle_description->pins++; + return handle_description->pin_virt_address; } } // If not then allocate some space and map it u32 address{}; - while (!(address = smmuAllocator.Allocate(static_cast(handleDesc->aligned_size)))) { + while (!(address = + smmuAllocator.Allocate(static_cast(handle_description->aligned_size)))) { // Free handles until the allocation succeeds std::scoped_lock queueLock(unmap_queue_lock); if (auto freeHandleDesc{unmap_queue.front()}) { // Handles in the unmap queue are guaranteed not to be pinned so don't bother // checking if they are before unmapping std::scoped_lock freeLock(freeHandleDesc->mutex); - if (handleDesc->pin_virt_address) + if (handle_description->pin_virt_address) UnmapHandle(*freeHandleDesc); } else { LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!"); } } - state.soc->smmu.Map(address, handleDesc->GetPointer(), - static_cast(handleDesc->aligned_size)); - handleDesc->pin_virt_address = address; + state.soc->smmu.Map(address, handle_description->GetPointer(), + static_cast(handle_description->aligned_size)); + handle_description->pin_virt_address = address; } - handleDesc->pins++; - return handleDesc->pin_virt_address; + handle_description->pins++; + return handle_description->pin_virt_address; */ } void NvMap::UnpinHandle(Handle::Id handle) { UNIMPLEMENTED_MSG("Unpinning"); /* - auto handleDesc{GetHandle(handle)}; - if (!handleDesc) + auto handle_description{GetHandle(handle)}; + if (!handle_description) return; - std::scoped_lock lock(handleDesc->mutex); - if (--handleDesc->pins < 0) { + std::scoped_lock lock(handle_description->mutex); + if (--handle_description->pins < 0) { LOG_WARNING(Service_NVDRV, "Pin count imbalance detected!"); - } else if (!handleDesc->pins) { + } else if (!handle_description->pins) { std::scoped_lock queueLock(unmap_queue_lock); // Add to the unmap queue allowing this handle's memory to be freed if needed - unmap_queue.push_back(handleDesc); - handleDesc->unmap_queue_entry = std::prev(unmap_queue.end()); + unmap_queue.push_back(handle_description); + handle_description->unmap_queue_entry = std::prev(unmap_queue.end()); } */ } @@ -195,39 +206,39 @@ std::optional NvMap::FreeHandle(Handle::Id handle, bool interna // We use a weak ptr here so we can tell when the handle has been freed and report that back to // guest - if (auto handleDesc = hWeak.lock()) { - std::scoped_lock lock(handleDesc->mutex); + if (auto handle_description = hWeak.lock()) { + std::scoped_lock lock(handle_description->mutex); if (internal_session) { - if (--handleDesc->internal_dupes < 0) + if (--handle_description->internal_dupes < 0) LOG_WARNING(Service_NVDRV, "Internal duplicate count imbalance detected!"); } else { - if (--handleDesc->dupes < 0) { + if (--handle_description->dupes < 0) { LOG_WARNING(Service_NVDRV, "User duplicate count imbalance detected!"); - } else if (handleDesc->dupes == 0) { + } else if (handle_description->dupes == 0) { // Force unmap the handle - if (handleDesc->pin_virt_address) { + if (handle_description->pin_virt_address) { std::scoped_lock queueLock(unmap_queue_lock); - UnmapHandle(*handleDesc); + UnmapHandle(*handle_description); } - handleDesc->pins = 0; + handle_description->pins = 0; } } // Try to remove the shared ptr to the handle from the map, if nothing else is using the - // handle then it will now be freed when `handleDesc` goes out of scope - if (TryRemoveHandle(*handleDesc)) - LOG_ERROR(Service_NVDRV, "Removed nvmap handle: {}", handle); + // handle then it will now be freed when `handle_description` goes out of scope + if (TryRemoveHandle(*handle_description)) + LOG_DEBUG(Service_NVDRV, "Removed nvmap handle: {}", handle); else - LOG_ERROR(Service_NVDRV, + LOG_DEBUG(Service_NVDRV, "Tried to free nvmap handle: {} but didn't as it still has duplicates", handle); freeInfo = { - .address = handleDesc->address, - .size = handleDesc->size, - .was_uncached = handleDesc->flags.map_uncached.Value() != 0, + .address = handle_description->address, + .size = handle_description->size, + .was_uncached = handle_description->flags.map_uncached.Value() != 0, }; } else { return std::nullopt; diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index e47aa755d..994c70e6f 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -59,6 +59,8 @@ public: u8 kind{}; //!< Used for memory compression bool allocated{}; //!< If the handle has been allocated with `Alloc` + u64 dma_map_addr{}; //! remove me after implementing pinning. + Handle(u64 size, Id id); /** @@ -101,16 +103,16 @@ private: /** * @brief Unmaps and frees the SMMU memory region a handle is mapped to - * @note Both `unmap_queue_lock` and `handleDesc.mutex` MUST be locked when calling this + * @note Both `unmap_queue_lock` and `handle_description.mutex` MUST be locked when calling this */ - void UnmapHandle(Handle& handleDesc); + void UnmapHandle(Handle& handle_description); /** * @brief Removes a handle from the map taking its dupes into account - * @note handleDesc.mutex MUST be locked when calling this + * @note handle_description.mutex MUST be locked when calling this * @return If the handle was removed from the map */ - bool TryRemoveHandle(const Handle& handleDesc); + bool TryRemoveHandle(const Handle& handle_description); public: /** @@ -131,6 +133,8 @@ public: std::shared_ptr GetHandle(Handle::Id handle); + VAddr GetHandleAddress(Handle::Id handle); + /** * @brief Maps a handle into the SMMU address space * @note This operation is refcounted, the number of calls to this must eventually match the diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 604711914..b1c0e9eb2 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -5,15 +5,16 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" -#include "core/hle/service/nvdrv/devices/nvmap.h" #include "core/perf_stats.h" #include "video_core/gpu.h" namespace Service::Nvidia::Devices { -nvdisp_disp0::nvdisp_disp0(Core::System& system_, std::shared_ptr nvmap_dev_) - : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)} {} +nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core) + : nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {} nvdisp_disp0::~nvdisp_disp0() = default; NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -40,7 +41,7 @@ void nvdisp_disp0::OnClose(DeviceFD fd) {} void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, u32 height, u32 stride, android::BufferTransformFlags transform, const Common::Rectangle& crop_rect) { - const VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle); + const VAddr addr = nvmap.GetHandleAddress(buffer_handle); LOG_TRACE(Service, "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", addr, offset, width, height, stride, format); @@ -54,4 +55,9 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat form system.GetPerfStats().BeginSystemFrame(); } +Kernel::KEvent* nvdisp_disp0::QueryEvent(u32 event_id) { + LOG_CRITICAL(Service_NVDRV, "Unknown DISP Event {}", event_id); + return nullptr; +} + } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 67b105e02..1ca9b2e74 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -11,13 +11,18 @@ #include "core/hle/service/nvflinger/buffer_transform_flags.h" #include "core/hle/service/nvflinger/pixel_format.h" +namespace Service::Nvidia::NvCore { +class Container; +class NvMap; +} // namespace Service::Nvidia::NvCore + namespace Service::Nvidia::Devices { class nvmap; class nvdisp_disp0 final : public nvdevice { public: - explicit nvdisp_disp0(Core::System& system_, std::shared_ptr nvmap_dev_); + explicit nvdisp_disp0(Core::System& system_, NvCore::Container& core); ~nvdisp_disp0() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -35,8 +40,11 @@ public: u32 stride, android::BufferTransformFlags transform, const Common::Rectangle& crop_rect); + Kernel::KEvent* QueryEvent(u32 event_id) override; + private: - std::shared_ptr nvmap_dev; + NvCore::Container& container; + NvCore::NvMap& nvmap; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 9867a648d..9283d6aec 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -7,15 +7,16 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" -#include "core/hle/service/nvdrv/devices/nvmap.h" #include "video_core/memory_manager.h" #include "video_core/rasterizer_interface.h" namespace Service::Nvidia::Devices { -nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, std::shared_ptr nvmap_dev_) - : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)} {} +nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, NvCore::Container& core) + : nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {} nvhost_as_gpu::~nvhost_as_gpu() = default; NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -143,7 +144,7 @@ NvResult nvhost_as_gpu::Remap(const std::vector& input, std::vector& out LOG_DEBUG(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}", entry.offset, entry.nvmap_handle, entry.pages); - const auto object{nvmap_dev->GetObject(entry.nvmap_handle)}; + const auto object{nvmap.GetHandle(entry.nvmap_handle)}; if (!object) { LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle); result = NvResult::InvalidState; @@ -153,7 +154,8 @@ NvResult nvhost_as_gpu::Remap(const std::vector& input, std::vector& out const auto offset{static_cast(entry.offset) << 0x10}; const auto size{static_cast(entry.pages) << 0x10}; const auto map_offset{static_cast(entry.map_offset) << 0x10}; - const auto addr{system.GPU().MemoryManager().Map(object->addr + map_offset, offset, size)}; + const auto addr{ + system.GPU().MemoryManager().Map(object->address + map_offset, offset, size)}; if (!addr) { LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!"); @@ -176,24 +178,7 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vectorGetObject(params.nvmap_handle)}; - if (!object) { - LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle); - std::memcpy(output.data(), ¶ms, output.size()); - return NvResult::InvalidState; - } - - // The real nvservices doesn't make a distinction between handles and ids, and - // object can only have one handle and it will be the same as its id. Assert that this is the - // case to prevent unexpected behavior. - ASSERT(object->id == params.nvmap_handle); auto& gpu = system.GPU(); - - u64 page_size{params.page_size}; - if (!page_size) { - page_size = object->align; - } - if ((params.flags & AddressSpaceFlags::Remap) != AddressSpaceFlags::None) { if (const auto buffer_map{FindBufferMap(params.offset)}; buffer_map) { const auto cpu_addr{static_cast(buffer_map->CpuAddr() + params.buffer_offset)}; @@ -220,10 +205,24 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vectorstatus == nvmap::Object::Status::Allocated); + const auto object{nvmap.GetHandle(params.nvmap_handle)}; + if (!object) { + LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle); + std::memcpy(output.data(), ¶ms, output.size()); + return NvResult::InvalidState; + } + + // The real nvservices doesn't make a distinction between handles and ids, and + // object can only have one handle and it will be the same as its id. Assert that this is the + // case to prevent unexpected behavior. + ASSERT(object->id == params.nvmap_handle); + + u64 page_size{params.page_size}; + if (!page_size) { + page_size = object->align; + } - const auto physical_address{object->addr + params.buffer_offset}; + const auto physical_address{object->address + params.buffer_offset}; u64 size{params.mapping_size}; if (!size) { size = object->size; @@ -363,4 +362,9 @@ std::optional nvhost_as_gpu::RemoveBufferMap(GPUVAddr gpu_addr) { return std::nullopt; } +Kernel::KEvent* nvhost_as_gpu::QueryEvent(u32 event_id) { + LOG_CRITICAL(Service_NVDRV, "Unknown AS GPU Event {}", event_id); + return nullptr; +} + } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 555843a6f..67d2f1e87 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -13,6 +13,11 @@ #include "common/swap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" +namespace Service::Nvidia::NvCore { +class Container; +class NvMap; +} // namespace Service::Nvidia::NvCore + namespace Service::Nvidia::Devices { constexpr u32 DEFAULT_BIG_PAGE_SIZE = 1 << 16; @@ -29,7 +34,7 @@ DECLARE_ENUM_FLAG_OPERATORS(AddressSpaceFlags); class nvhost_as_gpu final : public nvdevice { public: - explicit nvhost_as_gpu(Core::System& system_, std::shared_ptr nvmap_dev_); + explicit nvhost_as_gpu(Core::System& system_, NvCore::Container& core); ~nvhost_as_gpu() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -42,6 +47,8 @@ public: void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; + Kernel::KEvent* QueryEvent(u32 event_id) override; + private: class BufferMap final { public: @@ -180,7 +187,8 @@ private: void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); std::optional RemoveBufferMap(GPUVAddr gpu_addr); - std::shared_ptr nvmap_dev; + NvCore::Container& container; + NvCore::NvMap& nvmap; // This is expected to be ordered, therefore we must use a map, not unordered_map std::map buffer_mappings; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 5e2155e6c..51c40f620 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -279,6 +279,8 @@ Kernel::KEvent* nvhost_ctrl::QueryEvent(u32 event_id) { ASSERT(events_interface.events[slot]); return events_interface.events[slot]; } + // Is this possible in hardware? + ASSERT_MSG(false, "Slot:{}, SyncpointID:{}, requested", slot, syncpoint_id); return nullptr; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index a480bfc47..e7921ade2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -6,6 +6,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" #include "core/hle/service/nvdrv/nvdrv.h" @@ -22,10 +23,10 @@ Tegra::CommandHeader BuildFenceAction(Tegra::GPU::FenceOperation op, u32 syncpoi } } // namespace -nvhost_gpu::nvhost_gpu(Core::System& system_, std::shared_ptr nvmap_dev_, - EventInterface& events_interface_, NvCore::Container& core_) - : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, events_interface{events_interface_}, - core{core_}, syncpoint_manager{core_.GetSyncpointManager()} { +nvhost_gpu::nvhost_gpu(Core::System& system_, EventInterface& events_interface_, + NvCore::Container& core_) + : nvdevice{system_}, events_interface{events_interface_}, core{core_}, + syncpoint_manager{core_.GetSyncpointManager()}, nvmap{core.GetNvMapFile()} { channel_fence.id = syncpoint_manager.AllocateSyncpoint(); channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id); sm_exception_breakpoint_int_report_event = diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 4f73a7bae..440c0c42d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -17,6 +17,7 @@ namespace Service::Nvidia { namespace NvCore { class Container; +class NvMap; class SyncpointManager; } // namespace NvCore @@ -28,8 +29,8 @@ namespace Service::Nvidia::Devices { class nvmap; class nvhost_gpu final : public nvdevice { public: - explicit nvhost_gpu(Core::System& system_, std::shared_ptr nvmap_dev_, - EventInterface& events_interface_, NvCore::Container& core); + explicit nvhost_gpu(Core::System& system_, EventInterface& events_interface_, + NvCore::Container& core); ~nvhost_gpu() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -199,10 +200,10 @@ private: NvResult ChannelSetTimeout(const std::vector& input, std::vector& output); NvResult ChannelSetTimeslice(const std::vector& input, std::vector& output); - std::shared_ptr nvmap_dev; EventInterface& events_interface; NvCore::Container& core; NvCore::SyncpointManager& syncpoint_manager; + NvCore::NvMap& nvmap; NvFence channel_fence; // Events diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 2c9158c7c..aa1a00832 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -10,9 +10,8 @@ namespace Service::Nvidia::Devices { -nvhost_nvdec::nvhost_nvdec(Core::System& system_, std::shared_ptr nvmap_dev_, - NvCore::Container& core) - : nvhost_nvdec_common{system_, std::move(nvmap_dev_), core} {} +nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core) + : nvhost_nvdec_common{system_, core} {} nvhost_nvdec::~nvhost_nvdec() = default; NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 04da4a913..fef4b3216 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -10,8 +10,7 @@ namespace Service::Nvidia::Devices { class nvhost_nvdec final : public nvhost_nvdec_common { public: - explicit nvhost_nvdec(Core::System& system_, std::shared_ptr nvmap_dev_, - NvCore::Container& core); + explicit nvhost_nvdec(Core::System& system_, NvCore::Container& core); ~nvhost_nvdec() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 5a9c59f37..e76c9e5ed 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -9,9 +9,9 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h" -#include "core/hle/service/nvdrv/devices/nvmap.h" #include "core/memory.h" #include "video_core/memory_manager.h" #include "video_core/renderer_base.h" @@ -45,10 +45,9 @@ std::size_t WriteVectors(std::vector& dst, const std::vector& src, std::s } } // Anonymous namespace -nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, std::shared_ptr nvmap_dev_, - NvCore::Container& core_) - : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, core{core_}, - syncpoint_manager{core.GetSyncpointManager()} {} +nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_) + : nvdevice{system_}, core{core_}, + syncpoint_manager{core.GetSyncpointManager()}, nvmap{core.GetNvMapFile()} {} nvhost_nvdec_common::~nvhost_nvdec_common() = default; NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector& input) { @@ -90,10 +89,10 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector& input, } } for (const auto& cmd_buffer : command_buffers) { - const auto object = nvmap_dev->GetObject(cmd_buffer.memory_id); + const auto object = nvmap.GetHandle(cmd_buffer.memory_id); ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;); Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); - system.Memory().ReadBlock(object->addr + cmd_buffer.offset, cmdlist.data(), + system.Memory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(), cmdlist.size() * sizeof(u32)); gpu.PushCommandBuffer(fd_to_id[fd], cmdlist); } @@ -125,6 +124,7 @@ NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector& input, std::ve NvResult nvhost_nvdec_common::GetWaitbase(const std::vector& input, std::vector& output) { IoctlGetWaitbase params{}; + LOG_CRITICAL(Service_NVDRV, "called WAITBASE"); std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); params.value = 0; // Seems to be hard coded at 0 std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase)); @@ -141,7 +141,7 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector& input, std::vecto auto& gpu = system.GPU(); for (auto& cmd_buffer : cmd_buffer_handles) { - auto object{nvmap_dev->GetObject(cmd_buffer.map_handle)}; + auto object{nvmap.GetHandle(cmd_buffer.map_handle)}; if (!object) { LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmd_buffer.map_handle); std::memcpy(output.data(), ¶ms, output.size()); @@ -150,7 +150,8 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector& input, std::vecto if (object->dma_map_addr == 0) { // NVDEC and VIC memory is in the 32-bit address space // MapAllocate32 will attempt to map a lower 32-bit value in the shared gpu memory space - const GPUVAddr low_addr = gpu.MemoryManager().MapAllocate32(object->addr, object->size); + const GPUVAddr low_addr = + gpu.MemoryManager().MapAllocate32(object->address, object->size); object->dma_map_addr = static_cast(low_addr); // Ensure that the dma_map_addr is indeed in the lower 32-bit address space. ASSERT(object->dma_map_addr == low_addr); @@ -158,7 +159,7 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector& input, std::vecto if (!object->dma_map_addr) { LOG_ERROR(Service_NVDRV, "failed to map size={}", object->size); } else { - cmd_buffer.map_address = object->dma_map_addr; + cmd_buffer.map_address = static_cast(object->dma_map_addr); } } std::memcpy(output.data(), ¶ms, sizeof(IoctlMapBuffer)); @@ -184,4 +185,9 @@ NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector& input, return NvResult::Success; } +Kernel::KEvent* nvhost_nvdec_common::QueryEvent(u32 event_id) { + LOG_CRITICAL(Service_NVDRV, "Unknown HOSTX1 Event {}", event_id); + return nullptr; +} + } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index cccc94a58..74231d5c5 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -11,17 +11,16 @@ namespace Service::Nvidia { namespace NvCore { -class SyncpointManager; class Container; +class NvMap; +class SyncpointManager; } // namespace NvCore namespace Devices { -class nvmap; class nvhost_nvdec_common : public nvdevice { public: - explicit nvhost_nvdec_common(Core::System& system_, std::shared_ptr nvmap_dev_, - NvCore::Container& core); + explicit nvhost_nvdec_common(Core::System& system_, NvCore::Container& core); ~nvhost_nvdec_common() override; protected: @@ -114,12 +113,14 @@ protected: NvResult UnmapBuffer(const std::vector& input, std::vector& output); NvResult SetSubmitTimeout(const std::vector& input, std::vector& output); + Kernel::KEvent* QueryEvent(u32 event_id) override; + std::unordered_map fd_to_id{}; s32_le nvmap_fd{}; u32_le submit_timeout{}; - std::shared_ptr nvmap_dev; NvCore::Container& core; NvCore::SyncpointManager& syncpoint_manager; + NvCore::NvMap& nvmap; std::array device_syncpoints{}; }; }; // namespace Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 66558c331..358e89aa8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -8,9 +8,8 @@ #include "video_core/renderer_base.h" namespace Service::Nvidia::Devices { -nvhost_vic::nvhost_vic(Core::System& system_, std::shared_ptr nvmap_dev_, - NvCore::Container& core) - : nvhost_nvdec_common{system_, std::move(nvmap_dev_), core} {} +nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core) + : nvhost_nvdec_common{system_, core} {} nvhost_vic::~nvhost_vic() = default; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index 6f9838b2d..252b1e6f2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -9,8 +9,7 @@ namespace Service::Nvidia::Devices { class nvhost_vic final : public nvhost_nvdec_common { public: - explicit nvhost_vic(Core::System& system_, std::shared_ptr nvmap_dev_, - NvCore::Container& core); + explicit nvhost_vic(Core::System& system_, NvCore::Container& core); ~nvhost_vic(); NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index d8518149d..2aee68f5c 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -2,19 +2,24 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include +#include "common/alignment.h" #include "common/assert.h" #include "common/logging/log.h" +#include "core/core.h" +#include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/devices/nvmap.h" +#include "core/memory.h" + +using Core::Memory::YUZU_PAGESIZE; namespace Service::Nvidia::Devices { -nvmap::nvmap(Core::System& system_) : nvdevice{system_} { - // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to - // represent this. - CreateObject(0); -} +nvmap::nvmap(Core::System& system_, NvCore::Container& container_) + : nvdevice{system_}, container{container_}, file{container.GetNvMapFile()} {} nvmap::~nvmap() = default; @@ -63,38 +68,32 @@ void nvmap::OnOpen(DeviceFD fd) {} void nvmap::OnClose(DeviceFD fd) {} VAddr nvmap::GetObjectAddress(u32 handle) const { - auto object = GetObject(handle); - ASSERT(object); - ASSERT(object->status == Object::Status::Allocated); - return object->addr; + auto obj = file.GetHandle(handle); + if (obj) { + return obj->address; + } + return 0; } -u32 nvmap::CreateObject(u32 size) { - // Create a new nvmap object and obtain a handle to it. - auto object = std::make_shared(); - object->id = next_id++; - object->size = size; - object->status = Object::Status::Created; - object->refcount = 1; - - const u32 handle = next_handle++; - - handles.insert_or_assign(handle, std::move(object)); - - return handle; +std::shared_ptr nvmap::GetObject(u32 handle) const { + return file.GetHandle(handle); } NvResult nvmap::IocCreate(const std::vector& input, std::vector& output) { IocCreateParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); - - if (!params.size) { - LOG_ERROR(Service_NVDRV, "Size is 0"); - return NvResult::BadValue; + LOG_WARNING(Service_NVDRV, "called, size=0x{:08X}", params.size); + + std::shared_ptr handle_description{}; + auto result = + file.CreateHandle(Common::AlignUp(params.size, YUZU_PAGESIZE), handle_description); + if (result != NvResult::Success) { + LOG_CRITICAL(Service_NVDRV, "Failed to create Object"); + return result; } - - params.handle = CreateObject(params.size); + handle_description->orig_size = params.size; // Orig size is the unaligned size + params.handle = handle_description->id; + LOG_DEBUG(Service_NVDRV, "handle: {}, size: 0x{:X}", handle_description->id, params.size); std::memcpy(output.data(), ¶ms, sizeof(params)); return NvResult::Success; @@ -103,42 +102,42 @@ NvResult nvmap::IocCreate(const std::vector& input, std::vector& output) NvResult nvmap::IocAlloc(const std::vector& input, std::vector& output) { IocAllocParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); + LOG_WARNING(Service_NVDRV, "called, addr={:X}", params.address); if (!params.handle) { - LOG_ERROR(Service_NVDRV, "Handle is 0"); + LOG_CRITICAL(Service_NVDRV, "Handle is 0"); return NvResult::BadValue; } if ((params.align - 1) & params.align) { - LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align); + LOG_CRITICAL(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align); return NvResult::BadValue; } - const u32 min_alignment = 0x1000; - if (params.align < min_alignment) { - params.align = min_alignment; + // Force page size alignment at a minimum + if (params.align < YUZU_PAGESIZE) { + params.align = YUZU_PAGESIZE; } - auto object = GetObject(params.handle); - if (!object) { - LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); + auto handle_description{file.GetHandle(params.handle)}; + if (!handle_description) { + LOG_CRITICAL(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); return NvResult::BadValue; } - if (object->status == Object::Status::Allocated) { - LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); + if (handle_description->allocated) { + LOG_CRITICAL(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); return NvResult::InsufficientMemory; } - object->flags = params.flags; - object->align = params.align; - object->kind = params.kind; - object->addr = params.addr; - object->status = Object::Status::Allocated; - + const auto result = + handle_description->Alloc(params.flags, params.align, params.kind, params.address); + if (result != NvResult::Success) { + LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle); + return result; + } std::memcpy(output.data(), ¶ms, sizeof(params)); - return NvResult::Success; + return result; } NvResult nvmap::IocGetId(const std::vector& input, std::vector& output) { @@ -147,19 +146,20 @@ NvResult nvmap::IocGetId(const std::vector& input, std::vector& output) LOG_WARNING(Service_NVDRV, "called"); + // See the comment in FromId for extra info on this function if (!params.handle) { - LOG_ERROR(Service_NVDRV, "Handle is zero"); + LOG_CRITICAL(Service_NVDRV, "Error!"); return NvResult::BadValue; } - auto object = GetObject(params.handle); - if (!object) { - LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); - return NvResult::BadValue; + auto handle_description{file.GetHandle(params.handle)}; + if (!handle_description) { + LOG_CRITICAL(Service_NVDRV, "Error!"); + return NvResult::AccessDenied; // This will always return EPERM irrespective of if the + // handle exists or not } - params.id = object->id; - + params.id = handle_description->id; std::memcpy(output.data(), ¶ms, sizeof(params)); return NvResult::Success; } @@ -168,26 +168,29 @@ NvResult nvmap::IocFromId(const std::vector& input, std::vector& output) IocFromIdParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_WARNING(Service_NVDRV, "(STUBBED) called"); + LOG_WARNING(Service_NVDRV, "called, id:{}"); - auto itr = std::find_if(handles.begin(), handles.end(), - [&](const auto& entry) { return entry.second->id == params.id; }); - if (itr == handles.end()) { - LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); + // Handles and IDs are always the same value in nvmap however IDs can be used globally given the + // right permissions. + // Since we don't plan on ever supporting multiprocess we can skip implementing handle refs and + // so this function just does simple validation and passes through the handle id. + if (!params.id) { + LOG_CRITICAL(Service_NVDRV, "Error!"); return NvResult::BadValue; } - auto& object = itr->second; - if (object->status != Object::Status::Allocated) { - LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); + auto handle_description{file.GetHandle(params.id)}; + if (!handle_description) { + LOG_CRITICAL(Service_NVDRV, "Error!"); return NvResult::BadValue; } - itr->second->refcount++; - - // Return the existing handle instead of creating a new one. - params.handle = itr->first; - + auto result = handle_description->Duplicate(false); + if (result != NvResult::Success) { + LOG_CRITICAL(Service_NVDRV, "Error!"); + return result; + } + params.handle = handle_description->id; std::memcpy(output.data(), ¶ms, sizeof(params)); return NvResult::Success; } @@ -198,35 +201,43 @@ NvResult nvmap::IocParam(const std::vector& input, std::vector& output) IocParamParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_DEBUG(Service_NVDRV, "(STUBBED) called type={}", params.param); + LOG_WARNING(Service_NVDRV, "called type={}", params.param); - auto object = GetObject(params.handle); - if (!object) { - LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); + if (!params.handle) { + LOG_CRITICAL(Service_NVDRV, "Error!"); return NvResult::BadValue; } - if (object->status != Object::Status::Allocated) { - LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); + auto handle_description{file.GetHandle(params.handle)}; + if (!handle_description) { + LOG_CRITICAL(Service_NVDRV, "Error!"); return NvResult::BadValue; } - switch (static_cast(params.param)) { - case ParamTypes::Size: - params.result = object->size; + switch (params.param) { + case HandleParameterType::Size: + params.result = static_cast(handle_description->orig_size); + break; + case HandleParameterType::Alignment: + params.result = static_cast(handle_description->align); break; - case ParamTypes::Alignment: - params.result = object->align; + case HandleParameterType::Base: + params.result = static_cast(-22); // posix EINVAL break; - case ParamTypes::Heap: - // TODO(Subv): Seems to be a hardcoded value? - params.result = 0x40000000; + case HandleParameterType::Heap: + if (handle_description->allocated) + params.result = 0x40000000; + else + params.result = 0x40000000; break; - case ParamTypes::Kind: - params.result = object->kind; + case HandleParameterType::Kind: + params.result = handle_description->kind; + break; + case HandleParameterType::IsSharedMemMapped: + params.result = handle_description->is_shared_mem_mapped; break; default: - UNIMPLEMENTED(); + return NvResult::BadValue; } std::memcpy(output.data(), ¶ms, sizeof(params)); @@ -234,46 +245,25 @@ NvResult nvmap::IocParam(const std::vector& input, std::vector& output) } NvResult nvmap::IocFree(const std::vector& input, std::vector& output) { - // TODO(Subv): These flags are unconfirmed. - enum FreeFlags { - Freed = 0, - NotFreedYet = 1, - }; - IocFreeParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_DEBUG(Service_NVDRV, "(STUBBED) called"); + LOG_WARNING(Service_NVDRV, "called"); - auto itr = handles.find(params.handle); - if (itr == handles.end()) { - LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); - return NvResult::BadValue; - } - if (!itr->second->refcount) { - LOG_ERROR( - Service_NVDRV, - "There is no references to this object. The object is already freed. handle={:08X}", - params.handle); - return NvResult::BadValue; + if (!params.handle) { + LOG_CRITICAL(Service_NVDRV, "Handle null freed?"); + return NvResult::Success; } - itr->second->refcount--; - - params.size = itr->second->size; - - if (itr->second->refcount == 0) { - params.flags = Freed; - // The address of the nvmap is written to the output if we're finally freeing it, otherwise - // 0 is written. - params.address = itr->second->addr; + if (auto freeInfo{file.FreeHandle(params.handle, false)}) { + params.address = freeInfo->address; + params.size = static_cast(freeInfo->size); + params.flags = NvCore::NvMap::Handle::Flags{.map_uncached = freeInfo->was_uncached}; } else { - params.flags = NotFreedYet; - params.address = 0; + // This is possible when there's internel dups or other duplicates. + LOG_CRITICAL(Service_NVDRV, "Not freed"); } - handles.erase(params.handle); - std::memcpy(output.data(), ¶ms, sizeof(params)); return NvResult::Success; } diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index d5360d6e5..c22eb57a4 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -9,15 +9,23 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" +#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" +namespace Service::Nvidia::NvCore { +class Container; +} // namespace Service::Nvidia::NvCore + namespace Service::Nvidia::Devices { class nvmap final : public nvdevice { public: - explicit nvmap(Core::System& system_); + explicit nvmap(Core::System& system_, NvCore::Container& container); ~nvmap() override; + nvmap(nvmap const&) = delete; + nvmap& operator=(nvmap const&) = delete; + NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, std::vector& output) override; NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector& input, @@ -31,27 +39,16 @@ public: /// Returns the allocated address of an nvmap object given its handle. VAddr GetObjectAddress(u32 handle) const; - /// Represents an nvmap object. - struct Object { - enum class Status { Created, Allocated }; - u32 id; - u32 size; - u32 flags; - u32 align; - u8 kind; - VAddr addr; - Status status; - u32 refcount; - u32 dma_map_addr; - }; + std::shared_ptr GetObject(u32 handle) const; - std::shared_ptr GetObject(u32 handle) const { - auto itr = handles.find(handle); - if (itr != handles.end()) { - return itr->second; - } - return {}; - } + enum class HandleParameterType : u32_le { + Size = 1, + Alignment = 2, + Base = 3, + Heap = 4, + Kind = 5, + IsSharedMemMapped = 6 + }; private: /// Id to use for the next handle that is created. @@ -60,9 +57,6 @@ private: /// Id to use for the next object that is created. u32 next_id = 0; - /// Mapping of currently allocated handles to the objects they represent. - std::unordered_map> handles; - struct IocCreateParams { // Input u32_le size{}; @@ -83,11 +77,11 @@ private: // Input u32_le handle{}; u32_le heap_mask{}; - u32_le flags{}; + NvCore::NvMap::Handle::Flags flags{}; u32_le align{}; u8 kind{}; INSERT_PADDING_BYTES(7); - u64_le addr{}; + u64_le address{}; }; static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size"); @@ -96,14 +90,14 @@ private: INSERT_PADDING_BYTES(4); u64_le address{}; u32_le size{}; - u32_le flags{}; + NvCore::NvMap::Handle::Flags flags{}; }; static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size"); struct IocParamParams { // Input u32_le handle{}; - u32_le param{}; + HandleParameterType param{}; // Output u32_le result{}; }; @@ -117,14 +111,15 @@ private: }; static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); - u32 CreateObject(u32 size); - NvResult IocCreate(const std::vector& input, std::vector& output); NvResult IocAlloc(const std::vector& input, std::vector& output); NvResult IocGetId(const std::vector& input, std::vector& output); NvResult IocFromId(const std::vector& input, std::vector& output); NvResult IocParam(const std::vector& input, std::vector& output); NvResult IocFree(const std::vector& input, std::vector& output); + + NvCore::Container& container; + NvCore::NvMap& file; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 824c0e290..f4914d539 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -138,21 +138,18 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger Module::Module(Core::System& system) : service_context{system, "nvdrv"}, events_interface{*this}, container{system.GPU()} { - auto nvmap_dev = std::make_shared(system); - devices["/dev/nvhost-as-gpu"] = std::make_shared(system, nvmap_dev); + devices["/dev/nvhost-as-gpu"] = std::make_shared(system, container); devices["/dev/nvhost-gpu"] = - std::make_shared(system, nvmap_dev, events_interface, container); + std::make_shared(system, events_interface, container); devices["/dev/nvhost-ctrl-gpu"] = std::make_shared(system, events_interface); - devices["/dev/nvmap"] = nvmap_dev; - devices["/dev/nvdisp_disp0"] = std::make_shared(system, nvmap_dev); + devices["/dev/nvmap"] = std::make_shared(system, container); + devices["/dev/nvdisp_disp0"] = std::make_shared(system, container); devices["/dev/nvhost-ctrl"] = std::make_shared(system, events_interface, container); - devices["/dev/nvhost-nvdec"] = - std::make_shared(system, nvmap_dev, container); + devices["/dev/nvhost-nvdec"] = std::make_shared(system, container); devices["/dev/nvhost-nvjpg"] = std::make_shared(system); - devices["/dev/nvhost-vic"] = - std::make_shared(system, nvmap_dev, container); + devices["/dev/nvhost-vic"] = std::make_shared(system, container); } Module::~Module() = default; -- cgit v1.2.3 From af35dbcf633d35450b333eb33334b3dd1bc050a1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 5 Nov 2021 01:44:11 +0100 Subject: NVDRV: Fix Open/Close and make sure each device is correctly created. --- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 176 ++++++++++++++++----- src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 42 +++++ .../hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 9 +- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 12 +- .../hle/service/nvdrv/devices/nvhost_nvdec.cpp | 2 + src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | 2 +- .../service/nvdrv/devices/nvhost_nvdec_common.cpp | 2 + .../service/nvdrv/devices/nvhost_nvdec_common.h | 2 +- src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | 3 + src/core/hle/service/nvdrv/devices/nvhost_vic.h | 2 +- src/core/hle/service/nvdrv/nvdrv.cpp | 174 ++++++++------------ src/core/hle/service/nvdrv/nvdrv.h | 56 ++----- src/core/hle/service/nvflinger/nvflinger.cpp | 7 +- src/core/hle/service/nvflinger/nvflinger.h | 1 + 14 files changed, 291 insertions(+), 199 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 51c40f620..122c1d5e1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -3,9 +3,11 @@ // SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3 // or any later version Refer to the license.txt file included. +#include #include #include +#include #include "common/assert.h" #include "common/logging/log.h" #include "common/scope_exit.h" @@ -22,8 +24,19 @@ namespace Service::Nvidia::Devices { nvhost_ctrl::nvhost_ctrl(Core::System& system_, EventInterface& events_interface_, NvCore::Container& core_) : nvdevice{system_}, events_interface{events_interface_}, core{core_}, - syncpoint_manager{core_.GetSyncpointManager()} {} -nvhost_ctrl::~nvhost_ctrl() = default; + syncpoint_manager{core_.GetSyncpointManager()} { + events_interface.RegisterForSignal(this); +} + +nvhost_ctrl::~nvhost_ctrl() { + events_interface.UnregisterForSignal(this); + for (auto& event : events) { + if (!event.registered) { + continue; + } + events_interface.FreeEvent(event.kevent); + } +} NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, std::vector& output) { @@ -87,7 +100,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector SCOPE_EXIT({ std::memcpy(output.data(), ¶ms, sizeof(params)); if (must_unmark_fail) { - events_interface.fails[event_id] = 0; + events[event_id].fails = 0; } }); @@ -116,12 +129,12 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector auto& gpu = system.GPU(); const u32 target_value = params.fence.value; - auto lock = events_interface.Lock(); + auto lock = NvEventsLock(); u32 slot = [&]() { if (is_allocation) { params.value.raw = 0; - return events_interface.FindFreeEvent(fence_id); + return FindFreeNvEvent(fence_id); } else { return params.value.raw; } @@ -130,7 +143,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector must_unmark_fail = true; const auto check_failing = [&]() { - if (events_interface.fails[slot] > 2) { + if (events[slot].fails > 2) { { auto lk = system.StallProcesses(); gpu.WaitFence(fence_id, target_value); @@ -142,6 +155,10 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector return false; }; + if (slot >= MaxNvEvents) { + return NvResult::BadParameter; + } + if (params.timeout == 0) { if (check_failing()) { return NvResult::Success; @@ -149,17 +166,13 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector return NvResult::Timeout; } - if (slot >= MaxNvEvents) { - return NvResult::BadParameter; - } - - auto* event = events_interface.events[slot]; + auto& event = events[slot]; - if (!event) { + if (!event.registered) { return NvResult::BadParameter; } - if (events_interface.IsBeingUsed(slot)) { + if (event.IsBeingUsed()) { return NvResult::BadParameter; } @@ -169,9 +182,9 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector params.value.raw = 0; - events_interface.status[slot].store(EventState::Waiting, std::memory_order_release); - events_interface.assigned_syncpt[slot] = fence_id; - events_interface.assigned_value[slot] = target_value; + event.status.store(EventState::Waiting, std::memory_order_release); + event.assigned_syncpt = fence_id; + event.assigned_value = target_value; if (is_allocation) { params.value.syncpoint_id_for_allocation.Assign(static_cast(fence_id)); params.value.event_allocated.Assign(1); @@ -189,15 +202,17 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) { return NvResult::BadParameter; } - if (!events_interface.registered[slot]) { + auto& event = events[slot]; + + if (!event.registered) { return NvResult::Success; } - if (events_interface.IsBeingUsed(slot)) { + if (event.IsBeingUsed()) { return NvResult::Busy; } - events_interface.Free(slot); + FreeNvEvent(slot); return NvResult::Success; } @@ -210,15 +225,15 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector& input, std::ve return NvResult::BadParameter; } - auto lock = events_interface.Lock(); + auto lock = NvEventsLock(); - if (events_interface.registered[event_id]) { + if (events[event_id].registered) { const auto result = FreeEvent(event_id); if (result != NvResult::Success) { return result; } } - events_interface.Create(event_id); + CreateNvEvent(event_id); return NvResult::Success; } @@ -229,7 +244,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector& input, const u32 event_id = params.user_event_id & 0x00FF; LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id); - auto lock = events_interface.Lock(); + auto lock = NvEventsLock(); return FreeEvent(event_id); } @@ -244,44 +259,121 @@ NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector& input, std::v return NvResult::BadParameter; } - auto lock = events_interface.Lock(); + auto lock = NvEventsLock(); - if (events_interface.status[event_id].exchange( - EventState::Cancelling, std::memory_order_acq_rel) == EventState::Waiting) { - system.GPU().CancelSyncptInterrupt(events_interface.assigned_syncpt[event_id], - events_interface.assigned_value[event_id]); - syncpoint_manager.RefreshSyncpoint(events_interface.assigned_syncpt[event_id]); + auto& event = events[event_id]; + if (event.status.exchange(EventState::Cancelling, std::memory_order_acq_rel) == + EventState::Waiting) { + system.GPU().CancelSyncptInterrupt(event.assigned_syncpt, event.assigned_value); + syncpoint_manager.RefreshSyncpoint(event.assigned_syncpt); } - events_interface.fails[event_id]++; - events_interface.status[event_id].store(EventState::Cancelled, std::memory_order_release); - events_interface.events[event_id]->GetWritableEvent().Clear(); + event.fails++; + event.status.store(EventState::Cancelled, std::memory_order_release); + event.kevent->GetWritableEvent().Clear(); return NvResult::Success; } Kernel::KEvent* nvhost_ctrl::QueryEvent(u32 event_id) { - const auto event = SyncpointEventValue{.raw = event_id}; + const auto desired_event = SyncpointEventValue{.raw = event_id}; - const bool allocated = event.event_allocated.Value() != 0; - const u32 slot{allocated ? event.partial_slot.Value() : static_cast(event.slot)}; + const bool allocated = desired_event.event_allocated.Value() != 0; + const u32 slot{allocated ? desired_event.partial_slot.Value() + : static_cast(desired_event.slot)}; if (slot >= MaxNvEvents) { ASSERT(false); return nullptr; } - const u32 syncpoint_id{allocated ? event.syncpoint_id_for_allocation.Value() - : event.syncpoint_id.Value()}; + const u32 syncpoint_id{allocated ? desired_event.syncpoint_id_for_allocation.Value() + : desired_event.syncpoint_id.Value()}; - auto lock = events_interface.Lock(); + auto lock = NvEventsLock(); - if (events_interface.registered[slot] && - events_interface.assigned_syncpt[slot] == syncpoint_id) { - ASSERT(events_interface.events[slot]); - return events_interface.events[slot]; + auto& event = events[slot]; + if (event.registered && event.assigned_syncpt == syncpoint_id) { + ASSERT(event.kevent); + return event.kevent; } // Is this possible in hardware? ASSERT_MSG(false, "Slot:{}, SyncpointID:{}, requested", slot, syncpoint_id); return nullptr; } +std::unique_lock nvhost_ctrl::NvEventsLock() { + return std::unique_lock(events_mutex); +} + +void nvhost_ctrl::CreateNvEvent(u32 event_id) { + auto& event = events[event_id]; + ASSERT(!event.kevent); + ASSERT(!event.registered); + ASSERT(!event.IsBeingUsed()); + event.kevent = events_interface.CreateEvent(fmt::format("NVCTRL::NvEvent_{}", event_id)); + event.status = EventState::Available; + event.registered = true; + const u64 mask = 1ULL << event_id; + event.fails = 0; + events_mask |= mask; + event.assigned_syncpt = 0; +} + +void nvhost_ctrl::FreeNvEvent(u32 event_id) { + auto& event = events[event_id]; + ASSERT(event.kevent); + ASSERT(event.registered); + ASSERT(!event.IsBeingUsed()); + events_interface.FreeEvent(event.kevent); + event.kevent = nullptr; + event.status = EventState::Available; + event.registered = false; + const u64 mask = ~(1ULL << event_id); + events_mask &= mask; +} + +u32 nvhost_ctrl::FindFreeNvEvent(u32 syncpoint_id) { + u32 slot{MaxNvEvents}; + u32 free_slot{MaxNvEvents}; + for (u32 i = 0; i < MaxNvEvents; i++) { + auto& event = events[i]; + if (event.registered) { + if (!event.IsBeingUsed()) { + slot = i; + if (event.assigned_syncpt == syncpoint_id) { + return slot; + } + } + } else if (free_slot == MaxNvEvents) { + free_slot = i; + } + } + if (free_slot < MaxNvEvents) { + CreateNvEvent(free_slot); + return free_slot; + } + + if (slot < MaxNvEvents) { + return slot; + } + + LOG_CRITICAL(Service_NVDRV, "Failed to allocate an event"); + return 0; +} + +void nvhost_ctrl::SignalNvEvent(u32 syncpoint_id, u32 value) { + const u32 max = MaxNvEvents - std::countl_zero(events_mask); + const u32 min = std::countr_zero(events_mask); + for (u32 i = min; i < max; i++) { + auto& event = events[i]; + if (event.assigned_syncpt != syncpoint_id || event.assigned_value != value) { + continue; + } + if (event.status.exchange(EventState::Signalling, std::memory_order_acq_rel) == + EventState::Waiting) { + event.kevent->GetWritableEvent().Signal(); + } + event.status.store(EventState::Signalled, std::memory_order_release); + } +} + } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 9fd46ea5f..f2fc5d047 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -53,7 +53,49 @@ public: }; static_assert(sizeof(SyncpointEventValue) == sizeof(u32)); + void SignalNvEvent(u32 syncpoint_id, u32 value); + private: + struct InternalEvent { + // Mask representing registered events + + // Each kernel event associated to an NV event + Kernel::KEvent* kevent{}; + // The status of the current NVEvent + std::atomic status{}; + + // Tells the NVEvent that it has failed. + u32 fails{}; + // When an NVEvent is waiting on GPU interrupt, this is the sync_point + // associated with it. + u32 assigned_syncpt{}; + // This is the value of the GPU interrupt for which the NVEvent is waiting + // for. + u32 assigned_value{}; + + // Tells if an NVEvent is registered or not + bool registered{}; + + bool IsBeingUsed() { + const auto current_status = status.load(std::memory_order_acquire); + return current_status == EventState::Waiting || + current_status == EventState::Cancelling || + current_status == EventState::Signalling; + } + }; + + std::unique_lock NvEventsLock(); + + void CreateNvEvent(u32 event_id); + + void FreeNvEvent(u32 event_id); + + u32 FindFreeNvEvent(u32 syncpoint_id); + + std::array events{}; + std::mutex events_mutex; + u64 events_mask{}; + struct IocSyncptReadParams { u32_le id{}; u32_le value{}; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index e353408eb..ced57dfe6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -13,10 +13,13 @@ namespace Service::Nvidia::Devices { nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_) : nvdevice{system_}, events_interface{events_interface_} { - error_notifier_event = events_interface.CreateNonCtrlEvent("CtrlGpuErrorNotifier"); - unknown_event = events_interface.CreateNonCtrlEvent("CtrlGpuUknownEvent"); + error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier"); + unknown_event = events_interface.CreateEvent("CtrlGpuUknownEvent"); +} +nvhost_ctrl_gpu::~nvhost_ctrl_gpu() { + events_interface.FreeEvent(error_notifier_event); + events_interface.FreeEvent(unknown_event); } -nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, std::vector& output) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index e7921ade2..cb54ee5a4 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -30,13 +30,17 @@ nvhost_gpu::nvhost_gpu(Core::System& system_, EventInterface& events_interface_, channel_fence.id = syncpoint_manager.AllocateSyncpoint(); channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id); sm_exception_breakpoint_int_report_event = - events_interface.CreateNonCtrlEvent("GpuChannelSMExceptionBreakpointInt"); + events_interface.CreateEvent("GpuChannelSMExceptionBreakpointInt"); sm_exception_breakpoint_pause_report_event = - events_interface.CreateNonCtrlEvent("GpuChannelSMExceptionBreakpointPause"); - error_notifier_event = events_interface.CreateNonCtrlEvent("GpuChannelErrorNotifier"); + events_interface.CreateEvent("GpuChannelSMExceptionBreakpointPause"); + error_notifier_event = events_interface.CreateEvent("GpuChannelErrorNotifier"); } -nvhost_gpu::~nvhost_gpu() = default; +nvhost_gpu::~nvhost_gpu() { + events_interface.FreeEvent(sm_exception_breakpoint_int_report_event); + events_interface.FreeEvent(sm_exception_breakpoint_pause_report_event); + events_interface.FreeEvent(error_notifier_event); +} NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, std::vector& output) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index aa1a00832..00947ea19 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -10,6 +10,8 @@ namespace Service::Nvidia::Devices { +u32 nvhost_nvdec::next_id{}; + nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core) : nvhost_nvdec_common{system_, core} {} nvhost_nvdec::~nvhost_nvdec() = default; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index fef4b3216..3261ce1d4 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -24,7 +24,7 @@ public: void OnClose(DeviceFD fd) override; private: - u32 next_id{}; + static u32 next_id; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index e76c9e5ed..77e6a1cd6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -45,6 +45,8 @@ std::size_t WriteVectors(std::vector& dst, const std::vector& src, std::s } } // Anonymous namespace +std::unordered_map nvhost_nvdec_common::fd_to_id{}; + nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_) : nvdevice{system_}, core{core_}, syncpoint_manager{core.GetSyncpointManager()}, nvmap{core.GetNvMapFile()} {} diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index 74231d5c5..53029af6a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -115,7 +115,7 @@ protected: Kernel::KEvent* QueryEvent(u32 event_id) override; - std::unordered_map fd_to_id{}; + static std::unordered_map fd_to_id; s32_le nvmap_fd{}; u32_le submit_timeout{}; NvCore::Container& core; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 358e89aa8..c89ff6b27 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -8,6 +8,9 @@ #include "video_core/renderer_base.h" namespace Service::Nvidia::Devices { + +u32 nvhost_vic::next_id{}; + nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core) : nvhost_nvdec_common{system_, core} {} diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index 252b1e6f2..59e23b41e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -23,6 +23,6 @@ public: void OnClose(DeviceFD fd) override; private: - u32 next_id{}; + static u32 next_id; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index f4914d539..ff8c7c13c 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3 // or any later version Refer to the license.txt file included. -#include #include #include @@ -30,101 +29,39 @@ namespace Service::Nvidia { -EventInterface::EventInterface(Module& module_) : module{module_} { - events_mask = 0; - for (u32 i = 0; i < MaxNvEvents; i++) { - status[i] = EventState::Available; - events[i] = nullptr; - registered[i] = false; - } -} +EventInterface::EventInterface(Module& module_) : module{module_} {} -EventInterface::~EventInterface() { - auto lk = Lock(); - for (u32 i = 0; i < MaxNvEvents; i++) { - if (registered[i]) { - module.service_context.CloseEvent(events[i]); - events[i] = nullptr; - registered[i] = false; - } - } - for (auto* event : basic_events) { - module.service_context.CloseEvent(event); - } -} +EventInterface::~EventInterface() = default; -std::unique_lock EventInterface::Lock() { - return std::unique_lock(events_mutex); +void EventInterface::RegisterForSignal(Devices::nvhost_ctrl* device) { + std::unique_lock lk(guard); + on_signal.push_back(device); } -void EventInterface::Signal(u32 event_id) { - if (status[event_id].exchange(EventState::Signalling, std::memory_order_acq_rel) == - EventState::Waiting) { - events[event_id]->GetWritableEvent().Signal(); +void EventInterface::UnregisterForSignal(Devices::nvhost_ctrl* device) { + std::unique_lock lk(guard); + auto it = std::find(on_signal.begin(), on_signal.end(), device); + if (it != on_signal.end()) { + on_signal.erase(it); } - status[event_id].store(EventState::Signalled, std::memory_order_release); -} - -void EventInterface::Create(u32 event_id) { - ASSERT(!events[event_id]); - ASSERT(!registered[event_id]); - ASSERT(!IsBeingUsed(event_id)); - events[event_id] = - module.service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", event_id)); - status[event_id] = EventState::Available; - registered[event_id] = true; - const u64 mask = 1ULL << event_id; - fails[event_id] = 0; - events_mask |= mask; - assigned_syncpt[event_id] = 0; -} - -void EventInterface::Free(u32 event_id) { - ASSERT(events[event_id]); - ASSERT(registered[event_id]); - ASSERT(!IsBeingUsed(event_id)); - module.service_context.CloseEvent(events[event_id]); - events[event_id] = nullptr; - status[event_id] = EventState::Available; - registered[event_id] = false; - const u64 mask = ~(1ULL << event_id); - events_mask &= mask; } -u32 EventInterface::FindFreeEvent(u32 syncpoint_id) { - u32 slot{MaxNvEvents}; - u32 free_slot{MaxNvEvents}; - for (u32 i = 0; i < MaxNvEvents; i++) { - if (registered[i]) { - if (!IsBeingUsed(i)) { - slot = i; - if (assigned_syncpt[i] == syncpoint_id) { - return slot; - } - } - } else if (free_slot == MaxNvEvents) { - free_slot = i; - } +void EventInterface::Signal(u32 syncpoint_id, u32 value) { + std::unique_lock lk(guard); + for (auto* device : on_signal) { + device->SignalNvEvent(syncpoint_id, value); } - if (free_slot < MaxNvEvents) { - Create(free_slot); - return free_slot; - } - - if (slot < MaxNvEvents) { - return slot; - } - - LOG_CRITICAL(Service_NVDRV, "Failed to allocate an event"); - return 0; } -Kernel::KEvent* EventInterface::CreateNonCtrlEvent(std::string name) { +Kernel::KEvent* EventInterface::CreateEvent(std::string name) { Kernel::KEvent* new_event = module.service_context.CreateEvent(std::move(name)); - basic_events.push_back(new_event); return new_event; } +void EventInterface::FreeEvent(Kernel::KEvent* event) { + module.service_context.CloseEvent(event); +} + void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, Core::System& system) { auto module_ = std::make_shared(system); @@ -138,18 +75,50 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger Module::Module(Core::System& system) : service_context{system, "nvdrv"}, events_interface{*this}, container{system.GPU()} { - devices["/dev/nvhost-as-gpu"] = std::make_shared(system, container); - devices["/dev/nvhost-gpu"] = - std::make_shared(system, events_interface, container); - devices["/dev/nvhost-ctrl-gpu"] = - std::make_shared(system, events_interface); - devices["/dev/nvmap"] = std::make_shared(system, container); - devices["/dev/nvdisp_disp0"] = std::make_shared(system, container); - devices["/dev/nvhost-ctrl"] = - std::make_shared(system, events_interface, container); - devices["/dev/nvhost-nvdec"] = std::make_shared(system, container); - devices["/dev/nvhost-nvjpg"] = std::make_shared(system); - devices["/dev/nvhost-vic"] = std::make_shared(system, container); + builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) { + std::shared_ptr device = + std::make_shared(system, container); + return open_files.emplace(fd, device).first; + }; + builders["/dev/nvhost-gpu"] = [this, &system](DeviceFD fd) { + std::shared_ptr device = + std::make_shared(system, events_interface, container); + return open_files.emplace(fd, device).first; + }; + builders["/dev/nvhost-ctrl-gpu"] = [this, &system](DeviceFD fd) { + std::shared_ptr device = + std::make_shared(system, events_interface); + return open_files.emplace(fd, device).first; + }; + builders["/dev/nvmap"] = [this, &system](DeviceFD fd) { + std::shared_ptr device = + std::make_shared(system, container); + return open_files.emplace(fd, device).first; + }; + builders["/dev/nvdisp_disp0"] = [this, &system](DeviceFD fd) { + std::shared_ptr device = + std::make_shared(system, container); + return open_files.emplace(fd, device).first; + }; + builders["/dev/nvhost-ctrl"] = [this, &system](DeviceFD fd) { + std::shared_ptr device = + std::make_shared(system, events_interface, container); + return open_files.emplace(fd, device).first; + }; + builders["/dev/nvhost-nvdec"] = [this, &system](DeviceFD fd) { + std::shared_ptr device = + std::make_shared(system, container); + return open_files.emplace(fd, device).first; + }; + builders["/dev/nvhost-nvjpg"] = [this, &system](DeviceFD fd) { + std::shared_ptr device = std::make_shared(system); + return open_files.emplace(fd, device).first; + }; + builders["/dev/nvhost-vic"] = [this, &system](DeviceFD fd) { + std::shared_ptr device = + std::make_shared(system, container); + return open_files.emplace(fd, device).first; + }; } Module::~Module() = default; @@ -169,18 +138,18 @@ NvResult Module::VerifyFD(DeviceFD fd) const { } DeviceFD Module::Open(const std::string& device_name) { - if (devices.find(device_name) == devices.end()) { + auto it = builders.find(device_name); + if (it == builders.end()) { LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); return INVALID_NVDRV_FD; } - auto device = devices[device_name]; const DeviceFD fd = next_fd++; + auto& builder = it->second; + auto device = builder(fd)->second; device->OnOpen(fd); - open_files[fd] = std::move(device); - return fd; } @@ -256,14 +225,7 @@ NvResult Module::Close(DeviceFD fd) { } void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { - const u32 max = MaxNvEvents - std::countl_zero(events_interface.events_mask); - const u32 min = std::countr_zero(events_interface.events_mask); - for (u32 i = min; i < max; i++) { - if (events_interface.assigned_syncpt[i] == syncpoint_id && - events_interface.assigned_value[i] == value) { - events_interface.Signal(i); - } - } + events_interface.Signal(syncpoint_id, value); } NvResult Module::QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event) { diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 96adf2ffb..3983794bb 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -5,6 +5,7 @@ #pragma once +#include #include #include #include @@ -38,7 +39,8 @@ class SyncpointManager; namespace Devices { class nvdevice; -} +class nvhost_ctrl; +} // namespace Devices class Module; @@ -47,47 +49,19 @@ public: EventInterface(Module& module_); ~EventInterface(); - // Mask representing registered events - u64 events_mask{}; - // Each kernel event associated to an NV event - std::array events{}; - // The status of the current NVEvent - std::array, MaxNvEvents> status{}; - // Tells if an NVEvent is registered or not - std::array registered{}; - // Tells the NVEvent that it has failed. - std::array fails{}; - // When an NVEvent is waiting on GPU interrupt, this is the sync_point - // associated with it. - std::array assigned_syncpt{}; - // This is the value of the GPU interrupt for which the NVEvent is waiting - // for. - std::array assigned_value{}; - // Constant to denote an unasigned syncpoint. - static constexpr u32 unassigned_syncpt = 0xFFFFFFFF; - - bool IsBeingUsed(u32 event_id) { - const auto current_status = status[event_id].load(std::memory_order_acquire); - return current_status == EventState::Waiting || current_status == EventState::Cancelling || - current_status == EventState::Signalling; - } - - std::unique_lock Lock(); - - void Signal(u32 event_id); - - void Create(u32 event_id); + void RegisterForSignal(Devices::nvhost_ctrl*); + void UnregisterForSignal(Devices::nvhost_ctrl*); - void Free(u32 event_id); + void Signal(u32 syncpoint_id, u32 value); - u32 FindFreeEvent(u32 syncpoint_id); + Kernel::KEvent* CreateEvent(std::string name); - Kernel::KEvent* CreateNonCtrlEvent(std::string name); + void FreeEvent(Kernel::KEvent* event); private: - std::mutex events_mutex; Module& module; - std::vector basic_events; + std::mutex guard; + std::list on_signal; }; class Module final { @@ -97,9 +71,9 @@ public: /// Returns a pointer to one of the available devices, identified by its name. template - std::shared_ptr GetDevice(const std::string& name) { - auto itr = devices.find(name); - if (itr == devices.end()) + std::shared_ptr GetDevice(DeviceFD fd) { + auto itr = open_files.find(fd); + if (itr == open_files.end()) return nullptr; return std::static_pointer_cast(itr->second); } @@ -132,8 +106,9 @@ private: /// Id to use for the next open file descriptor. DeviceFD next_fd = 1; + using FilesContainerType = std::unordered_map>; /// Mapping of file descriptors to the devices they reference. - std::unordered_map> open_files; + FilesContainerType open_files; /// Mapping of device node names to their implementation. std::unordered_map> devices; @@ -147,6 +122,7 @@ private: void CreateEvent(u32 event_id); void FreeEvent(u32 event_id); + std::unordered_map> builders; }; /// Registers all NVDRV services with the specified service manager. diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 4246e5e25..8c3013f83 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -105,10 +105,15 @@ NVFlinger::~NVFlinger() { display.GetLayer(layer).Core().NotifyShutdown(); } } + + if (nvdrv) { + nvdrv->Close(disp_fd); + } } void NVFlinger::SetNVDrvInstance(std::shared_ptr instance) { nvdrv = std::move(instance); + disp_fd = nvdrv->Open("/dev/nvdisp_disp0"); } std::optional NVFlinger::OpenDisplay(std::string_view name) { @@ -276,7 +281,7 @@ void NVFlinger::Compose() { // Now send the buffer to the GPU for drawing. // TODO(Subv): Support more than just disp0. The display device selection is probably based // on which display we're drawing (Default, Internal, External, etc) - auto nvdisp = nvdrv->GetDevice("/dev/nvdisp_disp0"); + auto nvdisp = nvdrv->GetDevice(disp_fd); ASSERT(nvdisp); Common::Rectangle crop_rect{ diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 3bbe5d92b..b62615de2 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -116,6 +116,7 @@ private: void SplitVSync(std::stop_token stop_token); std::shared_ptr nvdrv; + s32 disp_fd; std::list displays; -- cgit v1.2.3 From 68d9504a046f40ce4ada54b0eba7228e659970de Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 5 Nov 2021 02:11:46 +0100 Subject: NVMAP: Fix the Free return parameters. --- src/core/hle/service/nvdrv/core/nvmap.cpp | 4 +++- src/core/hle/service/nvdrv/core/nvmap.h | 1 + src/core/hle/service/nvdrv/devices/nvmap.cpp | 28 ++++++++++++++-------------- 3 files changed, 18 insertions(+), 15 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index 281381cc4..1126daeb5 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -11,7 +11,9 @@ using Core::Memory::YUZU_PAGESIZE; namespace Service::Nvidia::NvCore { -NvMap::Handle::Handle(u64 size, Id id) : size(size), aligned_size(size), orig_size(size), id(id) {} +NvMap::Handle::Handle(u64 size, Id id) : size(size), aligned_size(size), orig_size(size), id(id) { + flags.raw = 0; +} NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) { std::scoped_lock lock(mutex); diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index 994c70e6f..5e6c73589 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -44,6 +44,7 @@ public: std::optional>::iterator> unmap_queue_entry{}; union Flags { + u32 raw; BitField<0, 1, u32> map_uncached; //!< If the handle should be mapped as uncached BitField<2, 1, u32> keep_uncached_after_free; //!< Only applicable when the handle was //!< allocated with a fixed address diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 2aee68f5c..57f58055d 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -82,7 +82,7 @@ std::shared_ptr nvmap::GetObject(u32 handle) const { NvResult nvmap::IocCreate(const std::vector& input, std::vector& output) { IocCreateParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_WARNING(Service_NVDRV, "called, size=0x{:08X}", params.size); + LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size); std::shared_ptr handle_description{}; auto result = @@ -102,7 +102,7 @@ NvResult nvmap::IocCreate(const std::vector& input, std::vector& output) NvResult nvmap::IocAlloc(const std::vector& input, std::vector& output) { IocAllocParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_WARNING(Service_NVDRV, "called, addr={:X}", params.address); + LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address); if (!params.handle) { LOG_CRITICAL(Service_NVDRV, "Handle is 0"); @@ -144,7 +144,7 @@ NvResult nvmap::IocGetId(const std::vector& input, std::vector& output) IocGetIdParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_WARNING(Service_NVDRV, "called"); + LOG_DEBUG(Service_NVDRV, "called"); // See the comment in FromId for extra info on this function if (!params.handle) { @@ -168,26 +168,26 @@ NvResult nvmap::IocFromId(const std::vector& input, std::vector& output) IocFromIdParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_WARNING(Service_NVDRV, "called, id:{}"); + LOG_DEBUG(Service_NVDRV, "called, id:{}"); // Handles and IDs are always the same value in nvmap however IDs can be used globally given the // right permissions. // Since we don't plan on ever supporting multiprocess we can skip implementing handle refs and // so this function just does simple validation and passes through the handle id. if (!params.id) { - LOG_CRITICAL(Service_NVDRV, "Error!"); + LOG_CRITICAL(Service_NVDRV, "Zero Id is invalid!"); return NvResult::BadValue; } auto handle_description{file.GetHandle(params.id)}; if (!handle_description) { - LOG_CRITICAL(Service_NVDRV, "Error!"); + LOG_CRITICAL(Service_NVDRV, "Unregistered handle!"); return NvResult::BadValue; } auto result = handle_description->Duplicate(false); if (result != NvResult::Success) { - LOG_CRITICAL(Service_NVDRV, "Error!"); + LOG_CRITICAL(Service_NVDRV, "Could not duplicate handle!"); return result; } params.handle = handle_description->id; @@ -201,16 +201,16 @@ NvResult nvmap::IocParam(const std::vector& input, std::vector& output) IocParamParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_WARNING(Service_NVDRV, "called type={}", params.param); + LOG_DEBUG(Service_NVDRV, "called type={}", params.param); if (!params.handle) { - LOG_CRITICAL(Service_NVDRV, "Error!"); + LOG_CRITICAL(Service_NVDRV, "Invalid handle!"); return NvResult::BadValue; } auto handle_description{file.GetHandle(params.handle)}; if (!handle_description) { - LOG_CRITICAL(Service_NVDRV, "Error!"); + LOG_CRITICAL(Service_NVDRV, "Not registered handle!"); return NvResult::BadValue; } @@ -228,7 +228,7 @@ NvResult nvmap::IocParam(const std::vector& input, std::vector& output) if (handle_description->allocated) params.result = 0x40000000; else - params.result = 0x40000000; + params.result = 0; break; case HandleParameterType::Kind: params.result = handle_description->kind; @@ -248,7 +248,7 @@ NvResult nvmap::IocFree(const std::vector& input, std::vector& output) { IocFreeParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_WARNING(Service_NVDRV, "called"); + LOG_DEBUG(Service_NVDRV, "called"); if (!params.handle) { LOG_CRITICAL(Service_NVDRV, "Handle null freed?"); @@ -258,10 +258,10 @@ NvResult nvmap::IocFree(const std::vector& input, std::vector& output) { if (auto freeInfo{file.FreeHandle(params.handle, false)}) { params.address = freeInfo->address; params.size = static_cast(freeInfo->size); - params.flags = NvCore::NvMap::Handle::Flags{.map_uncached = freeInfo->was_uncached}; + params.flags.raw = 0; + params.flags.map_uncached = freeInfo->was_uncached; } else { // This is possible when there's internel dups or other duplicates. - LOG_CRITICAL(Service_NVDRV, "Not freed"); } std::memcpy(output.data(), ¶ms, sizeof(params)); -- cgit v1.2.3 From ad038609c877ad54dde7b9592f0584deb56a27c5 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 5 Nov 2021 02:57:14 +0100 Subject: NVDRV: Fix clearing when destroying. --- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 13 +++++++------ src/core/hle/service/nvdrv/nvdrv.cpp | 7 ++----- src/core/hle/service/nvdrv/nvdrv.h | 3 --- 3 files changed, 9 insertions(+), 14 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 122c1d5e1..abde2a6d3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -24,12 +24,9 @@ namespace Service::Nvidia::Devices { nvhost_ctrl::nvhost_ctrl(Core::System& system_, EventInterface& events_interface_, NvCore::Container& core_) : nvdevice{system_}, events_interface{events_interface_}, core{core_}, - syncpoint_manager{core_.GetSyncpointManager()} { - events_interface.RegisterForSignal(this); -} + syncpoint_manager{core_.GetSyncpointManager()} {} nvhost_ctrl::~nvhost_ctrl() { - events_interface.UnregisterForSignal(this); for (auto& event : events) { if (!event.registered) { continue; @@ -77,8 +74,12 @@ NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, const std::vector& return NvResult::NotImplemented; } -void nvhost_ctrl::OnOpen(DeviceFD fd) {} -void nvhost_ctrl::OnClose(DeviceFD fd) {} +void nvhost_ctrl::OnOpen(DeviceFD fd) { + events_interface.RegisterForSignal(this); +} +void nvhost_ctrl::OnClose(DeviceFD fd) { + events_interface.UnregisterForSignal(this); +} NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector& input, std::vector& output) { IocGetConfigParams params{}; diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index ff8c7c13c..208de0b75 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -29,7 +29,7 @@ namespace Service::Nvidia { -EventInterface::EventInterface(Module& module_) : module{module_} {} +EventInterface::EventInterface(Module& module_) : module{module_}, guard{}, on_signal{} {} EventInterface::~EventInterface() = default; @@ -40,10 +40,7 @@ void EventInterface::RegisterForSignal(Devices::nvhost_ctrl* device) { void EventInterface::UnregisterForSignal(Devices::nvhost_ctrl* device) { std::unique_lock lk(guard); - auto it = std::find(on_signal.begin(), on_signal.end(), device); - if (it != on_signal.end()) { - on_signal.erase(it); - } + on_signal.remove(device); } void EventInterface::Signal(u32 syncpoint_id, u32 value) { diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 3983794bb..1fe98cf32 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -110,9 +110,6 @@ private: /// Mapping of file descriptors to the devices they reference. FilesContainerType open_files; - /// Mapping of device node names to their implementation. - std::unordered_map> devices; - KernelHelpers::ServiceContext service_context; EventInterface events_interface; -- cgit v1.2.3 From c77b8df12efab9f36f007ff3b309d43588a71260 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 5 Nov 2021 03:10:20 +0100 Subject: NVASGPU: Fix Remap. --- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 9283d6aec..b1c683511 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -144,6 +144,14 @@ NvResult nvhost_as_gpu::Remap(const std::vector& input, std::vector& out LOG_DEBUG(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}", entry.offset, entry.nvmap_handle, entry.pages); + if (entry.nvmap_handle == 0) { + // If nvmap handle is null, we should unmap instead. + const auto offset{static_cast(entry.offset) << 0x10}; + const auto size{static_cast(entry.pages) << 0x10}; + system.GPU().MemoryManager().Unmap(offset, size); + continue; + } + const auto object{nvmap.GetHandle(entry.nvmap_handle)}; if (!object) { LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle); -- cgit v1.2.3 From 139ea93512aeead8a4aee3910a3de86eb109a838 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 5 Nov 2021 15:52:31 +0100 Subject: VideoCore: implement channels on gpu caches. --- .../hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 34 ++++++++++++---------- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | 14 ++++++++- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 34 +++++++++++++++------- src/core/hle/service/nvdrv/devices/nvhost_gpu.h | 9 ++++++ src/core/hle/service/nvdrv/devices/nvmap.cpp | 2 +- src/core/hle/service/nvdrv/nvdrv.cpp | 2 +- 6 files changed, 65 insertions(+), 30 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index b1c683511..9946ce624 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -10,13 +10,17 @@ #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" +#include "core/hle/service/nvdrv/devices/nvhost_gpu.h" +#include "core/hle/service/nvdrv/nvdrv.h" +#include "video_core/control/channel_state.h" #include "video_core/memory_manager.h" #include "video_core/rasterizer_interface.h" namespace Service::Nvidia::Devices { -nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, NvCore::Container& core) - : nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {} +nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, Module& module_, NvCore::Container& core) + : nvdevice{system_}, module{module_}, container{core}, nvmap{core.GetNvMapFile()}, + gmmu{std::make_shared(system)} {} nvhost_as_gpu::~nvhost_as_gpu() = default; NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -102,9 +106,9 @@ NvResult nvhost_as_gpu::AllocateSpace(const std::vector& input, std::vector< const auto size{static_cast(params.pages) * static_cast(params.page_size)}; if ((params.flags & AddressSpaceFlags::FixedOffset) != AddressSpaceFlags::None) { - params.offset = *system.GPU().MemoryManager().AllocateFixed(params.offset, size); + params.offset = *(gmmu->AllocateFixed(params.offset, size)); } else { - params.offset = system.GPU().MemoryManager().Allocate(size, params.align); + params.offset = gmmu->Allocate(size, params.align); } auto result = NvResult::Success; @@ -124,8 +128,7 @@ NvResult nvhost_as_gpu::FreeSpace(const std::vector& input, std::vector& LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset, params.pages, params.page_size); - system.GPU().MemoryManager().Unmap(params.offset, - static_cast(params.pages) * params.page_size); + gmmu->Unmap(params.offset, static_cast(params.pages) * params.page_size); std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; @@ -148,7 +151,7 @@ NvResult nvhost_as_gpu::Remap(const std::vector& input, std::vector& out // If nvmap handle is null, we should unmap instead. const auto offset{static_cast(entry.offset) << 0x10}; const auto size{static_cast(entry.pages) << 0x10}; - system.GPU().MemoryManager().Unmap(offset, size); + gmmu->Unmap(offset, size); continue; } @@ -162,8 +165,7 @@ NvResult nvhost_as_gpu::Remap(const std::vector& input, std::vector& out const auto offset{static_cast(entry.offset) << 0x10}; const auto size{static_cast(entry.pages) << 0x10}; const auto map_offset{static_cast(entry.map_offset) << 0x10}; - const auto addr{ - system.GPU().MemoryManager().Map(object->address + map_offset, offset, size)}; + const auto addr{gmmu->Map(object->address + map_offset, offset, size)}; if (!addr) { LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!"); @@ -186,13 +188,12 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vector(buffer_map->CpuAddr() + params.buffer_offset)}; const auto gpu_addr{static_cast(params.offset + params.buffer_offset)}; - if (!gpu.MemoryManager().Map(cpu_addr, gpu_addr, params.mapping_size)) { + if (!gmmu->Map(cpu_addr, gpu_addr, params.mapping_size)) { LOG_CRITICAL(Service_NVDRV, "remap failed, flags={:X}, nvmap_handle={:X}, buffer_offset={}, " "mapping_size = {}, offset={}", @@ -238,9 +239,9 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vectorMapAllocate(physical_address, size, page_size); } else { - params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size); + params.offset = gmmu->Map(physical_address, params.offset, size); } auto result = NvResult::Success; @@ -262,7 +263,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(const std::vector& input, std::vectorUnmap(params.offset, *size); } else { LOG_ERROR(Service_NVDRV, "invalid offset=0x{:X}", params.offset); } @@ -274,9 +275,10 @@ NvResult nvhost_as_gpu::UnmapBuffer(const std::vector& input, std::vector& input, std::vector& output) { IoctlBindChannel params{}; std::memcpy(¶ms, input.data(), input.size()); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}", params.fd); + LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); - channel = params.fd; + auto gpu_channel_device = module.GetDevice(params.fd); + gpu_channel_device->channel_state->memory_manager = gmmu; return NvResult::Success; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 67d2f1e87..4ecae3caf 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -13,6 +13,14 @@ #include "common/swap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" +namespace Tegra { +class MemoryManager; +} // namespace Tegra + +namespace Service::Nvidia { +class Module; +} + namespace Service::Nvidia::NvCore { class Container; class NvMap; @@ -34,7 +42,7 @@ DECLARE_ENUM_FLAG_OPERATORS(AddressSpaceFlags); class nvhost_as_gpu final : public nvdevice { public: - explicit nvhost_as_gpu(Core::System& system_, NvCore::Container& core); + explicit nvhost_as_gpu(Core::System& system_, Module& module, NvCore::Container& core); ~nvhost_as_gpu() override; NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -187,9 +195,13 @@ private: void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); std::optional RemoveBufferMap(GPUVAddr gpu_addr); + Module& module; + NvCore::Container& container; NvCore::NvMap& nvmap; + std::shared_ptr gmmu; + // This is expected to be ordered, therefore we must use a map, not unordered_map std::map buffer_mappings; }; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index cb54ee5a4..38d45cb79 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -11,12 +11,14 @@ #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/memory.h" +#include "video_core/control/channel_state.h" +#include "video_core/engines/puller.h" #include "video_core/gpu.h" namespace Service::Nvidia::Devices { namespace { -Tegra::CommandHeader BuildFenceAction(Tegra::GPU::FenceOperation op, u32 syncpoint_id) { - Tegra::GPU::FenceAction result{}; +Tegra::CommandHeader BuildFenceAction(Tegra::Engines::Puller::FenceOperation op, u32 syncpoint_id) { + Tegra::Engines::Puller::FenceAction result{}; result.op.Assign(op); result.syncpoint_id.Assign(syncpoint_id); return {result.raw}; @@ -26,7 +28,8 @@ Tegra::CommandHeader BuildFenceAction(Tegra::GPU::FenceOperation op, u32 syncpoi nvhost_gpu::nvhost_gpu(Core::System& system_, EventInterface& events_interface_, NvCore::Container& core_) : nvdevice{system_}, events_interface{events_interface_}, core{core_}, - syncpoint_manager{core_.GetSyncpointManager()}, nvmap{core.GetNvMapFile()} { + syncpoint_manager{core_.GetSyncpointManager()}, nvmap{core.GetNvMapFile()}, + channel_state{system.GPU().AllocateChannel()} { channel_fence.id = syncpoint_manager.AllocateSyncpoint(); channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id); sm_exception_breakpoint_int_report_event = @@ -180,6 +183,12 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector& input, std::vectorinitiated) { + LOG_CRITICAL(Service_NVDRV, "Already allocated!"); + return NvResult::AlreadyAllocated; + } + + system.GPU().InitChannel(*channel_state); channel_fence.value = system.GPU().GetSyncpointValue(channel_fence.id); params.fence_out = channel_fence; @@ -206,7 +215,7 @@ static std::vector BuildWaitCommandList(NvFence fence) { {fence.value}, Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1, Tegra::SubmissionMode::Increasing), - BuildFenceAction(Tegra::GPU::FenceOperation::Acquire, fence.id), + BuildFenceAction(Tegra::Engines::Puller::FenceOperation::Acquire, fence.id), }; } @@ -220,7 +229,8 @@ static std::vector BuildIncrementCommandList(NvFence fence for (u32 count = 0; count < add_increment; ++count) { result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1, Tegra::SubmissionMode::Increasing)); - result.emplace_back(BuildFenceAction(Tegra::GPU::FenceOperation::Increment, fence.id)); + result.emplace_back( + BuildFenceAction(Tegra::Engines::Puller::FenceOperation::Increment, fence.id)); } return result; @@ -247,11 +257,13 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector auto& gpu = system.GPU(); + const auto bind_id = channel_state->bind_id; + params.fence_out.id = channel_fence.id; if (params.flags.add_wait.Value() && !syncpoint_manager.IsSyncpointExpired(params.fence_out.id, params.fence_out.value)) { - gpu.PushGPUEntries(Tegra::CommandList{BuildWaitCommandList(params.fence_out)}); + gpu.PushGPUEntries(bind_id, Tegra::CommandList{BuildWaitCommandList(params.fence_out)}); } if (params.flags.add_increment.Value() || params.flags.increment.Value()) { @@ -262,15 +274,15 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector params.fence_out.value = syncpoint_manager.GetSyncpointMax(params.fence_out.id); } - gpu.PushGPUEntries(std::move(entries)); + gpu.PushGPUEntries(bind_id, std::move(entries)); if (params.flags.add_increment.Value()) { if (params.flags.suppress_wfi) { - gpu.PushGPUEntries(Tegra::CommandList{ - BuildIncrementCommandList(params.fence_out, params.AddIncrementValue())}); + gpu.PushGPUEntries(bind_id, Tegra::CommandList{BuildIncrementCommandList( + params.fence_out, params.AddIncrementValue())}); } else { - gpu.PushGPUEntries(Tegra::CommandList{ - BuildIncrementWithWfiCommandList(params.fence_out, params.AddIncrementValue())}); + gpu.PushGPUEntries(bind_id, Tegra::CommandList{BuildIncrementWithWfiCommandList( + params.fence_out, params.AddIncrementValue())}); } } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 440c0c42d..3a65ed06d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -13,6 +13,12 @@ #include "core/hle/service/nvdrv/nvdata.h" #include "video_core/dma_pusher.h" +namespace Tegra { +namespace Control { +struct ChannelState; +} +} // namespace Tegra + namespace Service::Nvidia { namespace NvCore { @@ -26,6 +32,7 @@ class EventInterface; namespace Service::Nvidia::Devices { +class nvhost_as_gpu; class nvmap; class nvhost_gpu final : public nvdevice { public: @@ -46,6 +53,7 @@ public: Kernel::KEvent* QueryEvent(u32 event_id) override; private: + friend class nvhost_as_gpu; enum class CtxObjects : u32_le { Ctx2D = 0x902D, Ctx3D = 0xB197, @@ -204,6 +212,7 @@ private: NvCore::Container& core; NvCore::SyncpointManager& syncpoint_manager; NvCore::NvMap& nvmap; + std::shared_ptr channel_state; NvFence channel_fence; // Events diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 57f58055d..279997e81 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -168,7 +168,7 @@ NvResult nvmap::IocFromId(const std::vector& input, std::vector& output) IocFromIdParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_DEBUG(Service_NVDRV, "called, id:{}"); + LOG_DEBUG(Service_NVDRV, "called, id:{}", params.id); // Handles and IDs are always the same value in nvmap however IDs can be used globally given the // right permissions. diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 208de0b75..b39a4c6db 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -74,7 +74,7 @@ Module::Module(Core::System& system) : service_context{system, "nvdrv"}, events_interface{*this}, container{system.GPU()} { builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) { std::shared_ptr device = - std::make_shared(system, container); + std::make_shared(system, *this, container); return open_files.emplace(fd, device).first; }; builders["/dev/nvhost-gpu"] = [this, &system](DeviceFD fd) { -- cgit v1.2.3 From 2c62563ab58a70236a39571149f8370f3fdfb2a3 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 7 Nov 2021 14:17:32 +0100 Subject: NVHOST_CTRl: Implement missing method and fix some stuffs. --- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 30 +++++++++++++++++++--- src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 5 ++-- 2 files changed, 29 insertions(+), 6 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index abde2a6d3..0e22d9273 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -52,6 +52,8 @@ NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& return IocCtrlEventRegister(input, output); case 0x20: return IocCtrlEventUnregister(input, output); + case 0x21: + return IocCtrlEventUnregisterBatch(input, output); } break; default: @@ -249,6 +251,25 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector& input, return FreeEvent(event_id); } +NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(const std::vector& input, + std::vector& output) { + IocCtrlEventUnregisterBatchParams params{}; + std::memcpy(¶ms, input.data(), sizeof(params)); + u64 event_mask = params.user_events; + LOG_DEBUG(Service_NVDRV, " called, event_mask: {:X}", event_mask); + + auto lock = NvEventsLock(); + while (event_mask != 0) { + const u64 event_id = std::countr_zero(event_mask); + event_mask &= ~(1ULL << event_id); + const auto result = FreeEvent(static_cast(event_id)); + if (result != NvResult::Success) { + return result; + } + } + return NvResult::Success; +} + NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector& input, std::vector& output) { IocCtrlEventClearParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); @@ -362,10 +383,11 @@ u32 nvhost_ctrl::FindFreeNvEvent(u32 syncpoint_id) { } void nvhost_ctrl::SignalNvEvent(u32 syncpoint_id, u32 value) { - const u32 max = MaxNvEvents - std::countl_zero(events_mask); - const u32 min = std::countr_zero(events_mask); - for (u32 i = min; i < max; i++) { - auto& event = events[i]; + u64 signal_mask = events_mask; + while (signal_mask != 0) { + const u64 event_id = std::countr_zero(signal_mask); + signal_mask &= ~(1ULL << event_id); + auto& event = events[event_id]; if (event.assigned_syncpt != syncpoint_id || event.assigned_value != value) { continue; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index f2fc5d047..9bd10257b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -177,16 +177,17 @@ private: static_assert(sizeof(IocCtrlEventUnregisterParams) == 4, "IocCtrlEventUnregisterParams is incorrect size"); - struct IocCtrlEventKill { + struct IocCtrlEventUnregisterBatchParams { u64_le user_events{}; }; - static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size"); + static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8, "IocCtrlEventKill is incorrect size"); NvResult NvOsGetConfigU32(const std::vector& input, std::vector& output); NvResult IocCtrlEventWait(const std::vector& input, std::vector& output, bool is_allocation); NvResult IocCtrlEventRegister(const std::vector& input, std::vector& output); NvResult IocCtrlEventUnregister(const std::vector& input, std::vector& output); + NvResult IocCtrlEventUnregisterBatch(const std::vector& input, std::vector& output); NvResult IocCtrlClearEventWait(const std::vector& input, std::vector& output); NvResult FreeEvent(u32 slot); -- cgit v1.2.3 From 835b950f7ec300920b920b9b45f82ceaa4b33813 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 13 Nov 2021 02:29:54 +0100 Subject: NvHostCtrl: Fix merge of nvflinger. --- src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 9bd10257b..594d20600 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -180,7 +180,8 @@ private: struct IocCtrlEventUnregisterBatchParams { u64_le user_events{}; }; - static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8, "IocCtrlEventKill is incorrect size"); + static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8, + "IocCtrlEventKill is incorrect size"); NvResult NvOsGetConfigU32(const std::vector& input, std::vector& output); NvResult IocCtrlEventWait(const std::vector& input, std::vector& output, -- cgit v1.2.3 From c6ea0c650e38b7c475fea221b9655c754f7aaccc Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 13 Nov 2021 03:25:35 +0100 Subject: NVDRV: Update copyright notices. --- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 6 ++++-- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | 6 ++++-- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 6 ++++-- 4 files changed, 13 insertions(+), 7 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 9946ce624..5c70c9a57 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -1,5 +1,7 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2021 yuzu emulator team, 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 #include diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 4ecae3caf..f5fb33ba7 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -1,5 +1,7 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2021 yuzu emulator team, 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 diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 0e22d9273..a859a7abd 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 yuzu emulator team and Skyline Team and Contributors +// SPDX-FileCopyrightText: 2021 yuzu emulator team, 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. diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 594d20600..d56aea405 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -1,5 +1,7 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2021 yuzu emulator team, 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 -- cgit v1.2.3 From feb49c822d9cabc5bc7be9eab1f2bf4ba460176a Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 14 Nov 2021 20:55:52 +0100 Subject: NVDRV: Remake ASGPU --- .../hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 460 ++++++++++++++------- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | 163 ++++---- 2 files changed, 388 insertions(+), 235 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 5c70c9a57..344ddfc90 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -6,6 +6,7 @@ #include #include +#include "common/alignment.h" #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" @@ -21,8 +22,8 @@ namespace Service::Nvidia::Devices { nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, Module& module_, NvCore::Container& core) - : nvdevice{system_}, module{module_}, container{core}, nvmap{core.GetNvMapFile()}, - gmmu{std::make_shared(system)} {} + : nvdevice{system_}, module{module_}, container{core}, nvmap{core.GetNvMapFile()}, vm{}, + gmmu{} {} nvhost_as_gpu::~nvhost_as_gpu() = default; NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -89,12 +90,49 @@ NvResult nvhost_as_gpu::AllocAsEx(const std::vector& input, std::vector& IoctlAllocAsEx params{}; std::memcpy(¶ms, input.data(), input.size()); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); - if (params.big_page_size == 0) { - params.big_page_size = DEFAULT_BIG_PAGE_SIZE; + LOG_DEBUG(Service_NVDRV, "called, big_page_size=0x{:X}", params.big_page_size); + + std::scoped_lock lock(mutex); + + if (vm.initialised) { + UNREACHABLE_MSG("Cannot initialise an address space twice!"); + return NvResult::InvalidState; } - big_page_size = params.big_page_size; + if (params.big_page_size) { + if (!std::has_single_bit(params.big_page_size)) { + LOG_ERROR(Service_NVDRV, "Non power-of-2 big page size: 0x{:X}!", params.big_page_size); + return NvResult::BadValue; + } + + if (!(params.big_page_size & VM::SUPPORTED_BIG_PAGE_SIZES)) { + LOG_ERROR(Service_NVDRV, "Unsupported big page size: 0x{:X}!", params.big_page_size); + return NvResult::BadValue; + } + + vm.big_page_size = params.big_page_size; + vm.big_page_size_bits = static_cast(std::countr_zero(params.big_page_size)); + + vm.va_range_start = params.big_page_size << VM::VA_START_SHIFT; + } + + // If this is unspecified then default values should be used + if (params.va_range_start) { + vm.va_range_start = params.va_range_start; + vm.va_range_split = params.va_range_split; + vm.va_range_end = params.va_range_end; + } + + const u64 start_pages{vm.va_range_start >> VM::PAGE_SIZE_BITS}; + const u64 end_pages{vm.va_range_split >> VM::PAGE_SIZE_BITS}; + vm.small_page_allocator = std::make_shared(start_pages, end_pages); + + const u64 start_big_pages{vm.va_range_split >> vm.big_page_size_bits}; + const u64 end_big_pages{(vm.va_range_end - vm.va_range_split) >> vm.big_page_size_bits}; + vm.big_page_allocator = std::make_unique(start_big_pages, end_big_pages); + + gmmu = std::make_shared(system, 40, VM::PAGE_SIZE_BITS); + vm.initialised = true; return NvResult::Success; } @@ -106,21 +144,73 @@ NvResult nvhost_as_gpu::AllocateSpace(const std::vector& input, std::vector< LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages, params.page_size, params.flags); - const auto size{static_cast(params.pages) * static_cast(params.page_size)}; - if ((params.flags & AddressSpaceFlags::FixedOffset) != AddressSpaceFlags::None) { - params.offset = *(gmmu->AllocateFixed(params.offset, size)); + std::scoped_lock lock(mutex); + + if (!vm.initialised) { + return NvResult::BadValue; + } + + if (params.page_size != VM::YUZU_PAGESIZE && params.page_size != vm.big_page_size) { + return NvResult::BadValue; + } + + if (params.page_size != vm.big_page_size && + ((params.flags & MappingFlags::Sparse) != MappingFlags::None)) { + UNIMPLEMENTED_MSG("Sparse small pages are not implemented!"); + return NvResult::NotImplemented; + } + + const u32 page_size_bits{params.page_size == VM::YUZU_PAGESIZE ? VM::PAGE_SIZE_BITS + : vm.big_page_size_bits}; + + auto& allocator{params.page_size == VM::YUZU_PAGESIZE ? *vm.small_page_allocator + : *vm.big_page_allocator}; + + if ((params.flags & MappingFlags::Fixed) != MappingFlags::None) { + allocator.AllocateFixed(static_cast(params.offset >> page_size_bits), params.pages); } else { - params.offset = gmmu->Allocate(size, params.align); + params.offset = static_cast(allocator.Allocate(params.pages)) << page_size_bits; + if (!params.offset) { + UNREACHABLE_MSG("Failed to allocate free space in the GPU AS!"); + return NvResult::InsufficientMemory; + } } - auto result = NvResult::Success; - if (!params.offset) { - LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size); - result = NvResult::InsufficientMemory; + u64 size{static_cast(params.pages) * params.page_size}; + + if ((params.flags & MappingFlags::Sparse) != MappingFlags::None) { + gmmu->MapSparse(params.offset, size); } + allocation_map[params.offset] = { + .size = size, + .page_size = params.page_size, + .sparse = (params.flags & MappingFlags::Sparse) != MappingFlags::None, + }; + std::memcpy(output.data(), ¶ms, output.size()); - return result; + return NvResult::Success; +} + +void nvhost_as_gpu::FreeMappingLocked(u64 offset) { + auto mapping{mapping_map.at(offset)}; + + if (!mapping->fixed) { + auto& allocator{mapping->big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; + u32 page_size_bits{mapping->big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS}; + + allocator.Free(static_cast(mapping->offset >> page_size_bits), + static_cast(mapping->size >> page_size_bits)); + } + + // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state + // Only FreeSpace can unmap them fully + if (mapping->sparse_alloc) + gmmu->MapSparse(offset, mapping->size); + else + gmmu->Unmap(offset, mapping->size); + + mapping_map.erase(offset); } NvResult nvhost_as_gpu::FreeSpace(const std::vector& input, std::vector& output) { @@ -130,7 +220,40 @@ NvResult nvhost_as_gpu::FreeSpace(const std::vector& input, std::vector& LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset, params.pages, params.page_size); - gmmu->Unmap(params.offset, static_cast(params.pages) * params.page_size); + std::scoped_lock lock(mutex); + + if (!vm.initialised) { + return NvResult::BadValue; + } + + try { + auto allocation{allocation_map[params.offset]}; + + if (allocation.page_size != params.page_size || + allocation.size != (static_cast(params.pages) * params.page_size)) { + return NvResult::BadValue; + } + + for (const auto& mapping : allocation.mappings) { + FreeMappingLocked(mapping->offset); + } + + // Unset sparse flag if required + if (allocation.sparse) { + gmmu->Unmap(params.offset, allocation.size); + } + + auto& allocator{params.page_size == VM::YUZU_PAGESIZE ? *vm.small_page_allocator + : *vm.big_page_allocator}; + u32 page_size_bits{params.page_size == VM::YUZU_PAGESIZE ? VM::PAGE_SIZE_BITS + : vm.big_page_size_bits}; + + allocator.Free(static_cast(params.offset >> page_size_bits), + static_cast(allocation.size >> page_size_bits)); + allocation_map.erase(params.offset); + } catch ([[maybe_unused]] const std::out_of_range& e) { + return NvResult::BadValue; + } std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; @@ -141,43 +264,51 @@ NvResult nvhost_as_gpu::Remap(const std::vector& input, std::vector& out LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); - auto result = NvResult::Success; std::vector entries(num_entries); std::memcpy(entries.data(), input.data(), input.size()); + std::scoped_lock lock(mutex); + + if (!vm.initialised) { + return NvResult::BadValue; + } + for (const auto& entry : entries) { - LOG_DEBUG(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}", - entry.offset, entry.nvmap_handle, entry.pages); - - if (entry.nvmap_handle == 0) { - // If nvmap handle is null, we should unmap instead. - const auto offset{static_cast(entry.offset) << 0x10}; - const auto size{static_cast(entry.pages) << 0x10}; - gmmu->Unmap(offset, size); - continue; + GPUVAddr virtual_address{static_cast(entry.as_offset_big_pages) + << vm.big_page_size_bits}; + u64 size{static_cast(entry.big_pages) << vm.big_page_size_bits}; + + auto alloc{allocation_map.upper_bound(virtual_address)}; + + if (alloc-- == allocation_map.begin() || + (virtual_address - alloc->first) + size > alloc->second.size) { + LOG_WARNING(Service_NVDRV, "Cannot remap into an unallocated region!"); + return NvResult::BadValue; } - const auto object{nvmap.GetHandle(entry.nvmap_handle)}; - if (!object) { - LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle); - result = NvResult::InvalidState; - break; + if (!alloc->second.sparse) { + LOG_WARNING(Service_NVDRV, "Cannot remap a non-sparse mapping!"); + return NvResult::BadValue; } - const auto offset{static_cast(entry.offset) << 0x10}; - const auto size{static_cast(entry.pages) << 0x10}; - const auto map_offset{static_cast(entry.map_offset) << 0x10}; - const auto addr{gmmu->Map(object->address + map_offset, offset, size)}; + if (!entry.handle) { + gmmu->MapSparse(virtual_address, size); + } else { + auto handle{nvmap.GetHandle(entry.handle)}; + if (!handle) { + return NvResult::BadValue; + } - if (!addr) { - LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!"); - result = NvResult::InvalidState; - break; + VAddr cpu_address{static_cast( + handle->address + + (static_cast(entry.handle_offset_big_pages) << vm.big_page_size_bits))}; + + gmmu->Map(virtual_address, cpu_address, size); } } std::memcpy(output.data(), entries.data(), output.size()); - return result; + return NvResult::Success; } NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vector& output) { @@ -187,75 +318,96 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vector(buffer_map->CpuAddr() + params.buffer_offset)}; - const auto gpu_addr{static_cast(params.offset + params.buffer_offset)}; + std::scoped_lock lock(mutex); + + if (!vm.initialised) { + return NvResult::BadValue; + } - if (!gmmu->Map(cpu_addr, gpu_addr, params.mapping_size)) { - LOG_CRITICAL(Service_NVDRV, - "remap failed, flags={:X}, nvmap_handle={:X}, buffer_offset={}, " - "mapping_size = {}, offset={}", - params.flags, params.nvmap_handle, params.buffer_offset, - params.mapping_size, params.offset); + // Remaps a subregion of an existing mapping to a different PA + if ((params.flags & MappingFlags::Remap) != MappingFlags::None) { + try { + auto mapping{mapping_map.at(params.offset)}; - std::memcpy(output.data(), ¶ms, output.size()); - return NvResult::InvalidState; + if (mapping->size < params.mapping_size) { + LOG_WARNING(Service_NVDRV, + "Cannot remap a partially mapped GPU address space region: 0x{:X}", + params.offset); + return NvResult::BadValue; } - std::memcpy(output.data(), ¶ms, output.size()); - return NvResult::Success; - } else { - LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset); + u64 gpu_address{static_cast(params.offset + params.buffer_offset)}; + VAddr cpu_address{mapping->ptr + params.buffer_offset}; + + gmmu->Map(gpu_address, cpu_address, params.mapping_size); - std::memcpy(output.data(), ¶ms, output.size()); - return NvResult::InvalidState; + return NvResult::Success; + } catch ([[maybe_unused]] const std::out_of_range& e) { + LOG_WARNING(Service_NVDRV, "Cannot remap an unmapped GPU address space region: 0x{:X}", + params.offset); + return NvResult::BadValue; } } - const auto object{nvmap.GetHandle(params.nvmap_handle)}; - if (!object) { - LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle); - std::memcpy(output.data(), ¶ms, output.size()); - return NvResult::InvalidState; + auto handle{nvmap.GetHandle(params.handle)}; + if (!handle) { + return NvResult::BadValue; } - // The real nvservices doesn't make a distinction between handles and ids, and - // object can only have one handle and it will be the same as its id. Assert that this is the - // case to prevent unexpected behavior. - ASSERT(object->id == params.nvmap_handle); + VAddr cpu_address{static_cast(handle->address + params.buffer_offset)}; + u64 size{params.mapping_size ? params.mapping_size : handle->orig_size}; - u64 page_size{params.page_size}; - if (!page_size) { - page_size = object->align; - } + if ((params.flags & MappingFlags::Fixed) != MappingFlags::None) { + auto alloc{allocation_map.upper_bound(params.offset)}; - const auto physical_address{object->address + params.buffer_offset}; - u64 size{params.mapping_size}; - if (!size) { - size = object->size; - } + if (alloc-- == allocation_map.begin() || + (params.offset - alloc->first) + size > alloc->second.size) { + UNREACHABLE_MSG("Cannot perform a fixed mapping into an unallocated region!"); + return NvResult::BadValue; + } - const bool is_alloc{(params.flags & AddressSpaceFlags::FixedOffset) == AddressSpaceFlags::None}; - if (is_alloc) { - params.offset = gmmu->MapAllocate(physical_address, size, page_size); - } else { - params.offset = gmmu->Map(physical_address, params.offset, size); - } + gmmu->Map(params.offset, cpu_address, size); - auto result = NvResult::Success; - if (!params.offset) { - LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size); - result = NvResult::InvalidState; + auto mapping{std::make_shared(cpu_address, params.offset, size, true, false, + alloc->second.sparse)}; + alloc->second.mappings.push_back(mapping); + mapping_map[params.offset] = mapping; } else { - AddBufferMap(params.offset, size, physical_address, is_alloc); + bool big_page{[&]() { + if (Common::IsAligned(handle->align, vm.big_page_size)) + return true; + else if (Common::IsAligned(handle->align, VM::YUZU_PAGESIZE)) + return false; + else { + UNREACHABLE(); + return false; + } + }()}; + + auto& allocator{big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; + u32 page_size{big_page ? vm.big_page_size : VM::YUZU_PAGESIZE}; + u32 page_size_bits{big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS}; + + params.offset = static_cast(allocator.Allocate( + static_cast(Common::AlignUp(size, page_size) >> page_size_bits))) + << page_size_bits; + if (!params.offset) { + UNREACHABLE_MSG("Failed to allocate free space in the GPU AS!"); + return NvResult::InsufficientMemory; + } + + gmmu->Map(params.offset, cpu_address, size); + + auto mapping{ + std::make_shared(cpu_address, params.offset, size, false, big_page, false)}; + mapping_map[params.offset] = mapping; } std::memcpy(output.data(), ¶ms, output.size()); - return result; + return NvResult::Success; } NvResult nvhost_as_gpu::UnmapBuffer(const std::vector& input, std::vector& output) { @@ -264,13 +416,36 @@ NvResult nvhost_as_gpu::UnmapBuffer(const std::vector& input, std::vectorUnmap(params.offset, *size); - } else { - LOG_ERROR(Service_NVDRV, "invalid offset=0x{:X}", params.offset); + std::scoped_lock lock(mutex); + + if (!vm.initialised) { + return NvResult::BadValue; + } + + try { + auto mapping{mapping_map.at(params.offset)}; + + if (!mapping->fixed) { + auto& allocator{mapping->big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; + u32 page_size_bits{mapping->big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS}; + + allocator.Free(static_cast(mapping->offset >> page_size_bits), + static_cast(mapping->size >> page_size_bits)); + } + + // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state + // Only FreeSpace can unmap them fully + if (mapping->sparse_alloc) { + gmmu->MapSparse(params.offset, mapping->size); + } else { + gmmu->Unmap(params.offset, mapping->size); + } + + mapping_map.erase(params.offset); + } catch ([[maybe_unused]] const std::out_of_range& e) { + LOG_WARNING(Service_NVDRV, "Couldn't find region to unmap at 0x{:X}", params.offset); } - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } @@ -284,28 +459,37 @@ NvResult nvhost_as_gpu::BindChannel(const std::vector& input, std::vector{ + VaRegion{ + .offset = vm.small_page_allocator->vaStart << VM::PAGE_SIZE_BITS, + .page_size = VM::YUZU_PAGESIZE, + .pages = vm.small_page_allocator->vaLimit - vm.small_page_allocator->vaStart, + }, + VaRegion{ + .offset = vm.big_page_allocator->vaStart << vm.big_page_size_bits, + .page_size = vm.big_page_size, + .pages = vm.big_page_allocator->vaLimit - vm.big_page_allocator->vaStart, + }, + }; +} + NvResult nvhost_as_gpu::GetVARegions(const std::vector& input, std::vector& output) { IoctlGetVaRegions params{}; std::memcpy(¶ms, input.data(), input.size()); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr, - params.buf_size); - - params.buf_size = 0x30; + LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr, + params.buf_size); - params.small = IoctlVaRegion{ - .offset = 0x04000000, - .page_size = DEFAULT_SMALL_PAGE_SIZE, - .pages = 0x3fbfff, - }; + std::scoped_lock lock(mutex); - params.big = IoctlVaRegion{ - .offset = 0x04000000, - .page_size = big_page_size, - .pages = 0x1bffff, - }; + if (!vm.initialised) { + return NvResult::BadValue; + } - // TODO(ogniK): This probably can stay stubbed but should add support way way later + GetVARegionsImpl(params); std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; @@ -316,64 +500,24 @@ NvResult nvhost_as_gpu::GetVARegions(const std::vector& input, std::vector nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const { - const auto end{buffer_mappings.upper_bound(gpu_addr)}; - for (auto iter{buffer_mappings.begin()}; iter != end; ++iter) { - if (gpu_addr >= iter->second.StartAddr() && gpu_addr < iter->second.EndAddr()) { - return iter->second; - } - } - - return std::nullopt; -} - -void nvhost_as_gpu::AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, - bool is_allocated) { - buffer_mappings[gpu_addr] = {gpu_addr, size, cpu_addr, is_allocated}; -} - -std::optional nvhost_as_gpu::RemoveBufferMap(GPUVAddr gpu_addr) { - if (const auto iter{buffer_mappings.find(gpu_addr)}; iter != buffer_mappings.end()) { - std::size_t size{}; - - if (iter->second.IsAllocated()) { - size = iter->second.Size(); - } - - buffer_mappings.erase(iter); - - return size; - } - - return std::nullopt; -} - Kernel::KEvent* nvhost_as_gpu::QueryEvent(u32 event_id) { LOG_CRITICAL(Service_NVDRV, "Unknown AS GPU Event {}", event_id); return nullptr; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index f5fb33ba7..1d27739e2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -5,14 +5,19 @@ #pragma once +#include +#include #include #include +#include #include #include +#include "common/address_space.h" #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" +#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" namespace Tegra { @@ -30,17 +35,13 @@ class NvMap; namespace Service::Nvidia::Devices { -constexpr u32 DEFAULT_BIG_PAGE_SIZE = 1 << 16; -constexpr u32 DEFAULT_SMALL_PAGE_SIZE = 1 << 12; - -class nvmap; - -enum class AddressSpaceFlags : u32 { - None = 0x0, - FixedOffset = 0x1, - Remap = 0x100, +enum class MappingFlags : u32 { + None = 0, + Fixed = 1 << 0, + Sparse = 1 << 1, + Remap = 1 << 8, }; -DECLARE_ENUM_FLAG_OPERATORS(AddressSpaceFlags); +DECLARE_ENUM_FLAG_OPERATORS(MappingFlags); class nvhost_as_gpu final : public nvdevice { public: @@ -59,46 +60,15 @@ public: Kernel::KEvent* QueryEvent(u32 event_id) override; -private: - class BufferMap final { - public: - constexpr BufferMap() = default; - - constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_) - : start_addr{start_addr_}, end_addr{start_addr_ + size_} {} - - constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_, VAddr cpu_addr_, - bool is_allocated_) - : start_addr{start_addr_}, end_addr{start_addr_ + size_}, cpu_addr{cpu_addr_}, - is_allocated{is_allocated_} {} - - constexpr VAddr StartAddr() const { - return start_addr; - } - - constexpr VAddr EndAddr() const { - return end_addr; - } - - constexpr std::size_t Size() const { - return end_addr - start_addr; - } - - constexpr VAddr CpuAddr() const { - return cpu_addr; - } - - constexpr bool IsAllocated() const { - return is_allocated; - } - - private: - GPUVAddr start_addr{}; - GPUVAddr end_addr{}; - VAddr cpu_addr{}; - bool is_allocated{}; + struct VaRegion { + u64 offset; + u32 page_size; + u32 _pad0_; + u64 pages; }; + static_assert(sizeof(VaRegion) == 0x18); +private: struct IoctlAllocAsEx { u32_le flags{}; // usually passes 1 s32_le as_fd{}; // ignored; passes 0 @@ -113,7 +83,7 @@ private: struct IoctlAllocSpace { u32_le pages{}; u32_le page_size{}; - AddressSpaceFlags flags{}; + MappingFlags flags{}; INSERT_PADDING_WORDS(1); union { u64_le offset; @@ -130,19 +100,19 @@ private: static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size"); struct IoctlRemapEntry { - u16_le flags{}; - u16_le kind{}; - u32_le nvmap_handle{}; - u32_le map_offset{}; - u32_le offset{}; - u32_le pages{}; + u16 flags; + u16 kind; + NvCore::NvMap::Handle::Id handle; + u32 handle_offset_big_pages; + u32 as_offset_big_pages; + u32 big_pages; }; static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size"); struct IoctlMapBufferEx { - AddressSpaceFlags flags{}; // bit0: fixed_offset, bit2: cacheable - u32_le kind{}; // -1 is default - u32_le nvmap_handle{}; + MappingFlags flags{}; // bit0: fixed_offset, bit2: cacheable + u32_le kind{}; // -1 is default + NvCore::NvMap::Handle::Id handle; u32_le page_size{}; // 0 means don't care s64_le buffer_offset{}; u64_le mapping_size{}; @@ -160,27 +130,15 @@ private: }; static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size"); - struct IoctlVaRegion { - u64_le offset{}; - u32_le page_size{}; - INSERT_PADDING_WORDS(1); - u64_le pages{}; - }; - static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size"); - struct IoctlGetVaRegions { u64_le buf_addr{}; // (contained output user ptr on linux, ignored) u32_le buf_size{}; // forced to 2*sizeof(struct va_region) u32_le reserved{}; - IoctlVaRegion small{}; - IoctlVaRegion big{}; + std::array regions{}; }; - static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2, + static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2, "IoctlGetVaRegions is incorrect size"); - s32 channel{}; - u32 big_page_size{DEFAULT_BIG_PAGE_SIZE}; - NvResult AllocAsEx(const std::vector& input, std::vector& output); NvResult AllocateSpace(const std::vector& input, std::vector& output); NvResult Remap(const std::vector& input, std::vector& output); @@ -189,23 +147,74 @@ private: NvResult FreeSpace(const std::vector& input, std::vector& output); NvResult BindChannel(const std::vector& input, std::vector& output); + void GetVARegionsImpl(IoctlGetVaRegions& params); NvResult GetVARegions(const std::vector& input, std::vector& output); NvResult GetVARegions(const std::vector& input, std::vector& output, std::vector& inline_output); - std::optional FindBufferMap(GPUVAddr gpu_addr) const; - void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); - std::optional RemoveBufferMap(GPUVAddr gpu_addr); + void FreeMappingLocked(u64 offset); Module& module; NvCore::Container& container; NvCore::NvMap& nvmap; + struct Mapping { + VAddr ptr; + u64 offset; + u64 size; + bool fixed; + bool big_page; // Only valid if fixed == false + bool sparse_alloc; + + Mapping(VAddr ptr_, u64 offset_, u64 size_, bool fixed_, bool big_page_, bool sparse_alloc_) + : ptr(ptr_), offset(offset_), size(size_), fixed(fixed_), big_page(big_page_), + sparse_alloc(sparse_alloc_) {} + }; + + struct Allocation { + u64 size; + std::list> mappings; + u32 page_size; + bool sparse; + }; + + std::map> + mapping_map; //!< This maps the base addresses of mapped buffers to their total sizes and + //!< mapping type, this is needed as what was originally a single buffer may + //!< have been split into multiple GPU side buffers with the remap flag. + std::map allocation_map; //!< Holds allocations created by AllocSpace from + //!< which fixed buffers can be mapped into + std::mutex mutex; //!< Locks all AS operations + + struct VM { + static constexpr u32 YUZU_PAGESIZE{0x1000}; + static constexpr u32 PAGE_SIZE_BITS{std::countr_zero(YUZU_PAGESIZE)}; + + static constexpr u32 SUPPORTED_BIG_PAGE_SIZES{0x30000}; + static constexpr u32 DEFAULT_BIG_PAGE_SIZE{0x20000}; + u32 big_page_size{DEFAULT_BIG_PAGE_SIZE}; + u32 big_page_size_bits{std::countr_zero(DEFAULT_BIG_PAGE_SIZE)}; + + static constexpr u32 VA_START_SHIFT{10}; + static constexpr u64 DEFAULT_VA_SPLIT{1ULL << 34}; + static constexpr u64 DEFAULT_VA_RANGE{1ULL << 37}; + u64 va_range_start{DEFAULT_BIG_PAGE_SIZE << VA_START_SHIFT}; + u64 va_range_split{DEFAULT_VA_SPLIT}; + u64 va_range_end{DEFAULT_VA_RANGE}; + + using Allocator = Common::FlatAllocator; + + std::unique_ptr big_page_allocator; + std::shared_ptr + small_page_allocator; //! Shared as this is also used by nvhost::GpuChannel + + bool initialised{}; + } vm; std::shared_ptr gmmu; - // This is expected to be ordered, therefore we must use a map, not unordered_map - std::map buffer_mappings; + // s32 channel{}; + // u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE}; }; } // namespace Service::Nvidia::Devices -- cgit v1.2.3 From 6fc4012396e98a1a6ac455791b314d2280a12a51 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 16 Nov 2021 00:01:40 +0100 Subject: VideoCore: Extra Fixes. --- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index a859a7abd..54074af75 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -143,7 +143,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector } }(); - must_unmark_fail = true; + must_unmark_fail = false; const auto check_failing = [&]() { if (events[slot].fails > 2) { @@ -164,6 +164,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector if (params.timeout == 0) { if (check_failing()) { + events[slot].fails = 0; return NvResult::Success; } return NvResult::Timeout; @@ -180,6 +181,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector } if (check_failing()) { + event.fails = 0; return NvResult::Success; } -- cgit v1.2.3 From f350c3d74ea7880fc6d21f7f638b0d4a70a3246b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 1 Jan 2022 22:03:37 +0100 Subject: Texture cache: Fix the remaining issues with memory mnagement and unmapping. --- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 344ddfc90..db2a6c3b2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -16,6 +16,7 @@ #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "video_core/control/channel_state.h" +#include "video_core/gpu.h" #include "video_core/memory_manager.h" #include "video_core/rasterizer_interface.h" @@ -24,6 +25,7 @@ namespace Service::Nvidia::Devices { nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, Module& module_, NvCore::Container& core) : nvdevice{system_}, module{module_}, container{core}, nvmap{core.GetNvMapFile()}, vm{}, gmmu{} {} + nvhost_as_gpu::~nvhost_as_gpu() = default; NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, @@ -132,6 +134,7 @@ NvResult nvhost_as_gpu::AllocAsEx(const std::vector& input, std::vector& vm.big_page_allocator = std::make_unique(start_big_pages, end_big_pages); gmmu = std::make_shared(system, 40, VM::PAGE_SIZE_BITS); + system.GPU().InitAddressSpace(*gmmu); vm.initialised = true; return NvResult::Success; -- cgit v1.2.3 From 668e80a9f42fb4ce0e16f6381d05bcbd286b2da1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 30 Jan 2022 10:31:13 +0100 Subject: VideoCore: Refactor syncing. --- src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 19 +++++++++++++++---- src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 4 ++++ src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 10 +++++----- src/core/hle/service/nvflinger/nvflinger.cpp | 9 +++++++-- 5 files changed, 32 insertions(+), 12 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index b1c0e9eb2..e6a976714 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -50,7 +50,7 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat form stride, format, transform, crop_rect}; system.GetPerfStats().EndSystemFrame(); - system.GPU().SwapBuffers(&framebuffer); + system.GPU().RequestSwapBuffers(&framebuffer, nullptr, 0); system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs()); system.GetPerfStats().BeginSystemFrame(); } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 54074af75..ffe42d423 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -18,6 +18,7 @@ #include "core/hle/service/nvdrv/core/syncpoint_manager.h" #include "core/hle/service/nvdrv/devices/nvhost_ctrl.h" #include "video_core/gpu.h" +#include "video_core/host1x/host1x.h" namespace Service::Nvidia::Devices { @@ -129,7 +130,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector return NvResult::Success; } - auto& gpu = system.GPU(); + auto& host1x_syncpoint_manager = system.Host1x().GetSyncpointManager(); const u32 target_value = params.fence.value; auto lock = NvEventsLock(); @@ -149,7 +150,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector if (events[slot].fails > 2) { { auto lk = system.StallProcesses(); - gpu.WaitFence(fence_id, target_value); + host1x_syncpoint_manager.WaitHost(fence_id, target_value); system.UnstallProcesses(); } params.value.raw = target_value; @@ -198,7 +199,15 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector } params.value.raw |= slot; - gpu.RegisterSyncptInterrupt(fence_id, target_value); + event.wait_handle = + host1x_syncpoint_manager.RegisterHostAction(fence_id, target_value, [this, slot]() { + auto& event = events[slot]; + if (event.status.exchange(EventState::Signalling, std::memory_order_acq_rel) == + EventState::Waiting) { + event.kevent->GetWritableEvent().Signal(); + } + event.status.store(EventState::Signalled, std::memory_order_release); + }); return NvResult::Timeout; } @@ -288,8 +297,10 @@ NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector& input, std::v auto& event = events[event_id]; if (event.status.exchange(EventState::Cancelling, std::memory_order_acq_rel) == EventState::Waiting) { - system.GPU().CancelSyncptInterrupt(event.assigned_syncpt, event.assigned_value); + auto& host1x_syncpoint_manager = system.Host1x().GetSyncpointManager(); + host1x_syncpoint_manager.DeregisterHostAction(event.assigned_syncpt, event.wait_handle); syncpoint_manager.RefreshSyncpoint(event.assigned_syncpt); + event.wait_handle = {}; } event.fails++; event.status.store(EventState::Cancelled, std::memory_order_release); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index d56aea405..136a1e925 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -11,6 +11,7 @@ #include "common/common_types.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" #include "core/hle/service/nvdrv/nvdrv.h" +#include "video_core/host1x/syncpoint_manager.h" namespace Service::Nvidia::NvCore { class Container; @@ -78,6 +79,9 @@ private: // Tells if an NVEvent is registered or not bool registered{}; + // Used for waiting on a syncpoint & canceling it. + Tegra::Host1x::SyncpointManager::ActionHandle wait_handle{}; + bool IsBeingUsed() { const auto current_status = status.load(std::memory_order_acquire); return current_status == EventState::Waiting || diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 38d45cb79..db3e266ad 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -210,10 +210,10 @@ NvResult nvhost_gpu::AllocateObjectContext(const std::vector& input, std::ve static std::vector BuildWaitCommandList(NvFence fence) { return { - Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1, + Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointPayload, 1, Tegra::SubmissionMode::Increasing), {fence.value}, - Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1, + Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointOperation, 1, Tegra::SubmissionMode::Increasing), BuildFenceAction(Tegra::Engines::Puller::FenceOperation::Acquire, fence.id), }; @@ -222,12 +222,12 @@ static std::vector BuildWaitCommandList(NvFence fence) { static std::vector BuildIncrementCommandList(NvFence fence, u32 add_increment) { std::vector result{ - Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1, + Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointPayload, 1, Tegra::SubmissionMode::Increasing), {}}; for (u32 count = 0; count < add_increment; ++count) { - result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1, + result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointOperation, 1, Tegra::SubmissionMode::Increasing)); result.emplace_back( BuildFenceAction(Tegra::Engines::Puller::FenceOperation::Increment, fence.id)); @@ -239,7 +239,7 @@ static std::vector BuildIncrementCommandList(NvFence fence static std::vector BuildIncrementWithWfiCommandList(NvFence fence, u32 add_increment) { std::vector result{ - Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForInterrupt, 1, + Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForIdle, 1, Tegra::SubmissionMode::Increasing), {}}; const std::vector increment{ diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 8c3013f83..aa112021d 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -24,6 +24,8 @@ #include "core/hle/service/vi/layer/vi_layer.h" #include "core/hle/service/vi/vi_results.h" #include "video_core/gpu.h" +#include "video_core/host1x/host1x.h" +#include "video_core/host1x/syncpoint_manager.h" namespace Service::NVFlinger { @@ -267,12 +269,12 @@ void NVFlinger::Compose() { return; // We are likely shutting down } - auto& gpu = system.GPU(); + auto& syncpoint_manager = system.Host1x().GetSyncpointManager(); const auto& multi_fence = buffer.fence; guard->unlock(); for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) { const auto& fence = multi_fence.fences[fence_id]; - gpu.WaitFence(fence.id, fence.value); + syncpoint_manager.WaitGuest(fence.id, fence.value); } guard->lock(); @@ -284,6 +286,7 @@ void NVFlinger::Compose() { auto nvdisp = nvdrv->GetDevice(disp_fd); ASSERT(nvdisp); + guard->unlock(); Common::Rectangle crop_rect{ static_cast(buffer.crop.Left()), static_cast(buffer.crop.Top()), static_cast(buffer.crop.Right()), static_cast(buffer.crop.Bottom())}; @@ -292,6 +295,8 @@ void NVFlinger::Compose() { igbp_buffer.Width(), igbp_buffer.Height(), igbp_buffer.Stride(), static_cast(buffer.transform), crop_rect); + guard->lock(); + swap_interval = buffer.swap_interval; auto fence = android::Fence::NoFence(); -- cgit v1.2.3 From 2931101e6f5aa755566ef40f6e6dc71909fd3e92 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 30 Jan 2022 22:26:01 +0100 Subject: NVDRV: Refactor Host1x --- src/core/hle/service/nvdrv/core/container.cpp | 8 ++--- src/core/hle/service/nvdrv/core/container.h | 10 ++++-- src/core/hle/service/nvdrv/core/nvmap.cpp | 33 ++++++++----------- src/core/hle/service/nvdrv/core/nvmap.h | 18 ++++++++--- .../hle/service/nvdrv/core/syncpoint_manager.cpp | 6 ++-- .../hle/service/nvdrv/core/syncpoint_manager.h | 12 ++++--- .../service/nvdrv/devices/nvhost_nvdec_common.cpp | 37 +++++++--------------- src/core/hle/service/nvdrv/nvdrv.cpp | 2 +- 8 files changed, 62 insertions(+), 64 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index 97b5b2c86..fbd66f001 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -6,18 +6,18 @@ #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h" -#include "video_core/gpu.h" +#include "video_core/host1x/host1x.h" namespace Service::Nvidia::NvCore { struct ContainerImpl { - ContainerImpl(Tegra::GPU& gpu_) : file{}, manager{gpu_} {} + ContainerImpl(Tegra::Host1x::Host1x& host1x_) : file{host1x_}, manager{host1x_} {} NvMap file; SyncpointManager manager; }; -Container::Container(Tegra::GPU& gpu_) { - impl = std::make_unique(gpu_); +Container::Container(Tegra::Host1x::Host1x& host1x_) { + impl = std::make_unique(host1x_); } Container::~Container() = default; diff --git a/src/core/hle/service/nvdrv/core/container.h b/src/core/hle/service/nvdrv/core/container.h index 91ac2305a..da75d74ff 100644 --- a/src/core/hle/service/nvdrv/core/container.h +++ b/src/core/hle/service/nvdrv/core/container.h @@ -8,8 +8,12 @@ #include namespace Tegra { -class GPU; -} + +namespace Host1x { +class Host1x; +} // namespace Host1x + +} // namespace Tegra namespace Service::Nvidia::NvCore { @@ -20,7 +24,7 @@ struct ContainerImpl; class Container { public: - Container(Tegra::GPU& gpu_); + Container(Tegra::Host1x::Host1x& host1x); ~Container(); NvMap& GetNvMapFile(); diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index 1126daeb5..9acec7ba6 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -7,6 +7,7 @@ #include "common/logging/log.h" #include "core/hle/service/nvdrv/core/nvmap.h" #include "core/memory.h" +#include "video_core/host1x/host1x.h" using Core::Memory::YUZU_PAGESIZE; @@ -61,7 +62,7 @@ NvResult NvMap::Handle::Duplicate(bool internal_session) { return NvResult::Success; } -NvMap::NvMap() = default; +NvMap::NvMap(Tegra::Host1x::Host1x& host1x_) : host1x{host1x_} {} void NvMap::AddHandle(std::shared_ptr handle_description) { std::scoped_lock lock(handles_lock); @@ -77,12 +78,11 @@ void NvMap::UnmapHandle(Handle& handle_description) { } // Free and unmap the handle from the SMMU - /* - state.soc->smmu.Unmap(handle_description.pin_virt_address, - static_cast(handle_description.aligned_size)); - smmuAllocator.Free(handle_description.pin_virt_address, - static_cast(handle_description.aligned_size)); handle_description.pin_virt_address = 0; - */ + host1x.MemoryManager().Unmap(static_cast(handle_description.pin_virt_address), + handle_description.aligned_size); + host1x.Allocator().Free(handle_description.pin_virt_address, + static_cast(handle_description.aligned_size)); + handle_description.pin_virt_address = 0; } bool NvMap::TryRemoveHandle(const Handle& handle_description) { @@ -131,12 +131,9 @@ VAddr NvMap::GetHandleAddress(Handle::Id handle) { } u32 NvMap::PinHandle(NvMap::Handle::Id handle) { - UNIMPLEMENTED_MSG("pinning"); - return 0; - /* auto handle_description{GetHandle(handle)}; - if (!handle_description) - [[unlikely]] return 0; + if (!handle_description) [[unlikely]] + return 0; std::scoped_lock lock(handle_description->mutex); if (!handle_description->pins) { @@ -157,8 +154,10 @@ u32 NvMap::PinHandle(NvMap::Handle::Id handle) { // If not then allocate some space and map it u32 address{}; + auto& smmu_allocator = host1x.Allocator(); + auto& smmu_memory_manager = host1x.MemoryManager(); while (!(address = - smmuAllocator.Allocate(static_cast(handle_description->aligned_size)))) { + smmu_allocator.Allocate(static_cast(handle_description->aligned_size)))) { // Free handles until the allocation succeeds std::scoped_lock queueLock(unmap_queue_lock); if (auto freeHandleDesc{unmap_queue.front()}) { @@ -172,19 +171,16 @@ u32 NvMap::PinHandle(NvMap::Handle::Id handle) { } } - state.soc->smmu.Map(address, handle_description->GetPointer(), - static_cast(handle_description->aligned_size)); + smmu_memory_manager.Map(static_cast(address), handle_description->address, + handle_description->aligned_size); handle_description->pin_virt_address = address; } handle_description->pins++; return handle_description->pin_virt_address; - */ } void NvMap::UnpinHandle(Handle::Id handle) { - UNIMPLEMENTED_MSG("Unpinning"); - /* auto handle_description{GetHandle(handle)}; if (!handle_description) return; @@ -199,7 +195,6 @@ void NvMap::UnpinHandle(Handle::Id handle) { unmap_queue.push_back(handle_description); handle_description->unmap_queue_entry = std::prev(unmap_queue.end()); } - */ } std::optional NvMap::FreeHandle(Handle::Id handle, bool internal_session) { diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index 5e6c73589..5acdc961e 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -15,6 +15,14 @@ #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 { /** * @brief The nvmap core class holds the global state for nvmap and provides methods to manage @@ -90,15 +98,17 @@ public: }; private: - std::list> unmap_queue; - std::mutex unmap_queue_lock; //!< Protects access to `unmap_queue` + std::list> unmap_queue{}; + std::mutex unmap_queue_lock{}; //!< Protects access to `unmap_queue` - std::unordered_map> handles; //!< Main owning map of handles + std::unordered_map> + handles{}; //!< Main owning map of handles std::mutex handles_lock; //!< Protects access to `handles` static constexpr u32 HandleIdIncrement{ 4}; //!< Each new handle ID is an increment of 4 from the previous std::atomic next_handle_id{HandleIdIncrement}; + Tegra::Host1x::Host1x& host1x; void AddHandle(std::shared_ptr handle); @@ -125,7 +135,7 @@ public: bool was_uncached; //!< If the handle was allocated as uncached }; - NvMap(); + NvMap(Tegra::Host1x::Host1x& host1x); /** * @brief Creates an unallocated handle of the given size diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp index ff6cbb37e..61e00448c 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp @@ -3,16 +3,16 @@ #include "common/assert.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h" -#include "video_core/gpu.h" +#include "video_core/host1x/host1x.h" namespace Service::Nvidia::NvCore { -SyncpointManager::SyncpointManager(Tegra::GPU& gpu_) : gpu{gpu_} {} +SyncpointManager::SyncpointManager(Tegra::Host1x::Host1x& host1x_) : host1x{host1x_} {} SyncpointManager::~SyncpointManager() = default; u32 SyncpointManager::RefreshSyncpoint(u32 syncpoint_id) { - syncpoints[syncpoint_id].min = gpu.GetSyncpointValue(syncpoint_id); + syncpoints[syncpoint_id].min = host1x.GetSyncpointManager().GetHostSyncpointValue(syncpoint_id); return GetSyncpointMin(syncpoint_id); } diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.h b/src/core/hle/service/nvdrv/core/syncpoint_manager.h index cf7f0b4be..f332edc6e 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.h +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.h @@ -10,14 +10,18 @@ #include "core/hle/service/nvdrv/nvdata.h" namespace Tegra { -class GPU; -} + +namespace Host1x { +class Host1x; +} // namespace Host1x + +} // namespace Tegra namespace Service::Nvidia::NvCore { class SyncpointManager final { public: - explicit SyncpointManager(Tegra::GPU& gpu_); + explicit SyncpointManager(Tegra::Host1x::Host1x& host1x); ~SyncpointManager(); /** @@ -78,7 +82,7 @@ private: std::array syncpoints{}; - Tegra::GPU& gpu; + Tegra::Host1x::Host1x& host1x; }; } // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 77e6a1cd6..b17589aa3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -13,6 +13,7 @@ #include "core/hle/service/nvdrv/core/syncpoint_manager.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h" #include "core/memory.h" +#include "video_core/host1x/host1x.h" #include "video_core/memory_manager.h" #include "video_core/renderer_base.h" @@ -140,29 +141,8 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector& input, std::vecto SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer)); - auto& gpu = system.GPU(); - for (auto& cmd_buffer : cmd_buffer_handles) { - auto object{nvmap.GetHandle(cmd_buffer.map_handle)}; - if (!object) { - LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmd_buffer.map_handle); - std::memcpy(output.data(), ¶ms, output.size()); - return NvResult::InvalidState; - } - if (object->dma_map_addr == 0) { - // NVDEC and VIC memory is in the 32-bit address space - // MapAllocate32 will attempt to map a lower 32-bit value in the shared gpu memory space - const GPUVAddr low_addr = - gpu.MemoryManager().MapAllocate32(object->address, object->size); - object->dma_map_addr = static_cast(low_addr); - // Ensure that the dma_map_addr is indeed in the lower 32-bit address space. - ASSERT(object->dma_map_addr == low_addr); - } - if (!object->dma_map_addr) { - LOG_ERROR(Service_NVDRV, "failed to map size={}", object->size); - } else { - cmd_buffer.map_address = static_cast(object->dma_map_addr); - } + cmd_buffer.map_address = nvmap.PinHandle(cmd_buffer.map_handle); } std::memcpy(output.data(), ¶ms, sizeof(IoctlMapBuffer)); std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(), @@ -172,11 +152,16 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector& input, std::vecto } NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector& input, std::vector& output) { - // This is intntionally stubbed. - // Skip unmapping buffers here, as to not break the continuity of the VP9 reference frame - // addresses, and risk invalidating data before the async GPU thread is done with it + IoctlMapBuffer params{}; + std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); + std::vector cmd_buffer_handles(params.num_entries); + + SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer)); + for (auto& cmd_buffer : cmd_buffer_handles) { + nvmap.UnpinHandle(cmd_buffer.map_handle); + } + std::memset(output.data(), 0, output.size()); - LOG_DEBUG(Service_NVDRV, "(STUBBED) called"); return NvResult::Success; } diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index b39a4c6db..8a9f3c717 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -71,7 +71,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger } Module::Module(Core::System& system) - : service_context{system, "nvdrv"}, events_interface{*this}, container{system.GPU()} { + : service_context{system, "nvdrv"}, events_interface{*this}, container{system.Host1x()} { builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) { std::shared_ptr device = std::make_shared(system, *this, container); -- cgit v1.2.3 From 920429fde745b3bf6d33b6ca991628f64988f754 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 30 Jan 2022 23:13:46 +0100 Subject: NVDRV: Further refactors and eliminate old code. --- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 26 +++------------------- src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 2 -- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 7 ++++-- src/core/hle/service/nvdrv/nvdrv.cpp | 21 ----------------- src/core/hle/service/nvdrv/nvdrv.h | 7 ------ src/core/hle/service/nvdrv/nvdrv_interface.cpp | 4 ---- src/core/hle/service/nvdrv/nvdrv_interface.h | 2 -- 7 files changed, 8 insertions(+), 61 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index ffe42d423..076edb02f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -77,12 +77,9 @@ NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, const std::vector& return NvResult::NotImplemented; } -void nvhost_ctrl::OnOpen(DeviceFD fd) { - events_interface.RegisterForSignal(this); -} -void nvhost_ctrl::OnClose(DeviceFD fd) { - events_interface.UnregisterForSignal(this); -} +void nvhost_ctrl::OnOpen(DeviceFD fd) {} + +void nvhost_ctrl::OnClose(DeviceFD fd) {} NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector& input, std::vector& output) { IocGetConfigParams params{}; @@ -395,21 +392,4 @@ u32 nvhost_ctrl::FindFreeNvEvent(u32 syncpoint_id) { return 0; } -void nvhost_ctrl::SignalNvEvent(u32 syncpoint_id, u32 value) { - u64 signal_mask = events_mask; - while (signal_mask != 0) { - const u64 event_id = std::countr_zero(signal_mask); - signal_mask &= ~(1ULL << event_id); - auto& event = events[event_id]; - if (event.assigned_syncpt != syncpoint_id || event.assigned_value != value) { - continue; - } - if (event.status.exchange(EventState::Signalling, std::memory_order_acq_rel) == - EventState::Waiting) { - event.kevent->GetWritableEvent().Signal(); - } - event.status.store(EventState::Signalled, std::memory_order_release); - } -} - } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 136a1e925..f511c0296 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -56,8 +56,6 @@ public: }; static_assert(sizeof(SyncpointEventValue) == sizeof(u32)); - void SignalNvEvent(u32 syncpoint_id, u32 value); - private: struct InternalEvent { // Mask representing registered events diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index db3e266ad..3f981af5a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -14,6 +14,7 @@ #include "video_core/control/channel_state.h" #include "video_core/engines/puller.h" #include "video_core/gpu.h" +#include "video_core/host1x/host1x.h" namespace Service::Nvidia::Devices { namespace { @@ -31,7 +32,8 @@ nvhost_gpu::nvhost_gpu(Core::System& system_, EventInterface& events_interface_, syncpoint_manager{core_.GetSyncpointManager()}, nvmap{core.GetNvMapFile()}, channel_state{system.GPU().AllocateChannel()} { channel_fence.id = syncpoint_manager.AllocateSyncpoint(); - channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id); + channel_fence.value = + system_.Host1x().GetSyncpointManager().GetGuestSyncpointValue(channel_fence.id); sm_exception_breakpoint_int_report_event = events_interface.CreateEvent("GpuChannelSMExceptionBreakpointInt"); sm_exception_breakpoint_pause_report_event = @@ -189,7 +191,8 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector& input, std::vector lk(guard); - on_signal.push_back(device); -} - -void EventInterface::UnregisterForSignal(Devices::nvhost_ctrl* device) { - std::unique_lock lk(guard); - on_signal.remove(device); -} - -void EventInterface::Signal(u32 syncpoint_id, u32 value) { - std::unique_lock lk(guard); - for (auto* device : on_signal) { - device->SignalNvEvent(syncpoint_id, value); - } -} - Kernel::KEvent* EventInterface::CreateEvent(std::string name) { Kernel::KEvent* new_event = module.service_context.CreateEvent(std::move(name)); return new_event; @@ -221,10 +204,6 @@ NvResult Module::Close(DeviceFD fd) { return NvResult::Success; } -void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { - events_interface.Signal(syncpoint_id, value); -} - NvResult Module::QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 1fe98cf32..31c45236e 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -49,11 +49,6 @@ public: EventInterface(Module& module_); ~EventInterface(); - void RegisterForSignal(Devices::nvhost_ctrl*); - void UnregisterForSignal(Devices::nvhost_ctrl*); - - void Signal(u32 syncpoint_id, u32 value); - Kernel::KEvent* CreateEvent(std::string name); void FreeEvent(Kernel::KEvent* event); @@ -96,8 +91,6 @@ public: /// Closes a device file descriptor and returns operation success. NvResult Close(DeviceFD fd); - void SignalSyncpt(const u32 syncpoint_id, const u32 value); - NvResult QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event); private: diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index bd41205b8..5e50a04e8 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -15,10 +15,6 @@ namespace Service::Nvidia { -void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) { - nvdrv->SignalSyncpt(syncpoint_id, value); -} - void NVDRV::Open(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NVDRV, "called"); IPC::ResponseBuilder rb{ctx, 4}; diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.h b/src/core/hle/service/nvdrv/nvdrv_interface.h index cbd37b52b..cd58a4f35 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.h +++ b/src/core/hle/service/nvdrv/nvdrv_interface.h @@ -18,8 +18,6 @@ public: explicit NVDRV(Core::System& system_, std::shared_ptr nvdrv_, const char* name); ~NVDRV() override; - void SignalGPUInterruptSyncpt(u32 syncpoint_id, u32 value); - private: void Open(Kernel::HLERequestContext& ctx); void Ioctl1(Kernel::HLERequestContext& ctx); -- cgit v1.2.3 From 4d60410dd979fb688de7735d2b4b25a557bdeac7 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 5 Feb 2022 18:15:26 +0100 Subject: MemoryManager: initial multi paging system implementation. --- .../hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 45 ++++++++++++---------- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | 1 + src/core/hle/service/nvdrv/devices/nvmap.cpp | 10 +++++ 3 files changed, 36 insertions(+), 20 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index db2a6c3b2..d95a88393 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -133,7 +133,8 @@ NvResult nvhost_as_gpu::AllocAsEx(const std::vector& input, std::vector& const u64 end_big_pages{(vm.va_range_end - vm.va_range_split) >> vm.big_page_size_bits}; vm.big_page_allocator = std::make_unique(start_big_pages, end_big_pages); - gmmu = std::make_shared(system, 40, VM::PAGE_SIZE_BITS); + gmmu = std::make_shared(system, 40, vm.big_page_size_bits, + VM::PAGE_SIZE_BITS); system.GPU().InitAddressSpace(*gmmu); vm.initialised = true; @@ -189,6 +190,7 @@ NvResult nvhost_as_gpu::AllocateSpace(const std::vector& input, std::vector< .size = size, .page_size = params.page_size, .sparse = (params.flags & MappingFlags::Sparse) != MappingFlags::None, + .big_pages = params.page_size != VM::YUZU_PAGESIZE, }; std::memcpy(output.data(), ¶ms, output.size()); @@ -209,7 +211,7 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) { // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state // Only FreeSpace can unmap them fully if (mapping->sparse_alloc) - gmmu->MapSparse(offset, mapping->size); + gmmu->MapSparse(offset, mapping->size, mapping->big_page); else gmmu->Unmap(offset, mapping->size); @@ -294,8 +296,9 @@ NvResult nvhost_as_gpu::Remap(const std::vector& input, std::vector& out return NvResult::BadValue; } + const bool use_big_pages = alloc->second.big_pages; if (!entry.handle) { - gmmu->MapSparse(virtual_address, size); + gmmu->MapSparse(virtual_address, size, use_big_pages); } else { auto handle{nvmap.GetHandle(entry.handle)}; if (!handle) { @@ -306,7 +309,7 @@ NvResult nvhost_as_gpu::Remap(const std::vector& input, std::vector& out handle->address + (static_cast(entry.handle_offset_big_pages) << vm.big_page_size_bits))}; - gmmu->Map(virtual_address, cpu_address, size); + gmmu->Map(virtual_address, cpu_address, size, use_big_pages); } } @@ -345,7 +348,7 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vector(params.offset + params.buffer_offset)}; VAddr cpu_address{mapping->ptr + params.buffer_offset}; - gmmu->Map(gpu_address, cpu_address, params.mapping_size); + gmmu->Map(gpu_address, cpu_address, params.mapping_size, mapping->big_page); return NvResult::Success; } catch ([[maybe_unused]] const std::out_of_range& e) { @@ -363,6 +366,17 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vector(handle->address + params.buffer_offset)}; u64 size{params.mapping_size ? params.mapping_size : handle->orig_size}; + bool big_page{[&]() { + if (Common::IsAligned(handle->align, vm.big_page_size)) + return true; + else if (Common::IsAligned(handle->align, VM::YUZU_PAGESIZE)) + return false; + else { + UNREACHABLE(); + return false; + } + }()}; + if ((params.flags & MappingFlags::Fixed) != MappingFlags::None) { auto alloc{allocation_map.upper_bound(params.offset)}; @@ -372,23 +386,14 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vectorMap(params.offset, cpu_address, size); + const bool use_big_pages = alloc->second.big_pages && big_page; + gmmu->Map(params.offset, cpu_address, size, use_big_pages); - auto mapping{std::make_shared(cpu_address, params.offset, size, true, false, - alloc->second.sparse)}; + auto mapping{std::make_shared(cpu_address, params.offset, size, true, + use_big_pages, alloc->second.sparse)}; alloc->second.mappings.push_back(mapping); mapping_map[params.offset] = mapping; } else { - bool big_page{[&]() { - if (Common::IsAligned(handle->align, vm.big_page_size)) - return true; - else if (Common::IsAligned(handle->align, VM::YUZU_PAGESIZE)) - return false; - else { - UNREACHABLE(); - return false; - } - }()}; auto& allocator{big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; u32 page_size{big_page ? vm.big_page_size : VM::YUZU_PAGESIZE}; @@ -402,7 +407,7 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vectorMap(params.offset, cpu_address, size); + gmmu->Map(params.offset, cpu_address, Common::AlignUp(size, page_size), big_page); auto mapping{ std::make_shared(cpu_address, params.offset, size, false, big_page, false)}; @@ -439,7 +444,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(const std::vector& input, std::vectorsparse_alloc) { - gmmu->MapSparse(params.offset, mapping->size); + gmmu->MapSparse(params.offset, mapping->size, mapping->big_page); } else { gmmu->Unmap(params.offset, mapping->size); } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 1d27739e2..12e881f0d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -177,6 +177,7 @@ private: std::list> mappings; u32 page_size; bool sparse; + bool big_pages; }; std::map> diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 279997e81..992c117f1 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -9,6 +9,8 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/devices/nvmap.h" @@ -136,6 +138,10 @@ NvResult nvmap::IocAlloc(const std::vector& input, std::vector& output) LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle); return result; } + ASSERT(system.CurrentProcess() + ->PageTable() + .LockForDeviceAddressSpace(handle_description->address, handle_description->size) + .IsSuccess()); std::memcpy(output.data(), ¶ms, sizeof(params)); return result; } @@ -256,6 +262,10 @@ NvResult nvmap::IocFree(const std::vector& input, std::vector& output) { } if (auto freeInfo{file.FreeHandle(params.handle, false)}) { + ASSERT(system.CurrentProcess() + ->PageTable() + .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size) + .IsSuccess()); params.address = freeInfo->address; params.size = static_cast(freeInfo->size); params.flags.raw = 0; -- cgit v1.2.3 From bc8b3d225eda388f0603830cbff8357893abb0f9 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 6 Feb 2022 01:16:11 +0100 Subject: VideoCore: Refactor fencing system. --- src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | 5 +++-- src/core/hle/service/nvdrv/devices/nvdisp_disp0.h | 3 ++- src/core/hle/service/nvflinger/nvflinger.cpp | 15 +++------------ 3 files changed, 8 insertions(+), 15 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index e6a976714..18c5324a9 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -40,7 +40,8 @@ void nvdisp_disp0::OnClose(DeviceFD fd) {} void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, u32 height, u32 stride, android::BufferTransformFlags transform, - const Common::Rectangle& crop_rect) { + const Common::Rectangle& crop_rect, + std::array& fences, u32 num_fences) { const VAddr addr = nvmap.GetHandleAddress(buffer_handle); LOG_TRACE(Service, "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", @@ -50,7 +51,7 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat form stride, format, transform, crop_rect}; system.GetPerfStats().EndSystemFrame(); - system.GPU().RequestSwapBuffers(&framebuffer, nullptr, 0); + system.GPU().RequestSwapBuffers(&framebuffer, fences, num_fences); system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs()); system.GetPerfStats().BeginSystemFrame(); } diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 1ca9b2e74..04217ab12 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -38,7 +38,8 @@ public: /// Performs a screen flip, drawing the buffer pointed to by the handle. void flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, u32 height, u32 stride, android::BufferTransformFlags transform, - const Common::Rectangle& crop_rect); + const Common::Rectangle& crop_rect, + std::array& fences, u32 num_fences); Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index aa112021d..4658f1e8b 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -269,17 +269,6 @@ void NVFlinger::Compose() { return; // We are likely shutting down } - auto& syncpoint_manager = system.Host1x().GetSyncpointManager(); - const auto& multi_fence = buffer.fence; - guard->unlock(); - for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) { - const auto& fence = multi_fence.fences[fence_id]; - syncpoint_manager.WaitGuest(fence.id, fence.value); - } - guard->lock(); - - MicroProfileFlip(); - // Now send the buffer to the GPU for drawing. // TODO(Subv): Support more than just disp0. The display device selection is probably based // on which display we're drawing (Default, Internal, External, etc) @@ -293,8 +282,10 @@ void NVFlinger::Compose() { nvdisp->flip(igbp_buffer.BufferId(), igbp_buffer.Offset(), igbp_buffer.ExternalFormat(), igbp_buffer.Width(), igbp_buffer.Height(), igbp_buffer.Stride(), - static_cast(buffer.transform), crop_rect); + static_cast(buffer.transform), crop_rect, + buffer.fence.fences, buffer.fence.num_fences); + MicroProfileFlip(); guard->lock(); swap_interval = buffer.swap_interval; -- cgit v1.2.3 From a9ca39f8591532ba6d37f7a3e068d5eefe416464 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 7 Feb 2022 07:52:04 +0100 Subject: NVDRV: Further improvements. --- src/core/hle/service/nvdrv/core/container.cpp | 8 +- src/core/hle/service/nvdrv/core/container.h | 8 +- src/core/hle/service/nvdrv/core/nvmap.cpp | 7 +- src/core/hle/service/nvdrv/core/nvmap.h | 7 +- .../hle/service/nvdrv/core/syncpoint_manager.cpp | 112 ++++++++++++++++--- .../hle/service/nvdrv/core/syncpoint_manager.h | 120 ++++++++++++++------- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 18 ++-- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 59 +++++----- src/core/hle/service/nvdrv/devices/nvhost_gpu.h | 19 ++-- .../hle/service/nvdrv/devices/nvhost_nvdec.cpp | 2 +- .../service/nvdrv/devices/nvhost_nvdec_common.cpp | 15 ++- .../service/nvdrv/devices/nvhost_nvdec_common.h | 6 +- src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | 2 +- 13 files changed, 256 insertions(+), 127 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index fbd66f001..4175d3d9c 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -1,7 +1,7 @@ -// Copyright 2021 yuzu emulator team -// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// 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 "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/nvmap.h" diff --git a/src/core/hle/service/nvdrv/core/container.h b/src/core/hle/service/nvdrv/core/container.h index da75d74ff..e069ade4e 100644 --- a/src/core/hle/service/nvdrv/core/container.h +++ b/src/core/hle/service/nvdrv/core/container.h @@ -1,7 +1,7 @@ -// Copyright 2021 yuzu emulator team -// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// 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 diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index 9acec7ba6..86d825af9 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -1,6 +1,7 @@ -// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// 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/alignment.h" #include "common/assert.h" diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index 5acdc961e..4f37dcf43 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -1,6 +1,7 @@ -// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// 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 diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp index 61e00448c..b34481b48 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp @@ -1,5 +1,7 @@ -// 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. #include "common/assert.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h" @@ -7,32 +9,108 @@ namespace Service::Nvidia::NvCore { -SyncpointManager::SyncpointManager(Tegra::Host1x::Host1x& host1x_) : host1x{host1x_} {} +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::RefreshSyncpoint(u32 syncpoint_id) { - syncpoints[syncpoint_id].min = host1x.GetSyncpointManager().GetHostSyncpointValue(syncpoint_id); - return GetSyncpointMin(syncpoint_id); +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::AllocateSyncpoint() { - for (u32 syncpoint_id = 1; syncpoint_id < MaxSyncPoints; syncpoint_id++) { - if (!syncpoints[syncpoint_id].is_allocated) { - syncpoints[syncpoint_id].is_allocated = true; - return syncpoint_id; +u32 SyncpointManager::FindFreeSyncpoint() { + for (u32 i{1}; i < syncpoints.size(); i++) { + if (!syncpoints[i].reserved) { + return i; } } - ASSERT_MSG(false, "No more available syncpoints!"); - return {}; + 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(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; } -u32 SyncpointManager::IncreaseSyncpoint(u32 syncpoint_id, u32 value) { - for (u32 index = 0; index < value; ++index) { - syncpoints[syncpoint_id].max.fetch_add(1, std::memory_order_relaxed); +NvFence SyncpointManager::GetSyncpointFence(u32 id) { + if (!syncpoints.at(id).reserved) { + UNREACHABLE(); + return NvFence{}; } - return GetSyncpointMax(syncpoint_id); + return {.id = static_cast(id), .value = syncpoints.at(id).counterMax}; } } // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.h b/src/core/hle/service/nvdrv/core/syncpoint_manager.h index f332edc6e..bfc8ba84b 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.h +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.h @@ -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 #include +#include #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(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 min; - std::atomic max; - std::atomic 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 counterMin; //!< The least value the syncpoint can be (The value it was + //!< when it was last synchronized with host1x) + std::atomic 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 syncpoints{}; + constexpr static std::size_t SyncpointCount{192}; + std::array syncpoints{}; + std::mutex reservation_lock; Tegra::Host1x::Host1x& host1x; }; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 076edb02f..a84e4d425 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -112,17 +112,23 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector } if (params.fence.value == 0) { - params.value.raw = syncpoint_manager.GetSyncpointMin(fence_id); + if (!syncpoint_manager.IsSyncpointAllocated(params.fence.id)) { + LOG_WARNING(Service_NVDRV, + "Unallocated syncpt_id={}, threshold={}, timeout={}, is_allocation={}", + params.fence.id, params.fence.value, params.timeout, is_allocation); + } else { + params.value.raw = syncpoint_manager.ReadSyncpointMinValue(fence_id); + } return NvResult::Success; } - if (syncpoint_manager.IsSyncpointExpired(fence_id, params.fence.value)) { - params.value.raw = syncpoint_manager.GetSyncpointMin(fence_id); + if (syncpoint_manager.IsFenceSignalled(params.fence)) { + params.value.raw = syncpoint_manager.ReadSyncpointMinValue(fence_id); return NvResult::Success; } - if (const auto new_value = syncpoint_manager.RefreshSyncpoint(fence_id); - syncpoint_manager.IsSyncpointExpired(fence_id, params.fence.value)) { + if (const auto new_value = syncpoint_manager.UpdateMin(fence_id); + syncpoint_manager.IsFenceSignalled(params.fence)) { params.value.raw = new_value; return NvResult::Success; } @@ -296,7 +302,7 @@ NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector& input, std::v EventState::Waiting) { auto& host1x_syncpoint_manager = system.Host1x().GetSyncpointManager(); host1x_syncpoint_manager.DeregisterHostAction(event.assigned_syncpt, event.wait_handle); - syncpoint_manager.RefreshSyncpoint(event.assigned_syncpt); + syncpoint_manager.UpdateMin(event.assigned_syncpt); event.wait_handle = {}; } event.fails++; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 3f981af5a..c2cc09993 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -31,9 +31,7 @@ nvhost_gpu::nvhost_gpu(Core::System& system_, EventInterface& events_interface_, : nvdevice{system_}, events_interface{events_interface_}, core{core_}, syncpoint_manager{core_.GetSyncpointManager()}, nvmap{core.GetNvMapFile()}, channel_state{system.GPU().AllocateChannel()} { - channel_fence.id = syncpoint_manager.AllocateSyncpoint(); - channel_fence.value = - system_.Host1x().GetSyncpointManager().GetGuestSyncpointValue(channel_fence.id); + channel_syncpoint = syncpoint_manager.AllocateSyncpoint(false); sm_exception_breakpoint_int_report_event = events_interface.CreateEvent("GpuChannelSMExceptionBreakpointInt"); sm_exception_breakpoint_pause_report_event = @@ -191,10 +189,8 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector& input, std::vector BuildWaitCommandList(NvFence fence) { }; } -static std::vector BuildIncrementCommandList(NvFence fence, - u32 add_increment) { +static std::vector BuildIncrementCommandList(NvFence fence) { std::vector result{ Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointPayload, 1, Tegra::SubmissionMode::Increasing), {}}; - for (u32 count = 0; count < add_increment; ++count) { + for (u32 count = 0; count < 2; ++count) { result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointOperation, 1, Tegra::SubmissionMode::Increasing)); result.emplace_back( @@ -239,14 +234,12 @@ static std::vector BuildIncrementCommandList(NvFence fence return result; } -static std::vector BuildIncrementWithWfiCommandList(NvFence fence, - u32 add_increment) { +static std::vector BuildIncrementWithWfiCommandList(NvFence fence) { std::vector result{ Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForIdle, 1, Tegra::SubmissionMode::Increasing), {}}; - const std::vector increment{ - BuildIncrementCommandList(fence, add_increment)}; + const std::vector increment{BuildIncrementCommandList(fence)}; result.insert(result.end(), increment.begin(), increment.end()); @@ -260,35 +253,41 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector auto& gpu = system.GPU(); + std::scoped_lock lock(channel_mutex); + const auto bind_id = channel_state->bind_id; - params.fence_out.id = channel_fence.id; + auto& flags = params.flags; - if (params.flags.add_wait.Value() && - !syncpoint_manager.IsSyncpointExpired(params.fence_out.id, params.fence_out.value)) { - gpu.PushGPUEntries(bind_id, Tegra::CommandList{BuildWaitCommandList(params.fence_out)}); - } + if (flags.fence_wait.Value()) { + if (flags.increment_value.Value()) { + return NvResult::BadParameter; + } - if (params.flags.add_increment.Value() || params.flags.increment.Value()) { - const u32 increment_value = params.flags.increment.Value() ? params.fence_out.value : 0; - params.fence_out.value = syncpoint_manager.IncreaseSyncpoint( - params.fence_out.id, params.AddIncrementValue() + increment_value); - } else { - params.fence_out.value = syncpoint_manager.GetSyncpointMax(params.fence_out.id); + if (!syncpoint_manager.IsFenceSignalled(params.fence)) { + gpu.PushGPUEntries(bind_id, Tegra::CommandList{BuildWaitCommandList(params.fence)}); + } } gpu.PushGPUEntries(bind_id, std::move(entries)); + params.fence.id = channel_syncpoint; + + u32 increment{(flags.fence_increment.Value() != 0 ? 2 : 0) + + (flags.increment_value.Value() != 0 ? params.fence.value : 0)}; + params.fence.value = syncpoint_manager.IncrementSyncpointMaxExt(channel_syncpoint, increment); - if (params.flags.add_increment.Value()) { - if (params.flags.suppress_wfi) { - gpu.PushGPUEntries(bind_id, Tegra::CommandList{BuildIncrementCommandList( - params.fence_out, params.AddIncrementValue())}); + if (flags.fence_increment.Value()) { + if (flags.suppress_wfi.Value()) { + gpu.PushGPUEntries(bind_id, + Tegra::CommandList{BuildIncrementCommandList(params.fence)}); } else { - gpu.PushGPUEntries(bind_id, Tegra::CommandList{BuildIncrementWithWfiCommandList( - params.fence_out, params.AddIncrementValue())}); + gpu.PushGPUEntries(bind_id, + Tegra::CommandList{BuildIncrementWithWfiCommandList(params.fence)}); } } + flags.raw = 0; + std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); return NvResult::Success; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 3a65ed06d..1e4ecd55b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -163,17 +163,13 @@ private: u32_le num_entries{}; // number of fence objects being submitted union { u32_le raw; - BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list - BitField<1, 1, u32_le> add_increment; // append an increment to the list - BitField<2, 1, u32_le> new_hw_format; // mostly ignored - BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt - BitField<8, 1, u32_le> increment; // increment the returned fence + BitField<0, 1, u32_le> fence_wait; // append a wait sync_point to the list + BitField<1, 1, u32_le> fence_increment; // append an increment to the list + BitField<2, 1, u32_le> new_hw_format; // mostly ignored + BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt + BitField<8, 1, u32_le> increment_value; // increment the returned fence } flags; - NvFence fence_out{}; // returned new fence object for others to wait on - - u32 AddIncrementValue() const { - return flags.add_increment.Value() << 1; - } + NvFence fence{}; // returned new fence object for others to wait on }; static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(NvFence), "IoctlSubmitGpfifo is incorrect size"); @@ -213,7 +209,8 @@ private: NvCore::SyncpointManager& syncpoint_manager; NvCore::NvMap& nvmap; std::shared_ptr channel_state; - NvFence channel_fence; + u32 channel_syncpoint; + std::mutex channel_mutex; // Events Kernel::KEvent* sm_exception_breakpoint_int_report_event; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 00947ea19..5e3820085 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -13,7 +13,7 @@ namespace Service::Nvidia::Devices { u32 nvhost_nvdec::next_id{}; nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core) - : nvhost_nvdec_common{system_, core} {} + : nvhost_nvdec_common{system_, core, NvCore::ChannelType::NvDec} {} nvhost_nvdec::~nvhost_nvdec() = default; NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index b17589aa3..008092dbb 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -48,9 +48,10 @@ std::size_t WriteVectors(std::vector& dst, const std::vector& src, std::s std::unordered_map nvhost_nvdec_common::fd_to_id{}; -nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_) - : nvdevice{system_}, core{core_}, - syncpoint_manager{core.GetSyncpointManager()}, nvmap{core.GetNvMapFile()} {} +nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_, + NvCore::ChannelType channel_type_) + : nvdevice{system_}, core{core_}, syncpoint_manager{core.GetSyncpointManager()}, + nvmap{core.GetNvMapFile()}, channel_type{channel_type_} {} nvhost_nvdec_common::~nvhost_nvdec_common() = default; NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector& input) { @@ -88,7 +89,7 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector& input, for (std::size_t i = 0; i < syncpt_increments.size(); i++) { const SyncptIncr& syncpt_incr = syncpt_increments[i]; fence_thresholds[i] = - syncpoint_manager.IncreaseSyncpoint(syncpt_incr.id, syncpt_incr.increments); + syncpoint_manager.IncrementSyncpointMaxExt(syncpt_incr.id, syncpt_incr.increments); } } for (const auto& cmd_buffer : command_buffers) { @@ -116,10 +117,8 @@ NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector& input, std::ve std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint)); LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); - if (device_syncpoints[params.param] == 0 && system.GPU().UseNvdec()) { - device_syncpoints[params.param] = syncpoint_manager.AllocateSyncpoint(); - } - params.value = device_syncpoints[params.param]; + const u32 id{NvCore::SyncpointManager::channel_syncpoints[static_cast(channel_type)]}; + params.value = id; std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint)); return NvResult::Success; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index 53029af6a..51bb7c2cb 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -6,6 +6,7 @@ #include #include "common/common_types.h" #include "common/swap.h" +#include "core/hle/service/nvdrv/core/syncpoint_manager.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" namespace Service::Nvidia { @@ -13,14 +14,14 @@ namespace Service::Nvidia { namespace NvCore { class Container; class NvMap; -class SyncpointManager; } // namespace NvCore namespace Devices { class nvhost_nvdec_common : public nvdevice { public: - explicit nvhost_nvdec_common(Core::System& system_, NvCore::Container& core); + explicit nvhost_nvdec_common(Core::System& system_, NvCore::Container& core, + NvCore::ChannelType channel_type); ~nvhost_nvdec_common() override; protected: @@ -121,6 +122,7 @@ protected: NvCore::Container& core; NvCore::SyncpointManager& syncpoint_manager; NvCore::NvMap& nvmap; + NvCore::ChannelType channel_type; std::array device_syncpoints{}; }; }; // namespace Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index c89ff6b27..490e399f4 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -12,7 +12,7 @@ namespace Service::Nvidia::Devices { u32 nvhost_vic::next_id{}; nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core) - : nvhost_nvdec_common{system_, core} {} + : nvhost_nvdec_common{system_, core, NvCore::ChannelType::VIC} {} nvhost_vic::~nvhost_vic() = default; -- cgit v1.2.3 From afab6c143cb486c7d14f1509cd04049ad08d3a65 Mon Sep 17 00:00:00 2001 From: Liam White Date: Wed, 13 Apr 2022 21:02:55 +0200 Subject: General: Fix compilation for GCC --- src/core/hle/service/nvdrv/core/nvmap.cpp | 38 ++++++++++++++-------- src/core/hle/service/nvdrv/core/nvmap.h | 1 + .../hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 3 ++ src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 8 ++--- .../hle/service/nvdrv/devices/nvhost_nvdec.cpp | 4 +-- src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | 4 +-- src/core/hle/service/nvdrv/devices/nvmap.cpp | 2 +- src/core/hle/service/nvdrv/nvdrv.h | 1 + src/core/hle/service/vi/vi.cpp | 1 + 9 files changed, 39 insertions(+), 23 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index 86d825af9..b02dbb9c9 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -13,7 +13,8 @@ using Core::Memory::YUZU_PAGESIZE; namespace Service::Nvidia::NvCore { -NvMap::Handle::Handle(u64 size, Id id) : size(size), aligned_size(size), orig_size(size), id(id) { +NvMap::Handle::Handle(u64 size_, Id id_) + : size(size_), aligned_size(size), orig_size(size), id(id_) { flags.raw = 0; } @@ -21,19 +22,21 @@ NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) std::scoped_lock lock(mutex); // Handles cannot be allocated twice - if (allocated) + if (allocated) { return NvResult::AccessDenied; + } flags = pFlags; kind = pKind; align = pAlign < YUZU_PAGESIZE ? YUZU_PAGESIZE : pAlign; // This flag is only applicable for handles with an address passed - if (pAddress) - flags.keep_uncached_after_free = 0; - else + if (pAddress) { + flags.keep_uncached_after_free.Assign(0); + } else { LOG_CRITICAL(Service_NVDRV, "Mapping nvmap handles without a CPU side address is unimplemented!"); + } size = Common::AlignUp(size, YUZU_PAGESIZE); aligned_size = Common::AlignUp(size, align); @@ -48,17 +51,19 @@ NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) NvResult NvMap::Handle::Duplicate(bool internal_session) { // Unallocated handles cannot be duplicated as duplication requires memory accounting (in HOS) - if (!allocated) [[unlikely]] + if (!allocated) [[unlikely]] { return NvResult::BadValue; + } std::scoped_lock lock(mutex); // If we internally use FromId the duplication tracking of handles won't work accurately due to // us not implementing per-process handle refs. - if (internal_session) + if (internal_session) { internal_dupes++; - else + } else { dupes++; + } return NvResult::Success; } @@ -92,8 +97,9 @@ bool NvMap::TryRemoveHandle(const Handle& handle_description) { std::scoped_lock lock(handles_lock); auto it{handles.find(handle_description.id)}; - if (it != handles.end()) + if (it != handles.end()) { handles.erase(it); + } return true; } else { @@ -102,8 +108,9 @@ bool NvMap::TryRemoveHandle(const Handle& handle_description) { } NvResult NvMap::CreateHandle(u64 size, std::shared_ptr& result_out) { - if (!size) [[unlikely]] + if (!size) [[unlikely]] { return NvResult::BadValue; + } u32 id{next_handle_id.fetch_add(HandleIdIncrement, std::memory_order_relaxed)}; auto handle_description{std::make_shared(size, id)}; @@ -133,8 +140,9 @@ VAddr NvMap::GetHandleAddress(Handle::Id handle) { u32 NvMap::PinHandle(NvMap::Handle::Id handle) { auto handle_description{GetHandle(handle)}; - if (!handle_description) [[unlikely]] + if (!handle_description) [[unlikely]] { return 0; + } std::scoped_lock lock(handle_description->mutex); if (!handle_description->pins) { @@ -183,8 +191,9 @@ u32 NvMap::PinHandle(NvMap::Handle::Id handle) { void NvMap::UnpinHandle(Handle::Id handle) { auto handle_description{GetHandle(handle)}; - if (!handle_description) + if (!handle_description) { return; + } std::scoped_lock lock(handle_description->mutex); if (--handle_description->pins < 0) { @@ -226,12 +235,13 @@ std::optional NvMap::FreeHandle(Handle::Id handle, bool interna // Try to remove the shared ptr to the handle from the map, if nothing else is using the // handle then it will now be freed when `handle_description` goes out of scope - if (TryRemoveHandle(*handle_description)) + if (TryRemoveHandle(*handle_description)) { LOG_DEBUG(Service_NVDRV, "Removed nvmap handle: {}", handle); - else + } else { LOG_DEBUG(Service_NVDRV, "Tried to free nvmap handle: {} but didn't as it still has duplicates", handle); + } freeInfo = { .address = handle_description->address, diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index 4f37dcf43..1082bb58d 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -5,6 +5,7 @@ #pragma once +#include #include #include #include diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index d95a88393..d1beefba6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -188,6 +188,7 @@ NvResult nvhost_as_gpu::AllocateSpace(const std::vector& input, std::vector< allocation_map[params.offset] = { .size = size, + .mappings{}, .page_size = params.page_size, .sparse = (params.flags & MappingFlags::Sparse) != MappingFlags::None, .big_pages = params.page_size != VM::YUZU_PAGESIZE, @@ -474,11 +475,13 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) { VaRegion{ .offset = vm.small_page_allocator->vaStart << VM::PAGE_SIZE_BITS, .page_size = VM::YUZU_PAGESIZE, + ._pad0_{}, .pages = vm.small_page_allocator->vaLimit - vm.small_page_allocator->vaStart, }, VaRegion{ .offset = vm.big_page_allocator->vaStart << vm.big_page_size_bits, .page_size = vm.big_page_size, + ._pad0_{}, .pages = vm.big_page_allocator->vaLimit - vm.big_page_allocator->vaStart, }, }; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index a84e4d425..7fffb8e48 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -204,12 +204,12 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector& input, std::vector event.wait_handle = host1x_syncpoint_manager.RegisterHostAction(fence_id, target_value, [this, slot]() { - auto& event = events[slot]; - if (event.status.exchange(EventState::Signalling, std::memory_order_acq_rel) == + auto& event_ = events[slot]; + if (event_.status.exchange(EventState::Signalling, std::memory_order_acq_rel) == EventState::Waiting) { - event.kevent->GetWritableEvent().Signal(); + event_.kevent->GetWritableEvent().Signal(); } - event.status.store(EventState::Signalled, std::memory_order_release); + event_.status.store(EventState::Signalled, std::memory_order_release); }); return NvResult::Timeout; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 5e3820085..fed537039 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -12,8 +12,8 @@ namespace Service::Nvidia::Devices { u32 nvhost_nvdec::next_id{}; -nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core) - : nvhost_nvdec_common{system_, core, NvCore::ChannelType::NvDec} {} +nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core_) + : nvhost_nvdec_common{system_, core_, NvCore::ChannelType::NvDec} {} nvhost_nvdec::~nvhost_nvdec() = default; NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 490e399f4..2e4ff988c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -11,8 +11,8 @@ namespace Service::Nvidia::Devices { u32 nvhost_vic::next_id{}; -nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core) - : nvhost_nvdec_common{system_, core, NvCore::ChannelType::VIC} {} +nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core_) + : nvhost_nvdec_common{system_, core_, NvCore::ChannelType::VIC} {} nvhost_vic::~nvhost_vic() = default; diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 992c117f1..f84fc8c37 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -269,7 +269,7 @@ NvResult nvmap::IocFree(const std::vector& input, std::vector& output) { params.address = freeInfo->address; params.size = static_cast(freeInfo->size); params.flags.raw = 0; - params.flags.map_uncached = freeInfo->was_uncached; + params.flags.map_uncached.Assign(freeInfo->was_uncached); } else { // This is possible when there's internel dups or other duplicates. } diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 31c45236e..b26254753 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -6,6 +6,7 @@ #pragma once #include +#include #include #include #include diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index f083811ec..9c917cacf 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -58,6 +58,7 @@ static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size"); class NativeWindow final { public: constexpr explicit NativeWindow(u32 id_) : id{id_} {} + constexpr explicit NativeWindow(const NativeWindow& other) = default; private: const u32 magic = 2; -- cgit v1.2.3 From 8d774e7415fac1153d8944baa2cc250cc4831107 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 18 Apr 2022 21:07:21 +0200 Subject: NvDec: Fix regressions. --- src/core/hle/service/nvdrv/core/syncpoint_manager.cpp | 6 ++++++ src/core/hle/service/nvdrv/core/syncpoint_manager.h | 5 +++++ src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 1 + .../hle/service/nvdrv/devices/nvhost_nvdec_common.cpp | 16 ++++++++++++---- src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h | 3 +++ src/core/hle/service/nvdrv/nvdrv.cpp | 5 ++++- 6 files changed, 31 insertions(+), 5 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp index b34481b48..fc4ff3c2f 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp @@ -55,6 +55,12 @@ u32 SyncpointManager::AllocateSyncpoint(bool clientManaged) { return ReserveSyncpoint(FindFreeSyncpoint(), clientManaged); } +void SyncpointManager::FreeSyncpoint(u32 id) { + std::lock_guard lock(reservation_lock); + ASSERT(syncpoints.at(id).reserved); + syncpoints.at(id).reserved = false; +} + bool SyncpointManager::IsSyncpointAllocated(u32 id) { return (id <= SyncpointCount) && syncpoints[id].reserved; } diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.h b/src/core/hle/service/nvdrv/core/syncpoint_manager.h index bfc8ba84b..da456f206 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.h +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.h @@ -84,6 +84,11 @@ public: */ 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 */ diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index c2cc09993..908e60191 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -43,6 +43,7 @@ nvhost_gpu::~nvhost_gpu() { events_interface.FreeEvent(sm_exception_breakpoint_int_report_event); events_interface.FreeEvent(sm_exception_breakpoint_pause_report_event); events_interface.FreeEvent(error_notifier_event); + syncpoint_manager.FreeSyncpoint(channel_syncpoint); } NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 008092dbb..fe83423d5 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -51,8 +51,12 @@ std::unordered_map nvhost_nvdec_common::fd_to_id{}; nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_, NvCore::ChannelType channel_type_) : nvdevice{system_}, core{core_}, syncpoint_manager{core.GetSyncpointManager()}, - nvmap{core.GetNvMapFile()}, channel_type{channel_type_} {} -nvhost_nvdec_common::~nvhost_nvdec_common() = default; + nvmap{core.GetNvMapFile()}, channel_type{channel_type_} { + channel_syncpoint = syncpoint_manager.AllocateSyncpoint(false); +} +nvhost_nvdec_common::~nvhost_nvdec_common() { + syncpoint_manager.FreeSyncpoint(channel_syncpoint); +} NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector& input) { IoctlSetNvmapFD params{}; @@ -117,8 +121,8 @@ NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector& input, std::ve std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint)); LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); - const u32 id{NvCore::SyncpointManager::channel_syncpoints[static_cast(channel_type)]}; - params.value = id; + // const u32 id{NvCore::SyncpointManager::channel_syncpoints[static_cast(channel_type)]}; + params.value = channel_syncpoint; std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint)); return NvResult::Success; @@ -176,4 +180,8 @@ Kernel::KEvent* nvhost_nvdec_common::QueryEvent(u32 event_id) { return nullptr; } +void nvhost_nvdec_common::Reset() { + fd_to_id.clear(); +} + } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index 51bb7c2cb..4046b0e13 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -24,6 +24,8 @@ public: NvCore::ChannelType channel_type); ~nvhost_nvdec_common() override; + static void Reset(); + protected: struct IoctlSetNvmapFD { s32_le nvmap_fd{}; @@ -117,6 +119,7 @@ protected: Kernel::KEvent* QueryEvent(u32 event_id) override; static std::unordered_map fd_to_id; + u32 channel_syncpoint; s32_le nvmap_fd{}; u32_le submit_timeout{}; NvCore::Container& core; diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 1be51e401..20bf24ec8 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -18,6 +18,7 @@ #include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" +#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h" #include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h" #include "core/hle/service/nvdrv/devices/nvhost_vic.h" #include "core/hle/service/nvdrv/devices/nvmap.h" @@ -101,7 +102,9 @@ Module::Module(Core::System& system) }; } -Module::~Module() = default; +Module::~Module() { + Devices::nvhost_nvdec_common::Reset(); +} NvResult Module::VerifyFD(DeviceFD fd) const { if (fd < 0) { -- cgit v1.2.3 From 9982cff98b4db38565715cc515ea496b6195725b Mon Sep 17 00:00:00 2001 From: VonChenPlus Date: Mon, 27 Jun 2022 12:39:57 +0800 Subject: Core: Fix get nvmap object random crash --- src/core/hle/service/nvdrv/core/nvmap.cpp | 15 ++++++++++++++- src/core/hle/service/nvdrv/core/nvmap.h | 5 +++++ src/core/hle/service/nvdrv/devices/nvmap.cpp | 12 ------------ src/core/hle/service/nvdrv/devices/nvmap.h | 5 ----- src/core/hle/service/nvdrv/nvdrv.h | 3 +-- src/core/hle/service/nvflinger/buffer_queue_consumer.cpp | 9 +++++++-- src/core/hle/service/nvflinger/buffer_queue_consumer.h | 8 +++++++- src/core/hle/service/nvflinger/buffer_queue_producer.cpp | 10 +++++++--- src/core/hle/service/nvflinger/buffer_queue_producer.h | 9 ++++++++- src/core/hle/service/nvflinger/nvflinger.cpp | 2 +- src/core/hle/service/vi/display/vi_display.cpp | 16 ++++++++++------ src/core/hle/service/vi/display/vi_display.h | 7 ++++++- 12 files changed, 66 insertions(+), 35 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index b02dbb9c9..dd30e156e 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -207,6 +207,19 @@ void NvMap::UnpinHandle(Handle::Id handle) { } } +void NvMap::DuplicateHandle(Handle::Id handle) { + auto handle_description{GetHandle(handle)}; + if (!handle_description) { + LOG_CRITICAL(Service_NVDRV, "Unregistered handle!"); + return; + } + + auto result = handle_description->Duplicate(false); + if (result != NvResult::Success) { + LOG_CRITICAL(Service_NVDRV, "Could not duplicate handle!"); + } +} + std::optional NvMap::FreeHandle(Handle::Id handle, bool internal_session) { std::weak_ptr hWeak{GetHandle(handle)}; FreeInfo freeInfo; @@ -254,7 +267,7 @@ std::optional NvMap::FreeHandle(Handle::Id handle, bool interna // Handle hasn't been freed from memory, set address to 0 to mark that the handle wasn't freed if (!hWeak.expired()) { - LOG_ERROR(Service_NVDRV, "nvmap handle: {} wasn't freed as it is still in use", handle); + LOG_DEBUG(Service_NVDRV, "nvmap handle: {} wasn't freed as it is still in use", handle); freeInfo.address = 0; } diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index 1082bb58d..b6613a521 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -162,6 +162,11 @@ public: */ void UnpinHandle(Handle::Id handle); + /** + * @brief Tries to duplicate a handle + */ + void DuplicateHandle(Handle::Id handle); + /** * @brief Tries to free a handle and remove a single dupe * @note If a handle has no dupes left and has no other users a FreeInfo struct will be returned diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index f84fc8c37..ddf273b5e 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -69,18 +69,6 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, const std::vector& input, void nvmap::OnOpen(DeviceFD fd) {} void nvmap::OnClose(DeviceFD fd) {} -VAddr nvmap::GetObjectAddress(u32 handle) const { - auto obj = file.GetHandle(handle); - if (obj) { - return obj->address; - } - return 0; -} - -std::shared_ptr nvmap::GetObject(u32 handle) const { - return file.GetHandle(handle); -} - NvResult nvmap::IocCreate(const std::vector& input, std::vector& output) { IocCreateParams params; std::memcpy(¶ms, input.data(), sizeof(params)); diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index c22eb57a4..52e1d7cff 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -36,11 +36,6 @@ public: void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; - /// Returns the allocated address of an nvmap object given its handle. - VAddr GetObjectAddress(u32 handle) const; - - std::shared_ptr GetObject(u32 handle) const; - enum class HandleParameterType : u32_le { Size = 1, Alignment = 2, diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index b26254753..22836529d 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -96,6 +96,7 @@ public: private: friend class EventInterface; + friend class Service::NVFlinger::NVFlinger; /// Id to use for the next open file descriptor. DeviceFD next_fd = 1; @@ -111,8 +112,6 @@ private: /// Manages syncpoints on the host NvCore::Container container; - void CreateEvent(u32 event_id); - void FreeEvent(u32 event_id); std::unordered_map> builders; }; diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp index 4b3d5efd6..a0330ab4a 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp @@ -5,15 +5,18 @@ // https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp #include "common/logging/log.h" +#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvflinger/buffer_item.h" #include "core/hle/service/nvflinger/buffer_queue_consumer.h" #include "core/hle/service/nvflinger/buffer_queue_core.h" #include "core/hle/service/nvflinger/producer_listener.h" +#include "core/hle/service/nvflinger/ui/graphic_buffer.h" namespace Service::android { -BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr core_) - : core{std::move(core_)}, slots{core->slots} {} +BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr core_, + Service::Nvidia::NvCore::NvMap& nvmap_) + : core{std::move(core_)}, slots{core->slots}, nvmap(nvmap_) {} BufferQueueConsumer::~BufferQueueConsumer() = default; @@ -133,6 +136,8 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc slots[slot].buffer_state = BufferState::Free; + nvmap.FreeHandle(slots[slot].graphic_buffer->BufferId(), false); + listener = core->connected_producer_listener; LOG_DEBUG(Service_NVFlinger, "releasing slot {}", slot); diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.h b/src/core/hle/service/nvflinger/buffer_queue_consumer.h index b598c314f..4ec06ca13 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.h +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.h @@ -13,6 +13,10 @@ #include "core/hle/service/nvflinger/buffer_queue_defs.h" #include "core/hle/service/nvflinger/status.h" +namespace Service::Nvidia::NvCore { +class NvMap; +} // namespace Service::Nvidia::NvCore + namespace Service::android { class BufferItem; @@ -21,7 +25,8 @@ class IConsumerListener; class BufferQueueConsumer final { public: - explicit BufferQueueConsumer(std::shared_ptr core_); + explicit BufferQueueConsumer(std::shared_ptr core_, + Service::Nvidia::NvCore::NvMap& nvmap_); ~BufferQueueConsumer(); Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present); @@ -32,6 +37,7 @@ public: private: std::shared_ptr core; BufferQueueDefs::SlotsType& slots; + Service::Nvidia::NvCore::NvMap& nvmap; }; } // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index 337431488..a4e46964c 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -14,7 +14,7 @@ #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/service/kernel_helpers.h" -#include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvflinger/buffer_queue_core.h" #include "core/hle/service/nvflinger/buffer_queue_producer.h" #include "core/hle/service/nvflinger/consumer_listener.h" @@ -26,8 +26,10 @@ namespace Service::android { BufferQueueProducer::BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_, - std::shared_ptr buffer_queue_core_) - : service_context{service_context_}, core{std::move(buffer_queue_core_)}, slots(core->slots) { + std::shared_ptr buffer_queue_core_, + Service::Nvidia::NvCore::NvMap& nvmap_) + : service_context{service_context_}, core{std::move(buffer_queue_core_)}, slots(core->slots), + nvmap(nvmap_) { buffer_wait_event = service_context.CreateEvent("BufferQueue:WaitEvent"); } @@ -530,6 +532,8 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input, item.is_droppable = core->dequeue_buffer_cannot_block || async; item.swap_interval = swap_interval; + nvmap.DuplicateHandle(item.graphic_buffer->BufferId()); + sticky_transform = sticky_transform_; if (core->queue.empty()) { diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h index 42d4722dc..0ba03a568 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.h +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.h @@ -31,6 +31,10 @@ namespace Service::KernelHelpers { class ServiceContext; } // namespace Service::KernelHelpers +namespace Service::Nvidia::NvCore { +class NvMap; +} // namespace Service::Nvidia::NvCore + namespace Service::android { class BufferQueueCore; @@ -39,7 +43,8 @@ class IProducerListener; class BufferQueueProducer final : public IBinder { public: explicit BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_, - std::shared_ptr buffer_queue_core_); + std::shared_ptr buffer_queue_core_, + Service::Nvidia::NvCore::NvMap& nvmap_); ~BufferQueueProducer(); void Transact(Kernel::HLERequestContext& ctx, android::TransactionId code, u32 flags) override; @@ -78,6 +83,8 @@ private: s32 next_callback_ticket{}; s32 current_callback_ticket{}; std::condition_variable_any callback_condition; + + Service::Nvidia::NvCore::NvMap& nvmap; }; } // namespace Service::android diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 4658f1e8b..aa14d2cbc 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -149,7 +149,7 @@ std::optional NVFlinger::CreateLayer(u64 display_id) { void NVFlinger::CreateLayerAtId(VI::Display& display, u64 layer_id) { const auto buffer_id = next_buffer_queue_id++; - display.CreateLayer(layer_id, buffer_id); + display.CreateLayer(layer_id, buffer_id, nvdrv->container); } void NVFlinger::CloseLayer(u64 layer_id) { diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index aa49aa775..288aafaaf 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp @@ -12,6 +12,7 @@ #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvflinger/buffer_item_consumer.h" #include "core/hle/service/nvflinger/buffer_queue_consumer.h" #include "core/hle/service/nvflinger/buffer_queue_core.h" @@ -29,11 +30,13 @@ struct BufferQueue { std::unique_ptr consumer; }; -static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_context) { +static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_context, + Service::Nvidia::NvCore::NvMap& nvmap) { auto buffer_queue_core = std::make_shared(); - return {buffer_queue_core, - std::make_unique(service_context, buffer_queue_core), - std::make_unique(buffer_queue_core)}; + return { + buffer_queue_core, + std::make_unique(service_context, buffer_queue_core, nvmap), + std::make_unique(buffer_queue_core, nvmap)}; } Display::Display(u64 id, std::string name_, @@ -74,10 +77,11 @@ void Display::SignalVSyncEvent() { vsync_event->GetWritableEvent().Signal(); } -void Display::CreateLayer(u64 layer_id, u32 binder_id) { +void Display::CreateLayer(u64 layer_id, u32 binder_id, + Service::Nvidia::NvCore::Container& nv_core) { ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment"); - auto [core, producer, consumer] = CreateBufferQueue(service_context); + auto [core, producer, consumer] = CreateBufferQueue(service_context, nv_core.GetNvMapFile()); auto buffer_item_consumer = std::make_shared(std::move(consumer)); buffer_item_consumer->Connect(false); diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 8dbb0ef80..33d5f398c 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h @@ -27,6 +27,11 @@ namespace Service::NVFlinger { class HosBinderDriverServer; } +namespace Service::Nvidia::NvCore { +class Container; +class NvMap; +} // namespace Service::Nvidia::NvCore + namespace Service::VI { class Layer; @@ -93,7 +98,7 @@ public: /// @param layer_id The ID to assign to the created layer. /// @param binder_id The ID assigned to the buffer queue. /// - void CreateLayer(u64 layer_id, u32 binder_id); + void CreateLayer(u64 layer_id, u32 binder_id, Service::Nvidia::NvCore::Container& core); /// Closes and removes a layer from this display with the given ID. /// -- cgit v1.2.3 From 8a372035db35465b8241d1e13eeb979e8682bb3f Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 27 Jun 2022 21:45:33 +0200 Subject: Nvflinger: correct duplication. --- src/core/hle/service/nvdrv/core/nvmap.cpp | 4 ++-- src/core/hle/service/nvdrv/core/nvmap.h | 2 +- src/core/hle/service/nvflinger/buffer_queue_consumer.cpp | 2 +- src/core/hle/service/nvflinger/buffer_queue_producer.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index dd30e156e..f811b66a0 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -207,14 +207,14 @@ void NvMap::UnpinHandle(Handle::Id handle) { } } -void NvMap::DuplicateHandle(Handle::Id handle) { +void NvMap::DuplicateHandle(Handle::Id handle, bool internal_session) { auto handle_description{GetHandle(handle)}; if (!handle_description) { LOG_CRITICAL(Service_NVDRV, "Unregistered handle!"); return; } - auto result = handle_description->Duplicate(false); + auto result = handle_description->Duplicate(internal_session); if (result != NvResult::Success) { LOG_CRITICAL(Service_NVDRV, "Could not duplicate handle!"); } diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index b6613a521..ef2df3ad7 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -165,7 +165,7 @@ public: /** * @brief Tries to duplicate a handle */ - void DuplicateHandle(Handle::Id handle); + void DuplicateHandle(Handle::Id handle, bool internal_session = false); /** * @brief Tries to free a handle and remove a single dupe diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp index a0330ab4a..1ce67c771 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp @@ -136,7 +136,7 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc slots[slot].buffer_state = BufferState::Free; - nvmap.FreeHandle(slots[slot].graphic_buffer->BufferId(), false); + nvmap.FreeHandle(slots[slot].graphic_buffer->BufferId(), true); listener = core->connected_producer_listener; diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index a4e46964c..d4ab23a10 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -532,7 +532,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input, item.is_droppable = core->dequeue_buffer_cannot_block || async; item.swap_interval = swap_interval; - nvmap.DuplicateHandle(item.graphic_buffer->BufferId()); + nvmap.DuplicateHandle(item.graphic_buffer->BufferId(), true); sticky_transform = sticky_transform_; -- cgit v1.2.3 From c2b7de66b325b52cebb7e26948db0d5b0eefee25 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 27 Jun 2022 21:23:06 +0200 Subject: Address Feedback from bylaws. --- src/core/hle/service/nvdrv/core/nvmap.cpp | 6 +----- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index f811b66a0..9b21da6b1 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -41,22 +41,18 @@ NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) size = Common::AlignUp(size, YUZU_PAGESIZE); aligned_size = Common::AlignUp(size, align); address = pAddress; - - // TODO: pin init - allocated = true; return NvResult::Success; } NvResult NvMap::Handle::Duplicate(bool internal_session) { + std::scoped_lock lock(mutex); // Unallocated handles cannot be duplicated as duplication requires memory accounting (in HOS) if (!allocated) [[unlikely]] { return NvResult::BadValue; } - std::scoped_lock lock(mutex); - // If we internally use FromId the duplication tracking of handles won't work accurately due to // us not implementing per-process handle refs. if (internal_session) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 908e60191..32e45540d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -270,12 +270,12 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector } } - gpu.PushGPUEntries(bind_id, std::move(entries)); params.fence.id = channel_syncpoint; u32 increment{(flags.fence_increment.Value() != 0 ? 2 : 0) + (flags.increment_value.Value() != 0 ? params.fence.value : 0)}; params.fence.value = syncpoint_manager.IncrementSyncpointMaxExt(channel_syncpoint, increment); + gpu.PushGPUEntries(bind_id, std::move(entries)); if (flags.fence_increment.Value()) { if (flags.suppress_wfi.Value()) { -- cgit v1.2.3 From d97d409647686aefe701aec1363e328be11d1443 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 1 Jul 2022 02:18:33 +0200 Subject: NvHostChannels: improve hack for supporting multiple channels. --- src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp | 10 ++++++++-- src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index fe83423d5..2ec1ad3e9 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -47,15 +47,21 @@ std::size_t WriteVectors(std::vector& dst, const std::vector& src, std::s } // Anonymous namespace std::unordered_map nvhost_nvdec_common::fd_to_id{}; +std::deque nvhost_nvdec_common::syncpts_accumulated{}; nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_, NvCore::ChannelType channel_type_) : nvdevice{system_}, core{core_}, syncpoint_manager{core.GetSyncpointManager()}, nvmap{core.GetNvMapFile()}, channel_type{channel_type_} { - channel_syncpoint = syncpoint_manager.AllocateSyncpoint(false); + if (syncpts_accumulated.empty()) { + channel_syncpoint = syncpoint_manager.AllocateSyncpoint(false); + } else { + channel_syncpoint = syncpts_accumulated.front(); + syncpts_accumulated.pop_front(); + } } nvhost_nvdec_common::~nvhost_nvdec_common() { - syncpoint_manager.FreeSyncpoint(channel_syncpoint); + syncpts_accumulated.push_back(channel_syncpoint); } NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector& input) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index 4046b0e13..93990bb9b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include "common/common_types.h" #include "common/swap.h" @@ -127,6 +128,8 @@ protected: NvCore::NvMap& nvmap; NvCore::ChannelType channel_type; std::array device_syncpoints{}; + + static std::deque syncpts_accumulated; }; }; // namespace Devices } // namespace Service::Nvidia -- cgit v1.2.3 From fedd983f96bcbcc0c39f651db1cca0503d582fd9 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 29 Jun 2022 19:27:49 -0400 Subject: general: Format licenses as per SPDX guidelines --- src/core/hle/service/nvdrv/core/container.cpp | 7 +++---- src/core/hle/service/nvdrv/core/container.h | 7 +++---- src/core/hle/service/nvdrv/core/nvmap.cpp | 7 +++---- src/core/hle/service/nvdrv/core/nvmap.h | 7 +++---- src/core/hle/service/nvdrv/core/syncpoint_manager.cpp | 7 +++---- src/core/hle/service/nvdrv/core/syncpoint_manager.h | 7 +++---- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 7 +++---- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | 7 +++---- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 7 +++---- src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 7 +++---- src/core/hle/service/nvdrv/nvdata.h | 7 +++---- src/core/hle/service/nvdrv/nvdrv.cpp | 7 +++---- src/core/hle/service/nvdrv/nvdrv.h | 7 +++---- src/core/hle/service/nvdrv/nvdrv_interface.cpp | 7 +++---- 14 files changed, 42 insertions(+), 56 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index 4175d3d9c..d2a632646 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -1,7 +1,6 @@ -// 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. +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-FileCopyrightText: 2022 Skyline Team and Contributors +// SPDX-License-Identifier: GPL-3.0-or-later #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/nvmap.h" diff --git a/src/core/hle/service/nvdrv/core/container.h b/src/core/hle/service/nvdrv/core/container.h index e069ade4e..5c8b95803 100644 --- a/src/core/hle/service/nvdrv/core/container.h +++ b/src/core/hle/service/nvdrv/core/container.h @@ -1,7 +1,6 @@ -// 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. +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-FileCopyrightText: 2022 Skyline Team and Contributors +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index 9b21da6b1..e63ec7717 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -1,7 +1,6 @@ -// 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. +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-FileCopyrightText: 2022 Skyline Team and Contributors +// SPDX-License-Identifier: GPL-3.0-or-later #include "common/alignment.h" #include "common/assert.h" diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index ef2df3ad7..6d6dac023 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -1,7 +1,6 @@ -// 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. +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-FileCopyrightText: 2022 Skyline Team and Contributors +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp index fc4ff3c2f..0bb2aec97 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp @@ -1,7 +1,6 @@ -// 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. +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-FileCopyrightText: 2022 Skyline Team and Contributors +// SPDX-License-Identifier: GPL-3.0-or-later #include "common/assert.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h" diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.h b/src/core/hle/service/nvdrv/core/syncpoint_manager.h index da456f206..6b71cd33d 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.h +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.h @@ -1,7 +1,6 @@ -// 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. +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-FileCopyrightText: 2022 Skyline Team and Contributors +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index d1beefba6..b48f7fcaf 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -1,7 +1,6 @@ -// SPDX-FileCopyrightText: 2021 yuzu emulator team, 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. +// SPDX-FileCopyrightText: 2021 yuzu Emulator Project +// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors +// SPDX-License-Identifier: GPL-3.0-or-later #include #include diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 12e881f0d..86fe71c75 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -1,7 +1,6 @@ -// SPDX-FileCopyrightText: 2021 yuzu emulator team, 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. +// SPDX-FileCopyrightText: 2021 yuzu Emulator Project +// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 7fffb8e48..5bee4a3d3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -1,7 +1,6 @@ -// SPDX-FileCopyrightText: 2021 yuzu emulator team, 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. +// SPDX-FileCopyrightText: 2021 yuzu Emulator Project +// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors +// SPDX-License-Identifier: GPL-3.0-or-later #include #include diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index f511c0296..4aa738b41 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -1,7 +1,6 @@ -// SPDX-FileCopyrightText: 2021 yuzu emulator team, 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. +// SPDX-FileCopyrightText: 2021 yuzu Emulator Project +// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 2ee91f9c4..0e2f47075 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h @@ -1,7 +1,6 @@ -// SPDX-FileCopyrightText: 2021 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. +// SPDX-FileCopyrightText: 2021 yuzu Emulator Project +// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 20bf24ec8..7929443d2 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -1,7 +1,6 @@ -// SPDX-FileCopyrightText: 2021 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. +// SPDX-FileCopyrightText: 2021 yuzu Emulator Project +// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors +// SPDX-License-Identifier: GPL-3.0-or-later #include diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 22836529d..a2aeb80b4 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -1,7 +1,6 @@ -// SPDX-FileCopyrightText: 2021 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. +// SPDX-FileCopyrightText: 2021 yuzu Emulator Project +// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index 5e50a04e8..edbdfee43 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -1,7 +1,6 @@ -// SPDX-FileCopyrightText: 2021 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. +// SPDX-FileCopyrightText: 2021 yuzu Emulator Project +// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors +// SPDX-License-Identifier: GPL-3.0-or-later #include #include "common/logging/log.h" -- cgit v1.2.3 From fa342cae227666c861806b9bf63e4286aff1e4d7 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 29 Jun 2022 20:33:04 -0400 Subject: address_space: Address feedback --- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index b48f7fcaf..7a95f5305 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -472,16 +472,16 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) { params.regions = std::array{ VaRegion{ - .offset = vm.small_page_allocator->vaStart << VM::PAGE_SIZE_BITS, + .offset = vm.small_page_allocator->GetVAStart() << VM::PAGE_SIZE_BITS, .page_size = VM::YUZU_PAGESIZE, ._pad0_{}, - .pages = vm.small_page_allocator->vaLimit - vm.small_page_allocator->vaStart, + .pages = vm.small_page_allocator->GetVALimit() - vm.small_page_allocator->GetVAStart(), }, VaRegion{ - .offset = vm.big_page_allocator->vaStart << vm.big_page_size_bits, + .offset = vm.big_page_allocator->GetVAStart() << vm.big_page_size_bits, .page_size = vm.big_page_size, ._pad0_{}, - .pages = vm.big_page_allocator->vaLimit - vm.big_page_allocator->vaStart, + .pages = vm.big_page_allocator->GetVALimit() - vm.big_page_allocator->GetVAStart(), }, }; } -- cgit v1.2.3 From 903705043dd768fe2bbeeddc621994ac61aae561 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Tue, 2 Aug 2022 03:38:19 -0400 Subject: nvdisp: End system frame after requesting to swap buffers Fixes frametime reporting --- src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 18c5324a9..4122fc98d 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -50,8 +50,8 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat form const Tegra::FramebufferConfig framebuffer{addr, offset, width, height, stride, format, transform, crop_rect}; - system.GetPerfStats().EndSystemFrame(); system.GPU().RequestSwapBuffers(&framebuffer, fences, num_fences); + system.GetPerfStats().EndSystemFrame(); system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs()); system.GetPerfStats().BeginSystemFrame(); } -- cgit v1.2.3 From c80ed6d81fef5858508ac4b841defe8ee3a8663d Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 19 Aug 2022 21:58:25 -0400 Subject: general: rework usages of UNREACHABLE macro --- src/core/hle/service/nvdrv/core/syncpoint_manager.cpp | 14 +++++++------- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp index 0bb2aec97..072b3a22f 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp @@ -29,7 +29,7 @@ SyncpointManager::~SyncpointManager() = default; u32 SyncpointManager::ReserveSyncpoint(u32 id, bool clientManaged) { if (syncpoints.at(id).reserved) { - UNREACHABLE_MSG("Requested syncpoint is in use"); + ASSERT_MSG(false, "Requested syncpoint is in use"); return 0; } @@ -45,7 +45,7 @@ u32 SyncpointManager::FindFreeSyncpoint() { return i; } } - UNREACHABLE_MSG("Failed to find a free syncpoint!"); + ASSERT_MSG(false, "Failed to find a free syncpoint!"); return 0; } @@ -68,7 +68,7 @@ bool SyncpointManager::HasSyncpointExpired(u32 id, u32 threshold) { const SyncpointInfo& syncpoint{syncpoints.at(id)}; if (!syncpoint.reserved) { - UNREACHABLE(); + ASSERT(false); return 0; } @@ -83,7 +83,7 @@ bool SyncpointManager::HasSyncpointExpired(u32 id, u32 threshold) { u32 SyncpointManager::IncrementSyncpointMaxExt(u32 id, u32 amount) { if (!syncpoints.at(id).reserved) { - UNREACHABLE(); + ASSERT(false); return 0; } @@ -92,7 +92,7 @@ u32 SyncpointManager::IncrementSyncpointMaxExt(u32 id, u32 amount) { u32 SyncpointManager::ReadSyncpointMinValue(u32 id) { if (!syncpoints.at(id).reserved) { - UNREACHABLE(); + ASSERT(false); return 0; } @@ -101,7 +101,7 @@ u32 SyncpointManager::ReadSyncpointMinValue(u32 id) { u32 SyncpointManager::UpdateMin(u32 id) { if (!syncpoints.at(id).reserved) { - UNREACHABLE(); + ASSERT(false); return 0; } @@ -111,7 +111,7 @@ u32 SyncpointManager::UpdateMin(u32 id) { NvFence SyncpointManager::GetSyncpointFence(u32 id) { if (!syncpoints.at(id).reserved) { - UNREACHABLE(); + ASSERT(false); return NvFence{}; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 7a95f5305..192503ffc 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -96,7 +96,7 @@ NvResult nvhost_as_gpu::AllocAsEx(const std::vector& input, std::vector& std::scoped_lock lock(mutex); if (vm.initialised) { - UNREACHABLE_MSG("Cannot initialise an address space twice!"); + ASSERT_MSG(false, "Cannot initialise an address space twice!"); return NvResult::InvalidState; } @@ -174,7 +174,7 @@ NvResult nvhost_as_gpu::AllocateSpace(const std::vector& input, std::vector< } else { params.offset = static_cast(allocator.Allocate(params.pages)) << page_size_bits; if (!params.offset) { - UNREACHABLE_MSG("Failed to allocate free space in the GPU AS!"); + ASSERT_MSG(false, "Failed to allocate free space in the GPU AS!"); return NvResult::InsufficientMemory; } } @@ -372,7 +372,7 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vectoralign, VM::YUZU_PAGESIZE)) return false; else { - UNREACHABLE(); + ASSERT(false); return false; } }()}; @@ -382,7 +382,7 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vectorfirst) + size > alloc->second.size) { - UNREACHABLE_MSG("Cannot perform a fixed mapping into an unallocated region!"); + ASSERT_MSG(false, "Cannot perform a fixed mapping into an unallocated region!"); return NvResult::BadValue; } @@ -403,7 +403,7 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vector(Common::AlignUp(size, page_size) >> page_size_bits))) << page_size_bits; if (!params.offset) { - UNREACHABLE_MSG("Failed to allocate free space in the GPU AS!"); + ASSERT_MSG(false, "Failed to allocate free space in the GPU AS!"); return NvResult::InsufficientMemory; } -- cgit v1.2.3 From ca3db0d7c94a20668781830ff852dbf512598efb Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 1 Sep 2022 05:45:22 +0200 Subject: General: address feedback --- src/core/hle/service/nvdrv/core/container.cpp | 12 ++++- src/core/hle/service/nvdrv/core/container.h | 23 ++++++--- src/core/hle/service/nvdrv/core/nvmap.cpp | 4 +- src/core/hle/service/nvdrv/core/nvmap.h | 59 +++++++++++----------- .../hle/service/nvdrv/core/syncpoint_manager.cpp | 32 ++++++------ .../hle/service/nvdrv/core/syncpoint_manager.h | 34 ++++++------- .../hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 28 +++++----- src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 2 +- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 2 +- .../hle/service/nvdrv/devices/nvhost_nvdec.cpp | 13 ++--- src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | 3 -- .../service/nvdrv/devices/nvhost_nvdec_common.cpp | 13 ++--- .../service/nvdrv/devices/nvhost_nvdec_common.h | 5 -- src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | 16 +++--- src/core/hle/service/nvdrv/devices/nvhost_vic.h | 3 -- src/core/hle/service/nvdrv/devices/nvmap.h | 4 +- src/core/hle/service/nvdrv/nvdrv.cpp | 4 +- src/core/hle/service/nvdrv/nvdrv.h | 2 +- 18 files changed, 131 insertions(+), 128 deletions(-) (limited to 'src/core/hle/service') diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index d2a632646..37ca24f5d 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -10,9 +10,11 @@ namespace Service::Nvidia::NvCore { struct ContainerImpl { - ContainerImpl(Tegra::Host1x::Host1x& host1x_) : file{host1x_}, manager{host1x_} {} + explicit ContainerImpl(Tegra::Host1x::Host1x& host1x_) + : file{host1x_}, manager{host1x_}, device_file_data{} {} NvMap file; SyncpointManager manager; + Container::Host1xDeviceFileData device_file_data; }; Container::Container(Tegra::Host1x::Host1x& host1x_) { @@ -29,6 +31,14 @@ const NvMap& Container::GetNvMapFile() const { return impl->file; } +Container::Host1xDeviceFileData& Container::Host1xDeviceFile() { + return impl->device_file_data; +} + +const Container::Host1xDeviceFileData& Container::Host1xDeviceFile() const { + return impl->device_file_data; +} + SyncpointManager& Container::GetSyncpointManager() { return impl->manager; } diff --git a/src/core/hle/service/nvdrv/core/container.h b/src/core/hle/service/nvdrv/core/container.h index 5c8b95803..b4b63ac90 100644 --- a/src/core/hle/service/nvdrv/core/container.h +++ b/src/core/hle/service/nvdrv/core/container.h @@ -4,15 +4,15 @@ #pragma once +#include #include +#include -namespace Tegra { +#include "core/hle/service/nvdrv/nvdata.h" -namespace Host1x { +namespace Tegra::Host1x { class Host1x; -} // namespace Host1x - -} // namespace Tegra +} // namespace Tegra::Host1x namespace Service::Nvidia::NvCore { @@ -23,7 +23,7 @@ struct ContainerImpl; class Container { public: - Container(Tegra::Host1x::Host1x& host1x); + explicit Container(Tegra::Host1x::Host1x& host1x); ~Container(); NvMap& GetNvMapFile(); @@ -34,6 +34,17 @@ public: const SyncpointManager& GetSyncpointManager() const; + struct Host1xDeviceFileData { + std::unordered_map fd_to_id{}; + std::deque syncpts_accumulated{}; + u32 nvdec_next_id{}; + u32 vic_next_id{}; + }; + + Host1xDeviceFileData& Host1xDeviceFile(); + + const Host1xDeviceFileData& Host1xDeviceFile() const; + private: std::unique_ptr impl; }; diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index e63ec7717..fbd8a74a5 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -119,7 +119,7 @@ std::shared_ptr NvMap::GetHandle(Handle::Id handle) { std::scoped_lock lock(handles_lock); try { return handles.at(handle); - } catch ([[maybe_unused]] std::out_of_range& e) { + } catch (std::out_of_range&) { return nullptr; } } @@ -128,7 +128,7 @@ VAddr NvMap::GetHandleAddress(Handle::Id handle) { std::scoped_lock lock(handles_lock); try { return handles.at(handle)->address; - } catch ([[maybe_unused]] std::out_of_range& e) { + } catch (std::out_of_range&) { return 0; } } diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index 6d6dac023..b9dd3801f 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -98,35 +98,6 @@ public: } }; -private: - std::list> unmap_queue{}; - std::mutex unmap_queue_lock{}; //!< Protects access to `unmap_queue` - - std::unordered_map> - handles{}; //!< Main owning map of handles - std::mutex handles_lock; //!< Protects access to `handles` - - static constexpr u32 HandleIdIncrement{ - 4}; //!< Each new handle ID is an increment of 4 from the previous - std::atomic next_handle_id{HandleIdIncrement}; - Tegra::Host1x::Host1x& host1x; - - void AddHandle(std::shared_ptr handle); - - /** - * @brief Unmaps and frees the SMMU memory region a handle is mapped to - * @note Both `unmap_queue_lock` and `handle_description.mutex` MUST be locked when calling this - */ - void UnmapHandle(Handle& handle_description); - - /** - * @brief Removes a handle from the map taking its dupes into account - * @note handle_description.mutex MUST be locked when calling this - * @return If the handle was removed from the map - */ - bool TryRemoveHandle(const Handle& handle_description); - -public: /** * @brief Encapsulates the result of a FreeHandle operation */ @@ -136,7 +107,7 @@ public: bool was_uncached; //!< If the handle was allocated as uncached }; - NvMap(Tegra::Host1x::Host1x& host1x); + explicit NvMap(Tegra::Host1x::Host1x& host1x); /** * @brief Creates an unallocated handle of the given size @@ -172,5 +143,33 @@ public: * describing the prior state of the handle */ std::optional FreeHandle(Handle::Id handle, bool internal_session); + +private: + std::list> unmap_queue{}; + std::mutex unmap_queue_lock{}; //!< Protects access to `unmap_queue` + + std::unordered_map> + handles{}; //!< Main owning map of handles + std::mutex handles_lock; //!< Protects access to `handles` + + static constexpr u32 HandleIdIncrement{ + 4}; //!< Each new handle ID is an increment of 4 from the previous + std::atomic next_handle_id{HandleIdIncrement}; + Tegra::Host1x::Host1x& host1x; + + void AddHandle(std::shared_ptr handle); + + /** + * @brief Unmaps and frees the SMMU memory region a handle is mapped to + * @note Both `unmap_queue_lock` and `handle_description.mutex` MUST be locked when calling this + */ + void UnmapHandle(Handle& handle_description); + + /** + * @brief Removes a handle from the map taking its dupes into account + * @note handle_description.mutex MUST be locked when calling this + * @return If the handle was removed from the map + */ + bool TryRemoveHandle(const Handle& handle_description); }; } // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp index 072b3a22f..eda2041a0 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp @@ -18,23 +18,23 @@ SyncpointManager::SyncpointManager(Tegra::Host1x::Host1x& host1x_) : host1x{host ReserveSyncpoint(VBlank0SyncpointId, true); ReserveSyncpoint(VBlank1SyncpointId, true); - for (u32 syncpointId : channel_syncpoints) { - if (syncpointId) { - ReserveSyncpoint(syncpointId, false); + for (u32 syncpoint_id : channel_syncpoints) { + if (syncpoint_id) { + ReserveSyncpoint(syncpoint_id, false); } } } SyncpointManager::~SyncpointManager() = default; -u32 SyncpointManager::ReserveSyncpoint(u32 id, bool clientManaged) { +u32 SyncpointManager::ReserveSyncpoint(u32 id, bool client_managed) { if (syncpoints.at(id).reserved) { ASSERT_MSG(false, "Requested syncpoint is in use"); return 0; } syncpoints.at(id).reserved = true; - syncpoints.at(id).interfaceManaged = clientManaged; + syncpoints.at(id).interface_managed = client_managed; return id; } @@ -49,9 +49,9 @@ u32 SyncpointManager::FindFreeSyncpoint() { return 0; } -u32 SyncpointManager::AllocateSyncpoint(bool clientManaged) { +u32 SyncpointManager::AllocateSyncpoint(bool client_managed) { std::lock_guard lock(reservation_lock); - return ReserveSyncpoint(FindFreeSyncpoint(), clientManaged); + return ReserveSyncpoint(FindFreeSyncpoint(), client_managed); } void SyncpointManager::FreeSyncpoint(u32 id) { @@ -64,7 +64,7 @@ bool SyncpointManager::IsSyncpointAllocated(u32 id) { return (id <= SyncpointCount) && syncpoints[id].reserved; } -bool SyncpointManager::HasSyncpointExpired(u32 id, u32 threshold) { +bool SyncpointManager::HasSyncpointExpired(u32 id, u32 threshold) const { const SyncpointInfo& syncpoint{syncpoints.at(id)}; if (!syncpoint.reserved) { @@ -74,10 +74,10 @@ bool SyncpointManager::HasSyncpointExpired(u32 id, u32 threshold) { // 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(syncpoint.counterMin - threshold) >= 0; + if (syncpoint.interface_managed) { + return static_cast(syncpoint.counter_min - threshold) >= 0; } else { - return (syncpoint.counterMax - threshold) >= (syncpoint.counterMin - threshold); + return (syncpoint.counter_max - threshold) >= (syncpoint.counter_min - threshold); } } @@ -87,7 +87,7 @@ u32 SyncpointManager::IncrementSyncpointMaxExt(u32 id, u32 amount) { return 0; } - return syncpoints.at(id).counterMax += amount; + return syncpoints.at(id).counter_max += amount; } u32 SyncpointManager::ReadSyncpointMinValue(u32 id) { @@ -96,7 +96,7 @@ u32 SyncpointManager::ReadSyncpointMinValue(u32 id) { return 0; } - return syncpoints.at(id).counterMin; + return syncpoints.at(id).counter_min; } u32 SyncpointManager::UpdateMin(u32 id) { @@ -105,8 +105,8 @@ u32 SyncpointManager::UpdateMin(u32 id) { return 0; } - syncpoints.at(id).counterMin = host1x.GetSyncpointManager().GetHostSyncpointValue(id); - return syncpoints.at(id).counterMin; + syncpoints.at(id).counter_min = host1x.GetSyncpointManager().GetHostSyncpointValue(id); + return syncpoints.at(id).counter_min; } NvFence SyncpointManager::GetSyncpointFence(u32 id) { @@ -115,7 +115,7 @@ NvFence SyncpointManager::GetSyncpointFence(u32 id) { return NvFence{}; } - return {.id = static_cast(id), .value = syncpoints.at(id).counterMax}; + return {.id = static_cast(id), .value = syncpoints.at(id).counter_max}; } } // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.h b/src/core/hle/service/nvdrv/core/syncpoint_manager.h index 6b71cd33d..b76ef9032 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.h +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.h @@ -11,13 +11,9 @@ #include "common/common_types.h" #include "core/hle/service/nvdrv/nvdata.h" -namespace Tegra { - -namespace Host1x { +namespace Tegra::Host1x { class Host1x; -} // namespace Host1x - -} // namespace Tegra +} // namespace Tegra::Host1x namespace Service::Nvidia::NvCore { @@ -54,15 +50,15 @@ public: * @brief Finds a free syncpoint and reserves it * @return The ID of the reserved syncpoint */ - u32 AllocateSyncpoint(bool clientManaged); + u32 AllocateSyncpoint(bool client_managed); /** * @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 HasSyncpointExpired(u32 id, u32 threshold) const; - bool IsFenceSignalled(NvFence fence) { + bool IsFenceSignalled(NvFence fence) const { return HasSyncpointExpired(fence.id, fence.value); } @@ -107,7 +103,7 @@ private: /** * @note reservation_lock should be locked when calling this */ - u32 ReserveSyncpoint(u32 id, bool clientManaged); + u32 ReserveSyncpoint(u32 id, bool client_managed); /** * @return The ID of the first free syncpoint @@ -115,15 +111,15 @@ private: u32 FindFreeSyncpoint(); struct SyncpointInfo { - std::atomic counterMin; //!< The least value the syncpoint can be (The value it was - //!< when it was last synchronized with host1x) - std::atomic 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) + std::atomic counter_min; //!< The least value the syncpoint can be (The value it was + //!< when it was last synchronized with host1x) + std::atomic counter_max; //!< The maximum value the syncpoint can reach according to + //!< the current usage + bool interface_managed; //!< 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 }; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 192503ffc..6411dbf43 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -106,7 +106,7 @@ NvResult nvhost_as_gpu::AllocAsEx(const std::vector& input, std::vector& return NvResult::BadValue; } - if (!(params.big_page_size & VM::SUPPORTED_BIG_PAGE_SIZES)) { + if ((params.big_page_size & VM::SUPPORTED_BIG_PAGE_SIZES) == 0) { LOG_ERROR(Service_NVDRV, "Unsupported big page size: 0x{:X}!", params.big_page_size); return NvResult::BadValue; } @@ -124,12 +124,13 @@ NvResult nvhost_as_gpu::AllocAsEx(const std::vector& input, std::vector& vm.va_range_end = params.va_range_end; } - const u64 start_pages{vm.va_range_start >> VM::PAGE_SIZE_BITS}; - const u64 end_pages{vm.va_range_split >> VM::PAGE_SIZE_BITS}; + const auto start_pages{static_cast(vm.va_range_start >> VM::PAGE_SIZE_BITS)}; + const auto end_pages{static_cast(vm.va_range_split >> VM::PAGE_SIZE_BITS)}; vm.small_page_allocator = std::make_shared(start_pages, end_pages); - const u64 start_big_pages{vm.va_range_split >> vm.big_page_size_bits}; - const u64 end_big_pages{(vm.va_range_end - vm.va_range_split) >> vm.big_page_size_bits}; + const auto start_big_pages{static_cast(vm.va_range_split >> vm.big_page_size_bits)}; + const auto end_big_pages{ + static_cast((vm.va_range_end - vm.va_range_split) >> vm.big_page_size_bits)}; vm.big_page_allocator = std::make_unique(start_big_pages, end_big_pages); gmmu = std::make_shared(system, 40, vm.big_page_size_bits, @@ -210,10 +211,11 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) { // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state // Only FreeSpace can unmap them fully - if (mapping->sparse_alloc) + if (mapping->sparse_alloc) { gmmu->MapSparse(offset, mapping->size, mapping->big_page); - else + } else { gmmu->Unmap(offset, mapping->size); + } mapping_map.erase(offset); } @@ -256,7 +258,7 @@ NvResult nvhost_as_gpu::FreeSpace(const std::vector& input, std::vector& allocator.Free(static_cast(params.offset >> page_size_bits), static_cast(allocation.size >> page_size_bits)); allocation_map.erase(params.offset); - } catch ([[maybe_unused]] const std::out_of_range& e) { + } catch (const std::out_of_range&) { return NvResult::BadValue; } @@ -351,7 +353,7 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vectorMap(gpu_address, cpu_address, params.mapping_size, mapping->big_page); return NvResult::Success; - } catch ([[maybe_unused]] const std::out_of_range& e) { + } catch (const std::out_of_range&) { LOG_WARNING(Service_NVDRV, "Cannot remap an unmapped GPU address space region: 0x{:X}", params.offset); return NvResult::BadValue; @@ -367,11 +369,11 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vectororig_size}; bool big_page{[&]() { - if (Common::IsAligned(handle->align, vm.big_page_size)) + if (Common::IsAligned(handle->align, vm.big_page_size)) { return true; - else if (Common::IsAligned(handle->align, VM::YUZU_PAGESIZE)) + } else if (Common::IsAligned(handle->align, VM::YUZU_PAGESIZE)) { return false; - else { + } else { ASSERT(false); return false; } @@ -450,7 +452,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(const std::vector& input, std::vector& input, std::vectorinitiated) { + if (channel_state->initialized) { LOG_CRITICAL(Service_NVDRV, "Already allocated!"); return NvResult::AlreadyAllocated; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index fed537039..1703f9cc3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -5,13 +5,12 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" #include "video_core/renderer_base.h" namespace Service::Nvidia::Devices { -u32 nvhost_nvdec::next_id{}; - nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core_) : nvhost_nvdec_common{system_, core_, NvCore::ChannelType::NvDec} {} nvhost_nvdec::~nvhost_nvdec() = default; @@ -22,8 +21,9 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& case 0x0: switch (command.cmd) { case 0x1: { - if (!fd_to_id.contains(fd)) { - fd_to_id[fd] = next_id++; + auto& host1x_file = core.Host1xDeviceFile(); + if (!host1x_file.fd_to_id.contains(fd)) { + host1x_file.fd_to_id[fd] = host1x_file.nvdec_next_id++; } return Submit(fd, input, output); } @@ -74,8 +74,9 @@ void nvhost_nvdec::OnOpen(DeviceFD fd) { void nvhost_nvdec::OnClose(DeviceFD fd) { LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); - const auto iter = fd_to_id.find(fd); - if (iter != fd_to_id.end()) { + auto& host1x_file = core.Host1xDeviceFile(); + const auto iter = host1x_file.fd_to_id.find(fd); + if (iter != host1x_file.fd_to_id.end()) { system.GPU().ClearCdmaInstance(iter->second); } system.AudioCore().SetNVDECActive(false); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 3261ce1d4..c1b4e53e8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -22,9 +22,6 @@ public: void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; - -private: - static u32 next_id; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 2ec1ad3e9..99eede702 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -46,13 +46,11 @@ std::size_t WriteVectors(std::vector& dst, const std::vector& src, std::s } } // Anonymous namespace -std::unordered_map nvhost_nvdec_common::fd_to_id{}; -std::deque nvhost_nvdec_common::syncpts_accumulated{}; - nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_, NvCore::ChannelType channel_type_) : nvdevice{system_}, core{core_}, syncpoint_manager{core.GetSyncpointManager()}, nvmap{core.GetNvMapFile()}, channel_type{channel_type_} { + auto& syncpts_accumulated = core.Host1xDeviceFile().syncpts_accumulated; if (syncpts_accumulated.empty()) { channel_syncpoint = syncpoint_manager.AllocateSyncpoint(false); } else { @@ -60,8 +58,9 @@ nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Containe syncpts_accumulated.pop_front(); } } + nvhost_nvdec_common::~nvhost_nvdec_common() { - syncpts_accumulated.push_back(channel_syncpoint); + core.Host1xDeviceFile().syncpts_accumulated.push_back(channel_syncpoint); } NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector& input) { @@ -108,7 +107,7 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector& input, Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); system.Memory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(), cmdlist.size() * sizeof(u32)); - gpu.PushCommandBuffer(fd_to_id[fd], cmdlist); + gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist); } std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmit)); // Some games expect command_buffers to be written back @@ -186,8 +185,4 @@ Kernel::KEvent* nvhost_nvdec_common::QueryEvent(u32 event_id) { return nullptr; } -void nvhost_nvdec_common::Reset() { - fd_to_id.clear(); -} - } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index 93990bb9b..fe76100c8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -25,8 +25,6 @@ public: NvCore::ChannelType channel_type); ~nvhost_nvdec_common() override; - static void Reset(); - protected: struct IoctlSetNvmapFD { s32_le nvmap_fd{}; @@ -119,7 +117,6 @@ protected: Kernel::KEvent* QueryEvent(u32 event_id) override; - static std::unordered_map fd_to_id; u32 channel_syncpoint; s32_le nvmap_fd{}; u32_le submit_timeout{}; @@ -128,8 +125,6 @@ protected: NvCore::NvMap& nvmap; NvCore::ChannelType channel_type; std::array device_syncpoints{}; - - static std::deque syncpts_accumulated; }; }; // namespace Devices } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 2e4ff988c..73f97136e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -4,13 +4,12 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/devices/nvhost_vic.h" #include "video_core/renderer_base.h" namespace Service::Nvidia::Devices { -u32 nvhost_vic::next_id{}; - nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core_) : nvhost_nvdec_common{system_, core_, NvCore::ChannelType::VIC} {} @@ -21,11 +20,13 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector& i switch (command.group) { case 0x0: switch (command.cmd) { - case 0x1: - if (!fd_to_id.contains(fd)) { - fd_to_id[fd] = next_id++; + case 0x1: { + auto& host1x_file = core.Host1xDeviceFile(); + if (!host1x_file.fd_to_id.contains(fd)) { + host1x_file.fd_to_id[fd] = host1x_file.vic_next_id++; } return Submit(fd, input, output); + } case 0x2: return GetSyncpoint(input, output); case 0x3: @@ -69,8 +70,9 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, const std::vector& i void nvhost_vic::OnOpen(DeviceFD fd) {} void nvhost_vic::OnClose(DeviceFD fd) { - const auto iter = fd_to_id.find(fd); - if (iter != fd_to_id.end()) { + auto& host1x_file = core.Host1xDeviceFile(); + const auto iter = host1x_file.fd_to_id.find(fd); + if (iter != host1x_file.fd_to_id.end()) { system.GPU().ClearCdmaInstance(iter->second); } } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index 59e23b41e..f164caafb 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -21,8 +21,5 @@ public: void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; - -private: - static u32 next_id; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 52e1d7cff..e9bfd0358 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -23,8 +23,8 @@ public: explicit nvmap(Core::System& system_, NvCore::Container& container); ~nvmap() override; - nvmap(nvmap const&) = delete; - nvmap& operator=(nvmap const&) = delete; + nvmap(const nvmap&) = delete; + nvmap& operator=(const nvmap&) = delete; NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector& input, std::vector& output) override; diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 7929443d2..5e7b7468f 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -101,9 +101,7 @@ Module::Module(Core::System& system) }; } -Module::~Module() { - Devices::nvhost_nvdec_common::Reset(); -} +Module::~Module() {} NvResult Module::VerifyFD(DeviceFD fd) const { if (fd < 0) { diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index a2aeb80b4..146d046a9 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -46,7 +46,7 @@ class Module; class EventInterface { public: - EventInterface(Module& module_); + explicit EventInterface(Module& module_); ~EventInterface(); Kernel::KEvent* CreateEvent(std::string name); -- cgit v1.2.3