mirror of
https://github.com/N64Recomp/N64ModernRuntime.git
synced 2026-04-27 12:32:07 +00:00
Merge branch 'N64Recomp:main' into rumble_pak
This commit is contained in:
commit
c0a774f725
9 changed files with 84 additions and 47 deletions
|
|
@ -82,25 +82,32 @@ namespace recomp {
|
||||||
void do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr);
|
void do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr);
|
||||||
const Version& get_project_version();
|
const Version& get_project_version();
|
||||||
|
|
||||||
/**
|
/// Specify the input configuration to the recomp runtime.
|
||||||
* The following arguments contain mandatory callbacks that need to be registered (i.e., can't be `nullptr`):
|
///
|
||||||
* - `rsp_callbacks`
|
/// The following callback fields are mandatory (i.e., fail on empty()):
|
||||||
* - `renderer_callbacks`
|
/// - `rsp_callbacks`
|
||||||
*
|
/// - `renderer_callbacks`
|
||||||
* It must be called only once and it must be called before `ultramodern::preinit`.
|
///
|
||||||
*/
|
struct Configuration {
|
||||||
void start(
|
Version project_version;
|
||||||
const Version& project_version,
|
ultramodern::renderer::WindowHandle window_handle;
|
||||||
ultramodern::renderer::WindowHandle window_handle,
|
recomp::rsp::callbacks_t rsp_callbacks;
|
||||||
const recomp::rsp::callbacks_t& rsp_callbacks,
|
ultramodern::renderer::callbacks_t renderer_callbacks;
|
||||||
const ultramodern::renderer::callbacks_t& renderer_callbacks,
|
ultramodern::audio_callbacks_t audio_callbacks;
|
||||||
const ultramodern::audio_callbacks_t& audio_callbacks,
|
ultramodern::input::callbacks_t input_callbacks;
|
||||||
const ultramodern::input::callbacks_t& input_callbacks,
|
ultramodern::gfx_callbacks_t gfx_callbacks;
|
||||||
const ultramodern::gfx_callbacks_t& gfx_callbacks,
|
ultramodern::events::callbacks_t events_callbacks;
|
||||||
const ultramodern::events::callbacks_t& events_callbacks,
|
ultramodern::error_handling::callbacks_t error_handling_callbacks;
|
||||||
const ultramodern::error_handling::callbacks_t& error_handling_callbacks,
|
ultramodern::threads::callbacks_t threads_callbacks;
|
||||||
const ultramodern::threads::callbacks_t& threads_callbacks
|
ultramodern::MessageQueueControl message_queue_control;
|
||||||
);
|
};
|
||||||
|
|
||||||
|
/// Start the recomp runtime.
|
||||||
|
///
|
||||||
|
/// This routine must be called only once and it must be called before
|
||||||
|
/// `ultramodern::preinit`.
|
||||||
|
///
|
||||||
|
void start(const Configuration& cfg);
|
||||||
|
|
||||||
SaveType get_save_type();
|
SaveType get_save_type();
|
||||||
bool eeprom_allowed();
|
bool eeprom_allowed();
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ extern "C" void osFlashWriteBuffer_recomp(uint8_t * rdram, recomp_context * ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the message indicating write completion
|
// Send the message indicating write completion
|
||||||
ultramodern::enqueue_external_message(mq, 0, false, true);
|
ultramodern::enqueue_external_message_src(mq, 0, false, ultramodern::EventMessageSource::Pi);
|
||||||
|
|
||||||
ctx->r2 = 0;
|
ctx->r2 = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +193,7 @@ extern "C" void osFlashReadArray_recomp(uint8_t * rdram, recomp_context * ctx) {
|
||||||
save_read(PASS_RDRAM dramAddr, offset, count);
|
save_read(PASS_RDRAM dramAddr, offset, count);
|
||||||
|
|
||||||
// Send the message indicating read completion
|
// Send the message indicating read completion
|
||||||
ultramodern::enqueue_external_message(mq, 0, false, true);
|
ultramodern::enqueue_external_message_src(mq, 0, false, ultramodern::EventMessageSource::Pi);
|
||||||
|
|
||||||
ctx->r2 = 0;
|
ctx->r2 = 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,7 @@ void do_dma(RDRAM_ARG PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_
|
||||||
recomp::do_rom_read(rdram, rdram_address, physical_addr, size);
|
recomp::do_rom_read(rdram, rdram_address, physical_addr, size);
|
||||||
|
|
||||||
// Send a message to the mq to indicate that the transfer completed
|
// Send a message to the mq to indicate that the transfer completed
|
||||||
ultramodern::enqueue_external_message(mq, 0, false, true);
|
ultramodern::enqueue_external_message_src(mq, 0, false, ultramodern::EventMessageSource::Pi);
|
||||||
} else if (physical_addr >= recomp::sram_base) {
|
} else if (physical_addr >= recomp::sram_base) {
|
||||||
if (!recomp::sram_allowed()) {
|
if (!recomp::sram_allowed()) {
|
||||||
ultramodern::error_handling::message_box("Attempted to use SRAM saving with other save type");
|
ultramodern::error_handling::message_box("Attempted to use SRAM saving with other save type");
|
||||||
|
|
@ -285,7 +285,7 @@ void do_dma(RDRAM_ARG PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_
|
||||||
save_read(rdram, rdram_address, physical_addr - recomp::sram_base, size);
|
save_read(rdram, rdram_address, physical_addr - recomp::sram_base, size);
|
||||||
|
|
||||||
// Send a message to the mq to indicate that the transfer completed
|
// Send a message to the mq to indicate that the transfer completed
|
||||||
ultramodern::enqueue_external_message(mq, 0, false, true);
|
ultramodern::enqueue_external_message_src(mq, 0, false, ultramodern::EventMessageSource::Pi);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "[WARN] PI DMA read from unknown region, phys address 0x%08X\n", physical_addr);
|
fprintf(stderr, "[WARN] PI DMA read from unknown region, phys address 0x%08X\n", physical_addr);
|
||||||
}
|
}
|
||||||
|
|
@ -302,7 +302,7 @@ void do_dma(RDRAM_ARG PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_
|
||||||
save_write(rdram, rdram_address, physical_addr - recomp::sram_base, size);
|
save_write(rdram, rdram_address, physical_addr - recomp::sram_base, size);
|
||||||
|
|
||||||
// Send a message to the mq to indicate that the transfer completed
|
// Send a message to the mq to indicate that the transfer completed
|
||||||
ultramodern::enqueue_external_message(mq, 0, false, true);
|
ultramodern::enqueue_external_message_src(mq, 0, false, ultramodern::EventMessageSource::Pi);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "[WARN] PI DMA write to unknown region, phys address 0x%08X\n", physical_addr);
|
fprintf(stderr, "[WARN] PI DMA write to unknown region, phys address 0x%08X\n", physical_addr);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -729,31 +729,20 @@ bool recomp::flashram_allowed() {
|
||||||
save_type == SaveType::AllowAll;
|
save_type == SaveType::AllowAll;
|
||||||
}
|
}
|
||||||
|
|
||||||
void recomp::start(
|
void recomp::start(const recomp::Configuration& cfg) {
|
||||||
const recomp::Version& version,
|
project_version = cfg.project_version;
|
||||||
ultramodern::renderer::WindowHandle window_handle,
|
|
||||||
const recomp::rsp::callbacks_t& rsp_callbacks,
|
|
||||||
const ultramodern::renderer::callbacks_t& renderer_callbacks,
|
|
||||||
const ultramodern::audio_callbacks_t& audio_callbacks,
|
|
||||||
const ultramodern::input::callbacks_t& input_callbacks,
|
|
||||||
const ultramodern::gfx_callbacks_t& gfx_callbacks_,
|
|
||||||
const ultramodern::events::callbacks_t& events_callbacks,
|
|
||||||
const ultramodern::error_handling::callbacks_t& error_handling_callbacks,
|
|
||||||
const ultramodern::threads::callbacks_t& threads_callbacks
|
|
||||||
) {
|
|
||||||
project_version = version;
|
|
||||||
recomp::check_all_stored_roms();
|
recomp::check_all_stored_roms();
|
||||||
|
|
||||||
recomp::rsp::set_callbacks(rsp_callbacks);
|
recomp::rsp::set_callbacks(cfg.rsp_callbacks);
|
||||||
|
|
||||||
static const ultramodern::rsp::callbacks_t ultramodern_rsp_callbacks {
|
static const ultramodern::rsp::callbacks_t ultramodern_rsp_callbacks {
|
||||||
.init = recomp::rsp::constants_init,
|
.init = recomp::rsp::constants_init,
|
||||||
.run_task = recomp::rsp::run_task,
|
.run_task = recomp::rsp::run_task,
|
||||||
};
|
};
|
||||||
|
|
||||||
ultramodern::set_callbacks(ultramodern_rsp_callbacks, renderer_callbacks, audio_callbacks, input_callbacks, gfx_callbacks_, events_callbacks, error_handling_callbacks, threads_callbacks);
|
ultramodern::set_callbacks(ultramodern_rsp_callbacks, cfg.renderer_callbacks, cfg.audio_callbacks, cfg.input_callbacks, cfg.gfx_callbacks, cfg.events_callbacks, cfg.error_handling_callbacks, cfg.threads_callbacks);
|
||||||
|
|
||||||
ultramodern::gfx_callbacks_t gfx_callbacks = gfx_callbacks_;
|
ultramodern::gfx_callbacks_t gfx_callbacks = cfg.gfx_callbacks;
|
||||||
|
|
||||||
ultramodern::gfx_callbacks_t::gfx_data_t gfx_data{};
|
ultramodern::gfx_callbacks_t::gfx_data_t gfx_data{};
|
||||||
|
|
||||||
|
|
@ -761,6 +750,7 @@ void recomp::start(
|
||||||
gfx_data = gfx_callbacks.create_gfx();
|
gfx_data = gfx_callbacks.create_gfx();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto window_handle = cfg.window_handle;
|
||||||
if (window_handle == ultramodern::renderer::WindowHandle{}) {
|
if (window_handle == ultramodern::renderer::WindowHandle{}) {
|
||||||
if (gfx_callbacks.create_window) {
|
if (gfx_callbacks.create_window) {
|
||||||
window_handle = gfx_callbacks.create_window(gfx_data);
|
window_handle = gfx_callbacks.create_window(gfx_data);
|
||||||
|
|
@ -770,6 +760,8 @@ void recomp::start(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ultramodern::set_message_queue_control(cfg.message_queue_control);
|
||||||
|
|
||||||
recomp::mods::initialize_mods();
|
recomp::mods::initialize_mods();
|
||||||
recomp::mods::scan_mods();
|
recomp::mods::scan_mods();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,27 @@ bool thread_queue_empty(RDRAM_ARG PTR(PTR(OSThread)) queue);
|
||||||
PTR(OSThread) thread_queue_peek(RDRAM_ARG PTR(PTR(OSThread)) queue);
|
PTR(OSThread) thread_queue_peek(RDRAM_ARG PTR(PTR(OSThread)) queue);
|
||||||
|
|
||||||
// Message queues.
|
// Message queues.
|
||||||
|
enum class EventMessageSource : int {
|
||||||
|
Timer,
|
||||||
|
Sp,
|
||||||
|
Si,
|
||||||
|
Ai,
|
||||||
|
Vi,
|
||||||
|
Pi,
|
||||||
|
Dp,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MessageQueueControl {
|
||||||
|
bool requeue_timer = true;
|
||||||
|
bool requeue_sp = true;
|
||||||
|
bool requeue_si = true;
|
||||||
|
bool requeue_ai = false;
|
||||||
|
bool requeue_vi = false;
|
||||||
|
bool requeue_pi = false;
|
||||||
|
bool requeue_dp = true;
|
||||||
|
};
|
||||||
|
void set_message_queue_control(const MessageQueueControl& mqc);
|
||||||
|
void enqueue_external_message_src(PTR(OSMesgQueue) mq, OSMesg msg, bool jam, EventMessageSource src);
|
||||||
void enqueue_external_message(PTR(OSMesgQueue) mq, OSMesg msg, bool jam, bool requeue_if_blocked);
|
void enqueue_external_message(PTR(OSMesgQueue) mq, OSMesg msg, bool jam, bool requeue_if_blocked);
|
||||||
void wait_for_external_message(RDRAM_ARG1);
|
void wait_for_external_message(RDRAM_ARG1);
|
||||||
void wait_for_external_message_timed(RDRAM_ARG1, u32 millis);
|
void wait_for_external_message_timed(RDRAM_ARG1, u32 millis);
|
||||||
|
|
|
||||||
|
|
@ -233,13 +233,13 @@ void vi_thread_func() {
|
||||||
if (cur_state->mq != NULLPTR) {
|
if (cur_state->mq != NULLPTR) {
|
||||||
// Send a message to the VI queue, and do not set it to be requeued if the queue was full.
|
// Send a message to the VI queue, and do not set it to be requeued if the queue was full.
|
||||||
// The worst case scenario is that the game misses a VI message and has to wait a little longer for the next.
|
// The worst case scenario is that the game misses a VI message and has to wait a little longer for the next.
|
||||||
ultramodern::enqueue_external_message(cur_state->mq, cur_state->msg, false, false);
|
ultramodern::enqueue_external_message_src(cur_state->mq, cur_state->msg, false, ultramodern::EventMessageSource::Vi);
|
||||||
}
|
}
|
||||||
remaining_retraces = cur_state->retrace_count;
|
remaining_retraces = cur_state->retrace_count;
|
||||||
}
|
}
|
||||||
if (events_context.ai.mq != NULLPTR) {
|
if (events_context.ai.mq != NULLPTR) {
|
||||||
// Send a message to the VI queue, and do not set it to be requeued if the queue was full for the same reason as the VI message above.
|
// Send a message to the VI queue, and do not set it to be requeued if the queue was full for the same reason as the VI message above.
|
||||||
ultramodern::enqueue_external_message(events_context.ai.mq, events_context.ai.msg, false, false);
|
ultramodern::enqueue_external_message_src(events_context.ai.mq, events_context.ai.msg, false, ultramodern::EventMessageSource::Ai);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,13 +252,13 @@ void vi_thread_func() {
|
||||||
void sp_complete() {
|
void sp_complete() {
|
||||||
uint8_t* rdram = events_context.rdram;
|
uint8_t* rdram = events_context.rdram;
|
||||||
std::lock_guard lock{ events_context.message_mutex };
|
std::lock_guard lock{ events_context.message_mutex };
|
||||||
ultramodern::enqueue_external_message(events_context.sp.mq, events_context.sp.msg, false, true);
|
ultramodern::enqueue_external_message_src(events_context.sp.mq, events_context.sp.msg, false, ultramodern::EventMessageSource::Sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dp_complete() {
|
void dp_complete() {
|
||||||
uint8_t* rdram = events_context.rdram;
|
uint8_t* rdram = events_context.rdram;
|
||||||
std::lock_guard lock{ events_context.message_mutex };
|
std::lock_guard lock{ events_context.message_mutex };
|
||||||
ultramodern::enqueue_external_message(events_context.dp.mq, events_context.dp.msg, false, true);
|
ultramodern::enqueue_external_message_src(events_context.dp.mq, events_context.dp.msg, false, ultramodern::EventMessageSource::Dp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_ready) {
|
void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_ready) {
|
||||||
|
|
@ -566,7 +566,7 @@ void ultramodern::submit_rsp_task(RDRAM_ARG PTR(OSTask) task_) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ultramodern::send_si_message() {
|
void ultramodern::send_si_message() {
|
||||||
ultramodern::enqueue_external_message(events_context.si.mq, events_context.si.msg, false, true);
|
ultramodern::enqueue_external_message_src(events_context.si.mq, events_context.si.msg, false, ultramodern::EventMessageSource::Si);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ultramodern::init_events(RDRAM_ARG ultramodern::renderer::WindowHandle window_handle) {
|
void ultramodern::init_events(RDRAM_ARG ultramodern::renderer::WindowHandle window_handle) {
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ void dispatch_displaylist_events(PTR(void) displaylist, u32 event_type) {
|
||||||
for (auto iter = extension_state.dl_events.pending_events.begin(); iter != extension_state.dl_events.pending_events.end(); ) {
|
for (auto iter = extension_state.dl_events.pending_events.begin(); iter != extension_state.dl_events.pending_events.end(); ) {
|
||||||
if (iter->displaylist == displaylist && iter->event_type == event_type) {
|
if (iter->displaylist == displaylist && iter->event_type == event_type) {
|
||||||
// Send the provided message to the corresponding message queue for this event, then remove this event from the queue.
|
// Send the provided message to the corresponding message queue for this event, then remove this event from the queue.
|
||||||
ultramodern::enqueue_external_message(iter->mq, iter->mesg, false, true);
|
ultramodern::enqueue_external_message_src(iter->mq, iter->mesg, false, ultramodern::EventMessageSource::Sp);
|
||||||
iter = extension_state.dl_events.pending_events.erase(iter);
|
iter = extension_state.dl_events.pending_events.erase(iter);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <bitset>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "blockingconcurrentqueue.h"
|
#include "blockingconcurrentqueue.h"
|
||||||
|
|
@ -13,6 +14,22 @@ struct QueuedMessage {
|
||||||
};
|
};
|
||||||
|
|
||||||
static moodycamel::BlockingConcurrentQueue<QueuedMessage> external_messages {};
|
static moodycamel::BlockingConcurrentQueue<QueuedMessage> external_messages {};
|
||||||
|
std::bitset<32> requeue_enabled;
|
||||||
|
|
||||||
|
void ultramodern::set_message_queue_control(const ultramodern::MessageQueueControl& mqc) {
|
||||||
|
requeue_enabled.reset();
|
||||||
|
requeue_enabled.set(static_cast<int>(EventMessageSource::Timer), mqc.requeue_timer);
|
||||||
|
requeue_enabled.set(static_cast<int>(EventMessageSource::Sp), mqc.requeue_sp);
|
||||||
|
requeue_enabled.set(static_cast<int>(EventMessageSource::Si), mqc.requeue_si);
|
||||||
|
requeue_enabled.set(static_cast<int>(EventMessageSource::Ai), mqc.requeue_ai);
|
||||||
|
requeue_enabled.set(static_cast<int>(EventMessageSource::Vi), mqc.requeue_vi);
|
||||||
|
requeue_enabled.set(static_cast<int>(EventMessageSource::Pi), mqc.requeue_pi);
|
||||||
|
requeue_enabled.set(static_cast<int>(EventMessageSource::Dp), mqc.requeue_dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ultramodern::enqueue_external_message_src(PTR(OSMesgQueue) mq, OSMesg msg, bool jam, EventMessageSource src) {
|
||||||
|
external_messages.enqueue({mq, msg, jam, requeue_enabled[static_cast<int>(src)]});
|
||||||
|
}
|
||||||
|
|
||||||
void ultramodern::enqueue_external_message(PTR(OSMesgQueue) mq, OSMesg msg, bool jam, bool requeue_if_blocked) {
|
void ultramodern::enqueue_external_message(PTR(OSMesgQueue) mq, OSMesg msg, bool jam, bool requeue_if_blocked) {
|
||||||
external_messages.enqueue({mq, msg, jam, requeue_if_blocked});
|
external_messages.enqueue({mq, msg, jam, requeue_if_blocked});
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ void timer_thread(RDRAM_ARG1) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Waiting for the timer completed, so send the timer's message to its message queue
|
// Waiting for the timer completed, so send the timer's message to its message queue
|
||||||
ultramodern::enqueue_external_message(cur_timer->mq, cur_timer->msg, false, true);
|
ultramodern::enqueue_external_message_src(cur_timer->mq, cur_timer->msg, false, ultramodern::EventMessageSource::Timer);
|
||||||
// If the timer has a specified interval then reload it with that value
|
// If the timer has a specified interval then reload it with that value
|
||||||
if (cur_timer->interval != 0) {
|
if (cur_timer->interval != 0) {
|
||||||
cur_timer->timestamp = cur_timer->interval + time_now();
|
cur_timer->timestamp = cur_timer->interval + time_now();
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue