#pragma once #include "Emu/CPU/CPUThread.h" #include "Emu/RSX/rsx_methods.h" #include #include namespace rsx { enum : u32 { c_fc_magic = "RRC"_u32, c_fc_version = 0x5, }; struct frame_capture_data { struct memory_block_data { std::vector data{}; }; // simple block to hold ps3 address and data struct memory_block { using enable_bitcopy = std::true_type; u32 offset; // Offset in rsx address space u32 location; // rsx memory location of the block u64 data_state; }; struct replay_command { std::pair rsx_command{}; // fifo command std::unordered_set memory_state{}; // index into memory_map for the various memory blocks that need applying before this command can run u64 tile_state{0}; // tile state for this command u64 display_buffer_state{0}; }; struct tile_info { using enable_bitcopy = std::true_type; u32 tile; u32 limit; u32 pitch; u32 format; }; struct zcull_info { using enable_bitcopy = std::true_type; u32 region; u32 size; u32 start; u32 offset; u32 status0; u32 status1; }; // bleh, may need to break these out, might be unnecessary to do both always struct tile_state { using enable_bitcopy = std::true_type; tile_info tiles[15]{}; zcull_info zculls[8]{}; }; struct buffer_state { using enable_bitcopy = std::true_type; u32 width{0}; u32 height{0}; u32 pitch{0}; u32 offset{0}; }; struct display_buffers_state { using enable_bitcopy = std::true_type; std::array buffers{}; u32 count{0}; }; u32 magic = c_fc_magic; u32 version = c_fc_version; u32 LE_format = std::endian::little == std::endian::native; // hashmap of holding various states for tile std::unordered_map tile_map; // hashmap of various memory 'changes' that can be applied to ps3 memory std::unordered_map memory_map; // hashmap of memory blocks that can be applied, this is split from above for size decrease std::unordered_map memory_data_map; // display buffer state map std::unordered_map display_buffers_map; // actual command queue to hold everything above std::vector replay_commands; // Initial registers state at the beginning of the capture rsx::rsx_state reg_state; void reset() { magic = c_fc_magic; version = c_fc_version; tile_map.clear(); memory_map.clear(); replay_commands.clear(); reg_state = method_registers; } }; class rsx_replay_thread : public cpu_thread { struct rsx_context { be_t user_addr; be_t dev_addr; be_t mem_handle; be_t context_id; be_t mem_addr; be_t dma_addr; be_t reports_addr; be_t driver_info; }; struct current_state { u64 tile_hash{0}; u64 display_buffer_hash{0}; frame_capture_data::display_buffers_state buffer_state{}; frame_capture_data::tile_state tile_state{}; }; u32 user_mem_addr{}; current_state cs{}; std::unique_ptr frame; public: rsx_replay_thread(std::unique_ptr&& frame_data) : cpu_thread(0) , frame(std::move(frame_data)) { } void cpu_task() override; private: be_t allocate_context(); std::vector alloc_write_fifo(be_t context_id) const; void apply_frame_state(be_t context_id, const frame_capture_data::replay_command& replay_cmd); }; }