mirror of
https://github.com/N64Recomp/N64ModernRuntime.git
synced 2026-04-05 01:38:17 +00:00
Format ultramodern
This commit is contained in:
parent
0b01a0e528
commit
108a240186
23 changed files with 452 additions and 453 deletions
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef __CONFIG_HPP__
|
||||
#define __CONFIG_HPP__
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "json/json.hpp"
|
||||
|
||||
|
|
@ -130,7 +130,7 @@ namespace ultramodern {
|
|||
{ultramodern::renderer::HighPrecisionFramebuffer::Off, "Off"},
|
||||
});
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
} // namespace renderer
|
||||
} // namespace ultramodern
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
namespace ultramodern {
|
||||
namespace error_handling {
|
||||
struct callbacks_t {
|
||||
using message_box_t = void(const char* msg);
|
||||
using message_box_t = void(const char *msg);
|
||||
|
||||
/**
|
||||
* Show an OS dialog with the given `msg`.
|
||||
|
|
@ -20,10 +20,10 @@ namespace ultramodern {
|
|||
|
||||
void set_callbacks(const callbacks_t& callbacks);
|
||||
|
||||
void message_box(const char* msg);
|
||||
void message_box(const char *msg);
|
||||
|
||||
[[noreturn]] void quick_exit(const char* filename, int line, const char *func, int exit_status = EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
[[noreturn]] void quick_exit(const char *filename, int line, const char *func, int exit_status = EXIT_FAILURE);
|
||||
} // namespace error_handling
|
||||
} // namespace ultramodern
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -10,16 +10,16 @@ namespace ultramodern {
|
|||
/**
|
||||
* Called in each VI.
|
||||
*/
|
||||
vi_callback_t* vi_callback;
|
||||
vi_callback_t *vi_callback;
|
||||
|
||||
/**
|
||||
* Called before entering the gfx main loop.
|
||||
*/
|
||||
gfx_init_callback_t* gfx_init_callback;
|
||||
gfx_init_callback_t *gfx_init_callback;
|
||||
};
|
||||
|
||||
void set_callbacks(const callbacks_t& callbacks);
|
||||
}
|
||||
}
|
||||
} // namespace events
|
||||
} // namespace ultramodern
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -26,11 +26,11 @@ namespace ultramodern {
|
|||
|
||||
struct callbacks_t {
|
||||
using poll_input_t = void(void);
|
||||
using get_input_t = bool(int controller_num, uint16_t* buttons, float* x, float* y);
|
||||
using get_input_t = bool(int controller_num, uint16_t *buttons, float *x, float *y);
|
||||
using set_rumble_t = void(int controller_num, bool rumble);
|
||||
using get_connected_device_info_t = connected_device_info_t(int controller_num);
|
||||
|
||||
poll_input_t* poll_input;
|
||||
poll_input_t *poll_input;
|
||||
|
||||
/**
|
||||
* Requests the state of the pressed buttons and the analog stick for the given `controller_num`.
|
||||
|
|
@ -39,25 +39,25 @@ namespace ultramodern {
|
|||
*
|
||||
* Returns `true` if was able to fetch the specified data, `false` otherwise and the parameter arguments are left untouched.
|
||||
*/
|
||||
get_input_t* get_input;
|
||||
get_input_t *get_input;
|
||||
|
||||
/**
|
||||
* Turns on or off rumbling for the specified controller.
|
||||
*
|
||||
* `controller_num` is zero-indexed, meaning 0 corresponds to the first controller.
|
||||
*/
|
||||
set_rumble_t* set_rumble;
|
||||
set_rumble_t *set_rumble;
|
||||
|
||||
/**
|
||||
* Returns the connected device info for the given `controller_num` (as in, the controller port of the console).
|
||||
*
|
||||
* `controller_num` is zero-indexed, meaning 0 corresponds to the first controller.
|
||||
*/
|
||||
get_connected_device_info_t* get_connected_device_info;
|
||||
get_connected_device_info_t *get_connected_device_info;
|
||||
};
|
||||
|
||||
void set_callbacks(const callbacks_t& callbacks);
|
||||
}
|
||||
}
|
||||
} // namespace input
|
||||
} // namespace ultramodern
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -7,21 +7,21 @@
|
|||
#include <span>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <Windows.h>
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <Windows.h>
|
||||
#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 "ultra64.h"
|
||||
#include "config.hpp"
|
||||
#include "ultra64.h"
|
||||
|
||||
namespace ultramodern {
|
||||
namespace renderer {
|
||||
|
|
@ -34,17 +34,17 @@ namespace ultramodern {
|
|||
auto operator<=>(const WindowHandle&) const = default;
|
||||
};
|
||||
#elif defined(__ANDROID__)
|
||||
using WindowHandle = ANativeWindow*;
|
||||
using WindowHandle = ANativeWindow *;
|
||||
#elif defined(__linux__)
|
||||
struct WindowHandle {
|
||||
Display* display;
|
||||
Display *display;
|
||||
Window window;
|
||||
auto operator<=>(const WindowHandle&) const = default;
|
||||
};
|
||||
#elif defined(__APPLE__)
|
||||
struct WindowHandle {
|
||||
void* window;
|
||||
void* view;
|
||||
void *window;
|
||||
void *view;
|
||||
auto operator<=>(const WindowHandle&) const = default;
|
||||
};
|
||||
#endif
|
||||
|
|
@ -58,28 +58,31 @@ namespace ultramodern {
|
|||
};
|
||||
|
||||
class RendererContext {
|
||||
public:
|
||||
virtual ~RendererContext() = default;
|
||||
public:
|
||||
virtual ~RendererContext() = default;
|
||||
|
||||
virtual bool valid() = 0;
|
||||
virtual SetupResult get_setup_result() const { return setup_result; }
|
||||
virtual bool valid() = 0;
|
||||
virtual SetupResult get_setup_result() const {
|
||||
return setup_result;
|
||||
}
|
||||
|
||||
virtual bool update_config(const GraphicsConfig& old_config, const GraphicsConfig& new_config) = 0;
|
||||
virtual bool update_config(const GraphicsConfig& old_config, const GraphicsConfig& new_config) = 0;
|
||||
|
||||
virtual void enable_instant_present() = 0;
|
||||
virtual void send_dl(const OSTask* task) = 0;
|
||||
virtual void update_screen(uint32_t vi_origin) = 0;
|
||||
virtual void shutdown() = 0;
|
||||
virtual uint32_t get_display_framerate() const = 0;
|
||||
virtual float get_resolution_scale() const = 0;
|
||||
virtual void load_shader_cache(std::span<const char> cache_binary) = 0;
|
||||
virtual void enable_instant_present() = 0;
|
||||
virtual void send_dl(const OSTask *task) = 0;
|
||||
virtual void update_screen(uint32_t vi_origin) = 0;
|
||||
virtual void shutdown() = 0;
|
||||
virtual uint32_t get_display_framerate() const = 0;
|
||||
virtual float get_resolution_scale() const = 0;
|
||||
virtual void load_shader_cache(std::span<const char> cache_binary) = 0;
|
||||
|
||||
protected:
|
||||
SetupResult setup_result;
|
||||
protected:
|
||||
SetupResult setup_result;
|
||||
};
|
||||
|
||||
struct callbacks_t {
|
||||
using create_render_context_t = std::unique_ptr<RendererContext>(uint8_t* rdram, WindowHandle window_handle, bool developer_mode);
|
||||
using create_render_context_t =
|
||||
std::unique_ptr<RendererContext>(uint8_t *rdram, WindowHandle window_handle, bool developer_mode);
|
||||
using get_graphics_api_name_t = std::string(const GraphicsConfig& config);
|
||||
|
||||
/**
|
||||
|
|
@ -97,10 +100,10 @@ namespace ultramodern {
|
|||
|
||||
void set_callbacks(const callbacks_t& callbacks);
|
||||
|
||||
std::unique_ptr<RendererContext> create_render_context(uint8_t* rdram, WindowHandle window_handle, bool developer_mode);
|
||||
std::unique_ptr<RendererContext> create_render_context(uint8_t *rdram, WindowHandle window_handle, bool developer_mode);
|
||||
|
||||
std::string get_graphics_api_name(const GraphicsConfig& config);
|
||||
}
|
||||
}
|
||||
} // namespace renderer
|
||||
} // namespace ultramodern
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -13,23 +13,23 @@ namespace ultramodern {
|
|||
namespace rsp {
|
||||
struct callbacks_t {
|
||||
using init_t = void();
|
||||
using run_microcode_t = bool(RDRAM_ARG const OSTask* task);
|
||||
using run_microcode_t = bool(RDRAM_ARG const OSTask *task);
|
||||
|
||||
init_t* init;
|
||||
init_t *init;
|
||||
|
||||
/**
|
||||
* Executes the given RSP task.
|
||||
*
|
||||
* Returns true if task was executed successfully.
|
||||
*/
|
||||
run_microcode_t* run_task;
|
||||
run_microcode_t *run_task;
|
||||
};
|
||||
|
||||
void set_callbacks(const callbacks_t& callbacks);
|
||||
|
||||
void init();
|
||||
bool run_task(RDRAM_ARG const OSTask* task);
|
||||
};
|
||||
bool run_task(RDRAM_ARG const OSTask *task);
|
||||
}; // namespace rsp
|
||||
} // namespace ultramodern
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#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;
|
||||
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 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_GFXTASK 1
|
||||
#define M_AUDTASK 2
|
||||
#define M_VIDTASK 3
|
||||
#define M_NJPEGTASK 4
|
||||
|
||||
/////////////
|
||||
|
|
@ -103,7 +103,7 @@ typedef struct OSThread_t {
|
|||
uint16_t state;
|
||||
OSId id;
|
||||
int32_t pad3;
|
||||
UltraThreadContext* context; // An actual pointer regardless of platform
|
||||
UltraThreadContext *context; // An actual pointer regardless of platform
|
||||
int32_t sp;
|
||||
} OSThread;
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
/*
|
||||
|
|
@ -221,13 +221,13 @@ typedef struct {
|
|||
int status;
|
||||
PTR(OSMesgQueue) queue;
|
||||
int channel;
|
||||
u8 id[32]; // TODO: funky endianness here
|
||||
u8 id[32]; // TODO: funky endianness here
|
||||
u8 label[32]; // TODO: funky endianness here
|
||||
int version;
|
||||
int dir_size;
|
||||
int inode_table; /* block location */
|
||||
int minode_table; /* mirrioring inode_table */
|
||||
int dir_table; /* block location */
|
||||
int inode_table; /* block location */
|
||||
int minode_table; /* mirrioring inode_table */
|
||||
int dir_table; /* block location */
|
||||
int inode_start_page; /* page # */
|
||||
// Padding and reversed members due to endianness
|
||||
u8 padding[2];
|
||||
|
|
@ -235,14 +235,13 @@ typedef struct {
|
|||
u8 banks;
|
||||
} OSPfs;
|
||||
|
||||
|
||||
// Controller
|
||||
|
||||
typedef struct {
|
||||
// These three members reversed due to endianness
|
||||
u8 err_no;
|
||||
u8 status; /* Controller status */
|
||||
u16 type; /* Controller Type */
|
||||
u8 status; /* Controller status */
|
||||
u16 type; /* Controller Type */
|
||||
} OSContStatus;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -252,7 +251,6 @@ typedef struct {
|
|||
u8 err_no;
|
||||
} OSContPad;
|
||||
|
||||
|
||||
///////////////
|
||||
// Functions //
|
||||
///////////////
|
||||
|
|
@ -263,7 +261,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);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#ifndef __ultramodern_HPP__
|
||||
#define __ultramodern_HPP__
|
||||
|
||||
#include <thread>
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
|
||||
#undef MOODYCAMEL_DELETE_FUNCTION
|
||||
#define MOODYCAMEL_DELETE_FUNCTION = delete
|
||||
|
|
@ -14,8 +14,8 @@
|
|||
#include "ultramodern/error_handling.hpp"
|
||||
#include "ultramodern/events.hpp"
|
||||
#include "ultramodern/input.hpp"
|
||||
#include "ultramodern/rsp.hpp"
|
||||
#include "ultramodern/renderer_context.hpp"
|
||||
#include "ultramodern/rsp.hpp"
|
||||
|
||||
struct UltraThreadContext {
|
||||
std::thread host_thread;
|
||||
|
|
@ -25,127 +25,122 @@ struct UltraThreadContext {
|
|||
|
||||
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
|
||||
// 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();
|
||||
// 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;
|
||||
// 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);
|
||||
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);
|
||||
// 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 {};
|
||||
// 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
|
||||
};
|
||||
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();
|
||||
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);
|
||||
// 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();
|
||||
// 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();
|
||||
// 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;
|
||||
};
|
||||
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);
|
||||
// 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;
|
||||
};
|
||||
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();
|
||||
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);
|
||||
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
|
||||
);
|
||||
/**
|
||||
* 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))
|
||||
|
|
|
|||
|
|
@ -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<uint32_t>(buffer_offset_frames * sizeof(int16_t) * samples_per_vi)) {
|
||||
buffered_byte_count -= static_cast<uint32_t>(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<uint32_t>(buffer_offset_frames * sizeof(int16_t) * samples_per_vi)) {
|
||||
buffered_byte_count -= static_cast<uint32_t>(buffer_offset_frames * sizeof(int16_t) * samples_per_vi);
|
||||
}
|
||||
else {
|
||||
buffered_byte_count = 0;
|
||||
}
|
||||
return buffered_byte_count;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ void ultramodern::error_handling::set_callbacks(const ultramodern::error_handlin
|
|||
error_handling_callbacks = callbacks;
|
||||
}
|
||||
|
||||
void ultramodern::error_handling::message_box(const char* msg) {
|
||||
void ultramodern::error_handling::message_box(const char *msg) {
|
||||
// We print the message to stderr since the user may not have provided a message_box callback
|
||||
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
|
|
@ -18,7 +18,7 @@ void ultramodern::error_handling::message_box(const char* msg) {
|
|||
}
|
||||
}
|
||||
|
||||
void ultramodern::error_handling::quick_exit(const char* filename, int line, const char *func, int exit_status) {
|
||||
void ultramodern::error_handling::quick_exit(const char *filename, int line, const char *func, int exit_status) {
|
||||
fprintf(stderr, "Exiting with exit status '%i'. Function %s, at file %s:%i, ", exit_status, func, filename, line);
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cinttypes>
|
||||
#include <variant>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
#include "blockingconcurrentqueue.h"
|
||||
|
||||
#include "ultramodern/ultra64.h"
|
||||
#include "ultramodern/ultramodern.hpp"
|
||||
|
||||
#include "ultramodern/rsp.hpp"
|
||||
#include "ultramodern/renderer_context.hpp"
|
||||
#include "ultramodern/rsp.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<const char> data;
|
||||
|
|
@ -69,14 +68,14 @@ static struct {
|
|||
} si;
|
||||
// The same message queue may be used for multiple events, so share a mutex for all of them
|
||||
std::mutex message_mutex;
|
||||
uint8_t* rdram;
|
||||
uint8_t *rdram;
|
||||
moodycamel::BlockingConcurrentQueue<Action> action_queue{};
|
||||
moodycamel::BlockingConcurrentQueue<OSTask*> sp_task_queue{};
|
||||
moodycamel::ConcurrentQueue<OSThread*> deleted_threads{};
|
||||
moodycamel::BlockingConcurrentQueue<OSTask *> sp_task_queue{};
|
||||
moodycamel::ConcurrentQueue<OSThread *> deleted_threads{};
|
||||
} events_context{};
|
||||
|
||||
extern "C" void osSetEventMesg(RDRAM_ARG OSEvent event_id, PTR(OSMesgQueue) mq_, OSMesg msg) {
|
||||
OSMesgQueue* mq = TO_PTR(OSMesgQueue, mq_);
|
||||
OSMesgQueue *mq = TO_PTR(OSMesgQueue, mq_);
|
||||
std::lock_guard lock{ events_context.message_mutex };
|
||||
|
||||
switch (event_id) {
|
||||
|
|
@ -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<std::chrono::seconds>(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;
|
||||
|
||||
|
|
@ -149,14 +148,14 @@ void vi_thread_func() {
|
|||
|
||||
{
|
||||
std::lock_guard lock{ events_context.message_mutex };
|
||||
uint8_t* rdram = events_context.rdram;
|
||||
uint8_t *rdram = events_context.rdram;
|
||||
if (remaining_retraces == 0) {
|
||||
remaining_retraces = events_context.vi.retrace_count;
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -186,18 +185,18 @@ void vi_thread_func() {
|
|||
}
|
||||
|
||||
void sp_complete() {
|
||||
uint8_t* rdram = events_context.rdram;
|
||||
uint8_t *rdram = events_context.rdram;
|
||||
std::lock_guard lock{ events_context.message_mutex };
|
||||
osSendMesg(PASS_RDRAM events_context.sp.mq, events_context.sp.msg, OS_MESG_NOBLOCK);
|
||||
}
|
||||
|
||||
void dp_complete() {
|
||||
uint8_t* rdram = events_context.rdram;
|
||||
uint8_t *rdram = events_context.rdram;
|
||||
std::lock_guard lock{ events_context.message_mutex };
|
||||
osSendMesg(PASS_RDRAM events_context.dp.mq, events_context.dp.msg, OS_MESG_NOBLOCK);
|
||||
}
|
||||
|
||||
void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_ready) {
|
||||
void task_thread_func(uint8_t *rdram, moodycamel::LightweightSemaphore *thread_ready) {
|
||||
ultramodern::set_native_thread_name("SP Task Thread");
|
||||
ultramodern::set_native_thread_priority(ultramodern::ThreadPriority::Normal);
|
||||
|
||||
|
|
@ -206,7 +205,7 @@ void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_r
|
|||
|
||||
while (true) {
|
||||
// Wait until an RSP task has been sent
|
||||
OSTask* task;
|
||||
OSTask *task;
|
||||
events_context.sp_task_queue.wait_dequeue(task);
|
||||
|
||||
if (task == nullptr) {
|
||||
|
|
@ -249,7 +248,7 @@ float ultramodern::get_resolution_scale() {
|
|||
}
|
||||
|
||||
void ultramodern::load_shader_cache(std::span<const char> cache_data) {
|
||||
events_context.action_queue.enqueue(LoadShaderCacheAction{cache_data});
|
||||
events_context.action_queue.enqueue(LoadShaderCacheAction{ cache_data });
|
||||
}
|
||||
|
||||
void ultramodern::trigger_config_action() {
|
||||
|
|
@ -258,7 +257,7 @@ void ultramodern::trigger_config_action() {
|
|||
|
||||
std::atomic<ultramodern::renderer::SetupResult> renderer_setup_result = ultramodern::renderer::SetupResult::Success;
|
||||
|
||||
void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_ready, ultramodern::renderer::WindowHandle window_handle) {
|
||||
void gfx_thread_func(uint8_t *rdram, moodycamel::LightweightSemaphore *thread_ready, ultramodern::renderer::WindowHandle window_handle) {
|
||||
bool enabled_instant_present = false;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
|
|
@ -267,7 +266,8 @@ void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_re
|
|||
|
||||
auto old_config = ultramodern::renderer::get_graphics_config();
|
||||
|
||||
auto renderer_context = ultramodern::renderer::create_render_context(rdram, window_handle, ultramodern::renderer::get_graphics_config().developer_mode);
|
||||
auto renderer_context =
|
||||
ultramodern::renderer::create_render_context(rdram, window_handle, ultramodern::renderer::get_graphics_config().developer_mode);
|
||||
|
||||
if (!renderer_context->valid()) {
|
||||
renderer_setup_result.store(renderer_context->get_setup_result());
|
||||
|
|
@ -290,7 +290,7 @@ void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_re
|
|||
Action action;
|
||||
if (events_context.action_queue.wait_dequeue_timed(action, 1ms)) {
|
||||
// Determine the action type and act on it
|
||||
if (const auto* task_action = std::get_if<SpTaskAction>(&action)) {
|
||||
if (const auto *task_action = std::get_if<SpTaskAction>(&action)) {
|
||||
// Turn on instant present if the game has been started and it hasn't been turned on yet.
|
||||
if (ultramodern::is_game_started() && !enabled_instant_present) {
|
||||
renderer_context->enable_instant_present();
|
||||
|
|
@ -307,21 +307,22 @@ void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_re
|
|||
renderer_context->send_dl(&task_action->task);
|
||||
auto renderer_end = std::chrono::high_resolution_clock::now();
|
||||
dp_complete();
|
||||
// printf("Renderer ProcessDList time: %d us\n", static_cast<u32>(std::chrono::duration_cast<std::chrono::microseconds>(renderer_end - renderer_start).count()));
|
||||
// printf("Renderer ProcessDList time: %d us\n",
|
||||
// static_cast<u32>(std::chrono::duration_cast<std::chrono::microseconds>(renderer_end - renderer_start).count()));
|
||||
}
|
||||
else if (const auto* swap_action = std::get_if<SwapBuffersAction>(&action)) {
|
||||
else if (const auto *swap_action = std::get_if<SwapBuffersAction>(&action)) {
|
||||
events_context.vi.current_buffer = events_context.vi.next_buffer;
|
||||
renderer_context->update_screen(swap_action->origin);
|
||||
display_refresh_rate = renderer_context->get_display_framerate();
|
||||
resolution_scale = renderer_context->get_resolution_scale();
|
||||
}
|
||||
else if (const auto* config_action = std::get_if<UpdateConfigAction>(&action)) {
|
||||
else if (const auto *config_action = std::get_if<UpdateConfigAction>(&action)) {
|
||||
auto new_config = ultramodern::renderer::get_graphics_config();
|
||||
if (renderer_context->update_config(old_config, new_config)) {
|
||||
old_config = new_config;
|
||||
}
|
||||
}
|
||||
else if (const auto* load_shader_cache_action = std::get_if<LoadShaderCacheAction>(&action)) {
|
||||
else if (const auto *load_shader_cache_action = std::get_if<LoadShaderCacheAction>(&action)) {
|
||||
renderer_context->load_shader_cache(load_shader_cache_action->data);
|
||||
}
|
||||
}
|
||||
|
|
@ -368,7 +369,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;
|
||||
|
|
@ -376,7 +378,7 @@ extern "C" void osViSwapBuffer(RDRAM_ARG PTR(void) frameBufPtr) {
|
|||
}
|
||||
|
||||
extern "C" void osViSetMode(RDRAM_ARG PTR(OSViMode) mode_) {
|
||||
OSViMode* mode = TO_PTR(OSViMode, mode_);
|
||||
OSViMode *mode = TO_PTR(OSViMode, mode_);
|
||||
VI_STATUS_REG = mode->comRegs.ctrl;
|
||||
VI_WIDTH_REG = mode->comRegs.width;
|
||||
// burst
|
||||
|
|
@ -395,29 +397,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 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_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) {
|
||||
|
|
@ -452,7 +454,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -481,7 +483,7 @@ extern "C" PTR(void) osViGetCurrentFramebuffer() {
|
|||
}
|
||||
|
||||
void ultramodern::submit_rsp_task(RDRAM_ARG PTR(OSTask) task_) {
|
||||
OSTask* task = TO_PTR(OSTask, task_);
|
||||
OSTask *task = TO_PTR(OSTask, task_);
|
||||
|
||||
// Send gfx tasks to the graphics action queue
|
||||
if (task->t.type == M_GFXTASK) {
|
||||
|
|
@ -525,10 +527,14 @@ void ultramodern::init_events(RDRAM_ARG ultramodern::renderer::WindowHandle wind
|
|||
show_renderer_error("Failed to load dynamic libraries. Make sure the DLLs are next to the recomp executable.");
|
||||
break;
|
||||
case ultramodern::renderer::SetupResult::InvalidGraphicsAPI:
|
||||
show_renderer_error(ultramodern::renderer::get_graphics_api_name(ultramodern::renderer::get_graphics_config()) + " is not supported on this platform. Please select a different graphics API.");
|
||||
show_renderer_error(
|
||||
ultramodern::renderer::get_graphics_api_name(ultramodern::renderer::get_graphics_config()) +
|
||||
" is not supported on this platform. Please select a different graphics API.");
|
||||
break;
|
||||
case ultramodern::renderer::SetupResult::GraphicsAPINotFound:
|
||||
show_renderer_error("Unable to initialize " + ultramodern::renderer::get_graphics_api_name(ultramodern::renderer::get_graphics_config()) + "." + driver_os_suffix);
|
||||
show_renderer_error(
|
||||
"Unable to initialize " + ultramodern::renderer::get_graphics_api_name(ultramodern::renderer::get_graphics_config()) +
|
||||
"." + driver_os_suffix);
|
||||
break;
|
||||
case ultramodern::renderer::SetupResult::GraphicsDeviceNotFound:
|
||||
show_renderer_error("Unable to find compatible graphics device." + driver_os_suffix);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#include "ultramodern/ultra64.h"
|
||||
#include "ultramodern/ultramodern.hpp"
|
||||
|
||||
static ultramodern::input::callbacks_t input_callbacks {};
|
||||
static ultramodern::input::callbacks_t input_callbacks{};
|
||||
|
||||
void ultramodern::input::set_callbacks(const callbacks_t& callbacks) {
|
||||
input_callbacks = callbacks;
|
||||
|
|
@ -27,8 +27,8 @@ void ultramodern::measure_input_latency() {
|
|||
#define CONT_NO_RESPONSE_ERROR 0x8
|
||||
|
||||
#define CONT_TYPE_NORMAL 0x0005
|
||||
#define CONT_TYPE_MOUSE 0x0002
|
||||
#define CONT_TYPE_VOICE 0x0100
|
||||
#define CONT_TYPE_MOUSE 0x0002
|
||||
#define CONT_TYPE_VOICE 0x0100
|
||||
|
||||
static int max_controllers = 0;
|
||||
|
||||
|
|
@ -36,11 +36,11 @@ static int max_controllers = 0;
|
|||
|
||||
static u16 get_controller_type(ultramodern::input::Device device_type) {
|
||||
switch (device_type) {
|
||||
case ultramodern::input::Device::None:
|
||||
return 0;
|
||||
case ultramodern::input::Device::None:
|
||||
return 0;
|
||||
|
||||
case ultramodern::input::Device::Controller:
|
||||
return CONT_TYPE_NORMAL;
|
||||
case ultramodern::input::Device::Controller:
|
||||
return CONT_TYPE_NORMAL;
|
||||
|
||||
#if 0
|
||||
case ultramodern::input::Device::Mouse:
|
||||
|
|
@ -54,7 +54,7 @@ static u16 get_controller_type(ultramodern::input::Device device_type) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void __osContGetInitData(u8* pattern, OSContStatus *data) {
|
||||
static void __osContGetInitData(u8 *pattern, OSContStatus *data) {
|
||||
*pattern = 0x00;
|
||||
|
||||
for (int controller = 0; controller < max_controllers; controller++) {
|
||||
|
|
@ -144,8 +144,9 @@ extern "C" void osContGetReadData(OSContPad *data) {
|
|||
data[controller].stick_x = (int8_t)(127 * x);
|
||||
data[controller].stick_y = (int8_t)(127 * y);
|
||||
data[controller].err_no = 0;
|
||||
} else {
|
||||
data[controller].err_no = CONT_NO_RESPONSE_ERROR; // CHNL_ERR_NORESP >> 4
|
||||
}
|
||||
else {
|
||||
data[controller].err_no = CONT_NO_RESPONSE_ERROR; // CHNL_ERR_NORESP >> 4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ struct QueuedMessage {
|
|||
bool jam;
|
||||
};
|
||||
|
||||
static moodycamel::BlockingConcurrentQueue<QueuedMessage> external_messages {};
|
||||
static moodycamel::BlockingConcurrentQueue<QueuedMessage> 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,7 +34,7 @@ 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -57,12 +57,12 @@ s32 MQ_IS_EMPTY(OSMesgQueue *mq) {
|
|||
return mq->validCount == 0;
|
||||
}
|
||||
|
||||
s32 MQ_IS_FULL(OSMesgQueue* mq) {
|
||||
s32 MQ_IS_FULL(OSMesgQueue *mq) {
|
||||
return MQ_GET_COUNT(mq) >= mq->msgCount;
|
||||
}
|
||||
|
||||
bool do_send(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, bool jam, bool block) {
|
||||
OSMesgQueue* mq = TO_PTR(OSMesgQueue, mq_);
|
||||
OSMesgQueue *mq = TO_PTR(OSMesgQueue, mq_);
|
||||
if (!block) {
|
||||
// If non-blocking, fail if the queue is full.
|
||||
if (MQ_IS_FULL(mq)) {
|
||||
|
|
@ -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,18 +96,19 @@ 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;
|
||||
}
|
||||
|
||||
bool do_recv(RDRAM_ARG PTR(OSMesgQueue) mq_, PTR(OSMesg) msg_, bool block) {
|
||||
OSMesgQueue* mq = TO_PTR(OSMesgQueue, mq_);
|
||||
OSMesgQueue *mq = TO_PTR(OSMesgQueue, mq_);
|
||||
if (!block) {
|
||||
// If non-blocking, fail if the queue is empty
|
||||
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--;
|
||||
|
||||
|
|
@ -135,19 +136,19 @@ 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_);
|
||||
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);
|
||||
|
||||
|
|
@ -157,19 +158,19 @@ 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_);
|
||||
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);
|
||||
|
||||
|
|
@ -178,15 +179,15 @@ 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_);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#include "ultramodern/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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#if 0
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "ultra64.h"
|
||||
# include "ultra64.h"
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
|
||||
#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);
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ void ultramodern::renderer::set_callbacks(const callbacks_t& callbacks) {
|
|||
render_callbacks = callbacks;
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<ultramodern::renderer::RendererContext> ultramodern::renderer::create_render_context(uint8_t* rdram, WindowHandle window_handle, bool developer_mode) {
|
||||
std::unique_ptr<ultramodern::renderer::RendererContext>
|
||||
ultramodern::renderer::create_render_context(uint8_t *rdram, WindowHandle window_handle, bool developer_mode) {
|
||||
if (render_callbacks.create_render_context == nullptr) {
|
||||
error_handling::message_box("[Error] The mandatory render callback `create_render_context` was not registered");
|
||||
ULTRAMODERN_QUICK_EXIT();
|
||||
|
|
@ -27,7 +27,6 @@ std::string ultramodern::renderer::get_graphics_api_name(const GraphicsConfig& c
|
|||
return config.get_graphics_api_name();
|
||||
}
|
||||
|
||||
|
||||
static ultramodern::renderer::GraphicsConfig graphic_config{};
|
||||
static std::mutex graphic_config_mutex;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -15,7 +15,7 @@ void ultramodern::rsp::init() {
|
|||
}
|
||||
}
|
||||
|
||||
bool ultramodern::rsp::run_task(RDRAM_ARG const OSTask* task) {
|
||||
bool ultramodern::rsp::run_task(RDRAM_ARG const OSTask *task) {
|
||||
assert(rsp_callbacks.run_task != nullptr);
|
||||
|
||||
return rsp_callbacks.run_task(PASS_RDRAM task);
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ void ultramodern::check_running_queue(RDRAM_ARG1) {
|
|||
// Check if there are any threads in the running queue.
|
||||
if (!thread_queue_empty(PASS_RDRAM running_queue)) {
|
||||
// Check if the highest priority thread in the queue is higher priority than the current thread.
|
||||
OSThread* next_thread = TO_PTR(OSThread, ultramodern::thread_queue_peek(PASS_RDRAM running_queue));
|
||||
OSThread* self = TO_PTR(OSThread, ultramodern::this_thread());
|
||||
OSThread *next_thread = TO_PTR(OSThread, ultramodern::thread_queue_peek(PASS_RDRAM running_queue));
|
||||
OSThread *self = TO_PTR(OSThread, ultramodern::this_thread());
|
||||
if (next_thread->priority > self->priority) {
|
||||
ultramodern::thread_queue_pop(PASS_RDRAM running_queue);
|
||||
// Swap to the higher priority thread.
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#ifdef _WIN32
|
||||
|
||||
#include <Windows.h>
|
||||
# include <Windows.h>
|
||||
|
||||
#include "ultramodern/ultra64.h"
|
||||
#include "ultramodern/ultramodern.hpp"
|
||||
# include "ultramodern/ultra64.h"
|
||||
# include "ultramodern/ultramodern.hpp"
|
||||
|
||||
extern "C" unsigned int sleep(unsigned int seconds) {
|
||||
Sleep(seconds * 1000);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
static PTR(OSThread) running_queue_impl = NULLPTR;
|
||||
|
||||
static PTR(OSThread)* queue_to_ptr(RDRAM_ARG PTR(PTR(OSThread)) queue) {
|
||||
static PTR(OSThread) *queue_to_ptr(RDRAM_ARG PTR(PTR(OSThread)) queue) {
|
||||
if (queue == ultramodern::running_queue) {
|
||||
return &running_queue_impl;
|
||||
}
|
||||
|
|
@ -12,8 +12,8 @@ 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_);
|
||||
PTR(OSThread) *cur = queue_to_ptr(PASS_RDRAM queue_);
|
||||
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;
|
||||
|
|
@ -32,7 +32,7 @@ void ultramodern::thread_queue_insert(RDRAM_ARG PTR(PTR(OSThread)) queue_, PTR(O
|
|||
}
|
||||
|
||||
PTR(OSThread) ultramodern::thread_queue_pop(RDRAM_ARG PTR(PTR(OSThread)) queue_) {
|
||||
PTR(OSThread)* queue = queue_to_ptr(PASS_RDRAM queue_);
|
||||
PTR(OSThread) *queue = queue_to_ptr(PASS_RDRAM queue_);
|
||||
PTR(OSThread) ret = *queue;
|
||||
*queue = TO_PTR(OSThread, ret)->next;
|
||||
TO_PTR(OSThread, ret)->queue = NULLPTR;
|
||||
|
|
@ -45,7 +45,7 @@ bool ultramodern::thread_queue_remove(RDRAM_ARG PTR(PTR(OSThread)) queue_, PTR(O
|
|||
|
||||
PTR(PTR(OSThread)) cur = queue_;
|
||||
while (cur != NULLPTR) {
|
||||
PTR(OSThread)* cur_ptr = queue_to_ptr(PASS_RDRAM queue_);
|
||||
PTR(OSThread) *cur_ptr = queue_to_ptr(PASS_RDRAM queue_);
|
||||
if (*cur_ptr == t_) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -56,11 +56,11 @@ bool ultramodern::thread_queue_remove(RDRAM_ARG PTR(PTR(OSThread)) queue_, PTR(O
|
|||
}
|
||||
|
||||
bool ultramodern::thread_queue_empty(RDRAM_ARG PTR(PTR(OSThread)) queue_) {
|
||||
PTR(OSThread)* queue = queue_to_ptr(PASS_RDRAM queue_);
|
||||
PTR(OSThread) *queue = queue_to_ptr(PASS_RDRAM queue_);
|
||||
return *queue == NULLPTR;
|
||||
}
|
||||
|
||||
PTR(OSThread) ultramodern::thread_queue_peek(RDRAM_ARG PTR(PTR(OSThread)) queue_) {
|
||||
PTR(OSThread)* queue = queue_to_ptr(PASS_RDRAM queue_);
|
||||
PTR(OSThread) *queue = queue_to_ptr(PASS_RDRAM queue_);
|
||||
return *queue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
#include <cstdio>
|
||||
#include <thread>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "blockingconcurrentqueue.h"
|
||||
#include "ultramodern/ultra64.h"
|
||||
#include "ultramodern/ultramodern.hpp"
|
||||
#include "blockingconcurrentqueue.h"
|
||||
|
||||
// Native APIs only used to set thread names for easier debugging
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
# include <Windows.h>
|
||||
#endif
|
||||
|
||||
extern "C" void bootproc();
|
||||
|
|
@ -37,20 +37,17 @@ int main(int argc, char** argv) {
|
|||
#endif
|
||||
|
||||
#if 1
|
||||
void run_thread_function(uint8_t* rdram, uint64_t addr, uint64_t sp, uint64_t arg);
|
||||
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,13 +113,14 @@ 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;
|
||||
std::atomic_int permanent_threads = 0;
|
||||
|
||||
void wait_for_resumed(RDRAM_ARG UltraThreadContext* thread_context) {
|
||||
void wait_for_resumed(RDRAM_ARG UltraThreadContext *thread_context) {
|
||||
TO_PTR(OSThread, ultramodern::this_thread())->context->running.wait();
|
||||
// If this thread's context was replaced by another thread or deleted, destroy it again from its own context.
|
||||
// This will trigger thread cleanup instead.
|
||||
|
|
@ -131,7 +129,7 @@ void wait_for_resumed(RDRAM_ARG UltraThreadContext* thread_context) {
|
|||
}
|
||||
}
|
||||
|
||||
void resume_thread(OSThread* t) {
|
||||
void resume_thread(OSThread *t) {
|
||||
debug_printf("[Thread] Resuming execution of thread %d\n", t->id);
|
||||
t->context->running.signal();
|
||||
}
|
||||
|
|
@ -141,24 +139,24 @@ void run_next_thread(RDRAM_ARG1) {
|
|||
throw std::runtime_error("No threads left to run!\n");
|
||||
}
|
||||
|
||||
OSThread* to_run = TO_PTR(OSThread, ultramodern::thread_queue_pop(PASS_RDRAM ultramodern::running_queue));
|
||||
OSThread *to_run = TO_PTR(OSThread, ultramodern::thread_queue_pop(PASS_RDRAM ultramodern::running_queue));
|
||||
debug_printf("[Scheduling] Resuming execution of thread %d\n", to_run->id);
|
||||
to_run->context->running.signal();
|
||||
}
|
||||
|
||||
void ultramodern::run_next_thread_and_wait(RDRAM_ARG1) {
|
||||
UltraThreadContext* cur_context = TO_PTR(OSThread, thread_self)->context;
|
||||
UltraThreadContext *cur_context = TO_PTR(OSThread, thread_self)->context;
|
||||
run_next_thread(PASS_RDRAM1);
|
||||
wait_for_resumed(PASS_RDRAM cur_context);
|
||||
}
|
||||
|
||||
void ultramodern::resume_thread_and_wait(RDRAM_ARG OSThread *t) {
|
||||
UltraThreadContext* cur_context = TO_PTR(OSThread, thread_self)->context;
|
||||
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) {
|
||||
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_);
|
||||
debug_printf("[Thread] Thread created: %d\n", self->id);
|
||||
thread_self = self_;
|
||||
|
|
@ -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);
|
||||
|
|
@ -222,7 +220,7 @@ uint32_t ultramodern::temporary_thread_count() {
|
|||
}
|
||||
|
||||
extern "C" void osStartThread(RDRAM_ARG PTR(OSThread) t_) {
|
||||
OSThread* t = TO_PTR(OSThread, t_);
|
||||
OSThread *t = TO_PTR(OSThread, t_);
|
||||
debug_printf("[os] Start Thread %d\n", t->id);
|
||||
|
||||
// Wait until the thread is initialized to indicate that it's ready to be started.
|
||||
|
|
@ -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_);
|
||||
|
||||
|
||||
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_) {
|
||||
|
|
@ -268,17 +266,17 @@ extern "C" void osDestroyThread(RDRAM_ARG PTR(OSThread) t_) {
|
|||
if (t_ == NULLPTR) {
|
||||
t_ = thread_self;
|
||||
}
|
||||
OSThread* t = TO_PTR(OSThread, t_);
|
||||
OSThread *t = TO_PTR(OSThread, t_);
|
||||
// Check if the thread is destroying itself (arg is null or thread_self)
|
||||
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_);
|
||||
}
|
||||
// Check if the thread has already been destroyed to prevent destroying it again.
|
||||
UltraThreadContext* cur_context = t->context;
|
||||
UltraThreadContext *cur_context = t->context;
|
||||
if (cur_context != nullptr) {
|
||||
// Mark the target thread as destroyed and resume it. When it starts it'll check this and terminate itself instead of resuming.
|
||||
t->context = nullptr;
|
||||
|
|
@ -290,7 +288,7 @@ extern "C" void osSetThreadPri(RDRAM_ARG PTR(OSThread) t_, OSPri pri) {
|
|||
if (t_ == NULLPTR) {
|
||||
t_ = thread_self;
|
||||
}
|
||||
OSThread* t = TO_PTR(OSThread, t_);
|
||||
OSThread *t = TO_PTR(OSThread, t_);
|
||||
|
||||
if (t->priority != pri) {
|
||||
t->priority = pri;
|
||||
|
|
@ -323,13 +321,13 @@ PTR(OSThread) ultramodern::this_thread() {
|
|||
}
|
||||
|
||||
static std::thread thread_cleaner_thread;
|
||||
static moodycamel::BlockingConcurrentQueue<UltraThreadContext*> deleted_threads{};
|
||||
static moodycamel::BlockingConcurrentQueue<UltraThreadContext *> deleted_threads{};
|
||||
extern std::atomic_bool exited;
|
||||
|
||||
void thread_cleaner_func() {
|
||||
using namespace std::chrono_literals;
|
||||
while (!exited) {
|
||||
UltraThreadContext* to_delete;
|
||||
UltraThreadContext *to_delete;
|
||||
if (deleted_threads.wait_dequeue_timed(to_delete, 10ms)) {
|
||||
debug_printf("[Cleanup] Deleting thread context %p\n", to_delete);
|
||||
|
||||
|
|
@ -340,7 +338,7 @@ 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) {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
#include "blockingconcurrentqueue.h"
|
||||
#include <set>
|
||||
#include <thread>
|
||||
#include <variant>
|
||||
#include <set>
|
||||
#include "blockingconcurrentqueue.h"
|
||||
|
||||
#include "ultramodern/ultra64.h"
|
||||
#include "ultramodern/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
|
||||
|
|
@ -70,8 +70,8 @@ void timer_thread(RDRAM_ARG1) {
|
|||
|
||||
// Lambda comparator function to keep the set ordered
|
||||
auto timer_sort = [PASS_RDRAM1](PTR(OSTimer) a_, PTR(OSTimer) b_) {
|
||||
OSTimer* a = TO_PTR(OSTimer, a_);
|
||||
OSTimer* b = TO_PTR(OSTimer, b_);
|
||||
OSTimer *a = TO_PTR(OSTimer, a_);
|
||||
OSTimer *b = TO_PTR(OSTimer, b_);
|
||||
|
||||
// Order by timestamp if the timers have different timestamps
|
||||
if (a->timestamp != b->timestamp) {
|
||||
|
|
@ -83,14 +83,15 @@ void timer_thread(RDRAM_ARG1) {
|
|||
};
|
||||
|
||||
// Ordered set of timers that are currently active
|
||||
std::set<PTR(OSTimer), decltype(timer_sort)> active_timers{timer_sort};
|
||||
|
||||
std::set<PTR(OSTimer), decltype(timer_sort)> 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<AddTimerAction>(&action)) {
|
||||
if (const auto *add_action = std::get_if<AddTimerAction>(&action)) {
|
||||
active_timers.insert(add_action->timer);
|
||||
} else if (const auto* remove_action = std::get_if<RemoveTimerAction>(&action)) {
|
||||
}
|
||||
else if (const auto *remove_action = std::get_if<RemoveTimerAction>(&action)) {
|
||||
active_timers.erase(remove_action->timer);
|
||||
}
|
||||
};
|
||||
|
|
@ -110,7 +111,7 @@ void timer_thread(RDRAM_ARG1) {
|
|||
|
||||
// Get the timer that's closest to running out
|
||||
PTR(OSTimer) cur_timer_ = *active_timers.begin();
|
||||
OSTimer* cur_timer = TO_PTR(OSTimer, cur_timer_);
|
||||
OSTimer *cur_timer = TO_PTR(OSTimer, cur_timer_);
|
||||
|
||||
// Remove the timer from the queue (it may get readded if waiting is interrupted)
|
||||
active_timers.erase(cur_timer_);
|
||||
|
|
@ -120,7 +121,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
|
||||
|
|
@ -169,13 +170,14 @@ extern "C" OSTime osGetTime() {
|
|||
}
|
||||
|
||||
extern "C" int osSetTimer(RDRAM_ARG PTR(OSTimer) t_, OSTime countdown, OSTime interval, PTR(OSMesgQueue) mq, OSMesg msg) {
|
||||
OSTimer* t = TO_PTR(OSTimer, t_);
|
||||
OSTimer *t = TO_PTR(OSTimer, t_);
|
||||
|
||||
// Determine the time when this timer will trigger off
|
||||
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 +216,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) {
|
||||
|
|
|
|||
|
|
@ -2,14 +2,9 @@
|
|||
#include "ultramodern/ultramodern.hpp"
|
||||
|
||||
void ultramodern::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& thread_callbacks,
|
||||
const error_handling::callbacks_t& error_handling_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& thread_callbacks,
|
||||
const error_handling::callbacks_t& error_handling_callbacks) {
|
||||
ultramodern::rsp::set_callbacks(rsp_callbacks);
|
||||
ultramodern::renderer::set_callbacks(renderer_callbacks);
|
||||
ultramodern::set_audio_callbacks(audio_callbacks);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue