From 7e788f47afc6fa7ea6b97767eb350449848eea78 Mon Sep 17 00:00:00 2001 From: James Benton Date: Wed, 23 May 2018 11:10:10 +0100 Subject: [PATCH] Add libdefaultheap, libgfd, libwhb. --- CMakeLists.txt | 9 + libraries/CMakeLists.txt | 6 + libraries/libdefaultheap/CMakeLists.txt | 16 + .../libdefaultheap/include/defaultheap.h | 20 + libraries/libdefaultheap/src/defaultheap.c | 75 ++ libraries/libgfd/CMakeLists.txt | 16 + libraries/libgfd/include/gfd.h | 207 ++++ libraries/libgfd/src/gfd.c | 880 ++++++++++++++++++ libraries/libwhb/CMakeLists.txt | 19 + libraries/libwhb/include/whb/align.h | 20 + libraries/libwhb/include/whb/commandserver.h | 29 + libraries/libwhb/include/whb/crash.h | 21 + libraries/libwhb/include/whb/file.h | 47 + libraries/libwhb/include/whb/gfx.h | 95 ++ libraries/libwhb/include/whb/libmanager.h | 27 + libraries/libwhb/include/whb/log.h | 38 + libraries/libwhb/include/whb/log_cafe.h | 24 + libraries/libwhb/include/whb/log_udp.h | 24 + libraries/libwhb/include/whb/proc.h | 30 + libraries/libwhb/include/whb/sdcard.h | 27 + libraries/libwhb/src/commandserver.c | 138 +++ libraries/libwhb/src/crash.c | 258 +++++ libraries/libwhb/src/file.c | 157 ++++ libraries/libwhb/src/gfx.c | 520 +++++++++++ libraries/libwhb/src/gfx_heap.c | 176 ++++ libraries/libwhb/src/gfx_heap.h | 35 + libraries/libwhb/src/gfx_shader.c | 299 ++++++ libraries/libwhb/src/gfx_texture.c | 55 ++ libraries/libwhb/src/libmanager.c | 33 + libraries/libwhb/src/log.c | 121 +++ libraries/libwhb/src/log_cafe.c | 29 + libraries/libwhb/src/log_udp.c | 58 ++ libraries/libwhb/src/proc.c | 111 +++ libraries/libwhb/src/sdcard.c | 80 ++ 34 files changed, 3700 insertions(+) create mode 100644 libraries/CMakeLists.txt create mode 100644 libraries/libdefaultheap/CMakeLists.txt create mode 100644 libraries/libdefaultheap/include/defaultheap.h create mode 100644 libraries/libdefaultheap/src/defaultheap.c create mode 100644 libraries/libgfd/CMakeLists.txt create mode 100644 libraries/libgfd/include/gfd.h create mode 100644 libraries/libgfd/src/gfd.c create mode 100644 libraries/libwhb/CMakeLists.txt create mode 100644 libraries/libwhb/include/whb/align.h create mode 100644 libraries/libwhb/include/whb/commandserver.h create mode 100644 libraries/libwhb/include/whb/crash.h create mode 100644 libraries/libwhb/include/whb/file.h create mode 100644 libraries/libwhb/include/whb/gfx.h create mode 100644 libraries/libwhb/include/whb/libmanager.h create mode 100644 libraries/libwhb/include/whb/log.h create mode 100644 libraries/libwhb/include/whb/log_cafe.h create mode 100644 libraries/libwhb/include/whb/log_udp.h create mode 100644 libraries/libwhb/include/whb/proc.h create mode 100644 libraries/libwhb/include/whb/sdcard.h create mode 100644 libraries/libwhb/src/commandserver.c create mode 100644 libraries/libwhb/src/crash.c create mode 100644 libraries/libwhb/src/file.c create mode 100644 libraries/libwhb/src/gfx.c create mode 100644 libraries/libwhb/src/gfx_heap.c create mode 100644 libraries/libwhb/src/gfx_heap.h create mode 100644 libraries/libwhb/src/gfx_shader.c create mode 100644 libraries/libwhb/src/gfx_texture.c create mode 100644 libraries/libwhb/src/libmanager.c create mode 100644 libraries/libwhb/src/log.c create mode 100644 libraries/libwhb/src/log_cafe.c create mode 100644 libraries/libwhb/src/log_udp.c create mode 100644 libraries/libwhb/src/proc.c create mode 100644 libraries/libwhb/src/sdcard.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 6dd7eb7..271a162 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,15 @@ externalproject_add(cafe DEPENDS tools BUILD_ALWAYS 1) +externalproject_add(libraries + SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries" + INSTALL_DIR "${WUT_STAGING}" + CMAKE_CACHE_ARGS + -DWUT_ROOT:filepath=${WUT_ROOT} + -DCMAKE_TOOLCHAIN_FILE:filepath=${WUT_TOOLCHAIN} + -DCMAKE_INSTALL_PREFIX:string= + BUILD_ALWAYS 1) + install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/" DESTINATION "${CMAKE_INSTALL_PREFIX}/include" FILES_MATCHING PATTERN "*.h*") diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt new file mode 100644 index 0000000..18ef69b --- /dev/null +++ b/libraries/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.2) +project(libraries C) + +add_subdirectory(libdefaultheap) +add_subdirectory(libgfd) +add_subdirectory(libwhb) diff --git a/libraries/libdefaultheap/CMakeLists.txt b/libraries/libdefaultheap/CMakeLists.txt new file mode 100644 index 0000000..3fb3a2c --- /dev/null +++ b/libraries/libdefaultheap/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.2) +project(libdefaultheap) + +file(GLOB_RECURSE SOURCE_FILES *.c) +file(GLOB_RECURSE HEADER_FILES *.h) + +add_library(defaultheap STATIC ${SOURCE_FILES} ${HEADER_FILES}) + +target_include_directories(defaultheap PRIVATE "../../include") +target_include_directories(defaultheap PUBLIC "include") + +install(TARGETS defaultheap + ARCHIVE DESTINATION "${CMAKE_INSTALL_PREFIX}/lib") +install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ + DESTINATION "${CMAKE_INSTALL_PREFIX}/include" + FILES_MATCHING PATTERN "*.h*") diff --git a/libraries/libdefaultheap/include/defaultheap.h b/libraries/libdefaultheap/include/defaultheap.h new file mode 100644 index 0000000..f4f0be1 --- /dev/null +++ b/libraries/libdefaultheap/include/defaultheap.h @@ -0,0 +1,20 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void * +MEMAllocFromDefaultHeap(uint32_t size); + +void * +MEMAllocFromDefaultHeapEx(uint32_t size, + int32_t alignment); + +void +MEMFreeToDefaultHeap(void *block); + +#ifdef __cplusplus +} +#endif diff --git a/libraries/libdefaultheap/src/defaultheap.c b/libraries/libdefaultheap/src/defaultheap.c new file mode 100644 index 0000000..ef330d2 --- /dev/null +++ b/libraries/libdefaultheap/src/defaultheap.c @@ -0,0 +1,75 @@ +#include "defaultheap.h" +#include + +typedef void *(*MEMAllocFromDefaultHeapFn)(uint32_t size); +typedef void *(*MEMAllocFromDefaultHeapExFn)(uint32_t size, int32_t alignment); +typedef void (*MEMFreeToDefaultHeapFn)(void *block); + +static OSDynLoadModule sCoreinitHandle = 0; +static MEMAllocFromDefaultHeapFn *MEMAllocFromDefaultHeapPtr = NULL; +static MEMAllocFromDefaultHeapExFn *MEMAllocFromDefaultHeapExPtr = NULL; +static MEMFreeToDefaultHeapFn *MEMFreeToDefaultHeapPtr = NULL; + +void * +MEMAllocFromDefaultHeap(uint32_t size) +{ + if (!sCoreinitHandle) { + if (OSDynLoad_Acquire("coreinit.rpl", &sCoreinitHandle)) { + return NULL; + } + } + + if (!MEMAllocFromDefaultHeapPtr) { + if (OSDynLoad_FindExport(sCoreinitHandle, + TRUE, + "MEMAllocFromDefaultHeap", + (void **)&MEMAllocFromDefaultHeapPtr)) { + return NULL; + } + } + + return (**MEMAllocFromDefaultHeapPtr)(size); +} + +void * +MEMAllocFromDefaultHeapEx(uint32_t size, + int32_t alignment) +{ + if (!sCoreinitHandle) { + if (OSDynLoad_Acquire("coreinit.rpl", &sCoreinitHandle)) { + return NULL; + } + } + + if (!MEMAllocFromDefaultHeapExPtr) { + if (OSDynLoad_FindExport(sCoreinitHandle, + TRUE, + "MEMAllocFromDefaultHeapEx", + (void **)&MEMAllocFromDefaultHeapExPtr)) { + return NULL; + } + } + + return (**MEMAllocFromDefaultHeapExPtr)(size, alignment); +} + +void +MEMFreeToDefaultHeap(void *block) +{ + if (!sCoreinitHandle) { + if (OSDynLoad_Acquire("coreinit.rpl", &sCoreinitHandle)) { + return; + } + } + + if (!MEMFreeToDefaultHeapPtr) { + if (OSDynLoad_FindExport(sCoreinitHandle, + TRUE, + "MEMFreeToDefaultHeap", + (void **)&MEMFreeToDefaultHeapPtr)) { + return; + } + } + + (**MEMFreeToDefaultHeapPtr)(block); +} diff --git a/libraries/libgfd/CMakeLists.txt b/libraries/libgfd/CMakeLists.txt new file mode 100644 index 0000000..c255490 --- /dev/null +++ b/libraries/libgfd/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.2) +project(libgfd) + +file(GLOB_RECURSE SOURCE_FILES *.c) +file(GLOB_RECURSE HEADER_FILES *.h) + +add_library(gfd STATIC ${SOURCE_FILES} ${HEADER_FILES}) + +target_include_directories(gfd PRIVATE "../../include") +target_include_directories(gfd PUBLIC "include") + +install(TARGETS gfd + ARCHIVE DESTINATION "${CMAKE_INSTALL_PREFIX}/lib") +install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ + DESTINATION "${CMAKE_INSTALL_PREFIX}/include" + FILES_MATCHING PATTERN "*.h*") diff --git a/libraries/libgfd/include/gfd.h b/libraries/libgfd/include/gfd.h new file mode 100644 index 0000000..b0758b2 --- /dev/null +++ b/libraries/libgfd/include/gfd.h @@ -0,0 +1,207 @@ +#pragma once +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GFDHeader GFDHeader; +typedef struct GFDBlockHeader GFDBlockHeader; +typedef struct GFDRelocationHeader GFDRelocationHeader; + +#define GFD_HEADER_MAGIC (0x47667832) +#define GFD_BLOCK_HEADER_MAGIC (0x424C4B7B) +#define GFD_RELOCATION_HEADER_MAGIC (0x7D424C4B) + +#define GFD_FILE_VERSION_MAJOR (7) +#define GFD_FILE_VERSION_MINOR (1) +#define GFD_BLOCK_VERSION_MAJOR (1) + +#define GFD_PATCH_MASK (0xFFF00000) +#define GFD_PATCH_DATA (0xD0600000) +#define GFD_PATCH_TEXT (0xCA700000) + +typedef enum GFDBlockType +{ + GFD_BLOCK_END_OF_FILE = 1, + GFD_BLOCK_PADDING = 2, + GFD_BLOCK_VERTEX_SHADER_HEADER = 3, + GFD_BLOCK_VERTEX_SHADER_PROGRAM = 5, + GFD_BLOCK_PIXEL_SHADER_HEADER = 6, + GFD_BLOCK_PIXEL_SHADER_PROGRAM = 7, + GFD_BLOCK_GEOMETRY_SHADER_HEADER = 8, + GFD_BLOCK_GEOMETRY_SHADER_PROGRAM = 9, + GFD_BLOCK_GEOMETRY_SHADER_COPY_PROGRAM = 10, + GFD_BLOCK_TEXTURE_HEADER = 11, + GFD_BLOCK_TEXTURE_IMAGE = 12, + GFD_BLOCK_TEXTURE_MIPMAP = 13, + GFD_BLOCK_COMPUTE_SHADER_HEADER = 14, + GFD_BLOCK_COMPUTE_SHADER_PROGRAM = 15, +} GFDBlockType; + +struct GFDHeader +{ + uint32_t magic; + uint32_t headerSize; + uint32_t majorVersion; + uint32_t minorVersion; + uint32_t gpuVersion; + uint32_t align; + uint32_t unk1; + uint32_t unk2; +}; +CHECK_OFFSET(GFDHeader, 0x00, magic); +CHECK_OFFSET(GFDHeader, 0x04, headerSize); +CHECK_OFFSET(GFDHeader, 0x08, majorVersion); +CHECK_OFFSET(GFDHeader, 0x0C, minorVersion); +CHECK_OFFSET(GFDHeader, 0x10, gpuVersion); +CHECK_OFFSET(GFDHeader, 0x14, align); +CHECK_OFFSET(GFDHeader, 0x18, unk1); +CHECK_OFFSET(GFDHeader, 0x1C, unk2); +CHECK_SIZE(GFDHeader, 0x20); + +struct GFDBlockHeader +{ + uint32_t magic; + uint32_t headerSize; + uint32_t majorVersion; + uint32_t minorVersion; + GFDBlockType type; + uint32_t dataSize; + uint32_t id; + uint32_t index; +}; +CHECK_OFFSET(GFDBlockHeader, 0x00, magic); +CHECK_OFFSET(GFDBlockHeader, 0x04, headerSize); +CHECK_OFFSET(GFDBlockHeader, 0x08, majorVersion); +CHECK_OFFSET(GFDBlockHeader, 0x0C, minorVersion); +CHECK_OFFSET(GFDBlockHeader, 0x10, type); +CHECK_OFFSET(GFDBlockHeader, 0x14, dataSize); +CHECK_OFFSET(GFDBlockHeader, 0x18, id); +CHECK_OFFSET(GFDBlockHeader, 0x1C, index); +CHECK_SIZE(GFDHeader, 0x20); + +struct GFDRelocationHeader +{ + uint32_t magic; + uint32_t headerSize; + uint32_t unk1; + uint32_t dataSize; + uint32_t dataOffset; + uint32_t textSize; + uint32_t textOffset; + uint32_t patchBase; + uint32_t patchCount; + uint32_t patchOffset; +}; +CHECK_OFFSET(GFDRelocationHeader, 0x00, magic); +CHECK_OFFSET(GFDRelocationHeader, 0x04, headerSize); +CHECK_OFFSET(GFDRelocationHeader, 0x08, unk1); +CHECK_OFFSET(GFDRelocationHeader, 0x0C, dataSize); +CHECK_OFFSET(GFDRelocationHeader, 0x10, dataOffset); +CHECK_OFFSET(GFDRelocationHeader, 0x14, textSize); +CHECK_OFFSET(GFDRelocationHeader, 0x18, textOffset); +CHECK_OFFSET(GFDRelocationHeader, 0x1C, patchBase); +CHECK_OFFSET(GFDRelocationHeader, 0x20, patchCount); +CHECK_OFFSET(GFDRelocationHeader, 0x24, patchOffset); +CHECK_SIZE(GFDRelocationHeader, 0x28); + +char * +GFDGetLastErrorString(); + +uint32_t +GFDGetGeometryShaderCount(const void *file); + +uint32_t +GFDGetGeometryShaderHeaderSize(uint32_t index, + const void *file); + +uint32_t +GFDGetGeometryShaderProgramSize(uint32_t index, + const void *file); + +uint32_t +GFDGetGeometryShaderCopyProgramSize(uint32_t index, + const void *file); + +BOOL +GFDGetGeometryShader(GX2GeometryShader *shader, + void *program, + void *copyProgram, + uint32_t index, + const void *file); + +uint32_t +GFDGetPixelShaderCount(const void *file); + +uint32_t +GFDGetPixelShaderHeaderSize(uint32_t index, + const void *file); + +uint32_t +GFDGetPixelShaderProgramSize(uint32_t index, + const void *file); + +BOOL +GFDGetPixelShader(GX2PixelShader *shader, + void *program, + uint32_t index, + const void *file); + +uint32_t +GFDGetVertexShaderCount(const void *file); + +uint32_t +GFDGetVertexShaderHeaderSize(uint32_t index, + const void *file); + +uint32_t +GFDGetVertexShaderProgramSize(uint32_t index, + const void *file); + +BOOL +GFDGetVertexShader(GX2VertexShader *shader, + void *program, + uint32_t index, + const void *file); + +uint32_t +GFDGetTextureCount(const void *file); + +uint32_t +GFDGetTextureHeaderSize(uint32_t index, + const void *file); + +uint32_t +GFDGetTextureImageSize(uint32_t index, + const void *file); + +uint32_t +GFDGetTextureMipImageSize(uint32_t index, + const void *file); + +uint32_t +GFDGetTextureAlignmentSize(uint32_t index, + const void *file); + +BOOL +GFDGetTexture(GX2Texture *texture, + void *image, + void *mipmap, + uint32_t index, + const void *file); + +BOOL +GFDGetGX2RTexture(GX2Texture *texture, + uint32_t index, + const void *file); + +const GX2Texture * +GFDGetTexturePointer(uint32_t index, + const void *file); + +#ifdef __cplusplus +} +#endif diff --git a/libraries/libgfd/src/gfd.c b/libraries/libgfd/src/gfd.c new file mode 100644 index 0000000..a934f83 --- /dev/null +++ b/libraries/libgfd/src/gfd.c @@ -0,0 +1,880 @@ +#include "gfd.h" + +#include +#include +#include +#include +#include + +// #define CHECK_GPU_VERSION + +static uint32_t _GFDCleanTag(uint32_t tag); +static BOOL _GFDCheckTagDAT(uint32_t tag); +static BOOL _GFDCheckTagSTR(uint32_t tag); +static BOOL _GFDRelocateBlock(const GFDBlockHeader *blockHeader, void *dst); +static BOOL _GFDRelocateBlockEx(const GFDRelocationHeader *relocationHeader, const uint32_t *patchTable, uint8_t *dst); +static uint32_t _GFDGetBlockDataSize(GFDBlockType type, uint32_t index, const void *file); +static uint32_t _GFDGetBlockCount(GFDBlockType type, const void *file); +static BOOL _GFDCheckBlockHeaderMagicVersions(const GFDBlockHeader *header); +static BOOL _GFDCheckHeaderVersions(const void *file); +static BOOL _GFDGetHeaderVersions(uint32_t *majorVersion, uint32_t *minorVersion, uint32_t *gpuVersion, const void *file); +static BOOL _GFDGetBlockPointer(GFDBlockType type, uint32_t index, void *file, GFDBlockHeader **blockHeaderOut, void **blockDataOut); +static BOOL _GFDGetBlockPointerConst(GFDBlockType type, uint32_t index, const void *file, const GFDBlockHeader **blockHeaderOut, const void **blockDataOut); + +static char +sLastError[1024] = { 0 }; + +static void +setLastError(const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + vsnprintf(sLastError, 1024, fmt, va); + va_end(va); +} + +char * +GFDGetLastErrorString() +{ + return sLastError; +} + +static BOOL +_GFDGetHeaderVersions(uint32_t *majorVersion, + uint32_t *minorVersion, + uint32_t *gpuVersion, + const void *file) +{ + GFDHeader *header = (GFDHeader *)file; + *majorVersion = 0; + *minorVersion = 0; + *gpuVersion = 0; + + if (header->magic != GFD_HEADER_MAGIC) { + setLastError("%s: header->magic %08X != %08X GFD_HEADER_MAGIC", __FUNCTION__, header->magic, GFD_HEADER_MAGIC); + return FALSE; + } + + *majorVersion = header->majorVersion; + *minorVersion = header->minorVersion; + *gpuVersion = header->gpuVersion; + return TRUE; +} + +static BOOL +_GFDCheckHeaderVersions(const void *file) +{ + uint32_t majorVersion, minorVersion, gpuVersion; + + if (!_GFDGetHeaderVersions(&majorVersion, &minorVersion, &gpuVersion, file)) { + return FALSE; + } + + if (majorVersion != GFD_FILE_VERSION_MAJOR) { + setLastError("%s: majorVersion %d != %d GFD_FILE_VERSION_MAJOR", __FUNCTION__, majorVersion, GFD_FILE_VERSION_MAJOR); + return FALSE; + } + + if (minorVersion != GFD_FILE_VERSION_MINOR) { + setLastError("%s: minorVersion %d != %d GFD_FILE_VERSION_MINOR", __FUNCTION__, minorVersion, GFD_FILE_VERSION_MINOR); + return FALSE; + } + +#ifdef CHECK_GPU_VERSION + if (gpuVersion != GX2TempGetGPUVersion()) { + setLastError("%s: gpuVersion %d != %d GX2TempGetGPUVersion()", __FUNCTION__, gpuVersion, GX2TempGetGPUVersion()); + return FALSE; + } +#endif + + return TRUE; +} + +static BOOL +_GFDCheckBlockHeaderMagicVersions(const GFDBlockHeader *header) +{ + if (header->magic != GFD_BLOCK_HEADER_MAGIC) { + setLastError("%s: header->magic %08X != GFD_BLOCK_HEADER_MAGIC", __FUNCTION__, header->magic); + return FALSE; + } + + if (header->majorVersion != GFD_BLOCK_VERSION_MAJOR) { + setLastError("%s: header->majorVersion %d != GFD_BLOCK_VERSION_MAJOR", __FUNCTION__, header->majorVersion); + return FALSE; + } + + return TRUE; +} + +static uint32_t +_GFDGetBlockCount(GFDBlockType type, + const void *file) +{ + const uint8_t *ptr = (const uint8_t *)file; + const GFDHeader *fileHeader = (const GFDHeader *)file; + const GFDBlockHeader *blockHeader; + uint32_t count = 0; + + if (!file) { + return 0; + } + + if (!_GFDCheckHeaderVersions(file)) { + return 0; + } + + ptr += fileHeader->headerSize; + blockHeader = (const GFDBlockHeader *)ptr; + + while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) { + if (blockHeader->type == type) { + count++; + } else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) { + break; + } + + ptr += blockHeader->headerSize + blockHeader->dataSize; + blockHeader = (const GFDBlockHeader *)ptr; + } + + return count; +} + +static uint32_t +_GFDGetBlockDataSize(GFDBlockType type, + uint32_t index, + const void *file) +{ + const uint8_t *ptr = (const uint8_t *)file; + const GFDHeader *fileHeader = (const GFDHeader *)file; + const GFDBlockHeader *blockHeader; + uint32_t count = 0; + + if (!file) { + return 0; + } + + if (!_GFDCheckHeaderVersions(file)) { + return 0; + } + + ptr += fileHeader->headerSize; + blockHeader = (const GFDBlockHeader *)ptr; + + while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) { + if (blockHeader->type == type) { + if (count == index) { + return blockHeader->dataSize; + } + + count++; + } else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) { + break; + } + + ptr += blockHeader->headerSize + blockHeader->dataSize; + blockHeader = (const GFDBlockHeader *)ptr; + } + + return 0; +} + +static BOOL +_GFDGetBlockPointerConst(GFDBlockType type, + uint32_t index, + const void *file, + const GFDBlockHeader **blockHeaderOut, + const void **blockDataOut) +{ + const uint8_t *ptr = (const uint8_t *)file; + const GFDHeader *fileHeader = (const GFDHeader *)file; + const GFDBlockHeader *blockHeader; + uint32_t count = 0; + + if (!file) { + return FALSE; + } + + if (!_GFDCheckHeaderVersions(file)) { + return FALSE; + } + + ptr += fileHeader->headerSize; + blockHeader = (const GFDBlockHeader *)ptr; + + while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) { + if (blockHeader->type == type) { + if (count == index) { + *blockHeaderOut = blockHeader; + *blockDataOut = ptr + blockHeader->headerSize; + return TRUE; + } + + count++; + } else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) { + break; + } + + ptr += blockHeader->headerSize + blockHeader->dataSize; + blockHeader = (const GFDBlockHeader *)ptr; + } + + return FALSE; +} + +static BOOL +_GFDGetBlockPointer(GFDBlockType type, + uint32_t index, + void *file, + GFDBlockHeader **blockHeaderOut, + void **blockDataOut) +{ + uint8_t *ptr = (uint8_t *)file; + GFDHeader *fileHeader = (GFDHeader *)file; + GFDBlockHeader *blockHeader; + uint32_t count = 0; + + if (!file) { + return FALSE; + } + + if (!_GFDCheckHeaderVersions(file)) { + return FALSE; + } + + ptr += fileHeader->headerSize; + blockHeader = (GFDBlockHeader *)ptr; + + while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) { + if (blockHeader->type == type) { + if (count == index) { + *blockHeaderOut = blockHeader; + *blockDataOut = ptr + blockHeader->headerSize; + + if (type == GFD_BLOCK_VERTEX_SHADER_HEADER + || type == GFD_BLOCK_PIXEL_SHADER_HEADER + || type == GFD_BLOCK_GEOMETRY_SHADER_HEADER + || type == GFD_BLOCK_COMPUTE_SHADER_HEADER) { + _GFDRelocateBlock(blockHeader, blockHeader); + } + + return TRUE; + } + + count++; + } else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) { + break; + } + + ptr += blockHeader->headerSize + blockHeader->dataSize; + blockHeader = (GFDBlockHeader *)ptr; + } + + return FALSE; +} + +static uint32_t +_GFDCleanTag(uint32_t tag) +{ + return tag & ~GFD_PATCH_MASK; +} + +static BOOL +_GFDCheckTagDAT(uint32_t tag) +{ + return (tag & GFD_PATCH_MASK) == GFD_PATCH_DATA; +} + +static BOOL +_GFDCheckTagSTR(uint32_t tag) +{ + return (tag & GFD_PATCH_MASK) == GFD_PATCH_TEXT; +} + +// This method differs from the official because they made poor design decisions. +static BOOL +_GFDRelocateBlockEx(const GFDRelocationHeader *relocationHeader, + const uint32_t *patchTable, + uint8_t *dst) +{ + uint32_t patchOffset = _GFDCleanTag(relocationHeader->patchOffset); + uint32_t i; + + for (i = 0; i < relocationHeader->patchCount; ++i) { + uint32_t *target; + uint32_t offset = patchTable[i]; + + if (offset == 0) { + continue; + } + + if (!_GFDCheckTagDAT(offset) && !_GFDCheckTagSTR(offset)) { + setLastError("%s: !_GFDCheckTagDAT(offset = %08X) && !_GFDCheckTagSTR(offset = %08X)", __FUNCTION__, offset, offset); + return FALSE; + } + + target = (uint32_t *)(dst + _GFDCleanTag(offset)); + + if (!_GFDCheckTagDAT(*target) && !_GFDCheckTagSTR(*target)) { + setLastError("%s: !_GFDCheckTagDAT(*target = %08X) && !_GFDCheckTagSTR(*target = %08X)", __FUNCTION__, *target, *target); + return FALSE; + } + + *target = (uintptr_t)(dst + _GFDCleanTag(*target)); + } + + return TRUE; +} + +static BOOL +_GFDRelocateBlock(const GFDBlockHeader *blockHeader, + void *dst) +{ + const uint8_t *blockData = ((const uint8_t *)blockHeader) + blockHeader->headerSize; + const GFDRelocationHeader *relocationHeader; + const uint32_t *patchTable; + + if (!blockHeader || !dst) { + return FALSE; + } + + relocationHeader = (const GFDRelocationHeader *)(blockData + + blockHeader->dataSize + - sizeof(GFDRelocationHeader)); + + if (relocationHeader->magic != GFD_RELOCATION_HEADER_MAGIC) { + setLastError("%s: relocationHeader->magic %08X != GFD_RELOCATION_HEADER_MAGIC", __FUNCTION__, relocationHeader->magic); + return FALSE; + } + + if (!_GFDCheckTagDAT(relocationHeader->patchOffset)) { + setLastError("%s: !_GFDCheckTagDAT(relocationHeader->patchOffset = %08X)", __FUNCTION__, relocationHeader->patchOffset); + return FALSE; + } + + patchTable = (const uint32_t *)(blockData + _GFDCleanTag(relocationHeader->patchOffset)); + return _GFDRelocateBlockEx(relocationHeader, patchTable, (uint8_t *)dst); +} + +static BOOL +_GFDCheckShaderAlign(void *program) +{ + return (((uintptr_t)program) & (GX2_SHADER_PROGRAM_ALIGNMENT - 1)) == 0; +} + +static BOOL +_GFDGetGenericBlock(GFDBlockType blockTypeHeader, + void *header, + GFDBlockType blockTypeProgram1, + void **outProgramPtr1, + void *program1, + GFDBlockType blockTypeProgram2, + void **outProgramPtr2, + void *program2, + uint32_t index, + const void *file) +{ + const uint8_t *ptr = (const uint8_t *)file; + const GFDHeader *fileHeader = (const GFDHeader *)file; + const GFDBlockHeader *blockHeader; + uint32_t headerCount = 0; + uint32_t program1Count = 0; + uint32_t program2Count = 0; + BOOL result = FALSE; + + if (!header || !file) { + return FALSE; + } + + ptr += fileHeader->headerSize; + blockHeader = (const GFDBlockHeader *)ptr; + + while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) { + ptr += blockHeader->headerSize; + + if (blockHeader->type == blockTypeHeader) { + if (headerCount == index) { + memcpy(header, ptr, blockHeader->dataSize); + + // Process relocations for all headers except a texture header. + if (blockTypeHeader != GFD_BLOCK_TEXTURE_HEADER) { + if (!_GFDRelocateBlock(blockHeader, header)) { + return FALSE; + } + } + } + + headerCount++; + } else if (blockHeader->type == blockTypeProgram1) { + if (program1Count == index) { + *outProgramPtr1 = program1; + memcpy(program1, ptr, blockHeader->dataSize); + } + + program1Count++; + } else if (program2 && blockHeader->type == blockTypeProgram2) { + if (program2Count == index) { + *outProgramPtr2 = program2; + memcpy(program2, ptr, blockHeader->dataSize); + } + + program2Count++; + } else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) { + break; + } + + if (headerCount > index && program1Count > index) { + if (!program2 || program2Count > index) { + result = TRUE; + break; + } + } + + ptr += blockHeader->dataSize; + blockHeader = (const GFDBlockHeader *)ptr; + } + + return result; +} +/* +BOOL +GFDGetVertexShader(GX2VertexShader *shader, + void *program, + uint32_t index, + const void *file) +{ + const uint8_t *ptr = (const uint8_t *)file; + const GFDHeader *fileHeader = (const GFDHeader *)file; + const GFDBlockHeader *blockHeader; + uint32_t headerCount = 0; + uint32_t programCount = 0; + BOOL result = FALSE; + + if (!shader || !program || !file) { + return FALSE; + } + + if ((uintptr_t)program & (GX2_SHADER_PROGRAM_ALIGNMENT - 1)) { + return FALSE; + } + + ptr += fileHeader->headerSize; + blockHeader = (const GFDBlockHeader *)ptr; + + while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) { + ptr += blockHeader->headerSize; + + if (blockHeader->type == GFD_BLOCK_VERTEX_SHADER_HEADER) { + if (headerCount == index) { + if (blockHeader->dataSize < sizeof(GX2VertexShader)) { + return FALSE; + } + + memcpy(shader, ptr, sizeof(GX2VertexShader)); + + if (!_GFDRelocateBlock(blockHeader, shader)) { + return FALSE; + } + } + + headerCount++; + } else if (blockHeader->type == GFD_BLOCK_VERTEX_SHADER_PROGRAM) { + if (programCount == index) { + shader->program = program; + memcpy(program, ptr, blockHeader->dataSize); + } + + programCount++; + } else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) { + break; + } + + if (headerCount > index && programCount > index) { + result = TRUE; + break; + } + + ptr += blockHeader->dataSize; + blockHeader = (const GFDBlockHeader *)ptr; + } + + return result; +} +*/ + +uint32_t +GFDGetComputeShaderCount(const void *file) +{ + return _GFDGetBlockCount(GFD_BLOCK_COMPUTE_SHADER_HEADER, + file); +} + +uint32_t +GFDGetComputeShaderHeaderSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_COMPUTE_SHADER_HEADER, + index, + file); +} + +uint32_t +GFDGetComputeShaderProgramSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_COMPUTE_SHADER_PROGRAM, + index, + file); +} + +/* +BOOL +GFDGetComputeShader(GX2ComputeShader *shader, + void *program, + uint32_t index, + const void *file) +{ + return _GFDGetGenericBlock(GFD_BLOCK_COMPUTE_SHADER_HEADER, + shader, + GFD_BLOCK_COMPUTE_SHADER_PROGRAM, + &shader->program, + program, + 0, + NULL, + NULL, + index, + file); +} +*/ + +uint32_t +GFDGetGeometryShaderCount(const void *file) +{ + return _GFDGetBlockCount(GFD_BLOCK_GEOMETRY_SHADER_HEADER, + file); +} + +uint32_t +GFDGetGeometryShaderHeaderSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_GEOMETRY_SHADER_HEADER, + index, + file); +} + +uint32_t +GFDGetGeometryShaderProgramSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_GEOMETRY_SHADER_PROGRAM, + index, + file); +} + +uint32_t +GFDGetGeometryShaderCopyProgramSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_GEOMETRY_SHADER_COPY_PROGRAM, + index, + file); +} + +BOOL +GFDGetGeometryShader(GX2GeometryShader *shader, + void *program, + void *copyProgram, + uint32_t index, + const void *file) +{ + if (!_GFDCheckShaderAlign(program) || !_GFDCheckShaderAlign(copyProgram)) { + return FALSE; + } + + return _GFDGetGenericBlock(GFD_BLOCK_GEOMETRY_SHADER_HEADER, + shader, + GFD_BLOCK_GEOMETRY_SHADER_PROGRAM, + &shader->program, + program, + GFD_BLOCK_GEOMETRY_SHADER_COPY_PROGRAM, + &shader->vertexProgram, + copyProgram, + index, + file); +} + +uint32_t +GFDGetPixelShaderCount(const void *file) +{ + return _GFDGetBlockCount(GFD_BLOCK_PIXEL_SHADER_HEADER, + file); +} + +uint32_t +GFDGetPixelShaderHeaderSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_PIXEL_SHADER_HEADER, + index, + file); +} + +uint32_t +GFDGetPixelShaderProgramSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_PIXEL_SHADER_PROGRAM, + index, + file); +} + +BOOL +GFDGetPixelShader(GX2PixelShader *shader, + void *program, + uint32_t index, + const void *file) +{ + if (!_GFDCheckShaderAlign(program)) { + return FALSE; + } + + return _GFDGetGenericBlock(GFD_BLOCK_PIXEL_SHADER_HEADER, + shader, + GFD_BLOCK_PIXEL_SHADER_PROGRAM, + &shader->program, + program, + 0, + NULL, + NULL, + index, + file); +} + +uint32_t +GFDGetVertexShaderCount(const void *file) +{ + return _GFDGetBlockCount(GFD_BLOCK_VERTEX_SHADER_HEADER, + file); +} + +uint32_t +GFDGetVertexShaderHeaderSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_VERTEX_SHADER_HEADER, + index, + file); +} + +uint32_t +GFDGetVertexShaderProgramSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_VERTEX_SHADER_PROGRAM, + index, + file); +} + +BOOL +GFDGetVertexShader(GX2VertexShader *shader, + void *program, + uint32_t index, + const void *file) +{ + return _GFDGetGenericBlock(GFD_BLOCK_VERTEX_SHADER_HEADER, + shader, + GFD_BLOCK_VERTEX_SHADER_PROGRAM, + &shader->program, + program, + 0, + NULL, + NULL, + index, + file); +} + +uint32_t +GFDGetTextureCount(const void *file) +{ + return _GFDGetBlockCount(GFD_BLOCK_TEXTURE_HEADER, + file); +} + +uint32_t +GFDGetTextureHeaderSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_TEXTURE_HEADER, + index, + file); +} + +uint32_t +GFDGetTextureImageSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_TEXTURE_IMAGE, + index, + file); +} + +uint32_t +GFDGetTextureMipImageSize(uint32_t index, + const void *file) +{ + return _GFDGetBlockDataSize(GFD_BLOCK_TEXTURE_MIPMAP, + index, + file); +} + +uint32_t +GFDGetTextureAlignmentSize(uint32_t index, + const void *file) +{ + const GFDBlockHeader *blockHeader; + const GX2Texture *texture; + + if (!_GFDGetBlockPointerConst(GFD_BLOCK_TEXTURE_HEADER, + index, + file, + &blockHeader, + (const void **)&texture)) { + return 0; + } + + return texture->surface.alignment; +} + +BOOL +GFDGetTexture(GX2Texture *texture, + void *image, + void *mipmap, + uint32_t index, + const void *file) +{ + return _GFDGetGenericBlock(GFD_BLOCK_TEXTURE_HEADER, + texture, + GFD_BLOCK_TEXTURE_IMAGE, + &texture->surface.image, + image, + GFD_BLOCK_TEXTURE_MIPMAP, + &texture->surface.mipmaps, + mipmap, + index, + file); +} + +BOOL +GFDGetGX2RTexture(GX2Texture *texture, + uint32_t index, + const void *file) +{ + const uint8_t *ptr = (const uint8_t *)file; + const GFDHeader *fileHeader = (const GFDHeader *)file; + const GFDBlockHeader *blockHeader; + uint32_t headerCount = 0; + BOOL created = FALSE; + + if (!texture || !file) { + return FALSE; + } + + ptr += fileHeader->headerSize; + blockHeader = (const GFDBlockHeader *)ptr; + + while (_GFDCheckBlockHeaderMagicVersions(blockHeader)) { + ptr += blockHeader->headerSize; + + if (blockHeader->type == GFD_BLOCK_TEXTURE_HEADER) { + if (headerCount == index) { + if (blockHeader->dataSize < sizeof(GX2Texture)) { + goto error; + } + + memcpy(texture, ptr, sizeof(GX2Texture)); + + texture->surface.image = NULL; + texture->surface.mipmaps = NULL; + + GX2RCreateSurface(&texture->surface, + GX2R_RESOURCE_BIND_TEXTURE + | GX2R_RESOURCE_USAGE_CPU_WRITE + | GX2R_RESOURCE_USAGE_GPU_READ); + + created = TRUE; + } else if (created) { + break; + } + + headerCount++; + } else if (blockHeader->type == GFD_BLOCK_TEXTURE_IMAGE) { + if (created) { + void *image = GX2RLockSurfaceEx(&texture->surface, 0, 0); + if (!image) { + goto error; + } + + memcpy(image, ptr, blockHeader->dataSize); + GX2RUnlockSurfaceEx(&texture->surface, 0, + GX2R_RESOURCE_DISABLE_CPU_INVALIDATE + | GX2R_RESOURCE_DISABLE_GPU_INVALIDATE); + } + } else if (blockHeader->type == GFD_BLOCK_TEXTURE_MIPMAP) { + if (created) { + void *mipmap = GX2RLockSurfaceEx(&texture->surface, -1, 0); + if (!mipmap) { + goto error; + } + + memcpy(mipmap, ptr, blockHeader->dataSize); + GX2RUnlockSurfaceEx(&texture->surface, -1, + GX2R_RESOURCE_DISABLE_CPU_INVALIDATE + | GX2R_RESOURCE_DISABLE_GPU_INVALIDATE); + } + } else if (blockHeader->type == GFD_BLOCK_END_OF_FILE) { + break; + } + + ptr += blockHeader->dataSize; + blockHeader = (const GFDBlockHeader *)ptr; + } + + if (created && (texture->surface.image || texture->surface.mipmaps)) { + if (texture->surface.image) { + GX2RInvalidateSurface(&texture->surface, 0, 0); + } + + if (texture->surface.mipmaps) { + GX2RInvalidateSurface(&texture->surface, -1, 0); + } + + return TRUE; + } + +error: + GX2RDestroySurfaceEx(&texture->surface, 0); + return FALSE; +} + +const GX2Texture * +GFDGetTexturePointer(uint32_t index, + const void *file) +{ + const GFDBlockHeader *blockHeader; + const GX2Texture *texture; + + if (!_GFDGetBlockPointerConst(GFD_BLOCK_TEXTURE_HEADER, + index, + file, + &blockHeader, + (const void **)&texture)) { + return NULL; + } + + if (blockHeader->dataSize < sizeof(GX2Texture)) { + return NULL; + } + + return texture; +} diff --git a/libraries/libwhb/CMakeLists.txt b/libraries/libwhb/CMakeLists.txt new file mode 100644 index 0000000..d89472f --- /dev/null +++ b/libraries/libwhb/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.2) +project(libwhb) + +file(GLOB_RECURSE SOURCE_FILES *.c) +file(GLOB_RECURSE HEADER_FILES *.h) + +add_library(whb STATIC ${SOURCE_FILES} ${HEADER_FILES}) + +target_include_directories(whb PRIVATE "../../include") +target_include_directories(whb PRIVATE "../libdefaultheap/include") +target_include_directories(whb PRIVATE "../libgfd/include") +target_include_directories(whb PUBLIC "include") + +install(TARGETS whb + ARCHIVE DESTINATION "${CMAKE_INSTALL_PREFIX}/lib") +install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ + DESTINATION "${CMAKE_INSTALL_PREFIX}/include" + FILES_MATCHING PATTERN "*.h*") + diff --git a/libraries/libwhb/include/whb/align.h b/libraries/libwhb/include/whb/align.h new file mode 100644 index 0000000..221e33a --- /dev/null +++ b/libraries/libwhb/include/whb/align.h @@ -0,0 +1,20 @@ +#pragma once +#include + +/** + * \defgroup whb_align Align + * \ingroup whb + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define WHBAlignUp(val, align) ((val + align - 1) & ~(align - 1)) + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/libraries/libwhb/include/whb/commandserver.h b/libraries/libwhb/include/whb/commandserver.h new file mode 100644 index 0000000..59f5d3f --- /dev/null +++ b/libraries/libwhb/include/whb/commandserver.h @@ -0,0 +1,29 @@ +#pragma once +#include + +/** + * \defgroup whb_commandserver Network Command Server + * \ingroup whb + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define WHB_SERVER_BUFFER_SIZE 1024 + +BOOL +WHBCommandServerInit(); + +void +WHBCommandServerStop(); + +BOOL +WHBCommandServerListen(char * stringLocation); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/libraries/libwhb/include/whb/crash.h b/libraries/libwhb/include/whb/crash.h new file mode 100644 index 0000000..dd255f9 --- /dev/null +++ b/libraries/libwhb/include/whb/crash.h @@ -0,0 +1,21 @@ +#pragma once +#include + +/** + * \defgroup whb_crash Crash Handler + * \ingroup whb + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +BOOL +WHBInitCrashHandler(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/libraries/libwhb/include/whb/file.h b/libraries/libwhb/include/whb/file.h new file mode 100644 index 0000000..914ccd2 --- /dev/null +++ b/libraries/libwhb/include/whb/file.h @@ -0,0 +1,47 @@ +#pragma once +#include + +/** + * \defgroup whb_file Filesystem + * \ingroup whb + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum WHBFileError +{ + WHB_FILE_OK = 0, + WHB_FILE_FATAL_ERROR = -1, +} WHBFileError; + +int32_t +WHBOpenFile(const char *path, + const char *mode); + +uint32_t +WHBGetFileSize(int32_t handle); + +uint32_t +WHBReadFile(int32_t handle, + void *buf, + uint32_t size, + uint32_t count); + +int32_t +WHBCloseFile(int32_t handle); + +char * +WHBReadWholeFile(const char *path, + uint32_t *outSize); + +void +WHBFreeWholeFile(char *file); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/libraries/libwhb/include/whb/gfx.h b/libraries/libwhb/include/whb/gfx.h new file mode 100644 index 0000000..fba9597 --- /dev/null +++ b/libraries/libwhb/include/whb/gfx.h @@ -0,0 +1,95 @@ +#pragma once +#include +#include +#include + +/** + * \defgroup whb_gfx Graphics + * \ingroup whb + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct WHBGfxShaderGroup WHBGfxShaderGroup; + +struct WHBGfxShaderGroup +{ + GX2FetchShader fetchShader; + void *fetchShaderProgram; + GX2PixelShader *pixelShader; + GX2VertexShader *vertexShader; + uint32_t numAttributes; + GX2AttribStream attributes[16]; +}; + +BOOL +WHBGfxInit(); + +void +WHBGfxShutdown(); + +void +WHBGfxBeginRender(); + +void +WHBGfxFinishRender(); + +void +WHBGfxBeginRenderDRC(); + +void +WHBGfxFinishRenderDRC(); + +void +WHBGfxBeginRenderTV(); + +void +WHBGfxFinishRenderTV(); + +GX2PixelShader * +WHBGfxLoadGFDPixelShader(uint32_t index, + const void *file); + +BOOL +WHBGfxFreePixelShader(GX2PixelShader *shader); + +GX2VertexShader * +WHBGfxLoadGFDVertexShader(uint32_t index, + const void *file); + +BOOL +WHBGfxFreeVertexShader(GX2VertexShader *shader); + +BOOL +WHBGfxLoadGFDShaderGroup(WHBGfxShaderGroup *group, + uint32_t index, + const void *file); + +BOOL +WHBGfxInitShaderAttribute(WHBGfxShaderGroup *group, + const char *name, + uint32_t buffer, + uint32_t offset, + GX2AttribFormat format); + +BOOL +WHBGfxInitFetchShader(WHBGfxShaderGroup *group); + +BOOL +WHBGfxFreeShaderGroup(WHBGfxShaderGroup *group); + +GX2Texture * +WHBGfxLoadGFDTexture(uint32_t index, + const void *file); + +BOOL +WHBGfxFreeTexture(GX2Texture *texture); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/libraries/libwhb/include/whb/libmanager.h b/libraries/libwhb/include/whb/libmanager.h new file mode 100644 index 0000000..d088997 --- /dev/null +++ b/libraries/libwhb/include/whb/libmanager.h @@ -0,0 +1,27 @@ +#pragma once + +/** + * \defgroup whb_socketinit Socket Library Initialization Manager + * \ingroup whb + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Socket Library (nsysnet.rpl) + */ + +void +WHBInitializeSocketLibrary(); + +void +WHBDeinitializeSocketLibrary(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/libraries/libwhb/include/whb/log.h b/libraries/libwhb/include/whb/log.h new file mode 100644 index 0000000..f2c1964 --- /dev/null +++ b/libraries/libwhb/include/whb/log.h @@ -0,0 +1,38 @@ +#pragma once +#include + +/** + * \defgroup whb_log Logger + * \ingroup whb + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*LogHandlerFn)(const char *msg); + +BOOL +WHBAddLogHandler(LogHandlerFn fn); + +BOOL +WHBRemoveLogHandler(LogHandlerFn fn); + +BOOL +WHBLogWrite(const char *str); + +BOOL +WHBLogPrint(const char *str); + +BOOL +WHBLogWritef(const char *fmt, ...); + +BOOL +WHBLogPrintf(const char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/libraries/libwhb/include/whb/log_cafe.h b/libraries/libwhb/include/whb/log_cafe.h new file mode 100644 index 0000000..023b5fe --- /dev/null +++ b/libraries/libwhb/include/whb/log_cafe.h @@ -0,0 +1,24 @@ +#pragma once +#include + +/** + * \defgroup whb_log_cafe Cafe OS System Log Output + * \ingroup whb + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +BOOL +WHBLogCafeInit(); + +BOOL +WHBLogCafeDeinit(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/libraries/libwhb/include/whb/log_udp.h b/libraries/libwhb/include/whb/log_udp.h new file mode 100644 index 0000000..00900c6 --- /dev/null +++ b/libraries/libwhb/include/whb/log_udp.h @@ -0,0 +1,24 @@ +#pragma once +#include + +/** + * \defgroup whb_log_udp UDP Log Output + * \ingroup whb + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +BOOL +WHBLogUdpInit(); + +BOOL +WHBLogUdpDeinit(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/libraries/libwhb/include/whb/proc.h b/libraries/libwhb/include/whb/proc.h new file mode 100644 index 0000000..b07cd57 --- /dev/null +++ b/libraries/libwhb/include/whb/proc.h @@ -0,0 +1,30 @@ +#pragma once +#include + +/** + * \defgroup whb_proc ProcUI Utilities + * \ingroup whb + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void +WHBProcInit(); + +void +WHBProcShutdown(); + +void +WHBProcStopRunning(); + +BOOL +WHBProcIsRunning(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/libraries/libwhb/include/whb/sdcard.h b/libraries/libwhb/include/whb/sdcard.h new file mode 100644 index 0000000..bee1a8c --- /dev/null +++ b/libraries/libwhb/include/whb/sdcard.h @@ -0,0 +1,27 @@ +#pragma once +#include + +/** + * \defgroup whb_sdcard SDCard Access + * \ingroup whb + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +BOOL +WHBMountSdCard(); + +char * +WHBGetSdCardMountPath(); + +BOOL +WHBUnmountSdCard(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/libraries/libwhb/src/commandserver.c b/libraries/libwhb/src/commandserver.c new file mode 100644 index 0000000..a2c1831 --- /dev/null +++ b/libraries/libwhb/src/commandserver.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include +#include + +#include + +#define SERVER_PORT 4406 + +int +sSocket = -1; + +int +sClient = -1; + +struct sockaddr_in +sAddr; + +static inline void +closeSocket(const char * funcName) +{ + int ret = socketclose(sSocket); + if(ret < 0) { + WHBLogPrintf("%s: Error occurred closing socket: %d", funcName, socketlasterr()); + } + else { + sSocket = -1; + } +} + +static inline void +closeClient(const char * funcName) +{ + int ret = socketclose(sClient); + if(ret < 0) { + WHBLogPrintf("%s: Error occurred closing client socket: %d", funcName, socketlasterr()); + } + else { + sClient = -1; + } +} + +BOOL +WHBCommandServerInit() +{ + int ret = 0; + + if(sSocket >= 0) { + WHBLogPrintf("%s: Command server is already running.", __FUNCTION__); + return TRUE; + } + + WHBInitializeSocketLibrary(); + + sSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(sSocket < 0) { + WHBLogPrintf("%s: Error occurred while creating socket: %d", __FUNCTION__, socketlasterr()); + sSocket = -1; + return FALSE; + } + + memset(&sAddr, 0, sizeof(struct sockaddr_in)); + sAddr.sin_family = AF_INET; + sAddr.sin_port = htons(SERVER_PORT); + sAddr.sin_addr.s_addr = htonl(INADDR_ANY); + + ret = bind(sSocket, (struct sockaddr *)&sAddr, sizeof(struct sockaddr_in)); + if(ret < 0) { + WHBLogPrintf("%s: Error occurred while binding to socket: %d", __FUNCTION__, socketlasterr()); + closeSocket(__FUNCTION__); + return FALSE; + } + + ret = listen(sSocket, 3); + if(ret < 0) { + WHBLogPrintf("%s: Error occurred while setting socket to listen mode: %d", __FUNCTION__, socketlasterr()); + closeSocket(__FUNCTION__); + return FALSE; + } + + return TRUE; +} + +void +WHBCommandServerStop() +{ + if(sSocket < 0) { + WHBLogPrintf("%s: Socket is already closed.", __FUNCTION__); + return; + } + + if(sClient >= 0) { + closeClient(__FUNCTION__); + } + closeSocket(__FUNCTION__); + WHBDeinitializeSocketLibrary(); +} + +BOOL +WHBCommandServerListen(char * stringLocation) +{ + char buffer[WHB_SERVER_BUFFER_SIZE]; + memset(buffer, 0, WHB_SERVER_BUFFER_SIZE); + + int ret; + struct sockaddr_in sClientAddr; + socklen_t sClientAddrLen = sizeof(struct sockaddr_in); + + if(sSocket < 0) { + WHBLogPrintf("%s: Socket is not open. Please run WHBCommandServerInit() first.", __FUNCTION__); + return FALSE; + } + + if(sClient < 0) { + sClient = accept(sSocket, (struct sockaddr *)&sClientAddr, &sClientAddrLen); + if(sClient < 0) { + WHBLogPrintf("%s: Error occurred while accepting a client connection: %d", __FUNCTION__, socketlasterr()); + return FALSE; + } + } + + ret = recv(sClient, buffer, WHB_SERVER_BUFFER_SIZE, 0); + if(ret < 0) { + WHBLogPrintf("%s: Error occurred while receiving data from client: %d", __FUNCTION__, socketlasterr()); + closeClient(__FUNCTION__); + return FALSE; + } + if(ret == 0) { + WHBLogPrintf("%s: Remote socket was closed. Closing client connection...", __FUNCTION__); + closeClient(__FUNCTION__); + return FALSE; + } + + memcpy(stringLocation, buffer, WHB_SERVER_BUFFER_SIZE); + return TRUE; +} diff --git a/libraries/libwhb/src/crash.c b/libraries/libwhb/src/crash.c new file mode 100644 index 0000000..85f5b14 --- /dev/null +++ b/libraries/libwhb/src/crash.c @@ -0,0 +1,258 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_DISASSEMBLY_SIZE (4096) +#define LOG_STACK_TRACE_SIZE (4096) +#define LOG_REGISTER_SIZE (4096) + +#define THREAD_STACK_SIZE (4096) + +static const char * +sCrashType = NULL; + +static char +sDisassemblyBuffer[LOG_DISASSEMBLY_SIZE]; + +static uint32_t +sDisassemblyLength = 0; + +static char +sStackTraceBuffer[LOG_STACK_TRACE_SIZE]; + +static uint32_t +sStackTraceLength = 0; + +static char +sRegistersBuffer[LOG_REGISTER_SIZE]; + +static uint32_t +sRegistersLength = 0; + +static uint8_t +sCrashThreadStack[THREAD_STACK_SIZE]; + +static OSThread __attribute__((aligned(8))) +sCrashThread; + +static int +crashReportThread(int argc, const char **argv) +{ + // Log crash dump + WHBLogPrint(sRegistersBuffer); + WHBLogPrint(sDisassemblyBuffer); + WHBLogPrint(sStackTraceBuffer); + + // TODO: Save crash dump to SD card? + return 0; +} + +static void +disassemblyPrintCallback(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + sDisassemblyLength += vsprintf(sDisassemblyBuffer + sDisassemblyLength, fmt, args); + sDisassemblyBuffer[sDisassemblyLength] = 0; + va_end(args); +} + +static void +getDisassembly(OSContext *context) +{ + sDisassemblyLength = 0; + sDisassemblyBuffer[0] = 0; + + if (context->srr0 > 16) { + DisassemblePPCRange((void *)(context->srr0 - 16), + (void *)(context->srr0 + 16), + disassemblyPrintCallback, + OSGetSymbolName, + DISASSEMBLE_PPC_FLAGS_NONE); + } +} + +static void +getStackTrace(OSContext *context) +{ + int i; + uint32_t *stackPtr; + char name[256]; + + sStackTraceLength = 0; + sStackTraceBuffer[0] = 0; + stackPtr = (uint32_t *)context->gpr[1]; + + sStackTraceLength += sprintf(sStackTraceBuffer + sStackTraceLength, "Address: Back Chain LR Save\n"); + + for (i = 0; i < 16; ++i) { + uint32_t addr; + + if (!stackPtr || (uintptr_t)stackPtr == 0x1 || (uintptr_t)stackPtr == 0xFFFFFFFF) { + break; + } + + sStackTraceLength += sprintf(sStackTraceBuffer + sStackTraceLength, "0x%08x: 0x%08x 0x%08x", stackPtr, stackPtr[0], stackPtr[1]); + + addr = OSGetSymbolName(stackPtr[1], name, sizeof(name)); + if (addr) { + sStackTraceLength += sprintf(sStackTraceBuffer + sStackTraceLength, " %s+0x%x", name, stackPtr[1] - addr); + } + + sStackTraceLength += sprintf(sStackTraceBuffer + sStackTraceLength, "\n"); + stackPtr = (uint32_t *)*stackPtr; + } + + sStackTraceBuffer[sStackTraceLength] = 0; +} + +static void +writeRegister(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + sRegistersLength += vsprintf(sRegistersBuffer + sRegistersLength, fmt, args); + sRegistersBuffer[sRegistersLength] = 0; + va_end(args); +} + +static void +getRegisters(OSContext *context) +{ + OSTime tbr = OSGetSystemTime(); + uint32_t addr; + char name[256]; + int i; + uint64_t *fpr, *psf; + + sRegistersLength = 0; + sRegistersBuffer[sRegistersLength] = 0; + + writeRegister("--Proc%d-Core%u--------- OSContext 0x%p --------------------\n\n", + OSGetUPID(), OSGetCoreId(), context); + writeRegister("tag1 = 0x%08X (expecting 0x%08X)\n", + (uint32_t)(context->tag >> 32), (uint32_t)(OS_CONTEXT_TAG >> 32)); + writeRegister("tag2 = 0x%08X (expecting 0x%08X)\n", + (uint32_t)(context->tag & 0xFFFFFFFF), (uint32_t)(OS_CONTEXT_TAG & 0xFFFFFFFF)); + writeRegister("TBR = 0x%08X_%08X\n", + (uint32_t)(tbr >> 32), (uint32_t)(tbr & 0xFFFFFFFF)); + writeRegister("CR = 0x%08X\n", context->cr); + writeRegister("CTR = 0x%08X\n", context->ctr); + + writeRegister("LR = 0x%08X", context->lr); + addr = OSGetSymbolName(context->lr, name, sizeof(name)); + if (addr) { + writeRegister(" %s+0x%X", name, context->lr - addr); + } + writeRegister("\n"); + + writeRegister("SRR0 = 0x%08X", context->srr0); + addr = OSGetSymbolName(context->srr0, name, sizeof(name)); + if (addr) { + writeRegister(" %s+0x%X", name, context->srr0 - addr); + } + writeRegister("\n"); + + writeRegister("SRR1 = 0x%08X\n", context->srr1); + writeRegister("state = 0x%04X\n", context->state); + + for (i = 0; i < 16; ++i) { + writeRegister("r%-2d = 0x%08x (%14d) r%-2d = 0x%08x (%14d)\n", + i, context->gpr[i], context->gpr[i], + i + 16, context->gpr[i + 16], context->gpr[i + 16]); + } + + writeRegister("\n--GQRs----------\n"); + for (i = 0; i < 4; ++i) { + writeRegister("gqr%d = 0x%08x \t gqr%d = 0x%08x\n", + i, context->gqr[i], context->gqr[i], + i + 4, context->gqr[i + 4], context->gqr[i + 4]); + } + + writeRegister("\n--Per-core OSContext runtime ----\n"); + for (i = 0; i < 3; ++i) { + writeRegister("coretime[%d] = 0x%016llX ticks, %lld second(s) elapsed\n", + i, context->coretime[i], context->coretime[i] / OSOneSecond); + } + + writeRegister("\n--FPRs----------\n"); + fpr = (uint64_t *)context->fpr; + for (i = 0; i < 16; ++i) { + writeRegister("fr%d \t= 0x%16.16llx \t fr%d \t= 0x%16.16llx\n", + i, fpr[i], + i + 16, fpr[i + 16]); + } + + writeRegister("\n\n--PSFs----------\n"); + psf = (uint64_t *)context->psf; + for (i = 0; i < 16; ++i) { + writeRegister("ps%d \t= 0x%16.16llx \t ps%d \t= 0x%16.16llx\n", + i, psf[i], + i + 16, psf[i + 16]); + } +} + +static BOOL +handleException(const char *type, + OSContext *context) +{ + sCrashType = type; + getDisassembly(context); + getStackTrace(context); + getRegisters(context); + + OSCreateThread(&sCrashThread, + crashReportThread, + 0, + NULL, + sCrashThreadStack + THREAD_STACK_SIZE, + THREAD_STACK_SIZE, + 16, + 0); + + OSResumeThread(&sCrashThread); + OSSuspendThread((OSThread *)context); + return TRUE; +} + +static BOOL +handleAlignment(OSContext *context) +{ + return handleException("ALIGNMENT", context); +} + +static BOOL +handleDSI(OSContext *context) +{ + return handleException("DSI", context); +} + +static BOOL +handleISI(OSContext *context) +{ + return handleException("ISI", context); +} + +static BOOL +handleProgram(OSContext *context) +{ + return handleException("PROGRAM", context); +} + +BOOL +WHBInitCrashHandler() +{ + OSSetExceptionCallback(OS_EXCEPTION_TYPE_ALIGNMENT, handleAlignment); + OSSetExceptionCallback(OS_EXCEPTION_TYPE_DSI, handleDSI); + OSSetExceptionCallback(OS_EXCEPTION_TYPE_ISI, handleISI); + OSSetExceptionCallback(OS_EXCEPTION_TYPE_PROGRAM, handleProgram); + return TRUE; +} diff --git a/libraries/libwhb/src/file.c b/libraries/libwhb/src/file.c new file mode 100644 index 0000000..d02926d --- /dev/null +++ b/libraries/libwhb/src/file.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include + +static BOOL +sInitialised = FALSE; + +static FSClient +sClient; + +static BOOL +InitFileSystem() +{ + if (!sInitialised) { + FSInit(); + + if (FSAddClient(&sClient, -1) != FS_STATUS_OK) { + return FALSE; + } + + sInitialised = TRUE; + } + + return TRUE; +} + +int32_t +WHBOpenFile(const char *path, + const char *mode) +{ + FSCmdBlock cmd; + FSStatus result; + FSFileHandle handle; + char tmp[256]; + tmp[0] = 0; + + if (!InitFileSystem()) { + return WHB_FILE_FATAL_ERROR; + } + + if (path[0] != '/') { + strcat(tmp, "/vol/content/"); + strcat(tmp, path); + } else { + strcat(tmp, path); + } + + FSInitCmdBlock(&cmd); + result = FSOpenFile(&sClient, &cmd, tmp, mode, &handle, -1); + if (result < 0) { + WHBLogPrintf("%s: FSOpenFile error %d", __FUNCTION__, result); + return WHB_FILE_FATAL_ERROR; + } + + return (int32_t)handle; +} + +uint32_t +WHBGetFileSize(int32_t handle) +{ + FSCmdBlock cmd; + FSStatus result; + FSStat stat; + FSInitCmdBlock(&cmd); + result = FSGetStatFile(&sClient, &cmd, (FSFileHandle)handle, &stat, -1); + if (result < 0) { + WHBLogPrintf("%s: FSGetStatFile error %d", __FUNCTION__, result); + return 0; + } + + return stat.size; +} + +uint32_t +WHBReadFile(int32_t handle, + void *buf, + uint32_t size, + uint32_t count) +{ + FSCmdBlock cmd; + FSStatus result; + FSInitCmdBlock(&cmd); + result = FSReadFile(&sClient, &cmd, buf, size, count, (FSFileHandle)handle, 0, -1); + if (result < 0) { + WHBLogPrintf("%s: FSReadFile error %d", __FUNCTION__, result); + return 0; + } + + return (uint32_t)result; +} + +int32_t +WHBCloseFile(int32_t handle) +{ + FSCmdBlock cmd; + FSStatus result; + FSInitCmdBlock(&cmd); + result = FSCloseFile(&sClient, &cmd, (FSFileHandle)handle, -1); + if (result != FS_STATUS_OK) { + WHBLogPrintf("%s: FSCloseFile error %d", __FUNCTION__, result); + return WHB_FILE_FATAL_ERROR; + } + + return WHB_FILE_OK; +} + +char * +WHBReadWholeFile(const char *path, + uint32_t *outSize) +{ + int32_t handle; + uint32_t size; + char *buf = NULL; + handle = WHBOpenFile(path, "r"); + if (handle == WHB_FILE_FATAL_ERROR) { + WHBLogPrintf("%s: WHBOpenFile failed", __FUNCTION__); + return NULL; + } + + size = WHBGetFileSize(handle); + if (size == 0) { + goto error; + } + + buf = MEMAllocFromDefaultHeapEx(size, 64); + if (!buf) { + WHBLogPrintf("%s: MEMAllocFromDefaultHeapEx(0x%X, 64) failed", __FUNCTION__, size); + goto error; + } + + if (WHBReadFile(handle, buf, 1, size) != size) { + goto error; + } + + if (outSize) { + *outSize = size; + } + + WHBCloseFile(handle); + return buf; + +error: + if (buf) { + MEMFreeToDefaultHeap(buf); + } + + WHBCloseFile(handle); + return NULL; +} + +void +WHBFreeWholeFile(char *file) +{ + MEMFreeToDefaultHeap(file); +} diff --git a/libraries/libwhb/src/gfx.c b/libraries/libwhb/src/gfx.c new file mode 100644 index 0000000..a0c2020 --- /dev/null +++ b/libraries/libwhb/src/gfx.c @@ -0,0 +1,520 @@ +#include "gfx_heap.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WHB_GFX_COMMAND_BUFFER_POOL_SIZE (0x400000) + +static void * +sCommandBufferPool = NULL; + +static GX2DrcRenderMode +sDrcRenderMode; + +static void * +sDrcScanBuffer = NULL; + +static uint32_t +sDrcScanBufferSize = 0; + +static GX2SurfaceFormat +sDrcSurfaceFormat; + +static GX2TVRenderMode +sTvRenderMode; + +static void * +sTvScanBuffer = NULL; + +static uint32_t +sTvScanBufferSize = 0; + +static GX2SurfaceFormat +sTvSurfaceFormat; + +static GX2ColorBuffer +sTvColourBuffer = { 0 }; + +static GX2DepthBuffer +sTvDepthBuffer = { 0 }; + +static GX2ColorBuffer +sDrcColourBuffer = { 0 }; + +static GX2DepthBuffer +sDrcDepthBuffer = { 0 }; + +static GX2ContextState * +sTvContextState = NULL; + +static GX2ContextState * +sDrcContextState = NULL; + +static BOOL +sGpuTimedOut = FALSE; + +static void * +GfxGX2RAlloc(GX2RResourceFlags flags, + uint32_t size, + uint32_t alignment) +{ + // Color, depth, scan buffers all belong in MEM1 + if ((flags & (GX2R_RESOURCE_BIND_COLOR_BUFFER + | GX2R_RESOURCE_BIND_DEPTH_BUFFER + | GX2R_RESOURCE_BIND_SCAN_BUFFER + | GX2R_RESOURCE_USAGE_FORCE_MEM1)) + && !(flags & GX2R_RESOURCE_USAGE_FORCE_MEM2)) { + return GfxHeapAllocMEM1(size, alignment); + } else { + return GfxHeapAllocMEM2(size, alignment); + } +} + +static void +GfxGX2RFree(GX2RResourceFlags flags, void *block) +{ + if ((flags & (GX2R_RESOURCE_BIND_COLOR_BUFFER + | GX2R_RESOURCE_BIND_DEPTH_BUFFER + | GX2R_RESOURCE_BIND_SCAN_BUFFER + | GX2R_RESOURCE_USAGE_FORCE_MEM1)) + && !(flags & GX2R_RESOURCE_USAGE_FORCE_MEM2)) { + return GfxHeapFreeMEM1(block); + } else { + return GfxHeapFreeMEM2(block); + } +} + +static void +GfxInitTvColourBuffer(GX2ColorBuffer *cb, + uint32_t width, + uint32_t height, + GX2SurfaceFormat format, + GX2AAMode aa) +{ + memset(cb, 0, sizeof(GX2ColorBuffer)); + cb->surface.use = GX2_SURFACE_USE_TEXTURE_COLOR_BUFFER_TV; + cb->surface.dim = GX2_SURFACE_DIM_TEXTURE_2D; + cb->surface.width = width; + cb->surface.height = height; + cb->surface.depth = 1; + cb->surface.mipLevels = 1; + cb->surface.format = format; + cb->surface.aa = aa; + cb->surface.tileMode = GX2_TILE_MODE_DEFAULT; + cb->viewNumSlices = 1; + GX2CalcSurfaceSizeAndAlignment(&cb->surface); + GX2InitColorBufferRegs(cb); +} + +static void +GfxInitDepthBuffer(GX2DepthBuffer *db, + uint32_t width, + uint32_t height, + GX2SurfaceFormat format, + GX2AAMode aa) +{ + memset(db, 0, sizeof(GX2DepthBuffer)); + + if (format == GX2_SURFACE_FORMAT_UNORM_R24_X8 || format == GX2_SURFACE_FORMAT_FLOAT_D24_S8) { + db->surface.use = GX2_SURFACE_USE_DEPTH_BUFFER; + } else { + db->surface.use = GX2_SURFACE_USE_DEPTH_BUFFER | GX2_SURFACE_USE_TEXTURE; + } + + db->surface.dim = GX2_SURFACE_DIM_TEXTURE_2D; + db->surface.width = width; + db->surface.height = height; + db->surface.depth = 1; + db->surface.mipLevels = 1; + db->surface.format = format; + db->surface.aa = aa; + db->surface.tileMode = GX2_TILE_MODE_DEFAULT; + db->viewNumSlices = 1; + db->depthClear = 1.0f; + GX2CalcSurfaceSizeAndAlignment(&db->surface); + GX2InitDepthBufferRegs(db); +} + +static uint32_t +GfxProcCallbackAcquired(void *context) +{ + if (!GfxHeapInitMEM1()) { + WHBLogPrintf("%s: GfxHeapInitMEM1 failed", __FUNCTION__); + goto error; + } + + if (!GfxHeapInitForeground()) { + WHBLogPrintf("%s: GfxHeapInitForeground failed", __FUNCTION__); + goto error; + } + + // Allocate TV scan buffer. + sTvScanBuffer = GfxHeapAllocForeground(sTvScanBufferSize, GX2_SCAN_BUFFER_ALIGNMENT); + if (!sTvScanBuffer) { + WHBLogPrintf("%s: sTvScanBuffer = GfxHeapAllocForeground(0x%X, 0x%X) failed", + __FUNCTION__, + sTvScanBufferSize, + GX2_SCAN_BUFFER_ALIGNMENT); + goto error; + } + GX2Invalidate(GX2_INVALIDATE_MODE_CPU, sTvScanBuffer, sTvScanBufferSize); + GX2SetTVBuffer(sTvScanBuffer, sTvScanBufferSize, sTvRenderMode, sTvSurfaceFormat, GX2_BUFFERING_MODE_DOUBLE); + + // Allocate TV colour buffer. + sTvColourBuffer.surface.image = GfxHeapAllocMEM1(sTvColourBuffer.surface.imageSize, sTvColourBuffer.surface.alignment); + if (!sTvColourBuffer.surface.image) { + WHBLogPrintf("%s: sTvColourBuffer = GfxHeapAllocMEM1(0x%X, 0x%X) failed", + __FUNCTION__, + sTvColourBuffer.surface.imageSize, + sTvColourBuffer.surface.alignment); + goto error; + } + GX2Invalidate(GX2_INVALIDATE_MODE_CPU, sTvColourBuffer.surface.image, sTvColourBuffer.surface.imageSize); + + // Allocate TV depth buffer. + sTvDepthBuffer.surface.image = GfxHeapAllocMEM1(sTvDepthBuffer.surface.imageSize, sTvDepthBuffer.surface.alignment); + if (!sTvDepthBuffer.surface.image) { + WHBLogPrintf("%s: sTvDepthBuffer = GfxHeapAllocMEM1(0x%X, 0x%X) failed", + __FUNCTION__, + sTvDepthBuffer.surface.imageSize, + sTvDepthBuffer.surface.alignment); + goto error; + } + GX2Invalidate(GX2_INVALIDATE_MODE_CPU, sTvDepthBuffer.surface.image, sTvDepthBuffer.surface.imageSize); + + // Allocate DRC scan buffer. + sDrcScanBuffer = GfxHeapAllocForeground(sDrcScanBufferSize, GX2_SCAN_BUFFER_ALIGNMENT); + if (!sDrcScanBuffer) { + WHBLogPrintf("%s: sDrcScanBuffer = GfxHeapAllocForeground(0x%X, 0x%X) failed", + __FUNCTION__, + sDrcScanBufferSize, + GX2_SCAN_BUFFER_ALIGNMENT); + goto error; + } + GX2Invalidate(GX2_INVALIDATE_MODE_CPU, sDrcScanBuffer, sDrcScanBufferSize); + GX2SetDRCBuffer(sDrcScanBuffer, sDrcScanBufferSize, sDrcRenderMode, sDrcSurfaceFormat, GX2_BUFFERING_MODE_DOUBLE); + + // Allocate DRC colour buffer. + sDrcColourBuffer.surface.image = GfxHeapAllocMEM1(sDrcColourBuffer.surface.imageSize, sDrcColourBuffer.surface.alignment); + if (!sDrcColourBuffer.surface.image) { + WHBLogPrintf("%s: sDrcColourBuffer = GfxHeapAllocMEM1(0x%X, 0x%X) failed", + __FUNCTION__, + sDrcColourBuffer.surface.imageSize, + sDrcColourBuffer.surface.alignment); + goto error; + } + GX2Invalidate(GX2_INVALIDATE_MODE_CPU, sDrcColourBuffer.surface.image, sDrcColourBuffer.surface.imageSize); + + // Allocate DRC depth buffer. + sDrcDepthBuffer.surface.image = GfxHeapAllocMEM1(sDrcDepthBuffer.surface.imageSize, sDrcDepthBuffer.surface.alignment); + if (!sDrcDepthBuffer.surface.image) { + WHBLogPrintf("%s: sDrcDepthBuffer = GfxHeapAllocMEM1(0x%X, 0x%X) failed", + __FUNCTION__, + sDrcDepthBuffer.surface.imageSize, + sDrcDepthBuffer.surface.alignment); + goto error; + } + GX2Invalidate(GX2_INVALIDATE_MODE_CPU, sDrcDepthBuffer.surface.image, sDrcDepthBuffer.surface.imageSize); + return 0; + +error: + return -1; +} + +static uint32_t +GfxProcCallbackReleased(void *context) +{ + GX2DrawDone(); + + if (sTvScanBuffer) { + GfxHeapFreeForeground(sTvScanBuffer); + sTvScanBuffer = NULL; + } + + if (sTvColourBuffer.surface.image) { + GfxHeapFreeMEM1(sTvColourBuffer.surface.image); + sTvColourBuffer.surface.image = NULL; + } + + if (sTvDepthBuffer.surface.image) { + GfxHeapFreeMEM1(sTvDepthBuffer.surface.image); + sTvDepthBuffer.surface.image = NULL; + } + + if (sDrcScanBuffer) { + GfxHeapFreeForeground(sDrcScanBuffer); + sDrcScanBuffer = NULL; + } + + if (sDrcColourBuffer.surface.image) { + GfxHeapFreeMEM1(sDrcColourBuffer.surface.image); + sDrcColourBuffer.surface.image = NULL; + } + + if (sDrcDepthBuffer.surface.image) { + GfxHeapFreeMEM1(sDrcDepthBuffer.surface.image); + sDrcDepthBuffer.surface.image = NULL; + } + + GfxHeapDestroyMEM1(); + GfxHeapDestroyForeground(); + return 0; +} + +BOOL +WHBGfxInit() +{ + uint32_t drcWidth, drcHeight; + uint32_t tvWidth, tvHeight; + uint32_t unk; + + sCommandBufferPool = GfxHeapAllocMEM2(WHB_GFX_COMMAND_BUFFER_POOL_SIZE, + GX2_COMMAND_BUFFER_ALIGNMENT); + if (!sCommandBufferPool) { + WHBLogPrintf("%s: failed to allocate command buffer pool", __FUNCTION__); + goto error; + } + + uint32_t initAttribs[] = { + GX2_INIT_CMD_BUF_BASE, (uintptr_t)sCommandBufferPool, + GX2_INIT_CMD_BUF_POOL_SIZE, WHB_GFX_COMMAND_BUFFER_POOL_SIZE, + GX2_INIT_ARGC, 0, + GX2_INIT_ARGV, 0, + GX2_INIT_END + }; + GX2Init(initAttribs); + + sDrcRenderMode = GX2GetSystemDRCScanMode(); + sTvSurfaceFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8; + sDrcSurfaceFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8; + + switch(GX2GetSystemTVScanMode()) + { + case GX2_TV_SCAN_MODE_480I: + case GX2_TV_SCAN_MODE_480P: + sTvRenderMode = GX2_TV_RENDER_MODE_WIDE_480P; + tvWidth = 854; + tvHeight = 480; + break; + case GX2_TV_SCAN_MODE_1080I: + case GX2_TV_SCAN_MODE_1080P: + sTvRenderMode = GX2_TV_RENDER_MODE_WIDE_1080P; + tvWidth = 1920; + tvHeight = 1080; + break; + case GX2_TV_SCAN_MODE_720P: + default: + sTvRenderMode = GX2_TV_RENDER_MODE_WIDE_720P; + tvWidth = 1280; + tvHeight = 720; + break; + } + + drcWidth = 854; + drcHeight = 480; + + // Setup TV and DRC buffers - they will be allocated in GfxProcCallbackAcquired. + GX2CalcTVSize(sTvRenderMode, sTvSurfaceFormat, GX2_BUFFERING_MODE_DOUBLE, &sTvScanBufferSize, &unk); + GfxInitTvColourBuffer(&sTvColourBuffer, tvWidth, tvHeight, sTvSurfaceFormat, GX2_AA_MODE1X); + GfxInitDepthBuffer(&sTvDepthBuffer, sTvColourBuffer.surface.width, sTvColourBuffer.surface.height, GX2_SURFACE_FORMAT_FLOAT_R32, sTvColourBuffer.surface.aa); + + GX2CalcDRCSize(sDrcRenderMode, sDrcSurfaceFormat, GX2_BUFFERING_MODE_DOUBLE, &sDrcScanBufferSize, &unk); + GfxInitTvColourBuffer(&sDrcColourBuffer, drcWidth, drcHeight, sDrcSurfaceFormat, GX2_AA_MODE1X); + GfxInitDepthBuffer(&sDrcDepthBuffer, sDrcColourBuffer.surface.width, sDrcColourBuffer.surface.height, GX2_SURFACE_FORMAT_FLOAT_R32, sDrcColourBuffer.surface.aa); + if (GfxProcCallbackAcquired(NULL) != 0) { + WHBLogPrintf("%s: GfxProcCallbackAcquired failed", __FUNCTION__); + goto error; + } + + GX2RSetAllocator(&GfxGX2RAlloc, &GfxGX2RFree); + ProcUIRegisterCallback(PROCUI_CALLBACK_ACQUIRE, GfxProcCallbackAcquired, NULL, 100); + ProcUIRegisterCallback(PROCUI_CALLBACK_RELEASE, GfxProcCallbackReleased, NULL, 100); + + // Initialise TV context state. + sTvContextState = GfxHeapAllocMEM2(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT); + if (!sTvContextState) { + WHBLogPrintf("%s: failed to allocate sTvContextState", __FUNCTION__); + goto error; + } + GX2SetupContextStateEx(sTvContextState, TRUE); + GX2SetContextState(sTvContextState); + GX2SetColorBuffer(&sTvColourBuffer, GX2_RENDER_TARGET_0); + GX2SetDepthBuffer(&sTvDepthBuffer); + GX2SetViewport(0, 0, (float)sTvColourBuffer.surface.width, (float)sTvColourBuffer.surface.height, 0.0f, 1.0f); + GX2SetScissor(0, 0, (float)sTvColourBuffer.surface.width, (float)sTvColourBuffer.surface.height); + GX2SetTVScale((float)sTvColourBuffer.surface.width, (float)sTvColourBuffer.surface.height); + + // Initialise DRC context state. + sDrcContextState = GfxHeapAllocMEM2(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT); + if (!sDrcContextState) { + WHBLogPrintf("%s: failed to allocate sDrcContextState", __FUNCTION__); + goto error; + } + GX2SetupContextStateEx(sDrcContextState, TRUE); + GX2SetContextState(sDrcContextState); + GX2SetColorBuffer(&sDrcColourBuffer, GX2_RENDER_TARGET_0); + GX2SetDepthBuffer(&sDrcDepthBuffer); + GX2SetViewport(0, 0, (float)sDrcColourBuffer.surface.width, (float)sDrcColourBuffer.surface.height, 0.0f, 1.0f); + GX2SetScissor(0, 0, (float)sDrcColourBuffer.surface.width, (float)sDrcColourBuffer.surface.height); + GX2SetDRCScale((float)sDrcColourBuffer.surface.width, (float)sDrcColourBuffer.surface.height); + + // Set 60fps VSync + GX2SetSwapInterval(1); + + return TRUE; + +error: + if (sCommandBufferPool) { + GfxHeapFreeMEM2(sCommandBufferPool); + sCommandBufferPool = NULL; + } + + if (sTvScanBuffer) { + GfxHeapFreeForeground(sTvScanBuffer); + sTvScanBuffer = NULL; + } + + if (sTvColourBuffer.surface.image) { + GfxHeapFreeMEM1(sTvColourBuffer.surface.image); + sTvColourBuffer.surface.image = NULL; + } + + if (sTvDepthBuffer.surface.image) { + GfxHeapFreeMEM1(sTvDepthBuffer.surface.image); + sTvDepthBuffer.surface.image = NULL; + } + + if (sTvContextState) { + GfxHeapFreeMEM2(sTvContextState); + sTvContextState = NULL; + } + + if (sDrcScanBuffer) { + GfxHeapFreeForeground(sDrcScanBuffer); + sDrcScanBuffer = NULL; + } + + if (sDrcColourBuffer.surface.image) { + GfxHeapFreeMEM1(sDrcColourBuffer.surface.image); + sDrcColourBuffer.surface.image = NULL; + } + + if (sDrcDepthBuffer.surface.image) { + GfxHeapFreeMEM1(sDrcDepthBuffer.surface.image); + sDrcDepthBuffer.surface.image = NULL; + } + + if (sDrcContextState) { + GfxHeapFreeMEM2(sDrcContextState); + sDrcContextState = NULL; + } + + return FALSE; +} + +void +WHBGfxShutdown() +{ + if (sGpuTimedOut) { + GX2ResetGPU(0); + sGpuTimedOut = FALSE; + } + + GfxProcCallbackReleased(NULL); + GX2RSetAllocator(NULL, NULL); + GX2Shutdown(); + + if (sTvContextState) { + GfxHeapFreeMEM2(sTvContextState); + sTvContextState = NULL; + } + + if (sDrcContextState) { + GfxHeapFreeMEM2(sDrcContextState); + sDrcContextState = NULL; + } + + if (sCommandBufferPool) { + GfxHeapFreeMEM2(sCommandBufferPool); + sCommandBufferPool = NULL; + } +} + +void +WHBGfxBeginRender() +{ + uint32_t swapCount, flipCount; + OSTime lastFlip, lastVsync; + uint32_t waitCount = 0; + + while (true) { + GX2GetSwapStatus(&swapCount, &flipCount, &lastFlip, &lastVsync); + + if (flipCount >= swapCount) { + break; + } + + if (waitCount >= 10) { + WHBLogPrint("WHBGfxBeginRender wait for swap timed out"); + sGpuTimedOut = TRUE; + break; + } + + waitCount++; + GX2WaitForVsync(); + } +} + +void +WHBGfxFinishRender() +{ + GX2SwapScanBuffers(); + GX2Flush(); + GX2DrawDone(); + GX2SetTVEnable(TRUE); + GX2SetDRCEnable(TRUE); +} + +void +WHBGfxBeginRenderDRC() +{ + GX2SetContextState(sDrcContextState); + GX2ClearColor(&sDrcColourBuffer, 0.0f, 1.0f, 0.0f, 1.0f); + GX2ClearDepthStencilEx(&sDrcDepthBuffer, sDrcDepthBuffer.depthClear, sDrcDepthBuffer.stencilClear, GX2_CLEAR_FLAGS_DEPTH | GX2_CLEAR_FLAGS_STENCIL); + GX2SetContextState(sDrcContextState); +} + +void +WHBGfxFinishRenderDRC() +{ + GX2CopyColorBufferToScanBuffer(&sDrcColourBuffer, GX2_SCAN_TARGET_DRC); +} + +void +WHBGfxBeginRenderTV() +{ + GX2SetContextState(sTvContextState); + GX2ClearColor(&sTvColourBuffer, 1.0f, 0.0f, 0.0f, 1.0f); + GX2ClearDepthStencilEx(&sTvDepthBuffer, sTvDepthBuffer.depthClear, sTvDepthBuffer.stencilClear, GX2_CLEAR_FLAGS_DEPTH | GX2_CLEAR_FLAGS_STENCIL); + GX2SetContextState(sTvContextState); +} + +void +WHBGfxFinishRenderTV() +{ + GX2CopyColorBufferToScanBuffer(&sTvColourBuffer, GX2_SCAN_TARGET_TV); +} diff --git a/libraries/libwhb/src/gfx_heap.c b/libraries/libwhb/src/gfx_heap.c new file mode 100644 index 0000000..9b726bb --- /dev/null +++ b/libraries/libwhb/src/gfx_heap.c @@ -0,0 +1,176 @@ +#include "gfx_heap.h" +#include +#include +#include +#include +#include + +static void * +sGfxHeapMEM1 = NULL; + +static void * +sGfxHeapForeground = NULL; + +#define GFX_FRAME_HEAP_TAG (0x123DECAF) + +BOOL +GfxHeapInitMEM1() +{ + MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1); + uint32_t size; + void *base; + + if (!MEMRecordStateForFrmHeap(heap, GFX_FRAME_HEAP_TAG)) { + WHBLogPrintf("%s: MEMRecordStateForFrmHeap failed", __FUNCTION__); + return FALSE; + } + + size = MEMGetAllocatableSizeForFrmHeapEx(heap, 4); + if (!size) { + WHBLogPrintf("%s: MEMGetAllocatableSizeForFrmHeapEx == 0", __FUNCTION__); + return FALSE; + } + + base = MEMAllocFromFrmHeapEx(heap, size, 4); + if (!base) { + WHBLogPrintf("%s: MEMAllocFromFrmHeapEx(heap, 0x%X, 4) failed", __FUNCTION__, size); + return FALSE; + } + + sGfxHeapMEM1 = MEMCreateExpHeapEx(base, size, 0); + if (!sGfxHeapMEM1) { + WHBLogPrintf("%s: MEMCreateExpHeapEx(0x%08X, 0x%X, 0) failed", __FUNCTION__, base, size); + return FALSE; + } + + return TRUE; +} + +BOOL +GfxHeapDestroyMEM1() +{ + MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1); + + if (sGfxHeapMEM1) { + MEMDestroyExpHeap(sGfxHeapMEM1); + sGfxHeapMEM1 = NULL; + } + + MEMFreeByStateToFrmHeap(heap, GFX_FRAME_HEAP_TAG); + return TRUE; +} + +BOOL +GfxHeapInitForeground() +{ + MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_FG); + uint32_t size; + void *base; + + size = MEMGetAllocatableSizeForFrmHeapEx(heap, 4); + if (!size) { + WHBLogPrintf("%s: MEMAllocFromFrmHeapEx(heap, 0x%X, 4)", __FUNCTION__, size); + return FALSE; + } + + base = MEMAllocFromFrmHeapEx(heap, size, 4); + if (!base) { + WHBLogPrintf("%s: MEMGetAllocatableSizeForFrmHeapEx == 0", __FUNCTION__); + return FALSE; + } + + sGfxHeapForeground = MEMCreateExpHeapEx(base, size, 0); + if (!sGfxHeapForeground) { + WHBLogPrintf("%s: MEMCreateExpHeapEx(0x%08X, 0x%X, 0)", __FUNCTION__, base, size); + return FALSE; + } + + return TRUE; +} + +BOOL +GfxHeapDestroyForeground() +{ + MEMHeapHandle foreground = MEMGetBaseHeapHandle(MEM_BASE_HEAP_FG); + + if (sGfxHeapForeground) { + MEMDestroyExpHeap(sGfxHeapForeground); + sGfxHeapForeground = NULL; + } + + MEMFreeToFrmHeap(foreground, MEM_FRAME_HEAP_FREE_ALL); + return TRUE; +} + +void * +GfxHeapAllocMEM1(uint32_t size, + uint32_t alignment) +{ + void *block; + + if (!sGfxHeapMEM1) { + return NULL; + } + + if (alignment < 4) { + alignment = 4; + } + + block = MEMAllocFromExpHeapEx(sGfxHeapMEM1, size, alignment); + return block; +} + +void +GfxHeapFreeMEM1(void *block) +{ + if (!sGfxHeapMEM1) { + return; + } + + MEMFreeToExpHeap(sGfxHeapMEM1, block); +} + +void * +GfxHeapAllocForeground(uint32_t size, + uint32_t alignment) +{ + void *block; + + if (!sGfxHeapForeground) { + return NULL; + } + + if (alignment < 4) { + alignment = 4; + } + + block = MEMAllocFromExpHeapEx(sGfxHeapForeground, size, alignment); + return block; +} + +void +GfxHeapFreeForeground(void *block) +{ + if (!sGfxHeapForeground) { + return; + } + + MEMFreeToExpHeap(sGfxHeapForeground, block); +} + +void * +GfxHeapAllocMEM2(uint32_t size, + uint32_t alignment) +{ + if (alignment < 4) { + alignment = 4; + } + + return MEMAllocFromDefaultHeapEx(size, alignment); +} + +void +GfxHeapFreeMEM2(void *block) +{ + MEMFreeToDefaultHeap(block); +} diff --git a/libraries/libwhb/src/gfx_heap.h b/libraries/libwhb/src/gfx_heap.h new file mode 100644 index 0000000..4d4debb --- /dev/null +++ b/libraries/libwhb/src/gfx_heap.h @@ -0,0 +1,35 @@ +#pragma once +#include + +BOOL +GfxHeapInitMEM1(); + +BOOL +GfxHeapDestroyMEM1(); + +BOOL +GfxHeapInitForeground(); + +BOOL +GfxHeapDestroyForeground(); + +void * +GfxHeapAllocMEM1(uint32_t size, + uint32_t alignment); + +void +GfxHeapFreeMEM1(void *block); + +void * +GfxHeapAllocForeground(uint32_t size, + uint32_t alignment); + +void +GfxHeapFreeForeground(void *block); + +void * +GfxHeapAllocMEM2(uint32_t size, + uint32_t alignment); + +void +GfxHeapFreeMEM2(void *block); diff --git a/libraries/libwhb/src/gfx_shader.c b/libraries/libwhb/src/gfx_shader.c new file mode 100644 index 0000000..eb57f7d --- /dev/null +++ b/libraries/libwhb/src/gfx_shader.c @@ -0,0 +1,299 @@ +#include "gfx_heap.h" +#include +#include +#include +#include +#include +#include +#include +#include + +GX2PixelShader * +WHBGfxLoadGFDPixelShader(uint32_t index, + const void *file) +{ + uint32_t headerSize, programSize; + GX2PixelShader *shader = NULL; + void *program = NULL; + + if (index >= GFDGetPixelShaderCount(file)) { + WHBLogPrintf("%s: index %u >= %u GFDGetPixelShaderCount(file)", + __FUNCTION__, + index, + GFDGetPixelShaderCount(file)); + goto error; + } + + headerSize = GFDGetPixelShaderHeaderSize(index, file); + if (!headerSize) { + WHBLogPrintf("%s: headerSize == 0", __FUNCTION__); + goto error; + } + + programSize = GFDGetPixelShaderProgramSize(index, file); + if (!programSize) { + WHBLogPrintf("%s: programSize == 0", __FUNCTION__); + goto error; + } + + shader = (GX2PixelShader *)GfxHeapAllocMEM2(headerSize, 64); + if (!shader) { + WHBLogPrintf("%s: GfxHeapAllocMEM2(%u, 64) failed", __FUNCTION__, headerSize); + goto error; + } + + shader->gx2rBuffer.flags = GX2R_RESOURCE_BIND_SHADER_PROGRAM | GX2R_RESOURCE_USAGE_CPU_WRITE | GX2R_RESOURCE_USAGE_GPU_READ; + shader->gx2rBuffer.elemSize = programSize; + shader->gx2rBuffer.elemCount = 1; + shader->gx2rBuffer.buffer = NULL; + if (!GX2RCreateBuffer(&shader->gx2rBuffer)) { + WHBLogPrintf("%s: GX2RCreateBuffer failed with programSize = %u", __FUNCTION__, programSize); + goto error; + } + + program = GX2RLockBufferEx(&shader->gx2rBuffer, 0); + if (!program) { + WHBLogPrintf("%s: GX2RLockBufferEx failed", __FUNCTION__); + goto error; + } + + if (!GFDGetPixelShader(shader, program, index, file)) { + WHBLogPrintf("%s: GFDGetPixelShader failed", __FUNCTION__); + GX2RUnlockBufferEx(&shader->gx2rBuffer, GX2R_RESOURCE_DISABLE_CPU_INVALIDATE | GX2R_RESOURCE_DISABLE_GPU_INVALIDATE); + goto error; + } + + GX2RUnlockBufferEx(&shader->gx2rBuffer, 0); + return shader; + +error: + if (shader) { + if (shader->gx2rBuffer.buffer) { + GX2RDestroyBufferEx(&shader->gx2rBuffer, 0); + } + + GfxHeapFreeMEM2(shader); + } + + return NULL; +} + +BOOL +WHBGfxFreePixelShader(GX2PixelShader *shader) +{ + if (shader->gx2rBuffer.buffer) { + GX2RDestroyBufferEx(&shader->gx2rBuffer, 0); + } + + GfxHeapFreeMEM2(shader); +} + +GX2VertexShader * +WHBGfxLoadGFDVertexShader(uint32_t index, + const void *file) +{ + uint32_t headerSize, programSize; + GX2VertexShader *shader = NULL; + void *program = NULL; + + if (index >= GFDGetVertexShaderCount(file)) { + WHBLogPrintf("%s: index %u >= %u GFDGetVertexShaderCount(file)", + __FUNCTION__, + index, + GFDGetVertexShaderCount(file)); + goto error; + } + + headerSize = GFDGetVertexShaderHeaderSize(index, file); + if (!headerSize) { + WHBLogPrintf("%s: headerSize == 0", __FUNCTION__); + goto error; + } + + programSize = GFDGetVertexShaderProgramSize(index, file); + if (!programSize) { + WHBLogPrintf("%s: programSize == 0", __FUNCTION__); + goto error; + } + + shader = (GX2VertexShader *)GfxHeapAllocMEM2(headerSize, 64); + if (!shader) { + WHBLogPrintf("%s: GfxHeapAllocMEM2(%u, 64) failed", __FUNCTION__, headerSize); + goto error; + } + + shader->gx2rBuffer.flags = GX2R_RESOURCE_BIND_SHADER_PROGRAM | GX2R_RESOURCE_USAGE_CPU_WRITE | GX2R_RESOURCE_USAGE_GPU_READ; + shader->gx2rBuffer.elemSize = programSize; + shader->gx2rBuffer.elemCount = 1; + shader->gx2rBuffer.buffer = NULL; + if (!GX2RCreateBuffer(&shader->gx2rBuffer)) { + WHBLogPrintf("%s: GX2RCreateBuffer failed with programSize = %u", __FUNCTION__, programSize); + goto error; + } + + program = GX2RLockBufferEx(&shader->gx2rBuffer, 0); + if (!program) { + WHBLogPrintf("%s: GX2RLockBufferEx failed", __FUNCTION__); + goto error; + } + + if (!GFDGetVertexShader(shader, program, index, file)) { + WHBLogPrintf("%s: GFDGetVertexShader failed", __FUNCTION__); + GX2RUnlockBufferEx(&shader->gx2rBuffer, GX2R_RESOURCE_DISABLE_CPU_INVALIDATE | GX2R_RESOURCE_DISABLE_GPU_INVALIDATE); + goto error; + } + + GX2RUnlockBufferEx(&shader->gx2rBuffer, 0); + return shader; + +error: + if (shader) { + if (shader->gx2rBuffer.buffer) { + GX2RDestroyBufferEx(&shader->gx2rBuffer, 0); + } + + GfxHeapFreeMEM2(shader); + } + + return NULL; +} + +BOOL +WHBGfxFreeVertexShader(GX2VertexShader *shader) +{ + if (shader->gx2rBuffer.buffer) { + GX2RDestroyBufferEx(&shader->gx2rBuffer, 0); + } + + GfxHeapFreeMEM2(shader); +} + +BOOL +WHBGfxLoadGFDShaderGroup(WHBGfxShaderGroup *group, + uint32_t index, + const void *file) +{ + memset(group, 0, sizeof(WHBGfxShaderGroup)); + group->vertexShader = WHBGfxLoadGFDVertexShader(index, file); + group->pixelShader = WHBGfxLoadGFDPixelShader(index, file); + + if (!group->vertexShader || !group->pixelShader) { + // A shader group requires at least a vertex shader and a pixel shader. + WHBGfxFreeShaderGroup(group); + return FALSE; + } + + return TRUE; +} + +static uint32_t +GfxGetAttribFormatSel(GX2AttribFormat format) +{ + switch (format) { + case GX2_ATTRIB_FORMAT_UNORM_8: + case GX2_ATTRIB_FORMAT_UINT_8: + case GX2_ATTRIB_FORMAT_SNORM_8: + case GX2_ATTRIB_FORMAT_SINT_8: + case GX2_ATTRIB_FORMAT_FLOAT_32: + return LATTE_SQ_SEL_MASK(LATTE_SQ_SEL_X, LATTE_SQ_SEL_0, LATTE_SQ_SEL_0, LATTE_SQ_SEL_1); + case GX2_ATTRIB_FORMAT_UNORM_8_8: + case GX2_ATTRIB_FORMAT_UINT_8_8: + case GX2_ATTRIB_FORMAT_SNORM_8_8: + case GX2_ATTRIB_FORMAT_SINT_8_8: + case GX2_ATTRIB_FORMAT_FLOAT_32_32: + return LATTE_SQ_SEL_MASK(LATTE_SQ_SEL_X, LATTE_SQ_SEL_Y, LATTE_SQ_SEL_0, LATTE_SQ_SEL_1); + case GX2_ATTRIB_FORMAT_FLOAT_32_32_32: + return LATTE_SQ_SEL_MASK(LATTE_SQ_SEL_X, LATTE_SQ_SEL_Y, LATTE_SQ_SEL_Z, LATTE_SQ_SEL_1); + case GX2_ATTRIB_FORMAT_UNORM_8_8_8_8: + case GX2_ATTRIB_FORMAT_UINT_8_8_8_8: + case GX2_ATTRIB_FORMAT_SNORM_8_8_8_8: + case GX2_ATTRIB_FORMAT_SINT_8_8_8_8: + case GX2_ATTRIB_FORMAT_FLOAT_32_32_32_32: + return LATTE_SQ_SEL_MASK(LATTE_SQ_SEL_X, LATTE_SQ_SEL_Y, LATTE_SQ_SEL_Z, LATTE_SQ_SEL_W); + break; + default: + return LATTE_SQ_SEL_MASK(LATTE_SQ_SEL_0, LATTE_SQ_SEL_0, LATTE_SQ_SEL_0, LATTE_SQ_SEL_1); + } +} + +static int32_t +GfxGetVertexAttribVarLocation(const GX2VertexShader* shader, + const char *name) +{ + uint32_t i; + + for (i = 0; i < shader->attribVarCount; ++i) { + if (strcmp(shader->attribVars[i].name, name) == 0) { + return shader->attribVars[i].location; + } + } + + return -1; +} + +BOOL +WHBGfxInitShaderAttribute(WHBGfxShaderGroup *group, + const char *name, + uint32_t buffer, + uint32_t offset, + GX2AttribFormat format) +{ + GX2AttribStream *attrib; + int32_t location; + + location = GfxGetVertexAttribVarLocation(group->vertexShader, name); + if (location == -1) { + return FALSE; + } + + attrib = &group->attributes[group->numAttributes++]; + attrib->location = location; + attrib->buffer = buffer; + attrib->offset = offset; + attrib->format = format; + attrib->type = GX2_ATTRIB_INDEX_PER_VERTEX; + attrib->aluDivisor = 0; + attrib->mask = GfxGetAttribFormatSel(format); + attrib->endianSwap = GX2_ENDIAN_SWAP_DEFAULT; + return TRUE; +} + +BOOL +WHBGfxInitFetchShader(WHBGfxShaderGroup *group) +{ + uint32_t size = GX2CalcFetchShaderSizeEx(group->numAttributes, + GX2_FETCH_SHADER_TESSELLATION_NONE, + GX2_TESSELLATION_MODE_DISCRETE); + group->fetchShaderProgram = GfxHeapAllocMEM2(size, GX2_SHADER_PROGRAM_ALIGNMENT); + + GX2InitFetchShaderEx(&group->fetchShader, + group->fetchShaderProgram, + group->numAttributes, + group->attributes, + GX2_FETCH_SHADER_TESSELLATION_NONE, + GX2_TESSELLATION_MODE_DISCRETE); + + GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, group->fetchShaderProgram, size); + return TRUE; +} + +BOOL +WHBGfxFreeShaderGroup(WHBGfxShaderGroup *group) +{ + if (group->fetchShaderProgram) { + GfxHeapFreeMEM2(group->fetchShaderProgram); + group->fetchShaderProgram = NULL; + } + + if (group->pixelShader) { + WHBGfxFreePixelShader(group->pixelShader); + group->pixelShader = NULL; + } + + if (group->vertexShader) { + WHBGfxFreeVertexShader(group->vertexShader); + group->vertexShader = NULL; + } + + return TRUE; +} diff --git a/libraries/libwhb/src/gfx_texture.c b/libraries/libwhb/src/gfx_texture.c new file mode 100644 index 0000000..6019a91 --- /dev/null +++ b/libraries/libwhb/src/gfx_texture.c @@ -0,0 +1,55 @@ +#include "gfx_heap.h" +#include +#include +#include +#include +#include + +GX2Texture * +WHBGfxLoadGFDTexture(uint32_t index, + const void *file) +{ + uint32_t headerSize, imageSize; + GX2Texture *texture = NULL; + void *image = NULL; + + if (index >= GFDGetTextureCount(file)) { + WHBLogPrintf("%s: invalid GFD texture index %u", __FUNCTION__, index); + goto error; + } + + headerSize = GFDGetTextureHeaderSize(index, file); + imageSize = GFDGetTextureImageSize(index, file); + + if (!headerSize || !imageSize) { + goto error; + } + + texture = (GX2Texture *)GfxHeapAllocMEM2(headerSize, 64); + if (!texture) { + WHBLogPrintf("%s: GfxHeapAllocMEM2(0x%X, 64) failed", __FUNCTION__, headerSize); + goto error; + } + + if (!GFDGetGX2RTexture(texture, index, file)) { + goto error; + } + + return texture; + +error: + if (texture) { + GX2RDestroySurfaceEx(&texture->surface, 0); + GfxHeapFreeMEM2(texture); + } + + return NULL; +} + +BOOL +WHBGfxFreeTexture(GX2Texture *texture) +{ + GX2RDestroySurfaceEx(&texture->surface, 0); + GfxHeapFreeMEM2(texture); + return TRUE; +} diff --git a/libraries/libwhb/src/libmanager.c b/libraries/libwhb/src/libmanager.c new file mode 100644 index 0000000..3701b00 --- /dev/null +++ b/libraries/libwhb/src/libmanager.c @@ -0,0 +1,33 @@ +#include + +/** + * Socket Library (nsysnet.rpl) + */ + +static BOOL +isSocketInitialized = FALSE; + +static unsigned int +numberOfSocketClients = 0; + +void +WHBInitializeSocketLibrary() +{ + if(!isSocketInitialized) { + isSocketInitialized = TRUE; + socket_lib_init(); + } + numberOfSocketClients++; +} + +void +WHBDeinitializeSocketLibrary() +{ + if(numberOfSocketClients > 0) { + numberOfSocketClients--; + } + if(isSocketInitialized && numberOfSocketClients == 0) { + isSocketInitialized = FALSE; + socket_lib_finish(); + } +} diff --git a/libraries/libwhb/src/log.c b/libraries/libwhb/src/log.c new file mode 100644 index 0000000..eccd15e --- /dev/null +++ b/libraries/libwhb/src/log.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include + +#define MAX_HANDLERS 16 +#define PRINTF_BUFFER_LENGTH 2048 + +static LogHandlerFn +sHandlers[MAX_HANDLERS] = { 0 }; + +static inline void +dispatchMessage(const char * str) +{ + int i; + for (i = 0; i < MAX_HANDLERS; ++i) { + if (sHandlers[i]) { + sHandlers[i](str); + } + } +} + +BOOL +WHBAddLogHandler(LogHandlerFn fn) +{ + int i; + + for (i = 0; i < MAX_HANDLERS; ++i) { + if (!sHandlers[i]) { + sHandlers[i] = fn; + return TRUE; + } + } + + return FALSE; +} + +BOOL +WHBRemoveLogHandler(LogHandlerFn fn) +{ + int i; + + for(i = 0; i < MAX_HANDLERS; ++i) { + if(sHandlers[i] == fn) { + sHandlers[i] = NULL; + return TRUE; + } + } + + return FALSE; +} + +BOOL +WHBLogWrite(const char *str) +{ + dispatchMessage(str); + return TRUE; +} + +BOOL +WHBLogPrint(const char *str) +{ + char *buf = MEMAllocFromDefaultHeapEx(PRINTF_BUFFER_LENGTH, 4); + if(!buf) { + return FALSE; + } + + snprintf(buf, PRINTF_BUFFER_LENGTH, "%s\n", str); + dispatchMessage(buf); + + MEMFreeToDefaultHeap(buf); + return TRUE; +} + +BOOL +WHBLogWritef(const char *fmt, ...) +{ + char *buf = MEMAllocFromDefaultHeapEx(PRINTF_BUFFER_LENGTH, 4); + va_list va; + + if (!buf) { + return FALSE; + } + + va_start(va, fmt); + vsnprintf(buf, PRINTF_BUFFER_LENGTH, fmt, va); + dispatchMessage(buf); + + MEMFreeToDefaultHeap(buf); + va_end(va); + return TRUE; +} + +BOOL +WHBLogPrintf(const char *fmt, ...) +{ + char *buf1 = MEMAllocFromDefaultHeapEx(PRINTF_BUFFER_LENGTH, 4); + char *buf2 = MEMAllocFromDefaultHeapEx(PRINTF_BUFFER_LENGTH, 4); + va_list va; + + if (!buf1) { + return FALSE; + } + + if(!buf2) { + MEMFreeToDefaultHeap(buf1); + return FALSE; + } + + va_start(va, fmt); + + vsnprintf(buf1, PRINTF_BUFFER_LENGTH, fmt, va); + snprintf(buf2, PRINTF_BUFFER_LENGTH, "%s\n", buf1); + dispatchMessage(buf2); + + MEMFreeToDefaultHeap(buf1); + MEMFreeToDefaultHeap(buf2); + va_end(va); + return TRUE; +} diff --git a/libraries/libwhb/src/log_cafe.c b/libraries/libwhb/src/log_cafe.c new file mode 100644 index 0000000..34d067e --- /dev/null +++ b/libraries/libwhb/src/log_cafe.c @@ -0,0 +1,29 @@ +#include +#include + +#include + +static void +cafeLogHandler(const char * msg) +{ + int length = strlen(msg); + + if(msg[length-1] != '\n') { + OSReport("%s\n", msg); + } + else { + OSReport(msg); + } +} + +BOOL +WHBLogCafeInit() +{ + return WHBAddLogHandler(cafeLogHandler); +} + +BOOL +WHBLogCafeDeinit() +{ + return WHBRemoveLogHandler(cafeLogHandler); +} diff --git a/libraries/libwhb/src/log_udp.c b/libraries/libwhb/src/log_udp.c new file mode 100644 index 0000000..2e5cd5e --- /dev/null +++ b/libraries/libwhb/src/log_udp.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include + +static int +sSocket = -1; + +static struct sockaddr_in +sSendAddr; + +#define SERVER_PORT 4405 + +static void +udpLogHandler(const char *msg) +{ + sendto(sSocket, + msg, + strlen(msg), + 0, + (struct sockaddr *)&sSendAddr, + sizeof(struct sockaddr_in)); +} + +BOOL +WHBLogUdpInit() +{ + int broadcastEnable = 1; + WHBInitializeSocketLibrary(); + + sSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sSocket < 0) { + return FALSE; + } + + setsockopt(sSocket, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)); + + memset(&sSendAddr, 0, sizeof(struct sockaddr_in)); + sSendAddr.sin_family = AF_INET; + sSendAddr.sin_port = htons(SERVER_PORT); + sSendAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST); + + return WHBAddLogHandler(udpLogHandler); +} + +BOOL +WHBLogUdpDeinit() +{ + if(shutdown(sSocket, SHUT_WR) != 0) { + return FALSE; + } + + WHBDeinitializeSocketLibrary(); + return WHBRemoveLogHandler(udpLogHandler); +} diff --git a/libraries/libwhb/src/proc.c b/libraries/libwhb/src/proc.c new file mode 100644 index 0000000..25ada6b --- /dev/null +++ b/libraries/libwhb/src/proc.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HBL_TITLE_ID (0x0005000013374842) +#define MII_MAKER_JPN_TITLE_ID (0x000500101004A000) +#define MII_MAKER_USA_TITLE_ID (0x000500101004A100) +#define MII_MAKER_EUR_TITLE_ID (0x000500101004A200) + +static uint32_t +sMainCore; + +static BOOL +sRunning = FALSE; + +static BOOL +sFromHBL = FALSE; + +static ProcUICallback +sAcquireCallback = NULL; + +static uint32_t +procSaveCallback(void *context) +{ + OSSavesDone_ReadyToRelease(); + return 0; +} + + +static uint32_t +procHomeButtonDenied(void *context) +{ + if (sFromHBL) { + WHBProcStopRunning(); + } + + return 0; +} + +void +WHBProcInit() +{ + uint64_t titleID = OSGetTitleID(); + + // Homebrew Launcher does not like the standard ProcUI application loop, + // so instead we disable the home buttom menu and use the home button + // to trigger an exit. + if (titleID == HBL_TITLE_ID || + titleID == MII_MAKER_JPN_TITLE_ID || + titleID == MII_MAKER_USA_TITLE_ID || + titleID == MII_MAKER_EUR_TITLE_ID) { + // Important: OSEnableHomeButtonMenu must come before ProcUIInitEx. + OSEnableHomeButtonMenu(FALSE); + sFromHBL = TRUE; + } + + sMainCore = OSGetCoreId(); + sRunning = TRUE; + ProcUIInitEx(&procSaveCallback, NULL); + ProcUIRegisterCallback(PROCUI_CALLBACK_HOME_BUTTON_DENIED, &procHomeButtonDenied, NULL, 100); +} + +void +WHBProcShutdown() +{ + sRunning = FALSE; + + // If we're running from Homebrew Launcher we must do a SYSRelaunchTitle to + // correctly return to HBL. + if (sFromHBL) { + SYSRelaunchTitle(0, NULL); + } +} + +void +WHBProcStopRunning() +{ + sRunning = FALSE; +} + +BOOL +WHBProcIsRunning() +{ + ProcUIStatus status; + + if (sMainCore != OSGetCoreId()) { + ProcUISubProcessMessages(TRUE); + return sRunning; + } + + status = ProcUIProcessMessages(TRUE); + if (status == PROCUI_STATUS_EXITING) { + WHBProcStopRunning(); + } else if (status == PROCUI_STATUS_RELEASE_FOREGROUND) { + ProcUIDrawDoneRelease(); + } + + if (!sRunning) { + ProcUIShutdown(); + } + + return sRunning; +} diff --git a/libraries/libwhb/src/sdcard.c b/libraries/libwhb/src/sdcard.c new file mode 100644 index 0000000..83dfe52 --- /dev/null +++ b/libraries/libwhb/src/sdcard.c @@ -0,0 +1,80 @@ +#include +#include +#include + +static BOOL +sMounted = FALSE; + +static char +sMountPath[128] = { 0 }; + +static FSClient +sClient; + +BOOL +WHBMountSdCard() +{ + FSCmdBlock cmd; + FSMountSource mountSource; + FSStatus result; + + if (sMounted) { + return TRUE; + } + + FSInit(); + + result = FSAddClient(&sClient, -1); + if (result != FS_STATUS_OK) { + WHBLogPrintf("%s: FSAddClient error %d", __FUNCTION__, result); + return FALSE; + } + + FSInitCmdBlock(&cmd); + result = FSGetMountSource(&sClient, &cmd, FS_MOUNT_SOURCE_SD, &mountSource, -1); + if (result < 0) { + WHBLogPrintf("%s: FSGetMountSource error %d", __FUNCTION__, result); + goto fail; + } + + result = FSMount(&sClient, &cmd, &mountSource, sMountPath, sizeof(sMountPath), -1); + if (result < 0) { + WHBLogPrintf("%s: FSMount error %d", __FUNCTION__, result); + goto fail; + } + + sMounted = TRUE; + return TRUE; + +fail: + FSDelClient(&sClient, -1); + return FALSE; +} + +char * +WHBGetSdCardMountPath() +{ + return sMountPath; +} + +BOOL +WHBUnmountSdCard() +{ + FSCmdBlock cmd; + FSStatus result; + + if (!sMounted) { + return TRUE; + } + + FSInitCmdBlock(&cmd); + + result = FSUnmount(&sClient, &cmd, sMountPath, -1); + if (result < 0) { + WHBLogPrintf("%s: FSUnmount error %d", __FUNCTION__, result); + return FALSE; + } + + sMounted = FALSE; + return TRUE; +}