mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2025-05-19 01:45:01 +00:00
Integrated RT64 (not included in repo), sign extended addresses
This commit is contained in:
parent
39b67c8468
commit
d0c3eb73ec
17 changed files with 185 additions and 92 deletions
|
@ -2,11 +2,25 @@
|
|||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cinttypes>
|
||||
#include <variant>
|
||||
|
||||
#include <Windows.h>
|
||||
#include "blockingconcurrentqueue.h"
|
||||
|
||||
#include "ultra64.h"
|
||||
#include "multilibultra.hpp"
|
||||
#include "recomp.h"
|
||||
|
||||
struct SpTaskAction {
|
||||
OSTask task;
|
||||
};
|
||||
|
||||
struct SwapBuffersAction {
|
||||
int32_t origin;
|
||||
};
|
||||
|
||||
using Action = std::variant<SpTaskAction, SwapBuffersAction>;
|
||||
|
||||
static struct {
|
||||
struct {
|
||||
std::thread thread;
|
||||
|
@ -18,8 +32,6 @@ static struct {
|
|||
std::thread thread;
|
||||
PTR(OSMesgQueue) mq = NULLPTR;
|
||||
OSMesg msg = (OSMesg)0;
|
||||
OSTask task;
|
||||
std::atomic_flag task_queued;
|
||||
} sp;
|
||||
struct {
|
||||
std::thread thread;
|
||||
|
@ -35,12 +47,12 @@ static struct {
|
|||
std::thread thread;
|
||||
PTR(OSMesgQueue) mq = NULLPTR;
|
||||
OSMesg msg = (OSMesg)0;
|
||||
std::atomic_flag read_queued;
|
||||
} 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;
|
||||
std::chrono::system_clock::time_point start;
|
||||
moodycamel::BlockingConcurrentQueue<Action> action_queue{};
|
||||
} events_context{};
|
||||
|
||||
extern "C" void osSetEventMesg(RDRAM_ARG OSEvent event_id, PTR(OSMesgQueue) mq_, OSMesg msg) {
|
||||
|
@ -73,8 +85,10 @@ extern "C" void osViSetEvent(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, u32 ret
|
|||
events_context.vi.retrace_count = retrace_count;
|
||||
}
|
||||
|
||||
constexpr uint32_t speed_multiplier = 10;
|
||||
|
||||
// N64 CPU counter ticks per millisecond
|
||||
constexpr uint32_t counter_per_ms = 46'875;
|
||||
constexpr uint32_t counter_per_ms = 46'875 * speed_multiplier;
|
||||
|
||||
uint64_t duration_to_count(std::chrono::system_clock::duration duration) {
|
||||
uint64_t delta_micros = std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
|
||||
|
@ -107,7 +121,7 @@ void vi_thread_func() {
|
|||
|
||||
while (true) {
|
||||
// Determine the next VI time (more accurate than adding 16ms each VI interrupt)
|
||||
auto next = events_context.start + (total_vis * 1000000us) / 60;
|
||||
auto next = events_context.start + (total_vis * 1000000us) / (60 * speed_multiplier);
|
||||
//if (next > std::chrono::system_clock::now()) {
|
||||
// printf("Sleeping for %" PRIu64 " us to get from %" PRIu64 " us to %" PRIu64 " us \n",
|
||||
// (next - std::chrono::system_clock::now()) / 1us,
|
||||
|
@ -118,22 +132,29 @@ void vi_thread_func() {
|
|||
//}
|
||||
std::this_thread::sleep_until(next);
|
||||
// Calculate how many VIs have passed
|
||||
uint64_t new_total_vis = ((std::chrono::system_clock::now() - events_context.start) * 60 / 1000ms) + 1;
|
||||
uint64_t new_total_vis = ((std::chrono::system_clock::now() - events_context.start) * (60 * 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;
|
||||
|
||||
remaining_retraces--;
|
||||
|
||||
if (remaining_retraces == 0) {
|
||||
{
|
||||
std::lock_guard lock{ events_context.message_mutex };
|
||||
remaining_retraces = events_context.vi.retrace_count;
|
||||
uint8_t* rdram = events_context.rdram;
|
||||
if (remaining_retraces == 0) {
|
||||
remaining_retraces = events_context.vi.retrace_count;
|
||||
|
||||
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");
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,41 +173,49 @@ void dp_complete() {
|
|||
osSendMesg(PASS_RDRAM events_context.dp.mq, events_context.dp.msg, OS_MESG_NOBLOCK);
|
||||
}
|
||||
|
||||
void gfx_thread_func() {
|
||||
void RT64Init(uint8_t* rom, uint8_t* rdram);
|
||||
void RT64SendDL(uint8_t* rdram, const OSTask* task);
|
||||
void RT64UpdateScreen(uint32_t vi_origin);
|
||||
void RT64PumpEvents();
|
||||
|
||||
void gfx_thread_func(uint8_t* rdram, uint8_t* rom) {
|
||||
using namespace std::chrono_literals;
|
||||
RT64Init(rom, rdram);
|
||||
|
||||
while (true) {
|
||||
// Wait for a sp task to be queued
|
||||
events_context.sp.task_queued.wait(false);
|
||||
|
||||
// Grab the task and inform the game that it's free to queue up a new task
|
||||
OSTask current_task = events_context.sp.task;
|
||||
events_context.sp.task_queued.clear();
|
||||
events_context.sp.task_queued.notify_all();
|
||||
|
||||
// Process the task
|
||||
if (current_task.t.type = M_GFXTASK) {
|
||||
// TODO interface with RT64 here
|
||||
|
||||
// (TODO let RT64 do this) Tell the game that the RSP and RDP tasks are complete
|
||||
sp_complete();
|
||||
dp_complete();
|
||||
} else if (current_task.t.type == M_AUDTASK) {
|
||||
sp_complete();
|
||||
} else {
|
||||
fprintf(stderr, "Unknown task type: %" PRIu32 "\n", current_task.t.type);
|
||||
std::exit(EXIT_FAILURE);
|
||||
// Try to pull an action from the queue
|
||||
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 (task_action->task.t.type == M_GFXTASK) {
|
||||
// (TODO let RT64 do this) Tell the game that the RSP and RDP tasks are complete
|
||||
RT64SendDL(rdram, &task_action->task);
|
||||
sp_complete();
|
||||
dp_complete();
|
||||
} else if (task_action->task.t.type == M_AUDTASK) {
|
||||
sp_complete();
|
||||
} else {
|
||||
fprintf(stderr, "Unknown task type: %" PRIu32 "\n", task_action->task.t.type);
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (const auto* swap_action = std::get_if<SwapBuffersAction>(&action)) {
|
||||
RT64UpdateScreen(swap_action->origin);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle events
|
||||
RT64PumpEvents();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void osViSwapBuffer(RDRAM_ARG PTR(void) frameBufPtr) {
|
||||
events_context.action_queue.enqueue(SwapBuffersAction{ frameBufPtr + 640 });
|
||||
}
|
||||
|
||||
void Multilibultra::submit_rsp_task(RDRAM_ARG PTR(OSTask) task_) {
|
||||
OSTask* task = TO_PTR(OSTask, task_);
|
||||
// Wait for the sp thread clear the old task
|
||||
events_context.sp.task_queued.wait(true);
|
||||
// Make a full copy of the task instead of just recording a pointer to it, since that's what osSpTaskLoad does
|
||||
events_context.sp.task = *task;
|
||||
|
||||
events_context.sp.task_queued.test_and_set();
|
||||
events_context.sp.task_queued.notify_all();
|
||||
events_context.action_queue.enqueue(SpTaskAction{ *task });
|
||||
}
|
||||
|
||||
void Multilibultra::send_si_message() {
|
||||
|
@ -194,8 +223,8 @@ void Multilibultra::send_si_message() {
|
|||
osSendMesg(PASS_RDRAM events_context.si.mq, events_context.si.msg, OS_MESG_NOBLOCK);
|
||||
}
|
||||
|
||||
void Multilibultra::init_events(uint8_t* rdram) {
|
||||
void Multilibultra::init_events(uint8_t* rdram, uint8_t* rom) {
|
||||
events_context.rdram = rdram;
|
||||
events_context.vi.thread = std::thread{ vi_thread_func };
|
||||
events_context.sp.thread = std::thread{ gfx_thread_func };
|
||||
}
|
||||
events_context.sp.thread = std::thread{ gfx_thread_func, rdram, rom };
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue