mirror of
https://github.com/wiiu-env/AutobootModule.git
synced 2024-11-01 01:25:05 +01:00
Show splash screen when quick starting into a game
This commit is contained in:
parent
d58ea5aad3
commit
8f52f74c13
2
Makefile
2
Makefile
@ -21,7 +21,7 @@ WUMS_ROOT := $(DEVKITPRO)/wums
|
|||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
TARGET := 99_autoboot
|
TARGET := 99_autoboot
|
||||||
BUILD := build
|
BUILD := build
|
||||||
SOURCES := source
|
SOURCES := source source/utils
|
||||||
DATA := data
|
DATA := data
|
||||||
INCLUDES := source include
|
INCLUDES := source include
|
||||||
|
|
||||||
|
@ -51,4 +51,5 @@ docker run -it --rm -v ${PWD}:/project autobootmodule-builder make clean
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
- GaryOderNichts
|
- GaryOderNichts
|
||||||
- Maschell
|
- Maschell
|
||||||
|
- Crementif
|
@ -2,7 +2,9 @@
|
|||||||
#include "BootUtils.h"
|
#include "BootUtils.h"
|
||||||
#include "MenuUtils.h"
|
#include "MenuUtils.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
#include "utils/SplashScreenDrawer.h"
|
||||||
|
#include "utils/SplashSoundPlayer.h"
|
||||||
|
#include "utils/gfx.h"
|
||||||
#include <coreinit/exit.h>
|
#include <coreinit/exit.h>
|
||||||
#include <coreinit/foreground.h>
|
#include <coreinit/foreground.h>
|
||||||
#include <coreinit/memdefaultheap.h>
|
#include <coreinit/memdefaultheap.h>
|
||||||
@ -351,9 +353,25 @@ bool launchQuickStartTitle() {
|
|||||||
MCP_Close(handle);
|
MCP_Close(handle);
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
DEBUG_FUNCTION_LINE("Launch %016llX", titleIdToLaunch);
|
DEBUG_FUNCTION_LINE("Launch %016llX", titleIdToLaunch);
|
||||||
|
char metaDir[256] = {};
|
||||||
|
auto res = ACPGetTitleMetaDir(titleIdToLaunch, metaDir, sizeof(metaDir) - 1);
|
||||||
|
if (res == ACP_RESULT_SUCCESS) {
|
||||||
|
GfxInit();
|
||||||
|
{
|
||||||
|
SplashScreenDrawer splashScreenDrawer(metaDir);
|
||||||
|
splashScreenDrawer.Draw();
|
||||||
|
SplashSoundPlayer splashSound(metaDir);
|
||||||
|
splashSound.Play();
|
||||||
|
}
|
||||||
|
GfxShutdown();
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("Failed to find assets");
|
||||||
|
}
|
||||||
ACPAssignTitlePatch(&titleInfo);
|
ACPAssignTitlePatch(&titleInfo);
|
||||||
_SYSLaunchTitleWithStdArgsInNoSplash(titleIdToLaunch, nullptr);
|
_SYSLaunchTitleByPathFromLauncher(titleInfo.path, strlen(titleInfo.path));
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("Failed to get title info");
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Launch Wii U Menu!");
|
DEBUG_FUNCTION_LINE("Launch Wii U Menu!");
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include <coreinit/filesystem_fsa.h>
|
#include <coreinit/filesystem_fsa.h>
|
||||||
#include <coreinit/mcp.h>
|
#include <coreinit/mcp.h>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
#include <mocha/mocha.h>
|
#include <mocha/mocha.h>
|
||||||
|
#include <string_view>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <whb/log.h>
|
||||||
|
|
||||||
bool GetTitleIdOfDisc(uint64_t *titleId, bool *discPresent) {
|
bool GetTitleIdOfDisc(uint64_t *titleId, bool *discPresent) {
|
||||||
if (discPresent) {
|
if (discPresent) {
|
||||||
@ -76,4 +82,27 @@ bool RestoreMLCUpdateDirectory() {
|
|||||||
DEBUG_FUNCTION_LINE_ERR("Failed to create FSA Client");
|
DEBUG_FUNCTION_LINE_ERR("Failed to create FSA Client");
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LoadFileIntoBuffer(std::string_view path, std::vector<uint8_t> &buffer) {
|
||||||
|
struct stat st {};
|
||||||
|
if (stat(path.data(), &st) < 0 || !S_ISREG(st.st_mode)) {
|
||||||
|
DEBUG_FUNCTION_LINE_INFO("\"%s\" doesn't exists", path.data());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *f = fopen(path.data(), "rb");
|
||||||
|
if (!f) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
buffer.resize(st.st_size);
|
||||||
|
|
||||||
|
if (fread(buffer.data(), 1, st.st_size, f) != st.st_size) {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("Failed load %s", path.data());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
return true;
|
||||||
}
|
}
|
@ -3,6 +3,8 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
template<class T, class... Args>
|
template<class T, class... Args>
|
||||||
std::unique_ptr<T> make_unique_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
|
std::unique_ptr<T> make_unique_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
|
||||||
@ -32,4 +34,6 @@ bool GetTitleIdOfDisc(uint64_t *titleId, bool *discPresent);
|
|||||||
|
|
||||||
bool DeleteMLCUpdateDirectory();
|
bool DeleteMLCUpdateDirectory();
|
||||||
|
|
||||||
bool RestoreMLCUpdateDirectory();
|
bool RestoreMLCUpdateDirectory();
|
||||||
|
|
||||||
|
bool LoadFileIntoBuffer(std::string_view path, std::vector<uint8_t> &buffer);
|
446
source/utils/ShaderSerializer.cpp
Normal file
446
source/utils/ShaderSerializer.cpp
Normal file
@ -0,0 +1,446 @@
|
|||||||
|
#include "ShaderSerializer.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <gx2/sampler.h>
|
||||||
|
#include <gx2/shaders.h>
|
||||||
|
#include <gx2r/buffer.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Based on https://github.com/Crementif/UntitledSandGame/blob/e752613ba54ac8f6767a8b37e9ac3f68ca180ad7/source/common/shader_serializer.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
static void writeAt(std::vector<uint8_t> &fh, size_t pos, Type value) {
|
||||||
|
*reinterpret_cast<Type *>(fh.data() + pos) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
static void write(std::vector<uint8_t> &fh, Type value) {
|
||||||
|
auto pos = fh.size();
|
||||||
|
fh.resize(pos + sizeof(Type));
|
||||||
|
*reinterpret_cast<Type *>(fh.data() + pos) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeString(std::vector<uint8_t> &fh, const char *str) {
|
||||||
|
auto pos = fh.size();
|
||||||
|
auto len = strlen(str) + 1;
|
||||||
|
fh.resize((static_cast<size_t>(pos + len) + (4 - 1)) & ~(4 - 1));
|
||||||
|
memcpy(fh.data() + pos, str, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeGX2RBuffer(std::vector<uint8_t> &fh, GX2RBuffer *buffer) {
|
||||||
|
write(fh, buffer->flags);
|
||||||
|
write(fh, buffer->elemSize);
|
||||||
|
write(fh, buffer->elemCount);
|
||||||
|
auto pos = fh.size();
|
||||||
|
fh.resize(pos + buffer->elemSize * buffer->elemCount);
|
||||||
|
memcpy(fh.data() + pos, buffer->buffer, buffer->elemSize * buffer->elemCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> SerializeVertexShader(GX2VertexShader *vertexShader) {
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
// write regs
|
||||||
|
write(data, vertexShader->regs.sq_pgm_resources_vs);
|
||||||
|
write(data, vertexShader->regs.vgt_primitiveid_en);
|
||||||
|
write(data, vertexShader->regs.spi_vs_out_config);
|
||||||
|
write(data, vertexShader->regs.num_spi_vs_out_id);
|
||||||
|
for (uint32_t spi_vs : vertexShader->regs.spi_vs_out_id) {
|
||||||
|
write(data, spi_vs);
|
||||||
|
}
|
||||||
|
write(data, vertexShader->regs.pa_cl_vs_out_cntl);
|
||||||
|
write(data, vertexShader->regs.sq_vtx_semantic_clear);
|
||||||
|
write(data, vertexShader->regs.num_sq_vtx_semantic);
|
||||||
|
for (uint32_t sq_vtx : vertexShader->regs.sq_vtx_semantic) {
|
||||||
|
write(data, sq_vtx);
|
||||||
|
}
|
||||||
|
write(data, vertexShader->regs.vgt_strmout_buffer_en);
|
||||||
|
write(data, vertexShader->regs.vgt_vertex_reuse_block_cntl);
|
||||||
|
write(data, vertexShader->regs.vgt_hos_reuse_depth);
|
||||||
|
|
||||||
|
// write program
|
||||||
|
write(data, vertexShader->size);
|
||||||
|
for (uint32_t i = 0; i < vertexShader->size; i++) {
|
||||||
|
write(data, ((uint8_t *) vertexShader->program)[i]);
|
||||||
|
}
|
||||||
|
write(data, vertexShader->mode);
|
||||||
|
|
||||||
|
// write uniform blocks
|
||||||
|
write(data, vertexShader->uniformBlockCount);
|
||||||
|
for (uint32_t i = 0; i < vertexShader->uniformBlockCount; i++) {
|
||||||
|
writeString(data, vertexShader->uniformBlocks[i].name);
|
||||||
|
write(data, vertexShader->uniformBlocks[i].offset);
|
||||||
|
write(data, vertexShader->uniformBlocks[i].size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write uniform vars
|
||||||
|
write(data, vertexShader->uniformVarCount);
|
||||||
|
for (uint32_t i = 0; i < vertexShader->uniformVarCount; i++) {
|
||||||
|
writeString(data, vertexShader->uniformVars[i].name);
|
||||||
|
write(data, vertexShader->uniformVars[i].type);
|
||||||
|
write(data, vertexShader->uniformVars[i].count);
|
||||||
|
write(data, vertexShader->uniformVars[i].offset);
|
||||||
|
write(data, vertexShader->uniformVars[i].block);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write initial values
|
||||||
|
write(data, vertexShader->initialValueCount);
|
||||||
|
for (uint32_t i = 0; i < vertexShader->initialValueCount; i++) {
|
||||||
|
write(data, vertexShader->initialValues[i].value[0]);
|
||||||
|
write(data, vertexShader->initialValues[i].value[1]);
|
||||||
|
write(data, vertexShader->initialValues[i].value[2]);
|
||||||
|
write(data, vertexShader->initialValues[i].value[3]);
|
||||||
|
write(data, vertexShader->initialValues[i].offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write loop vars
|
||||||
|
write(data, vertexShader->loopVarCount);
|
||||||
|
for (uint32_t i = 0; i < vertexShader->loopVarCount; i++) {
|
||||||
|
write(data, vertexShader->loopVars[i].offset);
|
||||||
|
write(data, vertexShader->loopVars[i].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write sampler vars
|
||||||
|
write(data, vertexShader->samplerVarCount);
|
||||||
|
for (uint32_t i = 0; i < vertexShader->samplerVarCount; i++) {
|
||||||
|
writeString(data, vertexShader->samplerVars[i].name);
|
||||||
|
write(data, vertexShader->samplerVars[i].type);
|
||||||
|
write(data, vertexShader->samplerVars[i].location);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write attribute vars
|
||||||
|
write(data, vertexShader->attribVarCount);
|
||||||
|
for (uint32_t i = 0; i < vertexShader->attribVarCount; i++) {
|
||||||
|
writeString(data, vertexShader->attribVars[i].name);
|
||||||
|
write(data, vertexShader->attribVars[i].type);
|
||||||
|
write(data, vertexShader->attribVars[i].count);
|
||||||
|
write(data, vertexShader->attribVars[i].location);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write ring item size
|
||||||
|
write(data, vertexShader->ringItemsize);
|
||||||
|
|
||||||
|
// write stream out
|
||||||
|
write(data, vertexShader->hasStreamOut);
|
||||||
|
for (uint32_t stride : vertexShader->streamOutStride) {
|
||||||
|
write(data, stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write gx2rBuffer
|
||||||
|
writeGX2RBuffer(data, &vertexShader->gx2rBuffer);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> SerializePixelShader(GX2PixelShader *pixelShader) {
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
// write regs
|
||||||
|
write(data, pixelShader->regs.sq_pgm_resources_ps);
|
||||||
|
write(data, pixelShader->regs.sq_pgm_exports_ps);
|
||||||
|
write(data, pixelShader->regs.spi_ps_in_control_0);
|
||||||
|
write(data, pixelShader->regs.spi_ps_in_control_1);
|
||||||
|
write(data, pixelShader->regs.num_spi_ps_input_cntl);
|
||||||
|
for (uint32_t spi_ps : pixelShader->regs.spi_ps_input_cntls) {
|
||||||
|
write(data, spi_ps);
|
||||||
|
}
|
||||||
|
write(data, pixelShader->regs.cb_shader_mask);
|
||||||
|
write(data, pixelShader->regs.cb_shader_control);
|
||||||
|
write(data, pixelShader->regs.db_shader_control);
|
||||||
|
write(data, pixelShader->regs.spi_input_z);
|
||||||
|
|
||||||
|
// write program
|
||||||
|
write(data, pixelShader->size);
|
||||||
|
for (uint32_t i = 0; i < pixelShader->size; i++) {
|
||||||
|
write(data, ((uint8_t *) pixelShader->program)[i]);
|
||||||
|
}
|
||||||
|
write(data, pixelShader->mode);
|
||||||
|
|
||||||
|
// write uniform blocks
|
||||||
|
write(data, pixelShader->uniformBlockCount);
|
||||||
|
for (uint32_t i = 0; i < pixelShader->uniformBlockCount; i++) {
|
||||||
|
writeString(data, pixelShader->uniformBlocks[i].name);
|
||||||
|
write(data, pixelShader->uniformBlocks[i].offset);
|
||||||
|
write(data, pixelShader->uniformBlocks[i].size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write uniform vars
|
||||||
|
write(data, pixelShader->uniformVarCount);
|
||||||
|
for (uint32_t i = 0; i < pixelShader->uniformVarCount; i++) {
|
||||||
|
writeString(data, pixelShader->uniformVars[i].name);
|
||||||
|
write(data, pixelShader->uniformVars[i].type);
|
||||||
|
write(data, pixelShader->uniformVars[i].count);
|
||||||
|
write(data, pixelShader->uniformVars[i].offset);
|
||||||
|
write(data, pixelShader->uniformVars[i].block);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write initial values
|
||||||
|
write(data, pixelShader->initialValueCount);
|
||||||
|
for (uint32_t i = 0; i < pixelShader->initialValueCount; i++) {
|
||||||
|
write(data, pixelShader->initialValues[i].value[0]);
|
||||||
|
write(data, pixelShader->initialValues[i].value[1]);
|
||||||
|
write(data, pixelShader->initialValues[i].value[2]);
|
||||||
|
write(data, pixelShader->initialValues[i].value[3]);
|
||||||
|
write(data, pixelShader->initialValues[i].offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write loop vars
|
||||||
|
write(data, pixelShader->loopVarCount);
|
||||||
|
for (uint32_t i = 0; i < pixelShader->loopVarCount; i++) {
|
||||||
|
write(data, pixelShader->loopVars[i].offset);
|
||||||
|
write(data, pixelShader->loopVars[i].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write sampler vars
|
||||||
|
write(data, pixelShader->samplerVarCount);
|
||||||
|
for (uint32_t i = 0; i < pixelShader->samplerVarCount; i++) {
|
||||||
|
writeString(data, pixelShader->samplerVars[i].name);
|
||||||
|
write(data, pixelShader->samplerVars[i].type);
|
||||||
|
write(data, pixelShader->samplerVars[i].location);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write gx2rBuffer
|
||||||
|
writeGX2RBuffer(data, &pixelShader->gx2rBuffer);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
static Type readAt(const std::span<const uint8_t> &data, size_t &pos) {
|
||||||
|
Type value = *reinterpret_cast<const Type *>(data.data() + pos);
|
||||||
|
pos += sizeof(Type);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *readString(const std::span<const uint8_t> &data, size_t &pos) {
|
||||||
|
std::string str(reinterpret_cast<const char *>(data.data() + pos));
|
||||||
|
pos += str.size() + 1;
|
||||||
|
pos = (pos + 3) & ~3; // align to 4 bytes
|
||||||
|
|
||||||
|
// Allocate memory for the string and copy the contents
|
||||||
|
char *result = static_cast<char *>(malloc(sizeof(char) * (str.size() + 1)));
|
||||||
|
strcpy(result, str.c_str());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GX2RBuffer readGX2RBuffer(const std::span<const uint8_t> &data, size_t &pos) {
|
||||||
|
GX2RBuffer buffer;
|
||||||
|
buffer.flags = readAt<GX2RResourceFlags>(data, pos);
|
||||||
|
buffer.elemSize = readAt<uint32_t>(data, pos);
|
||||||
|
buffer.elemCount = readAt<uint32_t>(data, pos);
|
||||||
|
size_t bufferSize = buffer.elemSize * buffer.elemCount;
|
||||||
|
buffer.buffer = malloc(sizeof(uint8_t) * bufferSize);
|
||||||
|
memcpy(buffer.buffer, data.data() + pos, bufferSize);
|
||||||
|
pos += bufferSize;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<GX2VertexShaderWrapper> DeserializeVertexShader(const std::span<const uint8_t> &data) {
|
||||||
|
size_t pos = 0;
|
||||||
|
auto vertexShaderWrapper = std::make_unique<GX2VertexShaderWrapper>();
|
||||||
|
auto *vertexShader = vertexShaderWrapper->getVertexShader();
|
||||||
|
*vertexShader = {};
|
||||||
|
|
||||||
|
// read regs
|
||||||
|
vertexShader->regs.sq_pgm_resources_vs = readAt<uint32_t>(data, pos);
|
||||||
|
vertexShader->regs.vgt_primitiveid_en = readAt<uint32_t>(data, pos);
|
||||||
|
vertexShader->regs.spi_vs_out_config = readAt<uint32_t>(data, pos);
|
||||||
|
vertexShader->regs.num_spi_vs_out_id = readAt<uint32_t>(data, pos);
|
||||||
|
for (uint32_t &spi_vs : vertexShader->regs.spi_vs_out_id) {
|
||||||
|
spi_vs = readAt<uint32_t>(data, pos);
|
||||||
|
}
|
||||||
|
vertexShader->regs.pa_cl_vs_out_cntl = readAt<uint32_t>(data, pos);
|
||||||
|
vertexShader->regs.sq_vtx_semantic_clear = readAt<uint32_t>(data, pos);
|
||||||
|
vertexShader->regs.num_sq_vtx_semantic = readAt<uint32_t>(data, pos);
|
||||||
|
for (uint32_t &sq_vtx : vertexShader->regs.sq_vtx_semantic) {
|
||||||
|
sq_vtx = readAt<uint32_t>(data, pos);
|
||||||
|
}
|
||||||
|
vertexShader->regs.vgt_strmout_buffer_en = readAt<uint32_t>(data, pos);
|
||||||
|
vertexShader->regs.vgt_vertex_reuse_block_cntl = readAt<uint32_t>(data, pos);
|
||||||
|
vertexShader->regs.vgt_hos_reuse_depth = readAt<uint32_t>(data, pos);
|
||||||
|
|
||||||
|
// read program
|
||||||
|
vertexShader->size = readAt<uint32_t>(data, pos);
|
||||||
|
vertexShader->program = memalign(256, vertexShader->size);
|
||||||
|
for (uint32_t i = 0; i < vertexShader->size; i++) {
|
||||||
|
static_cast<uint8_t *>(vertexShader->program)[i] = readAt<uint8_t>(data, pos);
|
||||||
|
}
|
||||||
|
vertexShader->mode = readAt<GX2ShaderMode>(data, pos);
|
||||||
|
|
||||||
|
// read uniform blocks
|
||||||
|
vertexShader->uniformBlockCount = readAt<uint32_t>(data, pos);
|
||||||
|
if (vertexShader->uniformBlockCount > 0) {
|
||||||
|
vertexShader->uniformBlocks = static_cast<GX2UniformBlock *>(malloc(sizeof(GX2UniformBlock) * vertexShader->uniformBlockCount));
|
||||||
|
for (uint32_t i = 0; i < vertexShader->uniformBlockCount; i++) {
|
||||||
|
vertexShader->uniformBlocks[i].name = readString(data, pos);
|
||||||
|
vertexShader->uniformBlocks[i].offset = readAt<uint32_t>(data, pos);
|
||||||
|
vertexShader->uniformBlocks[i].size = readAt<uint32_t>(data, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read uniform vars
|
||||||
|
vertexShader->uniformVarCount = readAt<uint32_t>(data, pos);
|
||||||
|
if (vertexShader->uniformVarCount > 0) {
|
||||||
|
vertexShader->uniformVars = static_cast<GX2UniformVar *>(malloc(sizeof(GX2UniformVar) * vertexShader->uniformVarCount));
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < vertexShader->uniformVarCount; i++) {
|
||||||
|
vertexShader->uniformVars[i].name = readString(data, pos);
|
||||||
|
vertexShader->uniformVars[i].type = readAt<GX2ShaderVarType>(data, pos);
|
||||||
|
vertexShader->uniformVars[i].count = readAt<uint32_t>(data, pos);
|
||||||
|
vertexShader->uniformVars[i].offset = readAt<uint32_t>(data, pos);
|
||||||
|
vertexShader->uniformVars[i].block = readAt<int32_t>(data, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read initial values
|
||||||
|
vertexShader->initialValueCount = readAt<uint32_t>(data, pos);
|
||||||
|
if (vertexShader->initialValueCount > 0) {
|
||||||
|
vertexShader->initialValues = static_cast<GX2UniformInitialValue *>(malloc(sizeof(GX2UniformInitialValue) * vertexShader->initialValueCount));
|
||||||
|
for (uint32_t i = 0; i < vertexShader->initialValueCount; i++) {
|
||||||
|
vertexShader->initialValues[i].value[0] = readAt<float>(data, pos);
|
||||||
|
vertexShader->initialValues[i].value[1] = readAt<float>(data, pos);
|
||||||
|
vertexShader->initialValues[i].value[2] = readAt<float>(data, pos);
|
||||||
|
vertexShader->initialValues[i].value[3] = readAt<float>(data, pos);
|
||||||
|
vertexShader->initialValues[i].offset = readAt<uint32_t>(data, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read loop vars
|
||||||
|
vertexShader->loopVarCount = readAt<uint32_t>(data, pos);
|
||||||
|
if (vertexShader->loopVarCount > 0) {
|
||||||
|
vertexShader->loopVars = static_cast<GX2LoopVar *>(malloc(sizeof(GX2LoopVar) + vertexShader->loopVarCount));
|
||||||
|
for (uint32_t i = 0; i < vertexShader->loopVarCount; i++) {
|
||||||
|
vertexShader->loopVars[i].offset = readAt<uint32_t>(data, pos);
|
||||||
|
vertexShader->loopVars[i].value = readAt<uint32_t>(data, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read sampler vars
|
||||||
|
vertexShader->samplerVarCount = readAt<uint32_t>(data, pos);
|
||||||
|
if (vertexShader->samplerVarCount > 0) {
|
||||||
|
vertexShader->samplerVars = static_cast<GX2SamplerVar *>(malloc(sizeof(GX2SamplerVar) * vertexShader->samplerVarCount));
|
||||||
|
for (uint32_t i = 0; i < vertexShader->samplerVarCount; i++) {
|
||||||
|
vertexShader->samplerVars[i].name = readString(data, pos);
|
||||||
|
vertexShader->samplerVars[i].type = readAt<GX2SamplerVarType>(data, pos);
|
||||||
|
vertexShader->samplerVars[i].location = readAt<uint32_t>(data, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read attribute vars
|
||||||
|
vertexShader->attribVarCount = readAt<uint32_t>(data, pos);
|
||||||
|
if (vertexShader->attribVarCount > 0) {
|
||||||
|
vertexShader->attribVars = static_cast<GX2AttribVar *>(malloc(sizeof(GX2AttribVar) * vertexShader->attribVarCount));
|
||||||
|
for (uint32_t i = 0; i < vertexShader->attribVarCount; i++) {
|
||||||
|
vertexShader->attribVars[i].name = readString(data, pos);
|
||||||
|
vertexShader->attribVars[i].type = readAt<GX2ShaderVarType>(data, pos);
|
||||||
|
vertexShader->attribVars[i].count = readAt<uint32_t>(data, pos);
|
||||||
|
vertexShader->attribVars[i].location = readAt<uint32_t>(data, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read ring item size
|
||||||
|
vertexShader->ringItemsize = readAt<uint32_t>(data, pos);
|
||||||
|
|
||||||
|
// read stream out
|
||||||
|
vertexShader->hasStreamOut = readAt<BOOL>(data, pos);
|
||||||
|
for (uint32_t &stride : vertexShader->streamOutStride) {
|
||||||
|
stride = readAt<uint32_t>(data, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read gx2rBuffer
|
||||||
|
vertexShader->gx2rBuffer = readGX2RBuffer(data, pos);
|
||||||
|
|
||||||
|
return vertexShaderWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<GX2PixelShaderWrapper> DeserializePixelShader(const std::span<const uint8_t> &data) {
|
||||||
|
size_t pos = 0;
|
||||||
|
auto pixelShaderWrapper = std::make_unique<GX2PixelShaderWrapper>();
|
||||||
|
auto *pixelShader = pixelShaderWrapper->getPixelShader();
|
||||||
|
*pixelShader = {};
|
||||||
|
// read regs
|
||||||
|
pixelShader->regs.sq_pgm_resources_ps = readAt<uint32_t>(data, pos);
|
||||||
|
pixelShader->regs.sq_pgm_exports_ps = readAt<uint32_t>(data, pos);
|
||||||
|
pixelShader->regs.spi_ps_in_control_0 = readAt<uint32_t>(data, pos);
|
||||||
|
pixelShader->regs.spi_ps_in_control_1 = readAt<uint32_t>(data, pos);
|
||||||
|
pixelShader->regs.num_spi_ps_input_cntl = readAt<uint32_t>(data, pos);
|
||||||
|
for (uint32_t &spi_ps : pixelShader->regs.spi_ps_input_cntls) {
|
||||||
|
spi_ps = readAt<uint32_t>(data, pos);
|
||||||
|
}
|
||||||
|
pixelShader->regs.cb_shader_mask = readAt<uint32_t>(data, pos);
|
||||||
|
pixelShader->regs.cb_shader_control = readAt<uint32_t>(data, pos);
|
||||||
|
pixelShader->regs.db_shader_control = readAt<uint32_t>(data, pos);
|
||||||
|
pixelShader->regs.spi_input_z = readAt<uint32_t>(data, pos);
|
||||||
|
|
||||||
|
// read program
|
||||||
|
pixelShader->size = readAt<uint32_t>(data, pos);
|
||||||
|
pixelShader->program = memalign(256, pixelShader->size);
|
||||||
|
for (uint32_t i = 0; i < pixelShader->size; i++) {
|
||||||
|
((uint8_t *) pixelShader->program)[i] = readAt<uint8_t>(data, pos);
|
||||||
|
}
|
||||||
|
pixelShader->mode = readAt<GX2ShaderMode>(data, pos);
|
||||||
|
|
||||||
|
// read uniform blocks
|
||||||
|
pixelShader->uniformBlockCount = readAt<uint32_t>(data, pos);
|
||||||
|
if (pixelShader->uniformBlockCount > 0) {
|
||||||
|
pixelShader->uniformBlocks = static_cast<GX2UniformBlock *>(malloc(sizeof(GX2UniformBlock) * pixelShader->uniformBlockCount));
|
||||||
|
for (uint32_t i = 0; i < pixelShader->uniformBlockCount; i++) {
|
||||||
|
pixelShader->uniformBlocks[i].name = readString(data, pos);
|
||||||
|
pixelShader->uniformBlocks[i].offset = readAt<uint32_t>(data, pos);
|
||||||
|
pixelShader->uniformBlocks[i].size = readAt<uint32_t>(data, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read uniform vars
|
||||||
|
pixelShader->uniformVarCount = readAt<uint32_t>(data, pos);
|
||||||
|
if (pixelShader->uniformVarCount > 0) {
|
||||||
|
pixelShader->uniformVars = static_cast<GX2UniformVar *>(malloc(sizeof(GX2UniformVar) + pixelShader->uniformVarCount));
|
||||||
|
for (uint32_t i = 0; i < pixelShader->uniformVarCount; i++) {
|
||||||
|
pixelShader->uniformVars[i].name = readString(data, pos);
|
||||||
|
pixelShader->uniformVars[i].type = readAt<GX2ShaderVarType>(data, pos);
|
||||||
|
pixelShader->uniformVars[i].count = readAt<uint32_t>(data, pos);
|
||||||
|
pixelShader->uniformVars[i].offset = readAt<uint32_t>(data, pos);
|
||||||
|
pixelShader->uniformVars[i].block = readAt<int32_t>(data, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read initial values
|
||||||
|
pixelShader->initialValueCount = readAt<uint32_t>(data, pos);
|
||||||
|
if (pixelShader->initialValueCount > 0) {
|
||||||
|
pixelShader->initialValues = static_cast<GX2UniformInitialValue *>(malloc(sizeof(GX2UniformInitialValue) * pixelShader->initialValueCount));
|
||||||
|
for (uint32_t i = 0; i < pixelShader->initialValueCount; i++) {
|
||||||
|
pixelShader->initialValues[i].value[0] = readAt<float>(data, pos);
|
||||||
|
pixelShader->initialValues[i].value[1] = readAt<float>(data, pos);
|
||||||
|
pixelShader->initialValues[i].value[2] = readAt<float>(data, pos);
|
||||||
|
pixelShader->initialValues[i].value[3] = readAt<float>(data, pos);
|
||||||
|
pixelShader->initialValues[i].offset = readAt<uint32_t>(data, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pixelShader->loopVarCount = readAt<uint32_t>(data, pos);
|
||||||
|
if (pixelShader->loopVarCount > 0) {
|
||||||
|
pixelShader->loopVars = static_cast<GX2LoopVar *>(malloc(sizeof(GX2LoopVar) * pixelShader->loopVarCount));
|
||||||
|
for (uint32_t i = 0; i < pixelShader->loopVarCount; i++) {
|
||||||
|
pixelShader->loopVars[i].offset = readAt<uint32_t>(data, pos);
|
||||||
|
pixelShader->loopVars[i].value = readAt<uint32_t>(data, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pixelShader->samplerVarCount = readAt<uint32_t>(data, pos);
|
||||||
|
if (pixelShader->samplerVarCount > 0) {
|
||||||
|
pixelShader->samplerVars = static_cast<GX2SamplerVar *>(malloc(sizeof(GX2SamplerVar) * pixelShader->samplerVarCount));
|
||||||
|
for (uint32_t i = 0; i < pixelShader->samplerVarCount; i++) {
|
||||||
|
pixelShader->samplerVars[i].name = readString(data, pos);
|
||||||
|
pixelShader->samplerVars[i].type = readAt<GX2SamplerVarType>(data, pos);
|
||||||
|
pixelShader->samplerVars[i].location = readAt<uint32_t>(data, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pixelShader->gx2rBuffer = readGX2RBuffer(data, pos);
|
||||||
|
|
||||||
|
return pixelShaderWrapper;
|
||||||
|
}
|
120
source/utils/ShaderSerializer.h
Normal file
120
source/utils/ShaderSerializer.h
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gx2/shaders.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class GX2PixelShaderWrapper {
|
||||||
|
public:
|
||||||
|
[[nodiscard]] GX2PixelShader *getPixelShader() {
|
||||||
|
return &pixelShader;
|
||||||
|
}
|
||||||
|
|
||||||
|
~GX2PixelShaderWrapper() {
|
||||||
|
if (pixelShader.program) {
|
||||||
|
free(pixelShader.program);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixelShader.uniformBlocks) {
|
||||||
|
for (uint32_t i = 0; i < pixelShader.uniformBlockCount; i++) {
|
||||||
|
free((void *) pixelShader.uniformBlocks[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(pixelShader.uniformBlocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixelShader.uniformVars) {
|
||||||
|
for (uint32_t i = 0; i < pixelShader.uniformVarCount; i++) {
|
||||||
|
free((void *) pixelShader.uniformVars[i].name);
|
||||||
|
}
|
||||||
|
free(pixelShader.uniformVars);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixelShader.initialValues) {
|
||||||
|
free(pixelShader.initialValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixelShader.samplerVars) {
|
||||||
|
for (uint32_t i = 0; i < pixelShader.samplerVarCount; i++) {
|
||||||
|
free((void *) pixelShader.samplerVars[i].name);
|
||||||
|
}
|
||||||
|
free(pixelShader.samplerVars);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixelShader.loopVars) {
|
||||||
|
free(pixelShader.loopVars);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixelShader.gx2rBuffer.buffer) {
|
||||||
|
free(pixelShader.gx2rBuffer.buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
alignas(0x40) GX2PixelShader pixelShader;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GX2VertexShaderWrapper {
|
||||||
|
public:
|
||||||
|
[[nodiscard]] GX2VertexShader *getVertexShader() {
|
||||||
|
return &vertexShader;
|
||||||
|
}
|
||||||
|
|
||||||
|
~GX2VertexShaderWrapper() {
|
||||||
|
if (vertexShader.program) {
|
||||||
|
free(vertexShader.program);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertexShader.uniformBlocks) {
|
||||||
|
for (uint32_t i = 0; i < vertexShader.uniformBlockCount; i++) {
|
||||||
|
free((void *) vertexShader.uniformBlocks[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(vertexShader.uniformBlocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertexShader.uniformVars) {
|
||||||
|
for (uint32_t i = 0; i < vertexShader.uniformVarCount; i++) {
|
||||||
|
free((void *) vertexShader.uniformVars[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(vertexShader.uniformVars);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertexShader.initialValues) {
|
||||||
|
free(vertexShader.initialValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertexShader.loopVars) {
|
||||||
|
free(vertexShader.loopVars);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertexShader.samplerVars) {
|
||||||
|
for (uint32_t i = 0; i < vertexShader.samplerVarCount; i++) {
|
||||||
|
free((void *) vertexShader.samplerVars[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(vertexShader.samplerVars);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertexShader.attribVars) {
|
||||||
|
for (uint32_t i = 0; i < vertexShader.attribVarCount; i++) {
|
||||||
|
free((void *) vertexShader.attribVars[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(vertexShader.attribVars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
alignas(0x40) GX2VertexShader vertexShader;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<uint8_t> SerializeVertexShader(GX2VertexShader *vertexShader);
|
||||||
|
|
||||||
|
std::vector<uint8_t> SerializePixelShader(GX2PixelShader *pixelShader);
|
||||||
|
|
||||||
|
std::unique_ptr<GX2VertexShaderWrapper> DeserializeVertexShader(const std::span<const uint8_t> &data);
|
||||||
|
|
||||||
|
std::unique_ptr<GX2PixelShaderWrapper> DeserializePixelShader(const std::span<const uint8_t> &data);
|
220
source/utils/SplashScreenDrawer.cpp
Normal file
220
source/utils/SplashScreenDrawer.cpp
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
#include "SplashScreenDrawer.h"
|
||||||
|
#include "ShaderSerializer.h"
|
||||||
|
#include "TGATexture.h"
|
||||||
|
#include "gfx.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include <fstream>
|
||||||
|
#include <gx2/draw.h>
|
||||||
|
#include <gx2/mem.h>
|
||||||
|
#include <gx2r/draw.h>
|
||||||
|
#include <whb/log.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
constexpr const char *s_textureVertexShader = R"(
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 aPos;
|
||||||
|
layout(location = 1) in vec2 aTexCoord;
|
||||||
|
|
||||||
|
layout(location = 0) out vec2 TexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
TexCoord = aTexCoord;
|
||||||
|
gl_Position = vec4(aPos.x, aPos.y, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
*/
|
||||||
|
|
||||||
|
constexpr uint8_t s_textureVertexShaderCompiled[] = {
|
||||||
|
0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x8A, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
|
||||||
|
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
|
||||||
|
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
|
||||||
|
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
|
||||||
|
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
|
||||||
|
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
|
||||||
|
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
|
||||||
|
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
|
||||||
|
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
|
||||||
|
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
|
||||||
|
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E,
|
||||||
|
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x80, 0x89, 0x00, 0x40, 0x01, 0xC0, 0xC8, 0x0F, 0x00, 0x94,
|
||||||
|
0x3C, 0xA0, 0x00, 0xC0, 0x08, 0x0B, 0x00, 0x94, 0x05, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x80,
|
||||||
|
0x00, 0x00, 0x00, 0x80, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0F, 0xFF,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x61, 0x50, 0x6F, 0x73,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x61, 0x54, 0x65, 0x78, 0x43, 0x6F, 0x6F, 0x72,
|
||||||
|
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
/*
|
||||||
|
constexpr const char *s_texturePixelShader = R"(
|
||||||
|
#version 450
|
||||||
|
#extension GL_ARB_shading_language_420pack: enable
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 TexCoord;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(binding = 0) uniform sampler2D inTexture;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
FragColor = texture(inTexture, TexCoord);
|
||||||
|
}
|
||||||
|
)";*/
|
||||||
|
constexpr uint8_t s_texturePixelShaderCompiled[] = {
|
||||||
|
0x00, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x8A,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
|
||||||
|
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0xC0,
|
||||||
|
0x88, 0x06, 0x20, 0x94, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0D, 0xF0,
|
||||||
|
0x00, 0x00, 0x80, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0F, 0xFF,
|
||||||
|
0x00, 0x00, 0x00, 0x01, 0x69, 0x6E, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72,
|
||||||
|
0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
static GX2Texture *LoadTGAAsTexture(std::string_view path) {
|
||||||
|
std::vector<uint8_t> buffer;
|
||||||
|
if (!LoadFileIntoBuffer(path, buffer)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *texture = TGA_LoadTexture(buffer);
|
||||||
|
if (texture == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
SplashScreenDrawer::SplashScreenDrawer(std::string_view meta_dir) {
|
||||||
|
// create shader group
|
||||||
|
mVertexShaderWrapper = DeserializeVertexShader(s_textureVertexShaderCompiled);
|
||||||
|
mPixelShaderWrapper = DeserializePixelShader(s_texturePixelShaderCompiled);
|
||||||
|
|
||||||
|
mShaderGroup = {};
|
||||||
|
mShaderGroup.vertexShader = mVertexShaderWrapper->getVertexShader();
|
||||||
|
mShaderGroup.pixelShader = mPixelShaderWrapper->getPixelShader();
|
||||||
|
|
||||||
|
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, mShaderGroup.vertexShader->program, mShaderGroup.vertexShader->size);
|
||||||
|
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, mShaderGroup.pixelShader->program, mShaderGroup.pixelShader->size);
|
||||||
|
|
||||||
|
GX2SetShaderMode(GX2_SHADER_MODE_UNIFORM_BLOCK);
|
||||||
|
|
||||||
|
GfxInitShaderAttribute(&mShaderGroup, "aPos", 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32);
|
||||||
|
GfxInitShaderAttribute(&mShaderGroup, "aTexCoord", 1, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32);
|
||||||
|
GfxInitFetchShader(&mShaderGroup);
|
||||||
|
|
||||||
|
// upload vertex position
|
||||||
|
mPositionBuffer.flags = GX2R_RESOURCE_BIND_VERTEX_BUFFER | GX2R_RESOURCE_USAGE_CPU_READ | GX2R_RESOURCE_USAGE_CPU_WRITE | GX2R_RESOURCE_USAGE_GPU_READ;
|
||||||
|
mPositionBuffer.elemSize = 2 * sizeof(float);
|
||||||
|
mPositionBuffer.elemCount = 4;
|
||||||
|
GX2RCreateBuffer(&mPositionBuffer);
|
||||||
|
void *posUploadBuffer = GX2RLockBufferEx(&mPositionBuffer, GX2R_RESOURCE_BIND_NONE);
|
||||||
|
memcpy(posUploadBuffer, mPositionData, mPositionBuffer.elemSize * mPositionBuffer.elemCount);
|
||||||
|
GX2RUnlockBufferEx(&mPositionBuffer, GX2R_RESOURCE_BIND_NONE);
|
||||||
|
|
||||||
|
// upload texture coords
|
||||||
|
mTexCoordBuffer.flags = GX2R_RESOURCE_BIND_VERTEX_BUFFER | GX2R_RESOURCE_USAGE_CPU_READ | GX2R_RESOURCE_USAGE_CPU_WRITE | GX2R_RESOURCE_USAGE_GPU_READ;
|
||||||
|
mTexCoordBuffer.elemSize = 2 * sizeof(float);
|
||||||
|
mTexCoordBuffer.elemCount = 4;
|
||||||
|
GX2RCreateBuffer(&mTexCoordBuffer);
|
||||||
|
void *coordsUploadBuffer = GX2RLockBufferEx(&mTexCoordBuffer, GX2R_RESOURCE_BIND_NONE);
|
||||||
|
memcpy(coordsUploadBuffer, mTexCoords, mTexCoordBuffer.elemSize * mTexCoordBuffer.elemCount);
|
||||||
|
GX2RUnlockBufferEx(&mTexCoordBuffer, GX2R_RESOURCE_BIND_NONE);
|
||||||
|
|
||||||
|
std::string bootTvTex = std::string(meta_dir).append("/bootTvTex.tga");
|
||||||
|
std::string bootDrcTex = std::string(meta_dir).append("/bootDrcTex.tga");
|
||||||
|
mTextureTV = LoadTGAAsTexture(bootTvTex);
|
||||||
|
mTextureDRC = LoadTGAAsTexture(bootDrcTex);
|
||||||
|
|
||||||
|
GX2Sampler sampler;
|
||||||
|
GX2InitSampler(&sampler, GX2_TEX_CLAMP_MODE_CLAMP, GX2_TEX_XY_FILTER_MODE_LINEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreenDrawer::Draw() {
|
||||||
|
if (!mTextureTV || !mTextureDRC) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Textures are missing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GfxBeginRender();
|
||||||
|
|
||||||
|
GfxBeginRenderTV();
|
||||||
|
GX2SetFetchShader(&mShaderGroup.fetchShader);
|
||||||
|
GX2SetVertexShader(mShaderGroup.vertexShader);
|
||||||
|
GX2SetPixelShader(mShaderGroup.pixelShader);
|
||||||
|
GX2SetShaderMode(GX2_SHADER_MODE_UNIFORM_BLOCK);
|
||||||
|
|
||||||
|
GX2RSetAttributeBuffer(&mPositionBuffer, 0, mPositionBuffer.elemSize, 0);
|
||||||
|
GX2RSetAttributeBuffer(&mTexCoordBuffer, 1, mTexCoordBuffer.elemSize, 0);
|
||||||
|
GX2SetPixelTexture(mTextureTV, mShaderGroup.pixelShader->samplerVars[0].location);
|
||||||
|
GX2SetPixelSampler(&mSampler, mShaderGroup.pixelShader->samplerVars[0].location);
|
||||||
|
|
||||||
|
GX2DrawEx(GX2_PRIMITIVE_MODE_QUADS, 4, 0, 1);
|
||||||
|
GfxFinishRenderTV();
|
||||||
|
|
||||||
|
GfxBeginRenderDRC();
|
||||||
|
GX2SetFetchShader(&mShaderGroup.fetchShader);
|
||||||
|
GX2SetVertexShader(mShaderGroup.vertexShader);
|
||||||
|
GX2SetPixelShader(mShaderGroup.pixelShader);
|
||||||
|
GX2SetShaderMode(GX2_SHADER_MODE_UNIFORM_BLOCK);
|
||||||
|
|
||||||
|
GX2RSetAttributeBuffer(&mPositionBuffer, 0, mPositionBuffer.elemSize, 0);
|
||||||
|
GX2RSetAttributeBuffer(&mTexCoordBuffer, 1, mTexCoordBuffer.elemSize, 0);
|
||||||
|
GX2SetPixelTexture(mTextureDRC, mShaderGroup.pixelShader->samplerVars[0].location);
|
||||||
|
GX2SetPixelSampler(&mSampler, mShaderGroup.pixelShader->samplerVars[0].location);
|
||||||
|
|
||||||
|
GX2DrawEx(GX2_PRIMITIVE_MODE_QUADS, 4, 0, 1);
|
||||||
|
GfxFinishRenderDRC();
|
||||||
|
|
||||||
|
GfxFinishRender();
|
||||||
|
}
|
||||||
|
|
||||||
|
SplashScreenDrawer::~SplashScreenDrawer() {
|
||||||
|
GX2RDestroyBufferEx(&mPositionBuffer, GX2R_RESOURCE_BIND_NONE);
|
||||||
|
GX2RDestroyBufferEx(&mTexCoordBuffer, GX2R_RESOURCE_BIND_NONE);
|
||||||
|
if (mTextureTV) {
|
||||||
|
if (mTextureTV->surface.image != nullptr) {
|
||||||
|
free(mTextureTV->surface.image);
|
||||||
|
mTextureTV->surface.image = nullptr;
|
||||||
|
}
|
||||||
|
::free(mTextureTV);
|
||||||
|
mTextureTV = nullptr;
|
||||||
|
}
|
||||||
|
if (mTextureDRC) {
|
||||||
|
if (mTextureDRC->surface.image != nullptr) {
|
||||||
|
free(mTextureDRC->surface.image);
|
||||||
|
mTextureDRC->surface.image = nullptr;
|
||||||
|
}
|
||||||
|
::free(mTextureDRC);
|
||||||
|
mTextureDRC = nullptr;
|
||||||
|
}
|
||||||
|
}
|
50
source/utils/SplashScreenDrawer.h
Normal file
50
source/utils/SplashScreenDrawer.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ShaderSerializer.h"
|
||||||
|
#include "gfx.h"
|
||||||
|
#include <gx2/sampler.h>
|
||||||
|
#include <gx2/shaders.h>
|
||||||
|
#include <gx2/texture.h>
|
||||||
|
#include <gx2r/buffer.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class SplashScreenDrawer {
|
||||||
|
public:
|
||||||
|
explicit SplashScreenDrawer(std::string_view meta_dir);
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
|
||||||
|
virtual ~SplashScreenDrawer();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const float mPositionData[8] = {
|
||||||
|
-1.0f,
|
||||||
|
-1.0f,
|
||||||
|
1.0f,
|
||||||
|
-1.0f,
|
||||||
|
1.0f,
|
||||||
|
1.0f,
|
||||||
|
-1.0f,
|
||||||
|
1.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
const float mTexCoords[8] = {
|
||||||
|
0.0f,
|
||||||
|
1.0f,
|
||||||
|
1.0f,
|
||||||
|
1.0f,
|
||||||
|
1.0f,
|
||||||
|
0.0f,
|
||||||
|
0.0f,
|
||||||
|
0.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
WHBGfxShaderGroup mShaderGroup = {};
|
||||||
|
std::unique_ptr<GX2VertexShaderWrapper> mVertexShaderWrapper;
|
||||||
|
std::unique_ptr<GX2PixelShaderWrapper> mPixelShaderWrapper;
|
||||||
|
GX2RBuffer mPositionBuffer = {};
|
||||||
|
GX2RBuffer mTexCoordBuffer = {};
|
||||||
|
GX2Texture *mTextureTV = nullptr;
|
||||||
|
GX2Texture *mTextureDRC = nullptr;
|
||||||
|
GX2Sampler mSampler = {};
|
||||||
|
};
|
102
source/utils/SplashSoundPlayer.cpp
Normal file
102
source/utils/SplashSoundPlayer.cpp
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#include "SplashSoundPlayer.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include <coreinit/transition.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <sndcore2/core.h>
|
||||||
|
#include <sndcore2/device.h>
|
||||||
|
#include <span>
|
||||||
|
#include <string>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <whb/log.h>
|
||||||
|
|
||||||
|
SplashSoundPlayer::SplashSoundPlayer(std::string_view meta_dir) {
|
||||||
|
std::string bootSound = std::string(meta_dir).append("/bootSound.btsnd");
|
||||||
|
|
||||||
|
if (!LoadFileIntoBuffer(bootSound, mBuffer)) {
|
||||||
|
mBuffer.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mBuffer.size() < 8) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto target = ((uint32_t *) mBuffer.data())[0];
|
||||||
|
if (target <= 2) {
|
||||||
|
mOutputTarget = static_cast<TransitionAudioTarget>(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
mLoopPoint = ((uint32_t *) mBuffer.data())[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashSoundPlayer::Play() {
|
||||||
|
if (mBuffer.empty() || mBuffer.size() < 8) {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("mBuffed is empty or too small");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AXTransitionAudioBuffer transitionAudioBuffer = {};
|
||||||
|
|
||||||
|
AXInit();
|
||||||
|
AXDeviceMode tvMode;
|
||||||
|
AXDeviceMode drcMode;
|
||||||
|
AXGetDeviceMode(0, &tvMode);
|
||||||
|
AXGetDeviceMode(1, &drcMode);
|
||||||
|
AXQuit();
|
||||||
|
|
||||||
|
WHBLogPrintf("TV mode before transition = %d\n", tvMode);
|
||||||
|
transitionAudioBuffer.tv.mode = tvMode;
|
||||||
|
|
||||||
|
WHBLogPrintf("DRC mode before transition = %d\n", drcMode);
|
||||||
|
transitionAudioBuffer.drc.mode = drcMode;
|
||||||
|
|
||||||
|
transitionAudioBuffer.unk1 = 1;
|
||||||
|
transitionAudioBuffer.unk2 = 0;
|
||||||
|
|
||||||
|
transitionAudioBuffer.tv.unk1 = 0.99987207655f;
|
||||||
|
transitionAudioBuffer.tv.unk2 = 600;
|
||||||
|
|
||||||
|
transitionAudioBuffer.drc.unk1 = transitionAudioBuffer.tv.unk1;
|
||||||
|
transitionAudioBuffer.tv.unk2 = transitionAudioBuffer.tv.unk2;
|
||||||
|
|
||||||
|
switch (mOutputTarget) {
|
||||||
|
case TV_ONLY:
|
||||||
|
transitionAudioBuffer.tv.enabled = true;
|
||||||
|
transitionAudioBuffer.drc.enabled = false;
|
||||||
|
break;
|
||||||
|
case DRC_ONLY:
|
||||||
|
transitionAudioBuffer.tv.enabled = false;
|
||||||
|
transitionAudioBuffer.drc.enabled = true;
|
||||||
|
break;
|
||||||
|
case BOTH:
|
||||||
|
transitionAudioBuffer.tv.enabled = true;
|
||||||
|
transitionAudioBuffer.drc.enabled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *audioBuffer = (void *) nullptr;
|
||||||
|
uint32_t audioBufferLen = 0;
|
||||||
|
auto res = __OSGetTransitionAudioBuffer(&audioBuffer, &audioBufferLen);
|
||||||
|
if (res == 0) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Could not get access to audio buffer from foreground bucket\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::span<uint8_t> audioBufferIn(mBuffer.data() + 8, mBuffer.size() - 8);
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE("Got audio buffer from foreground bucket @ %8.8x len = %d\n", audioBuffer, audioBufferLen);
|
||||||
|
if (audioBufferLen < mBuffer.size()) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("buffer not big enough");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(audioBuffer, audioBufferIn.data(), audioBufferIn.size());
|
||||||
|
__OSSetTransitionAudioSize(audioBufferIn.size());
|
||||||
|
|
||||||
|
transitionAudioBuffer.length = audioBufferIn.size();
|
||||||
|
transitionAudioBuffer.loopPoint = mLoopPoint;
|
||||||
|
transitionAudioBuffer.audioBuffer = audioBuffer;
|
||||||
|
transitionAudioBuffer.audioBufferLen = audioBufferLen;
|
||||||
|
AXSetUpTransitionAudio((AXTransitionAudioBuffer *) &transitionAudioBuffer);
|
||||||
|
AXStartTransitionAudio();
|
||||||
|
}
|
23
source/utils/SplashSoundPlayer.h
Normal file
23
source/utils/SplashSoundPlayer.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class SplashSoundPlayer {
|
||||||
|
public:
|
||||||
|
SplashSoundPlayer(std::string_view meta_dir);
|
||||||
|
|
||||||
|
void Play();
|
||||||
|
|
||||||
|
virtual ~SplashSoundPlayer() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum TransitionAudioTarget {
|
||||||
|
TV_ONLY,
|
||||||
|
DRC_ONLY,
|
||||||
|
BOTH
|
||||||
|
};
|
||||||
|
std::vector<uint8_t> mBuffer;
|
||||||
|
TransitionAudioTarget mOutputTarget = BOTH;
|
||||||
|
uint32_t mLoopPoint = 0;
|
||||||
|
};
|
84
source/utils/TGATexture.cpp
Normal file
84
source/utils/TGATexture.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#include <gx2/draw.h>
|
||||||
|
#include <gx2/mem.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
#include "TGATexture.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include <whb/log.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Based on
|
||||||
|
* https://github.com/Xpl0itU/savemii/blob/70e3b63db52113519230e1e39bd56876cef12dc8/src/tga_reader.cpp
|
||||||
|
* and
|
||||||
|
* https://github.com/Crementif/WiiU-GX2-Shader-Examples/blob/5a88f861043dcb7666d4d25a6bab6bd271e76d5f/include/TGATexture.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint16_t inline _swapU16(uint16_t v) {
|
||||||
|
return (v >> 8) | (v << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
GX2Texture *TGA_LoadTexture(std::span<uint8_t> data) {
|
||||||
|
TGA_HEADER *tgaHeader = (TGA_HEADER *) data.data();
|
||||||
|
|
||||||
|
uint32_t width = _swapU16(tgaHeader->width);
|
||||||
|
uint32_t height = _swapU16(tgaHeader->height);
|
||||||
|
|
||||||
|
if (tgaHeader->bits != 24) {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("Only 24bit TGA images are supported");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (tgaHeader->imagetype != 2 && tgaHeader->imagetype != 3) {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("Only uncompressed TGA images are supported");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
GX2Texture *texture = (GX2Texture *) malloc(sizeof(GX2Texture));
|
||||||
|
*texture = {};
|
||||||
|
|
||||||
|
texture->surface.width = width;
|
||||||
|
texture->surface.height = height;
|
||||||
|
texture->surface.depth = 1;
|
||||||
|
texture->surface.mipLevels = 1;
|
||||||
|
texture->surface.format = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8;
|
||||||
|
texture->surface.aa = GX2_AA_MODE1X;
|
||||||
|
texture->surface.use = GX2_SURFACE_USE_TEXTURE;
|
||||||
|
texture->surface.dim = GX2_SURFACE_DIM_TEXTURE_2D;
|
||||||
|
texture->surface.tileMode = GX2_TILE_MODE_LINEAR_ALIGNED;
|
||||||
|
texture->surface.swizzle = 0;
|
||||||
|
texture->viewFirstMip = 0;
|
||||||
|
texture->viewNumMips = 1;
|
||||||
|
texture->viewFirstSlice = 0;
|
||||||
|
texture->viewNumSlices = 1;
|
||||||
|
texture->compMap = 0x0010203;
|
||||||
|
GX2CalcSurfaceSizeAndAlignment(&texture->surface);
|
||||||
|
GX2InitTextureRegs(texture);
|
||||||
|
|
||||||
|
if (texture->surface.imageSize == 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
texture->surface.image = memalign(texture->surface.alignment, texture->surface.imageSize);
|
||||||
|
if (!texture->surface.image) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y < height; y++) {
|
||||||
|
uint32_t *out_data = (uint32_t *) texture->surface.image + (y * texture->surface.pitch);
|
||||||
|
for (uint32_t x = 0; x < width; x++) {
|
||||||
|
int index = sizeof(TGA_HEADER) + (3 * width * (height - 1 - y)) + (3 * x);
|
||||||
|
|
||||||
|
int b = data[index + 0] & 0xFF;
|
||||||
|
int g = data[index + 1] & 0xFF;
|
||||||
|
int r = data[index + 2] & 0xFF;
|
||||||
|
|
||||||
|
*out_data = r << 24 | g << 16 | b << 8 | 0xFF;
|
||||||
|
out_data++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: create texture with optimal tile format and use GX2CopySurface to convert from linear to tiled format
|
||||||
|
GX2Invalidate(GX2_INVALIDATE_MODE_CPU | GX2_INVALIDATE_MODE_TEXTURE, texture->surface.image, texture->surface.imageSize);
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
24
source/utils/TGATexture.h
Normal file
24
source/utils/TGATexture.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <gx2/texture.h>
|
||||||
|
|
||||||
|
struct WUT_PACKED TGA_HEADER {
|
||||||
|
uint8_t identsize; // size of ID field that follows 18 byte header (0 usually)
|
||||||
|
uint8_t colourmaptype; // type of colour map 0=none, 1=has palette
|
||||||
|
uint8_t imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed
|
||||||
|
|
||||||
|
uint8_t colourmapstart[2]; // first colour map entry in palette
|
||||||
|
uint8_t colourmaplength[2]; // number of colours in palette
|
||||||
|
uint8_t colourmapbits; // number of bits per palette entry 15,16,24,32
|
||||||
|
|
||||||
|
uint16_t xstart; // image x origin
|
||||||
|
uint16_t ystart; // image y origin
|
||||||
|
uint16_t width; // image width in pixels
|
||||||
|
uint16_t height; // image height in pixels
|
||||||
|
uint8_t bits; // image bits per pixel 8,16,24,32
|
||||||
|
uint8_t descriptor; // image descriptor bits (vh flip bits)
|
||||||
|
};
|
||||||
|
|
||||||
|
// quick and dirty 24-bit TGA loader
|
||||||
|
GX2Texture *TGA_LoadTexture(std::span<uint8_t> data);
|
549
source/utils/gfx.c
Normal file
549
source/utils/gfx.c
Normal file
@ -0,0 +1,549 @@
|
|||||||
|
/*
|
||||||
|
* Based on https://github.com/devkitPro/wut/blob/4933211d7ba86d4dd45c8525fc83747d799ecf31/libraries/libwhb/src/gfx.c
|
||||||
|
*/
|
||||||
|
#include "logger.h"
|
||||||
|
#include <avm/drc.h>
|
||||||
|
#include <avm/tv.h>
|
||||||
|
#include <coreinit/debug.h>
|
||||||
|
#include <coreinit/memdefaultheap.h>
|
||||||
|
#include <coreinit/memexpheap.h>
|
||||||
|
#include <coreinit/memfrmheap.h>
|
||||||
|
#include <coreinit/memheap.h>
|
||||||
|
#include <coreinit/savedframe.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/utils.h>
|
||||||
|
#include <gx2r/buffer.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 GX2SurfaceFormat sDrcSurfaceFormat;
|
||||||
|
static GX2ColorBuffer sTvColourBuffer = {0};
|
||||||
|
static GX2ColorBuffer sDrcColourBuffer = {0};
|
||||||
|
static GX2ContextState *sTvContextState = NULL;
|
||||||
|
static GX2ContextState *sDrcContextState = NULL;
|
||||||
|
static BOOL sGpuTimedOut = FALSE;
|
||||||
|
|
||||||
|
static void *sGfxHeapForeground = NULL;
|
||||||
|
|
||||||
|
static void *AllocMEM2(uint32_t size, uint32_t alignment) {
|
||||||
|
void *block;
|
||||||
|
|
||||||
|
if (alignment < 4) {
|
||||||
|
alignment = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
block = MEMAllocFromDefaultHeapEx(size, alignment);
|
||||||
|
if (!block) {
|
||||||
|
OSFatal("AutobootModule: Failed to allocate memory from MEM2");
|
||||||
|
}
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FreeMEM2(void *block) {
|
||||||
|
MEMFreeToDefaultHeap(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *AllocBucket(uint32_t size, uint32_t alignment) {
|
||||||
|
void *block;
|
||||||
|
|
||||||
|
if (!sGfxHeapForeground) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("sGfxHeapForeground was NULL");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alignment < 4) {
|
||||||
|
alignment = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
block = MEMAllocFromExpHeapEx(sGfxHeapForeground, size, alignment);
|
||||||
|
if (!block) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory from bucket");
|
||||||
|
}
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FreeBucket(void *block) {
|
||||||
|
if (!sGfxHeapForeground) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("sGfxHeapForeground was NULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEMFreeToExpHeap(sGfxHeapForeground, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
GfxGX2RAlloc(GX2RResourceFlags flags, uint32_t size, uint32_t alignment) {
|
||||||
|
return AllocMEM2(size, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
GfxGX2RFree(GX2RResourceFlags flags, void *block) {
|
||||||
|
return FreeMEM2(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 uint32_t InitMemory() {
|
||||||
|
// Allocate TV scan buffer.
|
||||||
|
sTvScanBuffer = AllocBucket(sTvScanBufferSize, GX2_SCAN_BUFFER_ALIGNMENT);
|
||||||
|
if (!sTvScanBuffer) {
|
||||||
|
DEBUG_FUNCTION_LINE_INFO("%s: sTvScanBuffer = AllocBucket(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_SINGLE);
|
||||||
|
|
||||||
|
// Allocate TV colour buffer.
|
||||||
|
sTvColourBuffer.surface.image = AllocMEM2(sTvColourBuffer.surface.imageSize, sTvColourBuffer.surface.alignment);
|
||||||
|
if (!sTvColourBuffer.surface.image) {
|
||||||
|
DEBUG_FUNCTION_LINE_INFO("%s: sTvColourBuffer = AllocMEM2(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 DRC scan buffer.
|
||||||
|
sDrcScanBuffer = AllocBucket(sDrcScanBufferSize, GX2_SCAN_BUFFER_ALIGNMENT);
|
||||||
|
if (!sDrcScanBuffer) {
|
||||||
|
DEBUG_FUNCTION_LINE_INFO("%s: sDrcScanBuffer = AllocBucket(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_SINGLE);
|
||||||
|
|
||||||
|
// Allocate DRC colour buffer.
|
||||||
|
sDrcColourBuffer.surface.image = AllocMEM2(sDrcColourBuffer.surface.imageSize, sDrcColourBuffer.surface.alignment);
|
||||||
|
if (!sDrcColourBuffer.surface.image) {
|
||||||
|
DEBUG_FUNCTION_LINE_INFO("%s: sDrcColourBuffer = AllocMEM2(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);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t DeinitMemory() {
|
||||||
|
if (sTvScanBuffer) {
|
||||||
|
FreeBucket(sTvScanBuffer);
|
||||||
|
sTvScanBuffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sTvColourBuffer.surface.image) {
|
||||||
|
FreeMEM2(sTvColourBuffer.surface.image);
|
||||||
|
sTvColourBuffer.surface.image = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sDrcScanBuffer) {
|
||||||
|
FreeBucket(sDrcScanBuffer);
|
||||||
|
sDrcScanBuffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sDrcColourBuffer.surface.image) {
|
||||||
|
FreeMEM2(sDrcColourBuffer.surface.image);
|
||||||
|
sDrcColourBuffer.surface.image = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL initBucketHeap() {
|
||||||
|
MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_FG);
|
||||||
|
uint32_t size;
|
||||||
|
void *base;
|
||||||
|
|
||||||
|
size = MEMGetAllocatableSizeForFrmHeapEx(heap, 4);
|
||||||
|
if (!size) {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("%s: MEMAllocFromFrmHeapEx(heap, 0x%X, 4)", __FUNCTION__, size);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
base = MEMAllocFromFrmHeapEx(heap, size, 4);
|
||||||
|
if (!base) {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("%s: MEMGetAllocatableSizeForFrmHeapEx == 0", __FUNCTION__);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
sGfxHeapForeground = MEMCreateExpHeapEx(base, size, 0);
|
||||||
|
if (!sGfxHeapForeground) {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("%s: MEMCreateExpHeapEx(0x%08X, 0x%X, 0)", __FUNCTION__, base, size);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL deInitBucketHeap() {
|
||||||
|
MEMHeapHandle foreground = MEMGetBaseHeapHandle(MEM_BASE_HEAP_FG);
|
||||||
|
|
||||||
|
if (sGfxHeapForeground) {
|
||||||
|
MEMDestroyExpHeap(sGfxHeapForeground);
|
||||||
|
sGfxHeapForeground = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEMFreeToFrmHeap(foreground, MEM_FRM_HEAP_FREE_ALL);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL GfxInit() {
|
||||||
|
initBucketHeap();
|
||||||
|
|
||||||
|
uint32_t drcWidth, drcHeight;
|
||||||
|
uint32_t tvWidth, tvHeight;
|
||||||
|
uint32_t unk;
|
||||||
|
|
||||||
|
sCommandBufferPool = AllocMEM2(WHB_GFX_COMMAND_BUFFER_POOL_SIZE,
|
||||||
|
GX2_COMMAND_BUFFER_ALIGNMENT);
|
||||||
|
if (!sCommandBufferPool) {
|
||||||
|
DEBUG_FUNCTION_LINE_INFO("%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);
|
||||||
|
|
||||||
|
// Clear frame information in saved foreground to avoid screen corruption
|
||||||
|
__OSClearSavedFrame(OS_SAVED_FRAME_A, OS_SAVED_FRAME_SCREEN_TV);
|
||||||
|
__OSClearSavedFrame(OS_SAVED_FRAME_A, OS_SAVED_FRAME_SCREEN_DRC);
|
||||||
|
__OSClearSavedFrame(OS_SAVED_FRAME_B, OS_SAVED_FRAME_SCREEN_TV);
|
||||||
|
__OSClearSavedFrame(OS_SAVED_FRAME_B, OS_SAVED_FRAME_SCREEN_DRC);
|
||||||
|
|
||||||
|
// Disable output until we have rendered something
|
||||||
|
GX2SetTVEnable(FALSE);
|
||||||
|
GX2SetDRCEnable(FALSE);
|
||||||
|
|
||||||
|
sDrcRenderMode = GX2GetSystemDRCMode();
|
||||||
|
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_SINGLE, &sTvScanBufferSize, &unk);
|
||||||
|
GfxInitTvColourBuffer(&sTvColourBuffer, tvWidth, tvHeight, sTvSurfaceFormat, GX2_AA_MODE1X);
|
||||||
|
|
||||||
|
GX2CalcDRCSize(sDrcRenderMode, sDrcSurfaceFormat, GX2_BUFFERING_MODE_DOUBLE, &sDrcScanBufferSize, &unk);
|
||||||
|
GfxInitTvColourBuffer(&sDrcColourBuffer, drcWidth, drcHeight, sDrcSurfaceFormat, GX2_AA_MODE1X);
|
||||||
|
|
||||||
|
GX2CalcDRCSize(sDrcRenderMode, sDrcSurfaceFormat, GX2_BUFFERING_MODE_SINGLE, &sDrcScanBufferSize, &unk);
|
||||||
|
if (InitMemory() != 0) {
|
||||||
|
DEBUG_FUNCTION_LINE_INFO("%s: GfxProcCallbackAcquired failed", __FUNCTION__);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
GX2RSetAllocator(&GfxGX2RAlloc, &GfxGX2RFree);
|
||||||
|
|
||||||
|
// Initialise TV context state.
|
||||||
|
sTvContextState = AllocMEM2(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT);
|
||||||
|
if (!sTvContextState) {
|
||||||
|
DEBUG_FUNCTION_LINE_INFO("%s: failed to allocate sTvContextState", __FUNCTION__);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
GX2SetupContextStateEx(sTvContextState, TRUE);
|
||||||
|
GX2SetContextState(sTvContextState);
|
||||||
|
GX2SetColorBuffer(&sTvColourBuffer, GX2_RENDER_TARGET_0);
|
||||||
|
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 = AllocMEM2(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);
|
||||||
|
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) {
|
||||||
|
FreeMEM2(sCommandBufferPool);
|
||||||
|
sCommandBufferPool = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sTvScanBuffer) {
|
||||||
|
FreeBucket(sTvScanBuffer);
|
||||||
|
sTvScanBuffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sTvColourBuffer.surface.image) {
|
||||||
|
FreeMEM2(sTvColourBuffer.surface.image);
|
||||||
|
sTvColourBuffer.surface.image = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sTvContextState) {
|
||||||
|
FreeMEM2(sTvContextState);
|
||||||
|
sTvContextState = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sDrcContextState) {
|
||||||
|
FreeMEM2(sDrcContextState);
|
||||||
|
sDrcContextState = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sDrcScanBuffer) {
|
||||||
|
FreeBucket(sDrcScanBuffer);
|
||||||
|
sDrcScanBuffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sDrcColourBuffer.surface.image) {
|
||||||
|
FreeMEM2(sDrcColourBuffer.surface.image);
|
||||||
|
sDrcColourBuffer.surface.image = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GfxShutdown() {
|
||||||
|
if (sGpuTimedOut) {
|
||||||
|
GX2ResetGPU(0);
|
||||||
|
sGpuTimedOut = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GX2RSetAllocator(NULL, NULL);
|
||||||
|
|
||||||
|
GX2Shutdown();
|
||||||
|
|
||||||
|
DeinitMemory();
|
||||||
|
|
||||||
|
if (sTvContextState) {
|
||||||
|
FreeMEM2(sTvContextState);
|
||||||
|
sTvContextState = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sDrcContextState) {
|
||||||
|
FreeMEM2(sDrcContextState);
|
||||||
|
sDrcContextState = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sCommandBufferPool) {
|
||||||
|
FreeMEM2(sCommandBufferPool);
|
||||||
|
sCommandBufferPool = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
deInitBucketHeap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GfxBeginRender() {
|
||||||
|
uint32_t swapCount, flipCount;
|
||||||
|
OSTime lastFlip, lastVsync;
|
||||||
|
uint32_t waitCount = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
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 GfxBeginRenderDRC() {
|
||||||
|
GX2SetContextState(sDrcContextState);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GfxFinishRenderDRC() {
|
||||||
|
GX2CopyColorBufferToScanBuffer(&sDrcColourBuffer, GX2_SCAN_TARGET_DRC);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GfxBeginRenderTV() {
|
||||||
|
GX2SetContextState(sTvContextState);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GfxFinishRenderTV() {
|
||||||
|
GX2CopyColorBufferToScanBuffer(&sTvColourBuffer, GX2_SCAN_TARGET_TV);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GfxFinishRender() {
|
||||||
|
GX2SwapScanBuffers();
|
||||||
|
GX2Flush();
|
||||||
|
GX2DrawDone();
|
||||||
|
GX2SetTVEnable(TRUE);
|
||||||
|
GX2SetDRCEnable(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL GfxInitFetchShader(WHBGfxShaderGroup *group) {
|
||||||
|
uint32_t size = GX2CalcFetchShaderSizeEx(group->numAttributes,
|
||||||
|
GX2_FETCH_SHADER_TESSELLATION_NONE,
|
||||||
|
GX2_TESSELLATION_MODE_DISCRETE);
|
||||||
|
group->fetchShaderProgram = AllocMEM2(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 GX2_SEL_MASK(GX2_SQ_SEL_X, GX2_SQ_SEL_0, GX2_SQ_SEL_0, GX2_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 GX2_SEL_MASK(GX2_SQ_SEL_X, GX2_SQ_SEL_Y, GX2_SQ_SEL_0, GX2_SQ_SEL_1);
|
||||||
|
case GX2_ATTRIB_FORMAT_FLOAT_32_32_32:
|
||||||
|
return GX2_SEL_MASK(GX2_SQ_SEL_X, GX2_SQ_SEL_Y, GX2_SQ_SEL_Z, GX2_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 GX2_SEL_MASK(GX2_SQ_SEL_X, GX2_SQ_SEL_Y, GX2_SQ_SEL_Z, GX2_SQ_SEL_W);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return GX2_SEL_MASK(GX2_SQ_SEL_0, GX2_SQ_SEL_0, GX2_SQ_SEL_0, GX2_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 GfxInitShaderAttribute(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;
|
||||||
|
}
|
40
source/utils/gfx.h
Normal file
40
source/utils/gfx.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <gx2/context.h>
|
||||||
|
#include <gx2/shaders.h>
|
||||||
|
#include <gx2/texture.h>
|
||||||
|
#include <whb/gfx.h>
|
||||||
|
#include <wut.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BOOL GfxInit();
|
||||||
|
|
||||||
|
void GfxShutdown();
|
||||||
|
|
||||||
|
void GfxBeginRender();
|
||||||
|
|
||||||
|
void GfxFinishRender();
|
||||||
|
|
||||||
|
void GfxBeginRenderDRC();
|
||||||
|
|
||||||
|
void GfxFinishRenderDRC();
|
||||||
|
|
||||||
|
void GfxBeginRenderTV();
|
||||||
|
|
||||||
|
void GfxFinishRenderTV();
|
||||||
|
|
||||||
|
BOOL GfxInitShaderAttribute(WHBGfxShaderGroup *group,
|
||||||
|
const char *name,
|
||||||
|
uint32_t buffer,
|
||||||
|
uint32_t offset,
|
||||||
|
GX2AttribFormat format);
|
||||||
|
|
||||||
|
BOOL GfxInitFetchShader(WHBGfxShaderGroup *group);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
Loading…
Reference in New Issue
Block a user