[video_core] Remove redundant references in GPU engine structs

Signed-off-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2026-04-30 16:30:19 +00:00
parent 82463a1550
commit 83581f8df2
7 changed files with 164 additions and 283 deletions

View file

@ -19,10 +19,10 @@ namespace Tegra::Control {
ChannelState::ChannelState(s32 bind_id_) : bind_id{bind_id_}, initialized{} {} ChannelState::ChannelState(s32 bind_id_) : bind_id{bind_id_}, initialized{} {}
void ChannelState::Init(Core::System& system, GPU& gpu, u64 program_id_) { void ChannelState::Init(Core::System& system, u64 program_id_) {
ASSERT(memory_manager); ASSERT(memory_manager);
program_id = program_id_; program_id = program_id_;
dma_pusher.emplace(system, gpu, *memory_manager, *this); dma_pusher.emplace(system, *memory_manager, *this);
maxwell_3d.emplace(system, *memory_manager); maxwell_3d.emplace(system, *memory_manager);
fermi_2d.emplace(*memory_manager); fermi_2d.emplace(*memory_manager);
kepler_compute.emplace(system, *memory_manager); kepler_compute.emplace(system, *memory_manager);

View file

@ -34,7 +34,7 @@ namespace Control {
struct ChannelState { struct ChannelState {
explicit ChannelState(s32 bind_id); explicit ChannelState(s32 bind_id);
void Init(Core::System& system, GPU& gpu, u64 program_id); void Init(Core::System& system, u64 program_id);
void BindRasterizer(VideoCore::RasterizerInterface* rasterizer); void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);

View file

@ -12,37 +12,32 @@
#include "video_core/guest_memory.h" #include "video_core/guest_memory.h"
#include "video_core/memory_manager.h" #include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h" #include "video_core/rasterizer_interface.h"
#include "video_core/texture_cache/util.h"
#ifdef _MSC_VER
#include <intrin.h>
#endif
namespace Tegra { namespace Tegra {
constexpr u32 MacroRegistersStart = 0xE00; constexpr u32 MacroRegistersStart = 0xE00;
[[maybe_unused]] constexpr u32 ComputeInline = 0x6D; [[maybe_unused]] constexpr u32 ComputeInline = 0x6D;
DmaPusher::DmaPusher(Core::System& system_, GPU& gpu_, MemoryManager& memory_manager_, DmaPusher::DmaPusher(Core::System& system_, MemoryManager& memory_manager_, Control::ChannelState& channel_state_)
Control::ChannelState& channel_state_) : system{system_}
: gpu{gpu_}, system{system_}, memory_manager{memory_manager_}, puller{gpu_, memory_manager_, , memory_manager{memory_manager_}
*this, channel_state_}, signal_sync{false}, synced{true} {} , channel_state{channel_state_}
, signal_sync{false}
, synced{false}
{}
DmaPusher::~DmaPusher() = default; DmaPusher::~DmaPusher() = default;
void DmaPusher::DispatchCalls() { void DmaPusher::DispatchCalls() {
dma_pushbuffer_subindex = 0; dma_pushbuffer_subindex = 0;
dma_state.is_last_call = true; dma_state.is_last_call = true;
while (system.IsPoweredOn()) { while (system.IsPoweredOn()) {
if (!Step()) { if (!Step()) {
break; break;
} }
} }
gpu.FlushCommands(); system.GPU().FlushCommands();
gpu.OnCommandListEnd(); system.GPU().OnCommandListEnd();
} }
bool DmaPusher::Step() { bool DmaPusher::Step() {
@ -171,9 +166,9 @@ void DmaPusher::SetState(const CommandHeader& command_header) {
dma_state.method_count = command_header.method_count; dma_state.method_count = command_header.method_count;
} }
void DmaPusher::CallMethod(u32 argument) const { void DmaPusher::CallMethod(u32 argument) {
if (dma_state.method < non_puller_methods) { if (dma_state.method < non_puller_methods) {
puller.CallPullerMethod(Engines::Puller::MethodCall{ puller.CallPullerMethod(*this, Engines::Puller::MethodCall{
dma_state.method, dma_state.method,
argument, argument,
dma_state.subchannel, dma_state.subchannel,
@ -191,9 +186,9 @@ void DmaPusher::CallMethod(u32 argument) const {
} }
} }
void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) const { void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) {
if (dma_state.method < non_puller_methods) { if (dma_state.method < non_puller_methods) {
puller.CallMultiMethod(dma_state.method, dma_state.subchannel, base_start, num_methods, dma_state.method_count); puller.CallMultiMethod(*this, dma_state.method, dma_state.subchannel, base_start, num_methods, dma_state.method_count);
} else { } else {
auto subchannel = subchannels[dma_state.subchannel]; auto subchannel = subchannels[dma_state.subchannel];
subchannel->ConsumeSink(); subchannel->ConsumeSink();
@ -204,7 +199,6 @@ void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) const {
void DmaPusher::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) { void DmaPusher::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
rasterizer = rasterizer_; rasterizer = rasterizer_;
puller.BindRasterizer(rasterizer);
} }
} // namespace Tegra } // namespace Tegra

View file

@ -109,25 +109,21 @@ inline CommandHeader BuildCommandHeader(BufferMethods method, u32 arg_count, Sub
struct CommandList final { struct CommandList final {
CommandList() = default; CommandList() = default;
explicit CommandList(std::size_t size) : command_lists(size) {} explicit CommandList(std::size_t size) : command_lists(size) {}
explicit CommandList( explicit CommandList(boost::container::small_vector<CommandHeader, 512>&& prefetch_command_list_)
boost::container::small_vector<CommandHeader, 512>&& prefetch_command_list_)
: prefetch_command_list{std::move(prefetch_command_list_)} {} : prefetch_command_list{std::move(prefetch_command_list_)} {}
boost::container::small_vector<CommandListHeader, 512> command_lists; boost::container::small_vector<CommandListHeader, 512> command_lists;
boost::container::small_vector<CommandHeader, 512> prefetch_command_list; boost::container::small_vector<CommandHeader, 512> prefetch_command_list;
}; };
/** /// @brief The DmaPusher class implements DMA submission to FIFOs, providing an area of memory that the
* The DmaPusher class implements DMA submission to FIFOs, providing an area of memory that the /// emulated app fills with commands and tells PFIFO to process. The pushbuffers are then assembled
* emulated app fills with commands and tells PFIFO to process. The pushbuffers are then assembled /// into a "command stream" consisting of 32-bit words that make up "commands".
* into a "command stream" consisting of 32-bit words that make up "commands". /// See https://envytools.readthedocs.io/en/latest/hw/fifo/dma-pusher.html#fifo-dma-pusher for
* See https://envytools.readthedocs.io/en/latest/hw/fifo/dma-pusher.html#fifo-dma-pusher for /// details on this implementation.
* details on this implementation.
*/
class DmaPusher final { class DmaPusher final {
public: public:
explicit DmaPusher(Core::System& system_, GPU& gpu_, MemoryManager& memory_manager_, explicit DmaPusher(Core::System& system_, MemoryManager& memory_manager_, Control::ChannelState& channel_state_);
Control::ChannelState& channel_state_);
~DmaPusher(); ~DmaPusher();
void Push(CommandList&& entries) { void Push(CommandList&& entries) {
@ -136,8 +132,7 @@ public:
void DispatchCalls(); void DispatchCalls();
void BindSubchannel(Engines::EngineInterface* engine, u32 subchannel_id, void BindSubchannel(Engines::EngineInterface* engine, u32 subchannel_id, Engines::EngineTypes engine_type) {
Engines::EngineTypes engine_type) {
subchannels[subchannel_id] = engine; subchannels[subchannel_id] = engine;
subchannel_type[subchannel_id] = engine_type; subchannel_type[subchannel_id] = engine_type;
} }
@ -152,11 +147,11 @@ private:
void SetState(const CommandHeader& command_header); void SetState(const CommandHeader& command_header);
void CallMethod(u32 argument) const; void CallMethod(u32 argument);
void CallMultiMethod(const u32* base_start, u32 num_methods) const; void CallMultiMethod(const u32* base_start, u32 num_methods);
Common::ScratchBuffer<CommandHeader> public:
command_headers; ///< Buffer for list of commands fetched at once Common::ScratchBuffer<CommandHeader> command_headers; ///< Buffer for list of commands fetched at once
std::queue<CommandList> dma_pushbuffer; ///< Queue of command lists to be processed std::queue<CommandList> dma_pushbuffer; ///< Queue of command lists to be processed
std::size_t dma_pushbuffer_subindex{}; ///< Index within a command list within the pushbuffer std::size_t dma_pushbuffer_subindex{}; ///< Index within a command list within the pushbuffer
@ -172,24 +167,24 @@ private:
bool is_last_call; bool is_last_call;
}; };
Core::System& system;
MemoryManager& memory_manager;
Control::ChannelState& channel_state;
DmaState dma_state{}; DmaState dma_state{};
bool dma_increment_once{};
const bool ib_enable{true}; ///< IB mode enabled
std::array<Engines::EngineInterface*, max_subchannels> subchannels{}; std::array<Engines::EngineInterface*, max_subchannels> subchannels{};
std::array<Engines::EngineTypes, max_subchannels> subchannel_type; std::array<Engines::EngineTypes, max_subchannels> subchannel_type;
GPU& gpu; Engines::Puller puller;
Core::System& system;
MemoryManager& memory_manager;
mutable Engines::Puller puller;
VideoCore::RasterizerInterface* rasterizer;
bool signal_sync;
bool synced;
std::mutex sync_mutex; std::mutex sync_mutex;
std::condition_variable sync_cv; std::condition_variable sync_cv;
VideoCore::RasterizerInterface* rasterizer = nullptr;
const bool ib_enable : 1 = true; ///< IB mode enabled
bool dma_increment_once : 1 = false;
bool signal_sync : 1 = false;
bool synced : 1 = false;
}; };
} // namespace Tegra } // namespace Tegra

View file

@ -22,37 +22,29 @@
namespace Tegra::Engines { namespace Tegra::Engines {
Puller::Puller(GPU& gpu_, MemoryManager& memory_manager_, DmaPusher& dma_pusher_, void Puller::ProcessBindMethod(DmaPusher& dma_pusher, const MethodCall& method_call) {
Control::ChannelState& channel_state_)
: gpu{gpu_}, memory_manager{memory_manager_}, dma_pusher{dma_pusher_}, channel_state{
channel_state_} {}
Puller::~Puller() = default;
void Puller::ProcessBindMethod(const MethodCall& method_call) {
// Bind the current subchannel to the desired engine id. // Bind the current subchannel to the desired engine id.
LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", method_call.subchannel, LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", method_call.subchannel, method_call.argument);
method_call.argument);
const auto engine_id = static_cast<EngineID>(method_call.argument); const auto engine_id = static_cast<EngineID>(method_call.argument);
bound_engines[method_call.subchannel] = engine_id; bound_engines[method_call.subchannel] = engine_id;
switch (engine_id) { switch (engine_id) {
case EngineID::FERMI_TWOD_A: case EngineID::FERMI_TWOD_A:
dma_pusher.BindSubchannel(&*channel_state.fermi_2d, method_call.subchannel, EngineTypes::Fermi2D); dma_pusher.BindSubchannel(&*dma_pusher.channel_state.fermi_2d, method_call.subchannel, EngineTypes::Fermi2D);
break; break;
case EngineID::MAXWELL_B: case EngineID::MAXWELL_B:
dma_pusher.BindSubchannel(&*channel_state.maxwell_3d, method_call.subchannel, EngineTypes::Maxwell3D); dma_pusher.BindSubchannel(&*dma_pusher.channel_state.maxwell_3d, method_call.subchannel, EngineTypes::Maxwell3D);
break; break;
case EngineID::KEPLER_COMPUTE_B: case EngineID::KEPLER_COMPUTE_B:
dma_pusher.BindSubchannel(&*channel_state.kepler_compute, method_call.subchannel, EngineTypes::KeplerCompute); dma_pusher.BindSubchannel(&*dma_pusher.channel_state.kepler_compute, method_call.subchannel, EngineTypes::KeplerCompute);
break; break;
case EngineID::MAXWELL_DMA_COPY_A: case EngineID::MAXWELL_DMA_COPY_A:
dma_pusher.BindSubchannel(&*channel_state.maxwell_dma, method_call.subchannel, EngineTypes::MaxwellDMA); dma_pusher.BindSubchannel(&*dma_pusher.channel_state.maxwell_dma, method_call.subchannel, EngineTypes::MaxwellDMA);
break; break;
case EngineID::KEPLER_INLINE_TO_MEMORY_B: case EngineID::KEPLER_INLINE_TO_MEMORY_B:
dma_pusher.BindSubchannel(&*channel_state.kepler_memory, method_call.subchannel, EngineTypes::KeplerMemory); dma_pusher.BindSubchannel(&*dma_pusher.channel_state.kepler_memory, method_call.subchannel, EngineTypes::KeplerMemory);
break; break;
case EngineID::NV01_TIMER: case EngineID::NV01_TIMER:
dma_pusher.BindSubchannel(&*channel_state.nv01_timer, method_call.subchannel, EngineTypes::Nv01Timer); dma_pusher.BindSubchannel(&*dma_pusher.channel_state.nv01_timer, method_call.subchannel, EngineTypes::Nv01Timer);
break; break;
default: default:
UNIMPLEMENTED_MSG("Unimplemented engine {:04X}", engine_id); UNIMPLEMENTED_MSG("Unimplemented engine {:04X}", engine_id);
@ -60,15 +52,15 @@ void Puller::ProcessBindMethod(const MethodCall& method_call) {
} }
} }
void Puller::ProcessFenceActionMethod() { void Puller::ProcessFenceActionMethod(DmaPusher& dma_pusher) {
switch (regs.fence_action.op) { switch (regs.fence_action.op) {
case Puller::FenceOperation::Acquire: case Puller::FenceOperation::Acquire:
// UNIMPLEMENTED_MSG("Channel Scheduling pending."); // UNIMPLEMENTED_MSG("Channel Scheduling pending.");
// WaitFence(regs.fence_action.syncpoint_id, regs.fence_value); // WaitFence(regs.fence_action.syncpoint_id, regs.fence_value);
rasterizer->ReleaseFences(); dma_pusher.rasterizer->ReleaseFences();
break; break;
case Puller::FenceOperation::Increment: case Puller::FenceOperation::Increment:
rasterizer->SignalSyncPoint(regs.fence_action.syncpoint_id); dma_pusher.rasterizer->SignalSyncPoint(regs.fence_action.syncpoint_id);
break; break;
default: default:
UNIMPLEMENTED_MSG("Unimplemented operation {}", regs.fence_action.op.Value()); UNIMPLEMENTED_MSG("Unimplemented operation {}", regs.fence_action.op.Value());
@ -76,37 +68,35 @@ void Puller::ProcessFenceActionMethod() {
} }
} }
void Puller::ProcessSemaphoreTriggerMethod() { void Puller::ProcessSemaphoreTriggerMethod(DmaPusher& dma_pusher) {
const auto semaphoreOperationMask = 0xF; const auto semaphoreOperationMask = 0xF;
const auto op = const auto op = GpuSemaphoreOperation(regs.semaphore_trigger & semaphoreOperationMask);
static_cast<GpuSemaphoreOperation>(regs.semaphore_trigger & semaphoreOperationMask);
if (op == GpuSemaphoreOperation::WriteLong) { if (op == GpuSemaphoreOperation::WriteLong) {
const GPUVAddr sequence_address{regs.semaphore_address.SemaphoreAddress()}; const GPUVAddr sequence_address{regs.semaphore_address.SemaphoreAddress()};
const u32 payload = regs.semaphore_sequence; const u32 payload = regs.semaphore_sequence;
rasterizer->Query(sequence_address, VideoCommon::QueryType::Payload, dma_pusher.rasterizer->Query(sequence_address, VideoCommon::QueryType::Payload, VideoCommon::QueryPropertiesFlags::HasTimeout, payload, 0);
VideoCommon::QueryPropertiesFlags::HasTimeout, payload, 0);
} else { } else {
do { do {
const u32 word{memory_manager.Read<u32>(regs.semaphore_address.SemaphoreAddress())}; const u32 word = dma_pusher.memory_manager.Read<u32>(regs.semaphore_address.SemaphoreAddress());
regs.acquire_source = true; regs.acquire_source = true;
regs.acquire_value = regs.semaphore_sequence; regs.acquire_value = regs.semaphore_sequence;
if (op == GpuSemaphoreOperation::AcquireEqual) { if (op == GpuSemaphoreOperation::AcquireEqual) {
regs.acquire_active = true; regs.acquire_active = true;
regs.acquire_mode = false; regs.acquire_mode = false;
if (word != regs.acquire_value) { if (word != regs.acquire_value) {
rasterizer->ReleaseFences(); dma_pusher.rasterizer->ReleaseFences();
continue; continue;
} }
} else if (op == GpuSemaphoreOperation::AcquireGequal) { } else if (op == GpuSemaphoreOperation::AcquireGequal) {
regs.acquire_active = true; regs.acquire_active = true;
regs.acquire_mode = true; regs.acquire_mode = true;
if (word < regs.acquire_value) { if (word < regs.acquire_value) {
rasterizer->ReleaseFences(); dma_pusher.rasterizer->ReleaseFences();
continue; continue;
} }
} else if (op == GpuSemaphoreOperation::AcquireMask) { } else if (op == GpuSemaphoreOperation::AcquireMask) {
if (word && regs.semaphore_sequence == 0) { if (word && regs.semaphore_sequence == 0) {
rasterizer->ReleaseFences(); dma_pusher.rasterizer->ReleaseFences();
continue; continue;
} }
} else { } else {
@ -116,21 +106,20 @@ void Puller::ProcessSemaphoreTriggerMethod() {
} }
} }
void Puller::ProcessSemaphoreRelease() { void Puller::ProcessSemaphoreRelease(DmaPusher& dma_pusher) {
const GPUVAddr sequence_address{regs.semaphore_address.SemaphoreAddress()}; const GPUVAddr sequence_address{regs.semaphore_address.SemaphoreAddress()};
const u32 payload = regs.semaphore_release; const u32 payload = regs.semaphore_release;
rasterizer->Query(sequence_address, VideoCommon::QueryType::Payload, dma_pusher.rasterizer->Query(sequence_address, VideoCommon::QueryType::Payload, VideoCommon::QueryPropertiesFlags::IsAFence, payload, 0);
VideoCommon::QueryPropertiesFlags::IsAFence, payload, 0);
} }
void Puller::ProcessSemaphoreAcquire() { void Puller::ProcessSemaphoreAcquire(DmaPusher& dma_pusher) {
u32 word = memory_manager.Read<u32>(regs.semaphore_address.SemaphoreAddress()); u32 word = dma_pusher.memory_manager.Read<u32>(regs.semaphore_address.SemaphoreAddress());
const auto value = regs.semaphore_acquire; const auto value = regs.semaphore_acquire;
while (word != value) { while (word != value) {
regs.acquire_active = true; regs.acquire_active = true;
regs.acquire_value = value; regs.acquire_value = value;
rasterizer->ReleaseFences(); dma_pusher.rasterizer->ReleaseFences();
word = memory_manager.Read<u32>(regs.semaphore_address.SemaphoreAddress()); word = dma_pusher.memory_manager.Read<u32>(regs.semaphore_address.SemaphoreAddress());
// TODO(kemathe73) figure out how to do the acquire_timeout // TODO(kemathe73) figure out how to do the acquire_timeout
regs.acquire_mode = false; regs.acquire_mode = false;
regs.acquire_source = false; regs.acquire_source = false;
@ -138,13 +127,13 @@ void Puller::ProcessSemaphoreAcquire() {
} }
/// Calls a GPU puller method. /// Calls a GPU puller method.
void Puller::CallPullerMethod(const MethodCall& method_call) { void Puller::CallPullerMethod(DmaPusher& dma_pusher, const MethodCall& method_call) {
regs.reg_array[method_call.method] = method_call.argument; regs.reg_array[method_call.method] = method_call.argument;
const auto method = static_cast<BufferMethods>(method_call.method); const auto method = static_cast<BufferMethods>(method_call.method);
switch (method) { switch (method) {
case BufferMethods::BindObject: { case BufferMethods::BindObject: {
ProcessBindMethod(method_call); ProcessBindMethod(dma_pusher, method_call);
break; break;
} }
case BufferMethods::Nop: case BufferMethods::Nop:
@ -155,16 +144,16 @@ void Puller::CallPullerMethod(const MethodCall& method_call) {
case BufferMethods::WrcacheFlush: case BufferMethods::WrcacheFlush:
break; break;
case BufferMethods::RefCnt: case BufferMethods::RefCnt:
rasterizer->SignalReference(); dma_pusher.rasterizer->SignalReference();
break; break;
case BufferMethods::SyncpointOperation: case BufferMethods::SyncpointOperation:
ProcessFenceActionMethod(); ProcessFenceActionMethod(dma_pusher);
break; break;
case BufferMethods::WaitForIdle: case BufferMethods::WaitForIdle:
rasterizer->WaitForIdle(); dma_pusher.rasterizer->WaitForIdle();
break; break;
case BufferMethods::SemaphoreOperation: { case BufferMethods::SemaphoreOperation: {
ProcessSemaphoreTriggerMethod(); ProcessSemaphoreTriggerMethod(dma_pusher);
break; break;
} }
case BufferMethods::NonStallInterrupt: { case BufferMethods::NonStallInterrupt: {
@ -177,7 +166,7 @@ void Puller::CallPullerMethod(const MethodCall& method_call) {
} }
case BufferMethods::MemOpB: { case BufferMethods::MemOpB: {
// Implement this better. // Implement this better.
rasterizer->InvalidateGPUCache(); dma_pusher.rasterizer->InvalidateGPUCache();
break; break;
} }
case BufferMethods::MemOpC: case BufferMethods::MemOpC:
@ -186,11 +175,11 @@ void Puller::CallPullerMethod(const MethodCall& method_call) {
break; break;
} }
case BufferMethods::SemaphoreAcquire: { case BufferMethods::SemaphoreAcquire: {
ProcessSemaphoreAcquire(); ProcessSemaphoreAcquire(dma_pusher);
break; break;
} }
case BufferMethods::SemaphoreRelease: { case BufferMethods::SemaphoreRelease: {
ProcessSemaphoreRelease(); ProcessSemaphoreRelease(dma_pusher);
break; break;
} }
case BufferMethods::Yield: { case BufferMethods::Yield: {
@ -205,27 +194,26 @@ void Puller::CallPullerMethod(const MethodCall& method_call) {
} }
/// Calls a GPU engine method. /// Calls a GPU engine method.
void Puller::CallEngineMethod(const MethodCall& method_call) { void Puller::CallEngineMethod(DmaPusher& dma_pusher, const MethodCall& method_call) {
const EngineID engine = bound_engines[method_call.subchannel]; const EngineID engine = bound_engines[method_call.subchannel];
switch (engine) { switch (engine) {
case EngineID::FERMI_TWOD_A: case EngineID::FERMI_TWOD_A:
channel_state.fermi_2d->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall()); dma_pusher.channel_state.fermi_2d->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
break; break;
case EngineID::MAXWELL_B: case EngineID::MAXWELL_B:
channel_state.maxwell_3d->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall()); dma_pusher.channel_state.maxwell_3d->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
break; break;
case EngineID::KEPLER_COMPUTE_B: case EngineID::KEPLER_COMPUTE_B:
channel_state.kepler_compute->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall()); dma_pusher.channel_state.kepler_compute->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
break; break;
case EngineID::MAXWELL_DMA_COPY_A: case EngineID::MAXWELL_DMA_COPY_A:
channel_state.maxwell_dma->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall()); dma_pusher.channel_state.maxwell_dma->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
break; break;
case EngineID::KEPLER_INLINE_TO_MEMORY_B: case EngineID::KEPLER_INLINE_TO_MEMORY_B:
channel_state.kepler_memory->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall()); dma_pusher.channel_state.kepler_memory->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
break; break;
case EngineID::NV01_TIMER: case EngineID::NV01_TIMER:
channel_state.nv01_timer->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall()); dma_pusher.channel_state.nv01_timer->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
break; break;
default: default:
UNIMPLEMENTED_MSG("Unimplemented engine"); UNIMPLEMENTED_MSG("Unimplemented engine");
@ -234,28 +222,26 @@ void Puller::CallEngineMethod(const MethodCall& method_call) {
} }
/// Calls a GPU engine multivalue method. /// Calls a GPU engine multivalue method.
void Puller::CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount, void Puller::CallEngineMultiMethod(DmaPusher& dma_pusher, u32 method, u32 subchannel, const u32* base_start, u32 amount, u32 methods_pending) {
u32 methods_pending) {
const EngineID engine = bound_engines[subchannel]; const EngineID engine = bound_engines[subchannel];
switch (engine) { switch (engine) {
case EngineID::FERMI_TWOD_A: case EngineID::FERMI_TWOD_A:
channel_state.fermi_2d->CallMultiMethod(method, base_start, amount, methods_pending); dma_pusher.channel_state.fermi_2d->CallMultiMethod(method, base_start, amount, methods_pending);
break; break;
case EngineID::MAXWELL_B: case EngineID::MAXWELL_B:
channel_state.maxwell_3d->CallMultiMethod(method, base_start, amount, methods_pending); dma_pusher.channel_state.maxwell_3d->CallMultiMethod(method, base_start, amount, methods_pending);
break; break;
case EngineID::KEPLER_COMPUTE_B: case EngineID::KEPLER_COMPUTE_B:
channel_state.kepler_compute->CallMultiMethod(method, base_start, amount, methods_pending); dma_pusher.channel_state.kepler_compute->CallMultiMethod(method, base_start, amount, methods_pending);
break; break;
case EngineID::MAXWELL_DMA_COPY_A: case EngineID::MAXWELL_DMA_COPY_A:
channel_state.maxwell_dma->CallMultiMethod(method, base_start, amount, methods_pending); dma_pusher.channel_state.maxwell_dma->CallMultiMethod(method, base_start, amount, methods_pending);
break; break;
case EngineID::KEPLER_INLINE_TO_MEMORY_B: case EngineID::KEPLER_INLINE_TO_MEMORY_B:
channel_state.kepler_memory->CallMultiMethod(method, base_start, amount, methods_pending); dma_pusher.channel_state.kepler_memory->CallMultiMethod(method, base_start, amount, methods_pending);
break; break;
case EngineID::NV01_TIMER: case EngineID::NV01_TIMER:
channel_state.nv01_timer->CallMultiMethod(method, base_start, amount, methods_pending); dma_pusher.channel_state.nv01_timer->CallMultiMethod(method, base_start, amount, methods_pending);
break; break;
default: default:
UNIMPLEMENTED_MSG("Unimplemented engine"); UNIMPLEMENTED_MSG("Unimplemented engine");
@ -264,31 +250,26 @@ void Puller::CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_s
} }
/// Calls a GPU method. /// Calls a GPU method.
void Puller::CallMethod(const MethodCall& method_call) { void Puller::CallMethod(DmaPusher& dma_pusher, const MethodCall& method_call) {
LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method_call.method, LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method_call.method, method_call.subchannel);
method_call.subchannel);
ASSERT(method_call.subchannel < bound_engines.size()); ASSERT(method_call.subchannel < bound_engines.size());
if (ExecuteMethodOnEngine(method_call.method)) { if (ExecuteMethodOnEngine(dma_pusher, method_call.method)) {
CallEngineMethod(method_call); CallEngineMethod(dma_pusher, method_call);
} else { } else {
CallPullerMethod(method_call); CallPullerMethod(dma_pusher, method_call);
} }
} }
/// Calls a GPU multivalue method. /// Calls a GPU multivalue method.
void Puller::CallMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount, void Puller::CallMultiMethod(DmaPusher& dma_pusher, u32 method, u32 subchannel, const u32* base_start, u32 amount, u32 methods_pending) {
u32 methods_pending) {
LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method, subchannel); LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method, subchannel);
ASSERT(subchannel < bound_engines.size()); ASSERT(subchannel < bound_engines.size());
if (ExecuteMethodOnEngine(dma_pusher, method)) {
if (ExecuteMethodOnEngine(method)) { CallEngineMultiMethod(dma_pusher, method, subchannel, base_start, amount, methods_pending);
CallEngineMultiMethod(method, subchannel, base_start, amount, methods_pending);
} else { } else {
for (u32 i = 0; i < amount; i++) { for (u32 i = 0; i < amount; i++) {
CallPullerMethod(MethodCall{ CallPullerMethod(dma_pusher, MethodCall{
method, method,
base_start[i], base_start[i],
subchannel, subchannel,
@ -298,13 +279,9 @@ void Puller::CallMultiMethod(u32 method, u32 subchannel, const u32* base_start,
} }
} }
void Puller::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
rasterizer = rasterizer_;
}
/// Determines where the method should be executed. /// Determines where the method should be executed.
[[nodiscard]] bool Puller::ExecuteMethodOnEngine(u32 method) { [[nodiscard]] bool Puller::ExecuteMethodOnEngine(DmaPusher& dma_pusher, u32 method) {
const auto buffer_method = static_cast<BufferMethods>(method); const auto buffer_method = BufferMethods(method);
return buffer_method >= BufferMethods::NonPullerMethods; return buffer_method >= BufferMethods::NonPullerMethods;
} }

View file

@ -70,32 +70,13 @@ public:
BitField<8, 24, u32> syncpoint_id; BitField<8, 24, u32> syncpoint_id;
}; };
explicit Puller(GPU& gpu_, MemoryManager& memory_manager_, DmaPusher& dma_pusher, void CallMethod(DmaPusher& dma_pusher, const MethodCall& method_call);
Control::ChannelState& channel_state); void CallMultiMethod(DmaPusher& dma_pusher, u32 method, u32 subchannel, const u32* base_start, u32 amount, u32 methods_pending);
~Puller(); void BindRasterizer(DmaPusher& dma_pusher, VideoCore::RasterizerInterface* rasterizer);
void CallPullerMethod(DmaPusher& dma_pusher, const MethodCall& method_call);
void CallMethod(const MethodCall& method_call); void CallEngineMethod(DmaPusher& dma_pusher, const MethodCall& method_call);
void CallEngineMultiMethod(DmaPusher& dma_pusher, u32 method, u32 subchannel, const u32* base_start, u32 amount, u32 methods_pending);
void CallMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount,
u32 methods_pending);
void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
void CallPullerMethod(const MethodCall& method_call);
void CallEngineMethod(const MethodCall& method_call);
void CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount,
u32 methods_pending);
private: private:
Tegra::GPU& gpu;
MemoryManager& memory_manager;
DmaPusher& dma_pusher;
Control::ChannelState& channel_state;
VideoCore::RasterizerInterface* rasterizer = nullptr;
static constexpr std::size_t NUM_REGS = 0x800; static constexpr std::size_t NUM_REGS = 0x800;
struct Regs { struct Regs {
static constexpr size_t NUM_REGS = 0x40; static constexpr size_t NUM_REGS = 0x40;
@ -139,12 +120,12 @@ private:
}; };
} regs{}; } regs{};
void ProcessBindMethod(const MethodCall& method_call); void ProcessBindMethod(DmaPusher& dma_pusher, const MethodCall& method_call);
void ProcessFenceActionMethod(); void ProcessFenceActionMethod(DmaPusher& dma_pusher);
void ProcessSemaphoreAcquire(); void ProcessSemaphoreAcquire(DmaPusher& dma_pusher);
void ProcessSemaphoreRelease(); void ProcessSemaphoreRelease(DmaPusher& dma_pusher);
void ProcessSemaphoreTriggerMethod(); void ProcessSemaphoreTriggerMethod(DmaPusher& dma_pusher);
[[nodiscard]] bool ExecuteMethodOnEngine(u32 method); [[nodiscard]] bool ExecuteMethodOnEngine(DmaPusher& dma_pusher, u32 method);
/// Mapping of command subchannels to their bound engine ids /// Mapping of command subchannels to their bound engine ids
std::array<EngineID, 8> bound_engines{}; std::array<EngineID, 8> bound_engines{};
@ -157,8 +138,7 @@ private:
}; };
#define ASSERT_REG_POSITION(field_name, position) \ #define ASSERT_REG_POSITION(field_name, position) \
static_assert(offsetof(Regs, field_name) == position * 4, \ static_assert(offsetof(Regs, field_name) == position * 4, "Field " #field_name " has invalid position")
"Field " #field_name " has invalid position")
ASSERT_REG_POSITION(semaphore_address, 0x4); ASSERT_REG_POSITION(semaphore_address, 0x4);
ASSERT_REG_POSITION(semaphore_sequence, 0x6); ASSERT_REG_POSITION(semaphore_sequence, 0x6);

View file

@ -40,30 +40,32 @@
namespace Tegra { namespace Tegra {
struct GPU::Impl { struct GPU::Impl {
explicit Impl(GPU& gpu_, Core::System& system_, bool is_async_, bool use_nvdec_) explicit Impl(Core::System& system_, bool is_async_, bool use_nvdec_)
: gpu{gpu_}, system{system_}, host1x{system.Host1x()}, use_nvdec{use_nvdec_}, : system{system_}
shader_notify{std::make_unique<VideoCore::ShaderNotify>()}, is_async{is_async_}, , use_nvdec{use_nvdec_}
gpu_thread{system_, is_async_}, scheduler{std::make_unique<Control::Scheduler>(gpu)} {} , shader_notify()
, is_async{is_async_}
, gpu_thread{system_, is_async_}
, scheduler(system_.GPU())
{}
~Impl() = default; ~Impl() = default;
std::shared_ptr<Control::ChannelState> CreateChannel(s32 channel_id) { std::shared_ptr<Control::ChannelState> CreateChannel(s32 channel_id) {
auto channel_state = std::make_shared<Tegra::Control::ChannelState>(channel_id); auto channel_state = std::make_shared<Tegra::Control::ChannelState>(channel_id);
channels.emplace(channel_id, channel_state); channels.emplace(channel_id, channel_state);
scheduler->DeclareChannel(channel_state); scheduler.DeclareChannel(channel_state);
return channel_state; return channel_state;
} }
void BindChannel(s32 channel_id) { void BindChannel(s32 channel_id) {
if (bound_channel == channel_id) { if (bound_channel != channel_id) {
return; auto it = channels.find(channel_id);
ASSERT(it != channels.end());
bound_channel = channel_id;
current_channel = it->second.get();
renderer->ReadRasterizer()->BindChannel(*current_channel);
} }
auto it = channels.find(channel_id);
ASSERT(it != channels.end());
bound_channel = channel_id;
current_channel = it->second.get();
rasterizer->BindChannel(*current_channel);
} }
std::shared_ptr<Control::ChannelState> AllocateChannel() { std::shared_ptr<Control::ChannelState> AllocateChannel() {
@ -71,13 +73,13 @@ struct GPU::Impl {
} }
void InitChannel(Control::ChannelState& to_init, u64 program_id) { void InitChannel(Control::ChannelState& to_init, u64 program_id) {
to_init.Init(system, gpu, program_id); to_init.Init(system, program_id);
to_init.BindRasterizer(rasterizer); to_init.BindRasterizer(renderer->ReadRasterizer());
rasterizer->InitializeChannel(to_init); renderer->ReadRasterizer()->InitializeChannel(to_init);
} }
void InitAddressSpace(Tegra::MemoryManager& memory_manager) { void InitAddressSpace(Tegra::MemoryManager& memory_manager) {
memory_manager.BindRasterizer(rasterizer); memory_manager.BindRasterizer(renderer->ReadRasterizer());
} }
void ReleaseChannel(Control::ChannelState& to_release) { void ReleaseChannel(Control::ChannelState& to_release) {
@ -87,26 +89,26 @@ struct GPU::Impl {
/// Binds a renderer to the GPU. /// Binds a renderer to the GPU.
void BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) { void BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) {
renderer = std::move(renderer_); renderer = std::move(renderer_);
rasterizer = renderer->ReadRasterizer(); system.Host1x().MemoryManager().BindInterface(renderer->ReadRasterizer());
host1x.MemoryManager().BindInterface(rasterizer); system.Host1x().GMMU().BindRasterizer(renderer->ReadRasterizer());
host1x.gmmu_manager.BindRasterizer(rasterizer);
} }
/// Flush all current written commands into the host GPU for execution. /// Flush all current written commands into the host GPU for execution.
void FlushCommands() { void FlushCommands() {
rasterizer->FlushCommands(); renderer->ReadRasterizer()->FlushCommands();
} }
/// Synchronizes CPU writes with Host GPU memory. /// Synchronizes CPU writes with Host GPU memory.
void InvalidateGPUCache() { void InvalidateGPUCache() {
std::function<void(PAddr, size_t)> callback_writes( std::function<void(PAddr, size_t)> callback_writes([this](PAddr address, size_t size) {
[this](PAddr address, size_t size) { rasterizer->OnCacheInvalidation(address, size); }); renderer->ReadRasterizer()->OnCacheInvalidation(address, size);
});
system.GatherGPUDirtyMemory(callback_writes); system.GatherGPUDirtyMemory(callback_writes);
} }
/// Signal the ending of command list. /// Signal the ending of command list.
void OnCommandListEnd() { void OnCommandListEnd() {
rasterizer->ReleaseFences(false); renderer->ReadRasterizer()->ReleaseFences(false);
Settings::UpdateGPUAccuracy(); Settings::UpdateGPUAccuracy();
} }
@ -143,62 +145,6 @@ struct GPU::Impl {
} }
} }
/// Returns a reference to the Maxwell3D GPU engine.
[[nodiscard]] Engines::Maxwell3D& Maxwell3D() {
ASSERT(current_channel);
return *current_channel->maxwell_3d;
}
/// Returns a const reference to the Maxwell3D GPU engine.
[[nodiscard]] const Engines::Maxwell3D& Maxwell3D() const {
ASSERT(current_channel);
return *current_channel->maxwell_3d;
}
/// Returns a reference to the KeplerCompute GPU engine.
[[nodiscard]] Engines::KeplerCompute& KeplerCompute() {
ASSERT(current_channel);
return *current_channel->kepler_compute;
}
/// Returns a reference to the KeplerCompute GPU engine.
[[nodiscard]] const Engines::KeplerCompute& KeplerCompute() const {
ASSERT(current_channel);
return *current_channel->kepler_compute;
}
/// Returns a reference to the GPU DMA pusher.
[[nodiscard]] Tegra::DmaPusher& DmaPusher() {
ASSERT(current_channel);
return *current_channel->dma_pusher;
}
/// Returns a const reference to the GPU DMA pusher.
[[nodiscard]] const Tegra::DmaPusher& DmaPusher() const {
ASSERT(current_channel);
return *current_channel->dma_pusher;
}
/// Returns a reference to the underlying renderer.
[[nodiscard]] VideoCore::RendererBase& Renderer() {
return *renderer;
}
/// Returns a const reference to the underlying renderer.
[[nodiscard]] const VideoCore::RendererBase& Renderer() const {
return *renderer;
}
/// Returns a reference to the shader notifier.
[[nodiscard]] VideoCore::ShaderNotify& ShaderNotify() {
return *shader_notify;
}
/// Returns a const reference to the shader notifier.
[[nodiscard]] const VideoCore::ShaderNotify& ShaderNotify() const {
return *shader_notify;
}
[[nodiscard]] u64 GetTicks() const { [[nodiscard]] u64 GetTicks() const {
u64 gpu_tick = system.CoreTiming().GetGPUTicks(); u64 gpu_tick = system.CoreTiming().GetGPUTicks();
Settings::GpuOverclock overclock = Settings::values.fast_gpu_time.GetValue(); Settings::GpuOverclock overclock = Settings::values.fast_gpu_time.GetValue();
@ -210,14 +156,6 @@ struct GPU::Impl {
return gpu_tick; return gpu_tick;
} }
[[nodiscard]] bool IsAsync() const {
return is_async;
}
[[nodiscard]] bool UseNvdec() const {
return use_nvdec;
}
void RendererFrameEndNotify() { void RendererFrameEndNotify() {
system.GetPerfStats().EndGameFrame(); system.GetPerfStats().EndGameFrame();
} }
@ -227,7 +165,7 @@ struct GPU::Impl {
/// core timing events. /// core timing events.
void Start() { void Start() {
Settings::UpdateGPUAccuracy(); Settings::UpdateGPUAccuracy();
gpu_thread.StartThread(*renderer, renderer->Context(), *scheduler); gpu_thread.StartThread(*renderer, renderer->Context(), scheduler);
} }
void NotifyShutdown() { void NotifyShutdown() {
@ -260,14 +198,13 @@ struct GPU::Impl {
} }
VideoCore::RasterizerDownloadArea OnCPURead(DAddr addr, u64 size) { VideoCore::RasterizerDownloadArea OnCPURead(DAddr addr, u64 size) {
auto raster_area = rasterizer->GetFlushArea(addr, size); auto raster_area = renderer->ReadRasterizer()->GetFlushArea(addr, size);
if (raster_area.preemtive) { if (raster_area.preemtive) {
return raster_area; return raster_area;
} }
raster_area.preemtive = true; raster_area.preemtive = true;
const u64 fence = RequestSyncOperation([this, &raster_area]() { const u64 fence = RequestSyncOperation([this, &raster_area]() {
rasterizer->FlushRegion(raster_area.start_address, renderer->ReadRasterizer()->FlushRegion(raster_area.start_address, raster_area.end_address - raster_area.start_address);
raster_area.end_address - raster_area.start_address);
}); });
gpu_thread.TickGPU(); gpu_thread.TickGPU();
WaitForSyncOperation(fence); WaitForSyncOperation(fence);
@ -280,7 +217,7 @@ struct GPU::Impl {
} }
bool OnCPUWrite(DAddr addr, u64 size) { bool OnCPUWrite(DAddr addr, u64 size) {
return rasterizer->OnCPUWrite(addr, size); return renderer->ReadRasterizer()->OnCPUWrite(addr, size);
} }
/// Notify rasterizer that any caches of the specified region should be flushed and invalidated /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
@ -288,8 +225,7 @@ struct GPU::Impl {
gpu_thread.FlushAndInvalidateRegion(addr, size); gpu_thread.FlushAndInvalidateRegion(addr, size);
} }
void RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers, void RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers, std::vector<Service::Nvidia::NvFence>&& fences) {
std::vector<Service::Nvidia::NvFence>&& fences) {
size_t num_fences{fences.size()}; size_t num_fences{fences.size()};
size_t current_request_counter{}; size_t current_request_counter{};
{ {
@ -304,7 +240,7 @@ struct GPU::Impl {
} }
} }
const auto wait_fence = RequestSyncOperation([this, current_request_counter, &layers, &fences, num_fences] { const auto wait_fence = RequestSyncOperation([this, current_request_counter, &layers, &fences, num_fences] {
auto& syncpoint_manager = host1x.GetSyncpointManager(); auto& syncpoint_manager = system.Host1x().host1x.GetSyncpointManager();
if (num_fences == 0) { if (num_fences == 0) {
renderer->Composite(layers); renderer->Composite(layers);
} }
@ -337,17 +273,14 @@ struct GPU::Impl {
return out; return out;
} }
GPU& gpu;
Core::System& system; Core::System& system;
Host1x::Host1x& host1x;
std::unique_ptr<VideoCore::RendererBase> renderer; std::unique_ptr<VideoCore::RendererBase> renderer;
VideoCore::RasterizerInterface* rasterizer = nullptr;
const bool use_nvdec; const bool use_nvdec;
s32 new_channel_id{1}; s32 new_channel_id{1};
/// Shader build notifier /// Shader build notifier
std::unique_ptr<VideoCore::ShaderNotify> shader_notify; VideoCore::ShaderNotify shader_notify;
/// When true, we are about to shut down emulation session, so terminate outstanding tasks /// When true, we are about to shut down emulation session, so terminate outstanding tasks
std::atomic_bool shutting_down{}; std::atomic_bool shutting_down{};
@ -371,7 +304,7 @@ struct GPU::Impl {
VideoCommon::GPUThread::ThreadManager gpu_thread; VideoCommon::GPUThread::ThreadManager gpu_thread;
std::unique_ptr<Core::Frontend::GraphicsContext> cpu_context; std::unique_ptr<Core::Frontend::GraphicsContext> cpu_context;
std::unique_ptr<Tegra::Control::Scheduler> scheduler; Tegra::Control::Scheduler scheduler;
ankerl::unordered_dense::map<s32, std::shared_ptr<Tegra::Control::ChannelState>> channels; ankerl::unordered_dense::map<s32, std::shared_ptr<Tegra::Control::ChannelState>> channels;
Tegra::Control::ChannelState* current_channel; Tegra::Control::ChannelState* current_channel;
s32 bound_channel{-1}; s32 bound_channel{-1};
@ -382,7 +315,8 @@ struct GPU::Impl {
}; };
GPU::GPU(Core::System& system, bool is_async, bool use_nvdec) GPU::GPU(Core::System& system, bool is_async, bool use_nvdec)
: impl{std::make_unique<Impl>(*this, system, is_async, use_nvdec)} {} : impl{std::make_unique<Impl>(system, is_async, use_nvdec)}
{}
GPU::~GPU() = default; GPU::~GPU() = default;
@ -423,8 +357,9 @@ void GPU::OnCommandListEnd() {
} }
u64 GPU::RequestFlush(DAddr addr, std::size_t size) { u64 GPU::RequestFlush(DAddr addr, std::size_t size) {
return impl->RequestSyncOperation( return impl->RequestSyncOperation([this, addr, size]() {
[this, addr, size]() { impl->rasterizer->FlushRegion(addr, size); }); impl->renderer->ReadRasterizer()->FlushRegion(addr, size);
});
} }
u64 GPU::CurrentSyncRequestFence() const { u64 GPU::CurrentSyncRequestFence() const {
@ -441,52 +376,52 @@ void GPU::TickWork() {
/// Gets a mutable reference to the Host1x interface /// Gets a mutable reference to the Host1x interface
Host1x::Host1x& GPU::Host1x() { Host1x::Host1x& GPU::Host1x() {
return impl->host1x; return impl->system.Host1x();
} }
/// Gets an immutable reference to the Host1x interface. /// Gets an immutable reference to the Host1x interface.
const Host1x::Host1x& GPU::Host1x() const { const Host1x::Host1x& GPU::Host1x() const {
return impl->host1x; return impl->system.Host1x();
} }
Engines::Maxwell3D& GPU::Maxwell3D() { Engines::Maxwell3D& GPU::Maxwell3D() {
return impl->Maxwell3D(); return *impl->current_channel->maxwell_3d;
} }
const Engines::Maxwell3D& GPU::Maxwell3D() const { const Engines::Maxwell3D& GPU::Maxwell3D() const {
return impl->Maxwell3D(); return *impl->current_channel->maxwell_3d;
} }
Engines::KeplerCompute& GPU::KeplerCompute() { Engines::KeplerCompute& GPU::KeplerCompute() {
return impl->KeplerCompute(); return *impl->current_channel->kepler_compute;
} }
const Engines::KeplerCompute& GPU::KeplerCompute() const { const Engines::KeplerCompute& GPU::KeplerCompute() const {
return impl->KeplerCompute(); return *impl->current_channel->kepler_compute;
} }
Tegra::DmaPusher& GPU::DmaPusher() { Tegra::DmaPusher& GPU::DmaPusher() {
return impl->DmaPusher(); return *impl->current_channel->dma_pusher;
} }
const Tegra::DmaPusher& GPU::DmaPusher() const { const Tegra::DmaPusher& GPU::DmaPusher() const {
return impl->DmaPusher(); return *impl->current_channel->dma_pusher;
} }
VideoCore::RendererBase& GPU::Renderer() { VideoCore::RendererBase& GPU::Renderer() {
return impl->Renderer(); return *impl->renderer;
} }
const VideoCore::RendererBase& GPU::Renderer() const { const VideoCore::RendererBase& GPU::Renderer() const {
return impl->Renderer(); return *impl->renderer;
} }
VideoCore::ShaderNotify& GPU::ShaderNotify() { VideoCore::ShaderNotify& GPU::ShaderNotify() {
return impl->ShaderNotify(); return impl->shader_notify;
} }
const VideoCore::ShaderNotify& GPU::ShaderNotify() const { const VideoCore::ShaderNotify& GPU::ShaderNotify() const {
return impl->ShaderNotify(); return impl->shader_notify;
} }
void GPU::RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers, void GPU::RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers,
@ -503,11 +438,11 @@ u64 GPU::GetTicks() const {
} }
bool GPU::IsAsync() const { bool GPU::IsAsync() const {
return impl->IsAsync(); return impl->is_async;
} }
bool GPU::UseNvdec() const { bool GPU::UseNvdec() const {
return impl->UseNvdec(); return impl->use_nvdec;
} }
void GPU::RendererFrameEndNotify() { void GPU::RendererFrameEndNotify() {