diff --git a/docs/README.md b/docs/README.md index 68775f99d8..3019b26204 100644 --- a/docs/README.md +++ b/docs/README.md @@ -25,3 +25,4 @@ Policies and information on development. - **[AI and LLM Usage](./policies/AI.md)** - **[Release Policy](./policies/Release.md)** - **[Coding guidelines](./policies/Coding.md)** +- **[Coding Style guidelines](./policies/CodingStyle.md)** diff --git a/docs/policies/Coding.md b/docs/policies/Coding.md index c50f93b142..8abc39a5a5 100644 --- a/docs/policies/Coding.md +++ b/docs/policies/Coding.md @@ -1,126 +1,70 @@ # Coding guidelines -These are mostly "suggestions", if you feel like your code is readable, comprehensible to others; and most importantly doesn't result in unreadable spaghetti you're fine to go. +These are **not** stylistic guidelines, they're, for the most part, suggestions on how to architecture new systems or improve upon the existing codebase. -But for new developers you may find that following these guidelines will make everything x10 easier. +# Foreword -## Naming conventions +Don't try to micro-optimize out of the get go, while yes, most of the code is pretty, subpar, most of these are aftertoughts and details that can be glossed over **generally**. -Simply put, types/classes are named as `PascalCase`, same for methods and functions like `AddElement`. Variables are named `like_this_snake_case` and constants are `IN_SCREAMING_CASE`. +Architectural issues are more important, for example an API returning a `std::string` is not as efficient as one that operates on `std::string_view` directly (cost of constructing an `std::string` w/o small-string optimization and all of that). -Except for Qt MOC where `functionName` is preferred. +Regardless of the details, try to keep things simple. As a general rule of thumb. -Template typenames prefer short names like `T`, `I`, `U`, if a longer name is required either `Iterator` or `perform_action` are fine as well. Do not use names like `SS` as systems like solaris define it for registers, in general do not use any of the following for short names: +# C++ guidelines -- `SS`, `DS`, `GS`, `FS`: Segment registers, defined by Solaris `` -- `EAX`, `EBX`, `ECX`, `EDX`, `ESI`, `EDI`, `ESP`, `EBP`, `EIP`: Registers, defined by Solaris. -- `X`: Defined by some utility headers, avoid. -- `_`: Defined by gettext, avoid. -- `N`, `M`, `S`: Preferably don't use this for types, use it for numeric constants. -- `TR`: Used by some weird `` whom define the Task Register as a logical register to provide to the user... (Need to remember which OS in specific). +Everyone has their own way of viewing good/bad C++ practices, my general outline: -Macros must always be in `SCREAMING_CASE`. Do not use short letter macros as systems like Solaris will conflict with them; a good rule of thumb is >5 characters per macro - i.e `THIS_MACRO_IS_GOOD`, `AND_ALSO_THIS_ONE`. +- At your disposal you may use `boost::container::static_vector<>` (beware it has a ctor/initialization cost which goes up the more elements you add). + - Or you may use `boost::container::small_vector<>` (which has an initialization cost as well, and will use extra book-keeping for heap, try to keep a balance). +- Don't use `[[likely]]` or `[[unlikely]]`; PGO builds exist for that. +- Don't use inline assembly to try to outsmart the compiler unless you're 100% sure the assembly you're writing is actually good. + - And if so, try to restructure your C++ code so the compiler vectorizes it/makes it better, right? + - Or if that fails, use intrinsics instead of raw `asm volatile`. +- Use `std::optional<>` instead of `std::unique_ptr<>` if possible. + - `std::unique_ptr<>` carries indirection cost due to it being memory allocated on the heap. + - It isn't often that objects that contain `std::unique_ptr<>`, are allocated on the heap themselves, allocating even more things on the heap seems redundant. +- Avoid `std::recursive_mutex` at all costs. + - It's basically implemented as a linked list most of the time and has HEAVY performance penalties. +- Exploit the fact `std::atomic/std::atomic` is basically free on most arches that matter. + - In x86_64, an atomic `uint32_t` is basically `mov [m32], r32`, which is essentially free/cheap. +- Avoid template parameters unless you really need them. + - For small inlineable functions this is fine, for more complex ones, please consider the generated assembly. +- Dont make your own memcpy/memset/strcpy/strncpy/etc. + - Seriously DON'T DO THIS. You will NOT beat the compiler. + - Nor 30 years of writing optimized `mem*`. + - If your code is slow, don't blame `mem*`, blame your code. +- Try to avoid using `virtual` since vtable indirection has a cost +- Avoid `dynamic_cast` and `typeid` at all costs. + - The reason is because the project has `-fno-rtti` disabled by default, due to the costs of dynamic polymorphism. +- Always copy-on-value for objects with `sizeof(void *) >= sizeof(T) * 2`, i.e objects sized as 2 pointers or less, for bigger objects you can use ref/pointer as usual. +- Try using move semantics instead of references, whenever possible. +- Remember function parameters are extremelly cheap as fuck, don't be afraid to place upto 8 parameters on a given function. +- Don't save a reference in structures of a parent object, i.e: + ```c++ + struct Child { + Parent& parent; + void Mehod() { + parent.Something(); + } + }; + ``` + - Instead you can do the following: + ```c++ + struct Child { + void Mehod(Parent& parent) { + parent.Something(); + } + }; + ``` + - This reduces the amount of pointers you have lying around, and also works better because of the aforementioned cheapness of parameter functions. -Try not using hungarian notation, if you're able. +# Engineering guidelines -## Formatting +Coding isn't also writing stuff but architecturing stuff, consider the following: -Formatting is extremelly lax, the general rule of thumb is: Don't add new lines just to increase line count. The less lines we have to look at, the better. This means also packing densely your code while not making it a clusterfuck. Strike a balance of "this is a short and comprehensible piece of code" and "my eyes are actually happy to see this!". Don't just drop the entire thing in a single line and call it "dense code", that's just spaghetti posing as code. In general, be mindful of what other devs need to look at. - -Do not put if/while/etc braces after lines: - -```c++ -// no dont do this -// this is more lines of code for no good reason (why braces need their separate lines?) -// and those take space in someone's screen, cumulatively -if (thing) -{ //<-- - some(); // ... -} //<-- 2 lines of code for basically "opening" and "closing" an statment - -// do this -if (thing) { //<-- [...] and with your brain you can deduce it's this piece of code - // that's being closed - some(); // ... -} //<-- only one line, and it's clearer since you know its closing something [...] - -// or this, albeit the extra line isn't needed (at your discretion of course) -if (thing) - some(); // ... - -// this is also ok, keeps things in one line and makes it extremely clear -if (thing) some(); - -// NOT ok, don't be "clever" and use the comma operator to stash a bunch of statments -// in a single line, doing this will definitely ruin someone's day - just do the thing below -// vvv -if (thing) some(), thing(), a2(a1(), y1(), j1()), do_complex_shit(wa(), wo(), ploo()); -// ... and in general don't use the comma operator for "multiple statments", EXCEPT if you think -// that it makes the code more readable (the situation may be rare however) - -// Wow so much clearer! Now I can actually see what each statment is meant to do! -if (thing) { - some(); - thing(); - a2(a1(), y1(), j1()); - do_complex_shit(wa(), wo(), ploo()); -} -``` - -Brace rules are lax, if you can get the point across, do it: - -```c++ -// this is fine -do { - if (thing) { - return 0; - } -} while (other); - -// this is also ok --- albeit a bit more dense -do if (thing) return 0; while (other); - -// ok as well -do { - if (thing) return 0; -} while (other); -``` - -There is no 80-column limit but preferably be mindful of other developer's readability (like don't just put everything onto one line). - -```c++ -// someone is going to be mad due to this -SDL_AudioSpec obtained; -device_name.empty() ? device = SDL_OpenAudioDevice(nullptr, capture, &spec, &obtained, false) : device = SDL_OpenAudioDevice(device_name.c_str(), capture, &spec, &obtained, false); - -// maybe consider this -SDL_AudioSpec obtained; -if (device_name.empty()) { - device = SDL_OpenAudioDevice(nullptr, capture, &spec, &obtained, false); -} else { - device = SDL_OpenAudioDevice(device_name.c_str(), capture, &spec, &obtained, false); -} - -// or this is fine as well -SDL_AudioSpec obtained; -device = SDL_OpenAudioDevice(device_name.empty() ? nullptr : device_name.c_str(), capture, &spec, &obtained, false); -``` - -A note about operators: Use them sparingly, yes, the language is lax on them, but some usages can be... tripping to say the least. - -```c++ -a, b, c; //<-- NOT OK multiple statments with comma operator is definitely a recipe for disaster -return c ? a : b; //<-- OK ternaries at end of return statments are clear and fine -return a, b; //<-- NOT OK return will take value of `b` but also evaluate `a`, just use a separate statment -void f(int a[]) //<-- OK? if you intend to use the pointer as an array, otherwise just mark it as * -``` - -And about templates, use them sparingly, don't just do meta-templating for the sake of it, do it when you actually need it. This isn't a competition to see who can make the most complicated and robust meta-templating system. Just use what works, and preferably stick to the standard libary instead of reinventing the wheel. Additionally: - -```c++ -// NOT OK This will create (T * N * C * P) versions of the same function. DO. NOT. DO. THIS. -template inline void what() const noexcept; - -// OK use parameters like a normal person, don't be afraid to use them :) -template inline void what(size_t n, size_t c, size_t p) const noexcept; -``` +- Try to reduce dependency on... dependencies + - While some dependencies are useful `boost::container` and `fmt` to name a few, remember each dependency added incurs a cost + - It may also be subpar with a hand rolled implementation, biggest exemplar of this is `spirv-tools` providing subpar SPIRV optimizations in comparison to the in-house optimizer. +- Try to rely less on indirection for architecturing systems + - If the underlying HLE kernel emulation requires it, try making a solution that keeps things local + - For example, there isn't a need for file descriptors to each be pointer, when they could be a fixed table size with elements that may be emplaced at will. diff --git a/docs/policies/CodingStyle.md b/docs/policies/CodingStyle.md new file mode 100644 index 0000000000..659e8f7384 --- /dev/null +++ b/docs/policies/CodingStyle.md @@ -0,0 +1,126 @@ +# Coding Style guidelines + +These are mostly "suggestions", if you feel like your code is readable, comprehensible to others; and most importantly doesn't result in unreadable spaghetti you're fine to go. + +But for new developers you may find that following these guidelines will make everything x10 easier. + +## Naming conventions + +Simply put, types/classes are named as `PascalCase`, same for methods and functions like `AddElement`. Variables are named `like_this_snake_case` and constants are `IN_SCREAMING_CASE`. + +Except for Qt MOC where `functionName` is preferred. + +Template typenames prefer short names like `T`, `I`, `U`, if a longer name is required either `Iterator` or `perform_action` are fine as well. Do not use names like `SS` as systems like solaris define it for registers, in general do not use any of the following for short names: + +- `SS`, `DS`, `GS`, `FS`: Segment registers, defined by Solaris `` +- `EAX`, `EBX`, `ECX`, `EDX`, `ESI`, `EDI`, `ESP`, `EBP`, `EIP`: Registers, defined by Solaris. +- `X`: Defined by some utility headers, avoid. +- `_`: Defined by gettext, avoid. +- `N`, `M`, `S`: Preferably don't use this for types, use it for numeric constants. +- `TR`: Used by some weird `` whom define the Task Register as a logical register to provide to the user... (Need to remember which OS in specific). + +Macros must always be in `SCREAMING_CASE`. Do not use short letter macros as systems like Solaris will conflict with them; a good rule of thumb is >5 characters per macro - i.e `THIS_MACRO_IS_GOOD`, `AND_ALSO_THIS_ONE`. + +Try not using hungarian notation, if you're able. + +## Formatting + +Formatting is extremelly lax, the general rule of thumb is: Don't add new lines just to increase line count. The less lines we have to look at, the better. This means also packing densely your code while not making it a clusterfuck. Strike a balance of "this is a short and comprehensible piece of code" and "my eyes are actually happy to see this!". Don't just drop the entire thing in a single line and call it "dense code", that's just spaghetti posing as code. In general, be mindful of what other devs need to look at. + +Do not put if/while/etc braces after lines: + +```c++ +// no dont do this +// this is more lines of code for no good reason (why braces need their separate lines?) +// and those take space in someone's screen, cumulatively +if (thing) +{ //<-- + some(); // ... +} //<-- 2 lines of code for basically "opening" and "closing" an statment + +// do this +if (thing) { //<-- [...] and with your brain you can deduce it's this piece of code + // that's being closed + some(); // ... +} //<-- only one line, and it's clearer since you know its closing something [...] + +// or this, albeit the extra line isn't needed (at your discretion of course) +if (thing) + some(); // ... + +// this is also ok, keeps things in one line and makes it extremely clear +if (thing) some(); + +// NOT ok, don't be "clever" and use the comma operator to stash a bunch of statments +// in a single line, doing this will definitely ruin someone's day - just do the thing below +// vvv +if (thing) some(), thing(), a2(a1(), y1(), j1()), do_complex_shit(wa(), wo(), ploo()); +// ... and in general don't use the comma operator for "multiple statments", EXCEPT if you think +// that it makes the code more readable (the situation may be rare however) + +// Wow so much clearer! Now I can actually see what each statment is meant to do! +if (thing) { + some(); + thing(); + a2(a1(), y1(), j1()); + do_complex_shit(wa(), wo(), ploo()); +} +``` + +Brace rules are lax, if you can get the point across, do it: + +```c++ +// this is fine +do { + if (thing) { + return 0; + } +} while (other); + +// this is also ok --- albeit a bit more dense +do if (thing) return 0; while (other); + +// ok as well +do { + if (thing) return 0; +} while (other); +``` + +There is no 80-column limit but preferably be mindful of other developer's readability (like don't just put everything onto one line). + +```c++ +// someone is going to be mad due to this +SDL_AudioSpec obtained; +device_name.empty() ? device = SDL_OpenAudioDevice(nullptr, capture, &spec, &obtained, false) : device = SDL_OpenAudioDevice(device_name.c_str(), capture, &spec, &obtained, false); + +// maybe consider this +SDL_AudioSpec obtained; +if (device_name.empty()) { + device = SDL_OpenAudioDevice(nullptr, capture, &spec, &obtained, false); +} else { + device = SDL_OpenAudioDevice(device_name.c_str(), capture, &spec, &obtained, false); +} + +// or this is fine as well +SDL_AudioSpec obtained; +device = SDL_OpenAudioDevice(device_name.empty() ? nullptr : device_name.c_str(), capture, &spec, &obtained, false); +``` + +A note about operators: Use them sparingly, yes, the language is lax on them, but some usages can be... tripping to say the least. + +```c++ +a, b, c; //<-- NOT OK multiple statments with comma operator is definitely a recipe for disaster +return c ? a : b; //<-- OK ternaries at end of return statments are clear and fine +return a, b; //<-- NOT OK return will take value of `b` but also evaluate `a`, just use a separate statment +void f(int a[]) //<-- OK? if you intend to use the pointer as an array, otherwise just mark it as * +``` + +And about templates, use them sparingly, don't just do meta-templating for the sake of it, do it when you actually need it. This isn't a competition to see who can make the most complicated and robust meta-templating system. Just use what works, and preferably stick to the standard libary instead of reinventing the wheel. Additionally: + +```c++ +// NOT OK This will create (T * N * C * P) versions of the same function. DO. NOT. DO. THIS. +template inline void what() const noexcept; + +// OK use parameters like a normal person, don't be afraid to use them :) +template inline void what(size_t n, size_t c, size_t p) const noexcept; +``` diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 3321a2d49d..a4ae0eec0a 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -27,7 +27,9 @@ void CpuManager::Initialize() { num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1; gpu_barrier.emplace(num_cores + 1); for (std::size_t core = 0; core < num_cores; core++) - core_data[core].host_thread = std::jthread(&CpuManager::RunThread, core); + core_data[core].host_thread = std::jthread([this, core](std::stop_token token) { + RunThread(token, core); + }); } void CpuManager::Shutdown() { diff --git a/src/video_core/control/channel_state.cpp b/src/video_core/control/channel_state.cpp index 7bd8954e50..c6f2c3c2ca 100644 --- a/src/video_core/control/channel_state.cpp +++ b/src/video_core/control/channel_state.cpp @@ -18,12 +18,12 @@ namespace Tegra::Control { ChannelState::Payload::Payload(Core::System& system, MemoryManager& memory_manager, ChannelState& channel_state) - : maxwell_3d(system, memory_manager) + : maxwell_3d(memory_manager) , fermi_2d(memory_manager) - , kepler_compute(system, memory_manager) - , maxwell_dma(system, memory_manager) - , kepler_memory(system, memory_manager) - , nv01_timer(system, memory_manager) + , kepler_compute(memory_manager) + , maxwell_dma(memory_manager) + , kepler_memory(memory_manager) + , nv01_timer(memory_manager) , dma_pusher(system, memory_manager, channel_state) {} 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; diff --git a/src/video_core/control/channel_state_cache.inc b/src/video_core/control/channel_state_cache.inc index d882d8222f..9cce06ab3b 100644 --- a/src/video_core/control/channel_state_cache.inc +++ b/src/video_core/control/channel_state_cache.inc @@ -41,7 +41,7 @@ void ChannelSetupCaches

::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 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 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 new_channel); private: ankerl::unordered_dense::map> 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 109d46dfe7..41bb43f0c1 100644 --- a/src/video_core/dma_pusher.cpp +++ b/src/video_core/dma_pusher.cpp @@ -179,9 +179,9 @@ void DmaPusher::CallMethod(u32 argument) { if (!subchannel->execution_mask[dma_state.method]) { subchannel->method_sink.emplace_back(dma_state.method, argument); } else { - subchannel->ConsumeSink(); + subchannel->ConsumeSink(system); subchannel->current_dma_segment = dma_state.dma_get + dma_state.dma_word_offset; - subchannel->CallMethod(dma_state.method, argument, dma_state.is_last_call); + subchannel->CallMethod(system, dma_state.method, argument, dma_state.is_last_call); } } } @@ -191,9 +191,9 @@ void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) { 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); } } 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::max)()> execution_mask{}; std::vector> 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 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 9aaa99f7ff..54eedcb08b 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(); @@ -298,7 +296,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) { @@ -391,7 +389,7 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume } } -void Maxwell3D::CallMacroMethod(u32 method, const std::vector& parameters) { +void Maxwell3D::CallMacroMethod(Core::System& system, u32 method, const std::vector& parameters) { // Reset the current macro. executing_macro = 0; @@ -400,11 +398,11 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector& parameters) ((method - MacroRegistersStart) >> 1) % static_cast(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) { @@ -414,7 +412,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; } @@ -424,12 +422,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) { @@ -458,7 +455,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; } @@ -480,7 +477,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(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 3ac79e0eb8..0ceeff78fc 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& parameters); + void CallMacroMethod(Core::System& system, u32 method, const std::vector& 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(regs.offset_in), - static_cast(regs.offset_out)); + LOG_TRACE(Render_OpenGL, "DMA copy 0x{:x} -> 0x{:x}", static_cast(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 b153619c16..5816b5901a 100644 --- a/src/video_core/engines/puller.cpp +++ b/src/video_core/engines/puller.cpp @@ -29,22 +29,22 @@ void Puller::ProcessBindMethod(DmaPusher& dma_pusher, const MethodCall& method_c bound_engines[method_call.subchannel] = engine_id; switch (engine_id) { case EngineID::FERMI_TWOD_A: - dma_pusher.BindSubchannel(&*dma_pusher.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(&*dma_pusher.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(&*dma_pusher.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(&*dma_pusher.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(&*dma_pusher.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(&*dma_pusher.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); @@ -198,22 +198,22 @@ void Puller::CallEngineMethod(DmaPusher& dma_pusher, const MethodCall& method_ca const EngineID engine = bound_engines[method_call.subchannel]; switch (engine) { case EngineID::FERMI_TWOD_A: - dma_pusher.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: - dma_pusher.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: - dma_pusher.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: - dma_pusher.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: - dma_pusher.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: - dma_pusher.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"); @@ -226,22 +226,22 @@ void Puller::CallEngineMultiMethod(DmaPusher& dma_pusher, u32 method, u32 subcha const EngineID engine = bound_engines[subchannel]; switch (engine) { case EngineID::FERMI_TWOD_A: - dma_pusher.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: - dma_pusher.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: - dma_pusher.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: - dma_pusher.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: - dma_pusher.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: - dma_pusher.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"); diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 38214b97e4..c8110e5dbe 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -46,7 +46,6 @@ struct GPU::Impl { , shader_notify() , is_async{is_async_} , gpu_thread{system_, is_async_} - , scheduler(system_.GPU()) {} ~Impl() = default; @@ -387,27 +386,27 @@ const Host1x::Host1x& GPU::Host1x() const { } Engines::Maxwell3D& GPU::Maxwell3D() { - return *impl->current_channel->maxwell_3d; + return impl->current_channel->payload->maxwell_3d; } const Engines::Maxwell3D& GPU::Maxwell3D() const { - return *impl->current_channel->maxwell_3d; + return impl->current_channel->payload->maxwell_3d; } Engines::KeplerCompute& GPU::KeplerCompute() { - return *impl->current_channel->kepler_compute; + return impl->current_channel->payload->kepler_compute; } const Engines::KeplerCompute& GPU::KeplerCompute() const { - return *impl->current_channel->kepler_compute; + return impl->current_channel->payload->kepler_compute; } Tegra::DmaPusher& GPU::DmaPusher() { - return *impl->current_channel->dma_pusher; + return impl->current_channel->payload->dma_pusher; } const Tegra::DmaPusher& GPU::DmaPusher() const { - return *impl->current_channel->dma_pusher; + return impl->current_channel->payload->dma_pusher; } VideoCore::RendererBase& GPU::Renderer() { diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 33f44e6fe7..bb31dac7be 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp @@ -40,7 +40,7 @@ void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Core::Fronten break; } if (auto* submit_list = std::get_if(&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(next.data)) { system.GPU().TickWork(); } else if (const auto* flush = std::get_if(&next.data)) { diff --git a/src/video_core/macro.cpp b/src/video_core/macro.cpp index 606162ba8d..b93b8320e3 100644 --- a/src/video_core/macro.cpp +++ b/src/video_core/macro.cpp @@ -76,10 +76,10 @@ bool IsTopologySafe(Maxwell3D::Regs::PrimitiveTopology topology) { } // Anonymous namespace -void HLE_DrawArraysIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { +void HLE_DrawArraysIndirect::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { auto topology = static_cast(parameters[0]); if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) { - Fallback(maxwell3d, parameters); + Fallback(system, maxwell3d, parameters); return; } @@ -105,7 +105,7 @@ void HLE_DrawArraysIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters) { +void HLE_DrawArraysIndirect::Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters) { SCOPE_EXIT { if (extended) { maxwell3d.engine_state = Maxwell3D::EngineHint::None; @@ -135,10 +135,10 @@ void HLE_DrawArraysIndirect::Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { +void HLE_DrawIndexedIndirect::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { auto topology = static_cast(parameters[0]); if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) { - Fallback(maxwell3d, parameters); + Fallback(system, maxwell3d, parameters); return; } @@ -173,7 +173,7 @@ void HLE_DrawIndexedIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters) { +void HLE_DrawIndexedIndirect::Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters) { maxwell3d.RefreshParameters(); const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); const u32 element_base = parameters[4]; @@ -196,7 +196,7 @@ void HLE_DrawIndexedIndirect::Fallback(Engines::Maxwell3D& maxwell3d, std::span< maxwell3d.replace_table.clear(); } } -void HLE_MultiLayerClear::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { +void HLE_MultiLayerClear::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { maxwell3d.RefreshParameters(); ASSERT(parameters.size() == 1); @@ -208,47 +208,44 @@ void HLE_MultiLayerClear::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { +void HLE_MultiDrawIndexedIndirectCount::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { const auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[2]); - if (!IsTopologySafe(topology)) { - Fallback(maxwell3d, parameters); - 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 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 = static_cast(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 parameters) { +void HLE_MultiDrawIndexedIndirectCount::Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters) { SCOPE_EXIT { // Clean everything. maxwell3d.regs.vertex_id_base = 0x0; @@ -262,7 +259,7 @@ void HLE_MultiDrawIndexedIndirectCount::Fallback(Engines::Maxwell3D& maxwell3d, // Nothing to do. return; } - const auto topology = static_cast(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; @@ -277,41 +274,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(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 parameters, [[maybe_unused]] u32 method) { +void HLE_DrawIndirectByteCount::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span 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 parameters) { +void HLE_DrawIndirectByteCount::Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span 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 parameters, [[maybe_unused]] u32 method) { +void HLE_C713C83D8F63CCF3::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { maxwell3d.RefreshParameters(); const u32 offset = (parameters[0] & 0x3FFFFFFF) << 2; const u32 address = maxwell3d.regs.shadow_scratch[24]; @@ -321,7 +318,7 @@ void HLE_C713C83D8F63CCF3::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { +void HLE_D7333D26E0A93EDE::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { maxwell3d.RefreshParameters(); const size_t index = parameters[0]; const u32 address = maxwell3d.regs.shadow_scratch[42 + index]; @@ -331,7 +328,7 @@ void HLE_D7333D26E0A93EDE::Execute(Engines::Maxwell3D& maxwell3d, std::span> 24) & 0xFF; const_buffer.address_low = address << 8; } -void HLE_BindShader::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { +void HLE_BindShader::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { maxwell3d.RefreshParameters(); auto& regs = maxwell3d.regs; const u32 index = parameters[0]; @@ -355,7 +352,7 @@ void HLE_BindShader::Execute(Engines::Maxwell3D& maxwell3d, std::span bind_group.raw_config = 0x11; maxwell3d.ProcessCBBind(bind_group_id); } -void HLE_SetRasterBoundingBox::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { +void HLE_SetRasterBoundingBox::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { maxwell3d.RefreshParameters(); const u32 raster_mode = parameters[0]; auto& regs = maxwell3d.regs; @@ -364,7 +361,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 parameters, [[maybe_unused]] u32 method) { +void HLE_ClearConstBuffer::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { static constexpr std::array zeroes{}; //must be bigger than either 7000 or 5F00 maxwell3d.RefreshParameters(); auto& regs = maxwell3d.regs; @@ -374,7 +371,7 @@ void HLE_ClearConstBuffer::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { +void HLE_ClearMemory::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { maxwell3d.RefreshParameters(); const u32 needed_memory = parameters[2] / sizeof(u32); if (needed_memory > zero_memory.size()) { @@ -385,10 +382,10 @@ void HLE_ClearMemory::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { +void HLE_TransformFeedbackSetup::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { maxwell3d.RefreshParameters(); auto& regs = maxwell3d.regs; regs.transform_feedback_enabled = 1; @@ -400,8 +397,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()); } @@ -441,7 +438,7 @@ void HLE_TransformFeedbackSetup::Execute(Engines::Maxwell3D& maxwell3d, std::spa } } -void MacroInterpreterImpl::Execute(Engines::Maxwell3D& maxwell3d, std::span params, u32 method) { +void MacroInterpreterImpl::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span params, u32 method) { Reset(); registers[1] = params[0]; @@ -451,7 +448,7 @@ void MacroInterpreterImpl::Execute(Engines::Maxwell3D& maxwell3d, std::span> 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: { @@ -513,7 +510,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: { @@ -522,12 +519,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: { @@ -543,7 +540,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; } @@ -556,7 +553,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; @@ -603,7 +600,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. @@ -621,12 +618,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. @@ -637,13 +634,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); @@ -684,8 +681,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()); } @@ -736,34 +733,35 @@ static const auto default_cg_mode = nullptr; //Allow RWE #endif struct MacroJITx64Impl final : public Xbyak::CodeGenerator, public DynamicCachedMacro { - explicit MacroJITx64Impl(std::span code_) + explicit MacroJITx64Impl(Core::System& system, std::span code_) : Xbyak::CodeGenerator(MAX_CODE_SIZE, default_cg_mode) , code{code_} { - Compile(); + Compile(system); } - void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, u32 method) override; + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span 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 registers{}; u32 carry_flag{}; }; @@ -789,15 +787,16 @@ struct MacroJITx64Impl final : public Xbyak::CodeGenerator, public DynamicCached std::span code; }; -void MacroJITx64Impl::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, u32 method) { +void MacroJITx64Impl::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span 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; @@ -914,10 +913,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. @@ -952,10 +951,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); @@ -966,10 +965,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); @@ -977,10 +976,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); @@ -988,10 +987,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); @@ -1017,23 +1016,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); @@ -1057,9 +1054,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(pc) + static_cast(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); @@ -1128,7 +1124,7 @@ void MacroJITx64Impl::Optimizer_ScanFlags() { } } -void MacroJITx64Impl::Compile() { +void MacroJITx64Impl::Compile(Core::System& system) { labels.fill(Xbyak::Label()); Common::X64::ABI_PushRegistersAndAdjustStack(*this, Common::X64::ABI_ALL_CALLEE_SAVED, 8); @@ -1168,7 +1164,7 @@ void MacroJITx64Impl::Compile() { next_opcode = {}; } pc = i; - Compile_NextInstruction(); + Compile_NextInstruction(system); } L(end_of_code); @@ -1179,7 +1175,7 @@ void MacroJITx64Impl::Compile() { program = getCode(); } -bool MacroJITx64Impl::Compile_NextInstruction() { +bool MacroJITx64Impl::Compile_NextInstruction(Core::System& system) { const auto opcode = GetOpCode(); if (labels[pc].getAddress()) { return false; @@ -1189,22 +1185,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); @@ -1276,7 +1272,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. @@ -1301,12 +1297,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. @@ -1317,7 +1313,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. @@ -1325,7 +1321,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); @@ -1366,36 +1362,36 @@ static void Dump(u64 hash, std::span code, bool decompiled = false) { macro_file.write(reinterpret_cast(code.data()), code.size_bytes()); } -void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method, std::span parameters) { - auto const execute_variant = [&maxwell3d, ¶meters, method](AnyCachedMacro& acm) { +void MacroEngine::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, u32 method, std::span parameters) { + auto const execute_variant = [&system, &maxwell3d, ¶meters, method](AnyCachedMacro& acm) { if (auto a = std::get_if(&acm)) - a->Execute(maxwell3d, parameters, method); + a->Execute(system, maxwell3d, parameters, method); if (auto a = std::get_if(&acm)) - a->Execute(maxwell3d, parameters, method); + a->Execute(system, maxwell3d, parameters, method); if (auto a = std::get_if(&acm)) - a->Execute(maxwell3d, parameters, method); + a->Execute(system, maxwell3d, parameters, method); if (auto a = std::get_if(&acm)) - a->Execute(maxwell3d, parameters, method); + a->Execute(system, maxwell3d, parameters, method); if (auto a = std::get_if(&acm)) - a->Execute(maxwell3d, parameters, method); + a->Execute(system, maxwell3d, parameters, method); if (auto a = std::get_if(&acm)) - a->Execute(maxwell3d, parameters, method); + a->Execute(system, maxwell3d, parameters, method); if (auto a = std::get_if(&acm)) - a->Execute(maxwell3d, parameters, method); + a->Execute(system, maxwell3d, parameters, method); if (auto a = std::get_if(&acm)) - a->Execute(maxwell3d, parameters, method); + a->Execute(system, maxwell3d, parameters, method); if (auto a = std::get_if(&acm)) - a->Execute(maxwell3d, parameters, method); + a->Execute(system, maxwell3d, parameters, method); if (auto a = std::get_if(&acm)) - a->Execute(maxwell3d, parameters, method); + a->Execute(system, maxwell3d, parameters, method); if (auto a = std::get_if(&acm)) - a->Execute(maxwell3d, parameters, method); + a->Execute(system, maxwell3d, parameters, method); if (auto a = std::get_if(&acm)) - a->Execute(maxwell3d, parameters, method); + a->Execute(system, maxwell3d, parameters, method); if (auto a = std::get_if(&acm)) - a->Execute(maxwell3d, parameters, method); + a->Execute(system, maxwell3d, parameters, method); if (auto a = std::get_if>(&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; @@ -1426,9 +1422,9 @@ void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method, std::spansecond); + ci.program = Compile(system, maxwell3d, macro_code->second); ci.hash = Common::HashValue(macro_code->second); } if (CanBeHLEProgram(ci.hash) && !Settings::values.disable_macro_hle) { @@ -1443,10 +1439,10 @@ void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method, std::span code) { +AnyCachedMacro MacroEngine::Compile(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span code) { #ifdef ARCHITECTURE_x86_64 if (!is_interpreted) - return std::make_unique(code); + return std::make_unique(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 parameters, [[maybe_unused]] u32 method); - void Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters); + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span 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 parameters, [[maybe_unused]] u32 method); - void Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters); + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters); bool extended; }; struct HLE_MultiLayerClear final { - void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); }; struct HLE_MultiDrawIndexedIndirectCount final { - void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); - void Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters); + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters); }; struct HLE_DrawIndirectByteCount final { - void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); - void Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters); + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Fallback(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters); }; struct HLE_C713C83D8F63CCF3 final { - void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); }; struct HLE_D7333D26E0A93EDE final { - void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); }; struct HLE_BindShader final { - void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); }; struct HLE_SetRasterBoundingBox final { - void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span 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 parameters, [[maybe_unused]] u32 method); + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); size_t base_size; }; struct HLE_ClearMemory final { - void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); std::vector zero_memory; }; struct HLE_TransformFeedbackSetup final { - void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); }; struct MacroInterpreterImpl final { MacroInterpreterImpl() {} MacroInterpreterImpl(std::span code_) : code{code_} {} - void Execute(Engines::Maxwell3D& maxwell3d, std::span params, u32 method); + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span 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 parameters, u32 method) = 0; + virtual void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span 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 parameters); - AnyCachedMacro Compile(Engines::Maxwell3D& maxwell3d, std::span code); + void Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, u32 method, std::span parameters); + AnyCachedMacro Compile(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span 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/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp index 3f4dd89c7e..beb742d8c5 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp +++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp @@ -238,7 +238,7 @@ void SetupRasterModes(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); @@ -261,7 +261,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() {