aboutsummaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
authorlizzie <lizzie@eden-emu.dev>2026-06-23 06:31:25 +0200
committercrueter <crueter@eden-emu.dev>2026-06-23 06:31:25 +0200
commit3aa0d462598beb2021308eee1d757d74fe33b312 (patch)
treeed425c3845ba8fa61184d97b0588cb049b518bd7 /src/video_core
parentf8facda35fe7f17143f84bbfbdacc4cc48678946 (diff)
[video_core, hle] remove redundant parent references in system structs (#3908)
reworked a bit to remove references of parent objects and instead pass as arguments to methods to prevent useless reloads Signed-off-by: lizzie <lizzie@eden-emu.dev> Co-authored-by: maufeat <sahyno1996@gmail.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3908 Reviewed-by: Maufeat <sahyno1996@gmail.com> Reviewed-by: crueter <crueter@eden-emu.dev>
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/cdma_pusher.cpp5
-rw-r--r--src/video_core/control/channel_state.cpp36
-rw-r--r--src/video_core/control/channel_state.h38
-rw-r--r--src/video_core/control/channel_state_cache.cpp10
-rw-r--r--src/video_core/control/channel_state_cache.inc5
-rw-r--r--src/video_core/control/scheduler.cpp11
-rw-r--r--src/video_core/control/scheduler.h6
-rw-r--r--src/video_core/dma_pusher.cpp46
-rw-r--r--src/video_core/dma_pusher.h55
-rw-r--r--src/video_core/engines/engine_interface.h23
-rw-r--r--src/video_core/engines/fermi_2d.cpp14
-rw-r--r--src/video_core/engines/fermi_2d.h10
-rw-r--r--src/video_core/engines/kepler_compute.cpp18
-rw-r--r--src/video_core/engines/kepler_compute.h13
-rw-r--r--src/video_core/engines/kepler_memory.cpp17
-rw-r--r--src/video_core/engines/kepler_memory.h14
-rw-r--r--src/video_core/engines/maxwell_3d.cpp31
-rw-r--r--src/video_core/engines/maxwell_3d.h16
-rw-r--r--src/video_core/engines/maxwell_dma.cpp17
-rw-r--r--src/video_core/engines/maxwell_dma.h14
-rw-r--r--src/video_core/engines/nv01_timer.h13
-rw-r--r--src/video_core/engines/puller.cpp139
-rw-r--r--src/video_core/engines/puller.h46
-rw-r--r--src/video_core/gpu.cpp182
-rw-r--r--src/video_core/gpu_thread.cpp28
-rw-r--r--src/video_core/gpu_thread.h15
-rw-r--r--src/video_core/host1x/control.cpp14
-rw-r--r--src/video_core/host1x/control.h13
-rw-r--r--src/video_core/host1x/host1x.cpp8
-rw-r--r--src/video_core/host1x/host1x.h138
-rw-r--r--src/video_core/host1x/vic.cpp20
-rw-r--r--src/video_core/host1x/vic.h107
-rw-r--r--src/video_core/macro.cpp338
-rw-r--r--src/video_core/macro.h50
-rw-r--r--src/video_core/renderer_opengl/gl_state_tracker.cpp7
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp4
-rw-r--r--src/video_core/renderer_vulkan/pipeline_statistics.cpp9
-rw-r--r--src/video_core/renderer_vulkan/pipeline_statistics.h9
-rw-r--r--src/video_core/renderer_vulkan/present/anti_alias_pass.h4
-rw-r--r--src/video_core/renderer_vulkan/present/fsr.cpp92
-rw-r--r--src/video_core/renderer_vulkan/present/fsr.h31
-rw-r--r--src/video_core/renderer_vulkan/present/fxaa.cpp87
-rw-r--r--src/video_core/renderer_vulkan/present/fxaa.h54
-rw-r--r--src/video_core/renderer_vulkan/present/layer.cpp71
-rw-r--r--src/video_core/renderer_vulkan/present/layer.h22
-rw-r--r--src/video_core/renderer_vulkan/present/sgsr.cpp37
-rw-r--r--src/video_core/renderer_vulkan/present/sgsr.h9
-rw-r--r--src/video_core/renderer_vulkan/present/smaa.cpp101
-rw-r--r--src/video_core/renderer_vulkan/present/smaa.h33
-rw-r--r--src/video_core/renderer_vulkan/present/window_adapt_pass.cpp34
-rw-r--r--src/video_core/renderer_vulkan/present/window_adapt_pass.h17
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp10
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp39
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h14
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp18
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp8
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_descriptor_pool.cpp23
-rw-r--r--src/video_core/renderer_vulkan/vk_descriptor_pool.h16
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp64
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_update_descriptor.h20
-rw-r--r--src/video_core/video_core.cpp8
-rw-r--r--src/video_core/video_core.h8
68 files changed, 1101 insertions, 1276 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 53b0d1638b..5c02b5ed90 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -334,7 +334,7 @@ if (YUZU_USE_EXTERNAL_FFMPEG)
add_dependencies(video_core ffmpeg-build)
endif()
-target_include_directories(video_core PRIVATE ${FFmpeg_INCLUDE_DIR})
+target_include_directories(video_core PUBLIC ${FFmpeg_INCLUDE_DIR})
target_link_libraries(video_core PRIVATE ${FFmpeg_LIBRARIES})
target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS})
diff --git a/src/video_core/cdma_pusher.cpp b/src/video_core/cdma_pusher.cpp
index 1f0f8b5a38..635ca769d8 100644
--- a/src/video_core/cdma_pusher.cpp
+++ b/src/video_core/cdma_pusher.cpp
@@ -20,8 +20,7 @@
namespace Tegra {
CDmaPusher::CDmaPusher(Host1x::Host1x& host1x_, s32 id)
- : host_processor(host1x_)
- , host1x{host1x_}
+ : host1x{host1x_}
, current_class{ChClassId(id)}
{
thread = std::jthread([this](std::stop_token stop_token) {
@@ -99,7 +98,7 @@ void CDmaPusher::ExecuteCommand(u32 method, u32 arg) {
switch (current_class) {
case ChClassId::Control:
LOG_TRACE(Service_NVDRV, "Class {} method {:#X} arg 0x{:X}", u32(current_class), method, arg);
- host_processor.ProcessMethod(Host1x::Control::Method(method), arg);
+ host_processor.ProcessMethod(host1x, Host1x::Control::Method(method), arg);
break;
default:
thi_regs.reg_array[method] = arg;
diff --git a/src/video_core/control/channel_state.cpp b/src/video_core/control/channel_state.cpp
index d07c7e2a83..c6f2c3c2ca 100644
--- a/src/video_core/control/channel_state.cpp
+++ b/src/video_core/control/channel_state.cpp
@@ -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(memory_manager)
+ , fermi_2d(memory_manager)
+ , kepler_compute(memory_manager)
+ , maxwell_dma(memory_manager)
+ , kepler_memory(memory_manager)
+ , nv01_timer(memory_manager)
+ , dma_pusher(system, memory_manager, channel_state)
+{}
-void ChannelState::Init(Core::System& system, GPU& gpu, u64 program_id_) {
+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, gpu, *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
diff --git a/src/video_core/control/channel_state.h b/src/video_core/control/channel_state.h
index 2984d2e09e..80811c1458 100644
--- a/src/video_core/control/channel_state.h
+++ b/src/video_core/control/channel_state.h
@@ -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 {
@@ -34,28 +35,33 @@ namespace Control {
struct ChannelState {
explicit ChannelState(s32 bind_id);
- void Init(Core::System& system, GPU& gpu, u64 program_id);
+ void Init(Core::System& system, u64 program_id);
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
diff --git a/src/video_core/control/channel_state_cache.cpp b/src/video_core/control/channel_state_cache.cpp
index f8c6a762d2..bd794d939a 100644
--- a/src/video_core/control/channel_state_cache.cpp
+++ b/src/video_core/control/channel_state_cache.cpp
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
@@ -6,8 +9,11 @@
namespace VideoCommon {
ChannelInfo::ChannelInfo(Tegra::Control::ChannelState& channel_state)
- : maxwell3d{*channel_state.maxwell_3d}, kepler_compute{*channel_state.kepler_compute},
- gpu_memory{*channel_state.memory_manager}, program_id{channel_state.program_id} {}
+ : maxwell3d{channel_state.payload->maxwell_3d}
+ , kepler_compute{channel_state.payload->kepler_compute}
+ , gpu_memory{*channel_state.memory_manager}
+ , program_id{channel_state.program_id}
+ {}
template class VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo>;
diff --git a/src/video_core/control/channel_state_cache.inc b/src/video_core/control/channel_state_cache.inc
index d882d8222f..5bb15f8907 100644
--- a/src/video_core/control/channel_state_cache.inc
+++ b/src/video_core/control/channel_state_cache.inc
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
@@ -41,7 +44,7 @@ void ChannelSetupCaches<P>::CreateChannel(struct Tegra::Control::ChannelState& c
AddressSpaceRef new_gpu_mem_ref{
.ref_count = 1,
.storage_id = address_spaces.size(),
- .gpu_memory = channel.memory_manager.get(),
+ .gpu_memory = channel.memory_manager,
};
address_spaces.emplace(channel.memory_manager->GetID(), new_gpu_mem_ref);
OnGPUASRegister(channel.memory_manager->GetID());
diff --git a/src/video_core/control/scheduler.cpp b/src/video_core/control/scheduler.cpp
index bd3b8b860e..8af13e415c 100644
--- a/src/video_core/control/scheduler.cpp
+++ b/src/video_core/control/scheduler.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: 2021 yuzu Emulator Project
@@ -12,11 +12,8 @@
#include "video_core/gpu.h"
namespace Tegra::Control {
-Scheduler::Scheduler(GPU& gpu_) : gpu{gpu_} {}
-Scheduler::~Scheduler() = default;
-
-void Scheduler::Push(s32 channel, CommandList&& entries) {
+void Scheduler::Push(GPU& gpu, s32 channel, CommandList&& entries) {
std::shared_ptr<ChannelState> channel_state;
{
std::unique_lock lk(scheduling_guard);
@@ -27,8 +24,8 @@ void Scheduler::Push(s32 channel, CommandList&& entries) {
}
// Process commands outside the lock to reduce contention.
// Multiple channels can prepare their commands in parallel.
- channel_state->dma_pusher->Push(std::move(entries));
- channel_state->dma_pusher->DispatchCalls();
+ channel_state->payload->dma_pusher.Push(std::move(entries));
+ channel_state->payload->dma_pusher.DispatchCalls();
}
void Scheduler::DeclareChannel(std::shared_ptr<ChannelState> new_channel) {
diff --git a/src/video_core/control/scheduler.h b/src/video_core/control/scheduler.h
index 9c2b9de32b..fb9c583386 100644
--- a/src/video_core/control/scheduler.h
+++ b/src/video_core/control/scheduler.h
@@ -22,17 +22,13 @@ struct ChannelState;
class Scheduler {
public:
- explicit Scheduler(GPU& gpu_);
- ~Scheduler();
-
- void Push(s32 channel, CommandList&& entries);
+ void Push(GPU& gpu, s32 channel, CommandList&& entries);
void DeclareChannel(std::shared_ptr<ChannelState> new_channel);
private:
ankerl::unordered_dense::map<s32, std::shared_ptr<ChannelState>> channels;
std::mutex scheduling_guard;
- GPU& gpu;
};
} // namespace Control
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp
index 8a7798e035..41bb43f0c1 100644
--- a/src/video_core/dma_pusher.cpp
+++ b/src/video_core/dma_pusher.cpp
@@ -12,37 +12,32 @@
#include "video_core/guest_memory.h"
#include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h"
-#include "video_core/texture_cache/util.h"
-
-#ifdef _MSC_VER
-#include <intrin.h>
-#endif
namespace Tegra {
constexpr u32 MacroRegistersStart = 0xE00;
[[maybe_unused]] constexpr u32 ComputeInline = 0x6D;
-DmaPusher::DmaPusher(Core::System& system_, GPU& gpu_, MemoryManager& memory_manager_,
- Control::ChannelState& channel_state_)
- : gpu{gpu_}, system{system_}, memory_manager{memory_manager_}, puller{gpu_, memory_manager_,
- *this, channel_state_}, signal_sync{false}, synced{true} {}
+DmaPusher::DmaPusher(Core::System& system_, MemoryManager& memory_manager_, Control::ChannelState& channel_state_)
+ : system{system_}
+ , memory_manager{memory_manager_}
+ , channel_state{channel_state_}
+ , signal_sync{false}
+ , synced{false}
+{}
DmaPusher::~DmaPusher() = default;
void DmaPusher::DispatchCalls() {
-
dma_pushbuffer_subindex = 0;
-
dma_state.is_last_call = true;
-
while (system.IsPoweredOn()) {
if (!Step()) {
break;
}
}
- gpu.FlushCommands();
- gpu.OnCommandListEnd();
+ system.GPU().FlushCommands();
+ system.GPU().OnCommandListEnd();
}
bool DmaPusher::Step() {
@@ -171,9 +166,9 @@ void DmaPusher::SetState(const CommandHeader& command_header) {
dma_state.method_count = command_header.method_count;
}
-void DmaPusher::CallMethod(u32 argument) const {
+void DmaPusher::CallMethod(u32 argument) {
if (dma_state.method < non_puller_methods) {
- puller.CallPullerMethod(Engines::Puller::MethodCall{
+ puller.CallPullerMethod(*this, Engines::Puller::MethodCall{
dma_state.method,
argument,
dma_state.subchannel,
@@ -181,30 +176,29 @@ void DmaPusher::CallMethod(u32 argument) const {
});
} else {
auto subchannel = subchannels[dma_state.subchannel];
- if (subchannel->execution_mask[dma_state.method]) {
- 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);
- } else {
+ if (!subchannel->execution_mask[dma_state.method]) {
subchannel->method_sink.emplace_back(dma_state.method, argument);
+ } else {
+ 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);
}
}
}
-void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) const {
+void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) {
if (dma_state.method < non_puller_methods) {
- puller.CallMultiMethod(dma_state.method, dma_state.subchannel, base_start, num_methods, dma_state.method_count);
+ puller.CallMultiMethod(*this, dma_state.method, dma_state.subchannel, base_start, num_methods, dma_state.method_count);
} else {
auto subchannel = subchannels[dma_state.subchannel];
- subchannel->ConsumeSink();
+ subchannel->ConsumeSink(system);
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);
+ subchannel->CallMultiMethod(system, dma_state.method, base_start, num_methods, dma_state.method_count);
}
}
void DmaPusher::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
rasterizer = rasterizer_;
- puller.BindRasterizer(rasterizer);
}
} // namespace Tegra
diff --git a/src/video_core/dma_pusher.h b/src/video_core/dma_pusher.h
index f850513603..62af628511 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
@@ -109,25 +109,21 @@ inline CommandHeader BuildCommandHeader(BufferMethods method, u32 arg_count, Sub
struct CommandList final {
CommandList() = default;
explicit CommandList(std::size_t size) : command_lists(size) {}
- explicit CommandList(
- boost::container::small_vector<CommandHeader, 512>&& prefetch_command_list_)
+ explicit CommandList(boost::container::small_vector<CommandHeader, 512>&& prefetch_command_list_)
: prefetch_command_list{std::move(prefetch_command_list_)} {}
boost::container::small_vector<CommandListHeader, 512> command_lists;
boost::container::small_vector<CommandHeader, 512> prefetch_command_list;
};
-/**
- * The DmaPusher class implements DMA submission to FIFOs, providing an area of memory that the
- * emulated app fills with commands and tells PFIFO to process. The pushbuffers are then assembled
- * into a "command stream" consisting of 32-bit words that make up "commands".
- * See https://envytools.readthedocs.io/en/latest/hw/fifo/dma-pusher.html#fifo-dma-pusher for
- * details on this implementation.
- */
+/// @brief The DmaPusher class implements DMA submission to FIFOs, providing an area of memory that the
+/// emulated app fills with commands and tells PFIFO to process. The pushbuffers are then assembled
+/// into a "command stream" consisting of 32-bit words that make up "commands".
+/// See https://envytools.readthedocs.io/en/latest/hw/fifo/dma-pusher.html#fifo-dma-pusher for
+/// details on this implementation.
class DmaPusher final {
public:
- explicit DmaPusher(Core::System& system_, GPU& gpu_, MemoryManager& memory_manager_,
- Control::ChannelState& channel_state_);
+ explicit DmaPusher(Core::System& system_, MemoryManager& memory_manager_, Control::ChannelState& channel_state_);
~DmaPusher();
void Push(CommandList&& entries) {
@@ -136,8 +132,7 @@ public:
void DispatchCalls();
- void BindSubchannel(Engines::EngineInterface* engine, u32 subchannel_id,
- Engines::EngineTypes engine_type) {
+ void BindSubchannel(Engines::EngineInterface* engine, u32 subchannel_id, Engines::EngineTypes engine_type) {
subchannels[subchannel_id] = engine;
subchannel_type[subchannel_id] = engine_type;
}
@@ -152,11 +147,11 @@ private:
void SetState(const CommandHeader& command_header);
- void CallMethod(u32 argument) const;
- void CallMultiMethod(const u32* base_start, u32 num_methods) const;
+ void CallMethod(u32 argument);
+ void CallMultiMethod(const u32* base_start, u32 num_methods);
- Common::ScratchBuffer<CommandHeader>
- command_headers; ///< Buffer for list of commands fetched at once
+public:
+ Common::ScratchBuffer<CommandHeader> command_headers; ///< Buffer for list of commands fetched at once
std::queue<CommandList> dma_pushbuffer; ///< Queue of command lists to be processed
std::size_t dma_pushbuffer_subindex{}; ///< Index within a command list within the pushbuffer
@@ -172,24 +167,24 @@ private:
bool is_last_call;
};
- DmaState dma_state{};
- bool dma_increment_once{};
-
- const bool ib_enable{true}; ///< IB mode enabled
+ Core::System& system;
+ MemoryManager& memory_manager;
+ Control::ChannelState& channel_state;
+ DmaState dma_state{};
std::array<Engines::EngineInterface*, max_subchannels> subchannels{};
std::array<Engines::EngineTypes, max_subchannels> subchannel_type;
- GPU& gpu;
- Core::System& system;
- MemoryManager& memory_manager;
- mutable Engines::Puller puller;
-
- VideoCore::RasterizerInterface* rasterizer;
- bool signal_sync;
- bool synced;
+ Engines::Puller puller;
std::mutex sync_mutex;
std::condition_variable sync_cv;
+
+ VideoCore::RasterizerInterface* rasterizer = nullptr;
+
+ const bool ib_enable : 1 = true; ///< IB mode enabled
+ bool dma_increment_once : 1 = false;
+ bool signal_sync : 1 = false;
+ bool synced : 1 = false;
};
} // namespace Tegra
diff --git a/src/video_core/engines/engine_interface.h b/src/video_core/engines/engine_interface.h
index bf3bd66aca..83dbf13059 100644
--- a/src/video_core/engines/engine_interface.h
+++ b/src/video_core/engines/engine_interface.h
@@ -12,6 +12,10 @@
#include "common/common_types.h"
+namespace Core {
+class System;
+}
+
namespace Tegra::Engines {
enum class EngineTypes : u32 {
@@ -28,28 +32,25 @@ public:
virtual ~EngineInterface() = default;
/// Write the value to the register identified by method.
- virtual void CallMethod(u32 method, u32 method_argument, bool is_last_call) = 0;
+ virtual void CallMethod(Core::System& system, u32 method, u32 method_argument, bool is_last_call) = 0;
/// Write multiple values to the register identified by method.
- virtual void CallMultiMethod(u32 method, const u32* base_start, u32 amount,
- u32 methods_pending) = 0;
+ virtual void CallMultiMethod(Core::System& system, u32 method, const u32* base_start, u32 amount, u32 methods_pending) = 0;
- void ConsumeSink() {
- if (method_sink.empty()) {
- return;
+ void ConsumeSink(Core::System& system) {
+ if (!method_sink.empty()) {
+ ConsumeSinkImpl(system);
}
- ConsumeSinkImpl();
}
std::bitset<(std::numeric_limits<u16>::max)()> execution_mask{};
std::vector<std::pair<u32, u32>> method_sink{};
- bool current_dirty{};
GPUVAddr current_dma_segment;
-
+ bool current_dirty{};
protected:
- virtual void ConsumeSinkImpl() {
+ virtual void ConsumeSinkImpl(Core::System& system) {
for (auto [method, value] : method_sink) {
- CallMethod(method, value, true);
+ CallMethod(system, method, value, true);
}
method_sink.clear();
}
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp
index b442c5cc76..8b02c91e03 100644
--- a/src/video_core/engines/fermi_2d.cpp
+++ b/src/video_core/engines/fermi_2d.cpp
@@ -36,9 +36,8 @@ void Fermi2D::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
rasterizer = rasterizer_;
}
-void Fermi2D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
- ASSERT_MSG(method < Regs::NUM_REGS,
- "Invalid Fermi2D register, increase the size of the Regs structure");
+void Fermi2D::CallMethod(Core::System& system, u32 method, u32 method_argument, bool is_last_call) {
+ ASSERT_MSG(method < Regs::NUM_REGS, "Invalid Fermi2D register, increase the size of the Regs structure");
regs.reg_array[method] = method_argument;
if (method == FERMI2D_REG_INDEX(pixels_from_memory.src_y0) + 1) {
@@ -46,13 +45,13 @@ void Fermi2D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
}
}
-void Fermi2D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, u32 methods_pending) {
+void Fermi2D::CallMultiMethod(Core::System& system, u32 method, const u32* base_start, u32 amount, u32 methods_pending) {
for (u32 i = 0; i < amount; ++i) {
- CallMethod(method, base_start[i], methods_pending - i <= 1);
+ CallMethod(system, method, base_start[i], methods_pending - i <= 1);
}
}
-void Fermi2D::ConsumeSinkImpl() {
+void Fermi2D::ConsumeSinkImpl(Core::System& system) {
for (auto [method, value] : method_sink) {
regs.reg_array[method] = value;
}
@@ -60,8 +59,7 @@ void Fermi2D::ConsumeSinkImpl() {
}
void Fermi2D::Blit() {
- LOG_DEBUG(HW_GPU, "called. source address=0x{:x}, destination address=0x{:x}",
- regs.src.Address(), regs.dst.Address());
+ LOG_DEBUG(HW_GPU, "called. source address=0x{:x}, destination address=0x{:x}", regs.src.Address(), regs.dst.Address());
UNIMPLEMENTED_IF_MSG(regs.operation != Operation::SrcCopy, "Operation is not copy");
UNIMPLEMENTED_IF_MSG(regs.src.layer != 0, "Source layer is not zero");
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h
index 705b323e15..7fddf9fdc1 100644
--- a/src/video_core/engines/fermi_2d.h
+++ b/src/video_core/engines/fermi_2d.h
@@ -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
@@ -44,11 +47,10 @@ public:
void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
/// Write the value to the register identified by method.
- void CallMethod(u32 method, u32 method_argument, bool is_last_call) override;
+ void CallMethod(Core::System& system, u32 method, u32 method_argument, bool is_last_call) override;
/// Write multiple values to the register identified by method.
- void CallMultiMethod(u32 method, const u32* base_start, u32 amount,
- u32 methods_pending) override;
+ void CallMultiMethod(Core::System& system, u32 method, const u32* base_start, u32 amount, u32 methods_pending) override;
enum class Origin : u32 {
Center = 0,
@@ -311,7 +313,7 @@ private:
/// registers.
void Blit();
- void ConsumeSinkImpl() override;
+ void ConsumeSinkImpl(Core::System& system) override;
};
#define ASSERT_REG_POSITION(field_name, position) \
diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp
index 7b4efeb1e0..1ef6e0fc0d 100644
--- a/src/video_core/engines/kepler_compute.cpp
+++ b/src/video_core/engines/kepler_compute.cpp
@@ -16,8 +16,10 @@
namespace Tegra::Engines {
-KeplerCompute::KeplerCompute(Core::System& system_, MemoryManager& memory_manager_)
- : system{system_}, memory_manager{memory_manager_}, upload_state{memory_manager, regs.upload} {
+KeplerCompute::KeplerCompute(MemoryManager& memory_manager_)
+ : 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;
@@ -31,16 +33,15 @@ void KeplerCompute::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_)
upload_state.BindRasterizer(rasterizer);
}
-void KeplerCompute::ConsumeSinkImpl() {
+void KeplerCompute::ConsumeSinkImpl(Core::System& system) {
for (auto [method, value] : method_sink) {
regs.reg_array[method] = value;
}
method_sink.clear();
}
-void KeplerCompute::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
- ASSERT_MSG(method < Regs::NUM_REGS,
- "Invalid KeplerCompute register, increase the size of the Regs structure");
+void KeplerCompute::CallMethod(Core::System& system, u32 method, u32 method_argument, bool is_last_call) {
+ ASSERT_MSG(method < Regs::NUM_REGS, "Invalid KeplerCompute register, increase the size of the Regs structure");
regs.reg_array[method] = method_argument;
@@ -78,8 +79,7 @@ void KeplerCompute::CallMethod(u32 method, u32 method_argument, bool is_last_cal
}
}
-void KeplerCompute::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
- u32 methods_pending) {
+void KeplerCompute::CallMultiMethod(Core::System& system, u32 method, const u32* base_start, u32 amount, u32 methods_pending) {
switch (method) {
case KEPLER_COMPUTE_REG_INDEX(data_upload):
upload_address = current_dma_segment;
@@ -87,7 +87,7 @@ void KeplerCompute::CallMultiMethod(u32 method, const u32* base_start, u32 amoun
return;
default:
for (u32 i = 0; i < amount; i++) {
- CallMethod(method, base_start[i], methods_pending - i <= 1);
+ CallMethod(system, method, base_start[i], methods_pending - i <= 1);
}
break;
}
diff --git a/src/video_core/engines/kepler_compute.h b/src/video_core/engines/kepler_compute.h
index 735e05fb43..4f7242f804 100644
--- a/src/video_core/engines/kepler_compute.h
+++ b/src/video_core/engines/kepler_compute.h
@@ -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
@@ -42,7 +45,7 @@ namespace Tegra::Engines {
class KeplerCompute final : public EngineInterface {
public:
- explicit KeplerCompute(Core::System& system, MemoryManager& memory_manager);
+ explicit KeplerCompute(MemoryManager& memory_manager);
~KeplerCompute();
/// Binds a rasterizer to this engine.
@@ -199,11 +202,10 @@ public:
"KeplerCompute LaunchParams has wrong size");
/// Write the value to the register identified by method.
- void CallMethod(u32 method, u32 method_argument, bool is_last_call) override;
+ void CallMethod(Core::System& system, u32 method, u32 method_argument, bool is_last_call) override;
/// Write multiple values to the register identified by method.
- void CallMultiMethod(u32 method, const u32* base_start, u32 amount,
- u32 methods_pending) override;
+ void CallMultiMethod(Core::System& system, u32 method, const u32* base_start, u32 amount, u32 methods_pending) override;
std::optional<GPUVAddr> GetIndirectComputeAddress() const {
return indirect_compute;
@@ -212,7 +214,7 @@ public:
private:
void ProcessLaunch();
- void ConsumeSinkImpl() override;
+ void ConsumeSinkImpl(Core::System& system) override;
/// Retrieves information about a specific TIC entry from the TIC buffer.
Texture::TICEntry GetTICEntry(u32 tic_index) const;
@@ -220,7 +222,6 @@ private:
/// Retrieves information about a specific TSC entry from the TSC buffer.
Texture::TSCEntry GetTSCEntry(u32 tsc_index) const;
- Core::System& system;
MemoryManager& memory_manager;
VideoCore::RasterizerInterface* rasterizer = nullptr;
Upload::State upload_state;
diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp
index 5d4c4720d3..3af5f91271 100644
--- a/src/video_core/engines/kepler_memory.cpp
+++ b/src/video_core/engines/kepler_memory.cpp
@@ -14,8 +14,9 @@
namespace Tegra::Engines {
-KeplerMemory::KeplerMemory(Core::System& system_, MemoryManager& memory_manager)
- : system{system_}, upload_state{memory_manager, regs.upload} {}
+KeplerMemory::KeplerMemory(MemoryManager& memory_manager)
+ : upload_state{memory_manager, regs.upload}
+{}
KeplerMemory::~KeplerMemory() = default;
@@ -27,16 +28,15 @@ void KeplerMemory::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
execution_mask[KEPLERMEMORY_REG_INDEX(data)] = true;
}
-void KeplerMemory::ConsumeSinkImpl() {
+void KeplerMemory::ConsumeSinkImpl(Core::System& system) {
for (auto [method, value] : method_sink) {
regs.reg_array[method] = value;
}
method_sink.clear();
}
-void KeplerMemory::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
- ASSERT_MSG(method < Regs::NUM_REGS,
- "Invalid KeplerMemory register, increase the size of the Regs structure");
+void KeplerMemory::CallMethod(Core::System& system, u32 method, u32 method_argument, bool is_last_call) {
+ ASSERT_MSG(method < Regs::NUM_REGS, "Invalid KeplerMemory register, increase the size of the Regs structure");
regs.reg_array[method] = method_argument;
@@ -52,15 +52,14 @@ void KeplerMemory::CallMethod(u32 method, u32 method_argument, bool is_last_call
}
}
-void KeplerMemory::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
- u32 methods_pending) {
+void KeplerMemory::CallMultiMethod(Core::System& system, u32 method, const u32* base_start, u32 amount, u32 methods_pending) {
switch (method) {
case KEPLERMEMORY_REG_INDEX(data):
upload_state.ProcessData(base_start, amount);
return;
default:
for (u32 i = 0; i < amount; i++) {
- CallMethod(method, base_start[i], methods_pending - i <= 1);
+ CallMethod(system, method, base_start[i], methods_pending - i <= 1);
}
break;
}
diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h
index fb1eecbba9..aa0952d17a 100644
--- a/src/video_core/engines/kepler_memory.h
+++ b/src/video_core/engines/kepler_memory.h
@@ -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
@@ -36,18 +39,17 @@ namespace Tegra::Engines {
class KeplerMemory final : public EngineInterface {
public:
- explicit KeplerMemory(Core::System& system_, MemoryManager& memory_manager);
+ explicit KeplerMemory(MemoryManager& memory_manager);
~KeplerMemory() override;
/// Binds a rasterizer to this engine.
void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
/// Write the value to the register identified by method.
- void CallMethod(u32 method, u32 method_argument, bool is_last_call) override;
+ void CallMethod(Core::System& system, u32 method, u32 method_argument, bool is_last_call) override;
/// Write multiple values to the register identified by method.
- void CallMultiMethod(u32 method, const u32* base_start, u32 amount,
- u32 methods_pending) override;
+ void CallMultiMethod(Core::System& system, u32 method, const u32* base_start, u32 amount, u32 methods_pending) override;
struct Regs {
static constexpr size_t NUM_REGS = 0x7F;
@@ -73,9 +75,7 @@ public:
} regs{};
private:
- void ConsumeSinkImpl() override;
-
- Core::System& system;
+ void ConsumeSinkImpl(Core::System& system) override;
Upload::State upload_state;
};
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 7cf351e458..3474ad6d63 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -25,9 +25,8 @@ namespace Tegra::Engines {
/// First register id that is actually a Macro call.
constexpr u32 MacroRegistersStart = 0xE00;
-Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_)
+Maxwell3D::Maxwell3D(MemoryManager& memory_manager_)
: draw_manager()
- , system{system_}
, memory_manager{memory_manager_}
#ifdef ARCHITECTURE_x86_64
, macro_engine(bool(Settings::values.disable_macro_jit))
@@ -201,11 +200,10 @@ bool Maxwell3D::IsMethodExecutable(u32 method) {
}
}
-void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) {
+void Maxwell3D::ProcessMacro(Core::System& system, u32 method, const u32* base_start, u32 amount, bool is_last_call) {
if (executing_macro == 0) {
// A macro call must begin by writing the macro method's register, not its argument.
- ASSERT_MSG((method % 2) == 0,
- "Can't start macro execution by writing to the ARGS register");
+ ASSERT((method % 2) == 0 && "Can't start macro execution by writing to the ARGS register");
executing_macro = method;
}
@@ -219,8 +217,8 @@ void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool
// Call the macro when there are no more parameters in the command buffer
if (is_last_call) {
- ConsumeSink();
- CallMacroMethod(executing_macro, macro_params);
+ ConsumeSink(system);
+ CallMacroMethod(system, executing_macro, macro_params);
macro_params.clear();
macro_addresses.clear();
macro_segments.clear();
@@ -287,7 +285,7 @@ u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) {
return argument;
}
-void Maxwell3D::ConsumeSinkImpl() {
+void Maxwell3D::ConsumeSinkImpl(Core::System& system) {
const auto control = shadow_state.shadow_ram_control;
if (control == Regs::ShadowRamControl::Track || control == Regs::ShadowRamControl::TrackWithFilter) {
for (auto [method, value] : method_sink) {
@@ -378,7 +376,7 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume
}
}
-void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters) {
+void Maxwell3D::CallMacroMethod(Core::System& system, u32 method, const std::vector<u32>& parameters) {
// Reset the current macro.
executing_macro = 0;
@@ -387,11 +385,11 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters)
((method - MacroRegistersStart) >> 1) % static_cast<u32>(macro_positions.size());
// Execute the current macro.
- macro_engine.Execute(*this, macro_positions[entry], parameters);
+ macro_engine.Execute(system, *this, macro_positions[entry], parameters);
draw_manager.DrawDeferred(*this);
}
-void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
+void Maxwell3D::CallMethod(Core::System& system, u32 method, u32 method_argument, bool is_last_call) {
// It is an error to write to a register other than the current macro's ARG register before
// it has finished execution.
if (executing_macro != 0) {
@@ -401,7 +399,7 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
// Methods after 0xE00 are special, they're actually triggers for some microcode that was
// uploaded to the GPU during initialization.
if (method >= MacroRegistersStart) {
- ProcessMacro(method, &method_argument, 1, is_last_call);
+ ProcessMacro(system, method, &method_argument, 1, is_last_call);
return;
}
@@ -411,12 +409,11 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
ProcessMethodCall(method, argument, method_argument, is_last_call);
}
-void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
- u32 methods_pending) {
+void Maxwell3D::CallMultiMethod(Core::System& system, u32 method, const u32* base_start, u32 amount, u32 methods_pending) {
// Methods after 0xE00 are special, they're actually triggers for some microcode that was
// uploaded to the GPU during initialization.
if (method >= MacroRegistersStart) {
- ProcessMacro(method, base_start, amount, amount == methods_pending);
+ ProcessMacro(system, method, base_start, amount, amount == methods_pending);
return;
}
switch (method) {
@@ -445,7 +442,7 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
}
default:
for (u32 i = 0; i < amount; i++) {
- CallMethod(method, base_start[i], methods_pending - i <= 1);
+ CallMethod(system, method, base_start[i], methods_pending - i <= 1);
}
break;
}
@@ -467,7 +464,7 @@ void Maxwell3D::ProcessFirmwareCall4() {
regs.shadow_scratch[0] = 1;
}
-void Maxwell3D::StampQueryResult(u64 payload, bool long_query) {
+void Maxwell3D::StampQueryResult(Core::System& system, u64 payload, bool long_query) {
const GPUVAddr sequence_address{regs.report_semaphore.Address()};
if (long_query) {
memory_manager.Write<u64>(sequence_address + sizeof(u64), system.GPU().GetTicks());
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 864ee27fb6..823be0f63e 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -55,7 +55,7 @@ namespace Tegra::Engines {
class Maxwell3D final : public EngineInterface {
public:
- explicit Maxwell3D(Core::System& system, MemoryManager& memory_manager);
+ explicit Maxwell3D(MemoryManager& memory_manager);
~Maxwell3D();
/// Binds a rasterizer to this engine.
@@ -3129,11 +3129,10 @@ public:
u32 GetRegisterValue(u32 method) const;
/// Write the value to the register identified by method.
- void CallMethod(u32 method, u32 method_argument, bool is_last_call) override;
+ void CallMethod(Core::System& system, u32 method, u32 method_argument, bool is_last_call) override;
/// Write multiple values to the register identified by method.
- void CallMultiMethod(u32 method, const u32* base_start, u32 amount,
- u32 methods_pending) override;
+ void CallMultiMethod(Core::System& system, u32 method, const u32* base_start, u32 amount, u32 methods_pending) override;
bool ShouldExecute() const {
return execute_on;
@@ -3190,13 +3189,13 @@ public:
private:
void InitializeRegisterDefaults();
- void ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call);
+ void ProcessMacro(Core::System& system, u32 method, const u32* base_start, u32 amount, bool is_last_call);
u32 ProcessShadowRam(u32 method, u32 argument);
void ProcessDirtyRegisters(u32 method, u32 argument);
- void ConsumeSinkImpl() override;
+ void ConsumeSinkImpl(Core::System& system) override;
void ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argument, bool is_last_call);
@@ -3212,7 +3211,7 @@ private:
* @param method Method to call
* @param parameters Arguments to the method call
*/
- void CallMacroMethod(u32 method, const std::vector<u32>& parameters);
+ void CallMacroMethod(Core::System& system, u32 method, const std::vector<u32>& parameters);
/// Handles writes to the macro uploading register.
void ProcessMacroUpload(u32 data);
@@ -3227,7 +3226,7 @@ private:
void ProcessQueryGet();
/// Writes the query result accordingly.
- void StampQueryResult(u64 payload, bool long_query);
+ void StampQueryResult(Core::System& system, u64 payload, bool long_query);
/// Handles conditional rendering.
void ProcessQueryCondition();
@@ -3242,7 +3241,6 @@ private:
bool IsMethodExecutable(u32 method);
- Core::System& system;
MemoryManager& memory_manager;
VideoCore::RasterizerInterface* rasterizer = nullptr;
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index 089d118a09..a4090bc2ce 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -21,8 +21,9 @@ namespace Tegra::Engines {
using namespace Texture;
-MaxwellDMA::MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_)
- : system{system_}, memory_manager{memory_manager_} {
+MaxwellDMA::MaxwellDMA(MemoryManager& memory_manager_)
+ : memory_manager{memory_manager_}
+{
execution_mask.reset();
execution_mask[offsetof(Regs, launch_dma) / sizeof(u32)] = true;
}
@@ -33,14 +34,14 @@ void MaxwellDMA::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
rasterizer = rasterizer_;
}
-void MaxwellDMA::ConsumeSinkImpl() {
+void MaxwellDMA::ConsumeSinkImpl(Core::System& system) {
for (auto [method, value] : method_sink) {
regs.reg_array[method] = value;
}
method_sink.clear();
}
-void MaxwellDMA::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
+void MaxwellDMA::CallMethod(Core::System& system, u32 method, u32 method_argument, bool is_last_call) {
ASSERT_MSG(method < NUM_REGS, "Invalid MaxwellDMA register");
regs.reg_array[method] = method_argument;
@@ -50,16 +51,14 @@ void MaxwellDMA::CallMethod(u32 method, u32 method_argument, bool is_last_call)
}
}
-void MaxwellDMA::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
- u32 methods_pending) {
+void MaxwellDMA::CallMultiMethod(Core::System& system, u32 method, const u32* base_start, u32 amount, u32 methods_pending) {
for (u32 i = 0; i < amount; ++i) {
- CallMethod(method, base_start[i], methods_pending - i <= 1);
+ CallMethod(system, method, base_start[i], methods_pending - i <= 1);
}
}
void MaxwellDMA::Launch() {
- LOG_TRACE(Render_OpenGL, "DMA copy 0x{:x} -> 0x{:x}", static_cast<GPUVAddr>(regs.offset_in),
- static_cast<GPUVAddr>(regs.offset_out));
+ LOG_TRACE(Render_OpenGL, "DMA copy 0x{:x} -> 0x{:x}", static_cast<GPUVAddr>(regs.offset_in), GPUVAddr(regs.offset_out));
// TODO(Subv): Perform more research and implement all features of this engine.
const LaunchDMA& launch = regs.launch_dma;
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h
index 99341e431c..9cf2813d31 100644
--- a/src/video_core/engines/maxwell_dma.h
+++ b/src/video_core/engines/maxwell_dma.h
@@ -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
@@ -238,15 +241,14 @@ public:
void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
- explicit MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_);
+ explicit MaxwellDMA(MemoryManager& memory_manager_);
~MaxwellDMA() override;
/// Write the value to the register identified by method.
- void CallMethod(u32 method, u32 method_argument, bool is_last_call) override;
+ void CallMethod(Core::System& system, u32 method, u32 method_argument, bool is_last_call) override;
/// Write multiple values to the register identified by method.
- void CallMultiMethod(u32 method, const u32* base_start, u32 amount,
- u32 methods_pending) override;
+ void CallMultiMethod(Core::System& system, u32 method, const u32* base_start, u32 amount, u32 methods_pending) override;
private:
/// Performs the copy from the source buffer to the destination buffer as configured in the
@@ -261,9 +263,7 @@ private:
void ReleaseSemaphore();
- void ConsumeSinkImpl() override;
-
- Core::System& system;
+ void ConsumeSinkImpl(Core::System& system) override;
MemoryManager& memory_manager;
VideoCore::RasterizerInterface* rasterizer = nullptr;
diff --git a/src/video_core/engines/nv01_timer.h b/src/video_core/engines/nv01_timer.h
index add9886f41..37c6668144 100644
--- a/src/video_core/engines/nv01_timer.h
+++ b/src/video_core/engines/nv01_timer.h
@@ -26,18 +26,16 @@ class MemoryManager;
namespace Tegra::Engines {
class Nv01Timer final : public EngineInterface {
public:
- explicit Nv01Timer(Core::System& system_, MemoryManager& memory_manager)
- : system{system_}
- {}
- ~Nv01Timer() override;
+ explicit Nv01Timer(MemoryManager& memory_manager) noexcept {}
+ ~Nv01Timer() noexcept override {}
/// Write the value to the register identified by method.
- void CallMethod(u32 method, u32 method_argument, bool is_last_call) override {
+ void CallMethod(Core::System& system, u32 method, u32 method_argument, bool is_last_call) override {
LOG_DEBUG(HW_GPU, "method={}, argument={}, is_last_call={}", method, method_argument, is_last_call);
}
/// Write multiple values to the register identified by method.
- void CallMultiMethod(u32 method, const u32* base_start, u32 amount, u32 methods_pending) override {
+ void CallMultiMethod(Core::System& system, u32 method, const u32* base_start, u32 amount, u32 methods_pending) override {
LOG_DEBUG(HW_GPU, "method={}, base_start={}, amount={}, pending={}", method, fmt::ptr(base_start), amount, methods_pending);
}
@@ -46,7 +44,6 @@ public:
INSERT_PADDING_BYTES_NOINIT(0x48);
} regs{};
private:
- void ConsumeSinkImpl() override {}
- Core::System& system;
+ void ConsumeSinkImpl(Core::System& system) override {}
};
}
diff --git a/src/video_core/engines/puller.cpp b/src/video_core/engines/puller.cpp
index 4030f93d49..5816b5901a 100644
--- a/src/video_core/engines/puller.cpp
+++ b/src/video_core/engines/puller.cpp
@@ -22,37 +22,29 @@
namespace Tegra::Engines {
-Puller::Puller(GPU& gpu_, MemoryManager& memory_manager_, DmaPusher& dma_pusher_,
- Control::ChannelState& channel_state_)
- : gpu{gpu_}, memory_manager{memory_manager_}, dma_pusher{dma_pusher_}, channel_state{
- channel_state_} {}
-
-Puller::~Puller() = default;
-
-void Puller::ProcessBindMethod(const MethodCall& method_call) {
+void Puller::ProcessBindMethod(DmaPusher& dma_pusher, const MethodCall& method_call) {
// Bind the current subchannel to the desired engine id.
- LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", method_call.subchannel,
- method_call.argument);
+ LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", method_call.subchannel, method_call.argument);
const auto engine_id = static_cast<EngineID>(method_call.argument);
bound_engines[method_call.subchannel] = engine_id;
switch (engine_id) {
case EngineID::FERMI_TWOD_A:
- dma_pusher.BindSubchannel(&*channel_state.fermi_2d, method_call.subchannel, EngineTypes::Fermi2D);
+ dma_pusher.BindSubchannel(&dma_pusher.channel_state.payload->fermi_2d, method_call.subchannel, EngineTypes::Fermi2D);
break;
case EngineID::MAXWELL_B:
- dma_pusher.BindSubchannel(&*channel_state.maxwell_3d, method_call.subchannel, EngineTypes::Maxwell3D);
+ dma_pusher.BindSubchannel(&dma_pusher.channel_state.payload->maxwell_3d, method_call.subchannel, EngineTypes::Maxwell3D);
break;
case EngineID::KEPLER_COMPUTE_B:
- dma_pusher.BindSubchannel(&*channel_state.kepler_compute, method_call.subchannel, EngineTypes::KeplerCompute);
+ dma_pusher.BindSubchannel(&dma_pusher.channel_state.payload->kepler_compute, method_call.subchannel, EngineTypes::KeplerCompute);
break;
case EngineID::MAXWELL_DMA_COPY_A:
- dma_pusher.BindSubchannel(&*channel_state.maxwell_dma, method_call.subchannel, EngineTypes::MaxwellDMA);
+ dma_pusher.BindSubchannel(&dma_pusher.channel_state.payload->maxwell_dma, method_call.subchannel, EngineTypes::MaxwellDMA);
break;
case EngineID::KEPLER_INLINE_TO_MEMORY_B:
- dma_pusher.BindSubchannel(&*channel_state.kepler_memory, method_call.subchannel, EngineTypes::KeplerMemory);
+ dma_pusher.BindSubchannel(&dma_pusher.channel_state.payload->kepler_memory, method_call.subchannel, EngineTypes::KeplerMemory);
break;
case EngineID::NV01_TIMER:
- dma_pusher.BindSubchannel(&*channel_state.nv01_timer, method_call.subchannel, EngineTypes::Nv01Timer);
+ dma_pusher.BindSubchannel(&dma_pusher.channel_state.payload->nv01_timer, method_call.subchannel, EngineTypes::Nv01Timer);
break;
default:
UNIMPLEMENTED_MSG("Unimplemented engine {:04X}", engine_id);
@@ -60,15 +52,15 @@ void Puller::ProcessBindMethod(const MethodCall& method_call) {
}
}
-void Puller::ProcessFenceActionMethod() {
+void Puller::ProcessFenceActionMethod(DmaPusher& dma_pusher) {
switch (regs.fence_action.op) {
case Puller::FenceOperation::Acquire:
// UNIMPLEMENTED_MSG("Channel Scheduling pending.");
// WaitFence(regs.fence_action.syncpoint_id, regs.fence_value);
- rasterizer->ReleaseFences();
+ dma_pusher.rasterizer->ReleaseFences();
break;
case Puller::FenceOperation::Increment:
- rasterizer->SignalSyncPoint(regs.fence_action.syncpoint_id);
+ dma_pusher.rasterizer->SignalSyncPoint(regs.fence_action.syncpoint_id);
break;
default:
UNIMPLEMENTED_MSG("Unimplemented operation {}", regs.fence_action.op.Value());
@@ -76,37 +68,35 @@ void Puller::ProcessFenceActionMethod() {
}
}
-void Puller::ProcessSemaphoreTriggerMethod() {
+void Puller::ProcessSemaphoreTriggerMethod(DmaPusher& dma_pusher) {
const auto semaphoreOperationMask = 0xF;
- const auto op =
- static_cast<GpuSemaphoreOperation>(regs.semaphore_trigger & semaphoreOperationMask);
+ const auto op = GpuSemaphoreOperation(regs.semaphore_trigger & semaphoreOperationMask);
if (op == GpuSemaphoreOperation::WriteLong) {
const GPUVAddr sequence_address{regs.semaphore_address.SemaphoreAddress()};
const u32 payload = regs.semaphore_sequence;
- rasterizer->Query(sequence_address, VideoCommon::QueryType::Payload,
- VideoCommon::QueryPropertiesFlags::HasTimeout, payload, 0);
+ dma_pusher.rasterizer->Query(sequence_address, VideoCommon::QueryType::Payload, VideoCommon::QueryPropertiesFlags::HasTimeout, payload, 0);
} else {
do {
- const u32 word{memory_manager.Read<u32>(regs.semaphore_address.SemaphoreAddress())};
+ const u32 word = dma_pusher.memory_manager.Read<u32>(regs.semaphore_address.SemaphoreAddress());
regs.acquire_source = true;
regs.acquire_value = regs.semaphore_sequence;
if (op == GpuSemaphoreOperation::AcquireEqual) {
regs.acquire_active = true;
regs.acquire_mode = false;
if (word != regs.acquire_value) {
- rasterizer->ReleaseFences();
+ dma_pusher.rasterizer->ReleaseFences();
continue;
}
} else if (op == GpuSemaphoreOperation::AcquireGequal) {
regs.acquire_active = true;
regs.acquire_mode = true;
if (word < regs.acquire_value) {
- rasterizer->ReleaseFences();
+ dma_pusher.rasterizer->ReleaseFences();
continue;
}
} else if (op == GpuSemaphoreOperation::AcquireMask) {
if (word && regs.semaphore_sequence == 0) {
- rasterizer->ReleaseFences();
+ dma_pusher.rasterizer->ReleaseFences();
continue;
}
} else {
@@ -116,21 +106,20 @@ void Puller::ProcessSemaphoreTriggerMethod() {
}
}
-void Puller::ProcessSemaphoreRelease() {
+void Puller::ProcessSemaphoreRelease(DmaPusher& dma_pusher) {
const GPUVAddr sequence_address{regs.semaphore_address.SemaphoreAddress()};
const u32 payload = regs.semaphore_release;
- rasterizer->Query(sequence_address, VideoCommon::QueryType::Payload,
- VideoCommon::QueryPropertiesFlags::IsAFence, payload, 0);
+ dma_pusher.rasterizer->Query(sequence_address, VideoCommon::QueryType::Payload, VideoCommon::QueryPropertiesFlags::IsAFence, payload, 0);
}
-void Puller::ProcessSemaphoreAcquire() {
- u32 word = memory_manager.Read<u32>(regs.semaphore_address.SemaphoreAddress());
+void Puller::ProcessSemaphoreAcquire(DmaPusher& dma_pusher) {
+ u32 word = dma_pusher.memory_manager.Read<u32>(regs.semaphore_address.SemaphoreAddress());
const auto value = regs.semaphore_acquire;
while (word != value) {
regs.acquire_active = true;
regs.acquire_value = value;
- rasterizer->ReleaseFences();
- word = memory_manager.Read<u32>(regs.semaphore_address.SemaphoreAddress());
+ dma_pusher.rasterizer->ReleaseFences();
+ word = dma_pusher.memory_manager.Read<u32>(regs.semaphore_address.SemaphoreAddress());
// TODO(kemathe73) figure out how to do the acquire_timeout
regs.acquire_mode = false;
regs.acquire_source = false;
@@ -138,13 +127,13 @@ void Puller::ProcessSemaphoreAcquire() {
}
/// Calls a GPU puller method.
-void Puller::CallPullerMethod(const MethodCall& method_call) {
+void Puller::CallPullerMethod(DmaPusher& dma_pusher, const MethodCall& method_call) {
regs.reg_array[method_call.method] = method_call.argument;
const auto method = static_cast<BufferMethods>(method_call.method);
switch (method) {
case BufferMethods::BindObject: {
- ProcessBindMethod(method_call);
+ ProcessBindMethod(dma_pusher, method_call);
break;
}
case BufferMethods::Nop:
@@ -155,16 +144,16 @@ void Puller::CallPullerMethod(const MethodCall& method_call) {
case BufferMethods::WrcacheFlush:
break;
case BufferMethods::RefCnt:
- rasterizer->SignalReference();
+ dma_pusher.rasterizer->SignalReference();
break;
case BufferMethods::SyncpointOperation:
- ProcessFenceActionMethod();
+ ProcessFenceActionMethod(dma_pusher);
break;
case BufferMethods::WaitForIdle:
- rasterizer->WaitForIdle();
+ dma_pusher.rasterizer->WaitForIdle();
break;
case BufferMethods::SemaphoreOperation: {
- ProcessSemaphoreTriggerMethod();
+ ProcessSemaphoreTriggerMethod(dma_pusher);
break;
}
case BufferMethods::NonStallInterrupt: {
@@ -177,7 +166,7 @@ void Puller::CallPullerMethod(const MethodCall& method_call) {
}
case BufferMethods::MemOpB: {
// Implement this better.
- rasterizer->InvalidateGPUCache();
+ dma_pusher.rasterizer->InvalidateGPUCache();
break;
}
case BufferMethods::MemOpC:
@@ -186,11 +175,11 @@ void Puller::CallPullerMethod(const MethodCall& method_call) {
break;
}
case BufferMethods::SemaphoreAcquire: {
- ProcessSemaphoreAcquire();
+ ProcessSemaphoreAcquire(dma_pusher);
break;
}
case BufferMethods::SemaphoreRelease: {
- ProcessSemaphoreRelease();
+ ProcessSemaphoreRelease(dma_pusher);
break;
}
case BufferMethods::Yield: {
@@ -205,27 +194,26 @@ void Puller::CallPullerMethod(const MethodCall& method_call) {
}
/// Calls a GPU engine method.
-void Puller::CallEngineMethod(const MethodCall& method_call) {
+void Puller::CallEngineMethod(DmaPusher& dma_pusher, const MethodCall& method_call) {
const EngineID engine = bound_engines[method_call.subchannel];
-
switch (engine) {
case EngineID::FERMI_TWOD_A:
- channel_state.fermi_2d->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
+ dma_pusher.channel_state.payload->fermi_2d.CallMethod(dma_pusher.system, method_call.method, method_call.argument, method_call.IsLastCall());
break;
case EngineID::MAXWELL_B:
- channel_state.maxwell_3d->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
+ dma_pusher.channel_state.payload->maxwell_3d.CallMethod(dma_pusher.system, method_call.method, method_call.argument, method_call.IsLastCall());
break;
case EngineID::KEPLER_COMPUTE_B:
- channel_state.kepler_compute->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
+ dma_pusher.channel_state.payload->kepler_compute.CallMethod(dma_pusher.system, method_call.method, method_call.argument, method_call.IsLastCall());
break;
case EngineID::MAXWELL_DMA_COPY_A:
- channel_state.maxwell_dma->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
+ dma_pusher.channel_state.payload->maxwell_dma.CallMethod(dma_pusher.system, method_call.method, method_call.argument, method_call.IsLastCall());
break;
case EngineID::KEPLER_INLINE_TO_MEMORY_B:
- channel_state.kepler_memory->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
+ dma_pusher.channel_state.payload->kepler_memory.CallMethod(dma_pusher.system, method_call.method, method_call.argument, method_call.IsLastCall());
break;
case EngineID::NV01_TIMER:
- channel_state.nv01_timer->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
+ dma_pusher.channel_state.payload->nv01_timer.CallMethod(dma_pusher.system, method_call.method, method_call.argument, method_call.IsLastCall());
break;
default:
UNIMPLEMENTED_MSG("Unimplemented engine");
@@ -234,28 +222,26 @@ void Puller::CallEngineMethod(const MethodCall& method_call) {
}
/// Calls a GPU engine multivalue method.
-void Puller::CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount,
- u32 methods_pending) {
+void Puller::CallEngineMultiMethod(DmaPusher& dma_pusher, u32 method, u32 subchannel, const u32* base_start, u32 amount, u32 methods_pending) {
const EngineID engine = bound_engines[subchannel];
-
switch (engine) {
case EngineID::FERMI_TWOD_A:
- channel_state.fermi_2d->CallMultiMethod(method, base_start, amount, methods_pending);
+ dma_pusher.channel_state.payload->fermi_2d.CallMultiMethod(dma_pusher.system, method, base_start, amount, methods_pending);
break;
case EngineID::MAXWELL_B:
- channel_state.maxwell_3d->CallMultiMethod(method, base_start, amount, methods_pending);
+ dma_pusher.channel_state.payload->maxwell_3d.CallMultiMethod(dma_pusher.system, method, base_start, amount, methods_pending);
break;
case EngineID::KEPLER_COMPUTE_B:
- channel_state.kepler_compute->CallMultiMethod(method, base_start, amount, methods_pending);
+ dma_pusher.channel_state.payload->kepler_compute.CallMultiMethod(dma_pusher.system, method, base_start, amount, methods_pending);
break;
case EngineID::MAXWELL_DMA_COPY_A:
- channel_state.maxwell_dma->CallMultiMethod(method, base_start, amount, methods_pending);
+ dma_pusher.channel_state.payload->maxwell_dma.CallMultiMethod(dma_pusher.system, method, base_start, amount, methods_pending);
break;
case EngineID::KEPLER_INLINE_TO_MEMORY_B:
- channel_state.kepler_memory->CallMultiMethod(method, base_start, amount, methods_pending);
+ dma_pusher.channel_state.payload->kepler_memory.CallMultiMethod(dma_pusher.system, method, base_start, amount, methods_pending);
break;
case EngineID::NV01_TIMER:
- channel_state.nv01_timer->CallMultiMethod(method, base_start, amount, methods_pending);
+ dma_pusher.channel_state.payload->nv01_timer.CallMultiMethod(dma_pusher.system, method, base_start, amount, methods_pending);
break;
default:
UNIMPLEMENTED_MSG("Unimplemented engine");
@@ -264,31 +250,26 @@ void Puller::CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_s
}
/// Calls a GPU method.
-void Puller::CallMethod(const MethodCall& method_call) {
- LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method_call.method,
- method_call.subchannel);
-
+void Puller::CallMethod(DmaPusher& dma_pusher, const MethodCall& method_call) {
+ LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method_call.method, method_call.subchannel);
ASSERT(method_call.subchannel < bound_engines.size());
- if (ExecuteMethodOnEngine(method_call.method)) {
- CallEngineMethod(method_call);
+ if (ExecuteMethodOnEngine(dma_pusher, method_call.method)) {
+ CallEngineMethod(dma_pusher, method_call);
} else {
- CallPullerMethod(method_call);
+ CallPullerMethod(dma_pusher, method_call);
}
}
/// Calls a GPU multivalue method.
-void Puller::CallMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount,
- u32 methods_pending) {
+void Puller::CallMultiMethod(DmaPusher& dma_pusher, u32 method, u32 subchannel, const u32* base_start, u32 amount, u32 methods_pending) {
LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method, subchannel);
-
ASSERT(subchannel < bound_engines.size());
-
- if (ExecuteMethodOnEngine(method)) {
- CallEngineMultiMethod(method, subchannel, base_start, amount, methods_pending);
+ if (ExecuteMethodOnEngine(dma_pusher, method)) {
+ CallEngineMultiMethod(dma_pusher, method, subchannel, base_start, amount, methods_pending);
} else {
for (u32 i = 0; i < amount; i++) {
- CallPullerMethod(MethodCall{
+ CallPullerMethod(dma_pusher, MethodCall{
method,
base_start[i],
subchannel,
@@ -298,13 +279,9 @@ void Puller::CallMultiMethod(u32 method, u32 subchannel, const u32* base_start,
}
}
-void Puller::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
- rasterizer = rasterizer_;
-}
-
/// Determines where the method should be executed.
-[[nodiscard]] bool Puller::ExecuteMethodOnEngine(u32 method) {
- const auto buffer_method = static_cast<BufferMethods>(method);
+[[nodiscard]] bool Puller::ExecuteMethodOnEngine(DmaPusher& dma_pusher, u32 method) {
+ const auto buffer_method = BufferMethods(method);
return buffer_method >= BufferMethods::NonPullerMethods;
}
diff --git a/src/video_core/engines/puller.h b/src/video_core/engines/puller.h
index fe5102e3ed..e8994f5640 100644
--- a/src/video_core/engines/puller.h
+++ b/src/video_core/engines/puller.h
@@ -70,32 +70,13 @@ public:
BitField<8, 24, u32> syncpoint_id;
};
- explicit Puller(GPU& gpu_, MemoryManager& memory_manager_, DmaPusher& dma_pusher,
- Control::ChannelState& channel_state);
- ~Puller();
-
- void CallMethod(const MethodCall& method_call);
-
- void CallMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount,
- u32 methods_pending);
-
- void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
-
- void CallPullerMethod(const MethodCall& method_call);
-
- void CallEngineMethod(const MethodCall& method_call);
-
- void CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount,
- u32 methods_pending);
-
+ void CallMethod(DmaPusher& dma_pusher, const MethodCall& method_call);
+ void CallMultiMethod(DmaPusher& dma_pusher, u32 method, u32 subchannel, const u32* base_start, u32 amount, u32 methods_pending);
+ void BindRasterizer(DmaPusher& dma_pusher, VideoCore::RasterizerInterface* rasterizer);
+ void CallPullerMethod(DmaPusher& dma_pusher, const MethodCall& method_call);
+ void CallEngineMethod(DmaPusher& dma_pusher, const MethodCall& method_call);
+ void CallEngineMultiMethod(DmaPusher& dma_pusher, u32 method, u32 subchannel, const u32* base_start, u32 amount, u32 methods_pending);
private:
- Tegra::GPU& gpu;
-
- MemoryManager& memory_manager;
- DmaPusher& dma_pusher;
- Control::ChannelState& channel_state;
- VideoCore::RasterizerInterface* rasterizer = nullptr;
-
static constexpr std::size_t NUM_REGS = 0x800;
struct Regs {
static constexpr size_t NUM_REGS = 0x40;
@@ -139,12 +120,12 @@ private:
};
} regs{};
- void ProcessBindMethod(const MethodCall& method_call);
- void ProcessFenceActionMethod();
- void ProcessSemaphoreAcquire();
- void ProcessSemaphoreRelease();
- void ProcessSemaphoreTriggerMethod();
- [[nodiscard]] bool ExecuteMethodOnEngine(u32 method);
+ void ProcessBindMethod(DmaPusher& dma_pusher, const MethodCall& method_call);
+ void ProcessFenceActionMethod(DmaPusher& dma_pusher);
+ void ProcessSemaphoreAcquire(DmaPusher& dma_pusher);
+ void ProcessSemaphoreRelease(DmaPusher& dma_pusher);
+ void ProcessSemaphoreTriggerMethod(DmaPusher& dma_pusher);
+ [[nodiscard]] bool ExecuteMethodOnEngine(DmaPusher& dma_pusher, u32 method);
/// Mapping of command subchannels to their bound engine ids
std::array<EngineID, 8> bound_engines{};
@@ -157,8 +138,7 @@ private:
};
#define ASSERT_REG_POSITION(field_name, position) \
- static_assert(offsetof(Regs, field_name) == position * 4, \
- "Field " #field_name " has invalid position")
+ static_assert(offsetof(Regs, field_name) == position * 4, "Field " #field_name " has invalid position")
ASSERT_REG_POSITION(semaphore_address, 0x4);
ASSERT_REG_POSITION(semaphore_sequence, 0x6);
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 391ca4ef5f..548a8bf809 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -40,30 +40,31 @@
namespace Tegra {
struct GPU::Impl {
- explicit Impl(GPU& gpu_, Core::System& system_, bool is_async_, bool use_nvdec_)
- : gpu{gpu_}, system{system_}, host1x{system.Host1x()}, use_nvdec{use_nvdec_},
- shader_notify{std::make_unique<VideoCore::ShaderNotify>()}, is_async{is_async_},
- gpu_thread{system_, is_async_}, scheduler{std::make_unique<Control::Scheduler>(gpu)} {}
+ explicit Impl(Core::System& system_, bool is_async_, bool use_nvdec_)
+ : system{system_}
+ , use_nvdec{use_nvdec_}
+ , shader_notify()
+ , is_async{is_async_}
+ , gpu_thread{system_}
+ {}
~Impl() = default;
std::shared_ptr<Control::ChannelState> CreateChannel(s32 channel_id) {
auto channel_state = std::make_shared<Tegra::Control::ChannelState>(channel_id);
channels.emplace(channel_id, channel_state);
- scheduler->DeclareChannel(channel_state);
+ scheduler.DeclareChannel(channel_state);
return channel_state;
}
void BindChannel(s32 channel_id) {
- if (bound_channel == channel_id) {
- return;
+ if (bound_channel != channel_id) {
+ auto it = channels.find(channel_id);
+ ASSERT(it != channels.end());
+ bound_channel = channel_id;
+ current_channel = it->second.get();
+ renderer->ReadRasterizer()->BindChannel(*current_channel);
}
- auto it = channels.find(channel_id);
- ASSERT(it != channels.end());
- bound_channel = channel_id;
- current_channel = it->second.get();
-
- rasterizer->BindChannel(*current_channel);
}
std::shared_ptr<Control::ChannelState> AllocateChannel() {
@@ -71,13 +72,13 @@ struct GPU::Impl {
}
void InitChannel(Control::ChannelState& to_init, u64 program_id) {
- to_init.Init(system, gpu, program_id);
- to_init.BindRasterizer(rasterizer);
- rasterizer->InitializeChannel(to_init);
+ to_init.Init(system, program_id);
+ to_init.BindRasterizer(renderer->ReadRasterizer());
+ renderer->ReadRasterizer()->InitializeChannel(to_init);
}
void InitAddressSpace(Tegra::MemoryManager& memory_manager) {
- memory_manager.BindRasterizer(rasterizer);
+ memory_manager.BindRasterizer(renderer->ReadRasterizer());
}
void ReleaseChannel(Control::ChannelState& to_release) {
@@ -87,26 +88,26 @@ struct GPU::Impl {
/// Binds a renderer to the GPU.
void BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) {
renderer = std::move(renderer_);
- rasterizer = renderer->ReadRasterizer();
- host1x.MemoryManager().BindInterface(rasterizer);
- host1x.gmmu_manager.BindRasterizer(rasterizer);
+ system.Host1x().memory_manager.BindInterface(renderer->ReadRasterizer());
+ system.Host1x().gmmu_manager.BindRasterizer(renderer->ReadRasterizer());
}
/// Flush all current written commands into the host GPU for execution.
void FlushCommands() {
- rasterizer->FlushCommands();
+ renderer->ReadRasterizer()->FlushCommands();
}
/// Synchronizes CPU writes with Host GPU memory.
void InvalidateGPUCache() {
- std::function<void(PAddr, size_t)> callback_writes(
- [this](PAddr address, size_t size) { rasterizer->OnCacheInvalidation(address, size); });
+ std::function<void(PAddr, size_t)> callback_writes([this](PAddr address, size_t size) {
+ renderer->ReadRasterizer()->OnCacheInvalidation(address, size);
+ });
system.GatherGPUDirtyMemory(callback_writes);
}
/// Signal the ending of command list.
void OnCommandListEnd() {
- rasterizer->ReleaseFences(false);
+ renderer->ReadRasterizer()->ReleaseFences(false);
Settings::UpdateGPUAccuracy();
}
@@ -143,62 +144,6 @@ struct GPU::Impl {
}
}
- /// Returns a reference to the Maxwell3D GPU engine.
- [[nodiscard]] Engines::Maxwell3D& Maxwell3D() {
- ASSERT(current_channel);
- return *current_channel->maxwell_3d;
- }
-
- /// Returns a const reference to the Maxwell3D GPU engine.
- [[nodiscard]] const Engines::Maxwell3D& Maxwell3D() const {
- ASSERT(current_channel);
- return *current_channel->maxwell_3d;
- }
-
- /// Returns a reference to the KeplerCompute GPU engine.
- [[nodiscard]] Engines::KeplerCompute& KeplerCompute() {
- ASSERT(current_channel);
- return *current_channel->kepler_compute;
- }
-
- /// Returns a reference to the KeplerCompute GPU engine.
- [[nodiscard]] const Engines::KeplerCompute& KeplerCompute() const {
- ASSERT(current_channel);
- return *current_channel->kepler_compute;
- }
-
- /// Returns a reference to the GPU DMA pusher.
- [[nodiscard]] Tegra::DmaPusher& DmaPusher() {
- ASSERT(current_channel);
- return *current_channel->dma_pusher;
- }
-
- /// Returns a const reference to the GPU DMA pusher.
- [[nodiscard]] const Tegra::DmaPusher& DmaPusher() const {
- ASSERT(current_channel);
- return *current_channel->dma_pusher;
- }
-
- /// Returns a reference to the underlying renderer.
- [[nodiscard]] VideoCore::RendererBase& Renderer() {
- return *renderer;
- }
-
- /// Returns a const reference to the underlying renderer.
- [[nodiscard]] const VideoCore::RendererBase& Renderer() const {
- return *renderer;
- }
-
- /// Returns a reference to the shader notifier.
- [[nodiscard]] VideoCore::ShaderNotify& ShaderNotify() {
- return *shader_notify;
- }
-
- /// Returns a const reference to the shader notifier.
- [[nodiscard]] const VideoCore::ShaderNotify& ShaderNotify() const {
- return *shader_notify;
- }
-
[[nodiscard]] u64 GetTicks() const {
u64 gpu_tick = system.CoreTiming().GetGPUTicks();
Settings::GpuOverclock overclock = Settings::values.fast_gpu_time.GetValue();
@@ -210,14 +155,6 @@ struct GPU::Impl {
return gpu_tick;
}
- [[nodiscard]] bool IsAsync() const {
- return is_async;
- }
-
- [[nodiscard]] bool UseNvdec() const {
- return use_nvdec;
- }
-
void RendererFrameEndNotify() {
system.GetPerfStats().EndGameFrame();
}
@@ -227,7 +164,7 @@ struct GPU::Impl {
/// core timing events.
void Start() {
Settings::UpdateGPUAccuracy();
- gpu_thread.StartThread(*renderer, renderer->Context(), *scheduler);
+ gpu_thread.StartThread(*renderer, renderer->Context(), scheduler);
}
void NotifyShutdown() {
@@ -251,25 +188,24 @@ 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) {
- auto raster_area = rasterizer->GetFlushArea(addr, size);
+ auto raster_area = renderer->ReadRasterizer()->GetFlushArea(addr, size);
if (raster_area.preemtive) {
return raster_area;
}
raster_area.preemtive = true;
const u64 fence = RequestSyncOperation([this, &raster_area]() {
- rasterizer->FlushRegion(raster_area.start_address,
- raster_area.end_address - raster_area.start_address);
+ 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;
}
@@ -280,16 +216,15 @@ struct GPU::Impl {
}
bool OnCPUWrite(DAddr addr, u64 size) {
- return rasterizer->OnCPUWrite(addr, size);
+ return renderer->ReadRasterizer()->OnCPUWrite(addr, size);
}
/// 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,
- std::vector<Service::Nvidia::NvFence>&& fences) {
+ void RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers, std::vector<Service::Nvidia::NvFence>&& fences) {
size_t num_fences{fences.size()};
size_t current_request_counter{};
{
@@ -304,7 +239,7 @@ struct GPU::Impl {
}
}
const auto wait_fence = RequestSyncOperation([this, current_request_counter, &layers, &fences, num_fences] {
- auto& syncpoint_manager = host1x.GetSyncpointManager();
+ auto& syncpoint_manager = system.Host1x().GetSyncpointManager();
if (num_fences == 0) {
renderer->Composite(layers);
}
@@ -322,7 +257,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);
}
@@ -331,23 +266,20 @@ struct GPU::Impl {
const auto wait_fence =
RequestSyncOperation([&] { out = renderer->GetAppletCaptureBuffer(); });
- gpu_thread.TickGPU();
+ gpu_thread.TickGPU(is_async);
WaitForSyncOperation(wait_fence);
return out;
}
- GPU& gpu;
Core::System& system;
- Host1x::Host1x& host1x;
std::unique_ptr<VideoCore::RendererBase> renderer;
- VideoCore::RasterizerInterface* rasterizer = nullptr;
const bool use_nvdec;
s32 new_channel_id{1};
/// Shader build notifier
- std::unique_ptr<VideoCore::ShaderNotify> shader_notify;
+ VideoCore::ShaderNotify shader_notify;
/// When true, we are about to shut down emulation session, so terminate outstanding tasks
std::atomic_bool shutting_down{};
@@ -371,7 +303,7 @@ struct GPU::Impl {
VideoCommon::GPUThread::ThreadManager gpu_thread;
std::unique_ptr<Core::Frontend::GraphicsContext> cpu_context;
- std::unique_ptr<Tegra::Control::Scheduler> scheduler;
+ Tegra::Control::Scheduler scheduler;
ankerl::unordered_dense::map<s32, std::shared_ptr<Tegra::Control::ChannelState>> channels;
Tegra::Control::ChannelState* current_channel;
s32 bound_channel{-1};
@@ -382,7 +314,8 @@ struct GPU::Impl {
};
GPU::GPU(Core::System& system, bool is_async, bool use_nvdec)
- : impl{std::make_unique<Impl>(*this, system, is_async, use_nvdec)} {}
+ : impl{std::make_unique<Impl>(system, is_async, use_nvdec)}
+{}
GPU::~GPU() = default;
@@ -423,8 +356,9 @@ void GPU::OnCommandListEnd() {
}
u64 GPU::RequestFlush(DAddr addr, std::size_t size) {
- return impl->RequestSyncOperation(
- [this, addr, size]() { impl->rasterizer->FlushRegion(addr, size); });
+ return impl->RequestSyncOperation([this, addr, size]() {
+ impl->renderer->ReadRasterizer()->FlushRegion(addr, size);
+ });
}
u64 GPU::CurrentSyncRequestFence() const {
@@ -441,52 +375,52 @@ void GPU::TickWork() {
/// Gets a mutable reference to the Host1x interface
Host1x::Host1x& GPU::Host1x() {
- return impl->host1x;
+ return impl->system.Host1x();
}
/// Gets an immutable reference to the Host1x interface.
const Host1x::Host1x& GPU::Host1x() const {
- return impl->host1x;
+ return impl->system.Host1x();
}
Engines::Maxwell3D& GPU::Maxwell3D() {
- return impl->Maxwell3D();
+ return impl->current_channel->payload->maxwell_3d;
}
const Engines::Maxwell3D& GPU::Maxwell3D() const {
- return impl->Maxwell3D();
+ return impl->current_channel->payload->maxwell_3d;
}
Engines::KeplerCompute& GPU::KeplerCompute() {
- return impl->KeplerCompute();
+ return impl->current_channel->payload->kepler_compute;
}
const Engines::KeplerCompute& GPU::KeplerCompute() const {
- return impl->KeplerCompute();
+ return impl->current_channel->payload->kepler_compute;
}
Tegra::DmaPusher& GPU::DmaPusher() {
- return impl->DmaPusher();
+ return impl->current_channel->payload->dma_pusher;
}
const Tegra::DmaPusher& GPU::DmaPusher() const {
- return impl->DmaPusher();
+ return impl->current_channel->payload->dma_pusher;
}
VideoCore::RendererBase& GPU::Renderer() {
- return impl->Renderer();
+ return *impl->renderer;
}
const VideoCore::RendererBase& GPU::Renderer() const {
- return impl->Renderer();
+ return *impl->renderer;
}
VideoCore::ShaderNotify& GPU::ShaderNotify() {
- return impl->ShaderNotify();
+ return impl->shader_notify;
}
const VideoCore::ShaderNotify& GPU::ShaderNotify() const {
- return impl->ShaderNotify();
+ return impl->shader_notify;
}
void GPU::RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers,
@@ -503,11 +437,11 @@ u64 GPU::GetTicks() const {
}
bool GPU::IsAsync() const {
- return impl->IsAsync();
+ return impl->is_async;
}
bool GPU::UseNvdec() const {
- return impl->UseNvdec();
+ return impl->use_nvdec;
}
void GPU::RendererFrameEndNotify() {
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index d7c8ac391c..50570b596d 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -19,8 +19,9 @@
namespace VideoCommon::GPUThread {
-ThreadManager::ThreadManager(Core::System& system_, bool is_async_)
- : system{system_}, is_async{is_async_} {}
+ThreadManager::ThreadManager(Core::System& system_)
+ : system{system_}
+{}
ThreadManager::~ThreadManager() = default;
@@ -39,7 +40,7 @@ void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Core::Fronten
break;
}
if (auto* submit_list = std::get_if<SubmitListCommand>(&next.data)) {
- scheduler.Push(submit_list->channel, std::move(submit_list->entries));
+ scheduler.Push(system.GPU(), submit_list->channel, std::move(submit_list->entries));
} else if (std::holds_alternative<GPUTickCommand>(next.data)) {
system.GPU().TickWork();
} else if (const auto* flush = std::get_if<FlushRegionCommand>(&next.data)) {
@@ -60,41 +61,40 @@ 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;
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
index ac1283a338..4c3fadce15 100644
--- a/src/video_core/gpu_thread.h
+++ b/src/video_core/gpu_thread.h
@@ -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 {
@@ -103,7 +104,7 @@ struct SynchState final {
/// Class used to manage the GPU thread
class ThreadManager final {
public:
- explicit ThreadManager(Core::System& system_, bool is_async_);
+ explicit ThreadManager(Core::System& system_);
~ThreadManager();
/// Creates and starts the GPU thread.
@@ -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;
};
diff --git a/src/video_core/host1x/control.cpp b/src/video_core/host1x/control.cpp
index 53b3063557..93ee57456b 100644
--- a/src/video_core/host1x/control.cpp
+++ b/src/video_core/host1x/control.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: 2021 yuzu Emulator Project
@@ -10,26 +10,22 @@
namespace Tegra::Host1x {
-Control::Control(Host1x& host1x_) : host1x(host1x_) {}
-
-Control::~Control() = default;
-
-void Control::ProcessMethod(Method method, u32 argument) {
+void Control::ProcessMethod(Host1x& host1x, Method method, u32 argument) {
switch (method) {
case Method::LoadSyncptPayload32:
syncpoint_value = argument;
break;
case Method::WaitSyncpt:
case Method::WaitSyncpt32:
- Execute(argument);
+ Execute(host1x, argument);
break;
default:
- UNIMPLEMENTED_MSG("Control method {:#X}", static_cast<u32>(method));
+ UNIMPLEMENTED_MSG("Control method {:#X}", u32(method));
break;
}
}
-void Control::Execute(u32 data) {
+void Control::Execute(Host1x& host1x, u32 data) {
LOG_TRACE(Service_NVDRV, "Control wait syncpt {} value {}", data, syncpoint_value);
host1x.GetSyncpointManager().WaitHost(data, syncpoint_value);
}
diff --git a/src/video_core/host1x/control.h b/src/video_core/host1x/control.h
index bd8a2d7ad4..4d87e63b32 100644
--- a/src/video_core/host1x/control.h
+++ b/src/video_core/host1x/control.h
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: 2021 yuzu Emulator Project
// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors
// SPDX-License-Identifier: GPL-3.0-or-later
@@ -19,17 +22,11 @@ public:
WaitSyncpt32 = 0x50,
};
- explicit Control(Host1x& host1x);
- ~Control();
-
/// Writes the method into the state, Invoke Execute() if encountered
- void ProcessMethod(Method method, u32 argument);
-
-private:
+ void ProcessMethod(Host1x& host1x, Method method, u32 argument);
/// For Host1x, execute is waiting on a syncpoint previously written into the state
- void Execute(u32 data);
+ void Execute(Host1x& host1x, u32 data);
- Host1x& host1x;
u32 syncpoint_value{};
};
diff --git a/src/video_core/host1x/host1x.cpp b/src/video_core/host1x/host1x.cpp
index b4e4a38c80..590b0e0ff2 100644
--- a/src/video_core/host1x/host1x.cpp
+++ b/src/video_core/host1x/host1x.cpp
@@ -27,22 +27,22 @@ void Host1x::StartDevice(s32 fd, ChannelType type, u32 syncpt) {
#ifdef YUZU_LEGACY
std::call_once(nvdec_first_init, []() {std::this_thread::sleep_for(std::chrono::milliseconds{500});}); // HACK: For Astroneer
#endif
- devices[fd] = std::make_unique<Tegra::Host1x::Nvdec>(*this, fd, syncpt);
+ devices[fd].emplace<Tegra::Host1x::Nvdec>(*this, fd, syncpt);
break;
case ChannelType::VIC:
#ifdef YUZU_LEGACY
std::call_once(vic_first_init, []() {std::this_thread::sleep_for(std::chrono::milliseconds{500});}); // HACK: For Astroneer
#endif
- devices[fd] = std::make_unique<Tegra::Host1x::Vic>(*this, fd, syncpt);
+ devices[fd].emplace<Tegra::Host1x::Vic>(*this, fd, syncpt);
break;
default:
- LOG_ERROR(HW_GPU, "Unimplemented host1x device {}", static_cast<u32>(type));
+ LOG_ERROR(HW_GPU, "Unimplemented host1x device {}", u32(type));
break;
}
}
void Host1x::StopDevice(s32 fd, ChannelType type) {
- devices.erase(fd);
+ devices[fd].emplace<std::monostate>();
}
} // namespace Tegra::Host1x
diff --git a/src/video_core/host1x/host1x.h b/src/video_core/host1x/host1x.h
index 838e749072..592ec449e8 100644
--- a/src/video_core/host1x/host1x.h
+++ b/src/video_core/host1x/host1x.h
@@ -8,10 +8,14 @@
#include <ankerl/unordered_dense.h>
#include <unordered_map>
-#include <queue>
+#include <variant>
#include "common/common_types.h"
+// fd types?
+#include "video_core/host1x/nvdec.h"
+#include "video_core/host1x/vic.h"
+
#include "common/address_space.h"
#include "video_core/cdma_pusher.h"
#include "video_core/host1x/gpu_device_memory_manager.h"
@@ -31,118 +35,90 @@ class Nvdec;
class FrameQueue {
public:
+ struct FrameDevice {
+ std::deque<std::pair<u64, std::shared_ptr<FFmpeg::Frame>>> m_presentation_order;
+ std::unordered_map<u64, std::shared_ptr<FFmpeg::Frame>> m_decode_order;
+ };
+
void Open(s32 fd) {
std::scoped_lock l{m_mutex};
- m_presentation_order.insert({fd, {}});
- m_decode_order.insert({fd, {}});
+ m_frame_devices.insert_or_assign(fd, FrameDevice{});
}
void Close(s32 fd) {
std::scoped_lock l{m_mutex};
- m_presentation_order.erase(fd);
- m_decode_order.erase(fd);
+ m_frame_devices.erase(fd);
}
s32 VicFindNvdecFdFromOffset(u64 search_offset) {
std::scoped_lock l{m_mutex};
- for (auto& map : m_presentation_order) {
- for (auto& [offset, frame] : map.second) {
- if (offset == search_offset) {
- return map.first;
- }
- }
- }
- for (auto& map : m_decode_order) {
- for (auto& [offset, frame] : map.second) {
- if (offset == search_offset) {
- return map.first;
- }
- }
+ for (auto const& [fd, dev] : m_frame_devices) {
+ for (auto const& [offset, frame] : dev.m_presentation_order)
+ if (offset == search_offset)
+ return fd;
+ for (auto const& [offset, frame] : dev.m_decode_order)
+ if (offset == search_offset)
+ return fd;
}
return -1;
}
void PushPresentOrder(s32 fd, u64 offset, std::shared_ptr<FFmpeg::Frame>&& frame) {
std::scoped_lock l{m_mutex};
- auto map = m_presentation_order.find(fd);
- if (map == m_presentation_order.end()) {
- return;
- }
-
- if (map->second.size() >= MAX_PRESENT_QUEUE) {
- map->second.pop_front();
+ if (auto const it = m_frame_devices.find(fd); it != m_frame_devices.end()) {
+ if (it->second.m_presentation_order.size() >= MAX_PRESENT_QUEUE)
+ it->second.m_presentation_order.pop_front();
+ it->second.m_presentation_order.emplace_back(offset, std::move(frame));
}
-
- map->second.emplace_back(offset, std::move(frame));
}
void PushDecodeOrder(s32 fd, u64 offset, std::shared_ptr<FFmpeg::Frame>&& frame) {
std::scoped_lock l{m_mutex};
- auto map = m_decode_order.find(fd);
- if (map == m_decode_order.end()) {
- return;
- }
-
- map->second.insert_or_assign(offset, std::move(frame));
-
- if (map->second.size() > MAX_DECODE_MAP) {
- auto it = map->second.begin();
- std::advance(it, map->second.size() - MAX_DECODE_MAP);
- map->second.erase(map->second.begin(), it);
+ if (auto const it = m_frame_devices.find(fd); it != m_frame_devices.end()) {
+ it->second.m_decode_order.insert_or_assign(offset, std::move(frame));
+ if (it->second.m_decode_order.size() > MAX_DECODE_MAP) {
+ auto it2 = it->second.m_decode_order.begin();
+ std::advance(it2, it->second.m_decode_order.size() - MAX_DECODE_MAP);
+ it->second.m_decode_order.erase(it->second.m_decode_order.begin(), it2);
+ }
}
}
std::shared_ptr<FFmpeg::Frame> GetFrame(s32 fd, u64 offset) {
- if (fd == -1) {
- return {};
- }
-
- std::scoped_lock l{m_mutex};
-
- auto present_map = m_presentation_order.find(fd);
- if (present_map != m_presentation_order.end() && !present_map->second.empty()) {
- return GetPresentOrderLocked(fd);
- }
-
- auto decode_map = m_decode_order.find(fd);
- if (decode_map != m_decode_order.end() && !decode_map->second.empty()) {
- return GetDecodeOrderLocked(fd, offset);
+ if (fd != -1) {
+ std::scoped_lock l{m_mutex};
+ if (auto const it = m_frame_devices.find(fd); it != m_frame_devices.end()) {
+ if (it->second.m_presentation_order.size() > 0)
+ return GetPresentOrderLocked(fd);
+ if (it->second.m_decode_order.size() > 0)
+ return GetDecodeOrderLocked(fd, offset);
+ }
}
-
return {};
}
private:
std::shared_ptr<FFmpeg::Frame> GetPresentOrderLocked(s32 fd) {
- auto map = m_presentation_order.find(fd);
- if (map == m_presentation_order.end() || map->second.empty()) {
- return {};
+ if (auto const it = m_frame_devices.find(fd); it != m_frame_devices.end()) {
+ auto frame = std::move(it->second.m_presentation_order.front().second);
+ it->second.m_presentation_order.pop_front();
+ return frame;
}
-
- auto frame = std::move(map->second.front().second);
- map->second.pop_front();
- return frame;
+ return {};
}
std::shared_ptr<FFmpeg::Frame> GetDecodeOrderLocked(s32 fd, u64 offset) {
- auto map = m_decode_order.find(fd);
- if (map == m_decode_order.end() || map->second.empty()) {
- return {};
- }
-
- auto it = map->second.find(offset);
- if (it == map->second.end()) {
- return {};
+ if (auto const it = m_frame_devices.find(fd); it != m_frame_devices.end()) {
+ if (auto const it2 = it->second.m_decode_order.find(offset); it2 != it->second.m_decode_order.end()) {
+ // TODO: this "mapped" prevents us from fully embracing ankerl
+ return std::move(it->second.m_decode_order.extract(it2).mapped());
+ }
}
- // TODO: this "mapped" prevents us from fully embracing ankerl
- return std::move(map->second.extract(it).mapped());
+ return {};
}
- using FramePtr = std::shared_ptr<FFmpeg::Frame>;
-
std::mutex m_mutex{};
- ankerl::unordered_dense::map<s32, std::deque<std::pair<u64, FramePtr>>> m_presentation_order;
- ankerl::unordered_dense::map<s32, std::unordered_map<u64, FramePtr>> m_decode_order;
+ ankerl::unordered_dense::map<s32, FrameDevice> m_frame_devices;
static constexpr size_t MAX_PRESENT_QUEUE = 100;
static constexpr size_t MAX_DECODE_MAP = 200;
@@ -196,11 +172,11 @@ public:
void StopDevice(s32 fd, ChannelType type);
void PushEntries(s32 fd, ChCommandHeaderList&& entries) {
- auto it = devices.find(fd);
- if (it == devices.end()) {
- return;
+ if (auto const nvdec = std::get_if<Tegra::Host1x::Nvdec>(&devices[fd])) {
+ nvdec->PushEntries(std::move(entries));
+ } else if (auto const vic = std::get_if<Tegra::Host1x::Vic>(&devices[fd])) {
+ vic->PushEntries(std::move(entries));
}
- it->second->PushEntries(std::move(entries));
}
Core::System& system;
@@ -209,7 +185,11 @@ public:
Tegra::MemoryManager gmmu_manager;
Common::FlatAllocator<u32, 0, 32> allocator;
FrameQueue frame_queue;
- ankerl::unordered_dense::map<s32, std::unique_ptr<CDmaPusher>> devices;
+ std::array<std::variant<
+ std::monostate,
+ Tegra::Host1x::Nvdec,
+ Tegra::Host1x::Vic
+ >, 1024> devices;
#ifdef YUZU_LEGACY
std::once_flag nvdec_first_init;
std::once_flag vic_first_init;
diff --git a/src/video_core/host1x/vic.cpp b/src/video_core/host1x/vic.cpp
index bafbb0ed25..f7830a3a45 100644
--- a/src/video_core/host1x/vic.cpp
+++ b/src/video_core/host1x/vic.cpp
@@ -407,15 +407,15 @@ void Vic::ReadInterlacedY8__V8U8_N420(const SlotStruct& slot, std::span<const Pl
};
switch (slot.config.deinterlace_mode) {
- case DXVAHD_DEINTERLACE_MODE_PRIVATE::WEAVE:
+ case DxvhadDeinterlaceModePrivate::Weave:
// Due to the fact that we do not write to memory in nvdec, we cannot use Weave as it
// relies on the previous frame.
DecodeBobField();
break;
- case DXVAHD_DEINTERLACE_MODE_PRIVATE::BOB_FIELD:
+ case DxvhadDeinterlaceModePrivate::BobField:
DecodeBobField();
break;
- case DXVAHD_DEINTERLACE_MODE_PRIVATE::DISI1:
+ case DxvhadDeinterlaceModePrivate::Disi1:
// Due to the fact that we do not write to memory in nvdec, we cannot use DISI1 as it
// relies on previous/next frames.
DecodeBobField();
@@ -431,13 +431,13 @@ void Vic::ReadInterlacedY8__V8U8_N420(const SlotStruct& slot, std::span<const Pl
void Vic::ReadY8__V8U8_N420(const SlotStruct& slot, std::span<const PlaneOffsets> offsets, std::shared_ptr<const FFmpeg::Frame> frame, bool planar) noexcept {
switch (slot.config.frame_format) {
- case DXVAHD_FRAME_FORMAT::PROGRESSIVE:
+ case DxvhadFrameFormat::Progressive:
ReadProgressiveY8__V8U8_N420(slot, offsets, std::move(frame), planar, false);
break;
- case DXVAHD_FRAME_FORMAT::TOP_FIELD:
+ case DxvhadFrameFormat::TopField:
ReadInterlacedY8__V8U8_N420(slot, offsets, std::move(frame), planar, true);
break;
- case DXVAHD_FRAME_FORMAT::BOTTOM_FIELD:
+ case DxvhadFrameFormat::BottomField:
ReadInterlacedY8__V8U8_N420(slot, offsets, std::move(frame), planar, false);
break;
default:
@@ -860,7 +860,7 @@ void Vic::WriteY8__V8U8_N420(const OutputSurfaceConfig& output_surface_config) n
};
switch (output_surface_config.out_block_kind) {
- case BLK_KIND::GENERIC_16Bx2: {
+ case BlkKind::Generic_16Bx2: {
u32 const block_height = u32(output_surface_config.out_block_height);
auto const out_luma_swizzle_size = Texture::CalculateSize(true, BytesPerPixel, out_luma_width, out_luma_height, 1, block_height, 0);
auto const out_chroma_swizzle_size = Texture::CalculateSize(true, BytesPerPixel * 2, out_chroma_width, out_chroma_height, 1, block_height, 0);
@@ -889,7 +889,7 @@ void Vic::WriteY8__V8U8_N420(const OutputSurfaceConfig& output_surface_config) n
Texture::SwizzleTexture(out_chroma, chroma_scratch, BytesPerPixel, out_chroma_width, out_chroma_height, 1, block_height, 0, 1);
}
} break;
- case BLK_KIND::PITCH: {
+ case BlkKind::Pitch: {
LOG_TRACE(HW_GPU, "Writing Y8__V8U8_N420 swizzled frame\n"
"\tinput surface {}x{} stride {} size {:#X}\n"
"\toutput luma {}x{} stride {} size {:#X} block height {} swizzled size 0x{:X}\n",
@@ -1032,7 +1032,7 @@ void Vic::WriteABGR(const OutputSurfaceConfig& output_surface_config, VideoPixel
};
switch (output_surface_config.out_block_kind) {
- case BLK_KIND::GENERIC_16Bx2: {
+ case BlkKind::Generic_16Bx2: {
const u32 block_height = u32(output_surface_config.out_block_height);
auto const out_swizzle_size = Texture::CalculateSize(true, BytesPerPixel, out_luma_width, out_luma_height, 1, block_height, 0);
LOG_TRACE(HW_GPU, "Writing ABGR swizzled frame\n"
@@ -1051,7 +1051,7 @@ void Vic::WriteABGR(const OutputSurfaceConfig& output_surface_config, VideoPixel
Texture::SwizzleTexture(out_luma, luma_scratch, BytesPerPixel, out_luma_width, out_luma_height, 1, block_height, 0, 1);
}
} break;
- case BLK_KIND::PITCH: {
+ case BlkKind::Pitch: {
LOG_TRACE(HW_GPU, "Writing ABGR pitch frame\n"
"\tinput surface {}x{} stride {} size {:#X}"
"\toutput surface {}x{} stride {} size {:#X}",
diff --git a/src/video_core/host1x/vic.h b/src/video_core/host1x/vic.h
index d728b38f91..23f3f66c18 100644
--- a/src/video_core/host1x/vic.h
+++ b/src/video_core/host1x/vic.h
@@ -6,16 +6,12 @@
#pragma once
-#include <condition_variable>
-#include <functional>
#include <memory>
-#include <mutex>
-#include <thread>
#include "common/common_types.h"
#include "common/scratch_buffer.h"
#include "video_core/cdma_pusher.h"
-#include "video_core/host1x/host1x.h"
+#include "video_core/host1x/ffmpeg.h"
namespace Tegra::Host1x {
class Host1x;
@@ -138,52 +134,53 @@ enum SurfaceIndex : u32 {
CombinedMotion = 7,
};
-enum class DXVAHD_ALPHA_FILL_MODE : u32 {
- OPAQUE = 0,
- BACKGROUND = 1,
- DESTINATION = 2,
- SOURCE_STREAM = 3,
- COMPOSITED = 4,
- SOURCE_ALPHA = 5,
+// Note: these will inevitably collide with Win32 defines if you use their UPPER_SNAKE_CASE naming
+enum class DxvhadAlphaFillMode : u32 {
+ Opaque = 0,
+ Background = 1,
+ Destination = 2,
+ SourceStream = 3,
+ Composited = 4,
+ SourceAlpha = 5,
};
-enum class DXVAHD_FRAME_FORMAT : u64 {
- PROGRESSIVE = 0,
- INTERLACED_TOP_FIELD_FIRST = 1,
- INTERLACED_BOTTOM_FIELD_FIRST = 2,
- TOP_FIELD = 3,
- BOTTOM_FIELD = 4,
- SUBPIC_PROGRESSIVE = 5,
- SUBPIC_INTERLACED_TOP_FIELD_FIRST = 6,
- SUBPIC_INTERLACED_BOTTOM_FIELD_FIRST = 7,
- SUBPIC_TOP_FIELD = 8,
- SUBPIC_BOTTOM_FIELD = 9,
- TOP_FIELD_CHROMA_BOTTOM = 10,
- BOTTOM_FIELD_CHROMA_TOP = 11,
- SUBPIC_TOP_FIELD_CHROMA_BOTTOM = 12,
- SUBPIC_BOTTOM_FIELD_CHROMA_TOP = 13,
+enum class DxvhadFrameFormat : u64 {
+ Progressive = 0,
+ InterlacedTopFieldFirst = 1,
+ InterlacedBottomFieldFirst = 2,
+ TopField = 3,
+ BottomField = 4,
+ SubpicProgressive = 5,
+ SubpicInterlacedTopFieldFirst = 6,
+ SubpicInterlacedBottomFieldFirst = 7,
+ SubpicTopField = 8,
+ SubpicBottomField = 9,
+ TopFieldChromaBottom = 10,
+ BottomFieldChromaTop = 11,
+ SubpicTopFieldChromaBottom = 12,
+ SubpicBottomFieldChromaTop = 13,
};
-enum class DXVAHD_DEINTERLACE_MODE_PRIVATE : u64 {
- WEAVE = 0,
- BOB_FIELD = 1,
- BOB = 2,
- NEWBOB = 3,
- DISI1 = 4,
- WEAVE_LUMA_BOB_FIELD_CHROMA = 5,
- MAX = 0xF,
+enum class DxvhadDeinterlaceModePrivate : u64 {
+ Weave = 0,
+ BobField = 1,
+ Bob = 2,
+ Newbob = 3,
+ Disi1 = 4,
+ WeaveLumaBobFieldChroma = 5,
+ Max = 0xF,
};
-enum class BLK_KIND {
- PITCH = 0,
- GENERIC_16Bx2 = 1,
+enum class BlkKind {
+ Pitch = 0,
+ Generic_16Bx2 = 1,
// These are unsupported in the vic
- BL_NAIVE = 2,
- BL_KEPLER_XBAR_RAW = 3,
- VP2_TILED = 15,
+ BlNaive = 2,
+ BlKeplerXbarRaw = 3,
+ Vp2Tiled = 15,
};
-enum class BLEND_SRCFACTC : u32 {
+enum class BlendSrcFactC : u32 {
K1 = 0,
K1_TIMES_DST = 1,
NEG_K1_TIMES_DST = 2,
@@ -191,7 +188,7 @@ enum class BLEND_SRCFACTC : u32 {
ZERO = 4,
};
-enum class BLEND_DSTFACTC : u32 {
+enum class BlendDstFactC : u32 {
K1 = 0,
K2 = 1,
K1_TIMES_DST = 2,
@@ -201,7 +198,7 @@ enum class BLEND_DSTFACTC : u32 {
ONE = 6,
};
-enum class BLEND_SRCFACTA : u32 {
+enum class BlendSrcFactA : u32 {
K1 = 0,
K2 = 1,
NEG_K1_TIMES_DST = 2,
@@ -209,7 +206,7 @@ enum class BLEND_SRCFACTA : u32 {
MAX = 7,
};
-enum class BLEND_DSTFACTA : u32 {
+enum class BlendDstFactA : u32 {
K2 = 0,
NEG_K1_TIMES_SRC = 1,
ZERO = 2,
@@ -232,7 +229,7 @@ static_assert(sizeof(PipeConfig) == 0x10, "PipeConfig has the wrong size!");
struct OutputConfig {
union {
- BitField<0, 3, DXVAHD_ALPHA_FILL_MODE> alpha_fill_mode;
+ BitField<0, 3, DxvhadAlphaFillMode> alpha_fill_mode;
BitField<3, 3, u64> alpha_fill_slot;
BitField<6, 10, u64> background_a;
BitField<16, 10, u64> background_r;
@@ -265,7 +262,7 @@ struct OutputSurfaceConfig {
BitField<0, 7, VideoPixelFormat> out_pixel_format;
BitField<7, 2, u32> out_chroma_loc_horiz;
BitField<9, 2, u32> out_chroma_loc_vert;
- BitField<11, 4, BLK_KIND> out_block_kind;
+ BitField<11, 4, BlkKind> out_block_kind;
BitField<15, 4, u32> out_block_height; // in gobs, log2
BitField<19, 3, u32> reserved0;
BitField<22, 10, u32> reserved1;
@@ -365,7 +362,7 @@ struct SlotConfig {
BitField<14, 1, u64> prev_prev_motion_field_enable;
BitField<15, 1, u64> combined_motion_field_enable;
- BitField<16, 4, DXVAHD_FRAME_FORMAT> frame_format;
+ BitField<16, 4, DxvhadFrameFormat> frame_format;
BitField<20, 2, u64> filter_length_y; // 0: 1-tap, 1: 2-tap, 2: 5-tap, 3: 10-tap
BitField<22, 2, u64> filter_length_x;
BitField<24, 12, u64> panoramic;
@@ -377,7 +374,7 @@ struct SlotConfig {
BitField<10, 10, u64> filter_detail;
BitField<20, 10, u64> chroma_noise;
BitField<30, 10, u64> chroma_detail;
- BitField<40, 4, DXVAHD_DEINTERLACE_MODE_PRIVATE> deinterlace_mode;
+ BitField<40, 4, DxvhadDeinterlaceModePrivate> deinterlace_mode;
BitField<44, 3, u64> motion_accumulation_weight;
BitField<47, 11, u64> noise_iir;
BitField<58, 4, u64> light_level;
@@ -484,13 +481,13 @@ struct BlendingSlotStruct {
BitField<26, 6, u32> reserved1;
};
union {
- BitField<0, 3, BLEND_SRCFACTC> src_factor_color_match_select;
+ BitField<0, 3, BlendSrcFactC> src_factor_color_match_select;
BitField<3, 1, u32> reserved2;
- BitField<4, 3, BLEND_DSTFACTC> dst_factor_color_match_select;
+ BitField<4, 3, BlendDstFactC> dst_factor_color_match_select;
BitField<7, 1, u32> reserved3;
- BitField<8, 3, BLEND_SRCFACTA> src_factor_a_match_select;
+ BitField<8, 3, BlendSrcFactA> src_factor_a_match_select;
BitField<11, 1, u32> reserved4;
- BitField<12, 3, BLEND_DSTFACTA> dst_factor_a_match_select;
+ BitField<12, 3, BlendDstFactA> dst_factor_a_match_select;
BitField<15, 1, u32> reserved5;
BitField<16, 4, u32> reserved6;
BitField<20, 4, u32> reserved7;
@@ -624,8 +621,8 @@ private:
VicRegisters regs{};
Common::ScratchBuffer<u8> swizzle_scratch;
- Common::ScratchBuffer<Pixel> output_surface;
- Common::ScratchBuffer<Pixel> slot_surface;
+ Common::ScratchBuffer<Tegra::Host1x::Pixel> output_surface;
+ Common::ScratchBuffer<Tegra::Host1x::Pixel> slot_surface;
Common::ScratchBuffer<u8> luma_scratch;
Common::ScratchBuffer<u8> chroma_scratch;
diff --git a/src/video_core/macro.cpp b/src/video_core/macro.cpp
index 76a054665c..2833f95ee9 100644
--- a/src/video_core/macro.cpp
+++ b/src/video_core/macro.cpp
@@ -64,10 +64,10 @@ bool IsTopologySafe(Maxwell3D::Regs::PrimitiveTopology topology) {
} // Anonymous namespace
-void HLE_DrawArraysIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
+void HLE_DrawArraysIndirect::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0]);
if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) {
- Fallback(maxwell3d, parameters);
+ Fallback(system, maxwell3d, parameters);
return;
}
@@ -93,7 +93,7 @@ void HLE_DrawArraysIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::span<co
maxwell3d.replace_table.clear();
}
}
-void HLE_DrawArraysIndirect::Fallback(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters) {
+void HLE_DrawArraysIndirect::Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters) {
SCOPE_EXIT {
if (extended) {
maxwell3d.engine_state = Maxwell3D::EngineHint::None;
@@ -123,10 +123,10 @@ void HLE_DrawArraysIndirect::Fallback(Engines::Maxwell3D& maxwell3d, std::span<c
}
}
-void HLE_DrawIndexedIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
+void HLE_DrawIndexedIndirect::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0]);
if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) {
- Fallback(maxwell3d, parameters);
+ Fallback(system, maxwell3d, parameters);
return;
}
@@ -161,7 +161,7 @@ void HLE_DrawIndexedIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::span<c
maxwell3d.replace_table.clear();
}
}
-void HLE_DrawIndexedIndirect::Fallback(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters) {
+void HLE_DrawIndexedIndirect::Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters) {
maxwell3d.RefreshParameters();
const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
const u32 element_base = parameters[4];
@@ -184,7 +184,7 @@ void HLE_DrawIndexedIndirect::Fallback(Engines::Maxwell3D& maxwell3d, std::span<
maxwell3d.replace_table.clear();
}
}
-void HLE_MultiLayerClear::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
+void HLE_MultiLayerClear::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
maxwell3d.RefreshParameters();
ASSERT(parameters.size() == 1);
@@ -196,47 +196,44 @@ void HLE_MultiLayerClear::Execute(Engines::Maxwell3D& maxwell3d, std::span<const
maxwell3d.regs.clear_surface.raw = clear_params.raw;
maxwell3d.draw_manager.Clear(maxwell3d, num_layers);
}
-void HLE_MultiDrawIndexedIndirectCount::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
+void HLE_MultiDrawIndexedIndirectCount::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
const auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[2]);
- if (!IsTopologySafe(topology)) {
- Fallback(maxwell3d, parameters);
- return;
- }
-
- const u32 start_indirect = parameters[0];
- const u32 end_indirect = parameters[1];
- if (start_indirect >= end_indirect) {
- // Nothing to do.
- return;
+ if (IsTopologySafe(topology)) {
+ const u32 start_indirect = parameters[0];
+ const u32 end_indirect = parameters[1];
+ if (start_indirect >= end_indirect) {
+ // Nothing to do.
+ return;
+ }
+ const u32 padding = parameters[3]; // padding is in words
+ // size of each indirect segment
+ const u32 indirect_words = 5 + padding;
+ const u32 stride = indirect_words * sizeof(u32);
+ const std::size_t draw_count = end_indirect - start_indirect;
+ const u32 estimate = u32(maxwell3d.EstimateIndexBufferSize());
+ maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
+ auto& params = maxwell3d.draw_manager.indirect_state;
+ params.is_byte_count = false;
+ params.is_indexed = true;
+ params.include_count = true;
+ params.count_start_address = maxwell3d.GetMacroAddress(4);
+ params.indirect_start_address = maxwell3d.GetMacroAddress(5);
+ params.buffer_size = stride * draw_count;
+ params.max_draw_counts = draw_count;
+ params.stride = stride;
+ maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
+ maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro;
+ maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex);
+ maxwell3d.SetHLEReplacementAttributeType(0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance);
+ maxwell3d.SetHLEReplacementAttributeType(0, 0x648, Maxwell3D::HLEReplacementAttributeType::DrawID);
+ maxwell3d.draw_manager.DrawIndexedIndirect(maxwell3d, topology, 0, estimate);
+ maxwell3d.engine_state = Maxwell3D::EngineHint::None;
+ maxwell3d.replace_table.clear();
+ } else {
+ Fallback(system, maxwell3d, parameters);
}
-
- const u32 padding = parameters[3]; // padding is in words
-
- // size of each indirect segment
- const u32 indirect_words = 5 + padding;
- const u32 stride = indirect_words * sizeof(u32);
- const std::size_t draw_count = end_indirect - start_indirect;
- const u32 estimate = static_cast<u32>(maxwell3d.EstimateIndexBufferSize());
- maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
- auto& params = maxwell3d.draw_manager.indirect_state;
- params.is_byte_count = false;
- params.is_indexed = true;
- params.include_count = true;
- params.count_start_address = maxwell3d.GetMacroAddress(4);
- params.indirect_start_address = maxwell3d.GetMacroAddress(5);
- params.buffer_size = stride * draw_count;
- params.max_draw_counts = draw_count;
- params.stride = stride;
- maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
- maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro;
- maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex);
- maxwell3d.SetHLEReplacementAttributeType(0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance);
- maxwell3d.SetHLEReplacementAttributeType(0, 0x648, Maxwell3D::HLEReplacementAttributeType::DrawID);
- maxwell3d.draw_manager.DrawIndexedIndirect(maxwell3d, topology, 0, estimate);
- maxwell3d.engine_state = Maxwell3D::EngineHint::None;
- maxwell3d.replace_table.clear();
}
-void HLE_MultiDrawIndexedIndirectCount::Fallback(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters) {
+void HLE_MultiDrawIndexedIndirectCount::Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters) {
SCOPE_EXIT {
// Clean everything.
maxwell3d.regs.vertex_id_base = 0x0;
@@ -250,7 +247,7 @@ void HLE_MultiDrawIndexedIndirectCount::Fallback(Engines::Maxwell3D& maxwell3d,
// Nothing to do.
return;
}
- const auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[2]);
+ const auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[2]);
const u32 padding = parameters[3];
const std::size_t max_draws = parameters[4];
const u32 indirect_words = 5 + padding;
@@ -265,41 +262,41 @@ void HLE_MultiDrawIndexedIndirectCount::Fallback(Engines::Maxwell3D& maxwell3d,
maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro;
maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex);
maxwell3d.SetHLEReplacementAttributeType(0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance);
- maxwell3d.CallMethod(0x8e3, 0x648, true);
- maxwell3d.CallMethod(0x8e4, static_cast<u32>(index), true);
+ maxwell3d.CallMethod(system, 0x8e3, 0x648, true);
+ maxwell3d.CallMethod(system, 0x8e4, u32(index), true);
maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
maxwell3d.draw_manager.DrawIndex(maxwell3d, topology, parameters[base + 2], parameters[base], base_vertex, base_instance, parameters[base + 1]);
}
}
-void HLE_DrawIndirectByteCount::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
+void HLE_DrawIndirectByteCount::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
const bool force = maxwell3d.Rasterizer().HasDrawTransformFeedback();
- if (!force) {
- Fallback(maxwell3d, parameters);
- return;
+ if (force) {
+ auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[0] & 0xFFFFU);
+ auto& params = maxwell3d.draw_manager.indirect_state;
+ params.is_byte_count = true;
+ params.is_indexed = false;
+ params.include_count = false;
+ params.count_start_address = 0;
+ params.indirect_start_address = maxwell3d.GetMacroAddress(2);
+ params.buffer_size = 4;
+ params.max_draw_counts = 1;
+ params.stride = parameters[1];
+ maxwell3d.regs.draw.begin = parameters[0];
+ maxwell3d.regs.draw_auto_stride = parameters[1];
+ maxwell3d.regs.draw_auto_byte_count = parameters[2];
+ maxwell3d.draw_manager.DrawArrayIndirect(maxwell3d, topology);
+ } else {
+ Fallback(system, maxwell3d, parameters);
}
- auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[0] & 0xFFFFU);
- auto& params = maxwell3d.draw_manager.indirect_state;
- params.is_byte_count = true;
- params.is_indexed = false;
- params.include_count = false;
- params.count_start_address = 0;
- params.indirect_start_address = maxwell3d.GetMacroAddress(2);
- params.buffer_size = 4;
- params.max_draw_counts = 1;
- params.stride = parameters[1];
- maxwell3d.regs.draw.begin = parameters[0];
- maxwell3d.regs.draw_auto_stride = parameters[1];
- maxwell3d.regs.draw_auto_byte_count = parameters[2];
- maxwell3d.draw_manager.DrawArrayIndirect(maxwell3d, topology);
}
-void HLE_DrawIndirectByteCount::Fallback(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters) {
+void HLE_DrawIndirectByteCount::Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters) {
maxwell3d.RefreshParameters();
maxwell3d.regs.draw.begin = parameters[0];
maxwell3d.regs.draw_auto_stride = parameters[1];
maxwell3d.regs.draw_auto_byte_count = parameters[2];
maxwell3d.draw_manager.DrawArray(maxwell3d, maxwell3d.regs.draw.topology, 0, maxwell3d.regs.draw_auto_byte_count / maxwell3d.regs.draw_auto_stride, 0, 1);
}
-void HLE_C713C83D8F63CCF3::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
+void HLE_C713C83D8F63CCF3::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
maxwell3d.RefreshParameters();
const u32 offset = (parameters[0] & 0x3FFFFFFF) << 2;
const u32 address = maxwell3d.regs.shadow_scratch[24];
@@ -309,7 +306,7 @@ void HLE_C713C83D8F63CCF3::Execute(Engines::Maxwell3D& maxwell3d, std::span<cons
const_buffer.address_low = address << 8;
const_buffer.offset = offset;
}
-void HLE_D7333D26E0A93EDE::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
+void HLE_D7333D26E0A93EDE::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
maxwell3d.RefreshParameters();
const size_t index = parameters[0];
const u32 address = maxwell3d.regs.shadow_scratch[42 + index];
@@ -319,7 +316,7 @@ void HLE_D7333D26E0A93EDE::Execute(Engines::Maxwell3D& maxwell3d, std::span<cons
const_buffer.address_high = (address >> 24) & 0xFF;
const_buffer.address_low = address << 8;
}
-void HLE_BindShader::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
+void HLE_BindShader::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
maxwell3d.RefreshParameters();
auto& regs = maxwell3d.regs;
const u32 index = parameters[0];
@@ -343,7 +340,7 @@ void HLE_BindShader::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32>
bind_group.raw_config = 0x11;
maxwell3d.ProcessCBBind(bind_group_id);
}
-void HLE_SetRasterBoundingBox::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
+void HLE_SetRasterBoundingBox::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
maxwell3d.RefreshParameters();
const u32 raster_mode = parameters[0];
auto& regs = maxwell3d.regs;
@@ -352,7 +349,7 @@ void HLE_SetRasterBoundingBox::Execute(Engines::Maxwell3D& maxwell3d, std::span<
regs.raster_bounding_box.raw = raster_mode & 0xFFFFF00F;
regs.raster_bounding_box.pad.Assign(scratch_data & raster_enabled);
}
-void HLE_ClearConstBuffer::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
+void HLE_ClearConstBuffer::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
static constexpr std::array<u32, 0x7000> zeroes{}; //must be bigger than either 7000 or 5F00
maxwell3d.RefreshParameters();
auto& regs = maxwell3d.regs;
@@ -362,7 +359,7 @@ void HLE_ClearConstBuffer::Execute(Engines::Maxwell3D& maxwell3d, std::span<cons
regs.const_buffer.offset = 0;
maxwell3d.ProcessCBMultiData(zeroes.data(), parameters[2] * 4);
}
-void HLE_ClearMemory::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
+void HLE_ClearMemory::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
maxwell3d.RefreshParameters();
const u32 needed_memory = parameters[2] / sizeof(u32);
if (needed_memory > zero_memory.size()) {
@@ -373,10 +370,10 @@ void HLE_ClearMemory::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32
regs.upload.line_count = 1;
regs.upload.dest.address_high = parameters[0];
regs.upload.dest.address_low = parameters[1];
- maxwell3d.CallMethod(size_t(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true);
- maxwell3d.CallMultiMethod(size_t(MAXWELL3D_REG_INDEX(inline_data)), zero_memory.data(), needed_memory, needed_memory);
+ maxwell3d.CallMethod(system, size_t(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true);
+ maxwell3d.CallMultiMethod(system, size_t(MAXWELL3D_REG_INDEX(inline_data)), zero_memory.data(), needed_memory, needed_memory);
}
-void HLE_TransformFeedbackSetup::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
+void HLE_TransformFeedbackSetup::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
maxwell3d.RefreshParameters();
auto& regs = maxwell3d.regs;
regs.transform_feedback_enabled = 1;
@@ -388,8 +385,8 @@ void HLE_TransformFeedbackSetup::Execute(Engines::Maxwell3D& maxwell3d, std::spa
regs.upload.line_count = 1;
regs.upload.dest.address_high = parameters[0];
regs.upload.dest.address_low = parameters[1];
- maxwell3d.CallMethod(size_t(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true);
- maxwell3d.CallMethod(size_t(MAXWELL3D_REG_INDEX(inline_data)), regs.transform_feedback.controls[0].stride, true);
+ maxwell3d.CallMethod(system, size_t(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true);
+ maxwell3d.CallMethod(system, size_t(MAXWELL3D_REG_INDEX(inline_data)), regs.transform_feedback.controls[0].stride, true);
maxwell3d.Rasterizer().RegisterTransformFeedback(regs.upload.dest.Address());
}
@@ -429,7 +426,7 @@ void HLE_TransformFeedbackSetup::Execute(Engines::Maxwell3D& maxwell3d, std::spa
}
}
-void MacroInterpreterImpl::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> params, u32 method) {
+void MacroInterpreterImpl::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> params, u32 method) {
Reset();
registers[1] = params[0];
@@ -439,7 +436,7 @@ void MacroInterpreterImpl::Execute(Engines::Maxwell3D& maxwell3d, std::span<cons
// Execute the code until we hit an exit condition.
bool keep_executing = true;
while (keep_executing) {
- keep_executing = Step(maxwell3d, false);
+ keep_executing = Step(system, maxwell3d, false);
}
// Assert the the macro used all the input parameters
@@ -462,7 +459,7 @@ void MacroInterpreterImpl::Reset() {
/// @brief Executes a single macro instruction located at the current program counter. Returns whether
/// the interpreter should keep running.
/// @param is_delay_slot Whether the current step is being executed due to a delay slot in a previous instruction.
-bool MacroInterpreterImpl::Step(Engines::Maxwell3D& maxwell3d, bool is_delay_slot) {
+bool MacroInterpreterImpl::Step(Core::System& system, Engines::Maxwell3D& maxwell3d, bool is_delay_slot) {
u32 base_address = pc;
Macro::Opcode opcode = GetOpcode();
@@ -478,11 +475,11 @@ bool MacroInterpreterImpl::Step(Engines::Maxwell3D& maxwell3d, bool is_delay_slo
switch (opcode.operation) {
case Macro::Operation::ALU: {
u32 result = GetALUResult(opcode.alu_operation, GetRegister(opcode.src_a), GetRegister(opcode.src_b));
- ProcessResult(maxwell3d, opcode.result_operation, opcode.dst, result);
+ ProcessResult(system, maxwell3d, opcode.result_operation, opcode.dst, result);
break;
}
case Macro::Operation::AddImmediate: {
- ProcessResult(maxwell3d, opcode.result_operation, opcode.dst, GetRegister(opcode.src_a) + opcode.immediate);
+ ProcessResult(system, maxwell3d, opcode.result_operation, opcode.dst, GetRegister(opcode.src_a) + opcode.immediate);
break;
}
case Macro::Operation::ExtractInsert: {
@@ -492,7 +489,7 @@ bool MacroInterpreterImpl::Step(Engines::Maxwell3D& maxwell3d, bool is_delay_slo
src = (src >> opcode.bf_src_bit) & opcode.GetBitfieldMask();
dst &= ~(opcode.GetBitfieldMask() << opcode.bf_dst_bit);
dst |= src << opcode.bf_dst_bit;
- ProcessResult(maxwell3d, opcode.result_operation, opcode.dst, dst);
+ ProcessResult(system, maxwell3d, opcode.result_operation, opcode.dst, dst);
break;
}
case Macro::Operation::ExtractShiftLeftImmediate: {
@@ -501,7 +498,7 @@ bool MacroInterpreterImpl::Step(Engines::Maxwell3D& maxwell3d, bool is_delay_slo
u32 result = ((src >> dst) & opcode.GetBitfieldMask()) << opcode.bf_dst_bit;
- ProcessResult(maxwell3d, opcode.result_operation, opcode.dst, result);
+ ProcessResult(system, maxwell3d, opcode.result_operation, opcode.dst, result);
break;
}
case Macro::Operation::ExtractShiftLeftRegister: {
@@ -510,12 +507,12 @@ bool MacroInterpreterImpl::Step(Engines::Maxwell3D& maxwell3d, bool is_delay_slo
u32 result = ((src >> opcode.bf_src_bit) & opcode.GetBitfieldMask()) << dst;
- ProcessResult(maxwell3d, opcode.result_operation, opcode.dst, result);
+ ProcessResult(system, maxwell3d, opcode.result_operation, opcode.dst, result);
break;
}
case Macro::Operation::Read: {
u32 result = Read(maxwell3d, GetRegister(opcode.src_a) + opcode.immediate);
- ProcessResult(maxwell3d, opcode.result_operation, opcode.dst, result);
+ ProcessResult(system, maxwell3d, opcode.result_operation, opcode.dst, result);
break;
}
case Macro::Operation::Branch: {
@@ -531,7 +528,7 @@ bool MacroInterpreterImpl::Step(Engines::Maxwell3D& maxwell3d, bool is_delay_slo
delayed_pc = base_address + opcode.GetBranchTarget();
// Execute one more instruction due to the delay slot.
- return Step(maxwell3d, true);
+ return Step(system, maxwell3d, true);
}
break;
}
@@ -544,7 +541,7 @@ bool MacroInterpreterImpl::Step(Engines::Maxwell3D& maxwell3d, bool is_delay_slo
// cause an exit if it's executed inside a delay slot.
if (opcode.is_exit && !is_delay_slot) {
// Exit has a delay slot, execute the next instruction
- Step(maxwell3d, true);
+ Step(system, maxwell3d, true);
return false;
}
return true;
@@ -591,7 +588,7 @@ u32 MacroInterpreterImpl::GetALUResult(Macro::ALUOperation operation, u32 src_a,
}
/// Performs the result operation on the input result and stores it in the specified register (if necessary).
-void MacroInterpreterImpl::ProcessResult(Engines::Maxwell3D& maxwell3d, Macro::ResultOperation operation, u32 reg, u32 result) {
+void MacroInterpreterImpl::ProcessResult(Core::System& system, Engines::Maxwell3D& maxwell3d, Macro::ResultOperation operation, u32 reg, u32 result) {
switch (operation) {
case Macro::ResultOperation::IgnoreAndFetch:
// Fetch parameter and ignore result.
@@ -609,12 +606,12 @@ void MacroInterpreterImpl::ProcessResult(Engines::Maxwell3D& maxwell3d, Macro::R
case Macro::ResultOperation::FetchAndSend:
// Fetch parameter and send result.
SetRegister(reg, FetchParameter());
- Send(maxwell3d, result);
+ Send(system, maxwell3d, result);
break;
case Macro::ResultOperation::MoveAndSend:
// Move and send result.
SetRegister(reg, result);
- Send(maxwell3d, result);
+ Send(system, maxwell3d, result);
break;
case Macro::ResultOperation::FetchAndSetMethod:
// Fetch parameter and use result as Method Address.
@@ -625,13 +622,13 @@ void MacroInterpreterImpl::ProcessResult(Engines::Maxwell3D& maxwell3d, Macro::R
// Move result and use as Method Address, then fetch and send parameter.
SetRegister(reg, result);
SetMethodAddress(result);
- Send(maxwell3d, FetchParameter());
+ Send(system, maxwell3d, FetchParameter());
break;
case Macro::ResultOperation::MoveAndSetMethodSend:
// Move result and use as Method Address, then send bits 12:17 of result.
SetRegister(reg, result);
SetMethodAddress(result);
- Send(maxwell3d, (result >> 12) & 0b111111);
+ Send(system, maxwell3d, (result >> 12) & 0b111111);
break;
default:
UNIMPLEMENTED_MSG("Unimplemented result operation {}", operation);
@@ -672,8 +669,8 @@ void MacroInterpreterImpl::SetRegister(u32 register_id, u32 value) {
}
/// Calls a GPU Engine method with the input parameter.
-void MacroInterpreterImpl::Send(Engines::Maxwell3D& maxwell3d, u32 value) {
- maxwell3d.CallMethod(method_address.address, value, true);
+void MacroInterpreterImpl::Send(Core::System& system, Engines::Maxwell3D& maxwell3d, u32 value) {
+ maxwell3d.CallMethod(system, method_address.address, value, true);
// Increment the method address by the method increment.
method_address.address.Assign(method_address.address.Value() + method_address.increment.Value());
}
@@ -724,34 +721,35 @@ static const auto default_cg_mode = nullptr; //Allow RWE
#endif
struct MacroJITx64Impl final : public Xbyak::CodeGenerator, public DynamicCachedMacro {
- explicit MacroJITx64Impl(std::span<const u32> code_)
+ explicit MacroJITx64Impl(Core::System& system, std::span<const u32> code_)
: Xbyak::CodeGenerator(MAX_CODE_SIZE, default_cg_mode)
, code{code_}
{
- Compile();
+ Compile(system);
}
- void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, u32 method) override;
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, u32 method) override;
- void Compile_ALU(Macro::Opcode opcode);
- void Compile_AddImmediate(Macro::Opcode opcode);
- void Compile_ExtractInsert(Macro::Opcode opcode);
- void Compile_ExtractShiftLeftImmediate(Macro::Opcode opcode);
- void Compile_ExtractShiftLeftRegister(Macro::Opcode opcode);
- void Compile_Read(Macro::Opcode opcode);
+ void Compile_ALU(Core::System& system, Macro::Opcode opcode);
+ void Compile_AddImmediate(Core::System& system, Macro::Opcode opcode);
+ void Compile_ExtractInsert(Core::System& system, Macro::Opcode opcode);
+ void Compile_ExtractShiftLeftImmediate(Core::System& system, Macro::Opcode opcode);
+ void Compile_ExtractShiftLeftRegister(Core::System& system, Macro::Opcode opcode);
+ void Compile_Read(Core::System& system, Macro::Opcode opcode);
void Compile_Branch(Macro::Opcode opcode);
void Optimizer_ScanFlags();
- void Compile();
- bool Compile_NextInstruction();
+ void Compile(Core::System& system);
+ bool Compile_NextInstruction(Core::System& system);
Xbyak::Reg32 Compile_FetchParameter();
Xbyak::Reg32 Compile_GetRegister(u32 index, Xbyak::Reg32 dst);
- void Compile_ProcessResult(Macro::ResultOperation operation, u32 reg);
- void Compile_Send(Xbyak::Reg32 value);
+ void Compile_ProcessResult(Core::System& system, Macro::ResultOperation operation, u32 reg);
+ void Compile_Send(Core::System& system, Xbyak::Reg32 value);
Macro::Opcode GetOpCode() const;
struct JITState {
- Engines::Maxwell3D* maxwell3d{};
+ Engines::Maxwell3D* maxwell3d = nullptr;
+ Core::System* system = nullptr;
std::array<u32, Macro::NUM_MACRO_REGISTERS> registers{};
u32 carry_flag{};
};
@@ -777,15 +775,16 @@ struct MacroJITx64Impl final : public Xbyak::CodeGenerator, public DynamicCached
std::span<const u32> code;
};
-void MacroJITx64Impl::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, u32 method) {
+void MacroJITx64Impl::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, u32 method) {
ASSERT_OR_EXECUTE(program != nullptr, { return; });
JITState state{};
state.maxwell3d = &maxwell3d;
+ state.system = &system;
state.registers = {};
program(&state, parameters.data(), parameters.data() + parameters.size());
}
-void MacroJITx64Impl::Compile_ALU(Macro::Opcode opcode) {
+void MacroJITx64Impl::Compile_ALU(Core::System& system, Macro::Opcode opcode) {
const bool is_a_zero = opcode.src_a == 0;
const bool is_b_zero = opcode.src_b == 0;
const bool valid_operation = !is_a_zero && !is_b_zero;
@@ -902,10 +901,10 @@ void MacroJITx64Impl::Compile_ALU(Macro::Opcode opcode) {
UNIMPLEMENTED_MSG("Unimplemented ALU operation {}", opcode.alu_operation.Value());
break;
}
- Compile_ProcessResult(opcode.result_operation, opcode.dst);
+ Compile_ProcessResult(system, opcode.result_operation, opcode.dst);
}
-void MacroJITx64Impl::Compile_AddImmediate(Macro::Opcode opcode) {
+void MacroJITx64Impl::Compile_AddImmediate(Core::System& system, Macro::Opcode opcode) {
if (optimizer.skip_dummy_addimmediate) {
// Games tend to use this as an exit instruction placeholder. It's to encode an instruction
// without doing anything. In our case we can just not emit anything.
@@ -940,10 +939,10 @@ void MacroJITx64Impl::Compile_AddImmediate(Macro::Opcode opcode) {
sub(result, opcode.immediate * -1);
}
}
- Compile_ProcessResult(opcode.result_operation, opcode.dst);
+ Compile_ProcessResult(system, opcode.result_operation, opcode.dst);
}
-void MacroJITx64Impl::Compile_ExtractInsert(Macro::Opcode opcode) {
+void MacroJITx64Impl::Compile_ExtractInsert(Core::System& system, Macro::Opcode opcode) {
auto dst = Compile_GetRegister(opcode.src_a, RESULT);
auto src = Compile_GetRegister(opcode.src_b, eax);
@@ -954,10 +953,10 @@ void MacroJITx64Impl::Compile_ExtractInsert(Macro::Opcode opcode) {
shl(src, opcode.bf_dst_bit);
or_(dst, src);
- Compile_ProcessResult(opcode.result_operation, opcode.dst);
+ Compile_ProcessResult(system, opcode.result_operation, opcode.dst);
}
-void MacroJITx64Impl::Compile_ExtractShiftLeftImmediate(Macro::Opcode opcode) {
+void MacroJITx64Impl::Compile_ExtractShiftLeftImmediate(Core::System& system, Macro::Opcode opcode) {
const auto dst = Compile_GetRegister(opcode.src_a, ecx);
const auto src = Compile_GetRegister(opcode.src_b, RESULT);
@@ -965,10 +964,10 @@ void MacroJITx64Impl::Compile_ExtractShiftLeftImmediate(Macro::Opcode opcode) {
and_(src, opcode.GetBitfieldMask());
shl(src, opcode.bf_dst_bit);
- Compile_ProcessResult(opcode.result_operation, opcode.dst);
+ Compile_ProcessResult(system, opcode.result_operation, opcode.dst);
}
-void MacroJITx64Impl::Compile_ExtractShiftLeftRegister(Macro::Opcode opcode) {
+void MacroJITx64Impl::Compile_ExtractShiftLeftRegister(Core::System& system, Macro::Opcode opcode) {
const auto dst = Compile_GetRegister(opcode.src_a, ecx);
const auto src = Compile_GetRegister(opcode.src_b, RESULT);
@@ -976,10 +975,10 @@ void MacroJITx64Impl::Compile_ExtractShiftLeftRegister(Macro::Opcode opcode) {
and_(src, opcode.GetBitfieldMask());
shl(src, dst.cvt8());
- Compile_ProcessResult(opcode.result_operation, opcode.dst);
+ Compile_ProcessResult(system, opcode.result_operation, opcode.dst);
}
-void MacroJITx64Impl::Compile_Read(Macro::Opcode opcode) {
+void MacroJITx64Impl::Compile_Read(Core::System& system, Macro::Opcode opcode) {
if (optimizer.zero_reg_skip && opcode.src_a == 0) {
if (opcode.immediate == 0) {
xor_(RESULT, RESULT);
@@ -1005,23 +1004,21 @@ void MacroJITx64Impl::Compile_Read(Macro::Opcode opcode) {
int3();
L(pass_range_check);
}
- mov(rax, qword[STATE]);
- mov(RESULT,
- dword[rax + offsetof(Engines::Maxwell3D, regs) +
- offsetof(Engines::Maxwell3D::Regs, reg_array) + RESULT.cvt64() * sizeof(u32)]);
-
- Compile_ProcessResult(opcode.result_operation, opcode.dst);
+ mov(rax, qword[STATE + offsetof(JITState, maxwell3d)]);
+ mov(RESULT, dword[rax + offsetof(Engines::Maxwell3D, regs) + offsetof(Engines::Maxwell3D::Regs, reg_array) + RESULT.cvt64() * sizeof(u32)]);
+ Compile_ProcessResult(system, opcode.result_operation, opcode.dst);
}
-static void MacroJIT_SendThunk(Engines::Maxwell3D* maxwell3d, Macro::MethodAddress method_address, u32 value) {
- maxwell3d->CallMethod(method_address.address, value, true);
+static void MacroJIT_SendThunk(Core::System* system, Engines::Maxwell3D* maxwell3d, Macro::MethodAddress method_address, u32 value) {
+ maxwell3d->CallMethod(*system, method_address.address, value, true);
}
-void MacroJITx64Impl::Compile_Send(Xbyak::Reg32 value) {
+void MacroJITx64Impl::Compile_Send(Core::System& system, Xbyak::Reg32 value) {
Common::X64::ABI_PushRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0);
- mov(Common::X64::ABI_PARAM1, qword[STATE]);
- mov(Common::X64::ABI_PARAM2.cvt32(), METHOD_ADDRESS);
- mov(Common::X64::ABI_PARAM3.cvt32(), value);
+ mov(Common::X64::ABI_PARAM1, qword[STATE + offsetof(JITState, system)]);
+ mov(Common::X64::ABI_PARAM2, qword[STATE + offsetof(JITState, maxwell3d)]);
+ mov(Common::X64::ABI_PARAM3.cvt32(), METHOD_ADDRESS);
+ mov(Common::X64::ABI_PARAM4.cvt32(), value);
Common::X64::CallFarFunction(*this, &MacroJIT_SendThunk);
Common::X64::ABI_PopRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0);
@@ -1045,9 +1042,8 @@ void MacroJITx64Impl::Compile_Send(Xbyak::Reg32 value) {
}
void MacroJITx64Impl::Compile_Branch(Macro::Opcode opcode) {
- ASSERT_MSG(!is_delay_slot, "Executing a branch in a delay slot is not valid");
- const s32 jump_address =
- static_cast<s32>(pc) + static_cast<s32>(opcode.GetBranchTarget() / sizeof(s32));
+ ASSERT(!is_delay_slot && "Executing a branch in a delay slot is not valid");
+ const s32 jump_address = s32(pc) + s32(opcode.GetBranchTarget() / sizeof(s32));
Xbyak::Label end;
auto value = Compile_GetRegister(opcode.src_a, eax);
@@ -1116,7 +1112,7 @@ void MacroJITx64Impl::Optimizer_ScanFlags() {
}
}
-void MacroJITx64Impl::Compile() {
+void MacroJITx64Impl::Compile(Core::System& system) {
// Matching PROTECT_RE needed for W^X systems
setProtectMode(Xbyak::CodeArray::ProtectMode::PROTECT_RW);
labels.fill(Xbyak::Label());
@@ -1158,7 +1154,7 @@ void MacroJITx64Impl::Compile() {
next_opcode = {};
}
pc = i;
- Compile_NextInstruction();
+ Compile_NextInstruction(system);
}
L(end_of_code);
@@ -1170,7 +1166,7 @@ void MacroJITx64Impl::Compile() {
program = getCode<ProgramType>();
}
-bool MacroJITx64Impl::Compile_NextInstruction() {
+bool MacroJITx64Impl::Compile_NextInstruction(Core::System& system) {
const auto opcode = GetOpCode();
if (labels[pc].getAddress()) {
return false;
@@ -1180,22 +1176,22 @@ bool MacroJITx64Impl::Compile_NextInstruction() {
switch (opcode.operation) {
case Macro::Operation::ALU:
- Compile_ALU(opcode);
+ Compile_ALU(system, opcode);
break;
case Macro::Operation::AddImmediate:
- Compile_AddImmediate(opcode);
+ Compile_AddImmediate(system, opcode);
break;
case Macro::Operation::ExtractInsert:
- Compile_ExtractInsert(opcode);
+ Compile_ExtractInsert(system, opcode);
break;
case Macro::Operation::ExtractShiftLeftImmediate:
- Compile_ExtractShiftLeftImmediate(opcode);
+ Compile_ExtractShiftLeftImmediate(system, opcode);
break;
case Macro::Operation::ExtractShiftLeftRegister:
- Compile_ExtractShiftLeftRegister(opcode);
+ Compile_ExtractShiftLeftRegister(system, opcode);
break;
case Macro::Operation::Read:
- Compile_Read(opcode);
+ Compile_Read(system, opcode);
break;
case Macro::Operation::Branch:
Compile_Branch(opcode);
@@ -1267,7 +1263,7 @@ Xbyak::Reg32 MacroJITx64Impl::Compile_GetRegister(u32 index, Xbyak::Reg32 dst) {
return dst;
}
-void MacroJITx64Impl::Compile_ProcessResult(Macro::ResultOperation operation, u32 reg) {
+void MacroJITx64Impl::Compile_ProcessResult(Core::System& system, Macro::ResultOperation operation, u32 reg) {
const auto SetRegister = [this](u32 reg_index, const Xbyak::Reg32& result) {
// Register 0 is supposed to always return 0. NOP is implemented as a store to the zero
// register.
@@ -1292,12 +1288,12 @@ void MacroJITx64Impl::Compile_ProcessResult(Macro::ResultOperation operation, u3
case Macro::ResultOperation::FetchAndSend:
// Fetch parameter and send result.
SetRegister(reg, Compile_FetchParameter());
- Compile_Send(RESULT);
+ Compile_Send(system, RESULT);
break;
case Macro::ResultOperation::MoveAndSend:
// Move and send result.
SetRegister(reg, RESULT);
- Compile_Send(RESULT);
+ Compile_Send(system, RESULT);
break;
case Macro::ResultOperation::FetchAndSetMethod:
// Fetch parameter and use result as Method Address.
@@ -1308,7 +1304,7 @@ void MacroJITx64Impl::Compile_ProcessResult(Macro::ResultOperation operation, u3
// Move result and use as Method Address, then fetch and send parameter.
SetRegister(reg, RESULT);
SetMethodAddress(RESULT);
- Compile_Send(Compile_FetchParameter());
+ Compile_Send(system, Compile_FetchParameter());
break;
case Macro::ResultOperation::MoveAndSetMethodSend:
// Move result and use as Method Address, then send bits 12:17 of result.
@@ -1316,7 +1312,7 @@ void MacroJITx64Impl::Compile_ProcessResult(Macro::ResultOperation operation, u3
SetMethodAddress(RESULT);
shr(RESULT, 12);
and_(RESULT, 0b111111);
- Compile_Send(RESULT);
+ Compile_Send(system, RESULT);
break;
default:
UNIMPLEMENTED_MSG("Unimplemented macro operation {}", operation);
@@ -1357,36 +1353,36 @@ static void Dump(u64 hash, std::span<const u32> code, bool decompiled = false) {
macro_file.write(reinterpret_cast<const char*>(code.data()), code.size_bytes());
}
-void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method, std::span<const u32> parameters) {
- auto const execute_variant = [&maxwell3d, &parameters, method](AnyCachedMacro& acm) {
+void MacroEngine::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, u32 method, std::span<const u32> parameters) {
+ auto const execute_variant = [&system, &maxwell3d, &parameters, method](AnyCachedMacro& acm) {
if (auto a = std::get_if<HLE_DrawArraysIndirect>(&acm))
- a->Execute(maxwell3d, parameters, method);
+ a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_DrawIndexedIndirect>(&acm))
- a->Execute(maxwell3d, parameters, method);
+ a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_MultiDrawIndexedIndirectCount>(&acm))
- a->Execute(maxwell3d, parameters, method);
+ a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_MultiLayerClear>(&acm))
- a->Execute(maxwell3d, parameters, method);
+ a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_C713C83D8F63CCF3>(&acm))
- a->Execute(maxwell3d, parameters, method);
+ a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_D7333D26E0A93EDE>(&acm))
- a->Execute(maxwell3d, parameters, method);
+ a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_BindShader>(&acm))
- a->Execute(maxwell3d, parameters, method);
+ a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_SetRasterBoundingBox>(&acm))
- a->Execute(maxwell3d, parameters, method);
+ a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_ClearConstBuffer>(&acm))
- a->Execute(maxwell3d, parameters, method);
+ a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_ClearMemory>(&acm))
- a->Execute(maxwell3d, parameters, method);
+ a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_TransformFeedbackSetup>(&acm))
- a->Execute(maxwell3d, parameters, method);
+ a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_DrawIndirectByteCount>(&acm))
- a->Execute(maxwell3d, parameters, method);
+ a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<MacroInterpreterImpl>(&acm))
- a->Execute(maxwell3d, parameters, method);
+ a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<std::unique_ptr<DynamicCachedMacro>>(&acm))
- a->get()->Execute(maxwell3d, parameters, method);
+ a->get()->Execute(system, maxwell3d, parameters, method);
};
if (auto const it = macro_cache.find(method); it != macro_cache.end()) {
auto& ci = it->second;
@@ -1417,9 +1413,9 @@ void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method, std::span<c
code.resize(macro_cached.size() - rebased_method);
std::memcpy(code.data(), macro_cached.data() + rebased_method, code.size() * sizeof(u32));
ci.hash = Common::HashValue(code);
- ci.program = Compile(maxwell3d, code);
+ ci.program = Compile(system, maxwell3d, code);
} else {
- ci.program = Compile(maxwell3d, macro_code->second);
+ ci.program = Compile(system, maxwell3d, macro_code->second);
ci.hash = Common::HashValue(macro_code->second);
}
if (CanBeHLEProgram(ci.hash) && !Settings::values.disable_macro_hle) {
@@ -1434,10 +1430,10 @@ void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method, std::span<c
}
}
-AnyCachedMacro MacroEngine::Compile(Engines::Maxwell3D& maxwell3d, std::span<const u32> code) {
+AnyCachedMacro MacroEngine::Compile(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> code) {
#ifdef ARCHITECTURE_x86_64
if (!is_interpreted)
- return std::make_unique<MacroJITx64Impl>(code);
+ return std::make_unique<MacroJITx64Impl>(system, code);
#endif
return MacroInterpreterImpl(code);
}
diff --git a/src/video_core/macro.h b/src/video_core/macro.h
index a9a8f2de04..43b32ed920 100644
--- a/src/video_core/macro.h
+++ b/src/video_core/macro.h
@@ -14,6 +14,10 @@
#include "common/bit_field.h"
#include "common/common_types.h"
+namespace Core {
+class System;
+}
+
namespace Tegra {
namespace Engines {
@@ -106,61 +110,61 @@ struct HLEMacro {
/// also assigning the base vertex/instance.
struct HLE_DrawArraysIndirect final {
HLE_DrawArraysIndirect(bool extended_) noexcept : extended{extended_} {}
- void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
- void Fallback(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters);
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
+ void Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters);
bool extended;
};
/// @note: these macros have two versions, a normal and extended version, with the extended version
/// also assigning the base vertex/instance.
struct HLE_DrawIndexedIndirect final {
explicit HLE_DrawIndexedIndirect(bool extended_) noexcept : extended{extended_} {}
- void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
- void Fallback(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters);
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
+ void Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters);
bool extended;
};
struct HLE_MultiLayerClear final {
- void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
};
struct HLE_MultiDrawIndexedIndirectCount final {
- void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
- void Fallback(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters);
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
+ void Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters);
};
struct HLE_DrawIndirectByteCount final {
- void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
- void Fallback(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters);
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
+ void Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters);
};
struct HLE_C713C83D8F63CCF3 final {
- void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
};
struct HLE_D7333D26E0A93EDE final {
- void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
};
struct HLE_BindShader final {
- void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
};
struct HLE_SetRasterBoundingBox final {
- void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
};
struct HLE_ClearConstBuffer final {
HLE_ClearConstBuffer(size_t base_size_) noexcept : base_size{base_size_} {}
- void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
size_t base_size;
};
struct HLE_ClearMemory final {
- void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
std::vector<u32> zero_memory;
};
struct HLE_TransformFeedbackSetup final {
- void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method);
};
struct MacroInterpreterImpl final {
MacroInterpreterImpl() {}
MacroInterpreterImpl(std::span<const u32> code_) : code{code_} {}
- void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> params, u32 method);
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> params, u32 method);
void Reset();
- bool Step(Engines::Maxwell3D& maxwell3d, bool is_delay_slot);
+ bool Step(Core::System& system, Engines::Maxwell3D& maxwell3d, bool is_delay_slot);
u32 GetALUResult(Macro::ALUOperation operation, u32 src_a, u32 src_b);
- void ProcessResult(Engines::Maxwell3D& maxwell3d, Macro::ResultOperation operation, u32 reg, u32 result);
+ void ProcessResult(Core::System& system, Engines::Maxwell3D& maxwell3d, Macro::ResultOperation operation, u32 reg, u32 result);
bool EvaluateBranchCondition(Macro::BranchCondition cond, u32 value) const;
Macro::Opcode GetOpcode() const;
u32 GetRegister(u32 register_id) const;
@@ -169,7 +173,7 @@ struct MacroInterpreterImpl final {
[[nodiscard]] inline void SetMethodAddress(u32 address) noexcept {
method_address.raw = address;
}
- void Send(Engines::Maxwell3D& maxwell3d, u32 value);
+ void Send(Core::System& system, Engines::Maxwell3D& maxwell3d, u32 value);
u32 Read(Engines::Maxwell3D& maxwell3d, u32 method) const;
u32 FetchParameter();
/// General purpose macro registers.
@@ -192,7 +196,7 @@ struct DynamicCachedMacro {
/// Executes the macro code with the specified input parameters.
/// @param parameters The parameters of the macro
/// @param method The method to execute
- virtual void Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, u32 method) = 0;
+ virtual void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, u32 method) = 0;
};
using AnyCachedMacro = std::variant<
@@ -227,8 +231,8 @@ struct MacroEngine {
uploaded_macro_code.erase(method);
}
// Compiles the macro if its not in the cache, and executes the compiled macro
- void Execute(Engines::Maxwell3D& maxwell3d, u32 method, std::span<const u32> parameters);
- AnyCachedMacro Compile(Engines::Maxwell3D& maxwell3d, std::span<const u32> code);
+ void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, u32 method, std::span<const u32> parameters);
+ AnyCachedMacro Compile(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> code);
struct CacheInfo {
AnyCachedMacro program;
u64 hash{};
diff --git a/src/video_core/renderer_opengl/gl_state_tracker.cpp b/src/video_core/renderer_opengl/gl_state_tracker.cpp
index d53b422cac..dc91723300 100644
--- a/src/video_core/renderer_opengl/gl_state_tracker.cpp
+++ b/src/video_core/renderer_opengl/gl_state_tracker.cpp
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -204,7 +207,7 @@ void SetupDirtyMisc(Tables& tables) {
} // Anonymous namespace
void StateTracker::SetupTables(Tegra::Control::ChannelState& channel_state) {
- auto& tables{channel_state.maxwell_3d->dirty.tables};
+ auto& tables{channel_state.payload->maxwell_3d.dirty.tables};
SetupDirtyFlags(tables);
SetupDirtyColorMasks(tables);
SetupDirtyViewports(tables);
@@ -231,7 +234,7 @@ void StateTracker::SetupTables(Tegra::Control::ChannelState& channel_state) {
}
void StateTracker::ChangeChannel(Tegra::Control::ChannelState& channel_state) {
- flags = &channel_state.maxwell_3d->dirty.flags;
+ flags = &channel_state.payload->maxwell_3d.dirty.flags;
}
void StateTracker::InvalidateState() {
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index 2bca1ba28f..d99e528bc0 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -502,9 +502,9 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
two_textures_set_layout(device.GetLogical().CreateDescriptorSetLayout(
TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_CREATE_INFO)),
one_texture_descriptor_allocator{
- descriptor_pool.Allocator(*one_texture_set_layout, TEXTURE_DESCRIPTOR_BANK_INFO<1>)},
+ descriptor_pool.Allocator(device_, scheduler_, *one_texture_set_layout, TEXTURE_DESCRIPTOR_BANK_INFO<1>)},
two_textures_descriptor_allocator{
- descriptor_pool.Allocator(*two_textures_set_layout, TEXTURE_DESCRIPTOR_BANK_INFO<2>)},
+ descriptor_pool.Allocator(device_, scheduler_, *two_textures_set_layout, TEXTURE_DESCRIPTOR_BANK_INFO<2>)},
one_texture_pipeline_layout(device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo(
one_texture_set_layout.address(),
PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_VERTEX_BIT, sizeof(PushConstants)>))),
diff --git a/src/video_core/renderer_vulkan/pipeline_statistics.cpp b/src/video_core/renderer_vulkan/pipeline_statistics.cpp
index ad288436a8..04f42c71a6 100644
--- a/src/video_core/renderer_vulkan/pipeline_statistics.cpp
+++ b/src/video_core/renderer_vulkan/pipeline_statistics.cpp
@@ -31,14 +31,13 @@ static u64 GetUint64(const VkPipelineExecutableStatisticKHR& statistic) {
}
}
-PipelineStatistics::PipelineStatistics(const Device& device_) : device{device_} {}
+PipelineStatistics::PipelineStatistics(const Device& device_) {}
-void PipelineStatistics::Collect(VkPipeline pipeline) {
- const auto& dev{device.GetLogical()};
- const std::vector properties{dev.GetPipelineExecutablePropertiesKHR(pipeline)};
+void PipelineStatistics::Collect(const Device& device, VkPipeline pipeline) {
+ const std::vector properties{device.GetLogical().GetPipelineExecutablePropertiesKHR(pipeline)};
const u32 num_executables{static_cast<u32>(properties.size())};
for (u32 executable = 0; executable < num_executables; ++executable) {
- const auto statistics{dev.GetPipelineExecutableStatisticsKHR(pipeline, executable)};
+ const auto statistics{device.GetLogical().GetPipelineExecutableStatisticsKHR(pipeline, executable)};
if (statistics.empty()) {
continue;
}
diff --git a/src/video_core/renderer_vulkan/pipeline_statistics.h b/src/video_core/renderer_vulkan/pipeline_statistics.h
index 197bb09363..83e70b704f 100644
--- a/src/video_core/renderer_vulkan/pipeline_statistics.h
+++ b/src/video_core/renderer_vulkan/pipeline_statistics.h
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -16,9 +19,7 @@ class Device;
class PipelineStatistics {
public:
explicit PipelineStatistics(const Device& device_);
-
- void Collect(VkPipeline pipeline);
-
+ void Collect(const Device& device, VkPipeline pipeline);
void Report() const;
private:
@@ -30,8 +31,6 @@ private:
u64 branches_count{};
u64 basic_block_count{};
};
-
- const Device& device;
mutable std::mutex mutex;
std::vector<Stats> collected_stats;
};
diff --git a/src/video_core/renderer_vulkan/present/anti_alias_pass.h b/src/video_core/renderer_vulkan/present/anti_alias_pass.h
index 4990e87502..8061d01208 100644
--- a/src/video_core/renderer_vulkan/present/anti_alias_pass.h
+++ b/src/video_core/renderer_vulkan/present/anti_alias_pass.h
@@ -11,12 +11,12 @@
namespace Vulkan {
class Scheduler;
+class Device;
class AntiAliasPass {
public:
virtual ~AntiAliasPass() = default;
- virtual void Draw(Scheduler& scheduler, size_t image_index, VkImage* inout_image,
- VkImageView* inout_image_view) = 0;
+ virtual void Draw(const Device& device, Scheduler& scheduler, size_t image_index, VkImage* inout_image, VkImageView* inout_image_view) = 0;
};
} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/present/fsr.cpp b/src/video_core/renderer_vulkan/present/fsr.cpp
index ba6252ed95..894fb144f0 100644
--- a/src/video_core/renderer_vulkan/present/fsr.cpp
+++ b/src/video_core/renderer_vulkan/present/fsr.cpp
@@ -25,74 +25,74 @@ using namespace FSR;
using PushConstants = std::array<u32, 4 * 4>;
-FSR::FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count,
- VkExtent2D extent)
- : m_device{device}, m_memory_allocator{memory_allocator},
- m_image_count{image_count}, m_extent{extent} {
-
- CreateImages();
- CreateRenderPasses();
- CreateSampler();
- CreateShaders();
- CreateDescriptorPool();
- CreateDescriptorSetLayout();
- CreateDescriptorSets();
- CreatePipelineLayouts();
- CreatePipelines();
+FSR::FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, VkExtent2D extent)
+ : m_memory_allocator{memory_allocator}
+ , m_image_count{image_count}
+ , m_extent{extent}
+{
+ CreateImages(device);
+ CreateRenderPasses(device);
+ CreateSampler(device);
+ CreateShaders(device);
+ CreateDescriptorPool(device);
+ CreateDescriptorSetLayout(device);
+ CreateDescriptorSets(device);
+ CreatePipelineLayouts(device);
+ CreatePipelines(device);
}
-void FSR::CreateImages() {
+void FSR::CreateImages(const Device& device) {
m_dynamic_images.resize(m_image_count);
for (auto& images : m_dynamic_images) {
images.images[Easu] = CreateWrappedImage(m_memory_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
images.images[Rcas] = CreateWrappedImage(m_memory_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
- images.image_views[Easu] = CreateWrappedImageView(m_device, images.images[Easu], VK_FORMAT_R16G16B16A16_SFLOAT);
- images.image_views[Rcas] = CreateWrappedImageView(m_device, images.images[Rcas], VK_FORMAT_R16G16B16A16_SFLOAT);
+ images.image_views[Easu] = CreateWrappedImageView(device, images.images[Easu], VK_FORMAT_R16G16B16A16_SFLOAT);
+ images.image_views[Rcas] = CreateWrappedImageView(device, images.images[Rcas], VK_FORMAT_R16G16B16A16_SFLOAT);
}
}
-void FSR::CreateRenderPasses() {
- m_renderpass = CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT);
+void FSR::CreateRenderPasses(const Device& device) {
+ m_renderpass = CreateWrappedRenderPass(device, VK_FORMAT_R16G16B16A16_SFLOAT);
for (auto& images : m_dynamic_images) {
- images.framebuffers[Easu] = CreateWrappedFramebuffer(m_device, m_renderpass, images.image_views[Easu], m_extent);
- images.framebuffers[Rcas] = CreateWrappedFramebuffer(m_device, m_renderpass, images.image_views[Rcas], m_extent);
+ images.framebuffers[Easu] = CreateWrappedFramebuffer(device, m_renderpass, images.image_views[Easu], m_extent);
+ images.framebuffers[Rcas] = CreateWrappedFramebuffer(device, m_renderpass, images.image_views[Rcas], m_extent);
}
}
-void FSR::CreateSampler() {
- m_sampler = CreateBilinearSampler(m_device);
+void FSR::CreateSampler(const Device& device) {
+ m_sampler = CreateBilinearSampler(device);
}
-void FSR::CreateShaders() {
- m_vert_shader = BuildShader(m_device, VULKAN_FIDELITYFX_FSR_VERT_SPV);
+void FSR::CreateShaders(const Device& device) {
+ m_vert_shader = BuildShader(device, VULKAN_FIDELITYFX_FSR_VERT_SPV);
- if (m_device.IsFloat16Supported()) {
- m_easu_shader = BuildShader(m_device, VULKAN_FIDELITYFX_FSR_EASU_FP16_FRAG_SPV);
- m_rcas_shader = BuildShader(m_device, VULKAN_FIDELITYFX_FSR_RCAS_FP16_FRAG_SPV);
+ if (device.IsFloat16Supported()) {
+ m_easu_shader = BuildShader(device, VULKAN_FIDELITYFX_FSR_EASU_FP16_FRAG_SPV);
+ m_rcas_shader = BuildShader(device, VULKAN_FIDELITYFX_FSR_RCAS_FP16_FRAG_SPV);
} else {
- m_easu_shader = BuildShader(m_device, VULKAN_FIDELITYFX_FSR_EASU_FP32_FRAG_SPV);
- m_rcas_shader = BuildShader(m_device, VULKAN_FIDELITYFX_FSR_RCAS_FP32_FRAG_SPV);
+ m_easu_shader = BuildShader(device, VULKAN_FIDELITYFX_FSR_EASU_FP32_FRAG_SPV);
+ m_rcas_shader = BuildShader(device, VULKAN_FIDELITYFX_FSR_RCAS_FP32_FRAG_SPV);
}
}
-void FSR::CreateDescriptorPool() {
+void FSR::CreateDescriptorPool(const Device& device) {
// EASU: 1 descriptor
// RCAS: 1 descriptor
// 2 descriptors, 2 descriptor sets per invocation
- m_descriptor_pool = CreateWrappedDescriptorPool(m_device, 2 * m_image_count, 2 * m_image_count);
+ m_descriptor_pool = CreateWrappedDescriptorPool(device, 2 * m_image_count, 2 * m_image_count);
}
-void FSR::CreateDescriptorSetLayout() {
- m_descriptor_set_layout = CreateWrappedDescriptorSetLayout(m_device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER});
+void FSR::CreateDescriptorSetLayout(const Device& device) {
+ m_descriptor_set_layout = CreateWrappedDescriptorSetLayout(device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER});
}
-void FSR::CreateDescriptorSets() {
+void FSR::CreateDescriptorSets(const Device& device) {
std::vector<VkDescriptorSetLayout> layouts(MaxFsrStage, *m_descriptor_set_layout);
for (auto& images : m_dynamic_images)
images.descriptor_sets = CreateWrappedDescriptorSets(m_descriptor_pool, layouts);
}
-void FSR::CreatePipelineLayouts() {
+void FSR::CreatePipelineLayouts(const Device& device) {
const VkPushConstantRange range{
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.offset = 0,
@@ -108,17 +108,17 @@ void FSR::CreatePipelineLayouts() {
.pPushConstantRanges = &range,
};
- m_pipeline_layout = m_device.GetLogical().CreatePipelineLayout(ci);
+ m_pipeline_layout = device.GetLogical().CreatePipelineLayout(ci);
}
-void FSR::CreatePipelines() {
- m_easu_pipeline = CreateWrappedPipeline(m_device, m_renderpass, m_pipeline_layout,
+void FSR::CreatePipelines(const Device& device) {
+ m_easu_pipeline = CreateWrappedPipeline(device, m_renderpass, m_pipeline_layout,
std::tie(m_vert_shader, m_easu_shader));
- m_rcas_pipeline = CreateWrappedPipeline(m_device, m_renderpass, m_pipeline_layout,
+ m_rcas_pipeline = CreateWrappedPipeline(device, m_renderpass, m_pipeline_layout,
std::tie(m_vert_shader, m_rcas_shader));
}
-void FSR::UpdateDescriptorSets(VkImageView image_view, size_t image_index) {
+void FSR::UpdateDescriptorSets(const Device& device, VkImageView image_view, size_t image_index) {
Images& images = m_dynamic_images[image_index];
std::vector<VkDescriptorImageInfo> image_infos;
image_infos.reserve(2);
@@ -126,10 +126,10 @@ void FSR::UpdateDescriptorSets(VkImageView image_view, size_t image_index) {
CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, images.descriptor_sets[Easu], 0),
CreateWriteDescriptorSet(image_infos, *m_sampler, *images.image_views[Easu], images.descriptor_sets[Rcas], 0)
};
- m_device.GetLogical().UpdateDescriptorSets(updates, {});
+ device.GetLogical().UpdateDescriptorSets(updates, {});
}
-void FSR::UploadImages(Scheduler& scheduler) {
+void FSR::UploadImages(const Device& device, Scheduler& scheduler) {
if (!m_images_ready) {
m_images_ready = true;
scheduler.Record([&](vk::CommandBuffer cmdbuf) {
@@ -142,7 +142,7 @@ void FSR::UploadImages(Scheduler& scheduler) {
}
}
-VkImageView FSR::Draw(Scheduler& scheduler, size_t image_index, VkImage source_image,
+VkImageView FSR::Draw(const Device& device, Scheduler& scheduler, size_t image_index, VkImage source_image,
VkImageView source_image_view, VkExtent2D input_image_extent,
const Common::Rectangle<f32>& crop_rect) {
Images& images = m_dynamic_images[image_index];
@@ -179,8 +179,8 @@ VkImageView FSR::Draw(Scheduler& scheduler, size_t image_index, VkImage source_i
static_cast<float>(Settings::values.fsr_sharpening_slider.GetValue()) / 100.0f;
FsrRcasCon(rcas_con.data(), sharpening);
- UploadImages(scheduler);
- UpdateDescriptorSets(source_image_view, image_index);
+ UploadImages(device, scheduler);
+ UpdateDescriptorSets(device, source_image_view, image_index);
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([=](vk::CommandBuffer cmdbuf) {
diff --git a/src/video_core/renderer_vulkan/present/fsr.h b/src/video_core/renderer_vulkan/present/fsr.h
index 8602e81465..7762480757 100644
--- a/src/video_core/renderer_vulkan/present/fsr.h
+++ b/src/video_core/renderer_vulkan/present/fsr.h
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -14,27 +17,25 @@ class Scheduler;
class FSR {
public:
- explicit FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count,
- VkExtent2D extent);
- VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImage source_image,
+ explicit FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, VkExtent2D extent);
+ VkImageView Draw(const Device& device, Scheduler& scheduler, size_t image_index, VkImage source_image,
VkImageView source_image_view, VkExtent2D input_image_extent,
const Common::Rectangle<f32>& crop_rect);
private:
- void CreateImages();
- void CreateRenderPasses();
- void CreateSampler();
- void CreateShaders();
- void CreateDescriptorPool();
- void CreateDescriptorSetLayout();
- void CreateDescriptorSets();
- void CreatePipelineLayouts();
- void CreatePipelines();
+ void CreateImages(const Device& device);
+ void CreateRenderPasses(const Device& device);
+ void CreateSampler(const Device& device);
+ void CreateShaders(const Device& device);
+ void CreateDescriptorPool(const Device& device);
+ void CreateDescriptorSetLayout(const Device& device);
+ void CreateDescriptorSets(const Device& device);
+ void CreatePipelineLayouts(const Device& device);
+ void CreatePipelines(const Device& device);
- void UploadImages(Scheduler& scheduler);
- void UpdateDescriptorSets(VkImageView image_view, size_t image_index);
+ void UploadImages(const Device& device, Scheduler& scheduler);
+ void UpdateDescriptorSets(const Device& device, VkImageView image_view, size_t image_index);
- const Device& m_device;
MemoryAllocator& m_memory_allocator;
const size_t m_image_count;
const VkExtent2D m_extent;
diff --git a/src/video_core/renderer_vulkan/present/fxaa.cpp b/src/video_core/renderer_vulkan/present/fxaa.cpp
index bdafd1f4d0..62f79d490c 100644
--- a/src/video_core/renderer_vulkan/present/fxaa.cpp
+++ b/src/video_core/renderer_vulkan/present/fxaa.cpp
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -14,61 +17,60 @@
namespace Vulkan {
FXAA::FXAA(const Device& device, MemoryAllocator& allocator, size_t image_count, VkExtent2D extent)
- : m_device(device), m_allocator(allocator), m_extent(extent),
- m_image_count(static_cast<u32>(image_count)) {
- CreateImages();
- CreateRenderPasses();
- CreateSampler();
- CreateShaders();
- CreateDescriptorPool();
- CreateDescriptorSetLayouts();
- CreateDescriptorSets();
- CreatePipelineLayouts();
- CreatePipelines();
+ : m_extent(extent)
+ , m_image_count(u32(image_count))
+{
+ CreateImages(device, allocator);
+ CreateRenderPasses(device);
+ CreateSampler(device);
+ CreateShaders(device);
+ CreateDescriptorPool(device);
+ CreateDescriptorSetLayouts(device);
+ CreateDescriptorSets(device);
+ CreatePipelineLayouts(device);
+ CreatePipelines(device);
}
FXAA::~FXAA() = default;
-void FXAA::CreateImages() {
+void FXAA::CreateImages(const Device& device, MemoryAllocator& allocator) {
for (u32 i = 0; i < m_image_count; i++) {
Image& image = m_dynamic_images.emplace_back();
-
- image.image = CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
- image.image_view =
- CreateWrappedImageView(m_device, image.image, VK_FORMAT_R16G16B16A16_SFLOAT);
+ image.image = CreateWrappedImage(allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
+ image.image_view = CreateWrappedImageView(device, image.image, VK_FORMAT_R16G16B16A16_SFLOAT);
}
}
-void FXAA::CreateRenderPasses() {
- m_renderpass = CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT);
+void FXAA::CreateRenderPasses(const Device& device) {
+ m_renderpass = CreateWrappedRenderPass(device, VK_FORMAT_R16G16B16A16_SFLOAT);
for (auto& image : m_dynamic_images) {
image.framebuffer =
- CreateWrappedFramebuffer(m_device, m_renderpass, image.image_view, m_extent);
+ CreateWrappedFramebuffer(device, m_renderpass, image.image_view, m_extent);
}
}
-void FXAA::CreateSampler() {
- m_sampler = CreateWrappedSampler(m_device);
+void FXAA::CreateSampler(const Device& device) {
+ m_sampler = CreateWrappedSampler(device);
}
-void FXAA::CreateShaders() {
- m_vertex_shader = CreateWrappedShaderModule(m_device, FXAA_VERT_SPV);
- m_fragment_shader = CreateWrappedShaderModule(m_device, FXAA_FRAG_SPV);
+void FXAA::CreateShaders(const Device& device) {
+ m_vertex_shader = CreateWrappedShaderModule(device, FXAA_VERT_SPV);
+ m_fragment_shader = CreateWrappedShaderModule(device, FXAA_FRAG_SPV);
}
-void FXAA::CreateDescriptorPool() {
+void FXAA::CreateDescriptorPool(const Device& device) {
// 2 descriptors, 1 descriptor set per image
- m_descriptor_pool = CreateWrappedDescriptorPool(m_device, 2 * m_image_count, m_image_count);
+ m_descriptor_pool = CreateWrappedDescriptorPool(device, 2 * m_image_count, m_image_count);
}
-void FXAA::CreateDescriptorSetLayouts() {
+void FXAA::CreateDescriptorSetLayouts(const Device& device) {
m_descriptor_set_layout =
- CreateWrappedDescriptorSetLayout(m_device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ CreateWrappedDescriptorSetLayout(device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER});
}
-void FXAA::CreateDescriptorSets() {
+void FXAA::CreateDescriptorSets(const Device& device) {
VkDescriptorSetLayout layout = *m_descriptor_set_layout;
for (auto& images : m_dynamic_images) {
@@ -76,30 +78,28 @@ void FXAA::CreateDescriptorSets() {
}
}
-void FXAA::CreatePipelineLayouts() {
- m_pipeline_layout = CreateWrappedPipelineLayout(m_device, m_descriptor_set_layout);
+void FXAA::CreatePipelineLayouts(const Device& device) {
+ m_pipeline_layout = CreateWrappedPipelineLayout(device, m_descriptor_set_layout);
}
-void FXAA::CreatePipelines() {
- m_pipeline = CreateWrappedPipeline(m_device, m_renderpass, m_pipeline_layout,
+void FXAA::CreatePipelines(const Device& device) {
+ m_pipeline = CreateWrappedPipeline(device, m_renderpass, m_pipeline_layout,
std::tie(m_vertex_shader, m_fragment_shader));
}
-void FXAA::UpdateDescriptorSets(VkImageView image_view, size_t image_index) {
+void FXAA::UpdateDescriptorSets(const Device& device, VkImageView image_view, size_t image_index) {
Image& image = m_dynamic_images[image_index];
std::vector<VkDescriptorImageInfo> image_infos;
std::vector<VkWriteDescriptorSet> updates;
image_infos.reserve(2);
- updates.push_back(
- CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, image.descriptor_sets[0], 0));
- updates.push_back(
- CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, image.descriptor_sets[0], 1));
+ updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, image.descriptor_sets[0], 0));
+ updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, image.descriptor_sets[0], 1));
- m_device.GetLogical().UpdateDescriptorSets(updates, {});
+ device.GetLogical().UpdateDescriptorSets(updates, {});
}
-void FXAA::UploadImages(Scheduler& scheduler) {
+void FXAA::UploadImages(const Device& device, Scheduler& scheduler) {
if (m_images_ready) {
return;
}
@@ -114,8 +114,7 @@ void FXAA::UploadImages(Scheduler& scheduler) {
m_images_ready = true;
}
-void FXAA::Draw(Scheduler& scheduler, size_t image_index, VkImage* inout_image,
- VkImageView* inout_image_view) {
+void FXAA::Draw(const Device& device, Scheduler& scheduler, size_t image_index, VkImage* inout_image, VkImageView* inout_image_view) {
const Image& image{m_dynamic_images[image_index]};
const VkImage input_image{*inout_image};
const VkImage output_image{*image.image};
@@ -126,8 +125,8 @@ void FXAA::Draw(Scheduler& scheduler, size_t image_index, VkImage* inout_image,
const VkPipelineLayout layout{*m_pipeline_layout};
const VkExtent2D extent{m_extent};
- UploadImages(scheduler);
- UpdateDescriptorSets(*inout_image_view, image_index);
+ UploadImages(device, scheduler);
+ UpdateDescriptorSets(device, *inout_image_view, image_index);
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([=](vk::CommandBuffer cmdbuf) {
diff --git a/src/video_core/renderer_vulkan/present/fxaa.h b/src/video_core/renderer_vulkan/present/fxaa.h
index 97a2e5c1cb..7eaf31f81c 100644
--- a/src/video_core/renderer_vulkan/present/fxaa.h
+++ b/src/video_core/renderer_vulkan/present/fxaa.h
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -15,31 +18,33 @@ class StagingBufferPool;
class FXAA final : public AntiAliasPass {
public:
- explicit FXAA(const Device& device, MemoryAllocator& allocator, size_t image_count,
- VkExtent2D extent);
+ explicit FXAA(const Device& device, MemoryAllocator& allocator, size_t image_count, VkExtent2D extent);
~FXAA() override;
- void Draw(Scheduler& scheduler, size_t image_index, VkImage* inout_image,
- VkImageView* inout_image_view) override;
+ void Draw(const Device& device, Scheduler& scheduler, size_t image_index, VkImage* inout_image, VkImageView* inout_image_view) override;
private:
- void CreateImages();
- void CreateRenderPasses();
- void CreateSampler();
- void CreateShaders();
- void CreateDescriptorPool();
- void CreateDescriptorSetLayouts();
- void CreateDescriptorSets();
- void CreatePipelineLayouts();
- void CreatePipelines();
- void UpdateDescriptorSets(VkImageView image_view, size_t image_index);
- void UploadImages(Scheduler& scheduler);
-
- const Device& m_device;
- MemoryAllocator& m_allocator;
+ void CreateImages(const Device& device, MemoryAllocator& allocator);
+ void CreateRenderPasses(const Device& device);
+ void CreateSampler(const Device& device);
+ void CreateShaders(const Device& device);
+ void CreateDescriptorPool(const Device& device);
+ void CreateDescriptorSetLayouts(const Device& device);
+ void CreateDescriptorSets(const Device& device);
+ void CreatePipelineLayouts(const Device& device);
+ void CreatePipelines(const Device& device);
+ void UpdateDescriptorSets(const Device& device, VkImageView image_view, size_t image_index);
+ void UploadImages(const Device& device, Scheduler& scheduler);
+
+ struct Image {
+ vk::DescriptorSets descriptor_sets{};
+ vk::Framebuffer framebuffer{};
+ vk::Image image{};
+ vk::ImageView image_view{};
+ };
+ std::vector<Image> m_dynamic_images{};
const VkExtent2D m_extent;
const u32 m_image_count;
-
vk::ShaderModule m_vertex_shader{};
vk::ShaderModule m_fragment_shader{};
vk::DescriptorPool m_descriptor_pool{};
@@ -47,17 +52,8 @@ private:
vk::PipelineLayout m_pipeline_layout{};
vk::Pipeline m_pipeline{};
vk::RenderPass m_renderpass{};
-
- struct Image {
- vk::DescriptorSets descriptor_sets{};
- vk::Framebuffer framebuffer{};
- vk::Image image{};
- vk::ImageView image_view{};
- };
- std::vector<Image> m_dynamic_images{};
- bool m_images_ready{};
-
vk::Sampler m_sampler{};
+ bool m_images_ready{};
};
} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/present/layer.cpp b/src/video_core/renderer_vulkan/present/layer.cpp
index e20473d2af..14935f92bb 100644
--- a/src/video_core/renderer_vulkan/present/layer.cpp
+++ b/src/video_core/renderer_vulkan/present/layer.cpp
@@ -56,13 +56,15 @@ VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) {
} // Anonymous namespace
-Layer::Layer(const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
- Tegra::MaxwellDeviceMemoryManager& device_memory_, size_t image_count_,
- VkExtent2D output_size, VkDescriptorSetLayout layout, const PresentFilters& filters_)
- : device(device_), memory_allocator(memory_allocator_), scheduler(scheduler_),
- device_memory(device_memory_), filters(filters_), image_count(image_count_) {
- CreateDescriptorPool();
- CreateDescriptorSets(layout);
+Layer::Layer(const Device& device, MemoryAllocator& memory_allocator_, Scheduler& scheduler_, Tegra::MaxwellDeviceMemoryManager& device_memory_, size_t image_count_, VkExtent2D output_size, VkDescriptorSetLayout layout, const PresentFilters& filters_)
+ : memory_allocator(memory_allocator_)
+ , scheduler(scheduler_)
+ , device_memory(device_memory_)
+ , filters(filters_)
+ , image_count(image_count_)
+{
+ CreateDescriptorPool(device);
+ CreateDescriptorSets(device, layout);
if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr) {
sr_filter.emplace<FSR>(device, memory_allocator, image_count, output_size);
} else if (filters.get_scaling_filter() == Settings::ScalingFilter::Sgsr) {
@@ -76,7 +78,7 @@ Layer::~Layer() {
ReleaseRawImages();
}
-void Layer::ConfigureDraw(PresentPushConstants* out_push_constants,
+void Layer::ConfigureDraw(const Device& device, PresentPushConstants* out_push_constants,
VkDescriptorSet* out_descriptor_set, RasterizerVulkan& rasterizer,
VkSampler sampler, size_t image_index,
const Tegra::FramebufferConfig& framebuffer,
@@ -89,8 +91,8 @@ void Layer::ConfigureDraw(PresentPushConstants* out_push_constants,
const u32 scaled_height = texture_info ? texture_info->scaled_height : texture_height;
const bool use_accelerated = texture_info.has_value();
- RefreshResources(framebuffer);
- SetAntiAliasPass();
+ RefreshResources(device, framebuffer);
+ SetAntiAliasPass(device);
// Finish any pending renderpass
scheduler.RequestOutsideRenderPassOperationContext();
@@ -108,9 +110,9 @@ void Layer::ConfigureDraw(PresentPushConstants* out_push_constants,
texture_info ? texture_info->image_view : *raw_image_views[image_index];
if (auto* fxaa = std::get_if<FXAA>(&anti_alias)) {
- fxaa->Draw(scheduler, image_index, &source_image, &source_image_view);
+ fxaa->Draw(device, scheduler, image_index, &source_image, &source_image_view);
} else if (auto* smaa = std::get_if<SMAA>(&anti_alias)) {
- smaa->Draw(scheduler, image_index, &source_image, &source_image_view);
+ smaa->Draw(device, scheduler, image_index, &source_image, &source_image_view);
}
auto crop_rect = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height);
@@ -120,30 +122,30 @@ void Layer::ConfigureDraw(PresentPushConstants* out_push_constants,
};
if (auto* fsr = std::get_if<FSR>(&sr_filter)) {
- source_image_view = fsr->Draw(scheduler, image_index, source_image, source_image_view, render_extent, crop_rect);
+ source_image_view = fsr->Draw(device, scheduler, image_index, source_image, source_image_view, render_extent, crop_rect);
crop_rect = {0, 0, 1, 1};
} else if (auto* sgsr = std::get_if<SGSR>(&sr_filter)) {
- source_image_view = sgsr->Draw(scheduler, image_index, source_image, source_image_view, render_extent, crop_rect);
+ source_image_view = sgsr->Draw(device, scheduler, image_index, source_image, source_image_view, render_extent, crop_rect);
crop_rect = {0, 0, 1, 1};
}
- SetMatrixData(*out_push_constants, layout);
- SetVertexData(*out_push_constants, layout, crop_rect);
+ SetMatrixData(device, *out_push_constants, layout);
+ SetVertexData(device, *out_push_constants, layout, crop_rect);
- UpdateDescriptorSet(source_image_view, sampler, image_index);
+ UpdateDescriptorSet(device, source_image_view, sampler, image_index);
*out_descriptor_set = descriptor_sets[image_index];
}
-void Layer::CreateDescriptorPool() {
+void Layer::CreateDescriptorPool(const Device& device) {
descriptor_pool = CreateWrappedDescriptorPool(device, image_count, image_count);
}
-void Layer::CreateDescriptorSets(VkDescriptorSetLayout layout) {
+void Layer::CreateDescriptorSets(const Device& device, VkDescriptorSetLayout layout) {
const std::vector layouts(image_count, layout);
descriptor_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts);
}
-void Layer::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) {
+void Layer::CreateStagingBuffer(const Device& device, const Tegra::FramebufferConfig& framebuffer) {
const VkBufferCreateInfo ci{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
@@ -159,7 +161,7 @@ void Layer::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) {
buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload);
}
-void Layer::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
+void Layer::CreateRawImages(const Device& device, const Tegra::FramebufferConfig& framebuffer) {
const auto format = GetFormat(framebuffer);
resource_ticks.resize(image_count);
raw_images.resize(image_count);
@@ -172,7 +174,7 @@ void Layer::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
}
}
-void Layer::RefreshResources(const Tegra::FramebufferConfig& framebuffer) {
+void Layer::RefreshResources(const Device& device, const Tegra::FramebufferConfig& framebuffer) {
if (framebuffer.width == raw_width && framebuffer.height == raw_height &&
framebuffer.pixel_format == pixel_format && !raw_images.empty()) {
return;
@@ -184,11 +186,11 @@ void Layer::RefreshResources(const Tegra::FramebufferConfig& framebuffer) {
anti_alias.emplace<std::monostate>();
ReleaseRawImages();
- CreateStagingBuffer(framebuffer);
- CreateRawImages(framebuffer);
+ CreateStagingBuffer(device, framebuffer);
+ CreateRawImages(device, framebuffer);
}
-void Layer::SetAntiAliasPass() {
+void Layer::SetAntiAliasPass(const Device& device) {
if (!std::holds_alternative<std::monostate>(anti_alias) && anti_alias_setting == filters.get_anti_aliasing())
return;
@@ -229,20 +231,17 @@ u64 Layer::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer,
return GetSizeInBytes(framebuffer) * image_index;
}
-void Layer::SetMatrixData(PresentPushConstants& data,
- const Layout::FramebufferLayout& layout) const {
- data.modelview_matrix =
- MakeOrthographicMatrix(static_cast<f32>(layout.width), static_cast<f32>(layout.height));
+void Layer::SetMatrixData(const Device& device, PresentPushConstants& data, const Layout::FramebufferLayout& layout) const {
+ data.modelview_matrix = MakeOrthographicMatrix(f32(layout.width), static_cast<f32>(layout.height));
}
-void Layer::SetVertexData(PresentPushConstants& data, const Layout::FramebufferLayout& layout,
- const Common::Rectangle<f32>& crop) const {
+void Layer::SetVertexData(const Device& device, PresentPushConstants& data, const Layout::FramebufferLayout& layout, const Common::Rectangle<f32>& crop) const {
// Map the coordinates to the screen.
const auto& screen = layout.screen;
- const auto x = static_cast<f32>(screen.left);
- const auto y = static_cast<f32>(screen.top);
- const auto w = static_cast<f32>(screen.GetWidth());
- const auto h = static_cast<f32>(screen.GetHeight());
+ const auto x = f32(screen.left);
+ const auto y = f32(screen.top);
+ const auto w = f32(screen.GetWidth());
+ const auto h = f32(screen.GetHeight());
data.vertices[0] = ScreenRectVertex(x, y, crop.left, crop.top);
data.vertices[1] = ScreenRectVertex(x + w, y, crop.right, crop.top);
@@ -250,7 +249,7 @@ void Layer::SetVertexData(PresentPushConstants& data, const Layout::FramebufferL
data.vertices[3] = ScreenRectVertex(x + w, y + h, crop.right, crop.bottom);
}
-void Layer::UpdateDescriptorSet(VkImageView image_view, VkSampler sampler, size_t image_index) {
+void Layer::UpdateDescriptorSet(const Device& device, VkImageView image_view, VkSampler sampler, size_t image_index) {
const VkDescriptorImageInfo image_info{
.sampler = sampler,
.imageView = image_view,
diff --git a/src/video_core/renderer_vulkan/present/layer.h b/src/video_core/renderer_vulkan/present/layer.h
index 47a6a69218..4d75e86ba6 100644
--- a/src/video_core/renderer_vulkan/present/layer.h
+++ b/src/video_core/renderer_vulkan/present/layer.h
@@ -52,33 +52,31 @@ public:
const PresentFilters& filters);
~Layer();
- void ConfigureDraw(PresentPushConstants* out_push_constants,
+ void ConfigureDraw(const Device& device, PresentPushConstants* out_push_constants,
VkDescriptorSet* out_descriptor_set, RasterizerVulkan& rasterizer,
VkSampler sampler, size_t image_index,
const Tegra::FramebufferConfig& framebuffer,
const Layout::FramebufferLayout& layout);
private:
- void CreateDescriptorPool();
- void CreateDescriptorSets(VkDescriptorSetLayout layout);
- void CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer);
- void CreateRawImages(const Tegra::FramebufferConfig& framebuffer);
+ void CreateDescriptorPool(const Device& device);
+ void CreateDescriptorSets(const Device& device, VkDescriptorSetLayout layout);
+ void CreateStagingBuffer(const Device& device, const Tegra::FramebufferConfig& framebuffer);
+ void CreateRawImages(const Device& device, const Tegra::FramebufferConfig& framebuffer);
- void RefreshResources(const Tegra::FramebufferConfig& framebuffer);
- void SetAntiAliasPass();
+ void RefreshResources(const Device& device, const Tegra::FramebufferConfig& framebuffer);
+ void SetAntiAliasPass(const Device& device);
void ReleaseRawImages();
u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const;
u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, size_t image_index) const;
- void SetMatrixData(PresentPushConstants& data, const Layout::FramebufferLayout& layout) const;
- void SetVertexData(PresentPushConstants& data, const Layout::FramebufferLayout& layout,
- const Common::Rectangle<f32>& crop) const;
- void UpdateDescriptorSet(VkImageView image_view, VkSampler sampler, size_t image_index);
+ void SetMatrixData(const Device& device, PresentPushConstants& data, const Layout::FramebufferLayout& layout) const;
+ void SetVertexData(const Device& device, PresentPushConstants& data, const Layout::FramebufferLayout& layout, const Common::Rectangle<f32>& crop) const;
+ void UpdateDescriptorSet(const Device& device, VkImageView image_view, VkSampler sampler, size_t image_index);
void UpdateRawImage(const Tegra::FramebufferConfig& framebuffer, size_t image_index);
private:
- const Device& device;
MemoryAllocator& memory_allocator;
Scheduler& scheduler;
Tegra::MaxwellDeviceMemoryManager& device_memory;
diff --git a/src/video_core/renderer_vulkan/present/sgsr.cpp b/src/video_core/renderer_vulkan/present/sgsr.cpp
index 4175190690..5fc746458d 100644
--- a/src/video_core/renderer_vulkan/present/sgsr.cpp
+++ b/src/video_core/renderer_vulkan/present/sgsr.cpp
@@ -20,8 +20,7 @@ namespace Vulkan {
using PushConstants = std::array<u32, 4 + 2 + 1>;
SGSR::SGSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, VkExtent2D extent, bool edge_dir)
- : m_device{device}
- , m_memory_allocator{memory_allocator}
+ : m_memory_allocator{memory_allocator}
, m_image_count{image_count}
, m_extent{extent}
, m_edge_dir{edge_dir}
@@ -30,21 +29,21 @@ SGSR::SGSR(const Device& device, MemoryAllocator& memory_allocator, size_t image
m_dynamic_images.resize(m_image_count);
for (auto& images : m_dynamic_images) {
images.image = CreateWrappedImage(m_memory_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
- images.image_view = CreateWrappedImageView(m_device, images.image, VK_FORMAT_R16G16B16A16_SFLOAT);
+ images.image_view = CreateWrappedImageView(device, images.image, VK_FORMAT_R16G16B16A16_SFLOAT);
}
- m_renderpass = CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT);
+ m_renderpass = CreateWrappedRenderPass(device, VK_FORMAT_R16G16B16A16_SFLOAT);
for (auto& images : m_dynamic_images)
- images.framebuffer = CreateWrappedFramebuffer(m_device, m_renderpass, images.image_view, m_extent);
+ images.framebuffer = CreateWrappedFramebuffer(device, m_renderpass, images.image_view, m_extent);
- m_sampler = CreateBilinearSampler(m_device);
- m_vert_shader = BuildShader(m_device, SGSR1_SHADER_VERT_SPV);
+ m_sampler = CreateBilinearSampler(device);
+ m_vert_shader = BuildShader(device, SGSR1_SHADER_VERT_SPV);
m_stage_shader = m_edge_dir
- ? BuildShader(m_device, SGSR1_SHADER_MOBILE_EDGE_DIRECTION_FRAG_SPV)
- : BuildShader(m_device, SGSR1_SHADER_MOBILE_FRAG_SPV);
+ ? BuildShader(device, SGSR1_SHADER_MOBILE_EDGE_DIRECTION_FRAG_SPV)
+ : BuildShader(device, SGSR1_SHADER_MOBILE_FRAG_SPV);
// 2 descriptors, 2 descriptor sets per invocation
- m_descriptor_pool = CreateWrappedDescriptorPool(m_device, m_image_count, m_image_count);
- m_descriptor_set_layout = CreateWrappedDescriptorSetLayout(m_device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER});
+ m_descriptor_pool = CreateWrappedDescriptorPool(device, m_image_count, m_image_count);
+ m_descriptor_set_layout = CreateWrappedDescriptorSetLayout(device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER});
VkDescriptorSetLayout layout = *m_descriptor_set_layout;
for (auto& images : m_dynamic_images)
@@ -64,20 +63,20 @@ SGSR::SGSR(const Device& device, MemoryAllocator& memory_allocator, size_t image
.pushConstantRangeCount = 1,
.pPushConstantRanges = &range,
};
- m_pipeline_layout = m_device.GetLogical().CreatePipelineLayout(ci);
- m_stage_pipeline = CreateWrappedPipeline(m_device, m_renderpass, m_pipeline_layout, std::tie(m_vert_shader, m_stage_shader));
+ m_pipeline_layout = device.GetLogical().CreatePipelineLayout(ci);
+ m_stage_pipeline = CreateWrappedPipeline(device, m_renderpass, m_pipeline_layout, std::tie(m_vert_shader, m_stage_shader));
}
-void SGSR::UpdateDescriptorSets(VkImageView image_view, size_t image_index) {
+void SGSR::UpdateDescriptorSets(const Device& device, VkImageView image_view, size_t image_index) {
Images& images = m_dynamic_images[image_index];
std::vector<VkDescriptorImageInfo> image_infos;
std::vector<VkWriteDescriptorSet> updates;
image_infos.reserve(1);
updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, images.descriptor_sets[0], 0));
- m_device.GetLogical().UpdateDescriptorSets(updates, {});
+ device.GetLogical().UpdateDescriptorSets(updates, {});
}
-void SGSR::UploadImages(Scheduler& scheduler) {
+void SGSR::UploadImages(const Device& device, Scheduler& scheduler) {
if (!m_images_ready) {
scheduler.Record([&](vk::CommandBuffer cmdbuf) {
for (auto& image : m_dynamic_images)
@@ -88,7 +87,7 @@ void SGSR::UploadImages(Scheduler& scheduler) {
}
}
-VkImageView SGSR::Draw(Scheduler& scheduler, size_t image_index, VkImage source_image, VkImageView source_image_view, VkExtent2D input_image_extent, const Common::Rectangle<f32>& crop_rect) {
+VkImageView SGSR::Draw(const Device& device, Scheduler& scheduler, size_t image_index, VkImage source_image, VkImageView source_image_view, VkExtent2D input_image_extent, const Common::Rectangle<f32>& crop_rect) {
Images& images = m_dynamic_images[image_index];
auto const output_image = *images.image;
auto const descriptor_set = images.descriptor_sets[0];
@@ -122,8 +121,8 @@ VkImageView SGSR::Draw(Scheduler& scheduler, size_t image_index, VkImage source_
viewport_con[5] = std::bit_cast<u32>(viewport_height / input_image_height);
viewport_con[6] = std::bit_cast<u32>(sharpening);
- UploadImages(scheduler);
- UpdateDescriptorSets(source_image_view, image_index);
+ UploadImages(device, scheduler);
+ UpdateDescriptorSets(device, source_image_view, image_index);
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([=](vk::CommandBuffer cmdbuf) {
diff --git a/src/video_core/renderer_vulkan/present/sgsr.h b/src/video_core/renderer_vulkan/present/sgsr.h
index 67b25be75d..42ba00898f 100644
--- a/src/video_core/renderer_vulkan/present/sgsr.h
+++ b/src/video_core/renderer_vulkan/present/sgsr.h
@@ -16,13 +16,12 @@ class SGSR {
public:
static constexpr size_t SGSR_STAGE_COUNT = 1;
explicit SGSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, VkExtent2D extent, bool edge_dir);
- VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImage source_image, VkImageView source_image_view, VkExtent2D input_image_extent, const Common::Rectangle<f32>& crop_rect);
+ VkImageView Draw(const Device& device, Scheduler& scheduler, size_t image_index, VkImage source_image, VkImageView source_image_view, VkExtent2D input_image_extent, const Common::Rectangle<f32>& crop_rect);
private:
- void Initialize();
- void UploadImages(Scheduler& scheduler);
- void UpdateDescriptorSets(VkImageView image_view, size_t image_index);
+ void Initialize(const Device& device);
+ void UploadImages(const Device& device, Scheduler& scheduler);
+ void UpdateDescriptorSets(const Device& device, VkImageView image_view, size_t image_index);
- const Device& m_device;
MemoryAllocator& m_memory_allocator;
const size_t m_image_count;
const VkExtent2D m_extent;
diff --git a/src/video_core/renderer_vulkan/present/smaa.cpp b/src/video_core/renderer_vulkan/present/smaa.cpp
index 686112f2f0..28b0427fa0 100644
--- a/src/video_core/renderer_vulkan/present/smaa.cpp
+++ b/src/video_core/renderer_vulkan/present/smaa.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 2022 yuzu Emulator Project
@@ -27,22 +27,24 @@
namespace Vulkan {
SMAA::SMAA(const Device& device, MemoryAllocator& allocator, size_t image_count, VkExtent2D extent)
- : m_device(device), m_allocator(allocator), m_extent(extent),
- m_image_count(static_cast<u32>(image_count)) {
- CreateImages();
- CreateRenderPasses();
- CreateSampler();
- CreateShaders();
- CreateDescriptorPool();
- CreateDescriptorSetLayouts();
- CreateDescriptorSets();
- CreatePipelineLayouts();
- CreatePipelines();
+ : m_allocator(allocator)
+ , m_extent(extent)
+ , m_image_count(u32(image_count))
+{
+ CreateImages(device);
+ CreateRenderPasses(device);
+ CreateSampler(device);
+ CreateShaders(device);
+ CreateDescriptorPool(device);
+ CreateDescriptorSetLayouts(device);
+ CreateDescriptorSets(device);
+ CreatePipelineLayouts(device);
+ CreatePipelines(device);
}
SMAA::~SMAA() = default;
-void SMAA::CreateImages() {
+void SMAA::CreateImages(const Device& device) {
static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT};
static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT};
@@ -50,9 +52,9 @@ void SMAA::CreateImages() {
m_static_images[Search] = CreateWrappedImage(m_allocator, search_extent, VK_FORMAT_R8_UNORM);
m_static_image_views[Area] =
- CreateWrappedImageView(m_device, m_static_images[Area], VK_FORMAT_R8G8_UNORM);
+ CreateWrappedImageView(device, m_static_images[Area], VK_FORMAT_R8G8_UNORM);
m_static_image_views[Search] =
- CreateWrappedImageView(m_device, m_static_images[Search], VK_FORMAT_R8_UNORM);
+ CreateWrappedImageView(device, m_static_images[Search], VK_FORMAT_R8_UNORM);
for (u32 i = 0; i < m_image_count; i++) {
Images& images = m_dynamic_images.emplace_back();
@@ -64,39 +66,39 @@ void SMAA::CreateImages() {
CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
images.image_views[Blend] =
- CreateWrappedImageView(m_device, images.images[Blend], VK_FORMAT_R16G16B16A16_SFLOAT);
+ CreateWrappedImageView(device, images.images[Blend], VK_FORMAT_R16G16B16A16_SFLOAT);
images.image_views[Edges] =
- CreateWrappedImageView(m_device, images.images[Edges], VK_FORMAT_R16G16_SFLOAT);
+ CreateWrappedImageView(device, images.images[Edges], VK_FORMAT_R16G16_SFLOAT);
images.image_views[Output] =
- CreateWrappedImageView(m_device, images.images[Output], VK_FORMAT_R16G16B16A16_SFLOAT);
+ CreateWrappedImageView(device, images.images[Output], VK_FORMAT_R16G16B16A16_SFLOAT);
}
}
-void SMAA::CreateRenderPasses() {
- m_renderpasses[EdgeDetection] = CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16_SFLOAT);
+void SMAA::CreateRenderPasses(const Device& device) {
+ m_renderpasses[EdgeDetection] = CreateWrappedRenderPass(device, VK_FORMAT_R16G16_SFLOAT);
m_renderpasses[BlendingWeightCalculation] =
- CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT);
+ CreateWrappedRenderPass(device, VK_FORMAT_R16G16B16A16_SFLOAT);
m_renderpasses[NeighborhoodBlending] =
- CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT);
+ CreateWrappedRenderPass(device, VK_FORMAT_R16G16B16A16_SFLOAT);
for (auto& images : m_dynamic_images) {
images.framebuffers[EdgeDetection] = CreateWrappedFramebuffer(
- m_device, m_renderpasses[EdgeDetection], images.image_views[Edges], m_extent);
+ device, m_renderpasses[EdgeDetection], images.image_views[Edges], m_extent);
images.framebuffers[BlendingWeightCalculation] =
- CreateWrappedFramebuffer(m_device, m_renderpasses[BlendingWeightCalculation],
+ CreateWrappedFramebuffer(device, m_renderpasses[BlendingWeightCalculation],
images.image_views[Blend], m_extent);
images.framebuffers[NeighborhoodBlending] = CreateWrappedFramebuffer(
- m_device, m_renderpasses[NeighborhoodBlending], images.image_views[Output], m_extent);
+ device, m_renderpasses[NeighborhoodBlending], images.image_views[Output], m_extent);
}
}
-void SMAA::CreateSampler() {
- m_sampler = CreateWrappedSampler(m_device);
+void SMAA::CreateSampler(const Device& device) {
+ m_sampler = CreateWrappedSampler(device);
}
-void SMAA::CreateShaders() {
+void SMAA::CreateShaders(const Device& device) {
// These match the order of the SMAAStage enum
static constexpr std::array vert_shader_sources{
ARRAY_TO_SPAN(SMAA_EDGE_DETECTION_VERT_SPV),
@@ -110,33 +112,33 @@ void SMAA::CreateShaders() {
};
for (size_t i = 0; i < MaxSMAAStage; i++) {
- m_vertex_shaders[i] = CreateWrappedShaderModule(m_device, vert_shader_sources[i]);
- m_fragment_shaders[i] = CreateWrappedShaderModule(m_device, frag_shader_sources[i]);
+ m_vertex_shaders[i] = CreateWrappedShaderModule(device, vert_shader_sources[i]);
+ m_fragment_shaders[i] = CreateWrappedShaderModule(device, frag_shader_sources[i]);
}
}
-void SMAA::CreateDescriptorPool() {
+void SMAA::CreateDescriptorPool(const Device& device) {
// Edge detection: 1 descriptor
// Blending weight calculation: 3 descriptors
// Neighborhood blending: 2 descriptors
// 6 descriptors, 3 descriptor sets per image
- m_descriptor_pool = CreateWrappedDescriptorPool(m_device, 6 * m_image_count, 3 * m_image_count);
+ m_descriptor_pool = CreateWrappedDescriptorPool(device, 6 * m_image_count, 3 * m_image_count);
}
-void SMAA::CreateDescriptorSetLayouts() {
+void SMAA::CreateDescriptorSetLayouts(const Device& device) {
m_descriptor_set_layouts[EdgeDetection] =
- CreateWrappedDescriptorSetLayout(m_device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER});
+ CreateWrappedDescriptorSetLayout(device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER});
m_descriptor_set_layouts[BlendingWeightCalculation] =
- CreateWrappedDescriptorSetLayout(m_device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ CreateWrappedDescriptorSetLayout(device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER});
m_descriptor_set_layouts[NeighborhoodBlending] =
- CreateWrappedDescriptorSetLayout(m_device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ CreateWrappedDescriptorSetLayout(device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER});
}
-void SMAA::CreateDescriptorSets() {
+void SMAA::CreateDescriptorSets(const Device& device) {
std::vector<VkDescriptorSetLayout> layouts(m_descriptor_set_layouts.size());
std::ranges::transform(m_descriptor_set_layouts, layouts.begin(),
[](auto& layout) { return *layout; });
@@ -146,21 +148,21 @@ void SMAA::CreateDescriptorSets() {
}
}
-void SMAA::CreatePipelineLayouts() {
+void SMAA::CreatePipelineLayouts(const Device& device) {
for (size_t i = 0; i < MaxSMAAStage; i++) {
- m_pipeline_layouts[i] = CreateWrappedPipelineLayout(m_device, m_descriptor_set_layouts[i]);
+ m_pipeline_layouts[i] = CreateWrappedPipelineLayout(device, m_descriptor_set_layouts[i]);
}
}
-void SMAA::CreatePipelines() {
+void SMAA::CreatePipelines(const Device& device) {
for (size_t i = 0; i < MaxSMAAStage; i++) {
m_pipelines[i] =
- CreateWrappedPipeline(m_device, m_renderpasses[i], m_pipeline_layouts[i],
+ CreateWrappedPipeline(device, m_renderpasses[i], m_pipeline_layouts[i],
std::tie(m_vertex_shaders[i], m_fragment_shaders[i]));
}
}
-void SMAA::UpdateDescriptorSets(VkImageView image_view, size_t image_index) {
+void SMAA::UpdateDescriptorSets(const Device& device, VkImageView image_view, size_t image_index) {
Images& images = m_dynamic_images[image_index];
std::vector<VkDescriptorImageInfo> image_infos;
std::vector<VkWriteDescriptorSet> updates;
@@ -184,10 +186,10 @@ void SMAA::UpdateDescriptorSets(VkImageView image_view, size_t image_index) {
updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *images.image_views[Blend],
images.descriptor_sets[NeighborhoodBlending], 1));
- m_device.GetLogical().UpdateDescriptorSets(updates, {});
+ device.GetLogical().UpdateDescriptorSets(updates, {});
}
-void SMAA::UploadImages(Scheduler& scheduler) {
+void SMAA::UploadImages(const Device& device, Scheduler& scheduler) {
if (m_images_ready) {
return;
}
@@ -195,9 +197,9 @@ void SMAA::UploadImages(Scheduler& scheduler) {
static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT};
static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT};
- UploadImage(m_device, m_allocator, scheduler, m_static_images[Area], area_extent,
+ UploadImage(device, m_allocator, scheduler, m_static_images[Area], area_extent,
VK_FORMAT_R8G8_UNORM, ARRAY_TO_SPAN(areaTexBytes));
- UploadImage(m_device, m_allocator, scheduler, m_static_images[Search], search_extent,
+ UploadImage(device, m_allocator, scheduler, m_static_images[Search], search_extent,
VK_FORMAT_R8_UNORM, ARRAY_TO_SPAN(searchTexBytes));
scheduler.Record([&](vk::CommandBuffer cmdbuf) {
@@ -212,8 +214,7 @@ void SMAA::UploadImages(Scheduler& scheduler) {
m_images_ready = true;
}
-void SMAA::Draw(Scheduler& scheduler, size_t image_index, VkImage* inout_image,
- VkImageView* inout_image_view) {
+void SMAA::Draw(const Device& device, Scheduler& scheduler, size_t image_index, VkImage* inout_image, VkImageView* inout_image_view) {
Images& images = m_dynamic_images[image_index];
VkImage input_image = *inout_image;
@@ -232,8 +233,8 @@ void SMAA::Draw(Scheduler& scheduler, size_t image_index, VkImage* inout_image,
*images.framebuffers[BlendingWeightCalculation];
VkFramebuffer neighborhood_blending_framebuffer = *images.framebuffers[NeighborhoodBlending];
- UploadImages(scheduler);
- UpdateDescriptorSets(*inout_image_view, image_index);
+ UploadImages(device, scheduler);
+ UpdateDescriptorSets(device, *inout_image_view, image_index);
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([=, this](vk::CommandBuffer cmdbuf) {
diff --git a/src/video_core/renderer_vulkan/present/smaa.h b/src/video_core/renderer_vulkan/present/smaa.h
index fdf6def070..a547161395 100644
--- a/src/video_core/renderer_vulkan/present/smaa.h
+++ b/src/video_core/renderer_vulkan/present/smaa.h
@@ -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
@@ -16,11 +19,10 @@ class StagingBufferPool;
class SMAA final : public AntiAliasPass {
public:
- explicit SMAA(const Device& device, MemoryAllocator& allocator, size_t image_count,
- VkExtent2D extent);
+ explicit SMAA(const Device& device, MemoryAllocator& allocator, size_t image_count, VkExtent2D extent);
~SMAA() override;
- void Draw(Scheduler& scheduler, size_t image_index, VkImage* inout_image,
+ void Draw(const Device& device, Scheduler& scheduler, size_t image_index, VkImage* inout_image,
VkImageView* inout_image_view) override;
private:
@@ -44,19 +46,18 @@ private:
MaxDynamicImage = 3,
};
- void CreateImages();
- void CreateRenderPasses();
- void CreateSampler();
- void CreateShaders();
- void CreateDescriptorPool();
- void CreateDescriptorSetLayouts();
- void CreateDescriptorSets();
- void CreatePipelineLayouts();
- void CreatePipelines();
- void UpdateDescriptorSets(VkImageView image_view, size_t image_index);
- void UploadImages(Scheduler& scheduler);
-
- const Device& m_device;
+ void CreateImages(const Device& device);
+ void CreateRenderPasses(const Device& device);
+ void CreateSampler(const Device& device);
+ void CreateShaders(const Device& device);
+ void CreateDescriptorPool(const Device& device);
+ void CreateDescriptorSetLayouts(const Device& device);
+ void CreateDescriptorSets(const Device& device);
+ void CreatePipelineLayouts(const Device& device);
+ void CreatePipelines(const Device& device);
+ void UpdateDescriptorSets(const Device& device, VkImageView image_view, size_t image_index);
+ void UploadImages(const Device& device, Scheduler& scheduler);
+
MemoryAllocator& m_allocator;
const VkExtent2D m_extent;
const u32 m_image_count;
diff --git a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp
index 22ffacf119..549b0660c1 100644
--- a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp
+++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -15,19 +18,20 @@
namespace Vulkan {
-WindowAdaptPass::WindowAdaptPass(const Device& device_, VkFormat frame_format,
- vk::Sampler&& sampler_, vk::ShaderModule&& fragment_shader_)
- : device(device_), sampler(std::move(sampler_)), fragment_shader(std::move(fragment_shader_)) {
- CreateDescriptorSetLayout();
- CreatePipelineLayout();
- CreateVertexShader();
- CreateRenderPass(frame_format);
- CreatePipelines();
+WindowAdaptPass::WindowAdaptPass(const Device& device, VkFormat frame_format, vk::Sampler&& sampler_, vk::ShaderModule&& fragment_shader_)
+ : sampler(std::move(sampler_))
+ , fragment_shader(std::move(fragment_shader_))
+{
+ CreateDescriptorSetLayout(device);
+ CreatePipelineLayout(device);
+ CreateVertexShader(device);
+ CreateRenderPass(device, frame_format);
+ CreatePipelines(device);
}
WindowAdaptPass::~WindowAdaptPass() = default;
-void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, size_t image_index,
+void WindowAdaptPass::Draw(const Device& device, RasterizerVulkan& rasterizer, Scheduler& scheduler, size_t image_index,
std::list<Layer>& layers,
std::span<const Tegra::FramebufferConfig> configs,
const Layout::FramebufferLayout& layout, Frame* dst) {
@@ -60,7 +64,7 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s
break;
}
- layer_it->ConfigureDraw(&push_constants[i], &descriptor_sets[i], rasterizer, *sampler,
+ layer_it->ConfigureDraw(device, &push_constants[i], &descriptor_sets[i], rasterizer, *sampler,
image_index, configs[i], layout);
layer_it++;
}
@@ -111,12 +115,12 @@ VkRenderPass WindowAdaptPass::GetRenderPass() {
return *render_pass;
}
-void WindowAdaptPass::CreateDescriptorSetLayout() {
+void WindowAdaptPass::CreateDescriptorSetLayout(const Device& device) {
descriptor_set_layout =
CreateWrappedDescriptorSetLayout(device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER});
}
-void WindowAdaptPass::CreatePipelineLayout() {
+void WindowAdaptPass::CreatePipelineLayout(const Device& device) {
const VkPushConstantRange range{
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
.offset = 0,
@@ -134,15 +138,15 @@ void WindowAdaptPass::CreatePipelineLayout() {
});
}
-void WindowAdaptPass::CreateVertexShader() {
+void WindowAdaptPass::CreateVertexShader(const Device& device) {
vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV);
}
-void WindowAdaptPass::CreateRenderPass(VkFormat frame_format) {
+void WindowAdaptPass::CreateRenderPass(const Device& device, VkFormat frame_format) {
render_pass = CreateWrappedRenderPass(device, frame_format, VK_IMAGE_LAYOUT_UNDEFINED);
}
-void WindowAdaptPass::CreatePipelines() {
+void WindowAdaptPass::CreatePipelines(const Device& device) {
opaque_pipeline = CreateWrappedPipeline(device, render_pass, pipeline_layout,
std::tie(vertex_shader, fragment_shader));
premultiplied_pipeline = CreateWrappedPremultipliedBlendingPipeline(
diff --git a/src/video_core/renderer_vulkan/present/window_adapt_pass.h b/src/video_core/renderer_vulkan/present/window_adapt_pass.h
index cf667a4fc6..58d6fc01c0 100644
--- a/src/video_core/renderer_vulkan/present/window_adapt_pass.h
+++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.h
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -30,7 +33,7 @@ public:
vk::ShaderModule&& fragment_shader);
~WindowAdaptPass();
- void Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, size_t image_index,
+ void Draw(const Device& device, RasterizerVulkan& rasterizer, Scheduler& scheduler, size_t image_index,
std::list<Layer>& layers, std::span<const Tegra::FramebufferConfig> configs,
const Layout::FramebufferLayout& layout, Frame* dst);
@@ -38,14 +41,12 @@ public:
VkRenderPass GetRenderPass();
private:
- void CreateDescriptorSetLayout();
- void CreatePipelineLayout();
- void CreateVertexShader();
- void CreateRenderPass(VkFormat frame_format);
- void CreatePipelines();
+ void CreateDescriptorSetLayout(const Device& device);
+ void CreatePipelineLayout(const Device& device);
+ void CreateVertexShader(const Device& device);
+ void CreateRenderPass(const Device& device, VkFormat frame_format);
+ void CreatePipelines(const Device& device);
-private:
- const Device& device;
vk::DescriptorSetLayout descriptor_set_layout;
vk::PipelineLayout pipeline_layout;
vk::Sampler sampler;
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 30a39ef81e..b0a7d0c579 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -188,7 +188,7 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
Frame* frame = present_manager.GetRenderFrame();
scheduler.RequestOutsideRenderPassOperationContext();
- blit_swapchain.DrawToFrame(rasterizer, frame, framebuffers,
+ blit_swapchain.DrawToFrame(device, rasterizer, frame, framebuffers,
render_window.GetFramebufferLayout(), swapchain.GetImageCount(),
swapchain.GetImageViewFormat());
scheduler.Flush(*frame->render_ready);
@@ -226,12 +226,12 @@ vk::Buffer RendererVulkan::RenderToBuffer(std::span<const Tegra::FramebufferConf
f.image =
CreateWrappedImage(memory_allocator, VkExtent2D{layout.width, layout.height}, format);
f.image_view = CreateWrappedImageView(device, f.image, format);
- f.framebuffer = blit_capture.CreateFramebuffer(layout, *f.image_view, format);
+ f.framebuffer = blit_capture.CreateFramebuffer(device, layout, *f.image_view, format);
return f;
}();
auto dst_buffer = CreateWrappedBuffer(memory_allocator, buffer_size, MemoryUsage::Download);
- blit_capture.DrawToFrame(rasterizer, &frame, framebuffers, layout, 1, format);
+ blit_capture.DrawToFrame(device, rasterizer, &frame, framebuffers, layout, 1, format);
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([&](vk::CommandBuffer cmdbuf) {
@@ -295,12 +295,12 @@ void RendererVulkan::RenderAppletCaptureLayer(
if (!applet_frame.image) {
applet_frame.image = CreateWrappedImage(memory_allocator, CaptureImageSize, CaptureFormat);
applet_frame.image_view = CreateWrappedImageView(device, applet_frame.image, CaptureFormat);
- applet_frame.framebuffer = blit_applet.CreateFramebuffer(
+ applet_frame.framebuffer = blit_applet.CreateFramebuffer(device,
VideoCore::Capture::Layout, *applet_frame.image_view, CaptureFormat);
}
scheduler.RequestOutsideRenderPassOperationContext();
- blit_applet.DrawToFrame(rasterizer, &applet_frame, framebuffers, VideoCore::Capture::Layout, 1,
+ blit_applet.DrawToFrame(device, rasterizer, &applet_frame, framebuffers, VideoCore::Capture::Layout, 1,
CaptureFormat);
}
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index a742e4073c..05314fea27 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -18,23 +18,26 @@
namespace Vulkan {
-BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, const Device& device_,
- MemoryAllocator& memory_allocator_, PresentManager& present_manager_,
- Scheduler& scheduler_, const PresentFilters& filters_)
- : device_memory{device_memory_}, device{device_}, memory_allocator{memory_allocator_},
- present_manager{present_manager_}, scheduler{scheduler_}, filters{filters_},
- image_count{1}, image_index{0},
- swapchain_view_format{VK_FORMAT_B8G8R8A8_UNORM} {}
+BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, const Device& device_, MemoryAllocator& memory_allocator_, PresentManager& present_manager_, Scheduler& scheduler_, const PresentFilters& filters_)
+ : device_memory{device_memory_}
+ , memory_allocator{memory_allocator_}
+ , present_manager{present_manager_}
+ , scheduler{scheduler_}
+ , filters{filters_}
+ , image_count{1}
+ , image_index{0}
+ , swapchain_view_format{VK_FORMAT_B8G8R8A8_UNORM}
+{}
BlitScreen::~BlitScreen() = default;
-void BlitScreen::WaitIdle() {
+void BlitScreen::WaitIdle(const Device& device) {
present_manager.WaitPresent();
scheduler.Finish();
device.GetLogical().WaitIdle();
}
-void BlitScreen::SetWindowAdaptPass() {
+void BlitScreen::SetWindowAdaptPass(const Device& device) {
layers.clear();
scaling_filter = filters.get_scaling_filter();
@@ -82,7 +85,7 @@ void BlitScreen::SetWindowAdaptPass() {
}
}
-void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame,
+void BlitScreen::DrawToFrame(const Device& device, RasterizerVulkan& rasterizer, Frame* frame,
std::span<const Tegra::FramebufferConfig> framebuffers,
const Layout::FramebufferLayout& layout,
size_t current_swapchain_image_count,
@@ -107,8 +110,8 @@ void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame,
}
if (resource_update_required) {
- WaitIdle();
- SetWindowAdaptPass();
+ WaitIdle(device);
+ SetWindowAdaptPass(device);
if (presentation_recreate_required) {
present_manager.RecreateFrame(frame, layout.width, layout.height, swapchain_view_format,
@@ -131,22 +134,22 @@ void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame,
}
}
- window_adapt->Draw(rasterizer, scheduler, image_index, layers, framebuffers, layout, frame);
+ window_adapt->Draw(device, rasterizer, scheduler, image_index, layers, framebuffers, layout, frame);
if (++image_index >= image_count) {
image_index = 0;
}
}
-vk::Framebuffer BlitScreen::CreateFramebuffer(const Layout::FramebufferLayout& layout,
+vk::Framebuffer BlitScreen::CreateFramebuffer(const Device& device, const Layout::FramebufferLayout& layout,
VkImageView image_view,
VkFormat current_view_format) {
bool format_updated = swapchain_view_format != current_view_format;
swapchain_view_format = current_view_format;
if (!window_adapt || scaling_filter != filters.get_scaling_filter() || format_updated) {
- WaitIdle();
- SetWindowAdaptPass();
+ WaitIdle(device);
+ SetWindowAdaptPass(device);
image_index = 0;
}
@@ -155,10 +158,10 @@ vk::Framebuffer BlitScreen::CreateFramebuffer(const Layout::FramebufferLayout& l
.height = layout.height,
};
- return CreateFramebuffer(image_view, extent, window_adapt->GetRenderPass());
+ return CreateFramebuffer(device, image_view, extent, window_adapt->GetRenderPass());
}
-vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent,
+vk::Framebuffer BlitScreen::CreateFramebuffer(const Device& device, const VkImageView& image_view, VkExtent2D extent,
VkRenderPass render_pass) {
return device.GetLogical().CreateFramebuffer(VkFramebufferCreateInfo{
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h
index 531c57fc5c..e50f0bcf33 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -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
@@ -52,23 +55,22 @@ public:
Scheduler& scheduler, const PresentFilters& filters);
~BlitScreen();
- void DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame,
+ void DrawToFrame(const Device& device, RasterizerVulkan& rasterizer, Frame* frame,
std::span<const Tegra::FramebufferConfig> framebuffers,
const Layout::FramebufferLayout& layout, size_t current_swapchain_image_count,
VkFormat current_swapchain_view_format);
- [[nodiscard]] vk::Framebuffer CreateFramebuffer(const Layout::FramebufferLayout& layout,
+ [[nodiscard]] vk::Framebuffer CreateFramebuffer(const Device& device, const Layout::FramebufferLayout& layout,
VkImageView image_view,
VkFormat current_view_format);
private:
- void WaitIdle();
- void SetWindowAdaptPass();
- vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent,
+ void WaitIdle(const Device& device);
+ void SetWindowAdaptPass(const Device& device);
+ vk::Framebuffer CreateFramebuffer(const Device& device, const VkImageView& image_view, VkExtent2D extent,
VkRenderPass render_pass);
Tegra::MaxwellDeviceMemoryManager& device_memory;
- const Device& device;
MemoryAllocator& memory_allocator;
PresentManager& present_manager;
Scheduler& scheduler;
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index 55e8a9b3f0..c24b7a5757 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -234,7 +234,7 @@ struct ConditionalRenderingResolvePushConstants {
};
} // Anonymous namespace
-ComputePass::ComputePass(const Device& device_, DescriptorPool& descriptor_pool,
+ComputePass::ComputePass(const Device& device_, Scheduler& scheduler, DescriptorPool& descriptor_pool,
vk::Span<VkDescriptorSetLayoutBinding> bindings,
vk::Span<VkDescriptorUpdateTemplateEntry> templates,
const DescriptorBankInfo& bank_info,
@@ -270,7 +270,7 @@ ComputePass::ComputePass(const Device& device_, DescriptorPool& descriptor_pool,
.pipelineLayout = *layout,
.set = 0,
});
- descriptor_allocator = descriptor_pool.Allocator(*descriptor_set_layout, bank_info);
+ descriptor_allocator = descriptor_pool.Allocator(device, scheduler, *descriptor_set_layout, bank_info);
}
if (code.empty()) {
return;
@@ -313,7 +313,7 @@ ComputePass::~ComputePass() = default;
Uint8Pass::Uint8Pass(const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool,
StagingBufferPool& staging_buffer_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
- : ComputePass(device_, descriptor_pool, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS,
+ : ComputePass(device_, scheduler_, descriptor_pool, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS,
INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO, {},
VULKAN_UINT8_COMP_SPV),
scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
@@ -355,7 +355,7 @@ QuadIndexedPass::QuadIndexedPass(const Device& device_, Scheduler& scheduler_,
DescriptorPool& descriptor_pool_,
StagingBufferPool& staging_buffer_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
- : ComputePass(device_, descriptor_pool_, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS,
+ : ComputePass(device_, scheduler_, descriptor_pool_, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS,
INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO,
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(u32) * 3>, VULKAN_QUAD_INDEXED_COMP_SPV),
scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
@@ -416,7 +416,7 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble(
ConditionalRenderingResolvePass::ConditionalRenderingResolvePass(
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
- : ComputePass(device_, descriptor_pool_, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS,
+ : ComputePass(device_, scheduler_, descriptor_pool_, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS,
INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO,
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(ConditionalRenderingResolvePushConstants)>,
RESOLVE_CONDITIONAL_RENDER_COMP_SPV),
@@ -470,7 +470,7 @@ QueriesPrefixScanPass::QueriesPrefixScanPass(
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
: ComputePass(
- device_, descriptor_pool_, QUERIES_SCAN_DESCRIPTOR_SET_BINDINGS,
+ device_, scheduler_, descriptor_pool_, QUERIES_SCAN_DESCRIPTOR_SET_BINDINGS,
QUERIES_SCAN_DESCRIPTOR_UPDATE_TEMPLATE, QUERIES_SCAN_BANK_INFO,
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(QueriesPrefixScanPushConstants)>,
device_.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_BASIC_BIT) &&
@@ -547,7 +547,7 @@ ASTCDecoderPass::ASTCDecoderPass(const Device& device_, Scheduler& scheduler_,
StagingBufferPool& staging_buffer_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue_,
MemoryAllocator& memory_allocator_)
- : ComputePass(device_, descriptor_pool_, ASTC_DESCRIPTOR_SET_BINDINGS,
+ : ComputePass(device_, scheduler_, descriptor_pool_, ASTC_DESCRIPTOR_SET_BINDINGS,
ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY, ASTC_BANK_INFO,
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(AstcPushConstants)>, ASTC_DECODER_COMP_SPV),
scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
@@ -746,7 +746,7 @@ BlockLinearUnswizzle3DPass::BlockLinearUnswizzle3DPass(
StagingBufferPool& staging_buffer_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
: ComputePass(
- device_, descriptor_pool_,
+ device_, scheduler_, descriptor_pool_,
BL3D_DESCRIPTOR_SET_BINDINGS,
BL3D_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY,
BL3D_BANK_INFO,
@@ -941,7 +941,7 @@ MSAACopyPass::MSAACopyPass(const Device& device_, Scheduler& scheduler_,
DescriptorPool& descriptor_pool_,
StagingBufferPool& staging_buffer_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
- : ComputePass(device_, descriptor_pool_, MSAA_DESCRIPTOR_SET_BINDINGS,
+ : ComputePass(device_, scheduler_, descriptor_pool_, MSAA_DESCRIPTOR_SET_BINDINGS,
MSAA_DESCRIPTOR_UPDATE_TEMPLATE, MSAA_BANK_INFO, {},
CONVERT_NON_MSAA_TO_MSAA_COMP_SPV),
scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h
index 0e5badce01..cb213dae7e 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.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 2019 yuzu Emulator Project
@@ -35,7 +35,7 @@ struct StagingBufferRef;
class ComputePass {
public:
- explicit ComputePass(const Device& device, DescriptorPool& descriptor_pool,
+ explicit ComputePass(const Device& device, Scheduler& scheduler, DescriptorPool& descriptor_pool,
vk::Span<VkDescriptorSetLayoutBinding> bindings,
vk::Span<VkDescriptorUpdateTemplateEntry> templates,
const DescriptorBankInfo& bank_info,
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index 81ff8fe31a..2c1fd94e67 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -30,7 +30,7 @@ using Shader::ImageBufferDescriptor;
using Shader::Backend::SPIRV::RESCALING_LAYOUT_WORDS_OFFSET;
using Tegra::Texture::TexturePair;
-ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipeline_cache_,
+ComputePipeline::ComputePipeline(const Device& device_, Scheduler& scheduler, vk::PipelineCache& pipeline_cache_,
DescriptorPool& descriptor_pool,
GuestDescriptorQueue& guest_descriptor_queue_,
Common::ThreadWorker* thread_worker,
@@ -46,7 +46,7 @@ ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipel
std::copy_n(info.constant_buffer_used_sizes.begin(), uniform_buffer_sizes.size(),
uniform_buffer_sizes.begin());
- auto func{[this, &descriptor_pool, shader_notify, pipeline_statistics] {
+ auto func{[this, &scheduler, &descriptor_pool, shader_notify, pipeline_statistics] {
DescriptorLayoutBuilder builder{device};
builder.Add(info, VK_SHADER_STAGE_COMPUTE_BIT);
@@ -56,7 +56,7 @@ ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipel
descriptor_update_template =
builder.CreateTemplate(*descriptor_set_layout, *pipeline_layout, uses_push_descriptor);
if (!uses_push_descriptor) {
- descriptor_allocator = descriptor_pool.Allocator(*descriptor_set_layout, info);
+ descriptor_allocator = descriptor_pool.Allocator(device, scheduler, *descriptor_set_layout, info);
}
const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT,
@@ -94,7 +94,7 @@ ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipel
}
if (pipeline_statistics) {
- pipeline_statistics->Collect(*pipeline);
+ pipeline_statistics->Collect(device, *pipeline);
}
std::scoped_lock lock{build_mutex};
is_built = true;
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
index aa84c00e12..f3abe4c931 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
@@ -31,7 +31,7 @@ class Scheduler;
class ComputePipeline {
public:
- explicit ComputePipeline(const Device& device, vk::PipelineCache& pipeline_cache,
+ explicit ComputePipeline(const Device& device, Scheduler& scheduler, vk::PipelineCache& pipeline_cache,
DescriptorPool& descriptor_pool,
GuestDescriptorQueue& guest_descriptor_queue,
Common::ThreadWorker* thread_worker,
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
index 3af9758a31..b020d99b93 100644
--- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.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 2019 yuzu Emulator Project
@@ -125,27 +125,22 @@ vk::DescriptorSets DescriptorAllocator::AllocateDescriptors(size_t count) {
throw vk::Exception(VK_ERROR_OUT_OF_POOL_MEMORY);
}
-DescriptorPool::DescriptorPool(const Device& device_, Scheduler& scheduler)
- : device{device_}, master_semaphore{scheduler.GetMasterSemaphore()} {}
-
+DescriptorPool::DescriptorPool(const Device& device_, Scheduler& scheduler) {}
DescriptorPool::~DescriptorPool() = default;
-DescriptorAllocator DescriptorPool::Allocator(VkDescriptorSetLayout layout,
- std::span<const Shader::Info> infos) {
- return Allocator(layout, MakeBankInfo(infos));
+DescriptorAllocator DescriptorPool::Allocator(const Device& device, Scheduler& scheduler, VkDescriptorSetLayout layout, std::span<const Shader::Info> infos) {
+ return Allocator(device, scheduler, layout, MakeBankInfo(infos));
}
-DescriptorAllocator DescriptorPool::Allocator(VkDescriptorSetLayout layout,
- const Shader::Info& info) {
- return Allocator(layout, MakeBankInfo(std::array{info}));
+DescriptorAllocator DescriptorPool::Allocator(const Device& device, Scheduler& scheduler, VkDescriptorSetLayout layout, const Shader::Info& info) {
+ return Allocator(device, scheduler, layout, MakeBankInfo(std::array{info}));
}
-DescriptorAllocator DescriptorPool::Allocator(VkDescriptorSetLayout layout,
- const DescriptorBankInfo& info) {
- return DescriptorAllocator(device, master_semaphore, Bank(info), layout);
+DescriptorAllocator DescriptorPool::Allocator(const Device& device, Scheduler& scheduler, VkDescriptorSetLayout layout, const DescriptorBankInfo& info) {
+ return DescriptorAllocator(device, scheduler.GetMasterSemaphore(), Bank(device, info), layout);
}
-DescriptorBank& DescriptorPool::Bank(const DescriptorBankInfo& reqs) {
+DescriptorBank& DescriptorPool::Bank(const Device& device, const DescriptorBankInfo& reqs) {
std::shared_lock read_lock{banks_mutex};
const auto it = std::ranges::find_if(bank_infos, [&reqs](const DescriptorBankInfo& bank) {
return std::abs(bank.score - reqs.score) < SCORE_THRESHOLD && bank.IsSuperset(reqs);
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.h b/src/video_core/renderer_vulkan/vk_descriptor_pool.h
index 4aada5a006..4efeb60373 100644
--- a/src/video_core/renderer_vulkan/vk_descriptor_pool.h
+++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.h
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -68,17 +71,12 @@ public:
DescriptorPool& operator=(const DescriptorPool&) = delete;
DescriptorPool(const DescriptorPool&) = delete;
- DescriptorAllocator Allocator(VkDescriptorSetLayout layout,
- std::span<const Shader::Info> infos);
- DescriptorAllocator Allocator(VkDescriptorSetLayout layout, const Shader::Info& info);
- DescriptorAllocator Allocator(VkDescriptorSetLayout layout, const DescriptorBankInfo& info);
+ DescriptorAllocator Allocator(const Device& device, Scheduler& scheduler, VkDescriptorSetLayout layout, std::span<const Shader::Info> infos);
+ DescriptorAllocator Allocator(const Device& device, Scheduler& scheduler, VkDescriptorSetLayout layout, const Shader::Info& info);
+ DescriptorAllocator Allocator(const Device& device, Scheduler& scheduler, VkDescriptorSetLayout layout, const DescriptorBankInfo& info);
private:
- DescriptorBank& Bank(const DescriptorBankInfo& reqs);
-
- const Device& device;
- MasterSemaphore& master_semaphore;
-
+ DescriptorBank& Bank(const Device& device, const DescriptorBankInfo& reqs);
std::shared_mutex banks_mutex;
std::vector<DescriptorBankInfo> bank_infos;
std::vector<std::unique_ptr<DescriptorBank>> banks;
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 728554d6e6..3b5338a058 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -276,7 +276,7 @@ GraphicsPipeline::GraphicsPipeline(
descriptor_set_layout = builder.CreateDescriptorSetLayout(uses_push_descriptor);
if (!uses_push_descriptor) {
- descriptor_allocator = descriptor_pool.Allocator(*descriptor_set_layout, stage_infos);
+ descriptor_allocator = descriptor_pool.Allocator(device, scheduler, *descriptor_set_layout, stage_infos);
}
const VkDescriptorSetLayout set_layout{*descriptor_set_layout};
@@ -288,7 +288,7 @@ GraphicsPipeline::GraphicsPipeline(
Validate();
MakePipeline(render_pass);
if (pipeline_statistics) {
- pipeline_statistics->Collect(*pipeline);
+ pipeline_statistics->Collect(device, *pipeline);
}
std::scoped_lock lock{build_mutex};
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 23bfbceccb..798499141e 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -915,7 +915,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
spv_module.SetObjectNameEXT(name.c_str());
}
Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
- return std::make_unique<ComputePipeline>(device, vulkan_pipeline_cache, descriptor_pool,
+ return std::make_unique<ComputePipeline>(device, scheduler, vulkan_pipeline_cache, descriptor_pool,
guest_descriptor_queue, thread_worker, statistics,
&shader_notify, program.info, std::move(spv_module));
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index f0c704b700..06d405c2f5 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -126,16 +126,14 @@ public:
current_query = nullptr;
amend_value = 0;
accumulation_value = 0;
- queries_prefix_scan_pass = std::make_unique<QueriesPrefixScanPass>(
- device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
+ queries_prefix_scan_pass.emplace(device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = 8,
- .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
- VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
+ .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
@@ -592,8 +590,7 @@ private:
VideoCommon::HostQueryBase* current_query;
bool has_started{};
std::mutex flush_guard;
-
- std::unique_ptr<QueriesPrefixScanPass> queries_prefix_scan_pass;
+ std::optional<QueriesPrefixScanPass> queries_prefix_scan_pass;
};
// Transform feedback queries
@@ -1266,41 +1263,23 @@ private:
} // namespace
struct QueryCacheRuntimeImpl {
- QueryCacheRuntimeImpl(QueryCacheRuntime& runtime, VideoCore::RasterizerInterface* rasterizer_,
- Tegra::MaxwellDeviceMemoryManager& device_memory_,
- Vulkan::BufferCache& buffer_cache_, const Device& device_,
- const MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
- StagingBufferPool& staging_pool_,
- ComputePassDescriptorQueue& compute_pass_descriptor_queue,
- DescriptorPool& descriptor_pool, TextureCache& texture_cache_)
- : rasterizer{rasterizer_}, device_memory{device_memory_}, buffer_cache{buffer_cache_},
- device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_},
- staging_pool{staging_pool_}, guest_streamer(0, runtime),
- sample_streamer(static_cast<size_t>(QueryType::ZPassPixelCount64), runtime, rasterizer,
- texture_cache_, device, scheduler, memory_allocator,
- compute_pass_descriptor_queue, descriptor_pool),
- tfb_streamer(static_cast<size_t>(QueryType::StreamingByteCount), runtime, device,
- scheduler, memory_allocator, staging_pool),
- primitives_succeeded_streamer(
- static_cast<size_t>(QueryType::StreamingPrimitivesSucceeded), runtime, tfb_streamer,
- device_memory_),
- primitives_needed_minus_succeeded_streamer(
- static_cast<size_t>(QueryType::StreamingPrimitivesNeededMinusSucceeded), runtime, 0u),
- hcr_setup{}, hcr_is_set{}, is_hcr_running{}, maxwell3d{} {
+ QueryCacheRuntimeImpl(QueryCacheRuntime& runtime, VideoCore::RasterizerInterface* rasterizer_, Tegra::MaxwellDeviceMemoryManager& device_memory_, Vulkan::BufferCache& buffer_cache_, const Device& device_, const MemoryAllocator& memory_allocator_, Scheduler& scheduler_, StagingBufferPool& staging_pool_, ComputePassDescriptorQueue& compute_pass_descriptor_queue, DescriptorPool& descriptor_pool, TextureCache& texture_cache_)
+ : rasterizer{rasterizer_}, device_memory{device_memory_}, buffer_cache{buffer_cache_}
+ , device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_}
+ , staging_pool{staging_pool_}, guest_streamer(0, runtime)
+ , sample_streamer(size_t(QueryType::ZPassPixelCount64), runtime, rasterizer, texture_cache_, device, scheduler, memory_allocator, compute_pass_descriptor_queue, descriptor_pool)
+ , tfb_streamer(size_t(QueryType::StreamingByteCount), runtime, device, scheduler, memory_allocator, staging_pool)
+ , primitives_succeeded_streamer(size_t(QueryType::StreamingPrimitivesSucceeded), runtime, tfb_streamer, device_memory_)
+ , primitives_needed_minus_succeeded_streamer(size_t(QueryType::StreamingPrimitivesNeededMinusSucceeded), runtime, 0u)
+ , hcr_setup{}, hcr_is_set{}, is_hcr_running{}, maxwell3d{} {
hcr_setup.sType = VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT;
hcr_setup.pNext = nullptr;
hcr_setup.flags = 0;
- const bool has_conditional_rendering = device.IsExtConditionalRendering();
- if (has_conditional_rendering) {
- conditional_resolve_pass = std::make_unique<ConditionalRenderingResolvePass>(
- device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
- }
-
- VkBufferUsageFlags hcr_buffer_usage =
- VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
- if (has_conditional_rendering) {
+ VkBufferUsageFlags hcr_buffer_usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ if (device.IsExtConditionalRendering()) {
+ conditional_resolve_pass.emplace(device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
hcr_buffer_usage |= VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT;
}
@@ -1339,7 +1318,7 @@ struct QueryCacheRuntimeImpl {
std::vector<std::vector<VkBufferCopy>> copies_setup;
// Host conditional rendering data
- std::unique_ptr<ConditionalRenderingResolvePass> conditional_resolve_pass;
+ std::optional<ConditionalRenderingResolvePass> conditional_resolve_pass;
vk::Buffer hcr_resolve_buffer;
VkConditionalRenderingBeginInfoEXT hcr_setup;
VkBuffer hcr_buffer;
@@ -1351,13 +1330,7 @@ struct QueryCacheRuntimeImpl {
Maxwell3D* maxwell3d;
};
-QueryCacheRuntime::QueryCacheRuntime(VideoCore::RasterizerInterface* rasterizer,
- Tegra::MaxwellDeviceMemoryManager& device_memory_,
- Vulkan::BufferCache& buffer_cache_, const Device& device_,
- const MemoryAllocator& memory_allocator_,
- Scheduler& scheduler_, StagingBufferPool& staging_pool_,
- ComputePassDescriptorQueue& compute_pass_descriptor_queue,
- DescriptorPool& descriptor_pool, TextureCache& texture_cache_) {
+QueryCacheRuntime::QueryCacheRuntime(VideoCore::RasterizerInterface* rasterizer, Tegra::MaxwellDeviceMemoryManager& device_memory_, Vulkan::BufferCache& buffer_cache_, const Device& device_, const MemoryAllocator& memory_allocator_, Scheduler& scheduler_, StagingBufferPool& staging_pool_, ComputePassDescriptorQueue& compute_pass_descriptor_queue, DescriptorPool& descriptor_pool, TextureCache& texture_cache_) {
impl = std::make_unique<QueryCacheRuntimeImpl>(
*this, rasterizer, device_memory_, buffer_cache_, device_, memory_allocator_, scheduler_,
staging_pool_, compute_pass_descriptor_queue, descriptor_pool, texture_cache_);
@@ -1686,8 +1659,7 @@ void QueryCacheRuntime::SyncValues(std::span<SyncValuesType> values, VkBuffer ba
}
impl->scheduler.RequestOutsideRenderPassOperationContext();
- impl->scheduler.Record([src_buffer, dst_buffers = std::move(impl->buffers_to_upload_to),
- vk_copies = std::move(impl->copies_setup)](vk::CommandBuffer cmdbuf) {
+ impl->scheduler.Record([src_buffer, dst_buffers = std::move(impl->buffers_to_upload_to), vk_copies = std::move(impl->copies_setup)](vk::CommandBuffer cmdbuf) {
size_t size = dst_buffers.size();
for (size_t i = 0; i < size; i++) {
cmdbuf.CopyBuffer(src_buffer, dst_buffers[i].first, vk_copies[i]);
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
index a7b7c46f39..0b132c97d6 100644
--- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp
+++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
@@ -235,7 +235,7 @@ void SetupRasterModes(Maxwell3D::DirtyState::Tables &tables) {
} // Anonymous namespace
void StateTracker::SetupTables(Tegra::Control::ChannelState& channel_state) {
- auto& tables{channel_state.maxwell_3d->dirty.tables};
+ auto& tables{channel_state.payload->maxwell_3d.dirty.tables};
SetupDirtyFlags(tables);
SetupDirtyViewports(tables);
SetupDirtyScissors(tables);
@@ -258,7 +258,7 @@ void StateTracker::SetupTables(Tegra::Control::ChannelState& channel_state) {
}
void StateTracker::ChangeChannel(Tegra::Control::ChannelState& channel_state) {
- flags = &channel_state.maxwell_3d->dirty.flags;
+ flags = &channel_state.payload->maxwell_3d.dirty.flags;
}
void StateTracker::InvalidateState() {
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h
index 82fce298da..1497108b16 100644
--- a/src/video_core/renderer_vulkan/vk_update_descriptor.h
+++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h
@@ -1,10 +1,13 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
-
+#include <variant>
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan {
@@ -12,20 +15,15 @@ namespace Vulkan {
class Device;
class Scheduler;
-struct DescriptorUpdateEntry {
- struct Empty {};
-
+union DescriptorUpdateEntry {
DescriptorUpdateEntry() = default;
DescriptorUpdateEntry(VkDescriptorImageInfo image_) : image{image_} {}
DescriptorUpdateEntry(VkDescriptorBufferInfo buffer_) : buffer{buffer_} {}
DescriptorUpdateEntry(VkBufferView texel_buffer_) : texel_buffer{texel_buffer_} {}
-
- union {
- Empty empty{};
- VkDescriptorImageInfo image;
- VkDescriptorBufferInfo buffer;
- VkBufferView texel_buffer;
- };
+ std::monostate empty{};
+ VkDescriptorImageInfo image;
+ VkDescriptorBufferInfo buffer;
+ VkBufferView texel_buffer;
};
class UpdateDescriptorQueue final {
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index 1ac7a0bc35..54fb8f6239 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -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();
}
}
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index f8e2444f33..1a56dd99b6 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -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