Skip to content

Commit 575c8f2

Browse files
authored
Add recomp::Configuration and ultramodern::MessageQueueControl + plumbing (#131)
1 parent e8d7aec commit 575c8f2

9 files changed

Lines changed: 84 additions & 47 deletions

File tree

librecomp/include/librecomp/game.hpp

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -82,25 +82,32 @@ namespace recomp {
8282
void do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr);
8383
const Version& get_project_version();
8484

85-
/**
86-
* The following arguments contain mandatory callbacks that need to be registered (i.e., can't be `nullptr`):
87-
* - `rsp_callbacks`
88-
* - `renderer_callbacks`
89-
*
90-
* It must be called only once and it must be called before `ultramodern::preinit`.
91-
*/
92-
void start(
93-
const Version& project_version,
94-
ultramodern::renderer::WindowHandle window_handle,
95-
const recomp::rsp::callbacks_t& rsp_callbacks,
96-
const ultramodern::renderer::callbacks_t& renderer_callbacks,
97-
const ultramodern::audio_callbacks_t& audio_callbacks,
98-
const ultramodern::input::callbacks_t& input_callbacks,
99-
const ultramodern::gfx_callbacks_t& gfx_callbacks,
100-
const ultramodern::events::callbacks_t& events_callbacks,
101-
const ultramodern::error_handling::callbacks_t& error_handling_callbacks,
102-
const ultramodern::threads::callbacks_t& threads_callbacks
103-
);
85+
/// Specify the input configuration to the recomp runtime.
86+
///
87+
/// The following callback fields are mandatory (i.e., fail on empty()):
88+
/// - `rsp_callbacks`
89+
/// - `renderer_callbacks`
90+
///
91+
struct Configuration {
92+
Version project_version;
93+
ultramodern::renderer::WindowHandle window_handle;
94+
recomp::rsp::callbacks_t rsp_callbacks;
95+
ultramodern::renderer::callbacks_t renderer_callbacks;
96+
ultramodern::audio_callbacks_t audio_callbacks;
97+
ultramodern::input::callbacks_t input_callbacks;
98+
ultramodern::gfx_callbacks_t gfx_callbacks;
99+
ultramodern::events::callbacks_t events_callbacks;
100+
ultramodern::error_handling::callbacks_t error_handling_callbacks;
101+
ultramodern::threads::callbacks_t threads_callbacks;
102+
ultramodern::MessageQueueControl message_queue_control;
103+
};
104+
105+
/// Start the recomp runtime.
106+
///
107+
/// This routine must be called only once and it must be called before
108+
/// `ultramodern::preinit`.
109+
///
110+
void start(const Configuration& cfg);
104111

105112
SaveType get_save_type();
106113
bool eeprom_allowed();

librecomp/src/flash.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ extern "C" void osFlashWriteBuffer_recomp(uint8_t * rdram, recomp_context * ctx)
154154
}
155155

156156
// Send the message indicating write completion
157-
ultramodern::enqueue_external_message(mq, 0, false, true);
157+
ultramodern::enqueue_external_message_src(mq, 0, false, ultramodern::EventMessageSource::Pi);
158158

159159
ctx->r2 = 0;
160160
}
@@ -193,7 +193,7 @@ extern "C" void osFlashReadArray_recomp(uint8_t * rdram, recomp_context * ctx) {
193193
save_read(PASS_RDRAM dramAddr, offset, count);
194194

195195
// Send the message indicating read completion
196-
ultramodern::enqueue_external_message(mq, 0, false, true);
196+
ultramodern::enqueue_external_message_src(mq, 0, false, ultramodern::EventMessageSource::Pi);
197197

198198
ctx->r2 = 0;
199199
}

librecomp/src/pi.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ void do_dma(RDRAM_ARG PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_
275275
recomp::do_rom_read(rdram, rdram_address, physical_addr, size);
276276

277277
// Send a message to the mq to indicate that the transfer completed
278-
ultramodern::enqueue_external_message(mq, 0, false, true);
278+
ultramodern::enqueue_external_message_src(mq, 0, false, ultramodern::EventMessageSource::Pi);
279279
} else if (physical_addr >= recomp::sram_base) {
280280
if (!recomp::sram_allowed()) {
281281
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_
285285
save_read(rdram, rdram_address, physical_addr - recomp::sram_base, size);
286286

287287
// Send a message to the mq to indicate that the transfer completed
288-
ultramodern::enqueue_external_message(mq, 0, false, true);
288+
ultramodern::enqueue_external_message_src(mq, 0, false, ultramodern::EventMessageSource::Pi);
289289
} else {
290290
fprintf(stderr, "[WARN] PI DMA read from unknown region, phys address 0x%08X\n", physical_addr);
291291
}
@@ -302,7 +302,7 @@ void do_dma(RDRAM_ARG PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_
302302
save_write(rdram, rdram_address, physical_addr - recomp::sram_base, size);
303303

304304
// Send a message to the mq to indicate that the transfer completed
305-
ultramodern::enqueue_external_message(mq, 0, false, true);
305+
ultramodern::enqueue_external_message_src(mq, 0, false, ultramodern::EventMessageSource::Pi);
306306
} else {
307307
fprintf(stderr, "[WARN] PI DMA write to unknown region, phys address 0x%08X\n", physical_addr);
308308
}

librecomp/src/recomp.cpp

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -729,38 +729,28 @@ bool recomp::flashram_allowed() {
729729
save_type == SaveType::AllowAll;
730730
}
731731

732-
void recomp::start(
733-
const recomp::Version& version,
734-
ultramodern::renderer::WindowHandle window_handle,
735-
const recomp::rsp::callbacks_t& rsp_callbacks,
736-
const ultramodern::renderer::callbacks_t& renderer_callbacks,
737-
const ultramodern::audio_callbacks_t& audio_callbacks,
738-
const ultramodern::input::callbacks_t& input_callbacks,
739-
const ultramodern::gfx_callbacks_t& gfx_callbacks_,
740-
const ultramodern::events::callbacks_t& events_callbacks,
741-
const ultramodern::error_handling::callbacks_t& error_handling_callbacks,
742-
const ultramodern::threads::callbacks_t& threads_callbacks
743-
) {
744-
project_version = version;
732+
void recomp::start(const recomp::Configuration& cfg) {
733+
project_version = cfg.project_version;
745734
recomp::check_all_stored_roms();
746735

747-
recomp::rsp::set_callbacks(rsp_callbacks);
736+
recomp::rsp::set_callbacks(cfg.rsp_callbacks);
748737

749738
static const ultramodern::rsp::callbacks_t ultramodern_rsp_callbacks {
750739
.init = recomp::rsp::constants_init,
751740
.run_task = recomp::rsp::run_task,
752741
};
753742

754-
ultramodern::set_callbacks(ultramodern_rsp_callbacks, renderer_callbacks, audio_callbacks, input_callbacks, gfx_callbacks_, events_callbacks, error_handling_callbacks, threads_callbacks);
743+
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);
755744

756-
ultramodern::gfx_callbacks_t gfx_callbacks = gfx_callbacks_;
745+
ultramodern::gfx_callbacks_t gfx_callbacks = cfg.gfx_callbacks;
757746

758747
ultramodern::gfx_callbacks_t::gfx_data_t gfx_data{};
759748

760749
if (gfx_callbacks.create_gfx) {
761750
gfx_data = gfx_callbacks.create_gfx();
762751
}
763752

753+
auto window_handle = cfg.window_handle;
764754
if (window_handle == ultramodern::renderer::WindowHandle{}) {
765755
if (gfx_callbacks.create_window) {
766756
window_handle = gfx_callbacks.create_window(gfx_data);
@@ -770,6 +760,8 @@ void recomp::start(
770760
}
771761
}
772762

763+
ultramodern::set_message_queue_control(cfg.message_queue_control);
764+
773765
recomp::mods::initialize_mods();
774766
recomp::mods::scan_mods();
775767

ultramodern/include/ultramodern/ultramodern.hpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,27 @@ bool thread_queue_empty(RDRAM_ARG PTR(PTR(OSThread)) queue);
5252
PTR(OSThread) thread_queue_peek(RDRAM_ARG PTR(PTR(OSThread)) queue);
5353

5454
// Message queues.
55+
enum class EventMessageSource : int {
56+
Timer,
57+
Sp,
58+
Si,
59+
Ai,
60+
Vi,
61+
Pi,
62+
Dp,
63+
};
64+
65+
struct MessageQueueControl {
66+
bool requeue_timer = true;
67+
bool requeue_sp = true;
68+
bool requeue_si = true;
69+
bool requeue_ai = false;
70+
bool requeue_vi = false;
71+
bool requeue_pi = false;
72+
bool requeue_dp = true;
73+
};
74+
void set_message_queue_control(const MessageQueueControl& mqc);
75+
void enqueue_external_message_src(PTR(OSMesgQueue) mq, OSMesg msg, bool jam, EventMessageSource src);
5576
void enqueue_external_message(PTR(OSMesgQueue) mq, OSMesg msg, bool jam, bool requeue_if_blocked);
5677
void wait_for_external_message(RDRAM_ARG1);
5778
void wait_for_external_message_timed(RDRAM_ARG1, u32 millis);

ultramodern/src/events.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -233,13 +233,13 @@ void vi_thread_func() {
233233
if (cur_state->mq != NULLPTR) {
234234
// Send a message to the VI queue, and do not set it to be requeued if the queue was full.
235235
// The worst case scenario is that the game misses a VI message and has to wait a little longer for the next.
236-
ultramodern::enqueue_external_message(cur_state->mq, cur_state->msg, false, false);
236+
ultramodern::enqueue_external_message_src(cur_state->mq, cur_state->msg, false, ultramodern::EventMessageSource::Vi);
237237
}
238238
remaining_retraces = cur_state->retrace_count;
239239
}
240240
if (events_context.ai.mq != NULLPTR) {
241241
// 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.
242-
ultramodern::enqueue_external_message(events_context.ai.mq, events_context.ai.msg, false, false);
242+
ultramodern::enqueue_external_message_src(events_context.ai.mq, events_context.ai.msg, false, ultramodern::EventMessageSource::Ai);
243243
}
244244
}
245245

@@ -252,13 +252,13 @@ void vi_thread_func() {
252252
void sp_complete() {
253253
uint8_t* rdram = events_context.rdram;
254254
std::lock_guard lock{ events_context.message_mutex };
255-
ultramodern::enqueue_external_message(events_context.sp.mq, events_context.sp.msg, false, true);
255+
ultramodern::enqueue_external_message_src(events_context.sp.mq, events_context.sp.msg, false, ultramodern::EventMessageSource::Sp);
256256
}
257257

258258
void dp_complete() {
259259
uint8_t* rdram = events_context.rdram;
260260
std::lock_guard lock{ events_context.message_mutex };
261-
ultramodern::enqueue_external_message(events_context.dp.mq, events_context.dp.msg, false, true);
261+
ultramodern::enqueue_external_message_src(events_context.dp.mq, events_context.dp.msg, false, ultramodern::EventMessageSource::Dp);
262262
}
263263

264264
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_) {
566566
}
567567

568568
void ultramodern::send_si_message() {
569-
ultramodern::enqueue_external_message(events_context.si.mq, events_context.si.msg, false, true);
569+
ultramodern::enqueue_external_message_src(events_context.si.mq, events_context.si.msg, false, ultramodern::EventMessageSource::Si);
570570
}
571571

572572
void ultramodern::init_events(RDRAM_ARG ultramodern::renderer::WindowHandle window_handle) {

ultramodern/src/extensions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ void dispatch_displaylist_events(PTR(void) displaylist, u32 event_type) {
3838
for (auto iter = extension_state.dl_events.pending_events.begin(); iter != extension_state.dl_events.pending_events.end(); ) {
3939
if (iter->displaylist == displaylist && iter->event_type == event_type) {
4040
// Send the provided message to the corresponding message queue for this event, then remove this event from the queue.
41-
ultramodern::enqueue_external_message(iter->mq, iter->mesg, false, true);
41+
ultramodern::enqueue_external_message_src(iter->mq, iter->mesg, false, ultramodern::EventMessageSource::Sp);
4242
iter = extension_state.dl_events.pending_events.erase(iter);
4343
}
4444
else {

ultramodern/src/mesgqueue.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <bitset>
12
#include <thread>
23

34
#include "blockingconcurrentqueue.h"
@@ -13,6 +14,22 @@ struct QueuedMessage {
1314
};
1415

1516
static moodycamel::BlockingConcurrentQueue<QueuedMessage> external_messages {};
17+
std::bitset<32> requeue_enabled;
18+
19+
void ultramodern::set_message_queue_control(const ultramodern::MessageQueueControl& mqc) {
20+
requeue_enabled.reset();
21+
requeue_enabled.set(static_cast<int>(EventMessageSource::Timer), mqc.requeue_timer);
22+
requeue_enabled.set(static_cast<int>(EventMessageSource::Sp), mqc.requeue_sp);
23+
requeue_enabled.set(static_cast<int>(EventMessageSource::Si), mqc.requeue_si);
24+
requeue_enabled.set(static_cast<int>(EventMessageSource::Ai), mqc.requeue_ai);
25+
requeue_enabled.set(static_cast<int>(EventMessageSource::Vi), mqc.requeue_vi);
26+
requeue_enabled.set(static_cast<int>(EventMessageSource::Pi), mqc.requeue_pi);
27+
requeue_enabled.set(static_cast<int>(EventMessageSource::Dp), mqc.requeue_dp);
28+
}
29+
30+
void ultramodern::enqueue_external_message_src(PTR(OSMesgQueue) mq, OSMesg msg, bool jam, EventMessageSource src) {
31+
external_messages.enqueue({mq, msg, jam, requeue_enabled[static_cast<int>(src)]});
32+
}
1633

1734
void ultramodern::enqueue_external_message(PTR(OSMesgQueue) mq, OSMesg msg, bool jam, bool requeue_if_blocked) {
1835
external_messages.enqueue({mq, msg, jam, requeue_if_blocked});

ultramodern/src/timer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ void timer_thread(RDRAM_ARG1) {
130130
}
131131
else {
132132
// Waiting for the timer completed, so send the timer's message to its message queue
133-
ultramodern::enqueue_external_message(cur_timer->mq, cur_timer->msg, false, true);
133+
ultramodern::enqueue_external_message_src(cur_timer->mq, cur_timer->msg, false, ultramodern::EventMessageSource::Timer);
134134
// If the timer has a specified interval then reload it with that value
135135
if (cur_timer->interval != 0) {
136136
cur_timer->timestamp = cur_timer->interval + time_now();

0 commit comments

Comments
 (0)