diff options
| author | lizzie <lizzie@eden-emu.dev> | 2026-06-23 06:31:25 +0200 |
|---|---|---|
| committer | crueter <crueter@eden-emu.dev> | 2026-06-23 06:31:25 +0200 |
| commit | 3aa0d462598beb2021308eee1d757d74fe33b312 (patch) | |
| tree | ed425c3845ba8fa61184d97b0588cb049b518bd7 /src/video_core | |
| parent | f8facda35fe7f17143f84bbfbdacc4cc48678946 (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')
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, ¶meters, 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, ¶meters, 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 |
