mirror of
https://github.com/wiiu-env/wut.git
synced 2025-01-06 13:38:14 +01:00
Add libdefaultheap, libgfd, libwhb.
This commit is contained in:
parent
161331c4f4
commit
7e788f47af
@ -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
6
libraries/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libraries C)
|
||||
|
||||
add_subdirectory(libdefaultheap)
|
||||
add_subdirectory(libgfd)
|
||||
add_subdirectory(libwhb)
|
16
libraries/libdefaultheap/CMakeLists.txt
Normal file
16
libraries/libdefaultheap/CMakeLists.txt
Normal 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*")
|
20
libraries/libdefaultheap/include/defaultheap.h
Normal file
20
libraries/libdefaultheap/include/defaultheap.h
Normal 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
|
75
libraries/libdefaultheap/src/defaultheap.c
Normal file
75
libraries/libdefaultheap/src/defaultheap.c
Normal 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);
|
||||
}
|
16
libraries/libgfd/CMakeLists.txt
Normal file
16
libraries/libgfd/CMakeLists.txt
Normal 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*")
|
207
libraries/libgfd/include/gfd.h
Normal file
207
libraries/libgfd/include/gfd.h
Normal 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
880
libraries/libgfd/src/gfd.c
Normal 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;
|
||||
}
|
19
libraries/libwhb/CMakeLists.txt
Normal file
19
libraries/libwhb/CMakeLists.txt
Normal 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*")
|
||||
|
20
libraries/libwhb/include/whb/align.h
Normal file
20
libraries/libwhb/include/whb/align.h
Normal 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
|
||||
|
||||
/** @} */
|
29
libraries/libwhb/include/whb/commandserver.h
Normal file
29
libraries/libwhb/include/whb/commandserver.h
Normal 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
|
||||
|
||||
/** @} */
|
21
libraries/libwhb/include/whb/crash.h
Normal file
21
libraries/libwhb/include/whb/crash.h
Normal 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
|
||||
|
||||
/** @} */
|
47
libraries/libwhb/include/whb/file.h
Normal file
47
libraries/libwhb/include/whb/file.h
Normal 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
|
||||
|
||||
/** @} */
|
95
libraries/libwhb/include/whb/gfx.h
Normal file
95
libraries/libwhb/include/whb/gfx.h
Normal 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
|
||||
|
||||
/** @} */
|
27
libraries/libwhb/include/whb/libmanager.h
Normal file
27
libraries/libwhb/include/whb/libmanager.h
Normal 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
|
||||
|
||||
/** @} */
|
38
libraries/libwhb/include/whb/log.h
Normal file
38
libraries/libwhb/include/whb/log.h
Normal 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
|
||||
|
||||
/** @} */
|
24
libraries/libwhb/include/whb/log_cafe.h
Normal file
24
libraries/libwhb/include/whb/log_cafe.h
Normal 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
|
||||
|
||||
/** @} */
|
24
libraries/libwhb/include/whb/log_udp.h
Normal file
24
libraries/libwhb/include/whb/log_udp.h
Normal 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
|
||||
|
||||
/** @} */
|
30
libraries/libwhb/include/whb/proc.h
Normal file
30
libraries/libwhb/include/whb/proc.h
Normal 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
|
||||
|
||||
/** @} */
|
27
libraries/libwhb/include/whb/sdcard.h
Normal file
27
libraries/libwhb/include/whb/sdcard.h
Normal 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
|
||||
|
||||
/** @} */
|
138
libraries/libwhb/src/commandserver.c
Normal file
138
libraries/libwhb/src/commandserver.c
Normal 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;
|
||||
}
|
258
libraries/libwhb/src/crash.c
Normal file
258
libraries/libwhb/src/crash.c
Normal 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
157
libraries/libwhb/src/file.c
Normal 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
520
libraries/libwhb/src/gfx.c
Normal 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);
|
||||
}
|
176
libraries/libwhb/src/gfx_heap.c
Normal file
176
libraries/libwhb/src/gfx_heap.c
Normal 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);
|
||||
}
|
35
libraries/libwhb/src/gfx_heap.h
Normal file
35
libraries/libwhb/src/gfx_heap.h
Normal 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);
|
299
libraries/libwhb/src/gfx_shader.c
Normal file
299
libraries/libwhb/src/gfx_shader.c
Normal 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;
|
||||
}
|
55
libraries/libwhb/src/gfx_texture.c
Normal file
55
libraries/libwhb/src/gfx_texture.c
Normal 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;
|
||||
}
|
33
libraries/libwhb/src/libmanager.c
Normal file
33
libraries/libwhb/src/libmanager.c
Normal 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
121
libraries/libwhb/src/log.c
Normal 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;
|
||||
}
|
29
libraries/libwhb/src/log_cafe.c
Normal file
29
libraries/libwhb/src/log_cafe.c
Normal 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);
|
||||
}
|
58
libraries/libwhb/src/log_udp.c
Normal file
58
libraries/libwhb/src/log_udp.c
Normal 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
111
libraries/libwhb/src/proc.c
Normal 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;
|
||||
}
|
80
libraries/libwhb/src/sdcard.c
Normal file
80
libraries/libwhb/src/sdcard.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user