Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 26 additions & 19 deletions librecomp/include/librecomp/game.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,25 +82,32 @@ namespace recomp {
void do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr);
const Version& get_project_version();

/**
* 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 start(
const Version& 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
);
/// Specify the input configuration to the recomp runtime.
///
/// The following callback fields are mandatory (i.e., fail on empty()):
/// - `rsp_callbacks`
/// - `renderer_callbacks`
///
struct Configuration {
Version project_version;
ultramodern::renderer::WindowHandle window_handle;
recomp::rsp::callbacks_t rsp_callbacks;
ultramodern::renderer::callbacks_t renderer_callbacks;
ultramodern::audio_callbacks_t audio_callbacks;
ultramodern::input::callbacks_t input_callbacks;
ultramodern::gfx_callbacks_t gfx_callbacks;
ultramodern::events::callbacks_t events_callbacks;
ultramodern::error_handling::callbacks_t error_handling_callbacks;
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();
bool eeprom_allowed();
Expand Down
4 changes: 2 additions & 2 deletions librecomp/src/flash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ extern "C" void osFlashWriteBuffer_recomp(uint8_t * rdram, recomp_context * ctx)
}

// 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;
}
Expand Down Expand Up @@ -193,7 +193,7 @@ extern "C" void osFlashReadArray_recomp(uint8_t * rdram, recomp_context * ctx) {
save_read(PASS_RDRAM dramAddr, offset, count);

// 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;
}
Expand Down
6 changes: 3 additions & 3 deletions librecomp/src/pi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

// 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) {
if (!recomp::sram_allowed()) {
ultramodern::error_handling::message_box("Attempted to use SRAM saving with other save type");
Expand All @@ -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);

// 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 {
fprintf(stderr, "[WARN] PI DMA read from unknown region, phys address 0x%08X\n", physical_addr);
}
Expand All @@ -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);

// 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 {
fprintf(stderr, "[WARN] PI DMA write to unknown region, phys address 0x%08X\n", physical_addr);
}
Expand Down
24 changes: 8 additions & 16 deletions librecomp/src/recomp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -729,38 +729,28 @@ bool recomp::flashram_allowed() {
save_type == SaveType::AllowAll;
}

void recomp::start(
const recomp::Version& 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;
void recomp::start(const recomp::Configuration& cfg) {
project_version = cfg.project_version;
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 {
.init = recomp::rsp::constants_init,
.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{};

if (gfx_callbacks.create_gfx) {
gfx_data = gfx_callbacks.create_gfx();
}

auto window_handle = cfg.window_handle;
if (window_handle == ultramodern::renderer::WindowHandle{}) {
if (gfx_callbacks.create_window) {
window_handle = gfx_callbacks.create_window(gfx_data);
Expand All @@ -770,6 +760,8 @@ void recomp::start(
}
}

ultramodern::set_message_queue_control(cfg.message_queue_control);

recomp::mods::initialize_mods();
recomp::mods::scan_mods();

Expand Down
21 changes: 21 additions & 0 deletions ultramodern/include/ultramodern/ultramodern.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

// 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 wait_for_external_message(RDRAM_ARG1);
void wait_for_external_message_timed(RDRAM_ARG1, u32 millis);
Expand Down
10 changes: 5 additions & 5 deletions ultramodern/src/events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,13 +233,13 @@ void vi_thread_func() {
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.
// 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;
}
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.
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);
}
}

Expand All @@ -252,13 +252,13 @@ void vi_thread_func() {
void sp_complete() {
uint8_t* rdram = events_context.rdram;
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() {
uint8_t* rdram = events_context.rdram;
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) {
Expand Down Expand Up @@ -566,7 +566,7 @@ void ultramodern::submit_rsp_task(RDRAM_ARG PTR(OSTask) task_) {
}

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) {
Expand Down
2 changes: 1 addition & 1 deletion ultramodern/src/extensions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(); ) {
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.
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);
}
else {
Expand Down
17 changes: 17 additions & 0 deletions ultramodern/src/mesgqueue.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <bitset>
#include <thread>

#include "blockingconcurrentqueue.h"
Expand All @@ -13,6 +14,22 @@ struct QueuedMessage {
};

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) {
external_messages.enqueue({mq, msg, jam, requeue_if_blocked});
Expand Down
2 changes: 1 addition & 1 deletion ultramodern/src/timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ void timer_thread(RDRAM_ARG1) {
}
else {
// 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 (cur_timer->interval != 0) {
cur_timer->timestamp = cur_timer->interval + time_now();
Expand Down
Loading