less load, fix nv01 timer being kepler

This commit is contained in:
lizzie 2026-04-30 23:57:07 +00:00
parent 8ca1702dee
commit d930ff52e1
12 changed files with 93 additions and 79 deletions

View file

@ -17,28 +17,36 @@
namespace Tegra::Control {
ChannelState::ChannelState(s32 bind_id_) : bind_id{bind_id_}, initialized{} {}
ChannelState::Payload::Payload(Core::System& system, MemoryManager& memory_manager, ChannelState& channel_state)
: maxwell_3d(system, memory_manager)
, fermi_2d(memory_manager)
, kepler_compute(system, memory_manager)
, maxwell_dma(system, memory_manager)
, kepler_memory(system, memory_manager)
, nv01_timer(system, memory_manager)
, dma_pusher(system, memory_manager, channel_state)
{}
ChannelState::ChannelState(s32 bind_id_)
: bind_id{bind_id_}
{}
void ChannelState::Init(Core::System& system, u64 program_id_) {
ASSERT(memory_manager);
program_id = program_id_;
dma_pusher.emplace(system, *memory_manager, *this);
maxwell_3d.emplace(system, *memory_manager);
fermi_2d.emplace(*memory_manager);
kepler_compute.emplace(system, *memory_manager);
maxwell_dma.emplace(system, *memory_manager);
kepler_memory.emplace(system, *memory_manager);
payload.emplace(system, *memory_manager, *this);
initialized = true;
}
void ChannelState::BindRasterizer(VideoCore::RasterizerInterface* rasterizer) {
dma_pusher->BindRasterizer(rasterizer);
payload->dma_pusher.BindRasterizer(rasterizer);
memory_manager->BindRasterizer(rasterizer);
maxwell_3d->BindRasterizer(rasterizer);
fermi_2d->BindRasterizer(rasterizer);
kepler_memory->BindRasterizer(rasterizer);
kepler_compute->BindRasterizer(rasterizer);
maxwell_dma->BindRasterizer(rasterizer);
payload->maxwell_3d.BindRasterizer(rasterizer);
payload->fermi_2d.BindRasterizer(rasterizer);
payload->kepler_memory.BindRasterizer(rasterizer);
payload->kepler_compute.BindRasterizer(rasterizer);
payload->maxwell_dma.BindRasterizer(rasterizer);
//payload->nv01_timer.BindRasterizer(rasterizer);
}
} // namespace Tegra::Control

View file

@ -14,6 +14,7 @@
#include "video_core/engines/kepler_compute.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/engines/maxwell_dma.h"
#include "video_core/engines/nv01_timer.h"
#include "video_core/dma_pusher.h"
namespace Core {
@ -38,24 +39,29 @@ struct ChannelState {
void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
/// 3D engine
std::optional<Engines::Maxwell3D> maxwell_3d;
/// 2D engine
std::optional<Engines::Fermi2D> fermi_2d;
/// Compute engine
std::optional<Engines::KeplerCompute> kepler_compute;
/// DMA engine
std::optional<Engines::MaxwellDMA> maxwell_dma;
/// Inline memory engine
std::optional<Engines::KeplerMemory> kepler_memory;
/// NV01 Timer
std::optional<Engines::KeplerMemory> nv01_timer;
std::optional<DmaPusher> dma_pusher;
std::shared_ptr<MemoryManager> memory_manager;
struct Payload {
explicit Payload(Core::System& system, MemoryManager& memory_manager, ChannelState& channel_state);
/// 3D engine
Engines::Maxwell3D maxwell_3d;
/// 2D engine
Engines::Fermi2D fermi_2d;
/// Compute engine
Engines::KeplerCompute kepler_compute;
/// DMA engine
Engines::MaxwellDMA maxwell_dma;
/// Inline memory engine
Engines::KeplerMemory kepler_memory;
/// NV01 Timer
Engines::Nv01Timer nv01_timer;
DmaPusher dma_pusher;
};
std::optional<Payload> payload;
MemoryManager* memory_manager = nullptr;
s32 bind_id = -1;
u64 program_id = 0;
bool initialized{};
bool initialized = false;
};
} // namespace Control

View file

@ -189,12 +189,12 @@ struct GPU::Impl {
/// Push GPU command entries to be processed
void PushGPUEntries(s32 channel, Tegra::CommandList&& entries) {
gpu_thread.SubmitList(channel, std::move(entries));
gpu_thread.SubmitList(channel, std::move(entries), is_async);
}
/// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
void FlushRegion(DAddr addr, u64 size) {
gpu_thread.FlushRegion(addr, size);
gpu_thread.FlushRegion(addr, size, is_async);
}
VideoCore::RasterizerDownloadArea OnCPURead(DAddr addr, u64 size) {
@ -206,7 +206,7 @@ struct GPU::Impl {
const u64 fence = RequestSyncOperation([this, &raster_area]() {
renderer->ReadRasterizer()->FlushRegion(raster_area.start_address, raster_area.end_address - raster_area.start_address);
});
gpu_thread.TickGPU();
gpu_thread.TickGPU(is_async);
WaitForSyncOperation(fence);
return raster_area;
}
@ -222,7 +222,7 @@ struct GPU::Impl {
/// Notify rasterizer that any caches of the specified region should be flushed and invalidated
void FlushAndInvalidateRegion(DAddr addr, u64 size) {
gpu_thread.FlushAndInvalidateRegion(addr, size);
gpu_thread.FlushAndInvalidateRegion(addr, size, is_async);
}
void RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers,
@ -260,7 +260,7 @@ struct GPU::Impl {
syncpoint_manager.RegisterGuestAction(fences[i].id, fences[i].value, executer);
}
});
gpu_thread.TickGPU();
gpu_thread.TickGPU(is_async);
WaitForSyncOperation(wait_fence);
}
@ -269,7 +269,7 @@ struct GPU::Impl {
const auto wait_fence =
RequestSyncOperation([&] { out = renderer->GetAppletCaptureBuffer(); });
gpu_thread.TickGPU();
gpu_thread.TickGPU(is_async);
WaitForSyncOperation(wait_fence);
return out;

View file

@ -20,7 +20,8 @@
namespace VideoCommon::GPUThread {
ThreadManager::ThreadManager(Core::System& system_, bool is_async_)
: system{system_}, is_async{is_async_} {}
: system{system_}
{}
ThreadManager::~ThreadManager() = default;
@ -60,41 +61,41 @@ void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Core::Fronten
});
}
void ThreadManager::SubmitList(s32 channel, Tegra::CommandList&& entries) {
PushCommand(SubmitListCommand(channel, std::move(entries)));
void ThreadManager::SubmitList(s32 channel, Tegra::CommandList&& entries, bool is_async) {
PushCommand(SubmitListCommand(channel, std::move(entries)), false, is_async);
}
void ThreadManager::FlushRegion(DAddr addr, u64 size) {
void ThreadManager::FlushRegion(DAddr addr, u64 size, bool is_async) {
if (!is_async) {
// Always flush with synchronous GPU mode
PushCommand(FlushRegionCommand(addr, size));
PushCommand(FlushRegionCommand(addr, size), false, is_async);
}
return;
}
void ThreadManager::TickGPU() {
PushCommand(GPUTickCommand());
void ThreadManager::TickGPU(bool is_async) {
PushCommand(GPUTickCommand(), false, is_async);
}
void ThreadManager::InvalidateRegion(DAddr addr, u64 size) {
rasterizer->OnCacheInvalidation(addr, size);
}
void ThreadManager::FlushAndInvalidateRegion(DAddr addr, u64 size) {
void ThreadManager::FlushAndInvalidateRegion(DAddr addr, u64 size, bool is_async) {
if (Settings::IsGPULevelHigh()) {
if (!is_async) {
PushCommand(FlushRegionCommand(addr, size));
PushCommand(FlushRegionCommand(addr, size), false, is_async);
} else {
auto& gpu = system.GPU();
const u64 fence = gpu.RequestFlush(addr, size);
TickGPU();
TickGPU(is_async);
gpu.WaitForSyncOperation(fence);
}
}
rasterizer->OnCacheInvalidation(addr, size);
}
u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) {
u64 ThreadManager::PushCommand(CommandData&& command_data, bool block, bool is_async) {
if (!is_async) {
// In synchronous GPU mode, block the caller until the command has executed
block = true;

View file

@ -15,6 +15,7 @@
#include "common/bounded_threadsafe_queue.h"
#include "common/polyfill_thread.h"
#include "video_core/dma_pusher.h"
#include "video_core/framebuffer_config.h"
namespace Tegra {
@ -111,27 +112,25 @@ public:
Tegra::Control::Scheduler& scheduler);
/// Push GPU command entries to be processed
void SubmitList(s32 channel, Tegra::CommandList&& entries);
void SubmitList(s32 channel, Tegra::CommandList&& entries, bool is_async);
/// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
void FlushRegion(DAddr addr, u64 size);
void FlushRegion(DAddr addr, u64 size, bool is_async);
/// Notify rasterizer that any caches of the specified region should be invalidated
void InvalidateRegion(DAddr addr, u64 size);
/// Notify rasterizer that any caches of the specified region should be flushed and invalidated
void FlushAndInvalidateRegion(DAddr addr, u64 size);
void FlushAndInvalidateRegion(DAddr addr, u64 size, bool is_async);
void TickGPU();
void TickGPU(bool is_async);
private:
/// Pushes a command to be executed by the GPU thread
u64 PushCommand(CommandData&& command_data, bool block = false);
u64 PushCommand(CommandData&& command_data, bool block, bool is_async);
Core::System& system;
const bool is_async;
VideoCore::RasterizerInterface* rasterizer = nullptr;
SynchState state;
std::jthread thread;
};

View file

@ -45,23 +45,23 @@ std::unique_ptr<VideoCore::RendererBase> CreateRenderer(Core::System& system, Co
namespace VideoCore {
std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system) {
/// @brief Creates an emulated GPU instance using the given system context.
void CreateGPU(std::optional<Tegra::GPU>& gpu, Core::Frontend::EmuWindow& emu_window, Core::System& system) {
Settings::UpdateRescalingInfo();
const auto nvdec_value = Settings::values.nvdec_emulation.GetValue();
const bool use_nvdec = nvdec_value != Settings::NvdecEmulation::Off;
const bool use_async = Settings::values.use_asynchronous_gpu_emulation.GetValue();
auto gpu = std::make_unique<Tegra::GPU>(system, use_async, use_nvdec);
gpu.emplace(system, use_async, use_nvdec);
auto context = emu_window.CreateSharedContext();
auto scope = context->Acquire();
try {
auto renderer = CreateRenderer(system, emu_window, *gpu, std::move(context));
gpu->BindRenderer(std::move(renderer));
return gpu;
} catch (const std::runtime_error& exception) {
scope.Cancel();
LOG_ERROR(HW_GPU, "Failed to initialize GPU: {}", exception.what());
return nullptr;
gpu.reset();
}
}

View file

@ -1,9 +1,13 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include <optional>
namespace Core {
class System;
@ -20,8 +24,6 @@ class GPU;
namespace VideoCore {
class RendererBase;
/// Creates an emulated GPU instance using the given system context.
std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system);
void CreateGPU(std::optional<Tegra::GPU>& gpu, Core::Frontend::EmuWindow& emu_window, Core::System& system);
} // namespace VideoCore