mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 06:39:46 -06:00
VideoCommon/Fifo: Refactor to class, move to Core::System.
This commit is contained in:
@ -3,21 +3,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
|
||||
#include "Common/BlockingLoop.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Event.h"
|
||||
#include "Common/Flag.h"
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
namespace Core
|
||||
{
|
||||
class System;
|
||||
}
|
||||
namespace CoreTiming
|
||||
{
|
||||
struct EventType;
|
||||
}
|
||||
|
||||
namespace Fifo
|
||||
{
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void Prepare(); // Must be called from the CPU thread.
|
||||
void DoState(PointerWrap& f);
|
||||
void PauseAndLock(bool doLock, bool unpauseOnUnlock);
|
||||
void UpdateWantDeterminism(bool want);
|
||||
bool UseDeterministicGPUThread();
|
||||
|
||||
// Used for diagnostics.
|
||||
enum class SyncGPUReason
|
||||
{
|
||||
@ -29,23 +36,95 @@ enum class SyncGPUReason
|
||||
Swap,
|
||||
AuxSpace,
|
||||
};
|
||||
// In deterministic GPU thread mode this waits for the GPU to be done with pending work.
|
||||
void SyncGPU(SyncGPUReason reason, bool may_move_read_ptr = true);
|
||||
|
||||
// In single core mode, this runs the GPU for a single slice.
|
||||
// In dual core mode, this synchronizes with the GPU thread.
|
||||
void SyncGPUForRegisterAccess();
|
||||
class FifoManager final
|
||||
{
|
||||
public:
|
||||
FifoManager();
|
||||
FifoManager(const FifoManager& other) = delete;
|
||||
FifoManager(FifoManager&& other) = delete;
|
||||
FifoManager& operator=(const FifoManager& other) = delete;
|
||||
FifoManager& operator=(FifoManager&& other) = delete;
|
||||
~FifoManager();
|
||||
|
||||
void PushFifoAuxBuffer(const void* ptr, size_t size);
|
||||
void* PopFifoAuxBuffer(size_t size);
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void Prepare(); // Must be called from the CPU thread.
|
||||
void DoState(PointerWrap& f);
|
||||
void PauseAndLock(bool doLock, bool unpauseOnUnlock);
|
||||
void UpdateWantDeterminism(bool want);
|
||||
bool UseDeterministicGPUThread() const { return m_use_deterministic_gpu_thread; }
|
||||
|
||||
void FlushGpu();
|
||||
void RunGpu();
|
||||
void GpuMaySleep();
|
||||
void RunGpuLoop();
|
||||
void ExitGpuLoop();
|
||||
void EmulatorState(bool running);
|
||||
bool AtBreakpoint();
|
||||
void ResetVideoBuffer();
|
||||
// In deterministic GPU thread mode this waits for the GPU to be done with pending work.
|
||||
void SyncGPU(SyncGPUReason reason, bool may_move_read_ptr = true);
|
||||
|
||||
// In single core mode, this runs the GPU for a single slice.
|
||||
// In dual core mode, this synchronizes with the GPU thread.
|
||||
void SyncGPUForRegisterAccess();
|
||||
|
||||
void PushFifoAuxBuffer(const void* ptr, size_t size);
|
||||
void* PopFifoAuxBuffer(size_t size);
|
||||
|
||||
void FlushGpu();
|
||||
void RunGpu();
|
||||
void GpuMaySleep();
|
||||
void RunGpuLoop();
|
||||
void ExitGpuLoop();
|
||||
void EmulatorState(bool running);
|
||||
bool AtBreakpoint() const;
|
||||
void ResetVideoBuffer();
|
||||
|
||||
private:
|
||||
void RefreshConfig();
|
||||
void ReadDataFromFifo(u32 readPtr);
|
||||
void ReadDataFromFifoOnCPU(u32 readPtr);
|
||||
int RunGpuOnCpu(int ticks);
|
||||
int WaitForGpuThread(int ticks);
|
||||
static void SyncGPUCallback(Core::System& system, u64 ticks, s64 cyclesLate);
|
||||
|
||||
static constexpr u32 FIFO_SIZE = 2 * 1024 * 1024;
|
||||
|
||||
Common::BlockingLoop m_gpu_mainloop;
|
||||
|
||||
Common::Flag m_emu_running_state;
|
||||
|
||||
// Most of this array is unlikely to be faulted in...
|
||||
u8 m_fifo_aux_data[FIFO_SIZE]{};
|
||||
u8* m_fifo_aux_write_ptr = nullptr;
|
||||
u8* m_fifo_aux_read_ptr = nullptr;
|
||||
|
||||
// This could be in SConfig, but it depends on multiple settings
|
||||
// and can change at runtime.
|
||||
bool m_use_deterministic_gpu_thread = false;
|
||||
|
||||
CoreTiming::EventType* m_event_sync_gpu = nullptr;
|
||||
|
||||
// STATE_TO_SAVE
|
||||
u8* m_video_buffer = nullptr;
|
||||
u8* m_video_buffer_read_ptr = nullptr;
|
||||
std::atomic<u8*> m_video_buffer_write_ptr = nullptr;
|
||||
std::atomic<u8*> m_video_buffer_seen_ptr = nullptr;
|
||||
u8* m_video_buffer_pp_read_ptr = nullptr;
|
||||
// The read_ptr is always owned by the GPU thread. In normal mode, so is the
|
||||
// write_ptr, despite it being atomic. In deterministic GPU thread mode,
|
||||
// things get a bit more complicated:
|
||||
// - The seen_ptr is written by the GPU thread, and points to what it's already
|
||||
// processed as much of as possible - in the case of a partial command which
|
||||
// caused it to stop, not the same as the read ptr. It's written by the GPU,
|
||||
// under the lock, and updating the cond.
|
||||
// - The write_ptr is written by the CPU thread after it copies data from the
|
||||
// FIFO. Maybe someday it will be under the lock. For now, because RunGpuLoop
|
||||
// polls, it's just atomic.
|
||||
// - The pp_read_ptr is the CPU preprocessing version of the read_ptr.
|
||||
|
||||
std::atomic<int> m_sync_ticks = 0;
|
||||
bool m_syncing_suspended = false;
|
||||
Common::Event m_sync_wakeup_event;
|
||||
|
||||
std::optional<size_t> m_config_callback_id = std::nullopt;
|
||||
bool m_config_sync_gpu = false;
|
||||
int m_config_sync_gpu_max_distance = 0;
|
||||
int m_config_sync_gpu_min_distance = 0;
|
||||
float m_config_sync_gpu_overclock = 0.0f;
|
||||
};
|
||||
} // namespace Fifo
|
||||
|
Reference in New Issue
Block a user