Add libdefaultheap, libgfd, libwhb.

This commit is contained in:
James Benton 2018-05-23 11:10:10 +01:00
parent 161331c4f4
commit 7e788f47af
34 changed files with 3700 additions and 0 deletions

View File

@ -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=<INSTALL_DIR>
BUILD_ALWAYS 1)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/"
DESTINATION "${CMAKE_INSTALL_PREFIX}/include"
FILES_MATCHING PATTERN "*.h*")

6
libraries/CMakeLists.txt Normal file
View File

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.2)
project(libraries C)
add_subdirectory(libdefaultheap)
add_subdirectory(libgfd)
add_subdirectory(libwhb)

View File

@ -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*")

View File

@ -0,0 +1,20 @@
#pragma once
#include <wut.h>
#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

View File

@ -0,0 +1,75 @@
#include "defaultheap.h"
#include <coreinit/dynload.h>
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);
}

View File

@ -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*")

View File

@ -0,0 +1,207 @@
#pragma once
#include <wut.h>
#include <gx2/shaders.h>
#include <gx2/texture.h>
#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

880
libraries/libgfd/src/gfd.c Normal file
View File

@ -0,0 +1,880 @@
#include "gfd.h"
#include <gx2/temp.h>
#include <gx2r/surface.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
// #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;
}

View File

@ -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*")

View File

@ -0,0 +1,20 @@
#pragma once
#include <wut.h>
/**
* \defgroup whb_align Align
* \ingroup whb
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
#define WHBAlignUp(val, align) ((val + align - 1) & ~(align - 1))
#ifdef __cplusplus
}
#endif
/** @} */

View File

@ -0,0 +1,29 @@
#pragma once
#include <wut.h>
/**
* \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
/** @} */

View File

@ -0,0 +1,21 @@
#pragma once
#include <wut.h>
/**
* \defgroup whb_crash Crash Handler
* \ingroup whb
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
BOOL
WHBInitCrashHandler();
#ifdef __cplusplus
}
#endif
/** @} */

View File

@ -0,0 +1,47 @@
#pragma once
#include <wut.h>
/**
* \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
/** @} */

View File

@ -0,0 +1,95 @@
#pragma once
#include <wut.h>
#include <gx2/shaders.h>
#include <gx2/texture.h>
/**
* \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
/** @} */

View File

@ -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
/** @} */

View File

@ -0,0 +1,38 @@
#pragma once
#include <wut.h>
/**
* \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
/** @} */

View File

@ -0,0 +1,24 @@
#pragma once
#include <wut.h>
/**
* \defgroup whb_log_cafe Cafe OS System Log Output
* \ingroup whb
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
BOOL
WHBLogCafeInit();
BOOL
WHBLogCafeDeinit();
#ifdef __cplusplus
}
#endif
/** @} */

View File

@ -0,0 +1,24 @@
#pragma once
#include <wut.h>
/**
* \defgroup whb_log_udp UDP Log Output
* \ingroup whb
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
BOOL
WHBLogUdpInit();
BOOL
WHBLogUdpDeinit();
#ifdef __cplusplus
}
#endif
/** @} */

View File

@ -0,0 +1,30 @@
#pragma once
#include <wut.h>
/**
* \defgroup whb_proc ProcUI Utilities
* \ingroup whb
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
void
WHBProcInit();
void
WHBProcShutdown();
void
WHBProcStopRunning();
BOOL
WHBProcIsRunning();
#ifdef __cplusplus
}
#endif
/** @} */

View File

@ -0,0 +1,27 @@
#pragma once
#include <wut.h>
/**
* \defgroup whb_sdcard SDCard Access
* \ingroup whb
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
BOOL
WHBMountSdCard();
char *
WHBGetSdCardMountPath();
BOOL
WHBUnmountSdCard();
#ifdef __cplusplus
}
#endif
/** @} */

View File

@ -0,0 +1,138 @@
#include <coreinit/baseheap.h>
#include <coreinit/expandedheap.h>
#include <nsysnet/socket.h>
#include <whb/commandserver.h>
#include <whb/libmanager.h>
#include <whb/log.h>
#include <string.h>
#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;
}

View File

@ -0,0 +1,258 @@
#include <whb/crash.h>
#include <coreinit/core.h>
#include <coreinit/debug.h>
#include <coreinit/exception.h>
#include <coreinit/internal.h>
#include <coreinit/systeminfo.h>
#include <coreinit/thread.h>
#include <coreinit/time.h>
#include <stdarg.h>
#include <stdio.h>
#include <whb/log.h>
#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;
}

157
libraries/libwhb/src/file.c Normal file
View File

@ -0,0 +1,157 @@
#include <coreinit/filesystem.h>
#include <defaultheap.h>
#include <string.h>
#include <whb/file.h>
#include <whb/log.h>
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);
}

520
libraries/libwhb/src/gfx.c Normal file
View File

@ -0,0 +1,520 @@
#include "gfx_heap.h"
#include <gx2/clear.h>
#include <gx2/context.h>
#include <gx2/display.h>
#include <gx2/event.h>
#include <gx2/mem.h>
#include <gx2/registers.h>
#include <gx2/shaders.h>
#include <gx2/state.h>
#include <gx2/surface.h>
#include <gx2/swap.h>
#include <gx2/temp.h>
#include <gx2r/mem.h>
#include <proc_ui/procui.h>
#include <string.h>
#include <whb/gfx.h>
#include <whb/log.h>
#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);
}

View File

@ -0,0 +1,176 @@
#include "gfx_heap.h"
#include <coreinit/baseheap.h>
#include <coreinit/expandedheap.h>
#include <coreinit/frameheap.h>
#include <defaultheap.h>
#include <whb/log.h>
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);
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <wut.h>
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);

View File

@ -0,0 +1,299 @@
#include "gfx_heap.h"
#include <gfd.h>
#include <gx2r/buffer.h>
#include <gx2/mem.h>
#include <gx2/shaders.h>
#include <latte/latte_enum_sq.h>
#include <string.h>
#include <whb/gfx.h>
#include <whb/log.h>
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;
}

View File

@ -0,0 +1,55 @@
#include "gfx_heap.h"
#include <gfd.h>
#include <gx2r/surface.h>
#include <gx2/texture.h>
#include <whb/log.h>
#include <whb/gfx.h>
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;
}

View File

@ -0,0 +1,33 @@
#include <nsysnet/socket.h>
/**
* 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();
}
}

121
libraries/libwhb/src/log.c Normal file
View File

@ -0,0 +1,121 @@
#include <defaultheap.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <whb/log.h>
#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;
}

View File

@ -0,0 +1,29 @@
#include <coreinit/debug.h>
#include <whb/log.h>
#include <string.h>
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);
}

View File

@ -0,0 +1,58 @@
#include <coreinit/mutex.h>
#include <defaultheap.h>
#include <nsysnet/socket.h>
#include <string.h>
#include <whb/log.h>
#include <whb/log_udp.h>
#include <whb/libmanager.h>
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);
}

111
libraries/libwhb/src/proc.c Normal file
View File

@ -0,0 +1,111 @@
#include <coreinit/core.h>
#include <coreinit/exit.h>
#include <coreinit/foreground.h>
#include <coreinit/messagequeue.h>
#include <coreinit/systeminfo.h>
#include <coreinit/title.h>
#include <gx2/event.h>
#include <proc_ui/procui.h>
#include <sysapp/launch.h>
#include <whb/log.h>
#include <whb/proc.h>
#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;
}

View File

@ -0,0 +1,80 @@
#include <coreinit/filesystem.h>
#include <whb/sdcard.h>
#include <whb/log.h>
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;
}