diff --git a/ultramodern/include/ultramodern/config.hpp b/ultramodern/include/ultramodern/config.hpp index a8b99e2..b78d92f 100644 --- a/ultramodern/include/ultramodern/config.hpp +++ b/ultramodern/include/ultramodern/config.hpp @@ -5,71 +5,71 @@ #include "common/rt64_user_configuration.h" namespace ultramodern { - enum class Resolution { - Original, - Original2x, - Auto, - OptionCount - }; - enum class WindowMode { - Windowed, - Fullscreen, - OptionCount - }; - enum class HUDRatioMode { - Original, - Clamp16x9, - Full, - OptionCount - }; - enum class GraphicsApi { - Auto, - D3D12, - Vulkan, - OptionCount - }; + enum class Resolution { + Original, + Original2x, + Auto, + OptionCount + }; + enum class WindowMode { + Windowed, + Fullscreen, + OptionCount + }; + enum class HUDRatioMode { + Original, + Clamp16x9, + Full, + OptionCount + }; + enum class GraphicsApi { + Auto, + D3D12, + Vulkan, + OptionCount + }; - struct GraphicsConfig { - Resolution res_option; - WindowMode wm_option; - HUDRatioMode hr_option; - GraphicsApi api_option; - // TODO make custom enums that map to the RT64 ones to remove the direct dependency on RT64 in this file. - RT64::UserConfiguration::AspectRatio ar_option; - RT64::UserConfiguration::Antialiasing msaa_option; - RT64::UserConfiguration::RefreshRate rr_option; - int rr_manual_value; - int ds_option; - bool developer_mode; + struct GraphicsConfig { + Resolution res_option; + WindowMode wm_option; + HUDRatioMode hr_option; + GraphicsApi api_option; + // TODO make custom enums that map to the RT64 ones to remove the direct dependency on RT64 in this file. + RT64::UserConfiguration::AspectRatio ar_option; + RT64::UserConfiguration::Antialiasing msaa_option; + RT64::UserConfiguration::RefreshRate rr_option; + int rr_manual_value; + int ds_option; + bool developer_mode; - auto operator<=>(const GraphicsConfig& rhs) const = default; - }; + auto operator<=>(const GraphicsConfig& rhs) const = default; + }; - void set_graphics_config(const GraphicsConfig& config); - GraphicsConfig get_graphics_config(); + void set_graphics_config(const GraphicsConfig& config); + GraphicsConfig get_graphics_config(); - NLOHMANN_JSON_SERIALIZE_ENUM(ultramodern::Resolution, { - {ultramodern::Resolution::Original, "Original"}, - {ultramodern::Resolution::Original2x, "Original2x"}, - {ultramodern::Resolution::Auto, "Auto"}, - }); + NLOHMANN_JSON_SERIALIZE_ENUM(ultramodern::Resolution, { + {ultramodern::Resolution::Original, "Original"}, + {ultramodern::Resolution::Original2x, "Original2x"}, + {ultramodern::Resolution::Auto, "Auto"}, + }); - NLOHMANN_JSON_SERIALIZE_ENUM(ultramodern::WindowMode, { - {ultramodern::WindowMode::Windowed, "Windowed"}, - {ultramodern::WindowMode::Fullscreen, "Fullscreen"} - }); + NLOHMANN_JSON_SERIALIZE_ENUM(ultramodern::WindowMode, { + {ultramodern::WindowMode::Windowed, "Windowed"}, + {ultramodern::WindowMode::Fullscreen, "Fullscreen"} + }); - NLOHMANN_JSON_SERIALIZE_ENUM(ultramodern::HUDRatioMode, { - {ultramodern::HUDRatioMode::Original, "Original"}, - {ultramodern::HUDRatioMode::Clamp16x9, "Clamp16x9"}, - {ultramodern::HUDRatioMode::Full, "Full"}, - }); + NLOHMANN_JSON_SERIALIZE_ENUM(ultramodern::HUDRatioMode, { + {ultramodern::HUDRatioMode::Original, "Original"}, + {ultramodern::HUDRatioMode::Clamp16x9, "Clamp16x9"}, + {ultramodern::HUDRatioMode::Full, "Full"}, + }); - NLOHMANN_JSON_SERIALIZE_ENUM(ultramodern::GraphicsApi, { - {ultramodern::GraphicsApi::Auto, "Auto"}, - {ultramodern::GraphicsApi::D3D12, "D3D12"}, - {ultramodern::GraphicsApi::Vulkan, "Vulkan"}, - }); + NLOHMANN_JSON_SERIALIZE_ENUM(ultramodern::GraphicsApi, { + {ultramodern::GraphicsApi::Auto, "Auto"}, + {ultramodern::GraphicsApi::D3D12, "D3D12"}, + {ultramodern::GraphicsApi::Vulkan, "Vulkan"}, + }); }; #endif diff --git a/ultramodern/include/ultramodern/error_handling.hpp b/ultramodern/include/ultramodern/error_handling.hpp index 7632806..2eaf459 100644 --- a/ultramodern/include/ultramodern/error_handling.hpp +++ b/ultramodern/include/ultramodern/error_handling.hpp @@ -11,13 +11,13 @@ namespace ultramodern { * * The `msg` parameter is always non-`nullptr`. */ - message_box_t *message_box; + message_box_t* message_box; }; void set_callbacks(const callbacks_t& callbacks); void message_box(const char* msg); - } -} + } // namespace error_handling +} // namespace ultramodern #endif diff --git a/ultramodern/include/ultramodern/events.hpp b/ultramodern/include/ultramodern/events.hpp index dbb2ea5..1b39236 100644 --- a/ultramodern/include/ultramodern/events.hpp +++ b/ultramodern/include/ultramodern/events.hpp @@ -19,7 +19,7 @@ namespace ultramodern { }; void set_callbacks(const callbacks_t& callbacks); - } -} + } // namespace events +} // namespace ultramodern #endif diff --git a/ultramodern/include/ultramodern/rsp.hpp b/ultramodern/include/ultramodern/rsp.hpp index be1a85c..7118368 100644 --- a/ultramodern/include/ultramodern/rsp.hpp +++ b/ultramodern/include/ultramodern/rsp.hpp @@ -29,7 +29,7 @@ namespace ultramodern { void init(); bool run_task(RDRAM_ARG const OSTask* task); - }; + }; // namespace rsp } // namespace ultramodern #endif diff --git a/ultramodern/include/ultramodern/rt64_layer.h b/ultramodern/include/ultramodern/rt64_layer.h index 0928d06..39d0106 100644 --- a/ultramodern/include/ultramodern/rt64_layer.h +++ b/ultramodern/include/ultramodern/rt64_layer.h @@ -1,8 +1,8 @@ #ifndef __RT64_LAYER_H__ #define __RT64_LAYER_H__ -#include "ultramodern.hpp" #include "config.hpp" +#include "ultramodern.hpp" namespace RT64 { struct Application; @@ -19,30 +19,34 @@ namespace ultramodern { struct WindowHandle; struct RT64Context { - public: - ~RT64Context(); - RT64Context(uint8_t* rdram, WindowHandle window_handle, bool developer_mode); - bool valid() { return static_cast(app); } - RT64SetupResult get_setup_result() { return setup_result; } - - void update_config(const GraphicsConfig& old_config, const GraphicsConfig& new_config); - void enable_instant_present(); - void send_dl(const OSTask* task); - void update_screen(uint32_t vi_origin); - void shutdown(); - void set_dummy_vi(); - uint32_t get_display_framerate(); - void load_shader_cache(std::span cache_binary); - private: - RT64SetupResult setup_result; - std::unique_ptr app; + public: + ~RT64Context(); + RT64Context(uint8_t* rdram, WindowHandle window_handle, bool developer_mode); + bool valid() { + return static_cast(app); + } + RT64SetupResult get_setup_result() { + return setup_result; + } + + void update_config(const GraphicsConfig& old_config, const GraphicsConfig& new_config); + void enable_instant_present(); + void send_dl(const OSTask* task); + void update_screen(uint32_t vi_origin); + void shutdown(); + void set_dummy_vi(); + uint32_t get_display_framerate(); + void load_shader_cache(std::span cache_binary); + + private: + RT64SetupResult setup_result; + std::unique_ptr app; }; - + RT64::UserConfiguration::Antialiasing RT64MaxMSAA(); bool RT64SamplePositionsSupported(); -} +} // namespace ultramodern void set_rt64_hooks(); #endif - diff --git a/ultramodern/include/ultramodern/ultra64.h b/ultramodern/include/ultramodern/ultra64.h index 395cadb..20837e8 100644 --- a/ultramodern/include/ultramodern/ultra64.h +++ b/ultramodern/include/ultramodern/ultra64.h @@ -4,11 +4,11 @@ #include #ifdef __GNUC__ -#define UNUSED __attribute__((unused)) -#define ALIGNED(x) __attribute__((aligned(x))) +# define UNUSED __attribute__((unused)) +# define ALIGNED(x) __attribute__((aligned(x))) #else -#define UNUSED -#define ALIGNED(x) +# define UNUSED +# define ALIGNED(x) #endif typedef int64_t s64; @@ -23,60 +23,60 @@ typedef uint8_t u8; // TODO allow a compile-time flag to be set to switch between recomp mode and // fully native mode. #if 0 // For native compilation -# define PTR(x) x* -# define RDRAM_ARG -# define RDRAM_ARG1 -# define PASS_RDRAM -# define PASS_RDRAM1 -# define TO_PTR(type, var) var -# define GET_MEMBER(type, addr, member) (&addr->member) -# ifdef __cplusplus -# define NULLPTR nullptr -# endif +# define PTR(x) x* +# define RDRAM_ARG +# define RDRAM_ARG1 +# define PASS_RDRAM +# define PASS_RDRAM1 +# define TO_PTR(type, var) var +# define GET_MEMBER(type, addr, member) (&addr->member) +# ifdef __cplusplus +# define NULLPTR nullptr +# endif #else -# define PTR(x) int32_t -# define RDRAM_ARG uint8_t *rdram, -# define RDRAM_ARG1 uint8_t *rdram -# define PASS_RDRAM rdram, -# define PASS_RDRAM1 rdram -# define TO_PTR(type, var) ((type*)(&rdram[(uint64_t)var - 0xFFFFFFFF80000000])) -# define GET_MEMBER(type, addr, member) (addr + (intptr_t)&(((type*)nullptr)->member)) -# ifdef __cplusplus -# define NULLPTR (PTR(void))0 -# endif +# define PTR(x) int32_t +# define RDRAM_ARG uint8_t *rdram, +# define RDRAM_ARG1 uint8_t* rdram +# define PASS_RDRAM rdram, +# define PASS_RDRAM1 rdram +# define TO_PTR(type, var) ((type*)(&rdram[(uint64_t)var - 0xFFFFFFFF80000000])) +# define GET_MEMBER(type, addr, member) (addr + (intptr_t) & (((type*)nullptr)->member)) +# ifdef __cplusplus +# define NULLPTR (PTR(void))0 +# endif #endif #ifndef NULL -#define NULL (PTR(void) 0) +# define NULL (PTR(void) 0) #endif -#define OS_MESG_NOBLOCK 0 -#define OS_MESG_BLOCK 1 +#define OS_MESG_NOBLOCK 0 +#define OS_MESG_BLOCK 1 typedef s32 OSPri; typedef s32 OSId; -typedef u64 OSTime; - -#define OS_EVENT_SW1 0 /* CPU SW1 interrupt */ -#define OS_EVENT_SW2 1 /* CPU SW2 interrupt */ -#define OS_EVENT_CART 2 /* Cartridge interrupt: used by rmon */ -#define OS_EVENT_COUNTER 3 /* Counter int: used by VI/Timer Mgr */ -#define OS_EVENT_SP 4 /* SP task done interrupt */ -#define OS_EVENT_SI 5 /* SI (controller) interrupt */ -#define OS_EVENT_AI 6 /* AI interrupt */ -#define OS_EVENT_VI 7 /* VI interrupt: used by VI/Timer Mgr */ -#define OS_EVENT_PI 8 /* PI interrupt: used by PI Manager */ -#define OS_EVENT_DP 9 /* DP full sync interrupt */ -#define OS_EVENT_CPU_BREAK 10 /* CPU breakpoint: used by rmon */ -#define OS_EVENT_SP_BREAK 11 /* SP breakpoint: used by rmon */ -#define OS_EVENT_FAULT 12 /* CPU fault event: used by rmon */ -#define OS_EVENT_THREADSTATUS 13 /* CPU thread status: used by rmon */ -#define OS_EVENT_PRENMI 14 /* Pre NMI interrupt */ - -#define M_GFXTASK 1 -#define M_AUDTASK 2 -#define M_VIDTASK 3 +typedef u64 OSTime; + +#define OS_EVENT_SW1 0 /* CPU SW1 interrupt */ +#define OS_EVENT_SW2 1 /* CPU SW2 interrupt */ +#define OS_EVENT_CART 2 /* Cartridge interrupt: used by rmon */ +#define OS_EVENT_COUNTER 3 /* Counter int: used by VI/Timer Mgr */ +#define OS_EVENT_SP 4 /* SP task done interrupt */ +#define OS_EVENT_SI 5 /* SI (controller) interrupt */ +#define OS_EVENT_AI 6 /* AI interrupt */ +#define OS_EVENT_VI 7 /* VI interrupt: used by VI/Timer Mgr */ +#define OS_EVENT_PI 8 /* PI interrupt: used by PI Manager */ +#define OS_EVENT_DP 9 /* DP full sync interrupt */ +#define OS_EVENT_CPU_BREAK 10 /* CPU breakpoint: used by rmon */ +#define OS_EVENT_SP_BREAK 11 /* SP breakpoint: used by rmon */ +#define OS_EVENT_FAULT 12 /* CPU fault event: used by rmon */ +#define OS_EVENT_THREADSTATUS 13 /* CPU thread status: used by rmon */ +#define OS_EVENT_PRENMI 14 /* Pre NMI interrupt */ + +#define M_GFXTASK 1 +#define M_AUDTASK 2 +#define M_VIDTASK 3 #define M_NJPEGTASK 4 ///////////// @@ -112,7 +112,7 @@ typedef PTR(void) OSMesg; typedef struct OSMesgQueue { PTR(OSThread) blocked_on_recv; /* Linked list of threads blocked on receiving from this queue */ - PTR(OSThread) blocked_on_send; /* Linked list of threads blocked on sending to this queue */ + PTR(OSThread) blocked_on_send; /* Linked list of threads blocked on sending to this queue */ s32 validCount; /* Number of messages in the queue */ s32 first; /* Index of the first message in the ring buffer */ s32 msgCount; /* Size of message buffer */ @@ -122,29 +122,29 @@ typedef struct OSMesgQueue { // RSP typedef struct { - u32 type; - u32 flags; + u32 type; + u32 flags; PTR(u64) ucode_boot; - u32 ucode_boot_size; + u32 ucode_boot_size; PTR(u64) ucode; - u32 ucode_size; + u32 ucode_size; PTR(u64) ucode_data; - u32 ucode_data_size; + u32 ucode_data_size; PTR(u64) dram_stack; - u32 dram_stack_size; + u32 dram_stack_size; PTR(u64) output_buff; PTR(u64) output_buff_size; PTR(u64) data_ptr; - u32 data_size; + u32 data_size; PTR(u64) yield_data_ptr; - u32 yield_data_size; + u32 yield_data_size; } OSTask_s; typedef union { @@ -163,55 +163,55 @@ struct OSIoMesgHdr { }; struct OSIoMesg { - OSIoMesgHdr hdr; /* Message header */ - PTR(void) dramAddr; /* RDRAM buffer address (DMA) */ - u32 devAddr; /* Device buffer address (DMA) */ - u32 size; /* DMA transfer size in bytes */ - u32 piHandle; /* PI device handle */ + OSIoMesgHdr hdr; /* Message header */ + PTR(void) dramAddr; /* RDRAM buffer address (DMA) */ + u32 devAddr; /* Device buffer address (DMA) */ + u32 size; /* DMA transfer size in bytes */ + u32 piHandle; /* PI device handle */ }; struct OSPiHandle { - PTR(OSPiHandle_s) unused; /* point to next handle on the table */ + PTR(OSPiHandle_s) unused; /* point to next handle on the table */ // These four members reversed due to endianness - u8 relDuration; /* domain release duration */ - u8 pageSize; /* domain page size */ - u8 latency; /* domain latency */ - u8 type; /* DEVICE_TYPE_BULK for disk */ + u8 relDuration; /* domain release duration */ + u8 pageSize; /* domain page size */ + u8 latency; /* domain latency */ + u8 type; /* DEVICE_TYPE_BULK for disk */ // These three members reversed due to endianness - u16 padding; /* struct alignment padding */ - u8 domain; /* which domain */ - u8 pulse; /* domain pulse width */ - u32 baseAddress; /* Domain address */ - u32 speed; /* for roms only */ + u16 padding; /* struct alignment padding */ + u8 domain; /* which domain */ + u8 pulse; /* domain pulse width */ + u32 baseAddress; /* Domain address */ + u32 speed; /* for roms only */ /* The following are "private" elements" */ - u32 transferInfo[18]; /* for disk only */ + u32 transferInfo[18]; /* for disk only */ }; typedef struct { - u32 ctrl; - u32 width; - u32 burst; - u32 vSync; - u32 hSync; - u32 leap; - u32 hStart; - u32 xScale; - u32 vCurrent; + u32 ctrl; + u32 width; + u32 burst; + u32 vSync; + u32 hSync; + u32 leap; + u32 hStart; + u32 xScale; + u32 vCurrent; } OSViCommonRegs; typedef struct { - u32 origin; - u32 yScale; - u32 vStart; - u32 vBurst; - u32 vIntr; + u32 origin; + u32 yScale; + u32 vStart; + u32 vBurst; + u32 vIntr; } OSViFieldRegs; typedef struct { u8 padding[3]; u8 type; OSViCommonRegs comRegs; - OSViFieldRegs fldRegs[2]; + OSViFieldRegs fldRegs[2]; } OSViMode; /////////////// @@ -224,7 +224,7 @@ extern "C" { void osInitialize(void); -typedef void (thread_func_t)(PTR(void)); +typedef void(thread_func_t)(PTR(void)); void osCreateThread(RDRAM_ARG PTR(OSThread) t, OSId id, PTR(thread_func_t) entry, PTR(void) arg, PTR(void) sp, OSPri p); void osStartThread(RDRAM_ARG PTR(OSThread) t); diff --git a/ultramodern/include/ultramodern/ultramodern.hpp b/ultramodern/include/ultramodern/ultramodern.hpp index 547fba1..a23b58c 100644 --- a/ultramodern/include/ultramodern/ultramodern.hpp +++ b/ultramodern/include/ultramodern/ultramodern.hpp @@ -1,10 +1,10 @@ #ifndef __ultramodern_HPP__ #define __ultramodern_HPP__ -#include #include -#include #include +#include +#include #undef MOODYCAMEL_DELETE_FUNCTION #define MOODYCAMEL_DELETE_FUNCTION = delete @@ -12,17 +12,17 @@ #include "ultra64.h" #if defined(_WIN32) -# define WIN32_LEAN_AND_MEAN -# include +# define WIN32_LEAN_AND_MEAN +# include #elif defined(__ANDROID__) -# include "android/native_window.h" +# include "android/native_window.h" #elif defined(__linux__) -# include "X11/Xlib.h" -# undef None -# undef Status -# undef LockMask -# undef Always -# undef Success +# include "X11/Xlib.h" +# undef None +# undef Status +# undef LockMask +# undef Always +# undef Success #endif #include "ultramodern/error_handling.hpp" @@ -60,125 +60,128 @@ namespace ultramodern { }; #endif -// We need a place in rdram to hold the PI handles, so pick an address in extended rdram -constexpr uint32_t rdram_size = 1024 * 1024 * 16; // 16MB to give extra room for anything custom -constexpr int32_t cart_handle = 0x80800000; -constexpr int32_t drive_handle = (int32_t)(cart_handle + sizeof(OSPiHandle)); -constexpr int32_t flash_handle = (int32_t)(drive_handle + sizeof(OSPiHandle)); -constexpr uint32_t save_size = 1024 * 1024 / 8; // Maximum save size, 1Mbit for flash - -// Initialization. -void preinit(RDRAM_ARG WindowHandle window_handle); -void init_saving(RDRAM_ARG1); -void init_events(RDRAM_ARG WindowHandle window_handle); -void init_timers(RDRAM_ARG1); -void init_thread_cleanup(); - -// Thread queues. -constexpr PTR(PTR(OSThread)) running_queue = (PTR(PTR(OSThread)))-1; - -void thread_queue_insert(RDRAM_ARG PTR(PTR(OSThread)) queue, PTR(OSThread) toadd); -PTR(OSThread) thread_queue_pop(RDRAM_ARG PTR(PTR(OSThread)) queue); -bool thread_queue_remove(RDRAM_ARG PTR(PTR(OSThread)) queue_, PTR(OSThread) t_); -bool thread_queue_empty(RDRAM_ARG PTR(PTR(OSThread)) queue); -PTR(OSThread) thread_queue_peek(RDRAM_ARG PTR(PTR(OSThread)) queue); - -// Message queues. -void wait_for_external_message(RDRAM_ARG1); -void wait_for_external_message_timed(RDRAM_ARG1, u32 millis); - -// Thread scheduling. -void check_running_queue(RDRAM_ARG1); -void run_next_thread_and_wait(RDRAM_ARG1); -void resume_thread_and_wait(RDRAM_ARG OSThread* t); -void schedule_running_thread(RDRAM_ARG PTR(OSThread) t); -void cleanup_thread(UltraThreadContext* thread_context); -uint32_t permanent_thread_count(); -uint32_t temporary_thread_count(); -struct thread_terminated : std::exception {}; - -enum class ThreadPriority { - Low, - Normal, - High, - VeryHigh, - Critical -}; - -void set_native_thread_name(const std::string& name); -void set_native_thread_priority(ThreadPriority pri); -PTR(OSThread) this_thread(); -void set_main_thread(); -bool is_game_thread(); -void submit_rsp_task(RDRAM_ARG PTR(OSTask) task); -void send_si_message(RDRAM_ARG1); -uint32_t get_speed_multiplier(); - -// Time -std::chrono::high_resolution_clock::time_point get_start(); -std::chrono::high_resolution_clock::duration time_since_start(); -void measure_input_latency(); -void sleep_milliseconds(uint32_t millis); -void sleep_until(const std::chrono::high_resolution_clock::time_point& time_point); - -// Graphics -void get_window_size(uint32_t& width, uint32_t& height); -uint32_t get_target_framerate(uint32_t original); -uint32_t get_display_refresh_rate(); -void load_shader_cache(std::span cache_data); - -// Audio -void init_audio(); -void set_audio_frequency(uint32_t freq); -void queue_audio_buffer(RDRAM_ARG PTR(s16) audio_data, uint32_t byte_count); -uint32_t get_remaining_audio_bytes(); - -struct audio_callbacks_t { - using queue_samples_t = void(int16_t*, size_t); - using get_samples_remaining_t = size_t(); - using set_frequency_t = void(uint32_t); - queue_samples_t* queue_samples; - get_samples_remaining_t* get_frames_remaining; - set_frequency_t* set_frequency; -}; - -// TODO: These functions are currently called by librecomp, but will get called by ultramodern in the future -// Input -struct input_callbacks_t { - using poll_input_t = void(void); - using get_input_t = void(uint16_t*, float*, float*); - using set_rumble_t = void(bool); - poll_input_t* poll_input; - get_input_t* get_input; - set_rumble_t* set_rumble; -}; + // We need a place in rdram to hold the PI handles, so pick an address in extended rdram + constexpr uint32_t rdram_size = 1024 * 1024 * 16; // 16MB to give extra room for anything custom + constexpr int32_t cart_handle = 0x80800000; + constexpr int32_t drive_handle = (int32_t)(cart_handle + sizeof(OSPiHandle)); + constexpr int32_t flash_handle = (int32_t)(drive_handle + sizeof(OSPiHandle)); + constexpr uint32_t save_size = 1024 * 1024 / 8; // Maximum save size, 1Mbit for flash + + // Initialization. + void preinit(RDRAM_ARG WindowHandle window_handle); + void init_saving(RDRAM_ARG1); + void init_events(RDRAM_ARG WindowHandle window_handle); + void init_timers(RDRAM_ARG1); + void init_thread_cleanup(); + + // Thread queues. + constexpr PTR(PTR(OSThread)) running_queue = (PTR(PTR(OSThread)))-1; + + void thread_queue_insert(RDRAM_ARG PTR(PTR(OSThread)) queue, PTR(OSThread) toadd); + PTR(OSThread) thread_queue_pop(RDRAM_ARG PTR(PTR(OSThread)) queue); + bool thread_queue_remove(RDRAM_ARG PTR(PTR(OSThread)) queue_, PTR(OSThread) t_); + bool thread_queue_empty(RDRAM_ARG PTR(PTR(OSThread)) queue); + PTR(OSThread) thread_queue_peek(RDRAM_ARG PTR(PTR(OSThread)) queue); + + // Message queues. + void wait_for_external_message(RDRAM_ARG1); + void wait_for_external_message_timed(RDRAM_ARG1, u32 millis); + + // Thread scheduling. + void check_running_queue(RDRAM_ARG1); + void run_next_thread_and_wait(RDRAM_ARG1); + void resume_thread_and_wait(RDRAM_ARG OSThread* t); + void schedule_running_thread(RDRAM_ARG PTR(OSThread) t); + void cleanup_thread(UltraThreadContext* thread_context); + uint32_t permanent_thread_count(); + uint32_t temporary_thread_count(); + struct thread_terminated : std::exception {}; + + enum class ThreadPriority { + Low, + Normal, + High, + VeryHigh, + Critical + }; -// TODO: Most of the members of this struct are not used by ultramodern. Should we move them to librecomp instead? -struct gfx_callbacks_t { - using gfx_data_t = void*; - using create_gfx_t = gfx_data_t(); - using create_window_t = WindowHandle(gfx_data_t); - using update_gfx_t = void(gfx_data_t); + void set_native_thread_name(const std::string& name); + void set_native_thread_priority(ThreadPriority pri); + PTR(OSThread) this_thread(); + void set_main_thread(); + bool is_game_thread(); + void submit_rsp_task(RDRAM_ARG PTR(OSTask) task); + void send_si_message(RDRAM_ARG1); + uint32_t get_speed_multiplier(); + + // Time + std::chrono::high_resolution_clock::time_point get_start(); + std::chrono::high_resolution_clock::duration time_since_start(); + void measure_input_latency(); + void sleep_milliseconds(uint32_t millis); + void sleep_until(const std::chrono::high_resolution_clock::time_point& time_point); + + // Graphics + void get_window_size(uint32_t& width, uint32_t& height); + uint32_t get_target_framerate(uint32_t original); + uint32_t get_display_refresh_rate(); + void load_shader_cache(std::span cache_data); + + // Audio + void init_audio(); + void set_audio_frequency(uint32_t freq); + void queue_audio_buffer(RDRAM_ARG PTR(s16) audio_data, uint32_t byte_count); + uint32_t get_remaining_audio_bytes(); + + struct audio_callbacks_t { + using queue_samples_t = void(int16_t*, size_t); + using get_samples_remaining_t = size_t(); + using set_frequency_t = void(uint32_t); + queue_samples_t* queue_samples; + get_samples_remaining_t* get_frames_remaining; + set_frequency_t* set_frequency; + }; - create_gfx_t* create_gfx; - create_window_t* create_window; - update_gfx_t* update_gfx; -}; + // TODO: These functions are currently called by librecomp, but will get called by ultramodern in the future + // Input + struct input_callbacks_t { + using poll_input_t = void(void); + using get_input_t = void(uint16_t*, float*, float*); + using set_rumble_t = void(bool); + poll_input_t* poll_input; + get_input_t* get_input; + set_rumble_t* set_rumble; + }; -bool is_game_started(); -void quit(); -void join_event_threads(); -void join_thread_cleaner_thread(); -void join_saving_thread(); + // TODO: Most of the members of this struct are not used by ultramodern. Should we move them to librecomp instead? + struct gfx_callbacks_t { + using gfx_data_t = void*; + using create_gfx_t = gfx_data_t(); + using create_window_t = WindowHandle(gfx_data_t); + using update_gfx_t = void(gfx_data_t); -void set_audio_callbacks(const audio_callbacks_t& callbacks); + create_gfx_t* create_gfx; + create_window_t* create_window; + update_gfx_t* update_gfx; + }; -/** - * Register all the callbacks used by `ultramodern`, most of them being optional. - * - * It must be called only once and it must be called before `ultramodern::preinit`. - */ -void set_callbacks(const rsp::callbacks_t& rsp_callbacks, const audio_callbacks_t& audio_callbacks, const input_callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks, const events::callbacks_t& events_callbacks, const error_handling::callbacks_t& error_handling_callbacks); + bool is_game_started(); + void quit(); + void join_event_threads(); + void join_thread_cleaner_thread(); + void join_saving_thread(); + + void set_audio_callbacks(const audio_callbacks_t& callbacks); + + /** + * Register all the callbacks used by `ultramodern`, most of them being optional. + * + * It must be called only once and it must be called before `ultramodern::preinit`. + */ + void set_callbacks( + const rsp::callbacks_t& rsp_callbacks, const audio_callbacks_t& audio_callbacks, const input_callbacks_t& input_callbacks, + const gfx_callbacks_t& gfx_callbacks, const events::callbacks_t& events_callbacks, + const error_handling::callbacks_t& error_handling_callbacks); } // namespace ultramodern #define MIN(a, b) ((a) < (b) ? (a) : (b)) diff --git a/ultramodern/src/audio.cpp b/ultramodern/src/audio.cpp index d3ae2e7..6e38803 100644 --- a/ultramodern/src/audio.cpp +++ b/ultramodern/src/audio.cpp @@ -36,7 +36,7 @@ void ultramodern::queue_audio_buffer(RDRAM_ARG PTR(int16_t) audio_data_, uint32_ } // For SDL2 -//uint32_t buffer_offset_frames = 1; +// uint32_t buffer_offset_frames = 1; // For Godot float buffer_offset_frames = 0.5f; @@ -52,16 +52,16 @@ uint32_t ultramodern::get_remaining_audio_bytes() { else { buffered_byte_count = 100; } - // Adjust the reported count to be some number of refreshes in the future, which helps ensure that - // there are enough samples even if the audio thread experiences a small amount of lag. This prevents - // audio popping on games that use the buffered audio byte count to determine how many samples - // to generate. - uint32_t samples_per_vi = (sample_rate / 60); - if (buffered_byte_count > static_cast(buffer_offset_frames * sizeof(int16_t) * samples_per_vi)) { - buffered_byte_count -= static_cast(buffer_offset_frames * sizeof(int16_t) * samples_per_vi); - } - else { - buffered_byte_count = 0; - } - return buffered_byte_count; + // Adjust the reported count to be some number of refreshes in the future, which helps ensure that + // there are enough samples even if the audio thread experiences a small amount of lag. This prevents + // audio popping on games that use the buffered audio byte count to determine how many samples + // to generate. + uint32_t samples_per_vi = (sample_rate / 60); + if (buffered_byte_count > static_cast(buffer_offset_frames * sizeof(int16_t) * samples_per_vi)) { + buffered_byte_count -= static_cast(buffer_offset_frames * sizeof(int16_t) * samples_per_vi); + } + else { + buffered_byte_count = 0; + } + return buffered_byte_count; } diff --git a/ultramodern/src/events.cpp b/ultramodern/src/events.cpp index 7fba7b6..572ecbf 100644 --- a/ultramodern/src/events.cpp +++ b/ultramodern/src/events.cpp @@ -1,21 +1,21 @@ -#include #include #include #include -#include -#include -#include +#include #include #include -#include +#include +#include +#include +#include #include "blockingconcurrentqueue.h" -#include "ultra64.h" -#include "ultramodern/ultramodern.hpp" -#include "config.hpp" -#include "rt64_layer.h" +#include "ultramodern/config.hpp" #include "ultramodern/rsp.hpp" +#include "ultramodern/rt64_layer.h" +#include "ultramodern/ultra64.h" +#include "ultramodern/ultramodern.hpp" static ultramodern::events::callbacks_t events_callbacks{}; @@ -31,8 +31,7 @@ struct SwapBuffersAction { uint32_t origin; }; -struct UpdateConfigAction { -}; +struct UpdateConfigAction {}; struct LoadShaderCacheAction { std::span data; @@ -107,7 +106,6 @@ extern "C" void osViSetEvent(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, u32 ret uint64_t total_vis = 0; - extern std::atomic_bool exited; void set_dummy_vi(); @@ -124,15 +122,16 @@ void vi_thread_func() { while (!exited) { // Determine the next VI time (more accurate than adding 16ms each VI interrupt) auto next = ultramodern::get_start() + (total_vis * 1000000us) / (60 * ultramodern::get_speed_multiplier()); - //if (next > std::chrono::high_resolution_clock::now()) { - // printf("Sleeping for %" PRIu64 " us to get from %" PRIu64 " us to %" PRIu64 " us \n", - // (next - std::chrono::high_resolution_clock::now()) / 1us, - // (std::chrono::high_resolution_clock::now() - events_context.start) / 1us, - // (next - events_context.start) / 1us); - //} else { - // printf("No need to sleep\n"); - //} - // Detect if there's more than a second to wait and wait a fixed amount instead for the next VI if so, as that usually means the system clock went back in time. + // if (next > std::chrono::high_resolution_clock::now()) { + // printf("Sleeping for %" PRIu64 " us to get from %" PRIu64 " us to %" PRIu64 " us \n", + // (next - std::chrono::high_resolution_clock::now()) / 1us, + // (std::chrono::high_resolution_clock::now() - events_context.start) / 1us, + // (next - events_context.start) / 1us); + // } else { + // printf("No need to sleep\n"); + // } + // Detect if there's more than a second to wait and wait a fixed amount instead for the next VI if so, as that usually means the + // system clock went back in time. if (std::chrono::floor(next - std::chrono::high_resolution_clock::now()) > 1s) { // printf("Skipping the next VI wait\n"); next = std::chrono::high_resolution_clock::now(); @@ -141,7 +140,7 @@ void vi_thread_func() { // Calculate how many VIs have passed uint64_t new_total_vis = (ultramodern::time_since_start() * (60 * ultramodern::get_speed_multiplier()) / 1000ms) + 1; if (new_total_vis > total_vis + 1) { - //printf("Skipped % " PRId64 " frames in VI interupt thread!\n", new_total_vis - total_vis - 1); + // printf("Skipped % " PRId64 " frames in VI interupt thread!\n", new_total_vis - total_vis - 1); } total_vis = new_total_vis; @@ -156,7 +155,7 @@ void vi_thread_func() { if (ultramodern::is_game_started()) { if (events_context.vi.mq != NULLPTR) { if (osSendMesg(PASS_RDRAM events_context.vi.mq, events_context.vi.msg, OS_MESG_NOBLOCK) == -1) { - //printf("Game skipped a VI frame!\n"); + // printf("Game skipped a VI frame!\n"); } } } @@ -174,7 +173,7 @@ void vi_thread_func() { } if (events_context.ai.mq != NULLPTR) { if (osSendMesg(PASS_RDRAM events_context.ai.mq, events_context.ai.msg, OS_MESG_NOBLOCK) == -1) { - //printf("Game skipped a AI frame!\n"); + // printf("Game skipped a AI frame!\n"); } } } @@ -213,15 +212,14 @@ void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_r return; } - if (!ultramodern::rsp::run_task(PASS_RDRAM task)) { fprintf(stderr, "Failed to execute task type: %" PRIu32 "\n", task->t.type); assert(false); -# ifdef __APPLE__ +#ifdef __APPLE__ std::_Exit(EXIT_FAILURE); -# else +#else std::quick_exit(EXIT_FAILURE); -# endif +#endif } // Tell the game that the RSP has completed @@ -261,7 +259,7 @@ uint32_t ultramodern::get_display_refresh_rate() { } void ultramodern::load_shader_cache(std::span cache_data) { - events_context.action_queue.enqueue(LoadShaderCacheAction{cache_data}); + events_context.action_queue.enqueue(LoadShaderCacheAction{ cache_data }); } std::atomic rt64_setup_result = ultramodern::RT64SetupResult::Success; @@ -275,7 +273,7 @@ void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_re ultramodern::GraphicsConfig old_config = ultramodern::get_graphics_config(); - ultramodern::RT64Context rt64{rdram, window_handle, cur_config.load().developer_mode}; + ultramodern::RT64Context rt64{ rdram, window_handle, cur_config.load().developer_mode }; if (!rt64.valid()) { // TODO move recomp code out of ultramodern. @@ -316,7 +314,9 @@ void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_re rt64.send_dl(&task_action->task); auto rt64_end = std::chrono::high_resolution_clock::now(); dp_complete(); +#if 0 // printf("RT64 ProcessDList time: %d us\n", static_cast(std::chrono::duration_cast(rt64_end - rt64_start).count())); +#endif } else if (const auto* swap_action = std::get_if(&action)) { events_context.vi.current_buffer = events_context.vi.next_buffer; @@ -377,7 +377,8 @@ void set_dummy_vi() { extern "C" void osViSwapBuffer(RDRAM_ARG PTR(void) frameBufPtr) { if (vi_black) { VI_H_START_REG = 0; - } else { + } + else { VI_H_START_REG = hstart; } events_context.vi.next_buffer = frameBufPtr; @@ -404,29 +405,29 @@ extern "C" void osViSetMode(RDRAM_ARG PTR(OSViMode) mode_) { VI_INTR_REG = mode->fldRegs[0].vIntr; } -#define VI_CTRL_TYPE_16 0x00002 -#define VI_CTRL_TYPE_32 0x00003 -#define VI_CTRL_GAMMA_DITHER_ON 0x00004 -#define VI_CTRL_GAMMA_ON 0x00008 -#define VI_CTRL_DIVOT_ON 0x00010 -#define VI_CTRL_SERRATE_ON 0x00040 -#define VI_CTRL_ANTIALIAS_MASK 0x00300 -#define VI_CTRL_ANTIALIAS_MODE_1 0x00100 -#define VI_CTRL_ANTIALIAS_MODE_2 0x00200 -#define VI_CTRL_ANTIALIAS_MODE_3 0x00300 -#define VI_CTRL_PIXEL_ADV_MASK 0x01000 -#define VI_CTRL_PIXEL_ADV_1 0x01000 -#define VI_CTRL_PIXEL_ADV_2 0x02000 -#define VI_CTRL_PIXEL_ADV_3 0x03000 -#define VI_CTRL_DITHER_FILTER_ON 0x10000 - -#define OS_VI_GAMMA_ON 0x0001 -#define OS_VI_GAMMA_OFF 0x0002 -#define OS_VI_GAMMA_DITHER_ON 0x0004 -#define OS_VI_GAMMA_DITHER_OFF 0x0008 -#define OS_VI_DIVOT_ON 0x0010 -#define OS_VI_DIVOT_OFF 0x0020 -#define OS_VI_DITHER_FILTER_ON 0x0040 +#define VI_CTRL_TYPE_16 0x00002 +#define VI_CTRL_TYPE_32 0x00003 +#define VI_CTRL_GAMMA_DITHER_ON 0x00004 +#define VI_CTRL_GAMMA_ON 0x00008 +#define VI_CTRL_DIVOT_ON 0x00010 +#define VI_CTRL_SERRATE_ON 0x00040 +#define VI_CTRL_ANTIALIAS_MASK 0x00300 +#define VI_CTRL_ANTIALIAS_MODE_1 0x00100 +#define VI_CTRL_ANTIALIAS_MODE_2 0x00200 +#define VI_CTRL_ANTIALIAS_MODE_3 0x00300 +#define VI_CTRL_PIXEL_ADV_MASK 0x01000 +#define VI_CTRL_PIXEL_ADV_1 0x01000 +#define VI_CTRL_PIXEL_ADV_2 0x02000 +#define VI_CTRL_PIXEL_ADV_3 0x03000 +#define VI_CTRL_DITHER_FILTER_ON 0x10000 + +#define OS_VI_GAMMA_ON 0x0001 +#define OS_VI_GAMMA_OFF 0x0002 +#define OS_VI_GAMMA_DITHER_ON 0x0004 +#define OS_VI_GAMMA_DITHER_OFF 0x0008 +#define OS_VI_DIVOT_ON 0x0010 +#define OS_VI_DIVOT_OFF 0x0020 +#define OS_VI_DITHER_FILTER_ON 0x0040 #define OS_VI_DITHER_FILTER_OFF 0x0080 extern "C" void osViSetSpecialFeatures(uint32_t func) { @@ -461,7 +462,7 @@ extern "C" void osViSetSpecialFeatures(uint32_t func) { if ((func & OS_VI_DITHER_FILTER_OFF) != 0) { VI_STATUS_REG &= ~VI_CTRL_DITHER_FILTER_ON; - //VI_STATUS_REG |= __osViNext->modep->comRegs.ctrl & VI_CTRL_ANTIALIAS_MASK; + // VI_STATUS_REG |= __osViNext->modep->comRegs.ctrl & VI_CTRL_ANTIALIAS_MASK; } } @@ -555,7 +556,9 @@ void ultramodern::init_events(RDRAM_ARG ultramodern::WindowHandle window_handle) show_rt64_error("Failed to load dynamic libraries. Make sure the DLLs are next to the recomp executable."); break; case ultramodern::RT64SetupResult::InvalidGraphicsAPI: - show_rt64_error(get_graphics_api_name(cur_config.load().api_option) + " is not supported on this platform. Please select a different graphics API."); + show_rt64_error( + get_graphics_api_name(cur_config.load().api_option) + + " is not supported on this platform. Please select a different graphics API."); break; case ultramodern::RT64SetupResult::GraphicsAPINotFound: show_rt64_error("Unable to initialize " + get_graphics_api_name(cur_config.load().api_option) + "." + driver_os_suffix); diff --git a/ultramodern/src/mesgqueue.cpp b/ultramodern/src/mesgqueue.cpp index b792bcd..85a2be7 100644 --- a/ultramodern/src/mesgqueue.cpp +++ b/ultramodern/src/mesgqueue.cpp @@ -11,10 +11,10 @@ struct QueuedMessage { bool jam; }; -static moodycamel::BlockingConcurrentQueue external_messages {}; +static moodycamel::BlockingConcurrentQueue external_messages{}; void enqueue_external_message(PTR(OSMesgQueue) mq, OSMesg msg, bool jam) { - external_messages.enqueue({mq, msg, jam}); + external_messages.enqueue({ mq, msg, jam }); } bool do_send(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, bool jam, bool block); @@ -34,13 +34,13 @@ void ultramodern::wait_for_external_message(RDRAM_ARG1) { void ultramodern::wait_for_external_message_timed(RDRAM_ARG1, u32 millis) { QueuedMessage to_send; - if (external_messages.wait_dequeue_timed(to_send, std::chrono::milliseconds{millis})) { + if (external_messages.wait_dequeue_timed(to_send, std::chrono::milliseconds{ millis })) { do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false); } } extern "C" void osCreateMesgQueue(RDRAM_ARG PTR(OSMesgQueue) mq_, PTR(OSMesg) msg, s32 count) { - OSMesgQueue *mq = TO_PTR(OSMesgQueue, mq_); + OSMesgQueue* mq = TO_PTR(OSMesgQueue, mq_); mq->blocked_on_recv = NULLPTR; mq->blocked_on_send = NULLPTR; mq->msgCount = count; @@ -49,11 +49,11 @@ extern "C" void osCreateMesgQueue(RDRAM_ARG PTR(OSMesgQueue) mq_, PTR(OSMesg) ms mq->first = 0; } -s32 MQ_GET_COUNT(OSMesgQueue *mq) { +s32 MQ_GET_COUNT(OSMesgQueue* mq) { return mq->validCount; } -s32 MQ_IS_EMPTY(OSMesgQueue *mq) { +s32 MQ_IS_EMPTY(OSMesgQueue* mq) { return mq->validCount == 0; } @@ -77,7 +77,7 @@ bool do_send(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, bool jam, bool block) { ultramodern::run_next_thread_and_wait(PASS_RDRAM1); } } - + if (jam) { // Jams insert at the head of the message queue's buffer. mq->first = (mq->first + mq->msgCount - 1) % mq->msgCount; @@ -96,7 +96,7 @@ bool do_send(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, bool jam, bool block) { if (!ultramodern::thread_queue_empty(PASS_RDRAM blocked_queue)) { ultramodern::schedule_running_thread(PASS_RDRAM ultramodern::thread_queue_pop(PASS_RDRAM blocked_queue)); } - + return true; } @@ -107,7 +107,8 @@ bool do_recv(RDRAM_ARG PTR(OSMesgQueue) mq_, PTR(OSMesg) msg_, bool block) { if (MQ_IS_EMPTY(mq)) { return false; } - } else { + } + else { // Otherwise, yield this thread in a loop until the queue is no longer full while (MQ_IS_EMPTY(mq)) { debug_printf("[Message Queue] Thread %d is blocked on receive\n", TO_PTR(OSThread, ultramodern::this_thread())->id); @@ -119,7 +120,7 @@ bool do_recv(RDRAM_ARG PTR(OSMesgQueue) mq_, PTR(OSMesg) msg_, bool block) { if (msg_ != NULLPTR) { *TO_PTR(OSMesg, msg_) = TO_PTR(OSMesg, mq->msg)[mq->first]; } - + mq->first = (mq->first + 1) % mq->msgCount; mq->validCount--; @@ -133,21 +134,21 @@ bool do_recv(RDRAM_ARG PTR(OSMesgQueue) mq_, PTR(OSMesg) msg_, bool block) { } extern "C" s32 osSendMesg(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, s32 flags) { - OSMesgQueue *mq = TO_PTR(OSMesgQueue, mq_); + OSMesgQueue* mq = TO_PTR(OSMesgQueue, mq_); bool jam = false; - + // Don't directly send to the message queue if this isn't a game thread to avoid contention. if (!ultramodern::is_game_thread()) { enqueue_external_message(mq_, msg, jam); return 0; } - + // Handle any messages that have been received from an external thread. dequeue_external_messages(PASS_RDRAM1); // Try to send the message. bool sent = do_send(PASS_RDRAM mq_, msg, jam, flags == OS_MESG_BLOCK); - + // Check the queue to see if this thread should swap execution to another. ultramodern::check_running_queue(PASS_RDRAM1); @@ -155,21 +156,21 @@ extern "C" s32 osSendMesg(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, s32 flags) } extern "C" s32 osJamMesg(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, s32 flags) { - OSMesgQueue *mq = TO_PTR(OSMesgQueue, mq_); + OSMesgQueue* mq = TO_PTR(OSMesgQueue, mq_); bool jam = true; - + // Don't directly send to the message queue if this isn't a game thread to avoid contention. if (!ultramodern::is_game_thread()) { enqueue_external_message(mq_, msg, jam); return 0; } - + // Handle any messages that have been received from an external thread. dequeue_external_messages(PASS_RDRAM1); // Try to send the message. bool sent = do_send(PASS_RDRAM mq_, msg, jam, flags == OS_MESG_BLOCK); - + // Check the queue to see if this thread should swap execution to another. ultramodern::check_running_queue(PASS_RDRAM1); @@ -177,16 +178,16 @@ extern "C" s32 osJamMesg(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, s32 flags) } extern "C" s32 osRecvMesg(RDRAM_ARG PTR(OSMesgQueue) mq_, PTR(OSMesg) msg_, s32 flags) { - OSMesgQueue *mq = TO_PTR(OSMesgQueue, mq_); - + OSMesgQueue* mq = TO_PTR(OSMesgQueue, mq_); + assert(ultramodern::is_game_thread() && "RecvMesg not allowed outside of game threads."); - + // Handle any messages that have been received from an external thread. dequeue_external_messages(PASS_RDRAM1); // Try to receive a message. bool received = do_recv(PASS_RDRAM mq_, msg_, flags == OS_MESG_BLOCK); - + // Check the queue to see if this thread should swap execution to another. ultramodern::check_running_queue(PASS_RDRAM1); diff --git a/ultramodern/src/misc_ultra.cpp b/ultramodern/src/misc_ultra.cpp index c01b9f7..f0f7c2d 100644 --- a/ultramodern/src/misc_ultra.cpp +++ b/ultramodern/src/misc_ultra.cpp @@ -1,10 +1,10 @@ #include "ultra64.h" -#define K0BASE 0x80000000 -#define K1BASE 0xA0000000 -#define K2BASE 0xC0000000 -#define IS_KSEG0(x) ((u32)(x) >= K0BASE && (u32)(x) < K1BASE) -#define IS_KSEG1(x) ((u32)(x) >= K1BASE && (u32)(x) < K2BASE) +#define K0BASE 0x80000000 +#define K1BASE 0xA0000000 +#define K2BASE 0xC0000000 +#define IS_KSEG0(x) ((u32)(x) >= K0BASE && (u32)(x) < K1BASE) +#define IS_KSEG1(x) ((u32)(x) >= K1BASE && (u32)(x) < K2BASE) #define K0_TO_PHYS(x) ((u32)(x)&0x1FFFFFFF) #define K1_TO_PHYS(x) ((u32)(x)&0x1FFFFFFF) @@ -12,11 +12,12 @@ u32 osVirtualToPhysical(PTR(void) addr) { uintptr_t addr_val = (uintptr_t)addr; if (IS_KSEG0(addr_val)) { return K0_TO_PHYS(addr_val); - } else if (IS_KSEG1(addr_val)) { + } + else if (IS_KSEG1(addr_val)) { return K1_TO_PHYS(addr_val); - } else { + } + else { // TODO handle TLB mappings return (u32)addr_val; } } - diff --git a/ultramodern/src/port_main.c b/ultramodern/src/port_main.c index 968b4d3..a433a58 100644 --- a/ultramodern/src/port_main.c +++ b/ultramodern/src/port_main.c @@ -1,10 +1,10 @@ #if 0 -#include -#include -#include "ultra64.h" +# include "ultra64.h" +# include +# include -#define THREAD_STACK_SIZE 0x1000 +# define THREAD_STACK_SIZE 0x1000 u8 idle_stack[THREAD_STACK_SIZE] ALIGNED(16); u8 main_stack[THREAD_STACK_SIZE] ALIGNED(16); diff --git a/ultramodern/src/rsp.cpp b/ultramodern/src/rsp.cpp index 1594304..d7c8530 100644 --- a/ultramodern/src/rsp.cpp +++ b/ultramodern/src/rsp.cpp @@ -3,7 +3,7 @@ #include "ultramodern/rsp.hpp" -static ultramodern::rsp::callbacks_t rsp_callbacks {}; +static ultramodern::rsp::callbacks_t rsp_callbacks{}; void ultramodern::rsp::set_callbacks(const callbacks_t& callbacks) { rsp_callbacks = callbacks; diff --git a/ultramodern/src/rt64_layer.cpp b/ultramodern/src/rt64_layer.cpp index 45290b1..7bd3924 100644 --- a/ultramodern/src/rt64_layer.cpp +++ b/ultramodern/src/rt64_layer.cpp @@ -1,6 +1,5 @@ -#include #include -// #include +#include #define HLSL_CPU #include "hle/rt64_application.h" @@ -42,7 +41,6 @@ unsigned int VI_X_SCALE_REG = 0; unsigned int VI_Y_SCALE_REG = 0; void dummy_check_interrupts() { - } RT64::UserConfiguration::Antialiasing compute_max_supported_aa(RT64::RenderSampleCounts bits) { @@ -84,7 +82,7 @@ void set_application_user_config(RT64::Application* application, const ultramode break; case ultramodern::HUDRatioMode::Clamp16x9: application->userConfig.extAspectRatio = RT64::UserConfiguration::AspectRatio::Manual; - application->userConfig.extAspectTarget = 16.0/9.0; + application->userConfig.extAspectTarget = 16.0 / 9.0; break; case ultramodern::HUDRatioMode::Full: application->userConfig.extAspectRatio = RT64::UserConfiguration::AspectRatio::Expand; @@ -270,11 +268,11 @@ uint32_t ultramodern::RT64Context::get_display_framerate() { void ultramodern::RT64Context::load_shader_cache(std::span cache_binary) { // TODO figure out how to avoid a copy here. - std::istringstream cache_stream{std::string{cache_binary.data(), cache_binary.size()}}; + std::istringstream cache_stream{ std::string{ cache_binary.data(), cache_binary.size() } }; if (!app->rasterShaderCache->loadOfflineList(cache_stream)) { - printf("Failed to preload shader cache!\n"); - assert(false); + printf("Failed to preload shader cache!\n"); + assert(false); } } diff --git a/ultramodern/src/scheduling.cpp b/ultramodern/src/scheduling.cpp index 4af1b98..4f0780b 100644 --- a/ultramodern/src/scheduling.cpp +++ b/ultramodern/src/scheduling.cpp @@ -6,7 +6,7 @@ void ultramodern::schedule_running_thread(RDRAM_ARG PTR(OSThread) t_) { TO_PTR(OSThread, t_)->state = OSThreadState::QUEUED; } -void swap_to_thread(RDRAM_ARG OSThread *to) { +void swap_to_thread(RDRAM_ARG OSThread* to) { debug_printf("[Scheduling] Thread %d giving execution to thread %d\n", TO_PTR(OSThread, ultramodern::this_thread())->id, to->id); // Insert this thread in the running queue. ultramodern::thread_queue_insert(PASS_RDRAM ultramodern::running_queue, ultramodern::this_thread()); diff --git a/ultramodern/src/task_win32.cpp b/ultramodern/src/task_win32.cpp index c3e511c..68a1ae4 100644 --- a/ultramodern/src/task_win32.cpp +++ b/ultramodern/src/task_win32.cpp @@ -1,9 +1,9 @@ #ifdef _WIN32 -#include +# include -#include "ultra64.h" -#include "ultramodern.hpp" +# include "ultra64.h" +# include "ultramodern.hpp" extern "C" unsigned int sleep(unsigned int seconds) { Sleep(seconds * 1000); diff --git a/ultramodern/src/threadqueue.cpp b/ultramodern/src/threadqueue.cpp index 5869811..d205cc4 100644 --- a/ultramodern/src/threadqueue.cpp +++ b/ultramodern/src/threadqueue.cpp @@ -13,7 +13,7 @@ static PTR(OSThread)* queue_to_ptr(RDRAM_ARG PTR(PTR(OSThread)) queue) { void ultramodern::thread_queue_insert(RDRAM_ARG PTR(PTR(OSThread)) queue_, PTR(OSThread) toadd_) { PTR(OSThread)* cur = queue_to_ptr(PASS_RDRAM queue_); - OSThread* toadd = TO_PTR(OSThread, toadd_); + OSThread* toadd = TO_PTR(OSThread, toadd_); debug_printf("[Thread Queue] Inserting thread %d into queue 0x%08X\n", toadd->id, (uintptr_t)queue_); while (*cur && TO_PTR(OSThread, *cur)->priority > toadd->priority) { cur = &TO_PTR(OSThread, *cur)->next; diff --git a/ultramodern/src/threads.cpp b/ultramodern/src/threads.cpp index fd59338..d53f0a9 100644 --- a/ultramodern/src/threads.cpp +++ b/ultramodern/src/threads.cpp @@ -1,15 +1,15 @@ -#include -#include #include +#include #include +#include +#include "blockingconcurrentqueue.h" #include "ultra64.h" #include "ultramodern.hpp" -#include "blockingconcurrentqueue.h" // Native APIs only used to set thread names for easier debugging #ifdef _WIN32 -#include +# include #endif extern "C" void bootproc(); @@ -39,18 +39,15 @@ int main(int argc, char** argv) { #if 1 void run_thread_function(uint8_t* rdram, uint64_t addr, uint64_t sp, uint64_t arg); #else -#define run_thread_function(func, sp, arg) func(arg) +# define run_thread_function(func, sp, arg) func(arg) #endif #if defined(_WIN32) void ultramodern::set_native_thread_name(const std::string& name) { - std::wstring wname{name.begin(), name.end()}; + std::wstring wname{ name.begin(), name.end() }; HRESULT r; - r = SetThreadDescription( - GetCurrentThread(), - wname.c_str() - ); + r = SetThreadDescription(GetCurrentThread(), wname.c_str()); } void ultramodern::set_native_thread_priority(ThreadPriority pri) { @@ -116,7 +113,8 @@ void ultramodern::set_native_thread_name(const std::string& name) { pthread_setname_np(name.c_str()); } -void ultramodern::set_native_thread_priority(ThreadPriority pri) {} +void ultramodern::set_native_thread_priority(ThreadPriority pri) { +} #endif std::atomic_int temporary_threads = 0; @@ -152,14 +150,14 @@ void ultramodern::run_next_thread_and_wait(RDRAM_ARG1) { wait_for_resumed(PASS_RDRAM cur_context); } -void ultramodern::resume_thread_and_wait(RDRAM_ARG OSThread *t) { +void ultramodern::resume_thread_and_wait(RDRAM_ARG OSThread* t) { UltraThreadContext* cur_context = TO_PTR(OSThread, thread_self)->context; resume_thread(t); wait_for_resumed(PASS_RDRAM cur_context); } static void _thread_func(RDRAM_ARG PTR(OSThread) self_, PTR(thread_func_t) entrypoint, PTR(void) arg, UltraThreadContext* thread_context) { - OSThread *self = TO_PTR(OSThread, self_); + OSThread* self = TO_PTR(OSThread, self_); debug_printf("[Thread] Thread created: %d\n", self->id); thread_self = self_; is_game_thread = true; @@ -183,7 +181,7 @@ static void _thread_func(RDRAM_ARG PTR(OSThread) self_, PTR(thread_func_t) entry // Wait until the thread is marked as running. wait_for_resumed(PASS_RDRAM thread_context); - + // Make sure the thread wasn't replaced or destroyed before it was started. if (self->context == thread_context) { debug_printf("[Thread] Thread started: %d\n", self->id); @@ -206,7 +204,7 @@ static void _thread_func(RDRAM_ARG PTR(OSThread) self_, PTR(thread_func_t) entry // Dispose of this thread now that it's completed or terminated. ultramodern::cleanup_thread(thread_context); - + // TODO fix these being hardcoded (this is only used for quicksaving) if ((self->id == 2 && self->priority == 5) || self->id == 13) { // slowly, flashrom temporary_threads.fetch_sub(1); @@ -239,14 +237,14 @@ extern "C" void osStartThread(RDRAM_ARG PTR(OSThread) t_) { else { t->state = OSThreadState::QUEUED; resume_thread(t); - //throw ultramodern::thread_terminated{}; + // throw ultramodern::thread_terminated{}; } } extern "C" void osCreateThread(RDRAM_ARG PTR(OSThread) t_, OSId id, PTR(thread_func_t) entrypoint, PTR(void) arg, PTR(void) sp, OSPri pri) { debug_printf("[os] Create Thread %d\n", id); - OSThread *t = TO_PTR(OSThread, t_); - + OSThread* t = TO_PTR(OSThread, t_); + t->next = NULLPTR; t->queue = NULLPTR; t->priority = pri; @@ -257,7 +255,7 @@ extern "C" void osCreateThread(RDRAM_ARG PTR(OSThread) t_, OSId id, PTR(thread_f // Spawn a new thread, which will immediately pause itself and wait until it's been started. // Pass the context as an argument to the thread function to ensure that it can't get cleared before the thread captures its value. t->context = new UltraThreadContext{}; - t->context->host_thread = std::thread{_thread_func, PASS_RDRAM t_, entrypoint, arg, t->context}; + t->context->host_thread = std::thread{ _thread_func, PASS_RDRAM t_, entrypoint, arg, t->context }; } extern "C" void osStopThread(RDRAM_ARG PTR(OSThread) t_) { @@ -273,7 +271,7 @@ extern "C" void osDestroyThread(RDRAM_ARG PTR(OSThread) t_) { if (t_ == thread_self) { throw ultramodern::thread_terminated{}; } - // Otherwise if the thread isn't stopped, remove it from its currrent queue., + // Otherwise if the thread isn't stopped, remove it from its currrent queue., if (t->state != OSThreadState::STOPPED) { ultramodern::thread_queue_remove(PASS_RDRAM t->queue, t_); } @@ -340,10 +338,10 @@ void thread_cleaner_func() { } void ultramodern::init_thread_cleanup() { - thread_cleaner_thread = std::thread{thread_cleaner_func}; + thread_cleaner_thread = std::thread{ thread_cleaner_func }; } -void ultramodern::cleanup_thread(UltraThreadContext *cur_context) { +void ultramodern::cleanup_thread(UltraThreadContext* cur_context) { deleted_threads.enqueue(cur_context); } diff --git a/ultramodern/src/timer.cpp b/ultramodern/src/timer.cpp index b278ff3..b5ee92c 100644 --- a/ultramodern/src/timer.cpp +++ b/ultramodern/src/timer.cpp @@ -1,14 +1,15 @@ +#include #include #include -#include + #include "blockingconcurrentqueue.h" #include "ultra64.h" #include "ultramodern.hpp" #ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include "Windows.h" +# define WIN32_LEAN_AND_MEAN +# include "Windows.h" #endif // Start time for the program @@ -83,14 +84,15 @@ void timer_thread(RDRAM_ARG1) { }; // Ordered set of timers that are currently active - std::set active_timers{timer_sort}; - + std::set active_timers{ timer_sort }; + // Lambda to process a timer action to handle adding and removing timers auto process_timer_action = [&](const Action& action) { // Determine the action type and act on it if (const auto* add_action = std::get_if(&action)) { active_timers.insert(add_action->timer); - } else if (const auto* remove_action = std::get_if(&action)) { + } + else if (const auto* remove_action = std::get_if(&action)) { active_timers.erase(remove_action->timer); } }; @@ -120,7 +122,7 @@ void timer_thread(RDRAM_ARG1) { // Wait for either the duration to complete or a new action to come through if (wait_duration.count() >= 0 && timer_context.action_queue.wait_dequeue_timed(cur_action, wait_duration)) { - // Timer was interrupted by a new action + // Timer was interrupted by a new action // Add the current timer back to the queue (done first in case the action is to remove this timer) active_timers.insert(cur_timer_); // Process the new action @@ -175,7 +177,8 @@ extern "C" int osSetTimer(RDRAM_ARG PTR(OSTimer) t_, OSTime countdown, OSTime in if (countdown == 0) { // Set the timestamp based on the interval t->timestamp = interval + time_now(); - } else { + } + else { t->timestamp = countdown + time_now(); } t->interval = interval; @@ -214,7 +217,7 @@ void ultramodern::sleep_until(const std::chrono::high_resolution_clock::time_poi #else void ultramodern::sleep_milliseconds(uint32_t millis) { - std::this_thread::sleep_for(std::chrono::milliseconds{millis}); + std::this_thread::sleep_for(std::chrono::milliseconds{ millis }); } void ultramodern::sleep_until(const std::chrono::high_resolution_clock::time_point& time_point) { diff --git a/ultramodern/src/ultrainit.cpp b/ultramodern/src/ultrainit.cpp index 4fca62a..8fd04e5 100644 --- a/ultramodern/src/ultrainit.cpp +++ b/ultramodern/src/ultrainit.cpp @@ -2,17 +2,13 @@ #include "ultramodern.hpp" void ultramodern::set_callbacks( - const rsp::callbacks_t& rsp_callbacks, - const audio_callbacks_t& audio_callbacks, - const input_callbacks_t& input_callbacks, - const gfx_callbacks_t& gfx_callbacks, - const events::callbacks_t& thread_callbacks, - const error_handling::callbacks_t& error_handling_callbacks -) { + const rsp::callbacks_t& rsp_callbacks, const audio_callbacks_t& audio_callbacks, const input_callbacks_t& input_callbacks, + const gfx_callbacks_t& gfx_callbacks, const events::callbacks_t& thread_callbacks, + const error_handling::callbacks_t& error_handling_callbacks) { ultramodern::rsp::set_callbacks(rsp_callbacks); ultramodern::set_audio_callbacks(audio_callbacks); (void)input_callbacks; // nothing yet - (void)gfx_callbacks; // nothing yet + (void)gfx_callbacks; // nothing yet ultramodern::events::set_callbacks(thread_callbacks); ultramodern::error_handling::set_callbacks(error_handling_callbacks); }