mirror of https://github.com/AxioDL/metaforce.git
300 lines
9.2 KiB
C++
300 lines
9.2 KiB
C++
#pragma once
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <string_view>
|
|
#include <vector>
|
|
|
|
#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
|
|
#include <xxhash/xxhash.h>
|
|
|
|
#include "hecl.hpp"
|
|
|
|
namespace hecl::Backend {
|
|
struct ExtensionSlot;
|
|
using namespace std::literals;
|
|
|
|
enum class TexCoordSource : uint8_t {
|
|
Invalid = 0xff,
|
|
Position = 0,
|
|
Normal = 1,
|
|
Tex0 = 2,
|
|
Tex1 = 3,
|
|
Tex2 = 4,
|
|
Tex3 = 5,
|
|
Tex4 = 6,
|
|
Tex5 = 7,
|
|
Tex6 = 8,
|
|
Tex7 = 9,
|
|
};
|
|
|
|
enum class BlendFactor : uint8_t {
|
|
Zero,
|
|
One,
|
|
SrcColor,
|
|
InvSrcColor,
|
|
DstColor,
|
|
InvDstColor,
|
|
SrcAlpha,
|
|
InvSrcAlpha,
|
|
DstAlpha,
|
|
InvDstAlpha,
|
|
SrcColor1,
|
|
InvSrcColor1,
|
|
Original = 0xff
|
|
};
|
|
|
|
constexpr std::string_view BlendFactorToDefine(BlendFactor factor, BlendFactor defaultFactor) {
|
|
switch (factor) {
|
|
case BlendFactor::Zero:
|
|
return "ZERO"sv;
|
|
case BlendFactor::One:
|
|
return "ONE"sv;
|
|
case BlendFactor::SrcColor:
|
|
return "SRCCOLOR"sv;
|
|
case BlendFactor::InvSrcColor:
|
|
return "INVSRCCOLOR"sv;
|
|
case BlendFactor::DstColor:
|
|
return "DSTCOLOR"sv;
|
|
case BlendFactor::InvDstColor:
|
|
return "INVDSTCOLOR"sv;
|
|
case BlendFactor::SrcAlpha:
|
|
return "SRCALPHA"sv;
|
|
case BlendFactor::InvSrcAlpha:
|
|
return "INVSRCALPHA"sv;
|
|
case BlendFactor::DstAlpha:
|
|
return "DSTALPHA"sv;
|
|
case BlendFactor::InvDstAlpha:
|
|
return "INVDSTALPHA"sv;
|
|
case BlendFactor::SrcColor1:
|
|
return "SRCCOLOR1"sv;
|
|
case BlendFactor::InvSrcColor1:
|
|
return "INVSRCCOLOR1"sv;
|
|
default:
|
|
return BlendFactorToDefine(defaultFactor, BlendFactor::Zero);
|
|
}
|
|
}
|
|
|
|
enum class ZTest : uint8_t { None, LEqual, Greater, Equal, GEqual, Original = 0xff };
|
|
|
|
enum class CullMode : uint8_t { None, Backface, Frontface, Original = 0xff };
|
|
|
|
struct TextureInfo {
|
|
TexCoordSource src;
|
|
uint8_t mtxIdx;
|
|
bool normalize;
|
|
};
|
|
|
|
enum class ReflectionType { None, Simple, Indirect };
|
|
|
|
/**
|
|
* @brief Hash subclass for identifying shaders and their metadata
|
|
*/
|
|
class ShaderTag : public Hash {
|
|
union {
|
|
uint64_t m_meta = 0;
|
|
struct {
|
|
uint8_t m_colorCount;
|
|
uint8_t m_uvCount;
|
|
uint8_t m_weightCount;
|
|
uint8_t m_skinSlotCount;
|
|
uint8_t m_primitiveType;
|
|
uint8_t m_reflectionType;
|
|
bool m_depthTest : 1;
|
|
bool m_depthWrite : 1;
|
|
bool m_backfaceCulling : 1;
|
|
bool m_alphaTest : 1;
|
|
};
|
|
};
|
|
|
|
public:
|
|
ShaderTag() = default;
|
|
ShaderTag(std::string_view source, uint8_t c, uint8_t u, uint8_t w, uint8_t s, boo::Primitive pt,
|
|
Backend::ReflectionType reflectionType, bool depthTest, bool depthWrite, bool backfaceCulling,
|
|
bool alphaTest)
|
|
: Hash(source) {
|
|
m_colorCount = c;
|
|
m_uvCount = u;
|
|
m_weightCount = w;
|
|
m_skinSlotCount = s;
|
|
m_primitiveType = uint8_t(pt);
|
|
m_reflectionType = uint8_t(reflectionType);
|
|
m_depthTest = depthTest;
|
|
m_depthWrite = depthWrite;
|
|
m_backfaceCulling = backfaceCulling;
|
|
m_alphaTest = alphaTest;
|
|
hash ^= m_meta;
|
|
}
|
|
ShaderTag(uint64_t hashin, uint8_t c, uint8_t u, uint8_t w, uint8_t s, boo::Primitive pt,
|
|
Backend::ReflectionType reflectionType, bool depthTest, bool depthWrite, bool backfaceCulling,
|
|
bool alphaTest)
|
|
: Hash(hashin) {
|
|
m_colorCount = c;
|
|
m_uvCount = u;
|
|
m_weightCount = w;
|
|
m_skinSlotCount = s;
|
|
m_primitiveType = uint8_t(pt);
|
|
m_reflectionType = uint8_t(reflectionType);
|
|
m_depthTest = depthTest;
|
|
m_depthWrite = depthWrite;
|
|
m_backfaceCulling = backfaceCulling;
|
|
m_alphaTest = alphaTest;
|
|
hash ^= m_meta;
|
|
}
|
|
ShaderTag(uint64_t comphashin, uint64_t meta) : Hash(comphashin), m_meta(meta) {}
|
|
ShaderTag(const ShaderTag& other) : Hash(other), m_meta(other.m_meta) {}
|
|
uint8_t getColorCount() const { return m_colorCount; }
|
|
uint8_t getUvCount() const { return m_uvCount; }
|
|
uint8_t getWeightCount() const { return m_weightCount; }
|
|
uint8_t getSkinSlotCount() const { return m_skinSlotCount; }
|
|
boo::Primitive getPrimType() const { return boo::Primitive(m_primitiveType); }
|
|
Backend::ReflectionType getReflectionType() const { return Backend::ReflectionType(m_reflectionType); }
|
|
bool getDepthTest() const { return m_depthTest; }
|
|
bool getDepthWrite() const { return m_depthWrite; }
|
|
bool getBackfaceCulling() const { return m_backfaceCulling; }
|
|
bool getAlphaTest() const { return m_alphaTest; }
|
|
uint64_t getMetaData() const { return m_meta; }
|
|
|
|
std::vector<boo::VertexElementDescriptor> vertexFormat() const {
|
|
std::vector<boo::VertexElementDescriptor> ret;
|
|
size_t elemCount = 2 + m_colorCount + m_uvCount + m_weightCount;
|
|
ret.resize(elemCount);
|
|
|
|
ret[0].semantic = boo::VertexSemantic::Position3;
|
|
ret[1].semantic = boo::VertexSemantic::Normal3;
|
|
size_t e = 2;
|
|
|
|
for (size_t i = 0; i < m_colorCount; ++i, ++e) {
|
|
ret[e].semantic = boo::VertexSemantic::ColorUNorm;
|
|
ret[e].semanticIdx = i;
|
|
}
|
|
|
|
for (size_t i = 0; i < m_uvCount; ++i, ++e) {
|
|
ret[e].semantic = boo::VertexSemantic::UV2;
|
|
ret[e].semanticIdx = i;
|
|
}
|
|
|
|
for (size_t i = 0; i < m_weightCount; ++i, ++e) {
|
|
ret[e].semantic = boo::VertexSemantic::Weight;
|
|
ret[e].semanticIdx = i;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
boo::AdditionalPipelineInfo additionalInfo(const ExtensionSlot& ext,
|
|
std::pair<BlendFactor, BlendFactor> blendFactors) const;
|
|
};
|
|
|
|
struct Function {
|
|
std::string_view m_source;
|
|
std::string_view m_entry;
|
|
Function() = default;
|
|
Function(std::string_view source, std::string_view entry) : m_source(source), m_entry(entry) {}
|
|
};
|
|
|
|
struct ExtensionSlot {
|
|
const char* shaderMacro = nullptr;
|
|
size_t texCount = 0;
|
|
const Backend::TextureInfo* texs = nullptr;
|
|
Backend::BlendFactor srcFactor = Backend::BlendFactor::Original;
|
|
Backend::BlendFactor dstFactor = Backend::BlendFactor::Original;
|
|
Backend::ZTest depthTest = Backend::ZTest::Original;
|
|
Backend::CullMode cullMode = Backend::CullMode::Backface;
|
|
bool noDepthWrite = false;
|
|
bool noColorWrite = false;
|
|
bool noAlphaWrite = false;
|
|
bool noAlphaOverwrite = false;
|
|
bool noReflection = false;
|
|
bool forceAlphaTest = false;
|
|
bool diffuseOnly = false;
|
|
|
|
constexpr ExtensionSlot(size_t texCount = 0, const Backend::TextureInfo* texs = nullptr,
|
|
Backend::BlendFactor srcFactor = Backend::BlendFactor::Original,
|
|
Backend::BlendFactor dstFactor = Backend::BlendFactor::Original,
|
|
Backend::ZTest depthTest = Backend::ZTest::Original,
|
|
Backend::CullMode cullMode = Backend::CullMode::Backface, bool noDepthWrite = false,
|
|
bool noColorWrite = false, bool noAlphaWrite = false, bool noAlphaOverwrite = false,
|
|
bool noReflection = false, bool forceAlphaTest = false, bool diffuseOnly = false) noexcept
|
|
: texCount(texCount)
|
|
, texs(texs)
|
|
, srcFactor(srcFactor)
|
|
, dstFactor(dstFactor)
|
|
, depthTest(depthTest)
|
|
, cullMode(cullMode)
|
|
, noDepthWrite(noDepthWrite)
|
|
, noColorWrite(noColorWrite)
|
|
, noAlphaWrite(noAlphaWrite)
|
|
, noAlphaOverwrite(noAlphaOverwrite)
|
|
, noReflection(noReflection)
|
|
, forceAlphaTest(forceAlphaTest)
|
|
, diffuseOnly(diffuseOnly) {}
|
|
|
|
mutable uint64_t m_hash = 0;
|
|
void calculateHash() const {
|
|
XXH64_state_t st;
|
|
XXH64_reset(&st, 0);
|
|
XXH64_update(&st, shaderMacro, strlen(shaderMacro));
|
|
for (size_t i = 0; i < texCount; ++i) {
|
|
const Backend::TextureInfo& tinfo = texs[i];
|
|
XXH64_update(&st, &tinfo, sizeof(tinfo));
|
|
}
|
|
XXH64_update(&st, &srcFactor, offsetof(ExtensionSlot, m_hash) - offsetof(ExtensionSlot, srcFactor));
|
|
m_hash = XXH64_digest(&st);
|
|
}
|
|
uint64_t hash() const {
|
|
if (m_hash == 0)
|
|
calculateHash();
|
|
return m_hash;
|
|
}
|
|
};
|
|
|
|
inline boo::AdditionalPipelineInfo ShaderTag::additionalInfo(const ExtensionSlot& ext,
|
|
std::pair<BlendFactor, BlendFactor> blendFactors) const {
|
|
boo::ZTest zTest;
|
|
switch (ext.depthTest) {
|
|
case hecl::Backend::ZTest::Original:
|
|
default:
|
|
zTest = getDepthTest() ? boo::ZTest::LEqual : boo::ZTest::None;
|
|
break;
|
|
case hecl::Backend::ZTest::None:
|
|
zTest = boo::ZTest::None;
|
|
break;
|
|
case hecl::Backend::ZTest::LEqual:
|
|
zTest = boo::ZTest::LEqual;
|
|
break;
|
|
case hecl::Backend::ZTest::Greater:
|
|
zTest = boo::ZTest::Greater;
|
|
break;
|
|
case hecl::Backend::ZTest::Equal:
|
|
zTest = boo::ZTest::Equal;
|
|
break;
|
|
case hecl::Backend::ZTest::GEqual:
|
|
zTest = boo::ZTest::GEqual;
|
|
break;
|
|
}
|
|
|
|
BlendFactor srcFactor = m_alphaTest ? BlendFactor::One : blendFactors.first;
|
|
BlendFactor dstFactor = m_alphaTest ? BlendFactor::Zero : blendFactors.second;
|
|
return {boo::BlendFactor((ext.srcFactor == BlendFactor::Original) ? srcFactor : ext.srcFactor),
|
|
boo::BlendFactor((ext.dstFactor == BlendFactor::Original) ? dstFactor : ext.dstFactor),
|
|
getPrimType(),
|
|
zTest,
|
|
ext.noDepthWrite ? false : getDepthWrite(),
|
|
!ext.noColorWrite,
|
|
!ext.noAlphaWrite,
|
|
(ext.cullMode == hecl::Backend::CullMode::Original)
|
|
? (getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None)
|
|
: boo::CullMode(ext.cullMode),
|
|
!ext.noAlphaOverwrite};
|
|
}
|
|
|
|
} // namespace hecl::Backend
|
|
|
|
namespace std {
|
|
template <>
|
|
struct hash<hecl::Backend::ShaderTag> {
|
|
size_t operator()(const hecl::Backend::ShaderTag& val) const noexcept { return val.valSizeT(); }
|
|
};
|
|
} // namespace std
|