first try to draw first logo

This commit is contained in:
Lurs
2026-02-20 21:13:50 +01:00
parent a4d72437ef
commit 97e7a8b145
26 changed files with 517 additions and 65 deletions
+2
View File
@@ -7,6 +7,7 @@ endif ()
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if (CMAKE_SYSTEM_NAME STREQUAL Linux)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unknown-pragmas -Wno-unused-variable -Wno-unused-parameter")
@@ -26,6 +27,7 @@ elseif (MSVC)
add_compile_options(/Zc:strictStrings-)
add_compile_options(/MP)
add_compile_options(/W0)
add_compile_options(/std:c++20)
endif ()
if (NOT MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error -Wno-c++11-narrowing")
+1 -1
+18
View File
@@ -16,15 +16,27 @@ inline void J3DFifoWriteXFCmdHdr(u16 addr, u8 len) {
}
inline void J3DFifoLoadIndx(u8 cmd, u16 indx, u16 addr) {
#ifdef TARGET_PC
GXCmd1u8(cmd);
GXCmd1u16(indx);
GXCmd1u16(addr);
#else
GXWGFifo.u8 = cmd;
GXWGFifo.u16 = indx;
GXWGFifo.u16 = addr;
#endif
}
inline void J3DFifoWriteCPCmd(u8 cmd, u32 param) {
#ifdef TARGET_PC
GXCmd1u8(GX_LOAD_CP_REG);
GXCmd1u8(cmd);
GXCmd1u32(param);
#else
GXWGFifo.u8 = GX_LOAD_CP_REG;
GXWGFifo.u8 = cmd;
GXWGFifo.u32 = param;
#endif
}
inline void J3DFifoLoadCPCmd(u8 reg, u32 value) {
@@ -34,9 +46,15 @@ inline void J3DFifoLoadCPCmd(u8 reg, u32 value) {
}
inline void J3DFifoWriteXFCmd(u16 cmd, u16 len) {
#ifdef TARGET_PC
GXCmd1u8(GX_LOAD_XF_REG);
GXCmd1u16(len - 1);
GXCmd1u16(cmd);
#else
GXWGFifo.u8 = GX_LOAD_XF_REG;
GXWGFifo.u16 = (len - 1);
GXWGFifo.u16 = cmd;
#endif
}
inline void J3DFifoLoadXFCmdHdr(u16 addr, u8 len) {
+2 -2
View File
@@ -18,8 +18,8 @@ public:
void setFovy(f32 fovy) { mFovY = fovy; }
void setAspect(f32 aspect) { mAspect = aspect; }
void setNear(f32 near) { mNear = near; }
void setFar(f32 far) { mFar = far; }
void setNear(f32 near_) { mNear = near_; }
void setFar(f32 far_) { mFar = far_; }
f32 getFar() { return mFar; }
+8
View File
@@ -36,7 +36,11 @@ typedef struct _GXColorS10 {
} GXColorS10;
typedef struct _GXTexObj {
#ifdef TARGET_PC
u32 dummy[22]; // Aurora's GXTexObj_ contains std::shared_ptr + many fields (~80 bytes)
#else
u32 dummy[8];
#endif
} GXTexObj;
typedef struct _GXLightObj {
@@ -48,7 +52,11 @@ typedef struct _GXTexRegion {
} GXTexRegion;
typedef struct _GXTlutObj {
#ifdef TARGET_PC
u32 dummy[4]; // Aurora's GXTlutObj_ contains std::shared_ptr (8+ bytes)
#else
u32 dummy[3];
#endif
} GXTlutObj;
typedef struct _GXTlutRegion {
+38 -2
View File
@@ -4,9 +4,45 @@
#ifdef __REVOLUTION_SDK__
#include <revolution/gx/GXVert.h>
#elif defined(TARGET_PC)
// On PC, use Aurora's GXVert declarations (extern functions implemented in
// GXVert.cpp, no hardware FIFO writes to 0xCC008000)
// On PC, include Aurora's GXVert for GXPosition/GXNormal/GXColor/GXTexCoord/GXEnd
// (extern functions implemented in Aurora's GXVert.cpp, stream-based vertex buffers)
#include "../../../extern/aurora/include/dolphin/gx/GXVert.h"
// Aurora's GXVert.h does not provide GXCmd, GXParam, GXMatrixIndex, or a valid
// GXWGFifo target. J3D code uses these for low-level display list writes.
// We declare them as extern (implemented in stubs.cpp) and provide a dummy
// GXWGFifo that writes into a throw-away buffer so direct FIFO writes don't crash.
// Replace Aurora's GXWGFifo macro (pointing to 0xCC008000) with an extern variable
#undef GXWGFifo
#ifdef __cplusplus
extern "C" {
#endif
// PPCWGPipe is already typedef'd by Aurora's GXVert.h above.
// Dummy FIFO sink: direct GXWGFifo writes in J3DFifo.h land here harmlessly.
extern volatile PPCWGPipe GXWGFifo;
void GXCmd1u8(const u8 x);
void GXCmd1u16(const u16 x);
void GXCmd1u32(const u32 x);
void GXParam1u8(const u8 x);
void GXParam1u16(const u16 x);
void GXParam1u32(const u32 x);
void GXParam1s8(const s8 x);
void GXParam1s16(const s16 x);
void GXParam1s32(const s32 x);
void GXParam1f32(const f32 x);
void GXParam3f32(const f32 x, const f32 y, const f32 z);
void GXParam4f32(const f32 x, const f32 y, const f32 z, const f32 w);
void GXMatrixIndex1u8(const u8 x);
#ifdef __cplusplus
}
#endif
#else
#include <dolphin/types.h>
#include <dolphin/os.h>
+3
View File
@@ -184,8 +184,10 @@ static u32 calcSum2(u16 const* data, u32 size) {
bool DynamicModuleControl::do_load() {
if (mModule != NULL) {
printf("[DIAG] DynamicModuleControl::do_load(%s) already loaded\n", mName); fflush(stdout);
return true;
}
printf("[DIAG] DynamicModuleControl::do_load(%s) loading... sArchive=%p sFileCache=%p\n", mName, sArchive, sFileCache); fflush(stdout);
JKRExpHeap* heap = mDoExt_getArchiveHeap();
s32 i = 0;
while (true) {
@@ -278,6 +280,7 @@ bool DynamicModuleControl::do_load() {
break;
}
}
printf("[DIAG] DynamicModuleControl::do_load(%s) SUCCESS mModule=%p type=%d size=%d\n", mName, mModule, mResourceType, mSize); fflush(stdout);
return true;
}
+5
View File
@@ -520,8 +520,13 @@ static void JFWDrawDoneAlarm() {
static void JFWGXAbortAlarmHandler(OSAlarm* param_0, OSContext* param_1) {
diagnoseGpHang();
GXAbortFrame();
#ifdef TARGET_PC
GXCmd1u8(0x61);
GXCmd1u32(0x5800000F);
#else
GXWGFifo.u8 = 0x61;
GXWGFifo.u32 = 0x5800000F;
#endif
GXFifoObj* fifo = GXGetCPUFifo();
if (fifo != NULL) {
+23
View File
@@ -2,6 +2,8 @@
* c_dylink.cpp
* REL to process name definitions and REL init functions
*/
#include <cstdio>
#include "c/c_dylink.h"
#include "DynamicLink.h"
#include "JSystem/JKernel/JKRExpHeap.h"
@@ -912,6 +914,7 @@ int cDyl_LinkASync(s16 i_ProfName) {
JUT_ASSERT(266, DMC_initialized);
if (!cDyl_Initialized) {
printf("[DIAG] cDyl_LinkASync: NOT initialized yet, profName=%d\n", i_ProfName); fflush(stdout);
OS_REPORT_ERROR("初期化が終わってないのに呼んでもらっても困ります %d %s\n", i_ProfName, fpcDbSv_getNameString(i_ProfName));
return cPhs_INIT_e;
}
@@ -932,10 +935,12 @@ int cDyl_LinkASync(s16 i_ProfName) {
return cPhs_COMPLEATE_e;
} else {
// "cDyl_LinkASync: Link failed. Returning\n"
printf("[DIAG] cDyl_LinkASync: link FAILED for profName=%d\n", i_ProfName); fflush(stdout);
OSReport_Error("cDyl_LinkASync: リンクに失敗しました。諦めます\n");
return cPhs_ERROR_e;
}
} else {
printf("[DIAG] cDyl_LinkASync: load_async not ready for profName=%d\n", i_ProfName); fflush(stdout);
return cPhs_INIT_e;
}
}
@@ -944,16 +949,29 @@ int cDyl_LinkASync(s16 i_ProfName) {
}
static int cDyl_InitCallback(void* param_0) {
printf("[DIAG] cDyl_InitCallback: START\n"); fflush(stdout);
JUT_ASSERT(335, !cDyl_Initialized);
#ifdef TARGET_PC
// On PC, the profile list is statically linked (g_fpcPf_ProfileList_p in f_pc_profile.cpp).
// Skip DVD-based REL loading and string table — OSLink/OSLinkFixed are stubs.
cDyl_Initialized = true;
fopScnM_CreateReq(PROC_LOGO_SCENE, 0x7FFF, 0, 0);
printf("[DIAG] cDyl_InitCallback: PROC_LOGO_SCENE created (PC path), DONE\n"); fflush(stdout);
return 1;
#else
#if PLATFORM_GCN
JKRHeap* parentHeap = mDoExt_getArchiveHeap();
#else
JKRHeap* parentHeap = DynamicModuleControlBase::getHeap();
#endif
printf("[DIAG] cDyl_InitCallback: parentHeap=%p\n", parentHeap); fflush(stdout);
JKRFileCache* loader = JKRMountDvdDrive("/", parentHeap, NULL);
printf("[DIAG] cDyl_InitCallback: JKRMountDvdDrive loader=%p\n", loader); fflush(stdout);
DynamicModuleControl::initialize();
printf("[DIAG] cDyl_InitCallback: DynamicModuleControl::initialize done\n"); fflush(stdout);
#if PLATFORM_GCN
void* strTbl = JKRGetResource("/dvd/str/Final/Release/frameworkF.str");
@@ -962,17 +980,22 @@ static int cDyl_InitCallback(void* param_0) {
#else
void* strTbl = JKRGetResource("/dvd/str/Final/Release/frameworkF.str");
#endif
printf("[DIAG] cDyl_InitCallback: frameworkF.str=%p\n", strTbl); fflush(stdout);
JKRDetachResource(strTbl, loader);
JKRUnmountDvdDrive(loader);
OSSetStringTable(strTbl);
DynamicModuleControl dmc("f_pc_profile_lst");
printf("[DIAG] cDyl_InitCallback: linking f_pc_profile_lst...\n"); fflush(stdout);
dmc.link();
printf("[DIAG] cDyl_InitCallback: link done\n"); fflush(stdout);
cDyl_Initialized = true;
fopScnM_CreateReq(PROC_LOGO_SCENE, 0x7FFF, 0, 0);
printf("[DIAG] cDyl_InitCallback: PROC_LOGO_SCENE created, DONE\n"); fflush(stdout);
return 1;
#endif
}
static mDoDvdThd_callback_c* cDyl_DVD;
+13
View File
@@ -3,6 +3,8 @@
* Game Boot Logo's Display
*/
#include <cstdio>
#include "d/dolzel.h" // IWYU pragma: keep
#include "d/d_s_logo.h"
@@ -589,11 +591,21 @@ static int resLoad(request_of_phase_process_class* i_phase, dScnLogo_c* i_this)
}
int dScnLogo_c::create() {
static bool sDiagLogged = false;
if (!sDiagLogged) {
printf("[DIAG] dScnLogo_c::create START\n"); fflush(stdout);
}
int phase_state = resLoad(&field_0x1c4, this);
if (!sDiagLogged) {
printf("[DIAG] dScnLogo_c::create resLoad=%d (need %d for complete)\n", phase_state, cPhs_COMPLEATE_e); fflush(stdout);
sDiagLogged = true;
}
if (phase_state != cPhs_COMPLEATE_e) {
return phase_state;
}
printf("[DIAG] dScnLogo_c::create resLoad COMPLETE, continuing init...\n"); fflush(stdout);
#if PLATFORM_WII
data_8053a730 = 1;
#endif
@@ -853,6 +865,7 @@ void dScnLogo_c::dvdDataLoad() {
}
static int dScnLogo_Create(scene_class* i_this) {
printf("[DIAG] dScnLogo_Create: entry i_this=%p\n", i_this); fflush(stdout);
return (new (i_this) dScnLogo_c())->create();
}
+17
View File
@@ -135,10 +135,16 @@ void GXSetDrawDone(void) {
CHECK_GXBEGIN(488, "GXSetDrawDone");
enabled = OSDisableInterrupts();
#ifdef TARGET_PC
// On PC there is no GX GPU, so draw is always immediately done.
// Without the hardware finish interrupt, GXWaitDrawDone would deadlock.
DrawDone = 1;
#else
reg = 0x45000002;
GX_WRITE_RAS_REG(reg);
GXFlush();
DrawDone = 0;
#endif
OSRestoreInterrupts(enabled);
}
@@ -147,6 +153,12 @@ void GXWaitDrawDone(void) {
CHECK_GXBEGIN(534, "GXWaitDrawDone");
#ifdef TARGET_PC
// On PC there is no GX hardware — draw is always done immediately.
DrawDone = 1;
return;
#endif
enabled = OSDisableInterrupts();
while (!DrawDone) {
OSSleepThread(&FinishQueue);
@@ -156,6 +168,11 @@ void GXWaitDrawDone(void) {
void GXDrawDone(void) {
CHECK_GXBEGIN(566, "GXDrawDone");
#ifdef TARGET_PC
// On PC, no GPU to wait for — return immediately.
DrawDone = 1;
return;
#endif
GXSetDrawDone();
GXWaitDrawDone();
}
+98 -1
View File
@@ -313,7 +313,7 @@ int OSCreateThread(OSThread* thread, void* (*func)(void*), void* param,
// ============================================================================
// Resume / Suspend
// ============================================================================
/*
s32 OSResumeThread(OSThread* thread) {
if (!thread) return 0;
@@ -365,6 +365,103 @@ s32 OSSuspendThread(OSThread* thread) {
return prevSuspend;
}
*/
// ============================================================================
// Resume / Suspend
// ============================================================================
s32 OSResumeThread(OSThread* thread) {
if (!thread)
return 0;
s32 prevSuspend = thread->suspend;
if (thread->suspend > 0) {
thread->suspend--;
}
// Only wake up if suspend count drops to 0
if (thread->suspend == 0) {
PCThreadData* data = nullptr;
// Lock the global map to safely retrieve our thread data pointer
{
std::lock_guard<std::mutex> mapLock(GetThreadDataMutex());
auto it = GetThreadDataMap().find(thread);
if (it != GetThreadDataMap().end()) {
data = it->second.get();
}
}
if (data) {
// Lock the specific thread mutex to safely modify state and notify
std::unique_lock<std::mutex> threadLock(data->mtx);
if (!data->started) {
// First resume: launch the native thread
data->started = true;
data->suspended = false;
// Unlock before launching to avoid potential deadlocks in thread initialization
threadLock.unlock();
data->nativeThread = std::thread(ThreadEntryWrapper, thread, data);
data->nativeThread.detach();
OSReport("[PC-OSThread] Started thread %p\n", thread);
} else {
// Resume from suspension: signal the condition variable
// IMPORTANT: Set suspended to false BEFORE notifying to pass the wait predicate
data->suspended = false;
data->cv.notify_all();
}
}
}
return prevSuspend;
}
s32 OSSuspendThread(OSThread* thread) {
if (!thread)
return 0;
s32 prevSuspend = thread->suspend;
thread->suspend++;
// If transitioning from running (0) to suspended (1)
if (prevSuspend == 0) {
PCThreadData* data = nullptr;
// Lock the global map to find our thread data
{
std::lock_guard<std::mutex> mapLock(GetThreadDataMutex());
auto it = GetThreadDataMap().find(thread);
if (it != GetThreadDataMap().end()) {
data = it->second.get();
}
}
if (data && data->started) {
std::unique_lock<std::mutex> threadLock(data->mtx);
data->suspended = true;
// FIX: If the thread is suspending ITSELF, we must block execution here.
// This replicates the GameCube behavior where OSSuspendThread yields the CPU
// immediately.
if (thread == OSGetCurrentThread()) {
// Block until 'suspended' becomes false (set by OSResumeThread)
// The predicate protects against spurious wakeups.
data->cv.wait(threadLock, [data] { return !data->suspended; });
} else {
// NOTE: Suspending *other* threads is difficult in C++ std::thread
// without cooperative checkpoints or platform-specific hacks.
// For now, we only set the flag. The target thread would need to check 'suspended'
// periodically.
}
}
}
return prevSuspend;
}
// ============================================================================
// Sleep / Wakeup (thread queue based)
+11 -11
View File
@@ -51,7 +51,7 @@ void setBasePath(const char* path) {
g_basePath() = path;
#endif
OSReport("[DvdEmu] Base path set to: %s\n", g_basePath().c_str());
printf("[DvdEmu] Base path set to: %s\n", g_basePath().c_str()); fflush(stdout);
}
const char* getBasePath() {
@@ -93,9 +93,9 @@ bool fileExists(const char* gcPath) {
#endif
if (exists) {
OSReport("[DvdEmu] FOUND: %s\n", gcPath);
printf("[DvdEmu] FOUND: %s\n", gcPath); fflush(stdout);
} else {
OSReport("[DvdEmu] MISSING: %s\n", gcPath);
printf("[DvdEmu] MISSING: %s\n", gcPath); fflush(stdout);
}
return exists;
@@ -116,11 +116,11 @@ u32 getFileSize(const char* gcPath) {
void* loadFile(const char* gcPath, u32* outSize, void* heap) {
std::string fullPath = convertPath(gcPath);
OSReport("[DvdEmu] Loading request: '%s'\n", gcPath);
printf("[DvdEmu] Loading request: '%s'\n", gcPath); fflush(stdout);
FILE* f = fopen(fullPath.c_str(), "rb");
if (!f) {
OSReport("[DvdEmu] ERROR: Failed to open file at physical path: %s\n", fullPath.c_str());
printf("[DvdEmu] ERROR: Failed to open file at physical path: %s\n", fullPath.c_str()); fflush(stdout);
if (outSize)
*outSize = 0;
return nullptr;
@@ -139,7 +139,7 @@ void* loadFile(const char* gcPath, u32* outSize, void* heap) {
#endif
if (!data) {
OSReport("[DvdEmu] FATAL: Failed to allocate %u bytes for %s\n", size, gcPath);
printf("[DvdEmu] FATAL: Failed to allocate %u bytes for %s\n", size, gcPath); fflush(stdout);
fclose(f);
if (outSize)
*outSize = 0;
@@ -150,14 +150,14 @@ void* loadFile(const char* gcPath, u32* outSize, void* heap) {
fclose(f);
if (bytesRead != size) {
OSReport("[DvdEmu] WARNING: Read error: expected %u, got %u for %s\n", size, bytesRead,
gcPath);
printf("[DvdEmu] WARNING: Read error: expected %u, got %u for %s\n", size, bytesRead,
gcPath); fflush(stdout);
}
if (outSize)
*outSize = bytesRead;
OSReport("[DvdEmu] SUCCESS: Loaded %s (%u bytes)\n", gcPath, bytesRead);
printf("[DvdEmu] SUCCESS: Loaded %s (%u bytes)\n", gcPath, bytesRead); fflush(stdout);
return data;
}
@@ -166,7 +166,7 @@ u32 loadFileToBuffer(const char* gcPath, void* buffer, u32 bufferSize, u32 offse
FILE* f = fopen(fullPath.c_str(), "rb");
if (!f) {
OSReport("[DvdEmu] Failed to open file for buffer load: %s\n", fullPath.c_str());
printf("[DvdEmu] Failed to open file for buffer load: %s\n", fullPath.c_str()); fflush(stdout);
return 0;
}
@@ -186,7 +186,7 @@ u32 loadFileToBuffer(const char* gcPath, void* buffer, u32 bufferSize, u32 offse
s32 DVDConvertPathToEntrynum_Emu(const char* path) {
if (!DvdEmu::fileExists(path)) {
OSReport("[DVD] Error: File not found for entrynum conversion: %s\n", path);
printf("[DVD] Error: File not found for entrynum conversion: %s\n", path); fflush(stdout);
return -1;
}
+139 -31
View File
@@ -11,10 +11,60 @@
#include <memory>
#include <dusk/dvd_emu.h>
/*
#ifndef _WIN32
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#if __APPLE__
#include <mach/mach_time.h>
#endif
#endif
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#undef IN
#undef OUT
#endif
#if __APPLE__
static u64 MachToDolphinNum;
static u64 MachToDolphinDenom;
#elif _WIN32
static LARGE_INTEGER PerfFrequency;
#endif
*/
// ==========================================================================
// General OS
// ==========================================================================
// Credits: Super Monkey Ball
/*
static u64 GetGCTicks() {
#if __APPLE__
return mach_absolute_time() * MachToDolphinNum / MachToDolphinDenom;
#elif __linux__ || __FreeBSD__
struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp);
return ((tp.tv_sec * 1000000000ull) + tp.tv_nsec) * OS_CORE_CLOCK / 1000000000ull;
#elif _WIN32
LARGE_INTEGER perf;
QueryPerformanceCounter(&perf);
perf.QuadPart *= OS_CORE_CLOCK;
perf.QuadPart /= PerfFrequency.QuadPart;
return perf.QuadPart;
#else
return 0;
#endif
} */
u32 OSGetConsoleType() {
return OS_CONSOLE_RETAIL1;
}
@@ -230,8 +280,15 @@ void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime* td) {
if (td) memset(td, 0, sizeof(OSCalendarTime));
}
OSTick OSGetTick(void) { return 0; }
OSTime OSGetTime(void) { return 0; }
OSTime OSGetTime(void) {
//return (OSTime)GetGCTicks();
return 0;
}
OSTick OSGetTick(void) {
//return (OSTick)GetGCTicks();
return 0;
}
u16 OSGetFontEncode() { return 0; }
@@ -250,7 +307,13 @@ void OSSetStringTable(void* stringTable) {}
BOOL OSUnlink(OSModuleInfo* oldModule) { return FALSE; }
void OSSwitchFiberEx(__REGISTER u32 param_0, __REGISTER u32 param_1, __REGISTER u32 param_2,
__REGISTER u32 param_3, __REGISTER u32 code, __REGISTER u32 stack) {}
__REGISTER u32 param_3, __REGISTER u32 code, __REGISTER u32 stack) {
// On PC, call the function directly instead of switching stacks.
// The PPC version switches to 'stack' and calls code(param_0, param_1).
// Only caller is mDoPrintf_vprintf_Interrupt: OSSwitchFiberEx(fmt, args, 0, 0, vprintf, sp)
typedef void (*Func2)(u32, u32);
((Func2)(uintptr_t)code)(param_0, param_1);
}
u32 __OSGetDIConfig() { return 0; }
u32 OSGetProgressiveMode(void) { return 0; }
@@ -512,30 +575,35 @@ void LCEnable() {
#pragma mark VI
static VIRetraceCallback sVIRetraceCallback = NULL;
// VI retrace emulation: on GameCube, the VI chip fires a hardware interrupt at
// every VSync (~60Hz). This triggers pre/post retrace callbacks, which in turn
// send messages to JUTVideo's message queue. waitForTick() blocks on that queue.
// On PC, we simulate this by calling VIWaitForRetrace() once per frame in the
// main loop, which increments the retrace counter and fires the callbacks.
static u32 sRetraceCount = 0;
static VIRetraceCallback sVIPreRetraceCallback = NULL;
static VIRetraceCallback sVIPostRetraceCallback = NULL;
extern "C" {
void VIConfigure(const GXRenderModeObj* rm) {
puts("VIConfigure is a stub");
// puts("VIConfigure is a stub");
}
void VIConfigurePan(u16 xOrg, u16 yOrg, u16 width, u16 height) {
puts("VIConfigurePan is a stub");
// puts("VIConfigurePan is a stub");
}
u32 VIGetRetraceCount() {
// puts("VIGetRetraceCount is a stub");
return 0; // TODO this might be important
return sRetraceCount;
}
u32 VIGetNextField() {
puts("VIGetNextField is a stub");
return 0;
}
void VISetBlack(BOOL black) {
puts("VISetBlack is a stub");
// puts("VISetBlack is a stub");
}
void VISetNextFrameBuffer(void* fb) {
@@ -543,34 +611,37 @@ void VISetNextFrameBuffer(void* fb) {
}
void VIWaitForRetrace() {
if (sVIRetraceCallback) {
sVIRetraceCallback(0);
sRetraceCount++;
if (sVIPreRetraceCallback) {
sVIPreRetraceCallback(sRetraceCount);
}
if (sVIPostRetraceCallback) {
sVIPostRetraceCallback(sRetraceCount);
}
}
void* VIGetCurrentFrameBuffer(void) {
puts("VIGetCurrentFrameBuffer is a stub");
return NULL;
}
u32 VIGetDTVStatus(void) {
puts("VIGetDTVStatus is a stub");
return 0;
}
void* VIGetNextFrameBuffer(void) {
puts("VIGetNextFrameBuffer is a stub");
return NULL;
}
VIRetraceCallback VISetPostRetraceCallback(VIRetraceCallback callback) {
sVIRetraceCallback = callback;
return callback;
VIRetraceCallback old = sVIPostRetraceCallback;
sVIPostRetraceCallback = callback;
return old;
}
VIRetraceCallback VISetPreRetraceCallback(VIRetraceCallback cb) {
puts("VISetPreRetraceCallback is a stub");
return cb;
VIRetraceCallback old = sVIPreRetraceCallback;
sVIPreRetraceCallback = cb;
return old;
}
} // extern "C"
@@ -1396,19 +1467,58 @@ void GDSetVtxDescv(const GXVtxDescList* attrPtr) {
#pragma mark GX
#include <dolphin/gx.h>
// Dummy FIFO sink for direct GXWGFifo writes in J3D code (e.g. J3DFifo.h).
// On GameCube these write to the GX command processor at 0xCC008000.
// On PC, writes land here harmlessly and are discarded.
volatile PPCWGPipe GXWGFifo;
// GXCmd/GXParam/GXMatrixIndex: low-level command FIFO functions used by J3D.
// Route through Aurora's software FIFO so display list data is actually recorded.
//
// We forward-declare Aurora's FIFO functions with explicit stdint types instead of
// including fifo.hpp, because the game's u32 (unsigned long) differs from Aurora's
// u32 (uint32_t = unsigned int on MSVC). Including fifo.hpp would resolve its u32
// parameter types to the game's unsigned long (since game headers are included first
// and set the include guards), causing MSVC name mangling mismatches at link time.
namespace aurora::gfx::fifo {
void write_u8(uint8_t val);
void write_u16(uint16_t val);
void write_u32(uint32_t val);
void write_f32(float val);
}
// Cast to stdint types: game headers define u32=unsigned long, but Aurora uses
// uint32_t=unsigned int. Both are 32-bit on Win32 but have different MSVC name mangling.
void GXCmd1u8(const u8 x) { aurora::gfx::fifo::write_u8(static_cast<uint8_t>(x)); }
void GXCmd1u16(const u16 x) { aurora::gfx::fifo::write_u16(static_cast<uint16_t>(x)); }
void GXCmd1u32(const u32 x) { aurora::gfx::fifo::write_u32(static_cast<uint32_t>(x)); }
void GXParam1u8(const u8 x) { aurora::gfx::fifo::write_u8(static_cast<uint8_t>(x)); }
void GXParam1u16(const u16 x) { aurora::gfx::fifo::write_u16(static_cast<uint16_t>(x)); }
void GXParam1u32(const u32 x) { aurora::gfx::fifo::write_u32(static_cast<uint32_t>(x)); }
void GXParam1s8(const s8 x) { aurora::gfx::fifo::write_u8(static_cast<uint8_t>(x)); }
void GXParam1s16(const s16 x) { aurora::gfx::fifo::write_u16(static_cast<uint16_t>(x)); }
void GXParam1s32(const s32 x) { aurora::gfx::fifo::write_u32(static_cast<uint32_t>(x)); }
void GXParam1f32(const f32 x) { aurora::gfx::fifo::write_f32(x); }
void GXParam3f32(const f32 x, const f32 y, const f32 z) {
aurora::gfx::fifo::write_f32(x);
aurora::gfx::fifo::write_f32(y);
aurora::gfx::fifo::write_f32(z);
}
void GXParam4f32(const f32 x, const f32 y, const f32 z, const f32 w) {
aurora::gfx::fifo::write_f32(x);
aurora::gfx::fifo::write_f32(y);
aurora::gfx::fifo::write_f32(z);
aurora::gfx::fifo::write_f32(w);
}
void GXMatrixIndex1u8(const u8 x) { aurora::gfx::fifo::write_u8(static_cast<uint8_t>(x)); }
// Moved-in GX helpers and helpers for metrics/project
void __GXSetSUTexSize() {
puts("__GXSetSUTexSize is a stub");
}
void __GXSetVAT() {
puts("__GXSetVAT is a stub");
}
void __GXSetVCD() {
puts("__GXSetVCD is a stub");
}
void __GXUpdateBPMask() {
puts("__GXUpdateBPMask is a stub");
}
// __GXSetVAT, __GXSetVCD, __GXUpdateBPMask: now provided by Aurora's GXManage.cpp (fifo branch)
void GXSetGPMetric(GXPerf0 perf0, GXPerf1 perf1) {
// puts("GXSetGPMetric is a stub");
@@ -1494,9 +1604,7 @@ void GXProject(f32 x, f32 y, f32 z, const f32 mtx[3][4], const f32* pm, const f3
void GXAbortFrame(void) {
puts("GXAbortFrame is a stub");
}
void GXEnableTexOffsets(GXTexCoordID coord, u8 line_enable, u8 point_enable) {
puts("GXEnableTexOffsets is a stub");
}
// GXEnableTexOffsets: now provided by Aurora's GXGeometry.cpp (fifo branch)
OSThread* GXGetCurrentGXThread(void) {
puts("GXGetCurrentGXThread is a stub");
return NULL;
+10 -1
View File
@@ -720,11 +720,20 @@ void fapGm_After() {
}
void fapGm_Execute() {
static u32 sExecCount = 0;
if (sExecCount < 10 || (sExecCount % 300 == 0)) {
printf("[DIAG] fapGm_Execute frame=%d\n", sExecCount);
fflush(stdout);
}
sExecCount++;
#if DEBUG
JUTDbPrint::getManager()->setCharColor(g_HIO.mColor);
#endif
fpcM_Management(NULL, fapGm_After);
printf("[DIAG] fapGm_Execute: entering fpcM_Management...\n"); fflush(stdout);
fpcM_Management(NULL, fapGm_After);
printf("[DIAG] fapGm_Execute: fpcM_Management returned\n"); fflush(stdout);
cCt_Counter(0);
}
+5 -1
View File
@@ -7,6 +7,7 @@
#include "JSystem/JUtility/JUTAssert.h"
#include "f_op/f_op_scene_iter.h"
#include "f_op/f_op_scene_req.h"
#include <cstdio>
scene_class* fopScnM_SearchByID(fpc_ProcID id) {
return (scene_class*)fopScnIt_Judge((fop_ScnItFunc)fpcSch_JudgeByID, &id);
@@ -29,7 +30,10 @@ fpc_ProcID fopScnM_DeleteReq(scene_class* i_scene) {
}
int fopScnM_CreateReq(s16 i_procName, s16 param_2, u16 param_3, u32 i_data) {
return fopScnRq_Request(0, 0, i_procName, (void*)i_data, param_2, param_3) != fpcM_ERROR_PROCESS_ID_e;
printf("[DIAG] fopScnM_CreateReq: procName=%d fade=%d\n", i_procName, param_2); fflush(stdout);
fpc_ProcID result = fopScnRq_Request(0, 0, i_procName, (void*)i_data, param_2, param_3);
printf("[DIAG] fopScnM_CreateReq: result=%d (error=%d)\n", result, fpcM_ERROR_PROCESS_ID_e); fflush(stdout);
return result != fpcM_ERROR_PROCESS_ID_e;
}
u32 fopScnM_ReRequest(s16 i_procName, u32 i_data) {
+8 -1
View File
@@ -9,6 +9,7 @@
#include "f_op/f_op_scene_pause.h"
#include "f_pc/f_pc_executor.h"
#include "f_pc/f_pc_manager.h"
#include <cstdio>
static cPhs_Step fopScnRq_phase_ClearOverlap(scene_request_class* i_sceneReq) {
return fopOvlpM_ClearOfReq() == 1 ? cPhs_NEXT_e : cPhs_INIT_e;
@@ -16,7 +17,13 @@ static cPhs_Step fopScnRq_phase_ClearOverlap(scene_request_class* i_sceneReq) {
}
static cPhs_Step fopScnRq_phase_Execute(scene_request_class* i_sceneReq) {
return fpcNdRq_Execute(&i_sceneReq->create_request);
static int sExecLogCount = 0;
cPhs_Step ret = (cPhs_Step)fpcNdRq_Execute(&i_sceneReq->create_request);
if (sExecLogCount < 30) {
printf("[DIAG] fopScnRq_phase_Execute: ret=%d name=%d\n", ret, i_sceneReq->create_request.name); fflush(stdout);
sExecLogCount++;
}
return ret;
}
static cPhs_Step fopScnRq_phase_IsDoingOverlap(scene_request_class* i_sceneReq) {
+4
View File
@@ -14,6 +14,7 @@
#include "f_pc/f_pc_profile.h"
#include "f_pc/f_pc_debug_sv.h"
#include "Z2AudioLib/Z2AudioMgr.h"
#include <cstdio>
BOOL fpcBs_Is_JustOfType(int i_typeA, int i_typeB) {
if (i_typeB == i_typeA) {
@@ -118,10 +119,13 @@ base_process_class* fpcBs_Create(s16 i_profname, fpc_ProcID i_procID, void* i_ap
u32 size;
pprofile = (process_profile_definition*)fpcPf_Get(i_profname);
printf("[DIAG] fpcBs_Create: profname=%d profile=%p procSize=%d unkSize=%d\n",
i_profname, pprofile, pprofile->process_size, pprofile->unk_size); fflush(stdout);
size = pprofile->process_size + pprofile->unk_size;
pprocess = (base_process_class*)cMl::memalignB(-4, size);
if (pprocess == NULL) {
printf("[DIAG] fpcBs_Create: memalignB FAILED for size=%u\n", size); fflush(stdout);
return NULL;
}
+7
View File
@@ -11,6 +11,7 @@
#include "f_pc/f_pc_executor.h"
#include "f_pc/f_pc_layer.h"
#include "f_pc/f_pc_debug_sv.h"
#include <cstdio>
BOOL fpcCtRq_isCreatingByID(create_tag* i_createTag, fpc_ProcID* i_id) {
fpc_ProcID id = ((create_request*)i_createTag->base.mpTagData)->id;
@@ -91,6 +92,12 @@ BOOL fpcCtRq_Do(create_request* i_request) {
}
}
static int sCtRqDoLogCount = 0;
if (sCtRqDoLogCount < 30) {
printf("[DIAG] fpcCtRq_Do: phase=%d process=%p\n", phase, i_request->process); fflush(stdout);
sCtRqDoLogCount++;
}
switch (phase) {
case cPhs_COMPLEATE_e: {
if (fpcEx_ToExecuteQ(i_request->process) == 0)
+7
View File
@@ -8,6 +8,7 @@
#include "f_pc/f_pc_leaf.h"
#include "f_pc/f_pc_node.h"
#include "f_pc/f_pc_pause.h"
#include <cstdio>
int fpcDw_Execute(base_process_class* i_proc) {
if (!fpcPause_IsEnable(i_proc, 2)) {
@@ -32,9 +33,15 @@ int fpcDw_Execute(base_process_class* i_proc) {
}
int fpcDw_Handler(fpcDw_HandlerFuncFunc i_iterHandler, fpcDw_HandlerFunc i_func) {
static int sDwLogCount = 0;
int ret;
if (sDwLogCount < 5) { printf("[DIAG] fpcDw_Handler: before BeforeOfDraw\n"); fflush(stdout); }
cAPIGph_BeforeOfDraw();
if (sDwLogCount < 5) { printf("[DIAG] fpcDw_Handler: before draw iteration\n"); fflush(stdout); }
ret = i_iterHandler(i_func);
if (sDwLogCount < 5) { printf("[DIAG] fpcDw_Handler: before AfterOfDraw\n"); fflush(stdout); }
cAPIGph_AfterOfDraw();
if (sDwLogCount < 5) { printf("[DIAG] fpcDw_Handler: done\n"); fflush(stdout); }
sDwLogCount++;
return ret;
}
+32 -2
View File
@@ -20,6 +20,7 @@
#include "f_pc/f_pc_pause.h"
#include "f_pc/f_pc_priority.h"
#include "m_Do/m_Do_controller_pad.h"
#include <cstdio>
void fpcM_Draw(void* i_proc) {
fpcDw_Execute((base_process_class*)i_proc);
@@ -42,16 +43,26 @@ BOOL fpcM_IsCreating(fpc_ProcID i_id) {
}
void fpcM_Management(fpcM_ManagementFunc i_preExecuteFn, fpcM_ManagementFunc i_postExecuteFn) {
static int sMgmtLogCount = 0;
MtxInit();
if (!fapGm_HIO_c::isCaptureScreen()) {
dComIfGd_peekZdata();
}
fapGm_HIO_c::executeCaptureScreen();
if (!dShutdownErrorMsg_c::execute()) {
bool shutdownRet = dShutdownErrorMsg_c::execute();
if (sMgmtLogCount < 10) {
printf("[DIAG] fpcM_Management: shutdown=%d\n", shutdownRet); fflush(stdout);
}
if (!shutdownRet) {
static bool l_dvdError = false;
if (!dDvdErrorMsg_c::execute()) {
bool dvdErrRet = dDvdErrorMsg_c::execute();
if (sMgmtLogCount < 10) {
printf("[DIAG] fpcM_Management: dvdError=%d\n", dvdErrRet); fflush(stdout);
}
if (!dvdErrRet) {
if (l_dvdError) {
dLib_time_c::startTime();
Z2GetSoundMgr()->pauseAllGameSound(false);
@@ -60,36 +71,55 @@ void fpcM_Management(fpcM_ManagementFunc i_preExecuteFn, fpcM_ManagementFunc i_p
cAPIGph_Painter();
if (sMgmtLogCount < 10) { printf("[DIAG] fpcM_Management: after cAPIGph_Painter\n"); fflush(stdout); }
if (!dPa_control_c::isStatus(1)) {
fpcDt_Handler();
} else {
dPa_control_c::offStatus(1);
}
if (sMgmtLogCount < 10) { printf("[DIAG] fpcM_Management: after fpcDt_Handler\n"); fflush(stdout); }
if (!fpcPi_Handler()) {
JUT_ASSERT(353, FALSE);
}
if (sMgmtLogCount < 10) { printf("[DIAG] fpcM_Management: after fpcPi_Handler\n"); fflush(stdout); }
if (!fpcCt_Handler()) {
JUT_ASSERT(357, FALSE);
}
if (sMgmtLogCount < 10) { printf("[DIAG] fpcM_Management: after fpcCt_Handler\n"); fflush(stdout); }
if (i_preExecuteFn != NULL) {
i_preExecuteFn();
}
if (sMgmtLogCount < 10) { printf("[DIAG] fpcM_Management: after preExecute\n"); fflush(stdout); }
if (!fapGm_HIO_c::isCaptureScreen()) {
fpcEx_Handler((fpcLnIt_QueueFunc)fpcM_Execute);
}
if (sMgmtLogCount < 10) { printf("[DIAG] fpcM_Management: after fpcEx_Handler\n"); fflush(stdout); }
if (!fapGm_HIO_c::isCaptureScreen() || fapGm_HIO_c::getCaptureScreenDivH() != 1) {
fpcDw_Handler((fpcDw_HandlerFuncFunc)fpcM_DrawIterater, (fpcDw_HandlerFunc)fpcM_Draw);
}
if (sMgmtLogCount < 10) { printf("[DIAG] fpcM_Management: after fpcDw_Handler\n"); fflush(stdout); }
if (i_postExecuteFn != NULL) {
if (sMgmtLogCount < 10) {
printf("[DIAG] fpcM_Management: calling postExecuteFn (fapGm_After)\n"); fflush(stdout);
}
i_postExecuteFn();
}
dComIfGp_drawSimpleModel();
sMgmtLogCount++;
} else if (!l_dvdError) {
dLib_time_c::stopTime();
Z2GetSoundMgr()->pauseAllGameSound(true);
+9
View File
@@ -12,6 +12,7 @@
#include "f_pc/f_pc_stdcreate_req.h"
#include "f_pc/f_pc_manager.h"
#include "f_pc/f_pc_debug_sv.h"
#include <cstdio>
void fpcNdRq_RequestQTo(node_create_request* i_request) {
fpcLy_CreatedMesg(i_request->layer);
@@ -47,10 +48,12 @@ int fpcNdRq_phase_IsCreated(node_create_request* i_request) {
}
int fpcNdRq_phase_Create(node_create_request* i_request) {
printf("[DIAG] fpcNdRq_phase_Create: name=%d layer=%p\n", i_request->name, i_request->layer); fflush(stdout);
i_request->creating_id =
fpcSCtRq_Request(i_request->layer, i_request->name,
(stdCreateFunc)i_request->create_req_methods->post_method, i_request,
i_request->data);
printf("[DIAG] fpcNdRq_phase_Create: creating_id=%d (error=%d)\n", i_request->creating_id, fpcM_ERROR_PROCESS_ID_e); fflush(stdout);
if (i_request->creating_id == fpcM_ERROR_PROCESS_ID_e) {
return cPhs_UNK3_e;
}
@@ -140,6 +143,12 @@ int fpcNdRq_Cancel(node_create_request* i_request) {
int fpcNdRq_Handler() {
node_class* node = l_fpcNdRq_Queue.mpHead;
static int sNdRqLogCount = 0;
if (l_fpcNdRq_Queue.mSize > 0 && sNdRqLogCount < 30) {
printf("[DIAG] fpcNdRq_Handler: queue size=%d\n", l_fpcNdRq_Queue.mSize); fflush(stdout);
sNdRqLogCount++;
}
#if DEBUG
if (g_fpcDbSv_service[9] != NULL) {
g_fpcDbSv_service[9](&l_fpcNdRq_Queue.mSize);
+10
View File
@@ -9,9 +9,11 @@
#include "f_pc/f_pc_manager.h"
#include "f_pc/f_pc_debug_sv.h"
#include <dolphin/dolphin.h>
#include <cstdio>
int fpcSCtRq_phase_Load(standard_create_request_class* i_request) {
int ret = fpcLd_Load(i_request->process_name);
printf("[DIAG] fpcSCtRq_phase_Load: procName=%d ret=%d\n", i_request->process_name, ret); fflush(stdout);
switch (ret) {
case cPhs_INIT_e:
@@ -26,15 +28,18 @@ int fpcSCtRq_phase_Load(standard_create_request_class* i_request) {
}
int fpcSCtRq_phase_CreateProcess(standard_create_request_class* i_request) {
printf("[DIAG] fpcSCtRq_phase_CreateProcess: procName=%d\n", i_request->process_name); fflush(stdout);
fpcLy_SetCurrentLayer(i_request->base.layer);
i_request->base.process =
fpcBs_Create(i_request->process_name, i_request->base.id, i_request->process_append);
if (i_request->base.process == NULL) {
printf("[DIAG] fpcSCtRq_phase_CreateProcess: fpcBs_Create FAILED for procName=%d\n", i_request->process_name); fflush(stdout);
OS_REPORT("fpcSCtRq_phase_CreateProcess %d\n", i_request->process_name);
fpcLd_Free(i_request->process_name);
return cPhs_ERROR_e;
} else {
printf("[DIAG] fpcSCtRq_phase_CreateProcess: fpcBs_Create OK proc=%p\n", i_request->base.process); fflush(stdout);
i_request->base.process->create_req = &i_request->base;
return cPhs_NEXT_e;
}
@@ -43,6 +48,11 @@ int fpcSCtRq_phase_CreateProcess(standard_create_request_class* i_request) {
int fpcSCtRq_phase_SubCreateProcess(standard_create_request_class* i_request) {
fpcLy_SetCurrentLayer(i_request->base.layer);
int ret = fpcBs_SubCreate(i_request->base.process);
static int sSubCreateLogCount = 0;
if (sSubCreateLogCount < 20) {
printf("[DIAG] fpcSCtRq_phase_SubCreateProcess: procName=%d ret=%d\n", i_request->process_name, ret); fflush(stdout);
sSubCreateLogCount++;
}
#if DEBUG
if (ret == 0 && i_request->unk_0x60-- <= 0) {
+29 -12
View File
@@ -4,11 +4,15 @@
*/
#include "m_Do/m_Do_DVDError.h"
#include "JSystem/JKernel/JKRAssertHeap.h"
#include <dolphin/os.h>
#include "JSystem/JKernel/JKRAssertHeap.h"
#include "m_Do/m_Do_Reset.h"
#include "m_Do/m_Do_dvd_thread.h"
#include "m_Do/m_Do_ext.h"
#include "m_Do/m_Do_Reset.h"
// Added for the sleep workaround
#include <chrono>
#include <thread>
#if PLATFORM_GCN
const int stack_size = 3072;
@@ -16,7 +20,6 @@ const int stack_size = 3072;
const int stack_size = 8192;
#endif
bool mDoDvdErr_initialized;
static OSThread DvdErr_thread;
@@ -26,20 +29,24 @@ static OSThread DvdErr_thread;
static u8 DvdErr_stack[stack_size] ATTRIBUTE_ALIGN(16);
#pragma pop
static OSAlarm Alarm;
// Alarm is not needed for the PC workaround
// static OSAlarm Alarm;
void mDoDvdErr_ThdInit() {
if (mDoDvdErr_initialized) {
return;
}
OSTime time = OSGetTime();
// OSTime time = OSGetTime(); // Unused in workaround
OSCreateThread(&DvdErr_thread, (void*(*)(void*))mDoDvdErr_Watch, NULL, DvdErr_stack + sizeof(DvdErr_stack),
sizeof(DvdErr_stack), OSGetThreadPriority(OSGetCurrentThread()) - 3, 1);
OSCreateThread(&DvdErr_thread, (void* (*)(void*))mDoDvdErr_Watch, NULL,
DvdErr_stack + sizeof(DvdErr_stack), sizeof(DvdErr_stack),
OSGetThreadPriority(OSGetCurrentThread()) - 3, 1);
OSResumeThread(&DvdErr_thread);
OSCreateAlarm(&Alarm);
OSSetPeriodicAlarm(&Alarm, time, OS_BUS_CLOCK / 4, AlarmHandler);
// PC Workaround: Disable Alarm logic. The thread will sleep itself.
// OSCreateAlarm(&Alarm);
// OSSetPeriodicAlarm(&Alarm, time, OS_BUS_CLOCK / 4, AlarmHandler);
mDoDvdErr_initialized = true;
}
@@ -47,7 +54,7 @@ void mDoDvdErr_ThdInit() {
void mDoDvdErr_ThdCleanup() {
if (mDoDvdErr_initialized) {
OSCancelThread(&DvdErr_thread);
OSCancelAlarm(&Alarm);
// OSCancelAlarm(&Alarm); // Disable Alarm cancel
mDoDvdErr_initialized = false;
}
}
@@ -66,10 +73,20 @@ static void mDoDvdErr_Watch(void*) {
if (status == DVD_STATE_FATAL_ERROR) {
mDoDvdThd::suspend();
}
OSSuspendThread(&DvdErr_thread);
// PC Workaround:
// Instead of suspending and waiting for an Alarm (which might not be implemented),
// we simply sleep for a short duration.
// OS_BUS_CLOCK / 4 corresponds to roughly 1/4th of a second on GC.
// We use 250ms here to simulate the periodic check.
// OSSuspendThread(&DvdErr_thread); // <-- Original causing deadlock without Alarm
std::this_thread::sleep_for(std::chrono::milliseconds(250));
} while (true);
}
static void AlarmHandler(OSAlarm*, OSContext*) {
// This handler is no longer called in the PC workaround
OSResumeThread(&DvdErr_thread);
}
}
+10
View File
@@ -3,6 +3,8 @@
* Graphics Management Functions
*/
#include <cstdio>
#include "d/dolzel.h" // IWYU pragma: keep
#include "JSystem/J2DGraph/J2DOrthoGraph.h"
@@ -1511,6 +1513,14 @@ static void drawItem3D() {
}
int mDoGph_Painter() {
// Diagnostic: log windowNum to track game state machine progress
static bool sDiagLoggedWindow = false;
if (!sDiagLoggedWindow) {
int wn = dComIfGp_getWindowNum();
printf("[DIAG] mDoGph_Painter: windowNum=%d\n", wn); fflush(stdout);
if (wn != 0) sDiagLoggedWindow = true;
}
#if DEBUG
drawHeapMap();
#endif
+8
View File
@@ -5,6 +5,7 @@
*/
#include "m_Do/m_Do_main.h"
#include <dolphin/vi.h>
#include <string>
#include "DynamicLink.h"
#include "JSystem/JAudio2/JASAudioThread.h"
@@ -178,11 +179,18 @@ void main01(void) {
mDoCPd_c::read(); // Read Controller
// Simulate VI retrace interrupt — fires post-retrace callback which sends
// a message to JUTVideo's queue, unblocking waitForTick() in beginRender()
VIWaitForRetrace();
// --- EXECUTE GAME LOGIC & RENDER ---
printf("[DIAG] main01: before fapGm_Execute (frame %d)\n", frame); fflush(stdout);
fapGm_Execute();
printf("[DIAG] main01: after fapGm_Execute\n"); fflush(stdout);
// --- Frame End & Limiter ---
aurora_end_frame();
printf("[DIAG] main01: after aurora_end_frame\n"); fflush(stdout);
std::this_thread::sleep_for(std::chrono::milliseconds(16)); // ~60 FPS Cap
} while (true);