Enable relevant RT64 enhancements, fix pause background corruption if song of soaring was played before ever pausing

This commit is contained in:
Mr-Wiseguy 2024-02-04 22:55:15 -05:00
parent 3326a1bcce
commit 958808acb0
7 changed files with 90 additions and 28 deletions

View File

@ -14,6 +14,7 @@ namespace ultramodern {
RT64::Application* RT64Init(uint8_t* rom, uint8_t* rdram, ultramodern::WindowHandle window_handle);
void RT64UpdateConfig(RT64::Application* application, const ultramodern::GraphicsConfig& old_config, const ultramodern::GraphicsConfig& new_config);
void RT64EnableInstantPresent(RT64::Application* application);
void RT64SendDL(uint8_t* rdram, const OSTask* task);
void RT64UpdateScreen(uint32_t vi_origin);
void RT64ChangeWindow();

View File

@ -31,8 +31,6 @@ s16 KaleidoScope_SetPageVertices(PlayState* play, Vtx* vtx, s16 vtxPage, s16 num
s32 cur_y;
u32 row;
gSegments[0x0D] = OS_K0_TO_PHYSICAL(play->pauseCtx.iconItemLangSegment);
cur_y = PAGE_BG_HEIGHT / 2;
// 2 verts per row plus 2 extra verts at the start and the end.
@ -74,10 +72,10 @@ s16 KaleidoScope_SetPageVertices(PlayState* play, Vtx* vtx, s16 vtxPage, s16 num
// These are overlay symbols, so their addresses need to be offset to get their actual loaded vram address.
// TODO remove this once the recompiler is able to handle overlay symbols automatically for patch functions.
s16** sVtxPageQuadsXRelocated = (s16**)((u8*)&sVtxPageQuadsX[0] + gKaleidoMgrOverlayTable[0].offset);
s16** sVtxPageQuadsWidthRelocated = (s16**)((u8*)&sVtxPageQuadsWidth[0] + gKaleidoMgrOverlayTable[0].offset);
s16** sVtxPageQuadsYRelocated = (s16**)((u8*)&sVtxPageQuadsY[0] + gKaleidoMgrOverlayTable[0].offset);
s16** sVtxPageQuadsHeightRelocated = (s16**)((u8*)&sVtxPageQuadsHeight[0] + gKaleidoMgrOverlayTable[0].offset);
s16** sVtxPageQuadsXRelocated = (s16**)KaleidoManager_GetRamAddr(sVtxPageQuadsX);
s16** sVtxPageQuadsWidthRelocated = (s16**)KaleidoManager_GetRamAddr(sVtxPageQuadsWidth);
s16** sVtxPageQuadsYRelocated = (s16**)KaleidoManager_GetRamAddr(sVtxPageQuadsY);
s16** sVtxPageQuadsHeightRelocated = (s16**)KaleidoManager_GetRamAddr(sVtxPageQuadsHeight);
s16 k = 60;
@ -128,8 +126,7 @@ typedef u8 bg_image_t[(2 + PAGE_BG_WIDTH) * (2 + PAGE_BG_HEIGHT)];
#define BG_IMAGE_COUNT 4
TexturePtr* bg_pointers[BG_IMAGE_COUNT];
bg_image_t bg_images[BG_IMAGE_COUNT];
u32 bg_image_count = 0;
bg_image_t bg_images[BG_IMAGE_COUNT] __attribute__((aligned(8)));
void assemble_image(TexturePtr* textures, bg_image_t* image_out) {
u8* pixels_out_start = *image_out;
@ -165,6 +162,58 @@ void assemble_image(TexturePtr* textures, bg_image_t* image_out) {
}
}
static bool assembled_kaleido_images = false;
extern TexturePtr sMaskPageBgTextures[];
extern TexturePtr sItemPageBgTextures[];
extern TexturePtr sMapPageBgTextures[];
extern TexturePtr sQuestPageBgTextures[];
extern void (*sKaleidoScopeUpdateFunc)(PlayState* play);
extern void (*sKaleidoScopeDrawFunc)(PlayState* play);
extern void KaleidoScope_Update(PlayState* play);
extern void KaleidoScope_Draw(PlayState* play);
void KaleidoUpdateWrapper(PlayState* play) {
KaleidoScope_Update(play);
}
void KaleidoDrawWrapper(PlayState* play) {
// @recomp Update the background image pointers to reflect the overlay's load address.
bg_pointers[0] = KaleidoManager_GetRamAddr(sMaskPageBgTextures);
bg_pointers[1] = KaleidoManager_GetRamAddr(sItemPageBgTextures);
bg_pointers[2] = KaleidoManager_GetRamAddr(sMapPageBgTextures);
bg_pointers[3] = KaleidoManager_GetRamAddr(sQuestPageBgTextures);
KaleidoScope_Draw(play);
// @recomp Check if this is the first time kaleido has been drawn. If so, assemble the background textures
// into the full seamless image.
if (!assembled_kaleido_images) {
assembled_kaleido_images = true;
// Record the old value for segments 0x08 and 0x0D, then update them with the correct values so that segmented addresses
// can be converted in assemble_image.
uintptr_t old_segment_08 = gSegments[0x08];
uintptr_t old_segment_0D = gSegments[0x0D];
gSegments[0x08] = OS_K0_TO_PHYSICAL(play->pauseCtx.iconItemSegment);
gSegments[0x0D] = OS_K0_TO_PHYSICAL(play->pauseCtx.iconItemLangSegment);
assemble_image(KaleidoManager_GetRamAddr(sMaskPageBgTextures), &bg_images[0]);
assemble_image(KaleidoManager_GetRamAddr(sItemPageBgTextures), &bg_images[1]);
assemble_image(KaleidoManager_GetRamAddr(sMapPageBgTextures), &bg_images[2]);
assemble_image(KaleidoManager_GetRamAddr(sQuestPageBgTextures), &bg_images[3]);
gSegments[0x08] = old_segment_08;
gSegments[0x0D] = old_segment_0D;
}
}
void KaleidoScopeCall_Init(PlayState* play) {
// @recomp Set the update and draw func pointers to the wrappers instead of the actual functions.
sKaleidoScopeUpdateFunc = KaleidoUpdateWrapper;
sKaleidoScopeDrawFunc = KaleidoDrawWrapper;
KaleidoSetup_Init(play);
}
// @recomp patched to fix bilerp seams.
Gfx* KaleidoScope_DrawPageSections(Gfx* gfx, Vtx* vertices, TexturePtr* textures) {
s32 i;
@ -172,24 +221,17 @@ Gfx* KaleidoScope_DrawPageSections(Gfx* gfx, Vtx* vertices, TexturePtr* textures
bg_image_t* cur_image = NULL;
// Check if this texture set has already been assembled into an image.
// Check if this texture set has been assembled into a full image.
u32 image_index;
for (image_index = 0; image_index < bg_image_count; image_index++) {
for (image_index = 0; image_index < BG_IMAGE_COUNT; image_index++) {
if (bg_pointers[image_index] == textures) {
cur_image = &bg_images[image_index];
break;
}
}
// If no image was found and there's a free image slot, assemble the image.
if (cur_image == NULL && image_index < BG_IMAGE_COUNT) {
assemble_image(textures, &bg_images[image_index]);
bg_pointers[image_index] = textures;
cur_image = &bg_images[image_index];
bg_image_count++;
}
if (cur_image == NULL) {
// No image was found and there are no free slots.
// No image was found.
return gfx;
}

View File

@ -24,7 +24,7 @@ s32 func_80847190(PlayState* play, Player* this, s32 arg2) {
static float filtered_gyro_x, filtered_gyro_y;
static int applied_gyro_x, applied_gyro_y;
const float filter_factor = 0.50f;
const float filter_factor = 0.00f;
// TODO remappable gyro reset button
if (play->state.input[0].press.button & BTN_L) {

View File

@ -394,17 +394,16 @@ void Interface_Draw(PlayState* play) {
gEXSetScissorAlign(OVERLAY_DISP++, G_EX_ORIGIN_LEFT, G_EX_ORIGIN_RIGHT, 0, -margin_reduction, -SCREEN_WIDTH, margin_reduction, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
// @recomp Move the item being equipped from the center of the screen to the right edge as the timer counts down
if (gKaleidoMgrOverlayTable[0].loadedRamAddr != NULL) {
// These are overlay symbols, so their addresses need to be offset to get their actual loaded vram address.
// TODO remove this once the recompiler is able to handle overlay symbols automatically for patch functions.
if ((pauseCtx->state == PAUSE_STATE_MAIN) && ((pauseCtx->mainState == PAUSE_MAIN_STATE_EQUIP_ITEM) ||
(pauseCtx->mainState == PAUSE_MAIN_STATE_EQUIP_MASK))) {
extern s16 sEquipAnimTimer;
extern s16 sMaskEquipAnimTimer;
extern s16 sEquipState;
extern s16 sMaskEquipState;
s16 equip_timer = *(s16*)((u8*)&sEquipAnimTimer + gKaleidoMgrOverlayTable[0].offset);
s16 mask_equip_timer = *(s16*)((u8*)&sMaskEquipAnimTimer + gKaleidoMgrOverlayTable[0].offset);
s16 equip_state = *(s16*)((u8*)&sEquipState + gKaleidoMgrOverlayTable[0].offset);
s16 mask_equip_state = *(s16*)((u8*)&sMaskEquipState + gKaleidoMgrOverlayTable[0].offset);
s16 equip_timer = *(s16*)KaleidoManager_GetRamAddr(&sEquipAnimTimer);
s16 mask_equip_timer = *(s16*)KaleidoManager_GetRamAddr(&sMaskEquipAnimTimer);
s16 equip_state = *(s16*)KaleidoManager_GetRamAddr(&sEquipState);
s16 mask_equip_state = *(s16*)KaleidoManager_GetRamAddr(&sMaskEquipState);
s16 timer = MIN(equip_timer, mask_equip_timer);
s32 max_timer = 10;

View File

@ -114,7 +114,7 @@ void recomp::reset_graphics_options() {
new_config.wm_option = ultramodern::WindowMode::Windowed;
new_config.ar_option = RT64::UserConfiguration::AspectRatio::Expand;
new_config.msaa_option = RT64::UserConfiguration::Antialiasing::MSAA4X;
new_config.rr_option = RT64::UserConfiguration::RefreshRate::Original;
new_config.rr_option = RT64::UserConfiguration::RefreshRate::Display;
new_config.rr_manual_value = 60;
ultramodern::set_graphics_config(new_config);
}

View File

@ -201,6 +201,13 @@ RT64::Application* RT64Init(uint8_t* rom, uint8_t* rdram, ultramodern::WindowHan
device_max_msaa = compute_max_supported_aa(common_sample_counts);
// Force gbi depth branches to prevent LODs from kicking in.
ret->enhancementConfig.f3dex.forceBranch = true;
// Scale LODs based on the output resolution.
ret->enhancementConfig.textureLOD.scale = true;
ret->updateEnhancementConfig();
return ret;
}
@ -260,6 +267,13 @@ void RT64UpdateConfig(RT64::Application* application, const ultramodern::Graphic
}
}
void RT64EnableInstantPresent(RT64::Application* application) {
// Enable the present early presentation mode for minimal latency.
application->enhancementConfig.presentation.mode = RT64::EnhancementConfiguration::Presentation::Mode::PresentEarly;
application->updateEnhancementConfig();
}
RT64::UserConfiguration::Antialiasing RT64MaxMSAA() {
return device_max_msaa;
}

View File

@ -268,6 +268,7 @@ ultramodern::GraphicsConfig ultramodern::get_graphics_config() {
}
void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_ready, ultramodern::WindowHandle window_handle) {
bool enabled_instant_present = false;
using namespace std::chrono_literals;
ultramodern::set_native_thread_name("Gfx Thread");
@ -293,6 +294,11 @@ void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_read
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)) {
// Turn on instant present if the game has been started and it hasn't been turned on yet.
if (ultramodern::is_game_started() && !enabled_instant_present) {
RT64EnableInstantPresent(application);
enabled_instant_present = true;
}
// Tell the game that the RSP completed instantly. This will allow it to queue other task types, but it won't
// start another graphics task until the RDP is also complete. Games usually preserve the RSP inputs until the RDP
// is finished as well, so sending this early shouldn't be an issue in most cases.