Aurora DVD support (#43)

* Aurora DVD support

* Remove commented code

* Restore STUB_LOG
This commit is contained in:
Luke Street
2026-03-09 01:33:04 -06:00
committed by GitHub
parent d35381a60e
commit 746d01e44c
12 changed files with 47 additions and 423 deletions
+5 -1
View File
@@ -10,6 +10,10 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
if (CMAKE_SYSTEM_NAME STREQUAL Linux)
set(DAWN_USE_WAYLAND ON CACHE BOOL "Enable support for Wayland surface" FORCE)
endif ()
set(AURORA_ENABLE_DVD ON CACHE BOOL "Enable DVD API support" FORCE)
add_subdirectory(extern/aurora EXCLUDE_FROM_ALL)
option(DUSK_BUILD_WARNINGS "If off, compiler warnings will be suppressed")
@@ -80,7 +84,7 @@ target_include_directories(game_debug PUBLIC
extern
${CMAKE_SOURCE_DIR}/build/${DUSK_TP_VERSION}/include
build/${DUSK_TP_VERSION}/include)
target_link_libraries(game_debug PUBLIC aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os)
target_link_libraries(game_debug PUBLIC aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_library(game SHARED ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${SSYSTEM_FILES} ${JSYSTEM_FILES} ${REL_FILES} ${DUSK_FILES} ${DOLPHIN_FILES})
+6 -1
View File
@@ -62,4 +62,9 @@ cmake -B build/dusk -GNinja
ninja -C build/dusk
```
After building the executable, extract the original game files to a folder named `data` in the same folder as the executable.
#### Running
Pass the disc image as a positional argument. Supported formats: ISO (GCM), RVZ, WIA, WBFS, CISO, GCZ
```sh
build/dusk/dusk /path/to/game.rvz
```
If no path is specified, Dusk defaults to `game.iso` in the current working directory.
+1 -1
-1
View File
@@ -1335,7 +1335,6 @@ set(DUSK_FILES
src/dusk/extras.cpp
src/dusk/globals.cpp
#src/dusk/m_Do_ext_dusk.cpp
src/dusk/dvd_emu.cpp
src/dusk/imgui/imgui.hpp
src/dusk/imgui/processes.cpp
src/dusk/imgui/camera.cpp
-45
View File
@@ -1,45 +0,0 @@
#ifndef DOLPHIN_DVD_EMU_H
#define DOLPHIN_DVD_EMU_H
#include "dolphin/types.h"
#include <string>
// PC-Emulation der DVD-Funktionen
namespace DvdEmu {
// Basis-Pfad zum Datenordner (relativ zur .exe)
void setBasePath(const char* path);
const char* getBasePath();
// Konvertiert GameCube-Pfad zu PC-Pfad
// z.B. "/res/Object/LogoUs.arc" -> "C:/Games/Dusk/data/res/Object/LogoUs.arc"
std::string convertPath(const char* gcPath);
// Prüft ob Datei existiert
bool fileExists(const char* gcPath);
// Lädt Datei komplett in Speicher
// Gibt Pointer zurück, Größe wird in outSize geschrieben
// Caller muss Speicher mit free() freigeben
void* loadFile(const char* gcPath, u32* outSize, void* heap = nullptr);
// Lädt Datei in vorhandenen Buffer
// Gibt gelesene Bytes zurück
u32 loadFileToBuffer(const char* gcPath, void* buffer, u32 bufferSize, u32 offset = 0);
// Datei-Größe abfragen
u32 getFileSize(const char* gcPath);
} // namespace DvdEmu
// Ersatz für DVDConvertPathToEntrynum
// Gibt einen "Fake" Entry-Number zurück (Hash des Pfads) oder -1 wenn nicht gefunden
s32 DVDConvertPathToEntrynum_Emu(const char* path);
// Speichert Pfad für Entry-Number (für späteres Laden)
void DVDRegisterPath(s32 entryNum, const char* path);
// Holt Pfad für Entry-Number
const char* DVDGetPathForEntry(s32 entryNum);
#endif // DOLPHIN_DVD_EMU_H
@@ -240,7 +240,7 @@ inline void* operator new[](size_t, JKRHeapToken, void* where) {
#define JKR_NEW new (JKRHeapToken::Dummy)
#define JKR_NEW_ARGS(...) new (JKRHeapToken::Dummy, __VA_ARGS__ )
#define JKR_DELETE(expr) jkrDelete(expr)
#define JKR_DELETE_ARRAY(expr) delete[] (expr)
#define JKR_DELETE_ARRAY(expr) jkrDeleteArray(expr)
#define JKR_HEAP_TOKEN , JKRHeapToken::Dummy
#define JKR_HEAP_TOKEN_PARAM , JKRHeapToken
#else
@@ -261,7 +261,7 @@ void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM, int alignment);
void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM, JKRHeap* heap, int alignment);
void operator delete(void* ptr JKR_HEAP_TOKEN_PARAM);
void operator delete[](void* ptr);
void operator delete[](void* ptr JKR_HEAP_TOKEN_PARAM);
#if TARGET_PC
template<typename T>
@@ -281,6 +281,10 @@ inline void jkrDelete(void* ptr) {
operator delete(ptr, JKRHeapToken::Dummy);
}
static void jkrDeleteArray(void* ptr) {
operator delete[](ptr, JKRHeapToken::Dummy);
}
#endif
void JKRDefaultMemoryErrorRoutine(void* heap, u32 size, int alignment);
+1 -1
View File
@@ -38,7 +38,7 @@ void J2DScreen::clean() {
mFontRes = NULL;
if (mNameTable != NULL) {
JKR_DELETE_ARRAY(mNameTable->getResNameTable());
JKR_DELETE_ARRAY(const_cast<ResNTAB*>(mNameTable->getResNameTable()));
JKR_DELETE(mNameTable);
mNameTable = NULL;
}
+2 -1
View File
@@ -3,7 +3,8 @@
#include "JSystem/JGadget/binary.h"
#include "JSystem/JGadget/define.h"
#include "global.h"
#include <stdint.h>
#include <cstdint>
#include <cstdlib>
#include "global.h"
+1 -9
View File
@@ -593,14 +593,6 @@ void* operator new[](size_t size) {
return JKRHeap::alloc(size, 4, NULL);
}
#else
void* operator new[](size_t size) {
return fallback_alloc(size, 0, false);
}
void* operator new[](std::size_t size, const std::nothrow_t&) noexcept {
return fallback_alloc(size, 0, false);
}
void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM) {
void* mem = JKRHeap::alloc(size, alignof(max_align_t), NULL);
if (mem == NULL) {
@@ -654,7 +646,7 @@ void operator delete[](void* ptr) {
JKRHeap::free(ptr, NULL);
}
#else
void operator delete[](void* ptr) {
void operator delete[](void* ptr JKR_HEAP_TOKEN_PARAM) {
if (ptr == NULL)
return;
JKRHeap* heap = JKRHeap::findFromRoot(ptr);
-218
View File
@@ -1,218 +0,0 @@
#include "dusk/dvd_emu.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unordered_map>
#include "dolphin/os.h"
#include "dusk/logging.h"
#ifdef _WIN32
#include <windows.h>
#include <direct.h>
#define PATH_SEP '\\'
#else
#include <sys/stat.h>
#include <unistd.h>
#define PATH_SEP '/'
#endif
namespace {
s32 g_nextEntryNum = 1;
// Lazy-init to avoid crash during DLL static initialization
std::string& g_basePath() {
static std::string instance = "data";
return instance;
}
std::unordered_map<s32, std::string>& getEntryPaths() {
static std::unordered_map<s32, std::string> instance;
return instance;
}
} // namespace
namespace DvdEmu {
void setBasePath(const char* path) {
#ifdef _WIN32
char exePath[MAX_PATH];
GetModuleFileNameA(NULL, exePath, MAX_PATH);
// Get the directory of the .exe
char* lastSlash = strrchr(exePath, '\\');
if (lastSlash) {
*lastSlash = '\0';
}
// exeDir + "/" + path
g_basePath() = exePath;
g_basePath() += PATH_SEP;
g_basePath() += path;
#else
g_basePath() = path;
#endif
DuskLog.debug("[DvdEmu] Base path set to: %s\n", g_basePath().c_str());
}
const char* getBasePath() {
return g_basePath().c_str();
}
std::string convertPath(const char* gcPath) {
std::string result = g_basePath();
// Skip leading slashes
const char* p = gcPath;
while (*p == '/' || *p == '\\')
p++;
result += PATH_SEP;
// Append path, converting slashes
while (*p) {
if (*p == '/' || *p == '\\') {
result += PATH_SEP;
} else {
result += *p;
}
p++;
}
return result;
}
bool fileExists(const char* gcPath) {
std::string fullPath = convertPath(gcPath);
#ifdef _WIN32
DWORD attrib = GetFileAttributesA(fullPath.c_str());
bool exists = (attrib != INVALID_FILE_ATTRIBUTES && !(attrib & FILE_ATTRIBUTE_DIRECTORY));
#else
struct stat st;
bool exists = (stat(fullPath.c_str(), &st) == 0 && S_ISREG(st.st_mode));
#endif
if (exists) {
DuskLog.info("[DvdEmu] FOUND: {}", gcPath);
} else {
DuskLog.warn("[DvdEmu] MISSING: {}", gcPath);
}
return exists;
}
u32 getFileSize(const char* gcPath) {
std::string fullPath = convertPath(gcPath);
FILE* f = fopen(fullPath.c_str(), "rb");
if (!f)
return 0;
fseek(f, 0, SEEK_END);
u32 size = (u32)ftell(f);
fclose(f);
return size;
}
void* loadFile(const char* gcPath, u32* outSize, void* heap) {
std::string fullPath = convertPath(gcPath);
DuskLog.debug("[DvdEmu] Loading request: '{}'", gcPath);
FILE* f = fopen(fullPath.c_str(), "rb");
if (!f) {
DuskLog.error("[DvdEmu] Failed to open file at physical path: {}", fullPath.c_str());
if (outSize)
*outSize = 0;
return nullptr;
}
fseek(f, 0, SEEK_END);
u32 size = (u32)ftell(f);
fseek(f, 0, SEEK_SET);
// Allocate with 32-byte alignment (matching GameCube)
void* data;
#ifdef _WIN32
data = _aligned_malloc(size, 32);
#else
data = aligned_alloc(32, (size + 31) & ~31);
#endif
if (!data) {
DuskLog.fatal("[DvdEmu] Failed to allocate {} bytes for {}", size, gcPath);
fclose(f);
if (outSize)
*outSize = 0;
return nullptr;
}
u32 bytesRead = (u32)fread(data, 1, size, f);
fclose(f);
if (bytesRead != size) {
DuskLog.fatal("[DvdEmu] Read error: expected {}, got {} for {}", size, bytesRead,
gcPath);
}
if (outSize)
*outSize = bytesRead;
DuskLog.info("[DvdEmu] Loaded {} ({} bytes)", gcPath, bytesRead);
return data;
}
u32 loadFileToBuffer(const char* gcPath, void* buffer, u32 bufferSize, u32 offset) {
std::string fullPath = convertPath(gcPath);
FILE* f = fopen(fullPath.c_str(), "rb");
if (!f) {
DuskLog.error("[DvdEmu] Failed to open file for buffer load: {}", fullPath.c_str());
return 0;
}
if (offset > 0) {
fseek(f, offset, SEEK_SET);
}
u32 bytesRead = (u32)fread(buffer, 1, bufferSize, f);
fclose(f);
return bytesRead;
}
} // namespace DvdEmu
// Entry-Number System (emulates DVD's entry system)
s32 DVDConvertPathToEntrynum_Emu(const char* path) {
if (!DvdEmu::fileExists(path)) {
printf("[DVD] Error: File not found for entrynum conversion: %s\n", path);
return -1;
}
// Check if already registered
for (const auto& pair : getEntryPaths()) {
if (pair.second == path) {
return pair.first;
}
}
// Assign new entry number
s32 entryNum = g_nextEntryNum++;
getEntryPaths()[entryNum] = path;
return entryNum;
}
void DVDRegisterPath(s32 entryNum, const char* path) {
getEntryPaths()[entryNum] = path;
}
const char* DVDGetPathForEntry(s32 entryNum) {
auto it = getEntryPaths().find(entryNum);
if (it != getEntryPaths().end()) {
return it->second.c_str();
}
return nullptr;
}
-118
View File
@@ -9,7 +9,6 @@
#include <condition_variable>
#include <unordered_map>
#include <memory>
#include <dusk/dvd_emu.h>
#include <dusk/logging.h>
@@ -1169,123 +1168,6 @@ void AIStopDMA(void) {
STUB_LOG();
}
#pragma mark DVD
#include <dolphin/dvd.h>
s32 DVDCancel(volatile DVDCommandBlock* block) {
STUB_LOG();
return 0;
}
s32 DVDCancel(DVDCommandBlock* block) {
STUB_LOG();
return 0;
}
BOOL DVDChangeDir(const char* dirName) {
STUB_LOG();
return TRUE;
}
BOOL DVDCheckDisk(void) {
STUB_LOG();
return TRUE;
}
BOOL DVDClose(DVDFileInfo* fileInfo) {
STUB_LOG();
return TRUE;
}
int DVDCloseDir(DVDDir* dir) {
STUB_LOG();
return 0;
}
s32 DVDConvertPathToEntrynum(const char* pathPtr) {
return DVDConvertPathToEntrynum_Emu(pathPtr);
}
BOOL DVDFastOpen(s32 entrynum, DVDFileInfo* fileInfo) {
const char* path = DVDGetPathForEntry(entrynum);
if (!path) {
OSReport("[DVD] DVDFastOpen: no path for entry %d\n", entrynum);
return FALSE;
}
u32 fileSize = DvdEmu::getFileSize(path);
if (fileSize == 0) {
OSReport("[DVD] DVDFastOpen: file not found or empty for entry %d (%s)\n", entrynum, path);
return FALSE;
}
// Repurpose startAddr to store entrynum for later DVDReadPrio lookups
fileInfo->startAddr = (u32)entrynum;
fileInfo->length = fileSize;
fileInfo->callback = NULL;
fileInfo->cb.state = 0;
return TRUE;
}
s32 DVDGetCommandBlockStatus(const DVDCommandBlock* block) {
STUB_LOG();
return 0;
}
DVDDiskID* DVDGetCurrentDiskID(void) {
STUB_LOG();
return NULL;
}
s32 DVDGetDriveStatus(void) {
STUB_LOG();
return 0;
}
void DVDInit(void) {
STUB_LOG();
}
BOOL DVDOpen(const char* fileName, DVDFileInfo* fileInfo) {
s32 entryNum = DVDConvertPathToEntrynum(fileName);
if (entryNum < 0) {
OSReport("[DVD] DVDOpen: file not found: %s\n", fileName);
return FALSE;
}
return DVDFastOpen(entryNum, fileInfo);
}
int DVDOpenDir(const char* dirName, DVDDir* dir) {
STUB_LOG();
return 0;
}
BOOL DVDReadAsyncPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset,
DVDCallback callback, s32 prio) {
// Synchronous read, then invoke callback with result
s32 entryNum = (s32)fileInfo->startAddr;
const char* path = DVDGetPathForEntry(entryNum);
if (!path) {
OSReport("[DVD] DVDReadAsyncPrio: no path for entry %d\n", entryNum);
if (callback) callback(-1, fileInfo);
return FALSE;
}
u32 bytesRead = DvdEmu::loadFileToBuffer(path, addr, (u32)length, (u32)offset);
if (callback) {
callback((s32)bytesRead, fileInfo);
}
return TRUE;
}
int DVDReadDir(DVDDir* dir, DVDDirEntry* dirent) {
STUB_LOG();
return 0;
}
s32 DVDReadPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, s32 prio) {
s32 entryNum = (s32)fileInfo->startAddr;
const char* path = DVDGetPathForEntry(entryNum);
if (!path) {
OSReport("[DVD] DVDReadPrio: no path for entry %d\n", entryNum);
return -1;
}
u32 bytesRead = DvdEmu::loadFileToBuffer(path, addr, (u32)length, (u32)offset);
return (s32)bytesRead;
}
void DVDReadAbsAsyncForBS(void* a, struct bb2struct* b, int c, int d, void (*e)()) {
STUB_LOG();
}
void DVDReadDiskID(void* a, DVDDiskID* b, void (*c)()) {
STUB_LOG();
}
void DVDReset() {
STUB_LOG();
}
#pragma mark GX
#include <dolphin/gx.h>
+25 -25
View File
@@ -44,13 +44,14 @@
#include <chrono>
#include <thread>
#include "SSystem/SComponent/c_API.h"
#include "dusk/dvd_emu.h"
#include "dusk/dusk.h"
#include "dusk/logging.h"
#include <aurora/aurora.h>
#include <aurora/event.h>
#include <aurora/main.h>
#include <aurora/dvd.h>
#include <dolphin/dvd.h>
#include "cxxopts.hpp"
@@ -67,7 +68,7 @@ const int audioHeapSize = 0x14D800;
#endif
// =========================================================================
// LOAD_COPYDATE - PC Version using DvdEmu
// LOAD_COPYDATE - PC Version
// =========================================================================
#define COPYDATE_PATH "/str/Final/Release/COPYDATE"
@@ -75,33 +76,26 @@ s32 LOAD_COPYDATE(void*) {
char buffer[32];
memset(buffer, 0, sizeof(buffer));
u32 size = 0;
void* data = DvdEmu::loadFile(COPYDATE_PATH, &size, nullptr);
DVDFileInfo fi;
if (DVDOpen(COPYDATE_PATH, &fi)) {
u32 readLen = (fi.length < sizeof(buffer) - 1) ? fi.length : sizeof(buffer) - 1;
// DVDReadPrio requires 32-byte aligned buffer and length rounded up to 32
u32 alignedLen = (readLen + 31) & ~31;
alignas(32) char readBuf[64];
DVDReadPrio(&fi, readBuf, alignedLen, 0, 2);
DVDClose(&fi);
// Fallback: Try root if not found
if (!data) {
data = DvdEmu::loadFile("/COPYDATE", &size, nullptr);
}
if (data) {
u32 copyLen = (size < sizeof(buffer) - 1) ? size : sizeof(buffer) - 1;
memcpy(buffer, data, copyLen);
buffer[copyLen] = '\0';
#ifdef _WIN32
_aligned_free(data);
#else
free(data);
#endif
memcpy(buffer, readBuf, readLen);
buffer[readLen] = '\0';
} else {
strcpy(buffer, "PC PORT BUILD");
OSReport("Warning: COPYDATE file not found at %s\n", COPYDATE_PATH);
DuskLog.warn("COPYDATE file not found at {}", COPYDATE_PATH);
}
memcpy(mDoMain::COPYDATE_STRING, buffer, sizeof(mDoMain::COPYDATE_STRING) - 1);
mDoMain::COPYDATE_STRING[sizeof(mDoMain::COPYDATE_STRING) - 1] = '\0';
OS_REPORT("\x1b[36mCOPYDATE=[%s]\n\x1b[m", mDoMain::COPYDATE_STRING);
DuskLog.info("COPYDATE=[{}]", mDoMain::COPYDATE_STRING);
return 1;
}
@@ -203,8 +197,11 @@ int game_main(int argc, char* argv[]) {
arg_options.add_options()
("l,log-level", "Log level from " + std::to_string(AuroraLogLevel::LOG_DEBUG) + " to " + std::to_string(AuroraLogLevel::LOG_FATAL), cxxopts::value<uint8_t>()->default_value("0"))
("h,help", "Print usage");
("h,help", "Print usage")
("dvd", "Path to DVD image file", cxxopts::value<std::string>()->default_value("game.iso"));
arg_options.parse_positional({"dvd"});
arg_options.positional_help("<dvd-image>");
arg_options.allow_unrecognised_options();
parsed_arg_options = arg_options.parse(argc, argv);
@@ -234,10 +231,13 @@ int game_main(int argc, char* argv[]) {
auroraInfo = aurora_initialize(argc, argv, &config);
OSInit();
const auto& dvd_path = parsed_arg_options["dvd"].as<std::string>();
DuskLog.info("Loading DVD image: {}", dvd_path);
if (!aurora_dvd_open(dvd_path.c_str())) {
DuskLog.fatal("Failed to open DVD image: {}", dvd_path);
}
// 3. Init DVD Emulation
DvdEmu::setBasePath("data");
OSInit();
mDoMain::sPowerOnTime = OSGetTime();