Skip to content

Commit 61f74e4

Browse files
committed
Add recomp::Configuration and ultramodern::MessageQueueControl + plumbing (N64Recomp#131)
1 parent ca568b6 commit 61f74e4

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
@@ -97,25 +97,32 @@ namespace recomp {
9797
void do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr);
9898
const Version& get_project_version();
9999

100-
/**
101-
* The following arguments contain mandatory callbacks that need to be registered (i.e., can't be `nullptr`):
102-
* - `rsp_callbacks`
103-
* - `renderer_callbacks`
104-
*
105-
* It must be called only once and it must be called before `ultramodern::preinit`.
106-
*/
107-
void start(
108-
const Version& project_version,
109-
ultramodern::renderer::WindowHandle window_handle,
110-
const recomp::rsp::callbacks_t& rsp_callbacks,
111-
const ultramodern::renderer::callbacks_t& renderer_callbacks,
112-
const ultramodern::audio_callbacks_t& audio_callbacks,
113-
const ultramodern::input::callbacks_t& input_callbacks,
114-
const ultramodern::gfx_callbacks_t& gfx_callbacks,
115-
const ultramodern::events::callbacks_t& events_callbacks,
116-
const ultramodern::error_handling::callbacks_t& error_handling_callbacks,
117-
const ultramodern::threads::callbacks_t& threads_callbacks
118-
);
100+
/// Specify the input configuration to the recomp runtime.
101+
///
102+
/// The following callback fields are mandatory (i.e., fail on empty()):
103+
/// - `rsp_callbacks`
104+
/// - `renderer_callbacks`
105+
///
106+
struct Configuration {
107+
Version project_version;
108+
ultramodern::renderer::WindowHandle window_handle;
109+
recomp::rsp::callbacks_t rsp_callbacks;
110+
ultramodern::renderer::callbacks_t renderer_callbacks;
111+
ultramodern::audio_callbacks_t audio_callbacks;
112+
ultramodern::input::callbacks_t input_callbacks;
113+
ultramodern::gfx_callbacks_t gfx_callbacks;
114+
ultramodern::events::callbacks_t events_callbacks;
115+
ultramodern::error_handling::callbacks_t error_handling_callbacks;
116+
ultramodern::threads::callbacks_t threads_callbacks;
117+
ultramodern::MessageQueueControl message_queue_control;
118+
};
119+
120+
/// Start the recomp runtime.
121+
///
122+
/// This routine must be called only once and it must be called before
123+
/// `ultramodern::preinit`.
124+
///
125+
void start(const Configuration& cfg);
119126

120127
SaveType get_save_type();
121128
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
@@ -792,38 +792,28 @@ bool recomp::flashram_allowed() {
792792
save_type == SaveType::AllowAll;
793793
}
794794

795-
void recomp::start(
796-
const recomp::Version& version,
797-
ultramodern::renderer::WindowHandle window_handle,
798-
const recomp::rsp::callbacks_t& rsp_callbacks,
799-
const ultramodern::renderer::callbacks_t& renderer_callbacks,
800-
const ultramodern::audio_callbacks_t& audio_callbacks,
801-
const ultramodern::input::callbacks_t& input_callbacks,
802-
const ultramodern::gfx_callbacks_t& gfx_callbacks_,
803-
const ultramodern::events::callbacks_t& events_callbacks,
804-
const ultramodern::error_handling::callbacks_t& error_handling_callbacks,
805-
const ultramodern::threads::callbacks_t& threads_callbacks
806-
) {
807-
project_version = version;
795+
void recomp::start(const recomp::Configuration& cfg) {
796+
project_version = cfg.project_version;
808797
recomp::check_all_stored_roms();
809798

810-
recomp::rsp::set_callbacks(rsp_callbacks);
799+
recomp::rsp::set_callbacks(cfg.rsp_callbacks);
811800

812801
static const ultramodern::rsp::callbacks_t ultramodern_rsp_callbacks {
813802
.init = recomp::rsp::constants_init,
814803
.run_task = recomp::rsp::run_task,
815804
};
816805

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

819-
ultramodern::gfx_callbacks_t gfx_callbacks = gfx_callbacks_;
808+
ultramodern::gfx_callbacks_t gfx_callbacks = cfg.gfx_callbacks;
820809

821810
ultramodern::gfx_callbacks_t::gfx_data_t gfx_data{};
822811

823812
if (gfx_callbacks.create_gfx) {
824813
gfx_data = gfx_callbacks.create_gfx();
825814
}
826815

816+
auto window_handle = cfg.window_handle;
827817
if (window_handle == ultramodern::renderer::WindowHandle{}) {
828818
if (gfx_callbacks.create_window) {
829819
window_handle = gfx_callbacks.create_window(gfx_data);
@@ -833,6 +823,8 @@ void recomp::start(
833823
}
834824
}
835825

826+
ultramodern::set_message_queue_control(cfg.message_queue_control);
827+
836828
recomp::mods::initialize_mods();
837829
recomp::mods::scan_mods();
838830

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
@@ -239,13 +239,13 @@ void vi_thread_func() {
239239
if (cur_state->mq != NULLPTR) {
240240
// Send a message to the VI queue, and do not set it to be requeued if the queue was full.
241241
// The worst case scenario is that the game misses a VI message and has to wait a little longer for the next.
242-
ultramodern::enqueue_external_message(cur_state->mq, cur_state->msg, false, false);
242+
ultramodern::enqueue_external_message_src(cur_state->mq, cur_state->msg, false, ultramodern::EventMessageSource::Vi);
243243
}
244244
remaining_retraces = cur_state->retrace_count;
245245
}
246246
if (events_context.ai.mq != NULLPTR) {
247247
// 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.
248-
ultramodern::enqueue_external_message(events_context.ai.mq, events_context.ai.msg, false, false);
248+
ultramodern::enqueue_external_message_src(events_context.ai.mq, events_context.ai.msg, false, ultramodern::EventMessageSource::Ai);
249249
}
250250
}
251251

@@ -258,13 +258,13 @@ void vi_thread_func() {
258258
void sp_complete() {
259259
uint8_t* rdram = events_context.rdram;
260260
std::lock_guard lock{ events_context.message_mutex };
261-
ultramodern::enqueue_external_message(events_context.sp.mq, events_context.sp.msg, false, true);
261+
ultramodern::enqueue_external_message_src(events_context.sp.mq, events_context.sp.msg, false, ultramodern::EventMessageSource::Sp);
262262
}
263263

264264
void dp_complete() {
265265
uint8_t* rdram = events_context.rdram;
266266
std::lock_guard lock{ events_context.message_mutex };
267-
ultramodern::enqueue_external_message(events_context.dp.mq, events_context.dp.msg, false, true);
267+
ultramodern::enqueue_external_message_src(events_context.dp.mq, events_context.dp.msg, false, ultramodern::EventMessageSource::Dp);
268268
}
269269

270270
void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_ready) {
@@ -571,7 +571,7 @@ void ultramodern::submit_rsp_task(RDRAM_ARG PTR(OSTask) task_) {
571571
}
572572

573573
void ultramodern::send_si_message() {
574-
ultramodern::enqueue_external_message(events_context.si.mq, events_context.si.msg, false, true);
574+
ultramodern::enqueue_external_message_src(events_context.si.mq, events_context.si.msg, false, ultramodern::EventMessageSource::Si);
575575
}
576576

577577
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)