metaforce/hecl/include/hecl/Backend.hpp

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