mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-06-22 06:56:31 -04:00
first try to draw first logo
This commit is contained in:
@@ -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")
|
||||
|
||||
Vendored
+1
-1
Submodule extern/aurora updated: 223bcf39b8...928834269d
@@ -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) {
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user