From 611fe0223cb29cf0a8e9a3aa0f28b55ddba79f0a Mon Sep 17 00:00:00 2001 From: MonsterDruide1 <5958456@gmail.com> Date: Sat, 19 Aug 2023 03:49:39 +0200 Subject: [PATCH] common: Copy aglRes-Files from WiiU-Decomp (#15) --- CMakeLists.txt | 16 +- include/common/aglResBinaryShaderArchive.h | 65 ++++ include/common/aglResBinaryShaderProgram.h | 43 +++ include/common/aglResCommon.h | 187 ++++++++++ include/common/aglResShaderArchive.h | 68 ++++ include/common/aglResShaderBinary.h | 36 ++ include/common/aglResShaderMacro.h | 29 ++ include/common/aglResShaderProgram.h | 46 +++ include/common/aglResShaderSource.h | 30 ++ include/common/aglResShaderSymbol.h | 58 ++++ include/common/aglResShaderVariation.h | 32 ++ include/common/aglShader.h | 7 - include/common/aglShaderCompileInfo.h | 3 + include/common/aglShaderEnum.h | 34 ++ include/utility/aglResCommon.h | 43 --- include/utility/aglResParameter.h | 4 +- src/utility/aglParameterIO.cpp | 8 +- src/utility/aglResParameter.cpp | 11 +- src/utility/{ => common}/aglResCommon.cpp | 2 +- src/utility/common/aglResShaderArchive.cpp | 384 +++++++++++++++++++++ 20 files changed, 1042 insertions(+), 64 deletions(-) create mode 100644 include/common/aglResBinaryShaderArchive.h create mode 100644 include/common/aglResBinaryShaderProgram.h create mode 100644 include/common/aglResCommon.h create mode 100644 include/common/aglResShaderArchive.h create mode 100644 include/common/aglResShaderBinary.h create mode 100644 include/common/aglResShaderMacro.h create mode 100644 include/common/aglResShaderProgram.h create mode 100644 include/common/aglResShaderSource.h create mode 100644 include/common/aglResShaderSymbol.h create mode 100644 include/common/aglResShaderVariation.h create mode 100644 include/common/aglShaderEnum.h delete mode 100644 include/utility/aglResCommon.h rename src/utility/{ => common}/aglResCommon.cpp (93%) create mode 100644 src/utility/common/aglResShaderArchive.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 30ac9c5..63921bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,19 @@ add_library(agl OBJECT include/common/aglGPUMemBlock.h include/common/aglRenderBuffer.h include/common/aglRenderTarget.h + include/common/aglResBinaryShaderArchive.h + include/common/aglResBinaryShaderProgram.h + include/common/aglResCommon.h + include/common/aglResShaderArchive.h + include/common/aglResShaderBinary.h + include/common/aglResShaderMacro.h + include/common/aglResShaderProgram.h + include/common/aglResShaderSource.h + include/common/aglResShaderSymbol.h + include/common/aglResShaderVariation.h include/common/aglShader.h include/common/aglShaderCompileInfo.h + include/common/aglShaderEnum.h include/common/aglShaderProgram.h include/common/aglShaderProgramArchive.h include/common/aglTextureData.h @@ -58,7 +69,6 @@ add_library(agl OBJECT include/utility/aglParameterList.h include/utility/aglParameterObj.h include/utility/aglParameterStringMgr.h - include/utility/aglResCommon.h include/utility/aglResParameter.h include/utility/aglScreenShotMgr.h @@ -73,8 +83,10 @@ add_library(agl OBJECT src/utility/aglParameterList.cpp src/utility/aglParameterObj.cpp src/utility/aglParameterStringMgr.cpp - src/utility/aglResCommon.cpp src/utility/aglResParameter.cpp + + src/utility/common/aglResCommon.cpp + src/utility/common/aglResShaderArchive.cpp ) target_compile_options(agl PRIVATE -fno-exceptions) diff --git a/include/common/aglResBinaryShaderArchive.h b/include/common/aglResBinaryShaderArchive.h new file mode 100644 index 0000000..0bd6e7a --- /dev/null +++ b/include/common/aglResBinaryShaderArchive.h @@ -0,0 +1,65 @@ +#pragma once + +#include "common/aglResBinaryShaderProgram.h" +#include "common/aglResShaderBinary.h" +#include "common/aglResShaderProgram.h" + +namespace agl { + +struct ResBinaryShaderArchiveData { + union { + char mSignature[4]; + u32 mSigWord; + }; + u32 mVersion; + u32 mFileSize; + u32 mEndian; + u32 mResolved; + u32 mNameLen; + // char mName[]; + +public: + static u32 getVersion(); + static u32 getSignature(); + static const char* getExtension(); + +private: + static const u32 cVersion = 8; + static const u32 cSignature = 0x53484142; // SHAB + static const u32 cEndianCheckBit = 0x01000001; + + friend class ResCommon; + friend class ResBinaryShaderArchive; +}; +static_assert(sizeof(ResBinaryShaderArchiveData) == 0x18, + "agl::ResBinaryShaderArchiveData size mismatch"); + +class ResBinaryShaderArchive : public ResCommon { + AGL_RES_FILE_HEADER() + +public: + using ResCommon::ResCommon; + + const char* getName() const { + const DataType* const data = ptr(); + return (const char*)(data + 1); + } + + ResShaderBinaryArray getResShaderBinaryArray() const { + const DataType* const data = ptr(); + return (const ResShaderBinaryArrayData*)((uintptr_t)(data + 1) + data->mNameLen); + } + + s32 getResShaderBinaryNum() const { return getResShaderBinaryArray().getNum(); } + + ResBinaryShaderProgramArray getResBinaryShaderProgramArray() const { + const ResShaderBinaryArrayData* const data = getResShaderBinaryArray().ptr(); + return (const ResBinaryShaderProgramArrayData*)((uintptr_t)data + data->mSize); + } + + s32 getResBinaryShaderProgramNum() const { return getResBinaryShaderProgramArray().getNum(); } + + bool setUp(bool le_resolve_pointers); +}; + +} // namespace agl diff --git a/include/common/aglResBinaryShaderProgram.h b/include/common/aglResBinaryShaderProgram.h new file mode 100644 index 0000000..95142f9 --- /dev/null +++ b/include/common/aglResBinaryShaderProgram.h @@ -0,0 +1,43 @@ +#pragma once + +#include "common/aglResShaderSymbol.h" +#include "common/aglResShaderVariation.h" + +namespace agl { + +struct ResBinaryShaderProgramData { + u32 mSize; + u32 mNameLen; + u32 mKind; + u32 mBaseIndex; + // char mName[]; +}; +static_assert(sizeof(ResBinaryShaderProgramData) == 0x10, + "agl::ResBinaryShaderProgramData size mismatch"); + +class ResBinaryShaderProgram : public ResCommon { +public: + using ResCommon::ResCommon; + + const char* getName() const { return (const char*)(ptr() + 1); } + + ResShaderVariationArray getResShaderVariationArray() const { + const DataType* const data = ptr(); + return (const ResShaderVariationArrayData*)((uintptr_t)(data + 1) + data->mNameLen); + } + + ResShaderVariationArray getResShaderVariationDefaultArray() const { + const ResShaderVariationArrayData* const data = getResShaderVariationArray().ptr(); + return (const ResShaderVariationArrayData*)((uintptr_t)data + data->mSize); + } + + ResShaderSymbolArray getResShaderSymbolArray(ShaderSymbolType type) const; +}; + +using ResBinaryShaderProgramArray = ResArray; + +using ResBinaryShaderProgramArrayData = ResBinaryShaderProgramArray::DataType; +static_assert(sizeof(ResBinaryShaderProgramArrayData) == 8, + "agl::ResBinaryShaderProgramArrayData size mismatch"); + +} // namespace agl diff --git a/include/common/aglResCommon.h b/include/common/aglResCommon.h new file mode 100644 index 0000000..db574fd --- /dev/null +++ b/include/common/aglResCommon.h @@ -0,0 +1,187 @@ +#pragma once + +#include +#include + +namespace agl { + +// maybe first parameter is is_le, maybe it is big_endian - different between decomps +void ModifyEndianU32(bool is_le, void* p_data, size_t size); + +template +class ResCommon { +public: + using DataType = DataType_; + + ResCommon() : mpData(nullptr) {} + + ResCommon(const void* data) : mpData(static_cast(data)) {} + + bool isValid() const { return mpData != nullptr; } + + void verify() const { + if (isValidMagic()) { + const char* b = reinterpret_cast(mpData); + SEAD_ASSERT_MSG(false, "Wrong binary. [%c%c%c%c].", b[0], b[1], b[2], b[3]); + } + + if (isValidVersion()) { + SEAD_ASSERT_MSG(false, "Version error.current:%d binary:%d", DataType::getVersion(), + sead::BitUtil::bitCastPtr(ptr(), 4)); + } + } + + DataType* ptr() { + assertValid(); + return const_cast(mpData); + } + + const DataType* ptr() const { + assertValid(); + return mpData; + } + + u8* ptrBytes() const { return const_cast(reinterpret_cast(mpData)); } + + DataType& ref() { + assertValid(); + return *ptr(); + } + + const DataType& ref() const { + assertValid(); + return *ptr(); + } + + bool isValidMagic() const { + return sead::BitUtil::bitCastPtr(ptr(), 0) == DataType::getSignature(); + } + + bool isValidVersion() const { + return sead::BitUtil::bitCastPtr(ptr(), 4) == DataType::getVersion(); + } + + void assertValid() const { SEAD_ASSERT(isValid()); } + +protected: + const DataType* mpData; +}; + +#define AGL_RES_FILE_HEADER() \ +public: \ + bool modifyEndian() const { return ref().mEndian & DataType::cEndianCheckBit; } \ + \ + bool isEndianResolved() const { return !modifyEndian(); } \ + \ + void setEndianResolved() { ref().mEndian = 1 - ref().mEndian; } + +template +struct ResArrayData { + s32 mSize; + u32 mNum; + // DataType mData[]; + + using ElemType = DataType; +}; + +template +class ResArray : public ResCommon> { +public: + using ElemType = Type; + using ElemDataType = typename Type::DataType; + using DataType = typename ResArray::DataType; + using Base = ResCommon; + + using ResCommon::ResCommon; + +public: + class iterator { + public: + iterator(s32 index, ElemDataType* elem) : mIndex(index), mElem(elem) {} + + friend bool operator==(const iterator& lhs, const iterator& rhs) { + return lhs.mIndex == rhs.mIndex; + } + + friend bool operator!=(const iterator& lhs, const iterator& rhs) { + return lhs.mIndex != rhs.mIndex; + } + + iterator& operator++() { + ++mIndex; + mElem = (ElemDataType*)((uintptr_t)mElem + Type(mElem).ref().mSize); + return *this; + } + + ElemDataType& operator*() const { return *mElem; } + ElemDataType* operator->() const { return mElem; } + s32 getIndex() const { return mIndex; } + + private: + s32 mIndex; + ElemDataType* mElem; + }; + + class constIterator { + public: + constIterator(s32 index, const ElemDataType* elem) : mIndex(index), mElem(elem) {} + + friend bool operator==(const constIterator& lhs, const constIterator& rhs) { + return lhs.mIndex == rhs.mIndex; + } + + friend bool operator!=(const constIterator& lhs, const constIterator& rhs) { + return lhs.mIndex != rhs.mIndex; + } + + constIterator& operator++() { + ++mIndex; + mElem = (const ElemDataType*)((uintptr_t)mElem + Type(mElem).ref().mSize); + return *this; + } + + const ElemDataType& operator*() const { return *mElem; } + const ElemDataType* operator->() const { return mElem; } + s32 getIndex() const { return mIndex; } + + private: + s32 mIndex; + const ElemDataType* mElem; + }; + +public: + iterator begin() { return iterator(0, (ElemDataType*)(Base::ptr() + 1)); } + constIterator begin() const { return constIterator(0, (const ElemDataType*)(Base::ptr() + 1)); } + constIterator constBegin() const { + return constIterator(0, (const ElemDataType*)(Base::ptr() + 1)); + } + + iterator end() { return iterator(getNum(), nullptr); } + constIterator end() const { return constIterator(getNum(), nullptr); } + constIterator constEnd() const { return constIterator(getNum(), nullptr); } + +public: + u32 getNum() const { return Base::ref().mNum; } + + ElemType get(s32 n) const { + // clang-format off + SEAD_ASSERT(0 <= n && n <= static_cast< int >( this->getNum() )); + // clang-format on + + constIterator itr = constBegin(); + constIterator itr_end = constIterator(n, nullptr); + + while (itr != itr_end) + ++itr; + + return &(*itr); + } + + void modifyEndianArray(bool is_le) { + ModifyEndianU32(is_le, Base::ptr(), sizeof(DataType)); + + for (iterator it = begin(), it_end = end(); it != it_end; ++it) + ModifyEndianU32(is_le, &(*it), sizeof(ElemDataType)); + } +}; +} // namespace agl diff --git a/include/common/aglResShaderArchive.h b/include/common/aglResShaderArchive.h new file mode 100644 index 0000000..a212de3 --- /dev/null +++ b/include/common/aglResShaderArchive.h @@ -0,0 +1,68 @@ +#pragma once + +#include "common/aglResCommon.h" +#include "common/aglResShaderProgram.h" +#include "common/aglResShaderSource.h" + +namespace agl { + +struct ResShaderArchiveData { + union { + char mSignature[4]; + u32 mSigWord; + }; + u32 mVersion; + u32 mFileSize; + u32 mEndian; + u32 mNameLen; + // char mName[]; + +public: + static u32 getVersion(); + static u32 getSignature(); + static const char* getExtension(); + +private: + static const u32 cVersion = 11; + static const u32 cSignature = 0x53484141; // SHAA +#ifdef cafe + static const u32 cEndianCheckBit = 0x01000001; +#endif +#ifdef SWITCH + static const u32 cEndianCheckBit = 0x00000001; +#endif + + friend class ResCommon; + friend class ResShaderArchive; +}; +static_assert(sizeof(ResShaderArchiveData) == 0x14, "agl::ResShaderArchiveData size mismatch"); + +class ResShaderArchive : public ResCommon { + AGL_RES_FILE_HEADER() + +public: + using ResCommon::ResCommon; + + const char* getName() const { + const DataType* const data = ptr(); + return (const char*)(data + 1); + } + + ResShaderProgramArray getResShaderProgramArray() const { + const DataType* const data = ptr(); + return (const ResShaderProgramArrayData*)((uintptr_t)(data + 1) + data->mNameLen); + } + + s32 getResShaderProgramNum() const { return getResShaderProgramArray().getNum(); } + + ResShaderSourceArray getResShaderSourceArray() const { + const ResShaderProgramArrayData* const data = getResShaderProgramArray().ptr(); + return (const ResShaderSourceArrayData*)((uintptr_t)data + data->mSize); + } + + s32 getResShaderSourceNum() const { return getResShaderSourceArray().getNum(); } + + bool setUp(); +}; + +} // namespace agl diff --git a/include/common/aglResShaderBinary.h b/include/common/aglResShaderBinary.h new file mode 100644 index 0000000..23b0b89 --- /dev/null +++ b/include/common/aglResShaderBinary.h @@ -0,0 +1,36 @@ +#pragma once + +#include "common/aglResCommon.h" +#include "common/aglShaderEnum.h" + +namespace agl { + +struct ResShaderBinaryData { + u32 mSize; + u32 mShaderType; + s32 mDataOffset; // Relative to end of struct + u32 mDataSize; +}; +static_assert(sizeof(ResShaderBinaryData) == 0x10, "agl::ResShaderBinaryData size mismatch"); + +class ResShaderBinary : public ResCommon { +public: + using ResCommon::ResCommon; + + ShaderType getShaderType() const { return ShaderType(ref().mShaderType); } + + void* getData() const { + const DataType* const data = ptr(); + return (void*)((uintptr_t)(data + 1) + data->mDataOffset); + } + + void modifyBinaryEndian(); + void setUp(); +}; + +using ResShaderBinaryArray = ResArray; + +using ResShaderBinaryArrayData = ResShaderBinaryArray::DataType; +static_assert(sizeof(ResShaderBinaryArrayData) == 8, "agl::ResShaderBinaryArrayData size mismatch"); + +} // namespace agl diff --git a/include/common/aglResShaderMacro.h b/include/common/aglResShaderMacro.h new file mode 100644 index 0000000..91e2bbd --- /dev/null +++ b/include/common/aglResShaderMacro.h @@ -0,0 +1,29 @@ +#pragma once + +#include "common/aglResCommon.h" + +namespace agl { + +struct ResShaderMacroData { + u32 mSize; + u32 mNameLen; + u32 mValueLen; + // char mName[]; +}; +static_assert(sizeof(ResShaderMacroData) == 0xC, "agl::ResShaderMacroData size mismatch"); + +class ResShaderMacro : public ResCommon { +public: + using ResCommon::ResCommon; + + const char* getName() const { return (const char*)(ptr() + 1); } + + const char* getValue() const { return getName() + ptr()->mNameLen; } +}; + +using ResShaderMacroArray = ResArray; + +using ResShaderMacroArrayData = ResShaderMacroArray::DataType; +static_assert(sizeof(ResShaderMacroArrayData) == 8, "agl::ResShaderMacroArrayData size mismatch"); + +} // namespace agl diff --git a/include/common/aglResShaderProgram.h b/include/common/aglResShaderProgram.h new file mode 100644 index 0000000..fddfa34 --- /dev/null +++ b/include/common/aglResShaderProgram.h @@ -0,0 +1,46 @@ +#pragma once + +#include "common/aglResShaderMacro.h" +#include "common/aglResShaderSymbol.h" +#include "common/aglResShaderVariation.h" + +namespace agl { + +struct ResShaderProgramData { + u32 mSize; + u32 mNameLen; + s32 mSourceIndex[cShaderType_Num]; + // char mName[]; +}; +#ifdef SWITCH +static_assert(sizeof(ResShaderProgramData) == 0x18, "agl::ResShaderProgramData size mismatch"); +#endif +#ifdef cafe +static_assert(sizeof(ResShaderProgramData) == 0x14, "agl::ResShaderProgramData size mismatch"); +#endif + +class ResShaderProgram : public ResCommon { +public: + using ResCommon::ResCommon; + + const char* getName() const { return (const char*)(ptr() + 1); } + + ResShaderMacroArray getResShaderMacroArray(ShaderType type) const; + + ResShaderVariationArray getResShaderVariationArray() const; + + ResShaderVariationArray getResShaderVariationDefaultArray() const { + return (const ResShaderVariationArrayData*)((uintptr_t)getResShaderVariationArray().ptr() + + getResShaderVariationArray().ref().mSize); + } + + ResShaderSymbolArray getResShaderSymbolArray(ShaderSymbolType type) const; +}; + +using ResShaderProgramArray = ResArray; + +using ResShaderProgramArrayData = ResShaderProgramArray::DataType; +static_assert(sizeof(ResShaderProgramArrayData) == 8, + "agl::ResShaderProgramArrayData size mismatch"); + +} // namespace agl diff --git a/include/common/aglResShaderSource.h b/include/common/aglResShaderSource.h new file mode 100644 index 0000000..fdd6604 --- /dev/null +++ b/include/common/aglResShaderSource.h @@ -0,0 +1,30 @@ +#pragma once + +#include "common/aglResCommon.h" + +namespace agl { + +struct ResShaderSourceData { + u32 mSize; + u32 mNameLen; + u32 mTextLen; // Text Length + u32 _c; // Text Length... 2 + // char mName[]; +}; +static_assert(sizeof(ResShaderSourceData) == 0x10, "agl::ResShaderSourceData size mismatch"); + +class ResShaderSource : public ResCommon { +public: + using ResCommon::ResCommon; + + const char* getName() const { return (const char*)(ptr() + 1); } + + const char* getText() const { return getName() + ptr()->mNameLen; } +}; + +using ResShaderSourceArray = ResArray; + +using ResShaderSourceArrayData = ResShaderSourceArray::DataType; +static_assert(sizeof(ResShaderSourceArrayData) == 8, "agl::ResShaderSourceArrayData size mismatch"); + +} // namespace agl diff --git a/include/common/aglResShaderSymbol.h b/include/common/aglResShaderSymbol.h new file mode 100644 index 0000000..763520f --- /dev/null +++ b/include/common/aglResShaderSymbol.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include "common/aglResCommon.h" +#include "common/aglShaderEnum.h" + +namespace agl { + +struct ResShaderSymbolData { + u32 mSize; + s32 mOffset; + u32 mNameLen; + u32 mIDLen; + u32 mDefaultValueSize; + u32 mVariationNum; + // char mName[]; +}; +static_assert(sizeof(ResShaderSymbolData) == 0x18, "agl::ResShaderSymbolData size mismatch"); + +class ResShaderSymbol : public ResCommon { +public: + using ResCommon::ResCommon; + + const char* getName() const { + const DataType* const data = ptr(); + return (const char*)(data + 1); + } + + const char* getID() const { + const DataType* const data = ptr(); + return (const char*)((uintptr_t)(data + 1) + data->mNameLen); + } + + void* getDefaultValue() const { + const DataType* const data = ptr(); + return (void*)((uintptr_t)(data + 1) + data->mNameLen + data->mIDLen); + } + + const u8* getVariationEnableArray() const { + const DataType* const data = ptr(); + return (const u8*)((uintptr_t)(data + 1) + data->mNameLen + data->mIDLen + + data->mDefaultValueSize); + } + + bool isVariationEnable(s32 index) const { return getVariationEnableArray()[index]; } +}; + +class ResShaderSymbolArray : public ResArray { +public: + using ResArray::ResArray; + + ResShaderSymbol searchResShaderSymbolByID(const sead::SafeString& id) const; +}; + +using ResShaderSymbolArrayData = ResShaderSymbolArray::DataType; +static_assert(sizeof(ResShaderSymbolArrayData) == 8, "agl::ResShaderSymbolArrayData size mismatch"); + +} // namespace agl diff --git a/include/common/aglResShaderVariation.h b/include/common/aglResShaderVariation.h new file mode 100644 index 0000000..fe16be0 --- /dev/null +++ b/include/common/aglResShaderVariation.h @@ -0,0 +1,32 @@ +#pragma once + +#include "common/aglResCommon.h" + +namespace agl { + +struct ResShaderVariationData { + u32 mSize; + u32 mNameLen; + s32 mValueNum; + u32 mIDLen; + // char name[]; +}; +static_assert(sizeof(ResShaderVariationData) == 0x10, "agl::ResShaderVariationData size mismatch"); + +class ResShaderVariation : public ResCommon { +public: + using ResCommon::ResCommon; + + const char* getName() const { return (const char*)(ptr() + 1); } + + const char* getID() const; + const char* getValue(s32 index) const; +}; + +using ResShaderVariationArray = ResArray; + +using ResShaderVariationArrayData = ResShaderVariationArray::DataType; +static_assert(sizeof(ResShaderVariationArrayData) == 8, + "agl::ResShaderVariationArrayData size mismatch"); + +} // namespace agl diff --git a/include/common/aglShader.h b/include/common/aglShader.h index bd431f7..b312f1e 100644 --- a/include/common/aglShader.h +++ b/include/common/aglShader.h @@ -4,13 +4,6 @@ namespace agl { -enum ShaderType { - ShaderType_Vertex = 0, - ShaderType_Fragment = 1, - ShaderType_Geometry = 2, - ShaderType_Compute = 3 -}; - class Shader { public: Shader(); diff --git a/include/common/aglShaderCompileInfo.h b/include/common/aglShaderCompileInfo.h index b815c2f..9222ebe 100644 --- a/include/common/aglShaderCompileInfo.h +++ b/include/common/aglShaderCompileInfo.h @@ -3,11 +3,14 @@ #include #include #include "common/aglShader.h" +#include "common/aglShaderEnum.h" namespace sead { class Heap; } +// more information: +// https://github.com/aboood40091/sead/blob/master/packages/agl/include/common/aglShaderCompileInfo.h namespace agl { class ShaderCompileInfo : public sead::hostio::Node { diff --git a/include/common/aglShaderEnum.h b/include/common/aglShaderEnum.h new file mode 100644 index 0000000..4d9568e --- /dev/null +++ b/include/common/aglShaderEnum.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +namespace agl { + +// No idea which headers these are actually supposed to go in + +enum ShaderType { + cShaderType_Vertex, + cShaderType_Fragment, + cShaderType_Geometry, +#ifdef SWITCH + cShaderType_Compute, +#endif + cShaderType_Num +}; + +enum ShaderSymbolType { + cShaderSymbolType_Uniform, + cShaderSymbolType_UniformBlock, + cShaderSymbolType_Sampler, + cShaderSymbolType_Attribute, + cShaderSymbolType_Num, +}; + +enum ShaderMode { + cShaderMode_UniformRegister, + cShaderMode_UniformBlock, + cShaderMode_GeometryShader, + cShaderMode_Invalid +}; + +} // namespace agl diff --git a/include/utility/aglResCommon.h b/include/utility/aglResCommon.h deleted file mode 100644 index 4c8be7f..0000000 --- a/include/utility/aglResCommon.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include - -namespace agl { - -template -struct ResCommon { - bool isValid() const { return mPtr != nullptr; } - - ResDataType* ptr() const { - assertValid(); - return mPtr; - } - - u8* ptrBytes() const { return reinterpret_cast(mPtr); } - - bool isValidMagic() const { - return sead::BitUtil::bitCastPtr(ptr(), 0) == ResDataType::getSignature(); - } - - bool isValidVersion() const { - return sead::BitUtil::bitCastPtr(ptr(), 4) == ResDataType::getVersion(); - } - - void assertValid() const { SEAD_ASSERT(isValid()); } - - // NON_MATCHING: weird control flow - void verify() const { - char* b = reinterpret_cast(mPtr); - assertValid(); - SEAD_ASSERT_MSG(isValidMagic(), "Wrong binary. [%c%c%c%c].", b[0], b[1], b[2], b[3]); - SEAD_ASSERT_MSG(isValidVersion(), "Version error.current:%d binary:%d", - ResDataType::getVersion(), sead::BitUtil::bitCastPtr(ptr(), 4)); - } - - ResDataType* mPtr; -}; - -void ModifyEndianU32(bool big_endian, void* p_data, size_t size); - -} // namespace agl diff --git a/include/utility/aglResParameter.h b/include/utility/aglResParameter.h index fdb7670..a91ed53 100644 --- a/include/utility/aglResParameter.h +++ b/include/utility/aglResParameter.h @@ -4,7 +4,7 @@ #include #include #include -#include "utility/aglResCommon.h" +#include "common/aglResCommon.h" namespace sead { template @@ -259,7 +259,7 @@ struct ResParameterArchive : ResCommon { ResParameterList getRootList() const { return {reinterpret_cast( - ptrBytes() + sizeof(ResParameterArchiveData) + mPtr->offset_to_pio)}; + ptrBytes() + sizeof(ResParameterArchiveData) + ptr()->offset_to_pio)}; } }; diff --git a/src/utility/aglParameterIO.cpp b/src/utility/aglParameterIO.cpp index dfeede5..0ef6955 100644 --- a/src/utility/aglParameterIO.cpp +++ b/src/utility/aglParameterIO.cpp @@ -19,9 +19,9 @@ IParameterIO::IParameterIO(const sead::SafeString& name, u32 version) { void IParameterIO::applyResParameterArchive(ResParameterArchive arc) { SEAD_ASSERT(arc.isValid()); - mResFileSize = arc.mPtr->file_size; + mResFileSize = arc.ptr()->file_size; - if (mVersion != arc.mPtr->pio_version) + if (mVersion != arc.ptr()->pio_version) callbackInvalidVersion_(arc); applyResParameterList(arc.getRootList()); @@ -32,10 +32,10 @@ void IParameterIO::applyResParameterArchiveLerp(ResParameterArchive arc_a, SEAD_ASSERT(arc_a.isValid()); SEAD_ASSERT(arc_b.isValid()); - if (mVersion != arc_a.mPtr->pio_version) + if (mVersion != arc_a.ptr()->pio_version) callbackInvalidVersion_(arc_a); - if (mVersion != arc_b.mPtr->pio_version) + if (mVersion != arc_b.ptr()->pio_version) callbackInvalidVersion_(arc_b); applyResParameterList(arc_a.getRootList(), arc_b.getRootList(), t); diff --git a/src/utility/aglResParameter.cpp b/src/utility/aglResParameter.cpp index f80f708..3afc4f4 100644 --- a/src/utility/aglResParameter.cpp +++ b/src/utility/aglResParameter.cpp @@ -72,18 +72,19 @@ s32 ResParameterList::searchObjIndex(u32 obj_hash) const { // NON_MATCHING: partial implementation (unused conversion code is unimplemented) ResParameterArchive::ResParameterArchive(const void* p_data) { - mPtr = static_cast(const_cast(p_data)); + mpData = static_cast(const_cast(p_data)); if (!p_data) return; SEAD_ASSERT(sead::PtrUtil::isAlignedN(p_data, 4)); - if (mPtr->flags.isOff(ResParameterArchiveFlag::LittleEndian)) - ModifyEndianU32(false, mPtr, sizeof(ResParameterArchiveData)); + if (mpData->flags.isOff(ResParameterArchiveFlag::LittleEndian)) + ModifyEndianU32(false, const_cast(mpData), + sizeof(ResParameterArchiveData)); verify(); - if (mPtr->flags.isOn(ResParameterArchiveFlag::LittleEndian) && - mPtr->flags.isOn(ResParameterArchiveFlag::Utf8)) { + if (mpData->flags.isOn(ResParameterArchiveFlag::LittleEndian) && + mpData->flags.isOn(ResParameterArchiveFlag::Utf8)) { // Nothing else to do. return; } diff --git a/src/utility/aglResCommon.cpp b/src/utility/common/aglResCommon.cpp similarity index 93% rename from src/utility/aglResCommon.cpp rename to src/utility/common/aglResCommon.cpp index 2d70579..31eb12c 100644 --- a/src/utility/aglResCommon.cpp +++ b/src/utility/common/aglResCommon.cpp @@ -1,4 +1,4 @@ -#include "utility/aglResCommon.h" +#include "common/aglResCommon.h" #include #include diff --git a/src/utility/common/aglResShaderArchive.cpp b/src/utility/common/aglResShaderArchive.cpp new file mode 100644 index 0000000..93a9cb4 --- /dev/null +++ b/src/utility/common/aglResShaderArchive.cpp @@ -0,0 +1,384 @@ +#include "common/aglResShaderArchive.h" +#include +#include "common/aglResBinaryShaderArchive.h" +#include "common/aglResShaderBinary.h" +#include "common/aglResShaderSymbol.h" +#include "common/aglResShaderVariation.h" +#include "common/aglShader.h" + +#ifdef cafe +#include +#endif // cafe + +static inline void swap32(void* ptr, size_t size) { + u32* ptr_u32 = static_cast(ptr); + u32 count = size / sizeof(u32); + + for (u32 i = 0; i < count; i++) { + *ptr_u32 = sead::Endian::swapU32(*ptr_u32); + ptr_u32++; + } +} + +namespace { + +void modifyEndianResSymbolArray(bool is_le, agl::ResShaderSymbolArray symbol_array, + agl::ShaderSymbolType type) { + symbol_array.modifyEndianArray(is_le); + + if (type != agl::cShaderSymbolType_UniformBlock) + for (agl::ResShaderSymbolArray::iterator it = symbol_array.begin(), + it_end = symbol_array.end(); + it != it_end; ++it) + agl::ModifyEndianU32(is_le, agl::ResShaderSymbol(&(*it)).getDefaultValue(), + it->mDefaultValueSize); +} + +#ifdef cafe + +template +T* modifyBinaryAndNamePtr(void* base_ptr, T* ptr, s32 num) { + if (!ptr) + return nullptr; + + ptr = (T*)(uintptr_t(base_ptr) + uintptr_t(ptr)); + + for (s32 i = 0; i < num; i++) + ptr[i].name += uintptr_t(base_ptr); + + return ptr; +} + +void* modifyBinaryPtr(void* base_ptr, void* ptr) { + return (void*)(uintptr_t(base_ptr) + uintptr_t(ptr)); +} + +#endif // cafe + +} // namespace + +namespace agl { + +void ResShaderBinary::modifyBinaryEndian() { + size_t size = 0; + void* data = nullptr; + +#ifdef cafe + switch (getShaderType()) { + case cShaderType_Vertex: { + GX2VertexShader* vertex_shader = static_cast(getData()); + swap32(vertex_shader, sizeof(GX2VertexShader)); + + size += vertex_shader->numUniformBlocks * sizeof(GX2UniformBlock) + + vertex_shader->numUniforms * sizeof(GX2UniformVar) + + vertex_shader->numInitialValues * sizeof(GX2UniformInitialValue) + + vertex_shader->numSamplers * sizeof(GX2SamplerVar) + + vertex_shader->numAttribs * sizeof(GX2AttribVar); + + data = vertex_shader + 1; + } break; + case cShaderType_Fragment: { + GX2PixelShader* pixel_shader = static_cast(getData()); + swap32(pixel_shader, sizeof(GX2PixelShader)); + + size += pixel_shader->numUniformBlocks * sizeof(GX2UniformBlock) + + pixel_shader->numUniforms * sizeof(GX2UniformVar) + + pixel_shader->numInitialValues * sizeof(GX2UniformInitialValue) + + pixel_shader->numSamplers * sizeof(GX2SamplerVar); + + data = pixel_shader + 1; + } break; + case cShaderType_Geometry: { + GX2GeometryShader* geometry_shader = static_cast(getData()); + swap32(geometry_shader, sizeof(GX2GeometryShader)); + + size += geometry_shader->numUniformBlocks * sizeof(GX2UniformBlock) + + geometry_shader->numUniforms * sizeof(GX2UniformVar) + + geometry_shader->numInitialValues * sizeof(GX2UniformInitialValue) + + geometry_shader->numSamplers * sizeof(GX2SamplerVar); + + data = geometry_shader + 1; + } break; + } +#endif // cafe + + swap32(data, size); +} + +// unknown state, does not exist in SMO +void ResShaderBinary::setUp() { +#ifdef cafe + switch (getShaderType()) { + case cShaderType_Vertex: { + GX2VertexShader* vertex_shader = static_cast(getData()); + + vertex_shader->uniformBlocks = modifyBinaryAndNamePtr( + vertex_shader, vertex_shader->uniformBlocks, vertex_shader->numUniformBlocks); + vertex_shader->uniformVars = modifyBinaryAndNamePtr( + vertex_shader, vertex_shader->uniformVars, vertex_shader->numUniforms); + vertex_shader->samplerVars = modifyBinaryAndNamePtr( + vertex_shader, vertex_shader->samplerVars, vertex_shader->numSamplers); + vertex_shader->attribVars = modifyBinaryAndNamePtr( + vertex_shader, vertex_shader->attribVars, vertex_shader->numAttribs); + + vertex_shader->_loopVars = modifyBinaryPtr(vertex_shader, vertex_shader->_loopVars); + vertex_shader->shaderPtr = modifyBinaryPtr(vertex_shader, vertex_shader->shaderPtr); + } break; + case cShaderType_Fragment: { + GX2PixelShader* pixel_shader = static_cast(getData()); + + pixel_shader->uniformBlocks = modifyBinaryAndNamePtr( + pixel_shader, pixel_shader->uniformBlocks, pixel_shader->numUniformBlocks); + pixel_shader->uniformVars = modifyBinaryAndNamePtr( + pixel_shader, pixel_shader->uniformVars, pixel_shader->numUniforms); + pixel_shader->samplerVars = modifyBinaryAndNamePtr( + pixel_shader, pixel_shader->samplerVars, pixel_shader->numSamplers); + + pixel_shader->_loopVars = modifyBinaryPtr(pixel_shader, pixel_shader->_loopVars); + pixel_shader->shaderPtr = modifyBinaryPtr(pixel_shader, pixel_shader->shaderPtr); + } break; + case cShaderType_Geometry: { + GX2GeometryShader* geometry_shader = static_cast(getData()); + + geometry_shader->uniformBlocks = modifyBinaryAndNamePtr( + geometry_shader, geometry_shader->uniformBlocks, geometry_shader->numUniformBlocks); + geometry_shader->uniformVars = modifyBinaryAndNamePtr( + geometry_shader, geometry_shader->uniformVars, geometry_shader->numUniforms); + geometry_shader->samplerVars = modifyBinaryAndNamePtr( + geometry_shader, geometry_shader->samplerVars, geometry_shader->numSamplers); + + geometry_shader->_loopVars = modifyBinaryPtr(geometry_shader, geometry_shader->_loopVars); + geometry_shader->shaderPtr = modifyBinaryPtr(geometry_shader, geometry_shader->shaderPtr); + geometry_shader->copyShaderPtr = + modifyBinaryPtr(geometry_shader, geometry_shader->copyShaderPtr); + } break; + } +#endif // cafe +} + +const char* ResShaderVariation::getID() const { + const char* value = getName() + ref().mNameLen; + + for (s32 i = 0, index = static_cast(ref().mValueNum);; i++) { + while (*value == '\0') + value++; + + if (i == index) + break; + + while (*value != '\0') + value++; + } + + return value; +} + +const char* ResShaderVariation::getValue(s32 index) const { + // clang-format off + SEAD_ASSERT(0 <= index && index < static_cast< int >( ref().mValueNum )); + // clang-format on + + const char* value = getName() + ref().mNameLen; + + for (s32 i = 0;; i++) { + while (*value == '\0') + value++; + + if (i == index) + break; + + while (*value != '\0') + value++; + } + + return value; +} + +// unknown state, does not exist in SMO +ResShaderSymbol ResShaderSymbolArray::searchResShaderSymbolByID(const sead::SafeString& id) const { + for (constIterator it = begin(), it_end = end(); it != it_end; ++it) { + if (id.isEqual(ResShaderSymbol(&(*it)).getID())) + return &(*it); + } + + return nullptr; +} + +// NON_MATCHING: weird optimizations with bit magic to tell whether more than one loop iteration has +// to be done +ResShaderMacroArray ResShaderProgram::getResShaderMacroArray(ShaderType type) const { + const ResShaderMacroArrayData* macro_array; + { + const DataType* const data = ptr(); + macro_array = (const ResShaderMacroArrayData*)((uintptr_t)(data + 1) + data->mNameLen); + } + + for (s32 i = 0; i < type; i++) + macro_array = (const ResShaderMacroArrayData*)((uintptr_t)macro_array + macro_array->mSize); + + return macro_array; +} + +// NON_MATCHING: operand order in ADD +ResShaderVariationArray ResShaderProgram::getResShaderVariationArray() const { + const ResShaderMacroArrayData* macro_array; + { + const DataType* const data = ptr(); + macro_array = (const ResShaderMacroArrayData*)((uintptr_t)(data + 1) + data->mNameLen); + } + + for (s32 i = 0; i < cShaderType_Num; i++) + macro_array = (const ResShaderMacroArrayData*)((uintptr_t)macro_array + macro_array->mSize); + + return (const ResShaderVariationArrayData*)macro_array; +} + +// unknown state, does not exist in SMO +ResShaderSymbolArray ResShaderProgram::getResShaderSymbolArray(ShaderSymbolType type) const { + const ResShaderSymbolArrayData* symbol_array; + { + const ResShaderVariationArrayData* const data = getResShaderVariationDefaultArray().ptr(); + symbol_array = (const ResShaderSymbolArrayData*)((uintptr_t)data + data->mSize); + } + + for (s32 i = 0; i < type; i++) + symbol_array = + (const ResShaderSymbolArrayData*)((uintptr_t)symbol_array + symbol_array->mSize); + + return symbol_array; +} + +// unknown state, does not exist in SMO +ResShaderSymbolArray ResBinaryShaderProgram::getResShaderSymbolArray(ShaderSymbolType type) const { + const ResShaderSymbolArrayData* symbol_array; + { + const ResShaderVariationArrayData* const data = getResShaderVariationDefaultArray().ptr(); + symbol_array = (const ResShaderSymbolArrayData*)((uintptr_t)data + data->mSize); + } + + for (s32 i = 0; i < type; i++) + symbol_array = + (const ResShaderSymbolArrayData*)((uintptr_t)symbol_array + symbol_array->mSize); + + return symbol_array; +} + +// NON_MATCHING: heavily depends on the two (mismatching) functions above, probably a lot of +// mismatches carried over +bool ResShaderArchive::setUp() { +#ifdef cafe + SEAD_ASSERT(isValid()); +#endif + + if (!isEndianResolved()) { +#ifdef cafe + ModifyEndianU32(modifyEndian(), ptr(), sizeof(DataType)); + + verify(); +#endif +#ifdef SWITCH + ModifyEndianU32(false, ptr(), sizeof(DataType)); +#endif + + ResShaderProgramArray prog_arr = getResShaderProgramArray(); + prog_arr.modifyEndianArray(modifyEndian()); + + ResShaderSourceArray source_arr = getResShaderSourceArray(); + source_arr.modifyEndianArray(modifyEndian()); + + for (ResShaderProgramArray::iterator it = prog_arr.begin(), it_end = prog_arr.end(); + it != it_end; ++it) { + ResShaderProgram prog(&(*it)); + + for (s32 type = 0; type < cShaderType_Num; type++) + prog.getResShaderMacroArray(ShaderType(type)).modifyEndianArray(modifyEndian()); + + prog.getResShaderVariationArray().modifyEndianArray(modifyEndian()); + prog.getResShaderVariationDefaultArray().modifyEndianArray(modifyEndian()); + + for (s32 type = 0; type < cShaderSymbolType_Num; type++) + modifyEndianResSymbolArray(modifyEndian(), + prog.getResShaderSymbolArray(ShaderSymbolType(type)), + ShaderSymbolType(type)); + } + + setEndianResolved(); + } +#ifdef cafe + else { + verify(); + } +#endif + + return true; +} + +// NON_MATCHING: also heavily depends on the two (mismatching) functions above, probably a lot of +// mismatches carried over +bool ResBinaryShaderArchive::setUp(bool le_resolve_pointers) { + SEAD_ASSERT(isValid()); + + bool endian_resolved = isEndianResolved(); + + if (!endian_resolved) + ModifyEndianU32(modifyEndian(), ptr(), sizeof(DataType)); + + verify(); + + if (endian_resolved) { + if (ref().mResolved == 0) { + for (ResShaderBinaryArray::iterator it = getResShaderBinaryArray().begin(), + it_end = getResShaderBinaryArray().end(); + it != it_end; ++it) + ResShaderBinary(&(*it)).setUp(); + + ref().mResolved = 1; + } + } else { + ResShaderBinaryArray binary_arr = getResShaderBinaryArray(); + binary_arr.modifyEndianArray(modifyEndian()); + + ResBinaryShaderProgramArray binary_prog_arr = getResBinaryShaderProgramArray(); + binary_prog_arr.modifyEndianArray(modifyEndian()); + + for (ResBinaryShaderProgramArray::iterator it = binary_prog_arr.begin(), + it_end = binary_prog_arr.end(); + it != it_end; ++it) { + ResBinaryShaderProgram binary_prog(&(*it)); + + binary_prog.getResShaderVariationArray().modifyEndianArray(modifyEndian()); + binary_prog.getResShaderVariationDefaultArray().modifyEndianArray(modifyEndian()); + + for (s32 type = 0; type < cShaderSymbolType_Num; type++) + modifyEndianResSymbolArray( + modifyEndian(), binary_prog.getResShaderSymbolArray(ShaderSymbolType(type)), + ShaderSymbolType(type)); + } + + for (ResShaderBinaryArray::iterator it = binary_arr.begin(), it_end = binary_arr.end(); + it != it_end; ++it) { + ResShaderBinary binary(&(*it)); + binary.modifyBinaryEndian(); + + if (le_resolve_pointers && ref().mResolved == 0) + binary.setUp(); + } + + if (le_resolve_pointers) + ref().mResolved = 1; + + setEndianResolved(); + } + + return true; +} + +const char* ResShaderArchiveData::getExtension() { + return "sharc"; +} + +const char* ResBinaryShaderArchiveData::getExtension() { + return "sharcfb"; +} + +} // namespace agl