mirror of
https://github.com/N64Recomp/N64ModernRuntime.git
synced 2025-10-30 08:02:29 +00:00
Remove librecomp usage from ultramodern (#23)
* Start setting up user callbacks system * Implement RSP callbacks * move RSP callbacks (and related RSP stuff) to its own file * Move destroy_ui to gfx_callbacks_t and change recomp::start to require rsp_callbacks_t * error_handling.hpp * Remove UserCallbacks in favor of threads_callbacks_t * Add `ultramodern::set_callbacks` and some other cleanups * Move most RSP stuff to librecomp * Rename rsp_stuff.hpp to rsp.hpp * Add rsp.cpp to librecomp cmake file * review * Remove `recomp::message_box` * Fix missing rename
This commit is contained in:
parent
6dce8c2fc2
commit
e3e7024342
17 changed files with 299 additions and 96 deletions
|
|
@ -24,6 +24,7 @@ add_library(librecomp STATIC
|
|||
"${CMAKE_CURRENT_SOURCE_DIR}/src/pi.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/print.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/recomp.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/rsp.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/sp.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/ultra_stubs.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/ultra_translation.cpp"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <filesystem>
|
||||
|
||||
#include "recomp.h"
|
||||
#include "rsp.h"
|
||||
#include <ultramodern/ultramodern.hpp>
|
||||
|
||||
namespace recomp {
|
||||
|
|
@ -38,9 +39,8 @@ namespace recomp {
|
|||
void set_rom_contents(std::vector<uint8_t>&& new_rom);
|
||||
void do_rom_read(uint8_t* rdram, gpr ram_address, uint32_t physical_addr, size_t num_bytes);
|
||||
void do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr);
|
||||
void start(ultramodern::WindowHandle window_handle, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input_callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks);
|
||||
void start_game(std::u8string game_id);
|
||||
void message_box(const char* message);
|
||||
void start(ultramodern::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_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& thread_callbacks, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_);
|
||||
void start_game(const std::u8string& game_id);
|
||||
std::filesystem::path get_app_folder_path();
|
||||
std::u8string current_game_id();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
#ifndef __RSP_H__
|
||||
#define __RSP_H__
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "rsp_vu.h"
|
||||
#include "recomp.h"
|
||||
#include <cstdio>
|
||||
#include "ultramodern/ultra64.h"
|
||||
|
||||
// TODO: Move these to recomp namespace?
|
||||
|
||||
enum class RspExitReason {
|
||||
Invalid,
|
||||
|
|
@ -13,6 +17,8 @@ enum class RspExitReason {
|
|||
Unsupported
|
||||
};
|
||||
|
||||
using RspUcodeFunc = RspExitReason(uint8_t* rdram);
|
||||
|
||||
extern uint8_t dmem[];
|
||||
extern uint16_t rspReciprocals[512];
|
||||
extern uint16_t rspInverseSquareRoots[512];
|
||||
|
|
@ -61,7 +67,7 @@ static inline void RSP_MEM_H_STORE(uint32_t offset, uint32_t addr, uint32_t val)
|
|||
|
||||
#define RSP_ADD32(a, b) \
|
||||
((int32_t)((a) + (b)))
|
||||
|
||||
|
||||
#define RSP_SUB32(a, b) \
|
||||
((int32_t)((a) - (b)))
|
||||
|
||||
|
|
@ -91,4 +97,27 @@ static inline void dma_dmem_to_rdram(uint8_t* rdram, uint32_t dmem_addr, uint32_
|
|||
}
|
||||
}
|
||||
|
||||
namespace recomp {
|
||||
namespace rsp {
|
||||
struct callbacks_t {
|
||||
using get_rsp_microcode_t = RspUcodeFunc*(const OSTask* task);
|
||||
|
||||
/**
|
||||
* Return a function pointer to the corresponding RSP microcode function for the given `task_type`.
|
||||
*
|
||||
* The full OSTask (`task` parameter) is passed in case the `task_type` number is not enough information to distinguish out the exact microcode function.
|
||||
*
|
||||
* This function is allowed to return `nullptr` if no microcode matches the specified task. In this case a message will be printed to stderr and the program will exit.
|
||||
*/
|
||||
get_rsp_microcode_t* get_rsp_microcode;
|
||||
};
|
||||
|
||||
void set_callbacks(const callbacks_t& callbacks);
|
||||
|
||||
void constants_init();
|
||||
|
||||
bool run_task(uint8_t* rdram, const OSTask* task);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@
|
|||
#include "recomp_overlays.h"
|
||||
#include "recomp_game.h"
|
||||
#include "xxHash/xxh3.h"
|
||||
#include <ultramodern/ultramodern.hpp>
|
||||
#include "ultramodern/ultramodern.hpp"
|
||||
#include "ultramodern/error_handling.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
inline uint32_t byteswap(uint32_t val) {
|
||||
|
|
@ -402,7 +403,7 @@ std::u8string recomp::current_game_id() {
|
|||
return current_game.value();
|
||||
};
|
||||
|
||||
void recomp::start_game(std::u8string game_id) {
|
||||
void recomp::start_game(const std::u8string& game_id) {
|
||||
std::lock_guard<std::mutex> lock(current_game_mutex);
|
||||
current_game = game_id;
|
||||
game_status.store(GameStatus::Running);
|
||||
|
|
@ -412,7 +413,6 @@ bool ultramodern::is_game_started() {
|
|||
return game_status.load() != GameStatus::None;
|
||||
}
|
||||
|
||||
void set_audio_callbacks(const ultramodern::audio_callbacks_t& callbacks);
|
||||
void set_input_callbacks(const ultramodern::input_callbacks_t& callback);
|
||||
|
||||
std::atomic_bool exited = false;
|
||||
|
|
@ -426,9 +426,18 @@ void ultramodern::quit() {
|
|||
current_game.reset();
|
||||
}
|
||||
|
||||
void recomp::start(ultramodern::WindowHandle window_handle, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input_callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks_) {
|
||||
void recomp::start(ultramodern::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_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& thread_callbacks_, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_) {
|
||||
recomp::check_all_stored_roms();
|
||||
set_audio_callbacks(audio_callbacks);
|
||||
|
||||
recomp::rsp::set_callbacks(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, audio_callbacks, input_callbacks, gfx_callbacks_, thread_callbacks_, error_handling_callbacks_);
|
||||
|
||||
set_input_callbacks(input_callbacks);
|
||||
|
||||
ultramodern::gfx_callbacks_t gfx_callbacks = gfx_callbacks_;
|
||||
|
|
@ -467,7 +476,7 @@ void recomp::start(ultramodern::WindowHandle window_handle, const ultramodern::a
|
|||
case GameStatus::Running:
|
||||
{
|
||||
if (!recomp::load_stored_rom(current_game.value())) {
|
||||
recomp::message_box("Error opening stored ROM! Please restart this program.");
|
||||
ultramodern::error_handling::message_box("Error opening stored ROM! Please restart this program.");
|
||||
}
|
||||
|
||||
auto find_it = game_roms.find(current_game.value());
|
||||
|
|
@ -499,6 +508,7 @@ void recomp::start(ultramodern::WindowHandle window_handle, const ultramodern::a
|
|||
gfx_callbacks.update_gfx(gfx_data);
|
||||
}
|
||||
}
|
||||
|
||||
game_thread.join();
|
||||
ultramodern::join_event_threads();
|
||||
ultramodern::join_thread_cleaner_thread();
|
||||
|
|
|
|||
62
librecomp/src/rsp.cpp
Normal file
62
librecomp/src/rsp.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cinttypes>
|
||||
|
||||
#include "rsp.h"
|
||||
|
||||
static recomp::rsp::callbacks_t rsp_callbacks {};
|
||||
|
||||
void recomp::rsp::set_callbacks(const callbacks_t& callbacks) {
|
||||
rsp_callbacks = callbacks;
|
||||
}
|
||||
|
||||
uint8_t dmem[0x1000];
|
||||
uint16_t rspReciprocals[512];
|
||||
uint16_t rspInverseSquareRoots[512];
|
||||
|
||||
// From Ares emulator. For license details, see rsp_vu.h
|
||||
void recomp::rsp::constants_init() {
|
||||
rspReciprocals[0] = u16(~0);
|
||||
for (u16 index = 1; index < 512; index++) {
|
||||
u64 a = index + 512;
|
||||
u64 b = (u64(1) << 34) / a;
|
||||
rspReciprocals[index] = u16((b + 1) >> 8);
|
||||
}
|
||||
|
||||
for (u16 index = 0; index < 512; index++) {
|
||||
u64 a = (index + 512) >> ((index % 2 == 1) ? 1 : 0);
|
||||
u64 b = 1 << 17;
|
||||
//find the largest b where b < 1.0 / sqrt(a)
|
||||
while (a * (b + 1) * (b + 1) < (u64(1) << 44)) b++;
|
||||
rspInverseSquareRoots[index] = u16(b >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Runs a recompiled RSP microcode
|
||||
bool recomp::rsp::run_task(uint8_t* rdram, const OSTask* task) {
|
||||
assert(rsp_callbacks.get_rsp_microcode != nullptr);
|
||||
RspUcodeFunc* ucode_func = rsp_callbacks.get_rsp_microcode(task);
|
||||
|
||||
if (ucode_func == nullptr) {
|
||||
fprintf(stderr, "No registered RSP ucode for %" PRIu32 " (returned `nullptr`)\n", task->t.type);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load the OSTask into DMEM
|
||||
memcpy(&dmem[0xFC0], task, sizeof(OSTask));
|
||||
|
||||
// Load the ucode data into DMEM
|
||||
dma_rdram_to_dmem(rdram, 0x0000, task->t.ucode_data, 0xF80 - 1);
|
||||
|
||||
// Run the ucode
|
||||
RspExitReason exit_reason = ucode_func(rdram);
|
||||
|
||||
// Ensure that the ucode exited correctly
|
||||
if (exit_reason != RspExitReason::Broke) {
|
||||
fprintf(stderr, "RSP ucode %" PRIu32 " exited unexpectedly. exit_reason: %i\n", task->t.type, exit_reason);
|
||||
assert(exit_reason == RspExitReason::Broke);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -11,15 +11,18 @@ set(CMAKE_CXX_EXTENSIONS OFF)
|
|||
|
||||
add_library(ultramodern STATIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/audio.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/error_handling.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/events.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/mesgqueue.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/misc_ultra.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/rsp.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/rt64_layer.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/scheduling.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/task_win32.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/threadqueue.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/threads.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/timer.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/ultrainit.cpp"
|
||||
)
|
||||
|
||||
target_include_directories(ultramodern PUBLIC
|
||||
|
|
@ -43,11 +46,6 @@ target_include_directories(ultramodern PRIVATE
|
|||
"${PROJECT_SOURCE_DIR}/../rt64/src/contrib/nativefiledialog-extended/src/include"
|
||||
)
|
||||
|
||||
# TODO: remove when librecomp is untangled from ultramodern
|
||||
target_include_directories(ultramodern PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/librecomp/include"
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
include(FetchContent)
|
||||
# Fetch SDL2 on windows
|
||||
|
|
|
|||
23
ultramodern/include/ultramodern/error_handling.hpp
Normal file
23
ultramodern/include/ultramodern/error_handling.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef __ERROR_HANDLING_HPP__
|
||||
#define __ERROR_HANDLING_HPP__
|
||||
|
||||
namespace ultramodern {
|
||||
namespace error_handling {
|
||||
struct callbacks_t {
|
||||
using message_box_t = void(const char* msg);
|
||||
|
||||
/**
|
||||
* Show an OS dialog with the given `msg`.
|
||||
*
|
||||
* The `msg` parameter is always non-`nullptr`.
|
||||
*/
|
||||
message_box_t *message_box;
|
||||
};
|
||||
|
||||
void set_callbacks(const callbacks_t& callbacks);
|
||||
|
||||
void message_box(const char* msg);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
25
ultramodern/include/ultramodern/events.hpp
Normal file
25
ultramodern/include/ultramodern/events.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef __EVENTS_HPP__
|
||||
#define __EVENTS_HPP__
|
||||
|
||||
namespace ultramodern {
|
||||
namespace events {
|
||||
struct callbacks_t {
|
||||
using vi_callback_t = void();
|
||||
using gfx_init_callback_t = void();
|
||||
|
||||
/**
|
||||
* Called in each VI.
|
||||
*/
|
||||
vi_callback_t* vi_callback;
|
||||
|
||||
/**
|
||||
* Called before entering the gfx main loop.
|
||||
*/
|
||||
gfx_init_callback_t* gfx_init_callback;
|
||||
};
|
||||
|
||||
void set_callbacks(const callbacks_t& callbacks);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
#ifndef __ULTRAMODERN_RECOMP_UI__
|
||||
#define __ULTRAMODERN_RECOMP_UI__
|
||||
|
||||
namespace recomp {
|
||||
// Currently those functions are expected to be provided by the consumer of this library.
|
||||
// TODO: Change these functions to a callback registering system
|
||||
|
||||
void destroy_ui();
|
||||
void update_supported_options();
|
||||
}
|
||||
|
||||
#endif
|
||||
35
ultramodern/include/ultramodern/rsp.hpp
Normal file
35
ultramodern/include/ultramodern/rsp.hpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef __RSP_STUFF_HPP__
|
||||
#define __RSP_STUFF_HPP__
|
||||
|
||||
// TODO: rename
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "ultra64.h"
|
||||
|
||||
// TODO: Move these to ultramodern namespace?
|
||||
|
||||
namespace ultramodern {
|
||||
namespace rsp {
|
||||
struct callbacks_t {
|
||||
using init_t = void();
|
||||
using run_microcode_t = bool(RDRAM_ARG const OSTask* task);
|
||||
|
||||
init_t* init;
|
||||
|
||||
/**
|
||||
* Executes the given RSP task.
|
||||
*
|
||||
* Returns true if task was executed successfully.
|
||||
*/
|
||||
run_microcode_t* run_task;
|
||||
};
|
||||
|
||||
void set_callbacks(const callbacks_t& callbacks);
|
||||
|
||||
void init();
|
||||
bool run_task(RDRAM_ARG const OSTask* task);
|
||||
};
|
||||
} // namespace ultramodern
|
||||
|
||||
#endif
|
||||
|
|
@ -25,6 +25,10 @@
|
|||
# undef Success
|
||||
#endif
|
||||
|
||||
#include "ultramodern/error_handling.hpp"
|
||||
#include "ultramodern/events.hpp"
|
||||
#include "ultramodern/rsp.hpp"
|
||||
|
||||
struct UltraThreadContext {
|
||||
std::thread host_thread;
|
||||
moodycamel::LightweightSemaphore running;
|
||||
|
|
@ -132,6 +136,7 @@ struct audio_callbacks_t {
|
|||
set_frequency_t* set_frequency;
|
||||
};
|
||||
|
||||
// TODO: These functions are currently called by librecomp, but will get called by ultramodern in the future
|
||||
// Input
|
||||
struct input_callbacks_t {
|
||||
using poll_input_t = void(void);
|
||||
|
|
@ -142,21 +147,32 @@ struct input_callbacks_t {
|
|||
set_rumble_t* set_rumble;
|
||||
};
|
||||
|
||||
// TODO: Most of the members of this struct are not used by ultramodern. Should we move them to librecomp instead?
|
||||
struct gfx_callbacks_t {
|
||||
using gfx_data_t = void*;
|
||||
using create_gfx_t = gfx_data_t();
|
||||
using create_window_t = WindowHandle(gfx_data_t);
|
||||
using update_gfx_t = void(gfx_data_t);
|
||||
|
||||
create_gfx_t* create_gfx;
|
||||
create_window_t* create_window;
|
||||
update_gfx_t* update_gfx;
|
||||
};
|
||||
|
||||
bool is_game_started();
|
||||
void quit();
|
||||
void join_event_threads();
|
||||
void join_thread_cleaner_thread();
|
||||
void join_saving_thread();
|
||||
|
||||
void set_audio_callbacks(const audio_callbacks_t& callbacks);
|
||||
|
||||
/**
|
||||
* Register all the callbacks used by `ultramodern`, most of them being optional.
|
||||
*
|
||||
* It must be called only once and it must be called before `ultramodern::preinit`.
|
||||
*/
|
||||
void set_callbacks(const rsp::callbacks_t& rsp_callbacks, const audio_callbacks_t& audio_callbacks, const input_callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks, const events::callbacks_t& events_callbacks, const error_handling::callbacks_t& error_handling_callbacks);
|
||||
} // namespace ultramodern
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ static uint32_t sample_rate = 48000;
|
|||
|
||||
static ultramodern::audio_callbacks_t audio_callbacks;
|
||||
|
||||
void set_audio_callbacks(const ultramodern::audio_callbacks_t& callbacks) {
|
||||
void ultramodern::set_audio_callbacks(const ultramodern::audio_callbacks_t& callbacks) {
|
||||
audio_callbacks = callbacks;
|
||||
}
|
||||
|
||||
|
|
|
|||
19
ultramodern/src/error_handling.cpp
Normal file
19
ultramodern/src/error_handling.cpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include <cstdio>
|
||||
|
||||
#include "ultramodern/error_handling.hpp"
|
||||
|
||||
static ultramodern::error_handling::callbacks_t error_handling_callbacks{};
|
||||
|
||||
void ultramodern::error_handling::set_callbacks(const ultramodern::error_handling::callbacks_t& callbacks) {
|
||||
error_handling_callbacks = callbacks;
|
||||
}
|
||||
|
||||
void ultramodern::error_handling::message_box(const char* msg) {
|
||||
// We print the message to stderr since the user may not have provided a message_box callback
|
||||
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
|
||||
if (error_handling_callbacks.message_box != nullptr) {
|
||||
error_handling_callbacks.message_box(msg);
|
||||
}
|
||||
}
|
||||
|
|
@ -12,14 +12,16 @@
|
|||
#include "blockingconcurrentqueue.h"
|
||||
|
||||
#include "ultra64.h"
|
||||
#include "ultramodern.hpp"
|
||||
#include "ultramodern/ultramodern.hpp"
|
||||
#include "config.hpp"
|
||||
#include "rt64_layer.h"
|
||||
#include "recomp_ui.h"
|
||||
#include "recomp.h"
|
||||
#include "recomp_game.h"
|
||||
#include "recomp_input.h"
|
||||
#include "rsp.h"
|
||||
#include "ultramodern/rsp.hpp"
|
||||
|
||||
static ultramodern::events::callbacks_t events_callbacks{};
|
||||
|
||||
void ultramodern::events::set_callbacks(const ultramodern::events::callbacks_t& callbacks) {
|
||||
events_callbacks = callbacks;
|
||||
}
|
||||
|
||||
struct SpTaskAction {
|
||||
OSTask task;
|
||||
|
|
@ -116,7 +118,7 @@ void vi_thread_func() {
|
|||
// the game to generate new audio and gfx lists.
|
||||
ultramodern::set_native_thread_priority(ultramodern::ThreadPriority::Critical);
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
|
||||
int remaining_retraces = events_context.vi.retrace_count;
|
||||
|
||||
while (!exited) {
|
||||
|
|
@ -176,9 +178,10 @@ void vi_thread_func() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO move recomp code out of ultramodern.
|
||||
recomp::update_rumble();
|
||||
|
||||
if (events_callbacks.vi_callback != nullptr) {
|
||||
events_callbacks.vi_callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -194,45 +197,6 @@ void dp_complete() {
|
|||
osSendMesg(PASS_RDRAM events_context.dp.mq, events_context.dp.msg, OS_MESG_NOBLOCK);
|
||||
}
|
||||
|
||||
uint8_t dmem[0x1000];
|
||||
uint16_t rspReciprocals[512];
|
||||
uint16_t rspInverseSquareRoots[512];
|
||||
|
||||
using RspUcodeFunc = RspExitReason(uint8_t* rdram);
|
||||
extern RspUcodeFunc njpgdspMain;
|
||||
extern RspUcodeFunc aspMain;
|
||||
|
||||
// From Ares emulator. For license details, see rsp_vu.h
|
||||
void rsp_constants_init() {
|
||||
rspReciprocals[0] = u16(~0);
|
||||
for (u16 index = 1; index < 512; index++) {
|
||||
u64 a = index + 512;
|
||||
u64 b = (u64(1) << 34) / a;
|
||||
rspReciprocals[index] = u16((b + 1) >> 8);
|
||||
}
|
||||
|
||||
for (u16 index = 0; index < 512; index++) {
|
||||
u64 a = (index + 512) >> ((index % 2 == 1) ? 1 : 0);
|
||||
u64 b = 1 << 17;
|
||||
//find the largest b where b < 1.0 / sqrt(a)
|
||||
while (a * (b + 1) * (b + 1) < (u64(1) << 44)) b++;
|
||||
rspInverseSquareRoots[index] = u16(b >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Runs a recompiled RSP microcode
|
||||
void run_rsp_microcode(uint8_t* rdram, const OSTask* task, RspUcodeFunc* ucode_func) {
|
||||
// Load the OSTask into DMEM
|
||||
memcpy(&dmem[0xFC0], task, sizeof(OSTask));
|
||||
// Load the ucode data into DMEM
|
||||
dma_rdram_to_dmem(rdram, 0x0000, task->t.ucode_data, 0xF80 - 1);
|
||||
// Run the ucode
|
||||
RspExitReason exit_reason = ucode_func(rdram);
|
||||
// Ensure that the ucode exited correctly
|
||||
assert(exit_reason == RspExitReason::Broke);
|
||||
}
|
||||
|
||||
|
||||
void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_ready) {
|
||||
ultramodern::set_native_thread_name("SP Task Thread");
|
||||
ultramodern::set_native_thread_priority(ultramodern::ThreadPriority::Normal);
|
||||
|
|
@ -249,15 +213,9 @@ void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_r
|
|||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
if (!ultramodern::rsp::run_task(PASS_RDRAM task)) {
|
||||
fprintf(stderr, "Failed to execute task type: %" PRIu32 "\n", task->t.type);
|
||||
assert(false);
|
||||
std::quick_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
|
@ -323,10 +281,11 @@ void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_re
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO move recomp code out of ultramodern.
|
||||
recomp::update_supported_options();
|
||||
if (events_callbacks.gfx_init_callback != nullptr) {
|
||||
events_callbacks.gfx_init_callback();
|
||||
}
|
||||
|
||||
rsp_constants_init();
|
||||
ultramodern::rsp::init();
|
||||
|
||||
// Notify the caller thread that this thread is ready.
|
||||
thread_ready->signal();
|
||||
|
|
@ -372,8 +331,7 @@ void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_re
|
|||
}
|
||||
}
|
||||
}
|
||||
// TODO move recomp code out of ultramodern.
|
||||
recomp::destroy_ui();
|
||||
|
||||
rt64.shutdown();
|
||||
}
|
||||
|
||||
|
|
@ -571,7 +529,7 @@ void ultramodern::init_events(RDRAM_ARG ultramodern::WindowHandle window_handle)
|
|||
events_context.rdram = rdram;
|
||||
events_context.sp.gfx_thread = std::thread{ gfx_thread_func, rdram, &gfx_thread_ready, window_handle };
|
||||
events_context.sp.task_thread = std::thread{ task_thread_func, rdram, &task_thread_ready };
|
||||
|
||||
|
||||
// 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.
|
||||
gfx_thread_ready.wait();
|
||||
|
|
@ -580,9 +538,11 @@ void ultramodern::init_events(RDRAM_ARG ultramodern::WindowHandle window_handle)
|
|||
ultramodern::RT64SetupResult setup_result = rt64_setup_result.load();
|
||||
if (rt64_setup_result != ultramodern::RT64SetupResult::Success) {
|
||||
auto show_rt64_error = [](const std::string& msg) {
|
||||
// TODO move recomp code out of ultramodern (message boxes).
|
||||
recomp::message_box(("An error has been encountered on startup: " + msg).c_str());
|
||||
std::string error_msg = "An error has been encountered on startup: " + msg;
|
||||
|
||||
ultramodern::error_handling::message_box(error_msg.c_str());
|
||||
};
|
||||
|
||||
const std::string driver_os_suffix = "\nPlease make sure your GPU drivers and your OS are up to date.";
|
||||
switch (rt64_setup_result) {
|
||||
case ultramodern::RT64SetupResult::DynamicLibrariesNotFound:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#include "ultra64.h"
|
||||
#include "ultramodern.hpp"
|
||||
#include "recomp.h"
|
||||
|
||||
struct QueuedMessage {
|
||||
PTR(OSMesgQueue) mq;
|
||||
|
|
|
|||
22
ultramodern/src/rsp.cpp
Normal file
22
ultramodern/src/rsp.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include "ultramodern/rsp.hpp"
|
||||
|
||||
static ultramodern::rsp::callbacks_t rsp_callbacks {};
|
||||
|
||||
void ultramodern::rsp::set_callbacks(const callbacks_t& callbacks) {
|
||||
rsp_callbacks = callbacks;
|
||||
}
|
||||
|
||||
void ultramodern::rsp::init() {
|
||||
if (rsp_callbacks.init != nullptr) {
|
||||
rsp_callbacks.init();
|
||||
}
|
||||
}
|
||||
|
||||
bool ultramodern::rsp::run_task(RDRAM_ARG const OSTask* task) {
|
||||
assert(rsp_callbacks.run_task != nullptr);
|
||||
|
||||
return rsp_callbacks.run_task(PASS_RDRAM task);
|
||||
}
|
||||
|
|
@ -1,6 +1,22 @@
|
|||
#include "ultra64.h"
|
||||
#include "ultramodern.hpp"
|
||||
|
||||
void ultramodern::set_callbacks(
|
||||
const rsp::callbacks_t& rsp_callbacks,
|
||||
const audio_callbacks_t& audio_callbacks,
|
||||
const input_callbacks_t& input_callbacks,
|
||||
const gfx_callbacks_t& gfx_callbacks,
|
||||
const events::callbacks_t& thread_callbacks,
|
||||
const error_handling::callbacks_t& error_handling_callbacks
|
||||
) {
|
||||
ultramodern::rsp::set_callbacks(rsp_callbacks);
|
||||
ultramodern::set_audio_callbacks(audio_callbacks);
|
||||
(void)input_callbacks; // nothing yet
|
||||
(void)gfx_callbacks; // nothing yet
|
||||
ultramodern::events::set_callbacks(thread_callbacks);
|
||||
ultramodern::error_handling::set_callbacks(error_handling_callbacks);
|
||||
}
|
||||
|
||||
void ultramodern::preinit(RDRAM_ARG ultramodern::WindowHandle window_handle) {
|
||||
ultramodern::set_main_thread();
|
||||
ultramodern::init_events(PASS_RDRAM window_handle);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue