Merge branch 'main' into feat/generic-game

# Conflicts:
#	CMakeLists.txt
#	ultramodern/CMakeLists.txt
This commit is contained in:
dcvz 2024-05-21 21:39:33 +02:00
commit 8359984feb
18 changed files with 9551 additions and 176 deletions

9
.gitignore vendored Normal file
View file

@ -0,0 +1,9 @@
build/
temp/
.vscode/
*.o
*.elf
*.z64
*.n64
*.v64

View file

@ -1,11 +1,12 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.20)
project(N64ModernRuntime) project(N64ModernRuntime)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_CXX_STANDARD_REQUIRED True)
add_subdirectory(librecomp)
add_subdirectory(ultramodern) add_subdirectory(ultramodern)
add_subdirectory(librecomp)
set(RT64_STATIC TRUE) set(RT64_STATIC TRUE)
add_subdirectory(rt64) add_subdirectory(rt64)

View file

@ -1,6 +1,6 @@
# N64 Modern Runtime # N64 Modern Runtime
> Note > Note
This repo is a WIP as files are moved out of Zelda64Recomp and genericized. It cannot be used directly in its current state. This repo is a WIP as files are moved out of Zelda64Recomp and genericized. It cannot be used directly in its current state.
This repo contains two libraries: Ultramodern and Librecomp. This repo contains two libraries: Ultramodern and Librecomp.

View file

@ -20,13 +20,12 @@
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
#include <cstdint> #include <cstdint>
#define ARCHITECTURE_AMD64 #if defined(__x86_64__) || defined(_M_X64)
#define ARCHITECTURE_SUPPORTS_SSE4_1 1 #define ARCHITECTURE_SUPPORTS_SSE4_1 1
#if defined(ARCHITECTURE_AMD64)
#include <nmmintrin.h> #include <nmmintrin.h>
using v128 = __m128i; using v128 = __m128i;
#elif defined(ARCHITECTURE_ARM64) #elif defined(__aarch64__) || defined(_M_ARM64)
#define ARCHITECTURE_SUPPORTS_SSE4_1 1
#include <sse2neon.h> #include <sse2neon.h>
using v128 = __m128i; using v128 = __m128i;
#endif #endif

View file

@ -1,30 +1,30 @@
#include "recomp.h" #include "recomp.h"
enum class RDPStatusBit { enum class RDPStatusBit {
XbusDmem = 0, XbusDmem = 0,
Freeze = 1, Freeze = 1,
Flush = 2, Flush = 2,
CommandBusy = 6, CommandBusy = 6,
BufferReady = 7, BufferReady = 7,
DmaBusy = 8, DmaBusy = 8,
EndValid = 9, EndValid = 9,
StartValid = 10, StartValid = 10,
}; };
constexpr void update_bit(uint32_t& state, uint32_t flags, RDPStatusBit bit) { constexpr void update_bit(uint32_t& state, uint32_t flags, RDPStatusBit bit) {
int set_bit_pos = (int)bit * 2 + 0; int set_bit_pos = (int)bit * 2 + 0;
int reset_bit_pos = (int)bit * 2 + 1; int reset_bit_pos = (int)bit * 2 + 1;
bool set = (flags & (1U << set_bit_pos)) != 0; bool set = (flags & (1U << set_bit_pos)) != 0;
bool reset = (flags & (1U << reset_bit_pos)) != 0; bool reset = (flags & (1U << reset_bit_pos)) != 0;
if (set ^ reset) { if (set ^ reset) {
if (set) { if (set) {
state |= (1U << (int)bit); state |= (1U << (int)bit);
} }
else { else {
state &= ~(1U << (int)bit); state &= ~(1U << (int)bit);
} }
} }
} }
uint32_t rdp_state = 1 << (int)RDPStatusBit::BufferReady; uint32_t rdp_state = 1 << (int)RDPStatusBit::BufferReady;
@ -34,11 +34,11 @@ extern "C" void osDpSetNextBuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
} }
extern "C" void osDpGetStatus_recomp(uint8_t* rdram, recomp_context* ctx) { extern "C" void osDpGetStatus_recomp(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = rdp_state; ctx->r2 = rdp_state;
} }
extern "C" void osDpSetStatus_recomp(uint8_t* rdram, recomp_context* ctx) { extern "C" void osDpSetStatus_recomp(uint8_t* rdram, recomp_context* ctx) {
update_bit(rdp_state, ctx->r4, RDPStatusBit::XbusDmem); update_bit(rdp_state, ctx->r4, RDPStatusBit::XbusDmem);
update_bit(rdp_state, ctx->r4, RDPStatusBit::Freeze); update_bit(rdp_state, ctx->r4, RDPStatusBit::Freeze);
update_bit(rdp_state, ctx->r4, RDPStatusBit::Flush); update_bit(rdp_state, ctx->r4, RDPStatusBit::Flush);
} }

View file

@ -21,22 +21,22 @@ void save_clear(uint32_t start, uint32_t size, char value);
std::array<char, page_size> write_buffer; std::array<char, page_size> write_buffer;
extern "C" void osFlashInit_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osFlashInit_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = ultramodern::flash_handle; ctx->r2 = ultramodern::flash_handle;
} }
extern "C" void osFlashReadStatus_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osFlashReadStatus_recomp(uint8_t * rdram, recomp_context * ctx) {
PTR(u8) flash_status = ctx->r4; PTR(u8) flash_status = ctx->r4;
MEM_B(0, flash_status) = 0; MEM_B(0, flash_status) = 0;
} }
extern "C" void osFlashReadId_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osFlashReadId_recomp(uint8_t * rdram, recomp_context * ctx) {
PTR(u32) flash_type = ctx->r4; PTR(u32) flash_type = ctx->r4;
PTR(u32) flash_maker = ctx->r5; PTR(u32) flash_maker = ctx->r5;
// Mimic a real flash chip's type and maker, as some games actually check if one is present. // Mimic a real flash chip's type and maker, as some games actually check if one is present.
MEM_W(0, flash_type) = 0x11118001; MEM_W(0, flash_type) = 0x11118001;
MEM_W(0, flash_maker) = 0x00C2001E; MEM_W(0, flash_maker) = 0x00C2001E;
} }
extern "C" void osFlashClearStatus_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osFlashClearStatus_recomp(uint8_t * rdram, recomp_context * ctx) {
@ -44,98 +44,98 @@ extern "C" void osFlashClearStatus_recomp(uint8_t * rdram, recomp_context * ctx)
} }
extern "C" void osFlashAllErase_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osFlashAllErase_recomp(uint8_t * rdram, recomp_context * ctx) {
save_clear(0, ultramodern::save_size, 0xFF); save_clear(0, ultramodern::save_size, 0xFF);
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void osFlashAllEraseThrough_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osFlashAllEraseThrough_recomp(uint8_t * rdram, recomp_context * ctx) {
save_clear(0, ultramodern::save_size, 0xFF); save_clear(0, ultramodern::save_size, 0xFF);
ctx->r2 = 0; ctx->r2 = 0;
} }
// This function is named sector but really means page. // This function is named sector but really means page.
extern "C" void osFlashSectorErase_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osFlashSectorErase_recomp(uint8_t * rdram, recomp_context * ctx) {
uint32_t page_num = (uint32_t)ctx->r4; uint32_t page_num = (uint32_t)ctx->r4;
// Prevent out of bounds erase // Prevent out of bounds erase
if (page_num >= page_count) { if (page_num >= page_count) {
ctx->r2 = -1; ctx->r2 = -1;
return; return;
} }
save_clear(page_num * page_size, page_size, 0xFF); save_clear(page_num * page_size, page_size, 0xFF);
ctx->r2 = 0; ctx->r2 = 0;
} }
// Same naming issue as above. // Same naming issue as above.
extern "C" void osFlashSectorEraseThrough_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osFlashSectorEraseThrough_recomp(uint8_t * rdram, recomp_context * ctx) {
uint32_t page_num = (uint32_t)ctx->r4; uint32_t page_num = (uint32_t)ctx->r4;
// Prevent out of bounds erase // Prevent out of bounds erase
if (page_num >= page_count) { if (page_num >= page_count) {
ctx->r2 = -1; ctx->r2 = -1;
return; return;
} }
save_clear(page_num * page_size, page_size, 0xFF); save_clear(page_num * page_size, page_size, 0xFF);
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void osFlashCheckEraseEnd_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osFlashCheckEraseEnd_recomp(uint8_t * rdram, recomp_context * ctx) {
// All erases are blocking in this implementation, so this should always return OK. // All erases are blocking in this implementation, so this should always return OK.
ctx->r2 = 0; // FLASH_STATUS_ERASE_OK ctx->r2 = 0; // FLASH_STATUS_ERASE_OK
} }
extern "C" void osFlashWriteBuffer_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osFlashWriteBuffer_recomp(uint8_t * rdram, recomp_context * ctx) {
OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r4); OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r4);
int32_t pri = ctx->r5; int32_t pri = ctx->r5;
PTR(void) dramAddr = ctx->r6; PTR(void) dramAddr = ctx->r6;
PTR(OSMesgQueue) mq = ctx->r7; PTR(OSMesgQueue) mq = ctx->r7;
// Copy the input data into the write buffer // Copy the input data into the write buffer
for (size_t i = 0; i < page_size; i++) { for (size_t i = 0; i < page_size; i++) {
write_buffer[i] = MEM_B(i, dramAddr); write_buffer[i] = MEM_B(i, dramAddr);
} }
// Send the message indicating write completion // Send the message indicating write completion
osSendMesg(PASS_RDRAM mq, 0, OS_MESG_NOBLOCK); osSendMesg(PASS_RDRAM mq, 0, OS_MESG_NOBLOCK);
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void osFlashWriteArray_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osFlashWriteArray_recomp(uint8_t * rdram, recomp_context * ctx) {
uint32_t page_num = ctx->r4; uint32_t page_num = ctx->r4;
// Copy the write buffer into the save file // Copy the write buffer into the save file
save_write_ptr(write_buffer.data(), page_num * page_size, page_size); save_write_ptr(write_buffer.data(), page_num * page_size, page_size);
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void osFlashReadArray_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osFlashReadArray_recomp(uint8_t * rdram, recomp_context * ctx) {
OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r4); OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r4);
int32_t pri = ctx->r5; int32_t pri = ctx->r5;
uint32_t page_num = ctx->r6; uint32_t page_num = ctx->r6;
PTR(void) dramAddr = ctx->r7; PTR(void) dramAddr = ctx->r7;
uint32_t n_pages = MEM_W(0x10, ctx->r29); uint32_t n_pages = MEM_W(0x10, ctx->r29);
PTR(OSMesgQueue) mq = MEM_W(0x14, ctx->r29); PTR(OSMesgQueue) mq = MEM_W(0x14, ctx->r29);
uint32_t offset = page_num * page_size; uint32_t offset = page_num * page_size;
uint32_t count = n_pages * page_size; uint32_t count = n_pages * page_size;
// Read from the save file into the provided buffer // Read from the save file into the provided buffer
save_read(PASS_RDRAM dramAddr, offset, count); save_read(PASS_RDRAM dramAddr, offset, count);
// Send the message indicating read completion // Send the message indicating read completion
osSendMesg(PASS_RDRAM mq, 0, OS_MESG_NOBLOCK); osSendMesg(PASS_RDRAM mq, 0, OS_MESG_NOBLOCK);
ctx->r2 = 0; ctx->r2 = 0;
} }
extern "C" void osFlashChange_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osFlashChange_recomp(uint8_t * rdram, recomp_context * ctx) {
assert(false); assert(false);
} }

View file

@ -3,33 +3,33 @@
#include <ultramodern/ultramodern.hpp> #include <ultramodern/ultramodern.hpp>
extern "C" void osPfsInitPak_recomp(uint8_t * rdram, recomp_context* ctx) { extern "C" void osPfsInitPak_recomp(uint8_t * rdram, recomp_context* ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK ctx->r2 = 1; // PFS_ERR_NOPACK
} }
extern "C" void osPfsFreeBlocks_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osPfsFreeBlocks_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK ctx->r2 = 1; // PFS_ERR_NOPACK
} }
extern "C" void osPfsAllocateFile_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osPfsAllocateFile_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK ctx->r2 = 1; // PFS_ERR_NOPACK
} }
extern "C" void osPfsDeleteFile_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osPfsDeleteFile_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK ctx->r2 = 1; // PFS_ERR_NOPACK
} }
extern "C" void osPfsFileState_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osPfsFileState_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK ctx->r2 = 1; // PFS_ERR_NOPACK
} }
extern "C" void osPfsFindFile_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osPfsFindFile_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK ctx->r2 = 1; // PFS_ERR_NOPACK
} }
extern "C" void osPfsReadWriteFile_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osPfsReadWriteFile_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK ctx->r2 = 1; // PFS_ERR_NOPACK
} }
extern "C" void osPfsChecker_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osPfsChecker_recomp(uint8_t * rdram, recomp_context * ctx) {
ctx->r2 = 1; // PFS_ERR_NOPACK ctx->r2 = 1; // PFS_ERR_NOPACK
} }

View file

@ -7,5 +7,5 @@
void load_special_overlay(const SectionTableEntry& section, int32_t ram); void load_special_overlay(const SectionTableEntry& section, int32_t ram);
void load_patch_functions() { void load_patch_functions() {
load_special_overlay(section_table[0], section_table[0].ram_addr); load_special_overlay(section_table[0], section_table[0].ram_addr);
} }

9289
thirdparty/sse2neon/sse2neon.h vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,80 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.20)
project(ultramodern) project(ultramodern)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_EXTENSIONS OFF)
# Warnings
# TODO: uncoment this when we fix the warnings
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
add_library(ultramodern STATIC add_library(ultramodern STATIC
"${CMAKE_CURRENT_SOURCE_DIR}/src/audio.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/audio.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/events.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/events.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/mesgqueue.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/mesgqueue.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/misc_ultra.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/misc_ultra.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/rt64_layer.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/rt64_layer.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/scheduling.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/scheduling.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/task_win32.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/task_win32.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/threadqueue.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/threadqueue.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/threads.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/threads.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/timer.cpp") "${CMAKE_CURRENT_SOURCE_DIR}/src/timer.cpp"
)
target_include_directories(ultramodern PUBLIC target_include_directories(ultramodern PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/include/"
"${CMAKE_SOURCE_DIR}/thirdparty/concurrentqueue") "${CMAKE_SOURCE_DIR}/thirdparty/concurrentqueue"
target_link_libraries(ultramodern PRIVATE rt64) "${CMAKE_SOURCE_DIR}/thirdparty/sse2neon"
)
# TODO: remove when rt64 is no longer a hard dependency
target_include_directories(ultramodern PRIVATE
"${CMAKE_SOURCE_DIR}/rt64/src"
"${CMAKE_SOURCE_DIR}/rt64/src/contrib"
"${CMAKE_SOURCE_DIR}/rt64/src/contrib/hlslpp/include"
"${CMAKE_SOURCE_DIR}/rt64/src/contrib/dxc/inc"
"${CMAKE_SOURCE_DIR}/rt64/src/rhi"
"${CMAKE_SOURCE_DIR}/rt64/src/render"
"${CMAKE_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
FetchContent_Declare(
sdl2
URL https://github.com/libsdl-org/SDL/releases/download/release-2.28.5/SDL2-devel-2.28.5-VC.zip
URL_HASH MD5=d8173db078e54040c666f411c5a6afff
)
FetchContent_MakeAvailable(sdl2)
target_include_directories(ultramodern PRIVATE
${sdl2_SOURCE_DIR}/include
)
target_link_directories(ultramodern PRIVATE
${sdl2_SOURCE_DIR}/lib/x64
)
elseif (APPLE)
find_package(SDL2 REQUIRED)
target_include_directories(ultramodern PRIVATE ${SDL2_INCLUDE_DIRS})
else()
find_package(SDL2 REQUIRED)
find_package(X11 REQUIRED)
message(STATUS "SDL2_FOUND = ${SDL2_FOUND}")
message(STATUS "SDL2_INCLUDE_DIRS = ${SDL2_INCLUDE_DIRS}")
target_include_directories(ultramodern PRIVATE ${SDL2_INCLUDE_DIRS})
message(STATUS "X11_FOUND = ${X11_FOUND}")
message(STATUS "X11_INCLUDE_DIR = ${X11_INCLUDE_DIR}")
message(STATUS "X11_LIBRARIES = ${X11_LIBRARIES}")
target_include_directories(ultramodern PRIVATE ${X11_INCLUDE_DIR})
target_link_libraries(ultramodern PRIVATE ${X11_LIBRARIES})
endif()

View file

@ -0,0 +1,12 @@
#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

View file

@ -1,5 +1,5 @@
#include "ultra64.h" #include <ultramodern/ultra64.h>
#include "ultramodern.hpp" #include <ultramodern/ultramodern.hpp>
#include <cassert> #include <cassert>
static uint32_t sample_rate = 48000; static uint32_t sample_rate = 48000;
@ -7,32 +7,32 @@ static uint32_t sample_rate = 48000;
static ultramodern::audio_callbacks_t audio_callbacks; static ultramodern::audio_callbacks_t audio_callbacks;
void set_audio_callbacks(const ultramodern::audio_callbacks_t& callbacks) { void set_audio_callbacks(const ultramodern::audio_callbacks_t& callbacks) {
audio_callbacks = callbacks; audio_callbacks = callbacks;
} }
void ultramodern::init_audio() { void ultramodern::init_audio() {
// Pick an initial dummy sample rate; this will be set by the game later to the true sample rate. // Pick an initial dummy sample rate; this will be set by the game later to the true sample rate.
set_audio_frequency(48000); set_audio_frequency(48000);
} }
void ultramodern::set_audio_frequency(uint32_t freq) { void ultramodern::set_audio_frequency(uint32_t freq) {
if (audio_callbacks.set_frequency) { if (audio_callbacks.set_frequency) {
audio_callbacks.set_frequency(freq); audio_callbacks.set_frequency(freq);
} }
sample_rate = freq; sample_rate = freq;
} }
void ultramodern::queue_audio_buffer(RDRAM_ARG PTR(int16_t) audio_data_, uint32_t byte_count) { void ultramodern::queue_audio_buffer(RDRAM_ARG PTR(int16_t) audio_data_, uint32_t byte_count) {
// Ensure that the byte count is an integer multiple of samples. // Ensure that the byte count is an integer multiple of samples.
assert((byte_count & 1) == 0); assert((byte_count & 1) == 0);
// Calculate the number of samples from the number of bytes. // Calculate the number of samples from the number of bytes.
uint32_t sample_count = byte_count / sizeof(int16_t); uint32_t sample_count = byte_count / sizeof(int16_t);
// Queue the swapped audio data. // Queue the swapped audio data.
if (audio_callbacks.queue_samples) { if (audio_callbacks.queue_samples) {
audio_callbacks.queue_samples(TO_PTR(int16_t, audio_data_), sample_count); audio_callbacks.queue_samples(TO_PTR(int16_t, audio_data_), sample_count);
} }
} }
// For SDL2 // For SDL2
@ -44,24 +44,24 @@ float buffer_offset_frames = 0.5f;
// the remaining sample count and reporting a number that's too high here can lead to issues. // the remaining sample count and reporting a number that's too high here can lead to issues.
// Reporting a number that's too low can lead to audio lag in some games. // Reporting a number that's too low can lead to audio lag in some games.
uint32_t ultramodern::get_remaining_audio_bytes() { uint32_t ultramodern::get_remaining_audio_bytes() {
// Get the number of remaining buffered audio bytes. // Get the number of remaining buffered audio bytes.
uint32_t buffered_byte_count; uint32_t buffered_byte_count;
if (audio_callbacks.get_frames_remaining != nullptr) { if (audio_callbacks.get_frames_remaining != nullptr) {
buffered_byte_count = audio_callbacks.get_frames_remaining() * 2 * sizeof(int16_t); buffered_byte_count = audio_callbacks.get_frames_remaining() * 2 * sizeof(int16_t);
} }
else { else {
buffered_byte_count = 100; buffered_byte_count = 100;
} }
// Adjust the reported count to be some number of refreshes in the future, which helps ensure that // Adjust the reported count to be some number of refreshes in the future, which helps ensure that
// there are enough samples even if the audio thread experiences a small amount of lag. This prevents // there are enough samples even if the audio thread experiences a small amount of lag. This prevents
// audio popping on games that use the buffered audio byte count to determine how many samples // audio popping on games that use the buffered audio byte count to determine how many samples
// to generate. // to generate.
uint32_t samples_per_vi = (sample_rate / 60); uint32_t samples_per_vi = (sample_rate / 60);
if (buffered_byte_count > static_cast<uint32_t>(buffer_offset_frames * sizeof(int16_t) * samples_per_vi)) { if (buffered_byte_count > static_cast<uint32_t>(buffer_offset_frames * sizeof(int16_t) * samples_per_vi)) {
buffered_byte_count -= static_cast<uint32_t>(buffer_offset_frames * sizeof(int16_t) * samples_per_vi); buffered_byte_count -= static_cast<uint32_t>(buffer_offset_frames * sizeof(int16_t) * samples_per_vi);
} }
else { else {
buffered_byte_count = 0; buffered_byte_count = 0;
} }
return buffered_byte_count; return buffered_byte_count;
} }

View file

@ -11,13 +11,13 @@
#include "blockingconcurrentqueue.h" #include "blockingconcurrentqueue.h"
#include "ultra64.h" #include <ultramodern/ultra64.h>
#include "ultramodern.hpp" #include <ultramodern/ultramodern.hpp>
#include "config.hpp" #include <ultramodern/config.hpp>
#include "rt64_layer.h" #include <ultramodern/rt64_layer.h>
#include <ultramodern/recomp_ui.h>
#include "recomp.h" #include "recomp.h"
#include "recomp_game.h" #include "recomp_game.h"
#include "recomp_ui.h"
#include "recomp_input.h" #include "recomp_input.h"
#include "rsp.h" #include "rsp.h"
@ -325,7 +325,7 @@ void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_re
// TODO move recomp code out of ultramodern. // TODO move recomp code out of ultramodern.
recomp::update_supported_options(); recomp::update_supported_options();
rsp_constants_init(); rsp_constants_init();
// Notify the caller thread that this thread is ready. // Notify the caller thread that this thread is ready.
@ -458,14 +458,14 @@ extern "C" void osViSetMode(RDRAM_ARG PTR(OSViMode) mode_) {
#define VI_CTRL_PIXEL_ADV_3 0x03000 #define VI_CTRL_PIXEL_ADV_3 0x03000
#define VI_CTRL_DITHER_FILTER_ON 0x10000 #define VI_CTRL_DITHER_FILTER_ON 0x10000
#define OS_VI_GAMMA_ON 0x0001 #define OS_VI_GAMMA_ON 0x0001
#define OS_VI_GAMMA_OFF 0x0002 #define OS_VI_GAMMA_OFF 0x0002
#define OS_VI_GAMMA_DITHER_ON 0x0004 #define OS_VI_GAMMA_DITHER_ON 0x0004
#define OS_VI_GAMMA_DITHER_OFF 0x0008 #define OS_VI_GAMMA_DITHER_OFF 0x0008
#define OS_VI_DIVOT_ON 0x0010 #define OS_VI_DIVOT_ON 0x0010
#define OS_VI_DIVOT_OFF 0x0020 #define OS_VI_DIVOT_OFF 0x0020
#define OS_VI_DITHER_FILTER_ON 0x0040 #define OS_VI_DITHER_FILTER_ON 0x0040
#define OS_VI_DITHER_FILTER_OFF 0x0080 #define OS_VI_DITHER_FILTER_OFF 0x0080
extern "C" void osViSetSpecialFeatures(uint32_t func) { extern "C" void osViSetSpecialFeatures(uint32_t func) {
if ((func & OS_VI_GAMMA_ON) != 0) { if ((func & OS_VI_GAMMA_ON) != 0) {

View file

@ -1,12 +1,12 @@
#include "ultra64.h" #include <ultramodern/ultra64.h>
#define K0BASE 0x80000000 #define K0BASE 0x80000000
#define K1BASE 0xA0000000 #define K1BASE 0xA0000000
#define K2BASE 0xC0000000 #define K2BASE 0xC0000000
#define IS_KSEG0(x) ((u32)(x) >= K0BASE && (u32)(x) < K1BASE) #define IS_KSEG0(x) ((u32)(x) >= K0BASE && (u32)(x) < K1BASE)
#define IS_KSEG1(x) ((u32)(x) >= K1BASE && (u32)(x) < K2BASE) #define IS_KSEG1(x) ((u32)(x) >= K1BASE && (u32)(x) < K2BASE)
#define K0_TO_PHYS(x) ((u32)(x)&0x1FFFFFFF) /* kseg0 to physical */ #define K0_TO_PHYS(x) ((u32)(x)&0x1FFFFFFF)
#define K1_TO_PHYS(x) ((u32)(x)&0x1FFFFFFF) /* kseg1 to physical */ #define K1_TO_PHYS(x) ((u32)(x)&0x1FFFFFFF)
u32 osVirtualToPhysical(PTR(void) addr) { u32 osVirtualToPhysical(PTR(void) addr) {
uintptr_t addr_val = (uintptr_t)addr; uintptr_t addr_val = (uintptr_t)addr;

View file

@ -4,7 +4,7 @@
#define HLSL_CPU #define HLSL_CPU
#include "hle/rt64_application.h" #include "hle/rt64_application.h"
#include "rt64_layer.h" #include <ultramodern/rt64_layer.h>
#include "rt64_render_hooks.h" #include "rt64_render_hooks.h"
ultramodern::RT64Context::~RT64Context() = default; ultramodern::RT64Context::~RT64Context() = default;
@ -110,6 +110,10 @@ ultramodern::RT64SetupResult map_setup_result(RT64::Application::SetupResult rt6
case RT64::Application::SetupResult::GraphicsDeviceNotFound: case RT64::Application::SetupResult::GraphicsDeviceNotFound:
return ultramodern::RT64SetupResult::GraphicsDeviceNotFound; return ultramodern::RT64SetupResult::GraphicsDeviceNotFound;
} }
fprintf(stderr, "Unhandled `RT64::Application::SetupResult` ?\n");
assert(false);
std::exit(EXIT_FAILURE);
} }
ultramodern::RT64Context::RT64Context(uint8_t* rdram, ultramodern::WindowHandle window_handle, bool debug) { ultramodern::RT64Context::RT64Context(uint8_t* rdram, ultramodern::WindowHandle window_handle, bool debug) {

View file

@ -1,4 +1,4 @@
#include "ultramodern.hpp" #include <ultramodern/ultramodern.hpp>
void ultramodern::schedule_running_thread(RDRAM_ARG PTR(OSThread) t_) { void ultramodern::schedule_running_thread(RDRAM_ARG PTR(OSThread) t_) {
debug_printf("[Scheduling] Adding thread %d to the running queue\n", TO_PTR(OSThread, t_)->id); debug_printf("[Scheduling] Adding thread %d to the running queue\n", TO_PTR(OSThread, t_)->id);

View file

@ -1,6 +1,6 @@
#include <cassert> #include <cassert>
#include "ultramodern.hpp" #include <ultramodern/ultramodern.hpp>
static PTR(OSThread) running_queue_impl = NULLPTR; static PTR(OSThread) running_queue_impl = NULLPTR;

View file

@ -3,8 +3,8 @@
#include <set> #include <set>
#include "blockingconcurrentqueue.h" #include "blockingconcurrentqueue.h"
#include "ultra64.h" #include <ultramodern/ultra64.h>
#include "ultramodern.hpp" #include <ultramodern/ultramodern.hpp>
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN