mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-06-06 01:13:45 -04:00
[video_core] Remove redundant references in GPU engine structs
Signed-off-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
parent
82463a1550
commit
83581f8df2
7 changed files with 164 additions and 283 deletions
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue