Add overlays (#5)

This commit is contained in:
dcvz 2024-05-24 21:44:11 +02:00
parent 32632ab2ff
commit 72bc656c5e
7 changed files with 102 additions and 48 deletions

View file

@ -29,7 +29,15 @@ add_library(librecomp STATIC
"${CMAKE_CURRENT_SOURCE_DIR}/src/ultra_translation.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/vi.cpp")
target_include_directories(librecomp PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_include_directories(librecomp PRIVATE "${CMAKE_SOURCE_DIR}/rt64/src/contrib")
target_include_directories(librecomp PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_SOURCE_DIR}/ultramodern/include"
"${CMAKE_SOURCE_DIR}/thirdparty/concurrentqueue"
)
target_include_directories(librecomp PRIVATE
"${CMAKE_SOURCE_DIR}/rt64/src/contrib"
)
target_compile_options(librecomp PRIVATE -Wno-deprecated-declarations)
target_link_libraries(librecomp PRIVATE ultramodern)

View file

@ -256,7 +256,7 @@ recomp_func_t* get_function(int32_t vram);
#define LOOKUP_FUNC(val) \
get_function((int32_t)(val))
extern int32_t section_addresses[];
extern int32_t* section_addresses;
#define LO16(x) \
((x) & 0xFFFF)

View file

@ -43,6 +43,10 @@ namespace recomp {
void message_box(const char* message);
std::filesystem::path get_app_folder_path();
std::u8string current_game_id();
// TODO: implement both
const std::u8string& get_program_id();
void set_program_id(const std::u8string& program_id);
}
#endif

View file

@ -2,9 +2,26 @@
#define __RECOMP_OVERLAYS_H__
#include <cstdint>
#include "sections.h"
namespace recomp {
struct overlay_section_table_data_t {
SectionTableEntry* code_sections;
size_t num_code_sections;
size_t total_num_sections;
};
struct overlays_by_index_t {
int* table;
size_t len;
};
extern void register_overlays(const overlay_section_table_data_t& sections, const overlays_by_index_t& overlays);
extern void register_patch_section(SectionTableEntry* code_sections);
};
extern "C" void load_overlays(uint32_t rom, int32_t ram_addr, uint32_t size);
extern "C" void unload_overlays(int32_t ram_addr, uint32_t size);
void init_overlays();
#endif
#endif

View file

@ -1,13 +1,19 @@
#include <unordered_map>
#include <algorithm>
#include <cstdio>
#include <unordered_map>
#include <vector>
#include "recomp.h"
#include "recomp_overlays.h"
#include "../RecompiledFuncs/recomp_overlays.inl"
#include "sections.h"
constexpr size_t num_code_sections = ARRLEN(section_table);
static recomp::overlay_section_table_data_t sections_info {};
static recomp::overlays_by_index_t overlays_info {};
// SectionTableEntry sections[] defined in recomp_overlays.inl
void recomp::register_overlays(const recomp::overlay_section_table_data_t& sections, const recomp::overlays_by_index_t& overlays) {
sections_info = sections;
overlays_info = overlays;
}
struct LoadedSection {
int32_t loaded_ram_addr;
@ -27,11 +33,13 @@ std::vector<LoadedSection> loaded_sections{};
std::unordered_map<int32_t, recomp_func_t*> func_map{};
void load_overlay(size_t section_table_index, int32_t ram) {
const SectionTableEntry& section = section_table[section_table_index];
const SectionTableEntry& section = sections_info.code_sections[section_table_index];
for (size_t function_index = 0; function_index < section.num_funcs; function_index++) {
const FuncEntry& func = section.funcs[function_index];
func_map[ram + func.offset] = func.func;
}
loaded_sections.emplace_back(ram, section_table_index);
section_addresses[section.index] = ram;
}
@ -45,33 +53,31 @@ void load_special_overlay(const SectionTableEntry& section, int32_t ram) {
extern "C" {
int32_t section_addresses[num_sections];
int32_t* section_addresses = nullptr;
}
extern "C" void load_overlays(uint32_t rom, int32_t ram_addr, uint32_t size) {
// Search for the first section that's included in the loaded rom range
// Sections were sorted by `init_overlays` so we can use the bounds functions
auto lower = std::lower_bound(&section_table[0], &section_table[num_code_sections], rom,
auto lower = std::lower_bound(&sections_info.code_sections[0], &sections_info.code_sections[sections_info.num_code_sections], rom,
[](const SectionTableEntry& entry, uint32_t addr) {
return entry.rom_addr < addr;
}
);
auto upper = std::upper_bound(&section_table[0], &section_table[num_code_sections], (uint32_t)(rom + size),
auto upper = std::upper_bound(&sections_info.code_sections[0], &sections_info.code_sections[sections_info.num_code_sections], (uint32_t)(rom + size),
[](uint32_t addr, const SectionTableEntry& entry) {
return addr < entry.size + entry.rom_addr;
}
);
// Load the overlays that were found
for (auto it = lower; it != upper; ++it) {
load_overlay(std::distance(&section_table[0], it), it->rom_addr - rom + ram_addr);
load_overlay(std::distance(&sections_info.code_sections[0], it), it->rom_addr - rom + ram_addr);
}
}
extern "C" void unload_overlays(int32_t ram_addr, uint32_t size);
extern "C" void unload_overlay_by_id(uint32_t id) {
uint32_t section_table_index = overlay_sections_by_index[id];
const SectionTableEntry& section = section_table[section_table_index];
uint32_t section_table_index = overlays_info.table[id];
const SectionTableEntry& section = sections_info.code_sections[section_table_index];
auto find_it = std::find_if(loaded_sections.begin(), loaded_sections.end(), [section_table_index](const LoadedSection& s) { return s.section_table_index == section_table_index; });
@ -90,8 +96,8 @@ extern "C" void unload_overlay_by_id(uint32_t id) {
}
extern "C" void load_overlay_by_id(uint32_t id, uint32_t ram_addr) {
uint32_t section_table_index = overlay_sections_by_index[id];
const SectionTableEntry& section = section_table[section_table_index];
uint32_t section_table_index = overlays_info.table[id];
const SectionTableEntry& section = sections_info.code_sections[section_table_index];
int32_t prev_address = section_addresses[section.index];
if (/*ram_addr >= 0x80000000 && ram_addr < 0x81000000) {*/ prev_address == section.ram_addr) {
load_overlay(section_table_index, ram_addr);
@ -105,7 +111,7 @@ extern "C" void load_overlay_by_id(uint32_t id, uint32_t ram_addr) {
extern "C" void unload_overlays(int32_t ram_addr, uint32_t size) {
for (auto it = loaded_sections.begin(); it != loaded_sections.end();) {
const auto& section = section_table[it->section_table_index];
const auto& section = sections_info.code_sections[it->section_table_index];
// Check if the unloaded region overlaps with the loaded section
if (ram_addr < (it->loaded_ram_addr + section.size) && (ram_addr + size) >= it->loaded_ram_addr) {
@ -139,12 +145,14 @@ extern "C" void unload_overlays(int32_t ram_addr, uint32_t size) {
void load_patch_functions();
void init_overlays() {
for (size_t section_index = 0; section_index < num_code_sections; section_index++) {
section_addresses[section_table[section_index].index] = section_table[section_index].ram_addr;
section_addresses = (int32_t *)malloc(sections_info.total_num_sections * sizeof(int32_t));
for (size_t section_index = 0; section_index < sections_info.total_num_sections; section_index++) {
section_addresses[sections_info.code_sections[section_index].index] = sections_info.code_sections[section_index].ram_addr;
}
// Sort the executable sections by rom address
std::sort(&section_table[0], &section_table[num_code_sections],
std::sort(&sections_info.code_sections[0], &sections_info.code_sections[sections_info.num_code_sections],
[](const SectionTableEntry& a, const SectionTableEntry& b) {
return a.rom_addr < b.rom_addr;
}

View file

@ -2,10 +2,17 @@
#include <algorithm>
#include <vector>
#include "recomp.h"
#include "../../RecompiledPatches/recomp_overlays.inl"
#include "sections.h"
#include "recomp_overlays.h"
static SectionTableEntry* code_sections = nullptr;
void load_special_overlay(const SectionTableEntry& section, int32_t ram);
void load_patch_functions() {
load_special_overlay(section_table[0], section_table[0].ram_addr);
void register_patch_section(SectionTableEntry* sections) {
code_sections = sections;
}
void load_patch_functions() {
load_special_overlay(code_sections[0], code_sections[0].ram_addr);
}

View file

@ -1,6 +1,3 @@
#ifdef _WIN32
#include <Windows.h>
#endif
#include <cstdio>
#include <cstdlib>
#include <cstring>
@ -10,12 +7,19 @@
#include <unordered_set>
#include <fstream>
#include <iostream>
#include <optional>
#ifdef _WIN32
#include <Windows.h>
#elif defined(__linux__)
#include <pwd.h>
#endif
#include "recomp.h"
#include "recomp_overlays.h"
#include "recomp_game.h"
#include "xxHash/xxh3.h"
#include <ultramodern/ultramodern.hpp>
//#include "../../RecompiledPatches/patches_bin.h"
#ifdef _MSC_VER
inline uint32_t byteswap(uint32_t val) {
@ -98,7 +102,7 @@ std::filesystem::path recomp::get_app_folder_path() {
PWSTR known_path = NULL;
HRESULT result = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &known_path);
if (result == S_OK) {
recomp_dir = std::filesystem::path{known_path} / recomp::program_id;
recomp_dir = std::filesystem::path{known_path} / recomp::get_program_id();
}
CoTaskMemFree(known_path);
@ -110,7 +114,7 @@ std::filesystem::path recomp::get_app_folder_path() {
}
if (homedir != nullptr) {
recomp_dir = std::filesystem::path{homedir} / (std::u8string{u8".config/"} + std::u8string{recomp::program_id});
recomp_dir = std::filesystem::path{homedir} / (std::u8string{u8".config/"} + recomp::get_program_id());
}
#endif
@ -448,9 +452,9 @@ void recomp::start(ultramodern::WindowHandle window_handle, const ultramodern::a
std::thread game_thread{[](ultramodern::WindowHandle window_handle, uint8_t* rdram) {
debug_printf("[Recomp] Starting\n");
ultramodern::set_native_thread_name("Game Start Thread");
ultramodern::preinit(rdram, window_handle);
game_status.wait(GameStatus::None);
@ -459,25 +463,31 @@ void recomp::start(ultramodern::WindowHandle window_handle, const ultramodern::a
switch (game_status.load()) {
// TODO refactor this to allow a project to specify what entrypoint function to run for a give game.
case GameStatus::Running:
if (!recomp::load_stored_rom(current_game.value())) {
recomp::message_box("Error opening stored ROM! Please restart this program.");
{
if (!recomp::load_stored_rom(current_game.value())) {
recomp::message_box("Error opening stored ROM! Please restart this program.");
}
auto find_it = game_roms.find(current_game.value());
const recomp::GameEntry& game_entry = find_it->second;
ultramodern::load_shader_cache(game_entry.cache_data);
init(rdram, &context);
try {
recomp_entrypoint(rdram, &context);
} catch (ultramodern::thread_terminated& terminated) {
}
}
auto find_it = game_roms.find(current_game.value());
const recomp::GameEntry& game_entry = find_it->second;
ultramodern::load_shader_cache(game_entry.cache_data);
init(rdram, &context);
try {
recomp_entrypoint(rdram, &context);
} catch (ultramodern::thread_terminated& terminated) {
}
break;
case GameStatus::Quit:
break;
case GameStatus::None:
break;
}
debug_printf("[Recomp] Quitting\n");
}, window_handle, rdram_buffer.get()};