You've already forked HackerSM64
mirror of
https://github.com/HackerN64/HackerSM64.git
synced 2026-01-21 10:35:32 -08:00
Add system capabilities variable that tracks individual features instead of broad emulator support (#907)
Also implements check for FBE. * start implementing selftest * add some more * gSupportsLibpl destroyed * SYS_SUPPORTS -> SYSCAP * add emux check * make it compile * play around with it until it writes the ASM i want * format * explain what im doing * hopefully guard emux * one feedback * two feedback * better libpl check * better comment * resolve some feedbackg * add FBE check * dont need to skip this check if its only for the first frame' * skip framebuffer check if on a system that we know supports it. * document that nothing in the repo has emux yet * goodbye emux * feed1 * various detectable --------- Co-authored-by: someone2639 <someone2639@gmail.com>
This commit is contained in:
@@ -23,7 +23,7 @@ extern void __osPiGetAccess(void);
|
||||
extern void __osPiRelAccess(void);
|
||||
|
||||
u8 gEmulator = EMU_CONSOLE;
|
||||
u8 gSupportsLibpl = FALSE;
|
||||
u32 gSystemCapabilities = 0;
|
||||
|
||||
static inline u32 get_pj64_version() {
|
||||
// When calling this function, we know that the emulator is some version of Project 64,
|
||||
@@ -74,21 +74,37 @@ static u8 check_cache_emulation() {
|
||||
return cacheEmulated;
|
||||
}
|
||||
|
||||
// Tests various system quirks and initializes gEmulator to the detected emulator(s).
|
||||
// Also initializes gSystemCapabilities.
|
||||
u32 detect_emulator() {
|
||||
// Test to see if the libpl emulator extension is present.
|
||||
u32 magic;
|
||||
// Test to see if the libpl emulator extension is present.
|
||||
#ifdef LIBPL
|
||||
// We have libpl downloaded as a submodule, just use the API call.
|
||||
if (libpl_is_supported(LPL_ABI_VERSION_CURRENT)) {
|
||||
const lpl_plugin_info *plugin_info = libpl_get_graphics_plugin();
|
||||
|
||||
// We can query framebuffer emulation from libpl
|
||||
if (plugin_info->capabilities & LPL_FRAMEBUFFER_EMULATION) {
|
||||
gSystemCapabilities |= SUPPORTS_SOFTWARE_FRAMEBUFFER;
|
||||
}
|
||||
#else // LIBPL
|
||||
// libpl interacts with the hardware register at 0x1FFB0000,
|
||||
// so we can still _detect_ it by clearing the register and
|
||||
// seeing if we get a specific value back.
|
||||
osPiWriteIo(0x1ffb0000u, 0u);
|
||||
osPiReadIo(0x1ffb0000u, &magic);
|
||||
if (magic == 0x00500000u) {
|
||||
// libpl is supported. Must be ParallelN64
|
||||
#ifdef LIBPL
|
||||
gSupportsLibpl = libpl_is_supported(LPL_ABI_VERSION_CURRENT);
|
||||
#endif
|
||||
#endif // LIBPL
|
||||
gSystemCapabilities |= SUPPORTS_LIBPL;
|
||||
// If libpl is supported, we're on Parallel Launcher
|
||||
return EMU_PARALLEL_LAUNCHER;
|
||||
}
|
||||
|
||||
// If DPC registers are emulated, this is either console or a very accurate emulator
|
||||
if ((u32)IO_READ(DPC_PIPEBUSY_REG) | (u32)IO_READ(DPC_TMEM_REG) | (u32)IO_READ(DPC_BUFBUSY_REG)) {
|
||||
// Assume we have the ability to manipulate the framebuffer too.
|
||||
gSystemCapabilities |= SUPPORTS_SOFTWARE_FRAMEBUFFER;
|
||||
return EMU_CONSOLE;
|
||||
}
|
||||
|
||||
@@ -106,11 +122,14 @@ u32 detect_emulator() {
|
||||
if (1.0f != round_double_to_float(0.9999999999999999)) {
|
||||
fcr_set_rounding_mode(roundingMode);
|
||||
return EMU_WIIVC;
|
||||
} else {
|
||||
gSystemCapabilities |= SUPPORTS_FLOAT_ROUNDING_MODE;
|
||||
}
|
||||
fcr_set_rounding_mode(roundingMode);
|
||||
|
||||
// If cache is emulated, then this is likely Simple64, or some other accurate emulator.
|
||||
if (check_cache_emulation()) {
|
||||
gSystemCapabilities |= SUPPORTS_CACHING;
|
||||
return EMU_OTHER;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,34 @@ enum Emulator {
|
||||
EMU_OTHER = (1 << 6), // Any other emulator
|
||||
};
|
||||
|
||||
// initializes gEmulator
|
||||
/**
|
||||
* Various detectable system capabilities
|
||||
*/
|
||||
enum SystemCapabilities {
|
||||
// Whether the system caches instructions and data
|
||||
SUPPORTS_CACHING = (1 << 0),
|
||||
|
||||
// Whether the system supports changing how floats get rounded
|
||||
SUPPORTS_FLOAT_ROUNDING_MODE = (1 << 1),
|
||||
|
||||
// Whether the system supports the `libpl` API on Parallel Launcher
|
||||
SUPPORTS_LIBPL = (1 << 2),
|
||||
|
||||
// Whether the system can edit the framebuffer in software
|
||||
SUPPORTS_SOFTWARE_FRAMEBUFFER = (1 << 3),
|
||||
|
||||
// TODO: `emux` is a developing standard.
|
||||
// SUPPORTS_EMULATOR_EXTENSIONS = (1 << 4), // i.e. `emux`
|
||||
|
||||
// TODO: Figure out what these mean and implement them too
|
||||
// SUPPORTS_DMA_TIMING = 0,
|
||||
// SUPPORTS_RSP_PIPELINE_STALL_TIMING = 0,
|
||||
};
|
||||
|
||||
extern u32 detect_emulator();
|
||||
|
||||
/* gEmulator is an enum that identifies the current emulator.
|
||||
/**
|
||||
* gEmulator is an enum that identifies the current emulator.
|
||||
* The enum values work as a bitfield, so you can use the & and | operators
|
||||
* to test for multiple emulators or versions at once.
|
||||
*
|
||||
@@ -34,8 +58,17 @@ extern u32 detect_emulator();
|
||||
*/
|
||||
extern u8 gEmulator;
|
||||
|
||||
// determines whether libpl is safe to use
|
||||
extern u8 gSupportsLibpl;
|
||||
/**
|
||||
* Bitflag that lists all system capabilities, for more granular
|
||||
* feature detection than gEmulator.
|
||||
*/
|
||||
extern u32 gSystemCapabilities;
|
||||
|
||||
/**
|
||||
* Whether the emulator supports libpl.
|
||||
* Left in for backwards compatibility.
|
||||
*/
|
||||
#define gSupportsLibpl (gSystemCapabilities & SUPPORTS_LIBPL)
|
||||
|
||||
// Included for backwards compatibility when upgrading from HackerSM64 2.0
|
||||
#define gIsConsole ((gEmulator & EMU_CONSOLE) != 0)
|
||||
|
||||
@@ -408,6 +408,31 @@ void draw_reset_bars(void) {
|
||||
osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are emulating the framebuffer
|
||||
*
|
||||
* s32 frameIndex:
|
||||
* 0: Write to the framebuffer, wait to process displaylist
|
||||
* 1: Check whether the framebuffer write persisted
|
||||
*/
|
||||
static void check_fbe(s32 frameIndex) {
|
||||
// NOTE: For whatever reason, checking against pixel index 12 fails on some versions of GlideN64 (pain).
|
||||
// So apparently, this value being set to 13 actually matters...???
|
||||
const s32 fbePixelOffset = 13;
|
||||
const u16 fbePixelVal = 0xFF01;
|
||||
|
||||
if (frameIndex == 0) {
|
||||
// Write pixel to the framebuffer
|
||||
gFramebuffers[sRenderingFramebuffer][fbePixelOffset] = fbePixelVal;
|
||||
} else {
|
||||
// Check if pixel persisted in the framebuffer after executing the display list
|
||||
// that clears it (but before updating sRenderingFramebuffer!)
|
||||
if (gFramebuffers[sRenderingFramebuffer][fbePixelOffset] != fbePixelVal) {
|
||||
gSystemCapabilities |= SUPPORTS_SOFTWARE_FRAMEBUFFER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial settings for the first rendered frame.
|
||||
*/
|
||||
@@ -423,7 +448,23 @@ void render_init(void) {
|
||||
init_rcp(CLEAR_ZBUFFER);
|
||||
clear_framebuffer(0);
|
||||
end_master_display_list();
|
||||
exec_display_list(&gGfxPool->spTask);
|
||||
|
||||
// Skip the FBE check if system is console,
|
||||
// or had already been determined to support framebuffer emulation.
|
||||
if (gSystemCapabilities & SUPPORTS_SOFTWARE_FRAMEBUFFER) {
|
||||
exec_display_list(&gGfxPool->spTask);
|
||||
} else {
|
||||
check_fbe(0);
|
||||
|
||||
exec_display_list(&gGfxPool->spTask);
|
||||
|
||||
// Wait for frame rendering to complete to prevent race condition with FBE check
|
||||
osRecvMesg(&gGfxVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
|
||||
check_fbe(1);
|
||||
|
||||
// Send message back to queue to prevent locking up
|
||||
osSendMesg(&gGfxVblankQueue, gMainReceivedMesg, OS_MESG_BLOCK);
|
||||
}
|
||||
|
||||
// Skip incrementing the initial framebuffer index on certain emulators so that they display immediately as the Gfx task finishes
|
||||
// This will break accurate emulators, so only enable on Project64, Parallel Launcher and Mupen.
|
||||
|
||||
Reference in New Issue
Block a user