mirror of
				https://github.com/N64Recomp/N64ModernRuntime.git
				synced 2025-10-30 08:02:29 +00:00 
			
		
		
		
	 b4dbddb555
			
		
	
	
		b4dbddb555
		
			
		
	
	
	
	
		
			
			* `RendererContext` abstract class * Delete rt64_layer * Implement renderer creation callback * Make `GraphicsConfig` an abstract class * Remove rt64 * Add renderer callback to `ultramodern::set_callbacks` * Fix rebase * Change setup_result's visibility to protected * Declare abstract `is_equal` method instead of operators * Various fixes * Fix issues * trigger_config_action * Move GraphicsConfig back to ultramodern * Change `update_config` to return if any changes were applied * Rename renderer_wrapper to renderer_context * Remove SDL2 and other libraries * Allow registering get_graphics_api_name * Move WindowHandle to renderer namespace * Comments explaining which callbacks are required * Fix CI * Update readme * `ULTRAMODERN_QUICK_EXIT` macro * Remove --config from readme * Add `add_compile_definitions(NOMINMAX)`
		
			
				
	
	
		
			156 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			156 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef __ultramodern_HPP__
 | |
| #define __ultramodern_HPP__
 | |
| 
 | |
| #include <thread>
 | |
| #include <cassert>
 | |
| #include <stdexcept>
 | |
| #include <span>
 | |
| 
 | |
| #undef MOODYCAMEL_DELETE_FUNCTION
 | |
| #define MOODYCAMEL_DELETE_FUNCTION = delete
 | |
| #include "lightweightsemaphore.h"
 | |
| #include "ultra64.h"
 | |
| 
 | |
| #include "ultramodern/error_handling.hpp"
 | |
| #include "ultramodern/events.hpp"
 | |
| #include "ultramodern/input.hpp"
 | |
| #include "ultramodern/rsp.hpp"
 | |
| #include "ultramodern/renderer_context.hpp"
 | |
| 
 | |
| struct UltraThreadContext {
 | |
|     std::thread host_thread;
 | |
|     moodycamel::LightweightSemaphore running;
 | |
|     moodycamel::LightweightSemaphore initialized;
 | |
| };
 | |
| 
 | |
| namespace ultramodern {
 | |
| 
 | |
| // 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 renderer::WindowHandle window_handle);
 | |
| void init_saving(RDRAM_ARG1);
 | |
| void init_events(RDRAM_ARG renderer::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
 | |
| uint32_t get_target_framerate(uint32_t original);
 | |
| uint32_t get_display_refresh_rate();
 | |
| float get_resolution_scale();
 | |
| void load_shader_cache(std::span<const char> cache_data);
 | |
| void trigger_config_action();
 | |
| 
 | |
| // 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: 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 = renderer::WindowHandle(gfx_data_t);
 | |
|     using update_gfx_t = void(gfx_data_t);
 | |
| 
 | |
|     create_gfx_t* create_gfx;
 | |
|     create_window_t* create_window;
 | |
|     update_gfx_t* update_gfx;
 | |
| };
 | |
| 
 | |
| 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.
 | |
|  *
 | |
|  * The following arguments contain mandatory callbacks that need to be registered (i.e., can't be `nullptr`):
 | |
|  * - `rsp_callbacks`
 | |
|  * - `renderer_callbacks`
 | |
|  *
 | |
|  * It must be called only once and it must be called before `ultramodern::preinit`.
 | |
|  */
 | |
| void set_callbacks(
 | |
|     const rsp::callbacks_t& rsp_callbacks,
 | |
|     const renderer::callbacks_t& renderer_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))
 | |
| 
 | |
| #define debug_printf(...)
 | |
| //#define debug_printf(...) printf(__VA_ARGS__);
 | |
| 
 | |
| #endif
 |