From 635335fc85c4013922c68026e31b7d9ff91f2368 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Wed, 11 Feb 2026 02:04:47 -0400 Subject: [PATCH] [engine, dma] Adjustment of the execution mask handling --- src/video_core/dma_pusher.cpp | 187 ++++++++++++++++++---- src/video_core/dma_pusher.h | 4 +- src/video_core/engines/draw_manager.cpp | 17 +- src/video_core/engines/engine_interface.h | 35 +++- src/video_core/engines/fermi_2d.cpp | 6 +- src/video_core/engines/kepler_compute.cpp | 12 +- src/video_core/engines/kepler_memory.cpp | 9 +- src/video_core/engines/maxwell_3d.cpp | 41 +++-- src/video_core/engines/maxwell_3d.h | 11 +- src/video_core/engines/maxwell_dma.cpp | 6 +- 10 files changed, 263 insertions(+), 65 deletions(-) diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp index 3844a8e2f9..22fedf18ec 100644 --- a/src/video_core/dma_pusher.cpp +++ b/src/video_core/dma_pusher.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project @@ -7,7 +7,11 @@ #include "common/settings.h" #include "core/core.h" #include "video_core/dma_pusher.h" +#include "video_core/engines/fermi_2d.h" +#include "video_core/engines/kepler_compute.h" +#include "video_core/engines/kepler_memory.h" #include "video_core/engines/maxwell_3d.h" +#include "video_core/engines/maxwell_dma.h" #include "video_core/gpu.h" #include "video_core/guest_memory.h" #include "video_core/memory_manager.h" @@ -83,12 +87,41 @@ bool DmaPusher::Step() { } if (header.size > 0) { - if (Settings::IsDMALevelDefault() ? (Settings::IsGPULevelMedium() || Settings::IsGPULevelHigh()) : Settings::IsDMALevelSafe()) { - Tegra::Memory::GpuGuestMemoryheaders(memory_manager, dma_state.dma_get, header.size, &command_headers); - ProcessCommands(headers); + const bool use_safe_read = Settings::IsDMALevelDefault() + ? (Settings::IsGPULevelMedium() || Settings::IsGPULevelHigh()) + : Settings::IsDMALevelSafe(); + constexpr u32 bulk_count = 32; + const size_t total_size = static_cast(header.size); + const size_t total_bytes = total_size * sizeof(CommandHeader); + if (use_safe_read) { + memory_manager.FlushRegion(dma_state.dma_get, total_bytes); + } + + const u8* direct_span = memory_manager.GetSpan(dma_state.dma_get, total_bytes); + if (direct_span) { + const auto* headers = reinterpret_cast(direct_span); + for (u32 offset = 0; offset < header.size; offset += bulk_count) { + const u32 count = (std::min)(bulk_count, header.size - offset); + ProcessCommands(std::span(headers + offset, count), + static_cast(offset) * sizeof(CommandHeader)); + } } else { - Tegra::Memory::GpuGuestMemoryheaders(memory_manager, dma_state.dma_get, header.size, &command_headers); - ProcessCommands(headers); + for (u32 offset = 0; offset < header.size; offset += bulk_count) { + const u32 count = (std::min)(bulk_count, header.size - offset); + command_headers.resize_destructive(count); + const GPUVAddr gpu_addr = + dma_state.dma_get + static_cast(offset) * sizeof(CommandHeader); + if (use_safe_read) { + memory_manager.ReadBlock(gpu_addr, command_headers.data(), + count * sizeof(CommandHeader)); + } else { + memory_manager.ReadBlockUnsafe(gpu_addr, command_headers.data(), + count * sizeof(CommandHeader)); + } + ProcessCommands( + std::span(command_headers.data(), count), + static_cast(offset) * sizeof(CommandHeader)); + } } } @@ -110,51 +143,78 @@ bool DmaPusher::Step() { return true; } -void DmaPusher::ProcessCommands(std::span commands) { +void DmaPusher::ProcessCommands(std::span commands, u64 base_word_offset) { + u32 method = dma_state.method; + u32 method_count = dma_state.method_count; + u32 subchannel = dma_state.subchannel; + u64 dma_word_offset = dma_state.dma_word_offset; + bool non_incrementing = dma_state.non_incrementing; + bool is_last_call = dma_state.is_last_call; + const u64 dma_get = dma_state.dma_get; + + const auto sync_state = [&]() { + dma_state.method = method; + dma_state.method_count = method_count; + dma_state.subchannel = subchannel; + dma_state.dma_word_offset = dma_word_offset; + dma_state.non_incrementing = non_incrementing; + dma_state.is_last_call = is_last_call; + }; + for (size_t index = 0; index < commands.size();) { // Data word of methods command - if (dma_state.method_count && dma_state.non_incrementing) { + if (method_count && non_incrementing) { auto const& command_header = commands[index]; //must ref (MUltiMethod re) - dma_state.dma_word_offset = u32(index * sizeof(u32)); - const u32 max_write = u32(std::min(index + dma_state.method_count, commands.size()) - index); + dma_word_offset = base_word_offset + u32(index * sizeof(u32)); + const u32 max_write = + u32(std::min(index + method_count, commands.size()) - index); + sync_state(); CallMultiMethod(&command_header.argument, max_write); - dma_state.method_count -= max_write; - dma_state.is_last_call = true; + method_count -= max_write; + is_last_call = true; index += max_write; - } else if (dma_state.method_count) { + } else if (method_count) { auto const command_header = commands[index]; //can copy - dma_state.dma_word_offset = u32(index * sizeof(u32)); - dma_state.is_last_call = dma_state.method_count <= 1; + dma_word_offset = base_word_offset + u32(index * sizeof(u32)); + is_last_call = method_count <= 1; + sync_state(); CallMethod(command_header.argument); - dma_state.method += !dma_state.non_incrementing ? 1 : 0; - dma_state.non_incrementing |= dma_increment_once; - dma_state.method_count--; + method += !non_incrementing ? 1 : 0; + non_incrementing |= dma_increment_once; + method_count--; index++; } else { auto const command_header = commands[index]; //can copy // No command active - this is the first word of a new one switch (command_header.mode) { case SubmissionMode::Increasing: - SetState(command_header); - dma_state.non_incrementing = false; + method = command_header.method; + subchannel = command_header.subchannel; + method_count = command_header.method_count; + non_incrementing = false; dma_increment_once = false; break; case SubmissionMode::NonIncreasing: - SetState(command_header); - dma_state.non_incrementing = true; + method = command_header.method; + subchannel = command_header.subchannel; + method_count = command_header.method_count; + non_incrementing = true; dma_increment_once = false; break; case SubmissionMode::Inline: - dma_state.method = command_header.method; - dma_state.subchannel = command_header.subchannel; - dma_state.dma_word_offset = u64(-s64(dma_state.dma_get)); // negate to set address as 0 + method = command_header.method; + subchannel = command_header.subchannel; + dma_word_offset = u64(-s64(dma_get)); // negate to set address as 0 + sync_state(); CallMethod(command_header.arg_count); - dma_state.non_incrementing = true; + non_incrementing = true; dma_increment_once = false; break; case SubmissionMode::IncreaseOnce: - SetState(command_header); - dma_state.non_incrementing = false; + method = command_header.method; + subchannel = command_header.subchannel; + method_count = command_header.method_count; + non_incrementing = false; dma_increment_once = true; break; default: @@ -163,6 +223,8 @@ void DmaPusher::ProcessCommands(std::span commands) { index++; } } + + sync_state(); } void DmaPusher::SetState(const CommandHeader& command_header) { @@ -181,12 +243,45 @@ void DmaPusher::CallMethod(u32 argument) const { }); } else { auto subchannel = subchannels[dma_state.subchannel]; - if (!subchannel->execution_mask[dma_state.method]) { - subchannel->method_sink.emplace_back(dma_state.method, argument); + if (!subchannel) { + return; + } + const u32 method = dma_state.method; + const u32 word_index = method >> 6; + const u64 bit_mask = 1ULL << (method & 63); + const bool is_executable = + word_index < subchannel->execution_mask_words.size() && + (subchannel->execution_mask_words[word_index] & bit_mask) != 0; + if (!is_executable) { + subchannel->method_sink.emplace_back(method, argument); } else { subchannel->ConsumeSink(); subchannel->current_dma_segment = dma_state.dma_get + dma_state.dma_word_offset; - subchannel->CallMethod(dma_state.method, argument, dma_state.is_last_call); + switch (subchannel_type[dma_state.subchannel]) { + case Engines::EngineTypes::Maxwell3D: + static_cast(subchannel)->CallMethod(method, argument, + dma_state.is_last_call); + break; + case Engines::EngineTypes::KeplerCompute: + static_cast(subchannel)->CallMethod( + method, argument, dma_state.is_last_call); + break; + case Engines::EngineTypes::Fermi2D: + static_cast(subchannel)->CallMethod(method, argument, + dma_state.is_last_call); + break; + case Engines::EngineTypes::MaxwellDMA: + static_cast(subchannel)->CallMethod(method, argument, + dma_state.is_last_call); + break; + case Engines::EngineTypes::KeplerMemory: + static_cast(subchannel)->CallMethod( + method, argument, dma_state.is_last_call); + break; + default: + subchannel->CallMethod(method, argument, dma_state.is_last_call); + break; + } } } } @@ -196,9 +291,37 @@ void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) const { puller.CallMultiMethod(dma_state.method, dma_state.subchannel, base_start, num_methods, dma_state.method_count); } else { auto subchannel = subchannels[dma_state.subchannel]; + if (!subchannel) { + return; + } subchannel->ConsumeSink(); subchannel->current_dma_segment = dma_state.dma_get + dma_state.dma_word_offset; - subchannel->CallMultiMethod(dma_state.method, base_start, num_methods, dma_state.method_count); + switch (subchannel_type[dma_state.subchannel]) { + case Engines::EngineTypes::Maxwell3D: + static_cast(subchannel)->CallMultiMethod( + dma_state.method, base_start, num_methods, dma_state.method_count); + break; + case Engines::EngineTypes::KeplerCompute: + static_cast(subchannel)->CallMultiMethod( + dma_state.method, base_start, num_methods, dma_state.method_count); + break; + case Engines::EngineTypes::Fermi2D: + static_cast(subchannel)->CallMultiMethod( + dma_state.method, base_start, num_methods, dma_state.method_count); + break; + case Engines::EngineTypes::MaxwellDMA: + static_cast(subchannel)->CallMultiMethod( + dma_state.method, base_start, num_methods, dma_state.method_count); + break; + case Engines::EngineTypes::KeplerMemory: + static_cast(subchannel)->CallMultiMethod( + dma_state.method, base_start, num_methods, dma_state.method_count); + break; + default: + subchannel->CallMultiMethod(dma_state.method, base_start, num_methods, + dma_state.method_count); + break; + } } } diff --git a/src/video_core/dma_pusher.h b/src/video_core/dma_pusher.h index f850513603..ab96440ec2 100644 --- a/src/video_core/dma_pusher.h +++ b/src/video_core/dma_pusher.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project @@ -148,7 +148,7 @@ private: static constexpr u32 non_puller_methods = 0x40; static constexpr u32 max_subchannels = 8; bool Step(); - void ProcessCommands(std::span commands); + void ProcessCommands(std::span commands, u64 base_word_offset = 0); void SetState(const CommandHeader& command_header); diff --git a/src/video_core/engines/draw_manager.cpp b/src/video_core/engines/draw_manager.cpp index 971025cb55..437f2a346e 100644 --- a/src/video_core/engines/draw_manager.cpp +++ b/src/video_core/engines/draw_manager.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -5,8 +8,16 @@ #include "video_core/dirty_flags.h" #include "video_core/engines/draw_manager.h" #include "video_core/rasterizer_interface.h" +#include "video_core/renderer_vulkan/vk_rasterizer.h" namespace Tegra::Engines { +namespace { +template +inline void DrawFast(RasterizerT* rasterizer, bool draw_indexed, u32 instance_count) { + rasterizer->Draw(draw_indexed, instance_count); +} +} // namespace + DrawManager::DrawManager(Maxwell3D* maxwell3d_) : maxwell3d(maxwell3d_) {} void DrawManager::ProcessMethodCall(u32 method, u32 argument) { @@ -267,7 +278,11 @@ void DrawManager::ProcessDraw(bool draw_indexed, u32 instance_count) { UpdateTopology(); if (maxwell3d->ShouldExecute()) { - maxwell3d->rasterizer->Draw(draw_indexed, instance_count); + if (auto* rasterizer_vulkan = maxwell3d->RasterizerVulkan()) { + DrawFast(rasterizer_vulkan, draw_indexed, instance_count); + } else { + maxwell3d->rasterizer->Draw(draw_indexed, instance_count); + } } } diff --git a/src/video_core/engines/engine_interface.h b/src/video_core/engines/engine_interface.h index e271ecab59..b7e2cc63fe 100644 --- a/src/video_core/engines/engine_interface.h +++ b/src/video_core/engines/engine_interface.h @@ -6,7 +6,7 @@ #pragma once -#include +#include #include #include @@ -26,6 +26,11 @@ class EngineInterface { public: virtual ~EngineInterface() = default; + static constexpr size_t ExecutionMaskBits = (std::numeric_limits::max)(); + static constexpr size_t ExecutionMaskWordBits = 64; + static constexpr size_t ExecutionMaskWords = + (ExecutionMaskBits + ExecutionMaskWordBits - 1) / ExecutionMaskWordBits; + /// Write the value to the register identified by method. virtual void CallMethod(u32 method, u32 method_argument, bool is_last_call) = 0; @@ -40,7 +45,33 @@ public: ConsumeSinkImpl(); } - std::bitset<(std::numeric_limits::max)()> execution_mask{}; + void ClearExecutionMask() { + execution_mask_words.fill(0); + } + + void SetExecutionMaskBit(u32 method, bool value = true) { + if (method >= ExecutionMaskBits) { + return; + } + const size_t word_index = method >> 6; + const u64 bit_mask = 1ULL << (method & 63); + if (value) { + execution_mask_words[word_index] |= bit_mask; + } else { + execution_mask_words[word_index] &= ~bit_mask; + } + } + + bool IsExecutionMaskSet(u32 method) const { + if (method >= ExecutionMaskBits) { + return false; + } + const size_t word_index = method >> 6; + const u64 bit_mask = 1ULL << (method & 63); + return (execution_mask_words[word_index] & bit_mask) != 0; + } + + std::array execution_mask_words{}; std::vector> method_sink{}; bool current_dirty{}; GPUVAddr current_dma_segment; diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index 17fbe9961c..055edc9cbf 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project @@ -26,8 +26,8 @@ Fermi2D::Fermi2D(MemoryManager& memory_manager_) : memory_manager{memory_manager regs.src.depth = 1; regs.dst.depth = 1; - execution_mask.reset(); - execution_mask[FERMI2D_REG_INDEX(pixels_from_memory.src_y0) + 1] = true; + ClearExecutionMask(); + SetExecutionMaskBit(FERMI2D_REG_INDEX(pixels_from_memory.src_y0) + 1); } Fermi2D::~Fermi2D() = default; diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp index cd61ab222b..67c62523a3 100644 --- a/src/video_core/engines/kepler_compute.cpp +++ b/src/video_core/engines/kepler_compute.cpp @@ -1,7 +1,9 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" @@ -15,10 +17,10 @@ namespace Tegra::Engines { KeplerCompute::KeplerCompute(Core::System& system_, MemoryManager& memory_manager_) : system{system_}, memory_manager{memory_manager_}, upload_state{memory_manager, regs.upload} { - execution_mask.reset(); - execution_mask[KEPLER_COMPUTE_REG_INDEX(exec_upload)] = true; - execution_mask[KEPLER_COMPUTE_REG_INDEX(data_upload)] = true; - execution_mask[KEPLER_COMPUTE_REG_INDEX(launch)] = true; + ClearExecutionMask(); + SetExecutionMaskBit(KEPLER_COMPUTE_REG_INDEX(exec_upload)); + SetExecutionMaskBit(KEPLER_COMPUTE_REG_INDEX(data_upload)); + SetExecutionMaskBit(KEPLER_COMPUTE_REG_INDEX(launch)); } KeplerCompute::~KeplerCompute() = default; diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp index c026801a35..1f47ab0e7c 100644 --- a/src/video_core/engines/kepler_memory.cpp +++ b/src/video_core/engines/kepler_memory.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -19,9 +22,9 @@ KeplerMemory::~KeplerMemory() = default; void KeplerMemory::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) { upload_state.BindRasterizer(rasterizer_); - execution_mask.reset(); - execution_mask[KEPLERMEMORY_REG_INDEX(exec)] = true; - execution_mask[KEPLERMEMORY_REG_INDEX(data)] = true; + ClearExecutionMask(); + SetExecutionMaskBit(KEPLERMEMORY_REG_INDEX(exec)); + SetExecutionMaskBit(KEPLERMEMORY_REG_INDEX(data)); } void KeplerMemory::ConsumeSinkImpl() { diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 7dbb8f6617..4ae2618ccf 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project @@ -18,6 +18,7 @@ #include "video_core/gpu.h" #include "video_core/memory_manager.h" #include "video_core/rasterizer_interface.h" +#include "video_core/renderer_vulkan/vk_rasterizer.h" #include "video_core/textures/texture.h" namespace Tegra::Engines { @@ -30,15 +31,23 @@ Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_) memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)}, upload_state{memory_manager, regs.upload} { dirty.flags.flip(); InitializeRegisterDefaults(); - execution_mask.reset(); - for (size_t i = 0; i < execution_mask.size(); i++) - execution_mask[i] = IsMethodExecutable(u32(i)); + ClearExecutionMask(); + for (size_t i = 0; i < ExecutionMaskBits; ++i) { + if (IsMethodExecutable(u32(i))) { + SetExecutionMaskBit(u32(i)); + } + } } Maxwell3D::~Maxwell3D() = default; void Maxwell3D::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) { rasterizer = rasterizer_; + if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::Vulkan) { + rasterizer_vulkan = static_cast(rasterizer_); + } else { + rasterizer_vulkan = nullptr; + } upload_state.BindRasterizer(rasterizer_); } @@ -292,31 +301,37 @@ u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) { void Maxwell3D::ConsumeSinkImpl() { const auto control = shadow_state.shadow_ram_control; + DirtyState::Flags pending_flags{}; if (control == Regs::ShadowRamControl::Track || control == Regs::ShadowRamControl::TrackWithFilter) { for (auto [method, value] : method_sink) { shadow_state.reg_array[method] = value; - ProcessDirtyRegisters(method, value); + ProcessDirtyRegisters(method, value, &pending_flags); } } else if (control == Regs::ShadowRamControl::Replay) { - for (auto [method, value] : method_sink) - ProcessDirtyRegisters(method, shadow_state.reg_array[method]); + for (auto [method, value] : method_sink) { + ProcessDirtyRegisters(method, shadow_state.reg_array[method], &pending_flags); + } } else { - for (auto [method, value] : method_sink) - ProcessDirtyRegisters(method, value); + for (auto [method, value] : method_sink) { + ProcessDirtyRegisters(method, value, &pending_flags); + } } + dirty.flags |= pending_flags; method_sink.clear(); } -void Maxwell3D::ProcessDirtyRegisters(u32 method, u32 argument) { +void Maxwell3D::ProcessDirtyRegisters(u32 method, u32 argument, DirtyState::Flags* pending_flags) { if (regs.reg_array[method] != argument) { regs.reg_array[method] = argument; auto const& table0 = dirty.tables[0]; auto const& table1 = dirty.tables[1]; u8 const flag0 = table0[method]; u8 const flag1 = table1[method]; - dirty.flags[flag0] = true; - if (flag1 != flag0) - dirty.flags[flag1] = true; + auto& target_flags = pending_flags ? *pending_flags : dirty.flags; + target_flags.set(flag0); + if (flag1 != flag0) { + target_flags.set(flag1); + } } } diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 5312c04b6f..eddf3725b0 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -38,6 +38,10 @@ namespace VideoCore { class RasterizerInterface; } +namespace Vulkan { +class RasterizerVulkan; +} + namespace Tegra::Engines { class DrawManager; @@ -3093,6 +3097,10 @@ public: return *rasterizer; } + Vulkan::RasterizerVulkan* RasterizerVulkan() const { + return rasterizer_vulkan; + } + struct DirtyState { using Flags = std::bitset<(std::numeric_limits::max)()>; using Table = std::array; @@ -3141,7 +3149,7 @@ private: u32 ProcessShadowRam(u32 method, u32 argument); - void ProcessDirtyRegisters(u32 method, u32 argument); + void ProcessDirtyRegisters(u32 method, u32 argument, DirtyState::Flags* pending_flags = nullptr); void ConsumeSinkImpl() override; @@ -3193,6 +3201,7 @@ private: MemoryManager& memory_manager; VideoCore::RasterizerInterface* rasterizer = nullptr; + Vulkan::RasterizerVulkan* rasterizer_vulkan = nullptr; /// Start offsets of each macro in macro_memory std::array macro_positions{}; diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index 747759bf41..12bba12a22 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project @@ -23,8 +23,8 @@ using namespace Texture; MaxwellDMA::MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_) : system{system_}, memory_manager{memory_manager_} { - execution_mask.reset(); - execution_mask[offsetof(Regs, launch_dma) / sizeof(u32)] = true; + ClearExecutionMask(); + SetExecutionMaskBit(offsetof(Regs, launch_dma) / sizeof(u32)); } MaxwellDMA::~MaxwellDMA() = default;