Initial aurora setup, doesn't build yet
This commit is contained in:
parent
ba0d7ef58c
commit
2509e01125
18 changed files with 430 additions and 9 deletions
30
CMakeLists.txt
Normal file
30
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
project(marioparty4 LANGUAGES C CXX)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL Linux)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unknown-pragmas -Wno-unused-variable -Wno-unused-parameter")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32 -fsanitize=address -fsanitize-address-use-after-scope")
|
||||
set(CMAKE_PREFIX_PATH /usr)
|
||||
set(CMAKE_LIBRARY_ARCHITECTURE i386-linux-gnu)
|
||||
set(CMAKE_LIBRARY_PATH "/usr/lib32" CACHE PATH "")
|
||||
set(CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX 32)
|
||||
endif ()
|
||||
|
||||
add_subdirectory(extern/aurora EXCLUDE_FROM_ALL)
|
||||
|
||||
add_executable(marioparty4
|
||||
src/game/main.c
|
||||
src/game/init.c
|
||||
# libraries/dolphin_pc/GX.c
|
||||
# libraries/dolphin_pc/vi.c
|
||||
# libraries/dolphin_pc/pad_evdev.c
|
||||
# libraries/dolphin_pc/pad_dinput.c
|
||||
# src/port/byteswap.cpp
|
||||
src/port/imgui.cpp
|
||||
src/port/stubs.c
|
||||
)
|
||||
target_compile_definitions(marioparty4 PRIVATE TARGET_PC VERSION=0)
|
||||
target_include_directories(marioparty4 PRIVATE include)
|
||||
target_link_libraries(marioparty4 PRIVATE aurora::aurora aurora::main)
|
||||
18
README.md
18
README.md
|
|
@ -59,7 +59,7 @@ Linux
|
|||
- For non-x86(_64) platforms: Install wine from your package manager.
|
||||
- For x86(_64), [wibo](https://github.com/decompals/wibo), a minimal 32-bit Windows binary wrapper, will be automatically downloaded and used.
|
||||
|
||||
Building
|
||||
Building the game for the GameCube
|
||||
========
|
||||
|
||||
- Clone the repository:
|
||||
|
|
@ -89,11 +89,13 @@ Building
|
|||
ninja
|
||||
```
|
||||
|
||||
Diffing
|
||||
=======
|
||||
Building the game for PC
|
||||
=====
|
||||
After you got the GameCube build up and running for `GMPE01_00`:
|
||||
- Generate project files using CMake:
|
||||
```
|
||||
cmake -B build/port -G "Visual Studio 17 2022" -A Win32
|
||||
```
|
||||
Linux and MacOS, and x64 support is coming later.
|
||||
|
||||
Once the initial build succeeds, an `objdiff.json` should exist in the project root.
|
||||
|
||||
Download the latest release from [encounter/objdiff](https://github.com/encounter/objdiff). Under project settings, set `Project directory`. The configuration should be loaded automatically.
|
||||
|
||||
Select an object from the left sidebar to begin diffing. Changes to the project will rebuild automatically: changes to source files, headers, `configure.py`, `splits.txt` or `symbols.txt`.
|
||||
- Open the solution in Visual Studio and build.
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@ config.asflags = [
|
|||
"-mgekko",
|
||||
"--strip-local-absolute",
|
||||
"-I include",
|
||||
"-I libc",
|
||||
f"-I build/{config.version}/include",
|
||||
f"--defsym version={version_num}",
|
||||
]
|
||||
|
|
@ -192,6 +193,7 @@ cflags_base = [
|
|||
"-fp_contract on",
|
||||
"-str reuse",
|
||||
"-i include",
|
||||
"-i libc",
|
||||
"-i extern/musyx/include",
|
||||
f"-i build/{config.version}/include",
|
||||
"-multibyte",
|
||||
|
|
@ -270,6 +272,7 @@ cflags_musyx = [
|
|||
"-nodefaults",
|
||||
"-nosyspath",
|
||||
"-i include",
|
||||
"-i libc",
|
||||
"-i extern/musyx/include",
|
||||
"-inline auto",
|
||||
"-O4,p",
|
||||
|
|
|
|||
18
include/port/imgui.h
Normal file
18
include/port/imgui.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef _SRC_IMGUI_H_
|
||||
#define _SRC_IMGUI_H_
|
||||
|
||||
#include <aurora/aurora.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void imgui_main(const AuroraInfo* info);
|
||||
void frame_limiter();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -137,6 +137,9 @@ static long DLSize(struct Cell *list)
|
|||
|
||||
void *OSAllocFromHeap(int heap, unsigned long size)
|
||||
{
|
||||
#ifdef TARGET_PC
|
||||
return malloc(size);
|
||||
#endif
|
||||
struct HeapDesc *hd;
|
||||
struct Cell *cell;
|
||||
struct Cell *newCell;
|
||||
|
|
@ -297,6 +300,9 @@ void *OSAllocFixed(void **rstart, void **rend)
|
|||
|
||||
void OSFreeToHeap(int heap, void *ptr)
|
||||
{
|
||||
#ifdef TARGET_PC
|
||||
free(ptr);
|
||||
#else
|
||||
struct HeapDesc *hd;
|
||||
struct Cell *cell;
|
||||
|
||||
|
|
@ -310,6 +316,7 @@ void OSFreeToHeap(int heap, void *ptr)
|
|||
ASSERTMSG1(0x247, DLLookup(hd->allocated, cell), "OSFreeToHeap(): invalid pointer.");
|
||||
hd->allocated = DLExtract(hd->allocated, cell);
|
||||
hd->free = DLInsert(hd->free, cell);
|
||||
#endif
|
||||
}
|
||||
|
||||
int OSSetCurrentHeap(int heap)
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ void HuSysInit(GXRenderModeObj *mode)
|
|||
OSInit();
|
||||
DVDInit();
|
||||
VIInit();
|
||||
#if TARGET_PC
|
||||
VISetWindowTitle("Mario Party 4");
|
||||
#endif
|
||||
PADInit();
|
||||
#if VERSION_NTSC
|
||||
if(OSGetProgressiveMode() == 1 && VIGetDTVStatus() == 1) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,13 @@
|
|||
#include "game/gamework.h"
|
||||
#include "game/sreset.h"
|
||||
|
||||
#ifdef TARGET_PC
|
||||
#include "port/imgui.h"
|
||||
#include <aurora/aurora.h>
|
||||
#include <aurora/event.h>
|
||||
#include <aurora/main.h>
|
||||
#endif
|
||||
|
||||
extern FileListEntry _ovltbl[];
|
||||
u32 GlobalCounter;
|
||||
static u32 vcheck;
|
||||
|
|
@ -40,8 +47,54 @@ static u32 fi_req;
|
|||
s32 HuDvdErrWait;
|
||||
s32 SystemInitF;
|
||||
|
||||
void main(void)
|
||||
#ifdef TARGET_PC
|
||||
#include <stdio.h>
|
||||
void aurora_log_callback(AuroraLogLevel level, const char *message, unsigned int len)
|
||||
{
|
||||
const char *levelStr = "??";
|
||||
FILE *out = stdout;
|
||||
switch (level)
|
||||
{
|
||||
case LOG_DEBUG:
|
||||
levelStr = "DEBUG";
|
||||
break;
|
||||
case LOG_INFO:
|
||||
levelStr = "INFO";
|
||||
break;
|
||||
case LOG_WARNING:
|
||||
levelStr = "WARNING";
|
||||
break;
|
||||
case LOG_ERROR:
|
||||
levelStr = "ERROR";
|
||||
out = stderr;
|
||||
break;
|
||||
case LOG_FATAL:
|
||||
levelStr = "FATAL";
|
||||
out = stderr;
|
||||
break;
|
||||
}
|
||||
fprintf(out, "[%s: %s]\n", levelStr, message);
|
||||
if (level == LOG_FATAL)
|
||||
{
|
||||
fflush(out);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_PC
|
||||
int main(int argc, char* argv[])
|
||||
#else
|
||||
void main(void)
|
||||
#endif
|
||||
{
|
||||
#ifdef AURORA
|
||||
const AuroraInfo auroraInfo = aurora_initialize(argc, argv,
|
||||
&(AuroraConfig){
|
||||
.appName = "Mario Party 4",
|
||||
.logCallback = &aurora_log_callback,
|
||||
});
|
||||
#endif
|
||||
u32 met0;
|
||||
u32 met1;
|
||||
s16 i;
|
||||
|
|
@ -82,12 +135,33 @@ void main(void)
|
|||
VIWaitForRetrace();
|
||||
}
|
||||
while (1) {
|
||||
#ifdef TARGET_PC
|
||||
const AuroraEvent *event = aurora_update();
|
||||
bool exiting = false;
|
||||
while (event != NULL && event->type != AURORA_NONE)
|
||||
{
|
||||
if (event->type == AURORA_EXIT)
|
||||
{
|
||||
exiting = true;
|
||||
break;
|
||||
}
|
||||
++event;
|
||||
}
|
||||
if (exiting)
|
||||
{
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
retrace = VIGetRetraceCount();
|
||||
if (HuSoftResetButtonCheck() != 0 || HuDvdErrWait != 0) {
|
||||
continue;
|
||||
}
|
||||
HuPerfZero();
|
||||
|
||||
HuPerfBegin(2);
|
||||
#ifdef TARGET_PC
|
||||
aurora_begin_frame();
|
||||
#endif
|
||||
HuSysBeforeRender();
|
||||
GXSetGPMetric(GX_PERF0_CLIP_VTX, GX_PERF1_VERTICES);
|
||||
GXClearGPMetric();
|
||||
|
|
@ -95,10 +169,12 @@ void main(void)
|
|||
GXClearVCacheMetric();
|
||||
GXClearPixMetric();
|
||||
GXClearMemMetric();
|
||||
|
||||
HuPerfBegin(0);
|
||||
Hu3DPreProc();
|
||||
HuPadRead();
|
||||
pfClsScr();
|
||||
|
||||
HuPrcCall(1);
|
||||
MGSeqMain();
|
||||
HuPerfBegin(1);
|
||||
|
|
@ -106,8 +182,15 @@ void main(void)
|
|||
HuDvdErrorWatch();
|
||||
WipeExecAlways();
|
||||
HuPerfEnd(0);
|
||||
|
||||
pfDrawFonts();
|
||||
HuPerfEnd(1);
|
||||
|
||||
#ifdef TARGET_PC
|
||||
imgui_main(&auroraInfo);
|
||||
aurora_end_frame();
|
||||
#endif
|
||||
|
||||
msmMusFdoutEnd();
|
||||
HuSysDoneRender(retrace);
|
||||
GXReadGPMetric(&met0, &met1);
|
||||
|
|
@ -116,7 +199,15 @@ void main(void)
|
|||
GXReadMemMetric(&cp_req, &tc_req, &cpu_rd_req, &cpu_wr_req, &dsp_req, &io_req, &vi_req, &pe_req, &rf_req, &fi_req);
|
||||
HuPerfEnd(2);
|
||||
GlobalCounter++;
|
||||
|
||||
#ifdef TARGET_PC
|
||||
frame_limiter();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef TARGET_PC
|
||||
aurora_shutdown();
|
||||
#endif
|
||||
}
|
||||
|
||||
void HuSysVWaitSet(s16 vcount)
|
||||
|
|
|
|||
267
src/port/imgui.cpp
Normal file
267
src/port/imgui.cpp
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
extern "C"
|
||||
{
|
||||
#include "port/imgui.h"
|
||||
}
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <fmt/format.h>
|
||||
#include <imgui.h>
|
||||
#include <numeric>
|
||||
#include <thread>
|
||||
|
||||
static bool m_frameRate = true;
|
||||
static bool m_pipelineInfo = true;
|
||||
static bool m_graphicsBackend = true;
|
||||
static int m_debugOverlayCorner = 0; // top-left
|
||||
|
||||
using namespace std::string_literals;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
namespace aurora::gfx
|
||||
{
|
||||
extern std::atomic_uint32_t queuedPipelines;
|
||||
extern std::atomic_uint32_t createdPipelines;
|
||||
|
||||
extern size_t g_drawCallCount;
|
||||
extern size_t g_mergedDrawCallCount;
|
||||
extern size_t g_lastVertSize;
|
||||
extern size_t g_lastUniformSize;
|
||||
extern size_t g_lastIndexSize;
|
||||
extern size_t g_lastStorageSize;
|
||||
} // namespace aurora::gfx
|
||||
|
||||
static void SetOverlayWindowLocation(int corner)
|
||||
{
|
||||
const ImGuiViewport *viewport = ImGui::GetMainViewport();
|
||||
ImVec2 workPos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any!
|
||||
ImVec2 workSize = viewport->WorkSize;
|
||||
ImVec2 windowPos;
|
||||
ImVec2 windowPosPivot;
|
||||
constexpr float padding = 10.0f;
|
||||
windowPos.x = (corner & 1) != 0 ? (workPos.x + workSize.x - padding) : (workPos.x + padding);
|
||||
windowPos.y = (corner & 2) != 0 ? (workPos.y + workSize.y - padding) : (workPos.y + padding);
|
||||
windowPosPivot.x = (corner & 1) != 0 ? 1.0f : 0.0f;
|
||||
windowPosPivot.y = (corner & 2) != 0 ? 1.0f : 0.0f;
|
||||
ImGui::SetNextWindowPos(windowPos, ImGuiCond_Always, windowPosPivot);
|
||||
}
|
||||
|
||||
static void ImGuiStringViewText(std::string_view text)
|
||||
{
|
||||
// begin()/end() do not work on MSVC
|
||||
ImGui::TextUnformatted(text.data(), text.data() + text.size());
|
||||
}
|
||||
|
||||
static std::string BytesToString(size_t bytes)
|
||||
{
|
||||
constexpr std::array suffixes{"B"sv, "KB"sv, "MB"sv, "GB"sv, "TB"sv, "PB"sv, "EB"sv};
|
||||
uint32_t s = 0;
|
||||
auto count = static_cast<double>(bytes);
|
||||
while (count >= 1024.0 && s < 7)
|
||||
{
|
||||
s++;
|
||||
count /= 1024.0;
|
||||
}
|
||||
if (count - floor(count) == 0.0)
|
||||
{
|
||||
return fmt::format(FMT_STRING("{}{}"), static_cast<size_t>(count), suffixes[s]);
|
||||
}
|
||||
return fmt::format(FMT_STRING("{:.1f}{}"), count, suffixes[s]);
|
||||
}
|
||||
|
||||
void imgui_main(const AuroraInfo *info)
|
||||
{
|
||||
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoDecoration |
|
||||
ImGuiWindowFlags_AlwaysAutoResize |
|
||||
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
|
||||
if (m_debugOverlayCorner != -1)
|
||||
{
|
||||
SetOverlayWindowLocation(m_debugOverlayCorner);
|
||||
windowFlags |= ImGuiWindowFlags_NoMove;
|
||||
}
|
||||
ImGui::SetNextWindowBgAlpha(0.65f);
|
||||
if (ImGui::Begin("Debug Overlay", nullptr, windowFlags))
|
||||
{
|
||||
bool hasPrevious = false;
|
||||
if (m_frameRate)
|
||||
{
|
||||
if (hasPrevious)
|
||||
{
|
||||
ImGui::Separator();
|
||||
}
|
||||
hasPrevious = true;
|
||||
|
||||
ImGuiStringViewText(fmt::format(FMT_STRING("FPS: {:.1f}\n"), io.Framerate));
|
||||
}
|
||||
if (m_graphicsBackend)
|
||||
{
|
||||
if (hasPrevious)
|
||||
{
|
||||
ImGui::Separator();
|
||||
}
|
||||
hasPrevious = true;
|
||||
|
||||
std::string_view backendString = "Unknown"sv;
|
||||
switch (info->backend)
|
||||
{
|
||||
case BACKEND_D3D12:
|
||||
backendString = "D3D12"sv;
|
||||
break;
|
||||
case BACKEND_METAL:
|
||||
backendString = "Metal"sv;
|
||||
break;
|
||||
case BACKEND_VULKAN:
|
||||
backendString = "Vulkan"sv;
|
||||
break;
|
||||
case BACKEND_OPENGL:
|
||||
backendString = "OpenGL"sv;
|
||||
break;
|
||||
case BACKEND_OPENGLES:
|
||||
backendString = "OpenGL ES"sv;
|
||||
break;
|
||||
case BACKEND_WEBGPU:
|
||||
backendString = "WebGPU"sv;
|
||||
break;
|
||||
case BACKEND_NULL:
|
||||
backendString = "Null"sv;
|
||||
break;
|
||||
}
|
||||
ImGuiStringViewText(fmt::format(FMT_STRING("Backend: {}\n"), backendString));
|
||||
}
|
||||
if (m_pipelineInfo)
|
||||
{
|
||||
if (hasPrevious)
|
||||
{
|
||||
ImGui::Separator();
|
||||
}
|
||||
hasPrevious = true;
|
||||
|
||||
ImGuiStringViewText(
|
||||
fmt::format(FMT_STRING("Queued pipelines: {}\n"), aurora::gfx::queuedPipelines));
|
||||
ImGuiStringViewText(
|
||||
fmt::format(FMT_STRING("Done pipelines: {}\n"), aurora::gfx::createdPipelines));
|
||||
ImGuiStringViewText(
|
||||
fmt::format(FMT_STRING("Draw call count: {}\n"), aurora::gfx::g_drawCallCount));
|
||||
ImGuiStringViewText(fmt::format(FMT_STRING("Merged draw calls: {}\n"),
|
||||
aurora::gfx::g_mergedDrawCallCount));
|
||||
ImGuiStringViewText(fmt::format(FMT_STRING("Vertex size: {}\n"),
|
||||
BytesToString(aurora::gfx::g_lastVertSize)));
|
||||
ImGuiStringViewText(fmt::format(FMT_STRING("Uniform size: {}\n"),
|
||||
BytesToString(aurora::gfx::g_lastUniformSize)));
|
||||
ImGuiStringViewText(fmt::format(FMT_STRING("Index size: {}\n"),
|
||||
BytesToString(aurora::gfx::g_lastIndexSize)));
|
||||
ImGuiStringViewText(fmt::format(FMT_STRING("Storage size: {}\n"),
|
||||
BytesToString(aurora::gfx::g_lastStorageSize)));
|
||||
ImGuiStringViewText(fmt::format(
|
||||
FMT_STRING("Total: {}\n"),
|
||||
BytesToString(aurora::gfx::g_lastVertSize + aurora::gfx::g_lastUniformSize +
|
||||
aurora::gfx::g_lastIndexSize + aurora::gfx::g_lastStorageSize)));
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
class Limiter
|
||||
{
|
||||
using delta_clock = std::chrono::high_resolution_clock;
|
||||
using duration_t = std::chrono::nanoseconds;
|
||||
|
||||
public:
|
||||
void Reset()
|
||||
{
|
||||
m_oldTime = delta_clock::now();
|
||||
}
|
||||
|
||||
void Sleep(duration_t targetFrameTime)
|
||||
{
|
||||
if (targetFrameTime.count() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto start = delta_clock::now();
|
||||
duration_t adjustedSleepTime = SleepTime(targetFrameTime);
|
||||
if (adjustedSleepTime.count() > 0)
|
||||
{
|
||||
NanoSleep(adjustedSleepTime);
|
||||
duration_t overslept = TimeSince(start) - adjustedSleepTime;
|
||||
if (overslept < duration_t{targetFrameTime})
|
||||
{
|
||||
m_overheadTimes[m_overheadTimeIdx] = overslept;
|
||||
m_overheadTimeIdx = (m_overheadTimeIdx + 1) % m_overheadTimes.size();
|
||||
}
|
||||
}
|
||||
Reset();
|
||||
}
|
||||
|
||||
duration_t SleepTime(duration_t targetFrameTime)
|
||||
{
|
||||
const auto sleepTime = duration_t{targetFrameTime} - TimeSince(m_oldTime);
|
||||
m_overhead = std::accumulate(m_overheadTimes.begin(), m_overheadTimes.end(), duration_t{}) /
|
||||
m_overheadTimes.size();
|
||||
if (sleepTime > m_overhead)
|
||||
{
|
||||
return sleepTime - m_overhead;
|
||||
}
|
||||
return duration_t{0};
|
||||
}
|
||||
|
||||
private:
|
||||
delta_clock::time_point m_oldTime;
|
||||
std::array<duration_t, 4> m_overheadTimes{};
|
||||
size_t m_overheadTimeIdx = 0;
|
||||
duration_t m_overhead = duration_t{0};
|
||||
|
||||
duration_t TimeSince(delta_clock::time_point start)
|
||||
{
|
||||
return std::chrono::duration_cast<duration_t>(delta_clock::now() - start);
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
bool m_initialized;
|
||||
double m_countPerNs;
|
||||
|
||||
void NanoSleep(const duration_t duration)
|
||||
{
|
||||
if (!m_initialized)
|
||||
{
|
||||
LARGE_INTEGER freq;
|
||||
QueryPerformanceFrequency(&freq);
|
||||
m_countPerNs = static_cast<double>(freq.QuadPart) / 1000000000.0;
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
DWORD ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
|
||||
auto tickCount =
|
||||
static_cast<LONGLONG>(static_cast<double>(duration.count()) * m_countPerNs);
|
||||
LARGE_INTEGER count;
|
||||
QueryPerformanceCounter(&count);
|
||||
if (ms > 10)
|
||||
{
|
||||
// Adjust for Sleep overhead
|
||||
::Sleep(ms - 10);
|
||||
}
|
||||
auto end = count.QuadPart + tickCount;
|
||||
do
|
||||
{
|
||||
QueryPerformanceCounter(&count);
|
||||
} while (count.QuadPart < end);
|
||||
}
|
||||
#else
|
||||
void NanoSleep(const duration_t duration)
|
||||
{
|
||||
std::this_thread::sleep_for(duration);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static Limiter g_frameLimiter;
|
||||
void frame_limiter()
|
||||
{
|
||||
g_frameLimiter.Sleep(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds{1}) / 60);
|
||||
}
|
||||
0
src/port/stubs.c
Normal file
0
src/port/stubs.c
Normal file
Loading…
Add table
Add a link
Reference in a new issue