Made non-gfx RSP tasks execute on another thread, implemented VI registers
This commit is contained in:
parent
f024c4db84
commit
6ab12039ed
|
@ -37,7 +37,8 @@ static struct {
|
||||||
int retrace_count = 1;
|
int retrace_count = 1;
|
||||||
} vi;
|
} vi;
|
||||||
struct {
|
struct {
|
||||||
std::thread thread;
|
std::thread gfx_thread;
|
||||||
|
std::thread task_thread;
|
||||||
PTR(OSMesgQueue) mq = NULLPTR;
|
PTR(OSMesgQueue) mq = NULLPTR;
|
||||||
OSMesg msg = (OSMesg)0;
|
OSMesg msg = (OSMesg)0;
|
||||||
} sp;
|
} sp;
|
||||||
|
@ -60,6 +61,7 @@ static struct {
|
||||||
std::mutex message_mutex;
|
std::mutex message_mutex;
|
||||||
uint8_t* rdram;
|
uint8_t* rdram;
|
||||||
moodycamel::BlockingConcurrentQueue<Action> action_queue{};
|
moodycamel::BlockingConcurrentQueue<Action> action_queue{};
|
||||||
|
std::atomic<OSTask*> sp_task = nullptr;
|
||||||
} events_context{};
|
} events_context{};
|
||||||
|
|
||||||
extern "C" void osSetEventMesg(RDRAM_ARG OSEvent event_id, PTR(OSMesgQueue) mq_, OSMesg msg) {
|
extern "C" void osSetEventMesg(RDRAM_ARG OSEvent event_id, PTR(OSMesgQueue) mq_, OSMesg msg) {
|
||||||
|
@ -243,7 +245,39 @@ void run_rsp_microcode(uint8_t* rdram, const OSTask* task, RspUcodeFunc* ucode_f
|
||||||
sp_complete();
|
sp_complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
void event_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* events_thread_ready) {
|
|
||||||
|
void task_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_ready) {
|
||||||
|
// Notify the caller thread that this thread is ready.
|
||||||
|
thread_ready->test_and_set();
|
||||||
|
thread_ready->notify_all();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// Wait until an RSP task has been sent
|
||||||
|
events_context.sp_task.wait(nullptr);
|
||||||
|
|
||||||
|
// Retrieve the task pointer and clear the pending RSP task
|
||||||
|
OSTask* task = events_context.sp_task;
|
||||||
|
events_context.sp_task.store(nullptr);
|
||||||
|
|
||||||
|
// Run the correct function based on the task type
|
||||||
|
if (task->t.type == M_AUDTASK) {
|
||||||
|
run_rsp_microcode(rdram, task, aspMain);
|
||||||
|
}
|
||||||
|
else if (task->t.type == M_NJPEGTASK) {
|
||||||
|
run_rsp_microcode(rdram, task, njpgdspMain);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Unknown task type: %" PRIu32 "\n", task->t.type);
|
||||||
|
assert(false);
|
||||||
|
std::quick_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell the game that the RSP has completed
|
||||||
|
sp_complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_ready) {
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
|
||||||
fprintf(stderr, "Failed to initialize SDL2: %s\n", SDL_GetError());
|
fprintf(stderr, "Failed to initialize SDL2: %s\n", SDL_GetError());
|
||||||
|
@ -259,8 +293,8 @@ void event_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* events_th
|
||||||
rsp_constants_init();
|
rsp_constants_init();
|
||||||
|
|
||||||
// Notify the caller thread that this thread is ready.
|
// Notify the caller thread that this thread is ready.
|
||||||
events_thread_ready->test_and_set();
|
thread_ready->test_and_set();
|
||||||
events_thread_ready->notify_all();
|
thread_ready->notify_all();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Try to pull an action from the queue
|
// Try to pull an action from the queue
|
||||||
|
@ -268,20 +302,13 @@ void event_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* events_th
|
||||||
if (events_context.action_queue.wait_dequeue_timed(action, 1ms)) {
|
if (events_context.action_queue.wait_dequeue_timed(action, 1ms)) {
|
||||||
// Determine the action type and act on it
|
// Determine the action type and act on it
|
||||||
if (const auto* task_action = std::get_if<SpTaskAction>(&action)) {
|
if (const auto* task_action = std::get_if<SpTaskAction>(&action)) {
|
||||||
if (task_action->task.t.type == M_GFXTASK) {
|
// Tell the game that the RSP completed instantly. This will allow it to queue other task types, but it won't
|
||||||
// (TODO let RT64 do this) Tell the game that the RSP and RDP tasks are complete
|
// start another graphics task until the RDP is also complete. Games usually preserve the RSP inputs until the RDP
|
||||||
RT64SendDL(rdram, &task_action->task);
|
// is finished as well, so sending this early shouldn't be an issue in most cases.
|
||||||
|
// If this causes issues then the logic can be replaced with responding to yield requests.
|
||||||
sp_complete();
|
sp_complete();
|
||||||
|
RT64SendDL(rdram, &task_action->task);
|
||||||
dp_complete();
|
dp_complete();
|
||||||
} else if (task_action->task.t.type == M_AUDTASK) {
|
|
||||||
run_rsp_microcode(rdram, &task_action->task, aspMain);
|
|
||||||
} else if (task_action->task.t.type == M_NJPEGTASK) {
|
|
||||||
run_rsp_microcode(rdram, &task_action->task, njpgdspMain);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Unknown task type: %" PRIu32 "\n", task_action->task.t.type);
|
|
||||||
assert(false);
|
|
||||||
std::quick_exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
} else if (const auto* swap_action = std::get_if<SwapBuffersAction>(&action)) {
|
} else if (const auto* swap_action = std::get_if<SwapBuffersAction>(&action)) {
|
||||||
static volatile int i = 0;
|
static volatile int i = 0;
|
||||||
if (i >= 100) {
|
if (i >= 100) {
|
||||||
|
@ -319,9 +346,16 @@ extern unsigned int VI_V_BURST_REG;
|
||||||
extern unsigned int VI_X_SCALE_REG;
|
extern unsigned int VI_X_SCALE_REG;
|
||||||
extern unsigned int VI_Y_SCALE_REG;
|
extern unsigned int VI_Y_SCALE_REG;
|
||||||
|
|
||||||
|
uint32_t hstart = 0;
|
||||||
uint32_t vi_origin_offset = 320 * sizeof(uint16_t);
|
uint32_t vi_origin_offset = 320 * sizeof(uint16_t);
|
||||||
|
bool vi_black = false;
|
||||||
|
|
||||||
extern "C" void osViSwapBuffer(RDRAM_ARG PTR(void) frameBufPtr) {
|
extern "C" void osViSwapBuffer(RDRAM_ARG PTR(void) frameBufPtr) {
|
||||||
|
if (vi_black) {
|
||||||
|
VI_H_START_REG = 0;
|
||||||
|
} else {
|
||||||
|
VI_H_START_REG = hstart;
|
||||||
|
}
|
||||||
events_context.vi.next_buffer = frameBufPtr;
|
events_context.vi.next_buffer = frameBufPtr;
|
||||||
events_context.action_queue.enqueue(SwapBuffersAction{ osVirtualToPhysical(frameBufPtr) + vi_origin_offset });
|
events_context.action_queue.enqueue(SwapBuffersAction{ osVirtualToPhysical(frameBufPtr) + vi_origin_offset });
|
||||||
}
|
}
|
||||||
|
@ -334,7 +368,7 @@ extern "C" void osViSetMode(RDRAM_ARG PTR(OSViMode) mode_) {
|
||||||
VI_V_SYNC_REG = mode->comRegs.vSync;
|
VI_V_SYNC_REG = mode->comRegs.vSync;
|
||||||
VI_H_SYNC_REG = mode->comRegs.hSync;
|
VI_H_SYNC_REG = mode->comRegs.hSync;
|
||||||
VI_LEAP_REG = mode->comRegs.leap;
|
VI_LEAP_REG = mode->comRegs.leap;
|
||||||
VI_H_START_REG = mode->comRegs.hStart;
|
hstart = mode->comRegs.hStart;
|
||||||
VI_X_SCALE_REG = mode->comRegs.xScale;
|
VI_X_SCALE_REG = mode->comRegs.xScale;
|
||||||
VI_V_CURRENT_LINE_REG = mode->comRegs.vCurrent;
|
VI_V_CURRENT_LINE_REG = mode->comRegs.vCurrent;
|
||||||
|
|
||||||
|
@ -346,6 +380,71 @@ extern "C" void osViSetMode(RDRAM_ARG PTR(OSViMode) mode_) {
|
||||||
VI_INTR_REG = mode->fldRegs[0].vIntr;
|
VI_INTR_REG = mode->fldRegs[0].vIntr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define VI_CTRL_TYPE_16 0x00002
|
||||||
|
#define VI_CTRL_TYPE_32 0x00003
|
||||||
|
#define VI_CTRL_GAMMA_DITHER_ON 0x00004
|
||||||
|
#define VI_CTRL_GAMMA_ON 0x00008
|
||||||
|
#define VI_CTRL_DIVOT_ON 0x00010
|
||||||
|
#define VI_CTRL_SERRATE_ON 0x00040
|
||||||
|
#define VI_CTRL_ANTIALIAS_MASK 0x00300
|
||||||
|
#define VI_CTRL_ANTIALIAS_MODE_1 0x00100
|
||||||
|
#define VI_CTRL_ANTIALIAS_MODE_2 0x00200
|
||||||
|
#define VI_CTRL_ANTIALIAS_MODE_3 0x00300
|
||||||
|
#define VI_CTRL_PIXEL_ADV_MASK 0x01000
|
||||||
|
#define VI_CTRL_PIXEL_ADV_1 0x01000
|
||||||
|
#define VI_CTRL_PIXEL_ADV_2 0x02000
|
||||||
|
#define VI_CTRL_PIXEL_ADV_3 0x03000
|
||||||
|
#define VI_CTRL_DITHER_FILTER_ON 0x10000
|
||||||
|
|
||||||
|
#define OS_VI_GAMMA_ON 0x0001
|
||||||
|
#define OS_VI_GAMMA_OFF 0x0002
|
||||||
|
#define OS_VI_GAMMA_DITHER_ON 0x0004
|
||||||
|
#define OS_VI_GAMMA_DITHER_OFF 0x0008
|
||||||
|
#define OS_VI_DIVOT_ON 0x0010
|
||||||
|
#define OS_VI_DIVOT_OFF 0x0020
|
||||||
|
#define OS_VI_DITHER_FILTER_ON 0x0040
|
||||||
|
#define OS_VI_DITHER_FILTER_OFF 0x0080
|
||||||
|
|
||||||
|
extern "C" void osViSetSpecialFeatures(uint32_t func) {
|
||||||
|
if ((func & OS_VI_GAMMA_ON) != 0) {
|
||||||
|
VI_STATUS_REG |= VI_CTRL_GAMMA_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((func & OS_VI_GAMMA_OFF) != 0) {
|
||||||
|
VI_STATUS_REG &= ~VI_CTRL_GAMMA_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((func & OS_VI_GAMMA_DITHER_ON) != 0) {
|
||||||
|
VI_STATUS_REG |= VI_CTRL_GAMMA_DITHER_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((func & OS_VI_GAMMA_DITHER_OFF) != 0) {
|
||||||
|
VI_STATUS_REG &= ~VI_CTRL_GAMMA_DITHER_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((func & OS_VI_DIVOT_ON) != 0) {
|
||||||
|
VI_STATUS_REG |= VI_CTRL_DIVOT_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((func & OS_VI_DIVOT_OFF) != 0) {
|
||||||
|
VI_STATUS_REG &= ~VI_CTRL_DIVOT_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((func & OS_VI_DITHER_FILTER_ON) != 0) {
|
||||||
|
VI_STATUS_REG |= VI_CTRL_DITHER_FILTER_ON;
|
||||||
|
VI_STATUS_REG &= ~VI_CTRL_ANTIALIAS_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((func & OS_VI_DITHER_FILTER_OFF) != 0) {
|
||||||
|
VI_STATUS_REG &= ~VI_CTRL_DITHER_FILTER_ON;
|
||||||
|
//VI_STATUS_REG |= __osViNext->modep->comRegs.ctrl & VI_CTRL_ANTIALIAS_MASK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void osViBlack(uint8_t active) {
|
||||||
|
vi_black = active;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" PTR(void) osViGetNextFramebuffer() {
|
extern "C" PTR(void) osViGetNextFramebuffer() {
|
||||||
return events_context.vi.next_buffer;
|
return events_context.vi.next_buffer;
|
||||||
}
|
}
|
||||||
|
@ -356,8 +455,17 @@ extern "C" PTR(void) osViGetCurrentFramebuffer() {
|
||||||
|
|
||||||
void Multilibultra::submit_rsp_task(RDRAM_ARG PTR(OSTask) task_) {
|
void Multilibultra::submit_rsp_task(RDRAM_ARG PTR(OSTask) task_) {
|
||||||
OSTask* task = TO_PTR(OSTask, task_);
|
OSTask* task = TO_PTR(OSTask, task_);
|
||||||
|
|
||||||
|
// Send gfx tasks to the graphics action queue
|
||||||
|
if (task->t.type == M_GFXTASK) {
|
||||||
events_context.action_queue.enqueue(SpTaskAction{ *task });
|
events_context.action_queue.enqueue(SpTaskAction{ *task });
|
||||||
}
|
}
|
||||||
|
// Set all other tasks as the RSP task
|
||||||
|
else {
|
||||||
|
events_context.sp_task.store(task);
|
||||||
|
events_context.sp_task.notify_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Multilibultra::send_si_message() {
|
void Multilibultra::send_si_message() {
|
||||||
uint8_t* rdram = events_context.rdram;
|
uint8_t* rdram = events_context.rdram;
|
||||||
|
@ -365,13 +473,16 @@ void Multilibultra::send_si_message() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Multilibultra::init_events(uint8_t* rdram, uint8_t* rom) {
|
void Multilibultra::init_events(uint8_t* rdram, uint8_t* rom) {
|
||||||
std::atomic_flag events_thread_ready;
|
std::atomic_flag gfx_thread_ready;
|
||||||
|
std::atomic_flag task_thread_ready;
|
||||||
events_context.rdram = rdram;
|
events_context.rdram = rdram;
|
||||||
events_context.sp.thread = std::thread{ event_thread_func, rdram, rom, &events_thread_ready };
|
events_context.sp.gfx_thread = std::thread{ gfx_thread_func, rdram, rom, &gfx_thread_ready };
|
||||||
|
events_context.sp.task_thread = std::thread{ task_thread_func, rdram, rom, &task_thread_ready };
|
||||||
|
|
||||||
// Wait for the event thread to be ready before continuing to prevent the game from
|
// Wait for the two sp threads to be ready before continuing to prevent the game from
|
||||||
// running before we're able to handle RSP tasks.
|
// running before we're able to handle RSP tasks.
|
||||||
events_thread_ready.wait(false);
|
gfx_thread_ready.wait(false);
|
||||||
|
task_thread_ready.wait(false);
|
||||||
|
|
||||||
events_context.vi.thread = std::thread{ vi_thread_func };
|
events_context.vi.thread = std::thread{ vi_thread_func };
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,6 +235,8 @@ void osSetEventMesg(RDRAM_ARG OSEvent, PTR(OSMesgQueue), OSMesg);
|
||||||
void osViSetEvent(RDRAM_ARG PTR(OSMesgQueue), OSMesg, u32);
|
void osViSetEvent(RDRAM_ARG PTR(OSMesgQueue), OSMesg, u32);
|
||||||
void osViSwapBuffer(RDRAM_ARG PTR(void) frameBufPtr);
|
void osViSwapBuffer(RDRAM_ARG PTR(void) frameBufPtr);
|
||||||
void osViSetMode(RDRAM_ARG PTR(OSViMode));
|
void osViSetMode(RDRAM_ARG PTR(OSViMode));
|
||||||
|
void osViSetSpecialFeatures(uint32_t func);
|
||||||
|
void osViBlack(uint8_t active);
|
||||||
PTR(void) osViGetNextFramebuffer();
|
PTR(void) osViGetNextFramebuffer();
|
||||||
PTR(void) osViGetCurrentFramebuffer();
|
PTR(void) osViGetCurrentFramebuffer();
|
||||||
u32 osGetCount();
|
u32 osGetCount();
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
#include "recomp.h"
|
#include "recomp.h"
|
||||||
|
|
||||||
extern "C" void osViSetYScale_recomp(uint8_t* rdram, recomp_context * ctx) {
|
extern "C" void osViSetYScale_recomp(uint8_t* rdram, recomp_context * ctx) {
|
||||||
;
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void osViSetXScale_recomp(uint8_t* rdram, recomp_context * ctx) {
|
extern "C" void osViSetXScale_recomp(uint8_t* rdram, recomp_context * ctx) {
|
||||||
;
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void osCreateViManager_recomp(uint8_t* rdram, recomp_context* ctx) {
|
extern "C" void osCreateViManager_recomp(uint8_t* rdram, recomp_context* ctx) {
|
||||||
|
@ -14,11 +14,11 @@ extern "C" void osCreateViManager_recomp(uint8_t* rdram, recomp_context* ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void osViBlack_recomp(uint8_t* rdram, recomp_context* ctx) {
|
extern "C" void osViBlack_recomp(uint8_t* rdram, recomp_context* ctx) {
|
||||||
;
|
osViBlack((uint32_t)ctx->r4);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void osViSetSpecialFeatures_recomp(uint8_t* rdram, recomp_context* ctx) {
|
extern "C" void osViSetSpecialFeatures_recomp(uint8_t* rdram, recomp_context* ctx) {
|
||||||
;
|
osViSetSpecialFeatures((uint32_t)ctx->r4);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void osViGetCurrentFramebuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
|
extern "C" void osViGetCurrentFramebuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
|
||||||
|
|
Loading…
Reference in New Issue