aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/dma_pusher.cpp
diff options
context:
space:
mode:
authorDjihads <76681596+Djihads80@users.noreply.github.com>2026-10-30 11:33:03 +0100
committerGitHub <noreply@github.com>2026-10-30 11:33:03 +0100
commit9560dec549134cf50a7bcde3f86f87ed7658b25f (patch)
tree75493cfac29ed9d1dc350658e17c366f7e10a3c4 /src/video_core/dma_pusher.cpp
parent666d2447639594c7cd2b184acf2117b38766ac22 (diff)
parent937bb4dd30401a339a062386c121b9714e33e38d (diff)
Merge pull request #26 from Djihads80/nx2-experimental
Nx2 experimental
Diffstat (limited to 'src/video_core/dma_pusher.cpp')
-rw-r--r--src/video_core/dma_pusher.cpp86
1 files changed, 83 insertions, 3 deletions
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp
index 3cc5afe967..62f7e6bfdb 100644
--- a/src/video_core/dma_pusher.cpp
+++ b/src/video_core/dma_pusher.cpp
@@ -12,10 +12,13 @@
#include "common/settings.h"
#include "core/core.h"
#include "core/memory.h"
+#include "video_core/nx2_profile.h"
#include "video_core/dma_pusher.h"
#include "video_core/control/channel_state.h"
+#include "video_core/engines/kepler_compute.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/gpu.h"
+#include "video_core/gpu_split.h"
#include "video_core/guest_memory.h"
#include "video_core/memory_manager.h"
#include "video_core/nx2.h"
@@ -44,6 +47,14 @@ void DmaPusher::DispatchCalls() {
break;
}
}
+ if (auto& split = VideoCommon::GpuSplit::Get(); split.Active()) {
+ split.Defer([gpu = &system.GPU()] {
+ gpu->FlushCommands();
+ gpu->OnCommandListEnd();
+ });
+ split.Publish();
+ return;
+ }
system.GPU().FlushCommands();
system.GPU().OnCommandListEnd();
}
@@ -97,7 +108,16 @@ bool DmaPusher::Step() {
const bool macro_payload = engine == Engines::EngineTypes::Maxwell3D && dma_state.method >= MacroRegistersStart;
if (kepler_payload || macro_payload) {
const size_t words = std::min<size_t>(dma_state.method_count, header.size);
- subchannels[dma_state.subchannel]->current_dirty = memory_manager.IsMemoryDirty(dma_state.dma_get, words * sizeof(u32));
+ auto* const engine_state = subchannels[dma_state.subchannel];
+ if (auto& split = VideoCommon::GpuSplit::Get(); split.Active()) {
+ // The caches behind IsMemoryDirty belong to the split's back thread.
+ split.Defer([engine_state, memory = &memory_manager, address = GPUVAddr{dma_state.dma_get},
+ bytes = words * sizeof(u32)] {
+ engine_state->current_dirty = memory->IsMemoryDirty(address, bytes);
+ });
+ } else {
+ engine_state->current_dirty = memory_manager.IsMemoryDirty(dma_state.dma_get, words * sizeof(u32));
+ }
}
}
if (command_resume_offset == 0) {
@@ -115,9 +135,9 @@ bool DmaPusher::Step() {
u64{header.allow_flush}, split_method_end, parked_methods.size());
std::array<u32, 8> next_words{};
std::array<u32, 4> prev_words{};
- memory_manager.ReadBlock(header.addr, next_words.data(),
+ memory_manager.ReadBlockUnsafe(header.addr, next_words.data(),
std::min<size_t>(header.size, 8) * sizeof(u32));
- memory_manager.ReadBlock(split_method_end - sizeof(prev_words), prev_words.data(),
+ memory_manager.ReadBlockUnsafe(split_method_end - sizeof(prev_words), prev_words.data(),
sizeof(prev_words));
LOG_DEBUG(HW_GPU, " previous entry ends {:08x}; next entry starts {:08x}",
fmt::join(prev_words, " "), fmt::join(next_words, " "));
@@ -175,6 +195,7 @@ bool DmaPusher::Step() {
}
if (signal_sync) {
+ VideoCommon::GpuSplit::Get().Drain();
rasterizer->SignalFence([this]() {
std::scoped_lock lk(sync_mutex);
synced = true;
@@ -315,10 +336,18 @@ void DmaPusher::WatchArgument(u32 method, u32 argument) const {
}
}
+bool DmaPusher::WantsSegment() const {
+ // Only macro parameters and compute uploads read the engine's current_dma_segment.
+ const auto engine = subchannel_type[dma_state.subchannel];
+ return engine == Engines::EngineTypes::KeplerCompute ||
+ (engine == Engines::EngineTypes::Maxwell3D && dma_state.method >= MacroRegistersStart);
+}
+
void DmaPusher::CallMethod(u32 argument) {
if (g_semaphore_watch != 0) [[unlikely]] {
WatchArgument(dma_state.method, argument);
}
+ auto& split = VideoCommon::GpuSplit::Get();
if (dma_state.method < non_puller_methods) {
puller.CallPullerMethod(*this, Engines::Puller::MethodCall{
dma_state.method,
@@ -332,9 +361,34 @@ void DmaPusher::CallMethod(u32 argument) {
ReportUnboundSubchannel();
return;
}
+ if (split.Active()) {
+ const GPUVAddr segment = dma_state.dma_get + dma_state.dma_word_offset;
+ if (split.FrontMacros()) {
+ const auto type = subchannel_type[dma_state.subchannel];
+ if (type == Engines::EngineTypes::Maxwell3D) {
+ auto* const maxwell3d = static_cast<Engines::Maxwell3D*>(subchannel);
+ if (maxwell3d->GetNativeMacroEngine().native_turing) {
+ maxwell3d->FrontCallMethod(system, split, dma_state.method, argument,
+ dma_state.is_last_call);
+ return;
+ }
+ } else if (type == Engines::EngineTypes::KeplerCompute) {
+ auto* const compute = static_cast<Engines::KeplerCompute*>(subchannel);
+ if (compute->FrontRunsMacros()) {
+ compute->FrontCallMethod(system, split, dma_state.method, argument,
+ dma_state.is_last_call, &segment);
+ return;
+ }
+ }
+ }
+ split.Method(subchannel, dma_state.method, argument, dma_state.is_last_call,
+ WantsSegment() ? &segment : nullptr);
+ return;
+ }
if (!subchannel->execution_mask[dma_state.method]) {
subchannel->method_sink.emplace_back(dma_state.method, argument);
} else {
+ VideoCommon::Nx2Profile::Scope method_scope{VideoCommon::Nx2Profile::Zone::Method};
subchannel->ConsumeSink(system);
subchannel->current_dma_segment = dma_state.dma_get + dma_state.dma_word_offset;
subchannel->CallMethod(system, dma_state.method, argument, dma_state.is_last_call);
@@ -348,6 +402,7 @@ void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) {
WatchArgument(dma_state.method + (dma_state.non_incrementing ? 0 : i), base_start[i]);
}
}
+ auto& split = VideoCommon::GpuSplit::Get();
if (dma_state.method < non_puller_methods) {
puller.CallMultiMethod(*this, dma_state.method, dma_state.subchannel, base_start, num_methods, dma_state.method_count);
} else {
@@ -356,6 +411,31 @@ void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) {
ReportUnboundSubchannel();
return;
}
+ if (split.Active()) {
+ const GPUVAddr segment = dma_state.dma_get + dma_state.dma_word_offset;
+ if (split.FrontMacros()) {
+ const auto type = subchannel_type[dma_state.subchannel];
+ if (type == Engines::EngineTypes::Maxwell3D) {
+ auto* const maxwell3d = static_cast<Engines::Maxwell3D*>(subchannel);
+ if (maxwell3d->GetNativeMacroEngine().native_turing) {
+ maxwell3d->FrontCallMultiMethod(system, split, dma_state.method, base_start,
+ num_methods, dma_state.method_count);
+ return;
+ }
+ } else if (type == Engines::EngineTypes::KeplerCompute) {
+ auto* const compute = static_cast<Engines::KeplerCompute*>(subchannel);
+ if (compute->FrontRunsMacros()) {
+ compute->FrontCallMultiMethod(system, split, dma_state.method, base_start,
+ num_methods, dma_state.method_count, &segment);
+ return;
+ }
+ }
+ }
+ split.MultiMethod(subchannel, dma_state.method, base_start, num_methods,
+ dma_state.method_count, WantsSegment() ? &segment : nullptr);
+ return;
+ }
+ VideoCommon::Nx2Profile::Scope method_scope{VideoCommon::Nx2Profile::Zone::Method};
subchannel->ConsumeSink(system);
subchannel->current_dma_segment = dma_state.dma_get + dma_state.dma_word_offset;
subchannel->CallMultiMethod(system, dma_state.method, base_start, num_methods, dma_state.method_count);