From 8942047d419f6d2d0c56adad689fbf3bcd4d2961 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 7 Jun 2019 20:41:06 -0400 Subject: [PATCH] Gpu: Implement Hardware Interrupt Manager and manage GPU interrupts --- src/core/CMakeLists.txt | 2 ++ src/core/core.cpp | 12 +++++++++++- src/core/core.h | 10 ++++++++++ src/core/hardware_interrupt_manager.cpp | 21 +++++++++++++++++++++ src/core/hardware_interrupt_manager.h | 24 ++++++++++++++++++++++++ src/core/hle/service/nvdrv/interface.cpp | 2 -- src/core/hle/service/nvdrv/interface.h | 2 -- src/core/hle/service/nvdrv/nvdrv.h | 5 +---- src/video_core/gpu.cpp | 7 ++++++- src/video_core/gpu.h | 5 ++--- src/video_core/gpu_asynch.cpp | 7 +++++++ src/video_core/gpu_asynch.h | 3 +++ src/video_core/gpu_synch.h | 3 +++ 13 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 src/core/hardware_interrupt_manager.cpp create mode 100644 src/core/hardware_interrupt_manager.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c22585bfb4..12f06a1899 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -111,6 +111,8 @@ add_library(core STATIC frontend/scope_acquire_window_context.h gdbstub/gdbstub.cpp gdbstub/gdbstub.h + hardware_interrupt_manager.cpp + hardware_interrupt_manager.h hle/ipc.h hle/ipc_helpers.h hle/kernel/address_arbiter.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index 262411db85..d7f43f5ec5 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -19,6 +19,7 @@ #include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_real.h" #include "core/gdbstub/gdbstub.h" +#include "core/hardware_interrupt_manager.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" @@ -150,7 +151,7 @@ struct System::Impl { if (!renderer->Init()) { return ResultStatus::ErrorVideoCore; } - + interrupt_manager = std::make_unique(system); gpu_core = VideoCore::CreateGPU(system); is_powered_on = true; @@ -297,6 +298,7 @@ struct System::Impl { std::unique_ptr renderer; std::unique_ptr gpu_core; std::shared_ptr debug_context; + std::unique_ptr interrupt_manager; CpuCoreManager cpu_core_manager; bool is_powered_on = false; @@ -440,6 +442,14 @@ const Tegra::GPU& System::GPU() const { return *impl->gpu_core; } +Core::Hardware::InterruptManager& System::InterruptManager() { + return *impl->interrupt_manager; +} + +const Core::Hardware::InterruptManager& System::InterruptManager() const { + return *impl->interrupt_manager; +} + VideoCore::RendererBase& System::Renderer() { return *impl->renderer; } diff --git a/src/core/core.h b/src/core/core.h index 70adb7af96..53e6fdb7b9 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -66,6 +66,10 @@ namespace Core::Timing { class CoreTiming; } +namespace Core::Hardware { +class InterruptManager; +} + namespace Core { class ARM_Interface; @@ -230,6 +234,12 @@ public: /// Provides a constant reference to the core timing instance. const Timing::CoreTiming& CoreTiming() const; + /// Provides a reference to the interrupt manager instance. + Core::Hardware::InterruptManager& InterruptManager(); + + /// Provides a constant reference to the interrupt manager instance. + const Core::Hardware::InterruptManager& InterruptManager() const; + /// Provides a reference to the kernel instance. Kernel::KernelCore& Kernel(); diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp new file mode 100644 index 0000000000..463d2916c5 --- /dev/null +++ b/src/core/hardware_interrupt_manager.cpp @@ -0,0 +1,21 @@ + +#include "core/core.h" +#include "core/hardware_interrupt_manager.h" +#include "core/hle/service/nvdrv/interface.h" +#include "core/hle/service/sm/sm.h" + +namespace Core::Hardware { + +InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { + gpu_interrupt_event = + system.CoreTiming().RegisterEvent("GPUInterrupt", [this](u64 event_index, s64) { + auto nvdrv = system.ServiceManager().GetService("nvdrv"); + nvdrv->SignalGPUInterrupt(static_cast(event_index)); + }); +} + +void InterruptManager::InterruptGPU(const u32 event_index) { + system.CoreTiming().ScheduleEvent(10, gpu_interrupt_event, static_cast(event_index)); +} + +} // namespace Core::Hardware diff --git a/src/core/hardware_interrupt_manager.h b/src/core/hardware_interrupt_manager.h new file mode 100644 index 0000000000..fc565c88bf --- /dev/null +++ b/src/core/hardware_interrupt_manager.h @@ -0,0 +1,24 @@ +#pragma once + +#include "common/common_types.h" +#include "core/core_timing.h" + +namespace Core { +class System; +} + +namespace Core::Hardware { + +class InterruptManager { +public: + InterruptManager(Core::System& system); + ~InterruptManager() = default; + + void InterruptGPU(const u32 event_index); + +private: + Core::System& system; + Core::Timing::EventType* gpu_interrupt_event{}; +}; + +} // namespace Core::Hardware diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 76482d16e4..d95ba18cb2 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -140,8 +140,6 @@ NVDRV::NVDRV(std::shared_ptr nvdrv, const char* name) RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - query_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, - "NVDRV::query_event"); } NVDRV::~NVDRV() = default; diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 421b010174..09cf4bb121 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h @@ -35,8 +35,6 @@ private: std::shared_ptr nvdrv; u64 pid{}; - - Kernel::EventPair query_event; }; } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 9a4cdc60ff..d299f28772 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -8,6 +8,7 @@ #include #include #include "common/common_types.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/nvdrv/nvdata.h" #include "core/hle/service/service.h" @@ -15,10 +16,6 @@ namespace Service::NVFlinger { class NVFlinger; } -namespace Kernel { -class WritableEvent; -} - namespace Service::Nvidia { namespace Devices { diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 1d12f04930..06eb570ab7 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -29,7 +29,8 @@ u32 FramebufferConfig::BytesPerPixel(PixelFormat format) { UNREACHABLE(); } -GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer) : renderer{renderer} { +GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer) + : system{system}, renderer{renderer} { auto& rasterizer{renderer.Rasterizer()}; memory_manager = std::make_unique(rasterizer); dma_pusher = std::make_unique(*this); @@ -87,6 +88,10 @@ u32 GPU::GetSyncpointValue(const u32 syncpoint_id) const { } void GPU::RegisterEvent(const u32 event_id, const u32 syncpoint_id, const u32 value) { + for (auto& ev : events[syncpoint_id]) { + if (ev.event_id == event_id && ev.value == value) + return; + } events[syncpoint_id].emplace_back(event_id, value); } diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 4c97d6c6f4..c3e5311fac 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -238,9 +238,7 @@ public: virtual void FlushAndInvalidateRegion(CacheAddr addr, u64 size) = 0; protected: - virtual void TriggerCpuInterrupt(const u32 event_id) const { - // Todo implement this - } + virtual void TriggerCpuInterrupt(const u32 event_id) const = 0; private: void ProcessBindMethod(const MethodCall& method_call); @@ -260,6 +258,7 @@ private: protected: std::unique_ptr dma_pusher; VideoCore::RendererBase& renderer; + Core::System& system; private: std::unique_ptr memory_manager; diff --git a/src/video_core/gpu_asynch.cpp b/src/video_core/gpu_asynch.cpp index d4e2553a95..7060f9a89b 100644 --- a/src/video_core/gpu_asynch.cpp +++ b/src/video_core/gpu_asynch.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/core.h" +#include "core/hardware_interrupt_manager.h" #include "video_core/gpu_asynch.h" #include "video_core/gpu_thread.h" #include "video_core/renderer_base.h" @@ -38,4 +40,9 @@ void GPUAsynch::FlushAndInvalidateRegion(CacheAddr addr, u64 size) { gpu_thread.FlushAndInvalidateRegion(addr, size); } +void GPUAsynch::TriggerCpuInterrupt(const u32 event_id) const { + auto& interrupt_manager = system.InterruptManager(); + interrupt_manager.InterruptGPU(event_id); +} + } // namespace VideoCommon diff --git a/src/video_core/gpu_asynch.h b/src/video_core/gpu_asynch.h index 30be74cba8..d49e9b96e7 100644 --- a/src/video_core/gpu_asynch.h +++ b/src/video_core/gpu_asynch.h @@ -27,6 +27,9 @@ public: void InvalidateRegion(CacheAddr addr, u64 size) override; void FlushAndInvalidateRegion(CacheAddr addr, u64 size) override; +protected: + void TriggerCpuInterrupt(const u32 event_id) const override; + private: GPUThread::ThreadManager gpu_thread; }; diff --git a/src/video_core/gpu_synch.h b/src/video_core/gpu_synch.h index 3031fcf725..09bda854a2 100644 --- a/src/video_core/gpu_synch.h +++ b/src/video_core/gpu_synch.h @@ -25,6 +25,9 @@ public: void FlushRegion(CacheAddr addr, u64 size) override; void InvalidateRegion(CacheAddr addr, u64 size) override; void FlushAndInvalidateRegion(CacheAddr addr, u64 size) override; + +protected: + void TriggerCpuInterrupt(const u32 event_id) const override {} }; } // namespace VideoCommon