#pragma once #include "util/types.hpp" #include "Emu/RSX/gcm_enums.h" #include struct RsxDmaControl; namespace rsx { class thread; struct rsx_iomap_table; namespace FIFO { enum internal_commands : u32 { FIFO_NOP = 0xBABEF1F4, FIFO_EMPTY = 0xDEADF1F0, FIFO_BUSY = 0xBABEF1F0, FIFO_ERROR = 0xDEADBEEF, FIFO_PACKET_BEGIN = 0xF1F0, FIFO_DISABLED_COMMAND = 0xF1F4, FIFO_DRAW_BARRIER = 0xF1F8, }; enum flatten_op : u32 { NOTHING = 0, EMIT_END = 1, EMIT_BARRIER = 2 }; enum class state : u8 { running = 0, empty = 1, // PUT == GET spinning = 2, // Puller continuously jumps to self addr (synchronization technique) nop = 3, // Puller is processing a NOP command lock_wait = 4,// Puller is processing a lock acquire paused = 5, // Puller is paused externallly }; enum class interrupt_hint : u8 { conditional_render_eval = 1, zcull_sync = 2 }; struct register_pair { u32 reg; u32 value; void set(u32 reg, u32 val) { this->reg = reg; this->value = val; } }; class flattening_helper { enum register_props : u8 { none = 0, skip_on_match = 1, always_ignore = 2 }; enum optimization_hint : u8 { unknown, load_low, load_unoptimizable, application_not_compatible }; // Workaround for MSVC, C2248 static constexpr u8 register_props_always_ignore = register_props::always_ignore; static constexpr std::array m_register_properties = [] { constexpr std::array, 4> ignorable_ranges = {{ // General { NV4097_INVALIDATE_VERTEX_FILE, 3 }, // PSLight clears VERTEX_FILE[0-2] { NV4097_INVALIDATE_VERTEX_CACHE_FILE, 1 }, { NV4097_INVALIDATE_L2, 1 }, { NV4097_INVALIDATE_ZCULL, 1 } }}; std::array register_properties{}; for (const auto &method : ignorable_ranges) { for (u32 i = 0; i < method.second; ++i) { register_properties[method.first + i] |= register_props_always_ignore; } } return register_properties; }(); u32 deferred_primitive = 0; u32 draw_count = 0; bool in_begin_end = false; bool enabled = false; u32 num_collapsed = 0; optimization_hint fifo_hint = unknown; void reset(bool _enabled); public: flattening_helper() = default; ~flattening_helper() = default; u32 get_primitive() const { return deferred_primitive; } bool is_enabled() const { return enabled; } void force_disable(); void evaluate_performance(u32 total_draw_count); inline flatten_op test(register_pair& command); }; class FIFO_control { private: mutable rsx::thread* m_thread; RsxDmaControl* m_ctrl = nullptr; const rsx::rsx_iomap_table* m_iotable; u32 m_internal_get = 0; u32 m_memwatch_addr = 0; u32 m_memwatch_cmp = 0; u32 m_command_reg = 0; u32 m_command_inc = 0; u32 m_remaining_commands = 0; u32 m_args_ptr = 0; u32 m_cmd = ~0u; u32 m_cache_addr = 0; u32 m_cache_size = 0; alignas(64) std::byte m_cache[8][128]; public: FIFO_control(rsx::thread* pctrl); ~FIFO_control() = default; std::pair fetch_u32(u32 addr); void invalidate_cache() { m_cache_size = 0; } u32 get_pos() const { return m_internal_get; } u32 last_cmd() const { return m_cmd; } void sync_get() const; std::span get_current_arg_ptr() const; u32 get_remaining_args_count() const { return m_remaining_commands; } void restore_state(u32 cmd, u32 count); void inc_get(bool wait); void set_get(u32 get, u32 spin_cmd = 0); void abort(); template u32 read_put() const; void read(register_pair& data); inline bool read_unsafe(register_pair& data); bool skip_methods(u32 count); }; } }