2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-10-04 19:19:37 +00:00
metaforce/hecl/include/hecl/Pipeline.hpp
2018-12-07 19:18:42 -10:00

604 lines
28 KiB
C++

#pragma once
#include <type_traits>
#include <cassert>
#include "hecl/hecl.hpp"
#include "hecl/Backend/GLSL.hpp"
#include "hecl/Backend/HLSL.hpp"
#include "hecl/Backend/Metal.hpp"
#include "PipelineBase.hpp"
/* CMake-curated rep classes for the application */
#include "ApplicationReps.hpp"
namespace hecl {
#if HECL_RUNTIME
template <typename P, typename S>
class StageRuntimeObject : public StageRep<P, S> {
boo::ObjToken<boo::IShaderStage> m_stage;
public:
static constexpr StageTargetType TargetType = StageTargetType::Runtime;
static constexpr PipelineTargetType PipelineTarget = PipelineTargetType::StageRuntimeCollection;
static constexpr bool HasHash = false;
StageRuntimeObject() = default;
StageRuntimeObject(StageConverter<P, S>& conv, FactoryCtx& ctx, const StageBinary<P, S>& in) {
m_stage = static_cast<typename P::Context&>(ctx).newShaderStage(in.data(), in.size(), S::Enum);
}
boo::ObjToken<boo::IShaderStage> stage() const { return m_stage; }
};
#endif
class HECLIR : public PipelineRep<PlatformType::Null> {
const hecl::Backend::IR& m_ir;
const hecl::Backend::ShaderTag& m_tag;
const hecl::Backend::ExtensionSlot& m_extension;
uint64_t m_hash;
public:
HECLIR(const hecl::Backend::IR& ir, const hecl::Backend::ShaderTag& tag,
const hecl::Backend::ExtensionSlot& extension)
: m_ir(ir), m_tag(tag), m_extension(extension) {
m_hash = tag.val64();
m_hash ^= extension.hash();
}
static constexpr bool HasHash = true;
uint64_t Hash() const { return m_hash; }
const hecl::Backend::IR& ir() const { return m_ir; }
const hecl::Backend::ShaderTag& tag() const { return m_tag; }
const hecl::Backend::ExtensionSlot& extension() const { return m_extension; }
};
template <typename P, class BackendTp>
class HECLBackendImpl : public PipelineRep<P> {
hecl::Backend::ShaderTag m_tag;
BackendTp m_backend;
const hecl::Backend::ExtensionSlot& m_extension;
public:
static constexpr bool HasHash = false;
HECLBackendImpl(PipelineConverter<P>& conv, FactoryCtx& ctx, const HECLIR& in)
: m_tag(in.tag()), m_extension(in.extension()) {
hecl::Backend::Diagnostics diag;
m_backend.reset(in.ir(), diag);
}
std::string makeVert() const {
return m_backend.makeVert(m_tag.getColorCount(), m_tag.getUvCount(), m_tag.getWeightCount(),
m_tag.getSkinSlotCount(), m_extension.texCount, m_extension.texs,
m_tag.getReflectionType());
}
std::string makeFrag() const {
return m_backend.makeFrag(m_extension.blockCount, m_extension.blockNames,
m_tag.getAlphaTest() || m_extension.forceAlphaTest, m_tag.getReflectionType(),
m_backend.m_blendSrc, m_backend.m_blendDst, m_extension.lighting, m_extension.post,
m_extension.texCount, m_extension.texs);
}
const hecl::Backend::ShaderTag& getTag() const { return m_tag; }
const hecl::Backend::ExtensionSlot& extension() const { return m_extension; }
std::pair<hecl::Backend::BlendFactor, hecl::Backend::BlendFactor> blendFactors() const {
return {m_backend.m_blendSrc, m_backend.m_blendDst};
}
};
template <typename P>
class HECLBackend : public PipelineRep<P> {
public:
static constexpr bool HasHash = false;
};
template <>
class HECLBackend<PlatformType::OpenGL> : public HECLBackendImpl<PlatformType::OpenGL, hecl::Backend::GLSL> {
public:
using HECLBackendImpl::HECLBackendImpl;
};
template <>
class HECLBackend<PlatformType::Vulkan> : public HECLBackendImpl<PlatformType::Vulkan, hecl::Backend::GLSL> {
public:
using HECLBackendImpl::HECLBackendImpl;
};
template <>
class HECLBackend<PlatformType::D3D11> : public HECLBackendImpl<PlatformType::D3D11, hecl::Backend::HLSL> {
public:
using HECLBackendImpl::HECLBackendImpl;
};
template <>
class HECLBackend<PlatformType::Metal> : public HECLBackendImpl<PlatformType::Metal, hecl::Backend::Metal> {
public:
using HECLBackendImpl::HECLBackendImpl;
};
template <>
class HECLBackend<PlatformType::NX> : public HECLBackendImpl<PlatformType::NX, hecl::Backend::GLSL> {
public:
using HECLBackendImpl::HECLBackendImpl;
};
template <template <typename, typename> class T, typename P, typename... Rest>
StageCollection<T<P, Rest...>>::StageCollection(PipelineConverter<P>& conv, FactoryCtx& ctx, const HECLBackend<P>& in) {
m_vertex = conv.getVertexConverter().convert(ctx, StageSourceText<P, PipelineStage::Vertex>(in.makeVert()));
m_fragment = conv.getFragmentConverter().convert(ctx, StageSourceText<P, PipelineStage::Fragment>(in.makeFrag()));
m_vtxFmtData = in.getTag().vertexFormat();
m_vtxFmt = boo::VertexFormatInfo(m_vtxFmtData.size(), m_vtxFmtData.data());
m_additionalInfo = in.getTag().additionalInfo(in.extension(), in.blendFactors());
MakeHash();
}
#if HECL_RUNTIME
template <typename P>
class FinalPipeline : public PipelineRep<P> {
boo::ObjToken<boo::IShaderPipeline> m_pipeline;
public:
static constexpr PipelineTargetType TargetType = PipelineTargetType::FinalPipeline;
static constexpr bool HasHash = false;
FinalPipeline(PipelineConverter<P>& conv, FactoryCtx& ctx,
const StageCollection<StageRuntimeObject<P, PipelineStage::Null>>& in) {
m_pipeline = static_cast<typename P::Context&>(ctx).newShaderPipeline(
in.m_vertex.stage(), in.m_fragment.stage(), in.m_geometry.stage(), in.m_control.stage(),
in.m_evaluation.stage(), in.m_vtxFmt, in.m_additionalInfo);
}
boo::ObjToken<boo::IShaderPipeline> pipeline() const { return m_pipeline; }
};
#endif
template <typename... Args>
struct pack {};
struct null_t {};
template <typename P>
struct ShaderDB {};
#define STAGE_COLLECTION_SPECIALIZATIONS(T, P) StageCollection<T<P, PipelineStage::Null>>,
#define PIPELINE_RUNTIME_SPECIALIZATIONS(P) \
HECLBackend<P>, \
STAGE_COLLECTION_SPECIALIZATIONS(StageSourceText, P) STAGE_COLLECTION_SPECIALIZATIONS(StageBinary, P) \
STAGE_COLLECTION_SPECIALIZATIONS(StageRuntimeObject, P) FinalPipeline<P>,
#define PIPELINE_OFFLINE_SPECIALIZATIONS(P) HECLBackend<P>, STAGE_COLLECTION_SPECIALIZATIONS(StageSourceText, P)
#define STAGE_RUNTIME_SPECIALIZATIONS(P, S) \
StageBinary<P, S>, HECL_APPLICATION_STAGE_REPS(P, S) StageRuntimeObject<P, S>,
#define STAGE_OFFLINE_SPECIALIZATIONS(P, S) HECL_APPLICATION_STAGE_REPS(P, S)
#define SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, S) \
template <> \
struct ShaderDB<P>::StageDB<S> { \
using StageTypes = pack<STAGE_RUNTIME_SPECIALIZATIONS(P, S) null_t>; \
};
#define SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, S) \
template <> \
struct ShaderDB<P>::StageDB<S> { \
using StageTypes = pack<null_t>; \
};
#define SPECIALIZE_OFFLINE_STAGE(P, S) \
template <> \
struct ShaderDB<P>::StageDB<S> { \
using StageTypes = pack<STAGE_OFFLINE_SPECIALIZATIONS(P, S) null_t>; \
};
#define SPECIALIZE_RUNTIME_AVAILABLE_PLATFORM(P) \
template <> \
struct ShaderDB<P> { \
using PipelineTypes = pack<PIPELINE_RUNTIME_SPECIALIZATIONS(P) null_t>; \
template <typename S> \
struct StageDB {}; \
}; \
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Vertex) \
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Fragment) \
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Geometry) \
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Control) \
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Evaluation)
#define SPECIALIZE_RUNTIME_UNAVAILABLE_PLATFORM(P) \
template <> \
struct ShaderDB<P> { \
using PipelineTypes = pack<null_t>; \
template <typename S> \
struct StageDB {}; \
}; \
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Vertex) \
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Fragment) \
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Geometry) \
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Control) \
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Evaluation)
#define SPECIALIZE_OFFLINE_PLATFORM(P) \
template <> \
struct ShaderDB<P> { \
using PipelineTypes = pack<PIPELINE_OFFLINE_SPECIALIZATIONS(P) null_t>; \
template <typename S> \
struct StageDB {}; \
}; \
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Vertex) \
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Fragment) \
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Geometry) \
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Control) \
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Evaluation)
#if HECL_RUNTIME
#if BOO_HAS_GL
SPECIALIZE_RUNTIME_AVAILABLE_PLATFORM(hecl::PlatformType::OpenGL)
#else
SPECIALIZE_RUNTIME_UNAVAILABLE_PLATFORM(hecl::PlatformType::OpenGL)
#endif
#if BOO_HAS_VULKAN
SPECIALIZE_RUNTIME_AVAILABLE_PLATFORM(hecl::PlatformType::Vulkan)
#else
SPECIALIZE_RUNTIME_UNAVAILABLE_PLATFORM(hecl::PlatformType::Vulkan)
#endif
#if _WIN32
SPECIALIZE_RUNTIME_AVAILABLE_PLATFORM(hecl::PlatformType::D3D11)
#else
SPECIALIZE_RUNTIME_UNAVAILABLE_PLATFORM(hecl::PlatformType::D3D11)
#endif
#if BOO_HAS_METAL
SPECIALIZE_RUNTIME_AVAILABLE_PLATFORM(hecl::PlatformType::Metal)
#else
SPECIALIZE_RUNTIME_UNAVAILABLE_PLATFORM(hecl::PlatformType::Metal)
#endif
#if BOO_HAS_NX
SPECIALIZE_RUNTIME_AVAILABLE_PLATFORM(hecl::PlatformType::NX)
#else
SPECIALIZE_RUNTIME_UNAVAILABLE_PLATFORM(hecl::PlatformType::NX)
#endif
#else
SPECIALIZE_OFFLINE_PLATFORM(hecl::PlatformType::OpenGL)
SPECIALIZE_OFFLINE_PLATFORM(hecl::PlatformType::Vulkan)
SPECIALIZE_OFFLINE_PLATFORM(hecl::PlatformType::D3D11)
SPECIALIZE_OFFLINE_PLATFORM(hecl::PlatformType::Metal)
SPECIALIZE_OFFLINE_PLATFORM(hecl::PlatformType::NX)
#endif
class ShaderCacheZipStream;
template <typename P, typename S>
class StageConverter {
friend class PipelineConverter<P>;
#if HECL_RUNTIME
using StageTargetTp = StageRuntimeObject<P, S>;
#else
using StageTargetTp = StageBinary<P, S>;
#endif
std::unordered_map<uint64_t, StageTargetTp> m_stageCache;
#if 0 /* Horrible compiler memory explosion - DO NOT USE! */
template <typename ToTp, typename FromTp>
static constexpr bool is_stage_constructible_v =
std::is_constructible<ToTp, StageConverter<P, S>&, FactoryCtx&, FromTp>::value;
template<typename FinalTp, typename OriginTp, typename... AllTypes>
struct is_eventually_constructible : std::false_type {};
template<typename FinalTp, typename OriginTp, typename ToTp, typename T, typename... Targs>
struct _is_eventually_constructible
: std::conditional_t<is_stage_constructible_v<FinalTp, OriginTp>,
std::true_type,
std::conditional_t<is_stage_constructible_v<ToTp, OriginTp>,
is_eventually_constructible<FinalTp, ToTp, AllStageTypes>,
_is_eventually_constructible<FinalTp, OriginTp, T, Targs...>>> {};
template<typename FinalTp, typename OriginTp, typename ToTp>
struct _is_eventually_constructible<FinalTp, OriginTp, ToTp, null_t> : std::false_type {};
template<typename FinalTp, typename OriginTp, typename... AllTypes>
struct is_eventually_constructible<FinalTp, OriginTp, pack<AllTypes...>>
: _is_eventually_constructible<FinalTp, OriginTp, AllTypes...> {};
template <typename FinalTp, typename OriginTp>
static constexpr bool is_eventually_constructible_v =
is_eventually_constructible<FinalTp, OriginTp, AllStageTypes>::value;
template<typename FinalTp, typename OriginTp, typename ToTp, typename T, typename... Targs>
struct _next_type { using type = std::conditional_t<is_stage_constructible_v<FinalTp, ToTp> &&
is_eventually_constructible_v<ToTp, OriginTp>,
ToTp,
typename _next_type<FinalTp, OriginTp, T, Targs...>::type>; };
template<typename FinalTp, typename OriginTp, typename ToTp>
struct _next_type<FinalTp, OriginTp, ToTp, null_t> { using type = null_t; };
template<typename FinalTp, typename OriginTp, typename... AllTypes>
struct next_type { using type = null_t; };
template<typename FinalTp, typename OriginTp, typename... AllTypes>
struct next_type<FinalTp, OriginTp, pack<AllTypes...>> : _next_type<FinalTp, OriginTp, AllTypes...> {};
template <typename FinalTp, typename OriginTp>
using next_type_t = typename next_type<FinalTp, OriginTp, AllStageTypes>::type;
template<class ToTp, class FromTp>
std::enable_if_t<!is_stage_constructible_v<ToTp, FromTp>, ToTp>
_Do(FactoryCtx& ctx, const FromTp& in)
{
using NextTp = next_type_t<ToTp, FromTp>;
return ToTp(*this, ctx, _Do<NextTp, FromTp>(ctx, in));
}
template<class ToTp, class FromTp>
std::enable_if_t<is_stage_constructible_v<ToTp, FromTp>, ToTp>
_Do(FactoryCtx& ctx, const FromTp& in)
{
return ToTp(*this, ctx, in);
}
#endif
using StageTypes = typename ShaderDB<P>::template StageDB<S>::StageTypes;
template <typename ToTp, typename FromTp>
static constexpr bool is_stage_constructible_v =
std::is_constructible<ToTp, StageConverter<P, S>&, FactoryCtx&, FromTp>::value;
template <typename OriginTp, typename ToTp, typename T, typename... Targs>
struct _next_type {
using type = std::conditional_t<is_stage_constructible_v<ToTp, OriginTp>, ToTp,
typename _next_type<OriginTp, T, Targs...>::type>;
};
template <typename OriginTp, typename ToTp>
struct _next_type<OriginTp, ToTp, null_t> {
using type = null_t;
};
template <typename OriginTp, typename... AllTypes>
struct next_type {
using type = null_t;
};
template <typename OriginTp, typename... AllTypes>
struct next_type<OriginTp, pack<AllTypes...>> : _next_type<OriginTp, AllTypes...> {};
template <typename OriginTp>
using next_type_t = typename next_type<OriginTp, StageTypes>::type;
/* StageSourceText derivative -> StageBinary */
template <class ToTp, class FromTp, class NextTp>
std::enable_if_t<std::is_same_v<ToTp, StageBinary<P, S>> && std::is_base_of_v<StageSourceText<P, S>, NextTp>,
StageBinary<P, S>>
_DoDerivative(FactoryCtx& ctx, const FromTp& in) {
return StageBinary<P, S>(*this, ctx, NextTp(*this, ctx, in));
}
/* StageBinary derivative -> StageBinary */
template <class ToTp, class FromTp, class NextTp>
std::enable_if_t<std::is_same_v<ToTp, StageBinary<P, S>> && std::is_base_of_v<StageBinary<P, S>, NextTp>,
StageBinary<P, S>>
_DoDerivative(FactoryCtx& ctx, const FromTp& in) {
return NextTp(*this, ctx, in);
}
/* Non-StageSourceText derivative -> StageBinary */
template <class ToTp, class FromTp>
std::enable_if_t<std::is_same_v<ToTp, StageBinary<P, S>> && !std::is_base_of_v<StageSourceText<P, S>, FromTp>,
StageBinary<P, S>>
_Do(FactoryCtx& ctx, const FromTp& in) {
using NextTp = next_type_t<FromTp>;
static_assert(!std::is_same_v<NextTp, null_t>, "Unable to resolve StageBinary or StageSourceText derivative");
return _DoDerivative<ToTp, FromTp, NextTp>(ctx, in);
}
/* StageSourceText derivative -> StageBinary */
template <class ToTp, class FromTp>
std::enable_if_t<std::is_same_v<ToTp, StageBinary<P, S>> && std::is_base_of_v<StageSourceText<P, S>, FromTp>,
StageBinary<P, S>>
_Do(FactoryCtx& ctx, const FromTp& in) {
return StageBinary<P, S>(*this, ctx, in);
}
/* Non-StageBinary derivative -> StageRuntimeObject */
template <class ToTp, class FromTp>
std::enable_if_t<std::is_same_v<ToTp, StageRuntimeObject<P, S>> && !std::is_base_of_v<StageBinary<P, S>, FromTp>,
StageRuntimeObject<P, S>>
_Do(FactoryCtx& ctx, const FromTp& in) {
return StageRuntimeObject<P, S>(*this, ctx, _Do<StageBinary<P, S>, FromTp>(ctx, in));
}
/* StageBinary derivative -> StageRuntimeObject */
template <class ToTp, class FromTp>
std::enable_if_t<std::is_same_v<ToTp, StageRuntimeObject<P, S>> && std::is_base_of_v<StageBinary<P, S>, FromTp>,
StageRuntimeObject<P, S>>
_Do(FactoryCtx& ctx, const FromTp& in) {
return StageRuntimeObject<P, S>(*this, ctx, in);
}
template <class ToTp, class FromTp>
ToTp Do(FactoryCtx& ctx, const FromTp& in) {
return _Do<ToTp, FromTp>(ctx, in);
}
public:
#if HECL_RUNTIME
void loadFromStream(FactoryCtx& ctx, ShaderCacheZipStream& r);
#endif
template <class FromTp>
StageTargetTp convert(FactoryCtx& ctx, const FromTp& in) {
if (FromTp::HasHash) {
uint64_t hash = in.Hash();
auto search = m_stageCache.find(hash);
if (search != m_stageCache.end())
return search->second;
return m_stageCache.insert(std::make_pair(hash, Do<StageTargetTp>(ctx, in))).first->second;
}
return Do<StageTargetTp>(ctx, in);
}
};
class PipelineConverterBase {
boo::IGraphicsDataFactory* m_gfxF;
boo::IGraphicsDataFactory::Platform m_platform;
protected:
PipelineConverterBase(boo::IGraphicsDataFactory* gfxF, boo::IGraphicsDataFactory::Platform platform)
: m_gfxF(gfxF), m_platform(platform) {}
public:
virtual ~PipelineConverterBase() = default;
#if HECL_RUNTIME
template <class FromTp>
boo::ObjToken<boo::IShaderPipeline> convert(FactoryCtx& ctx, const FromTp& in);
template <class FromTp>
boo::ObjToken<boo::IShaderPipeline> convert(const FromTp& in);
#endif
};
template <typename P>
class PipelineConverter : public PipelineConverterBase {
#if HECL_RUNTIME
using PipelineTargetTp = FinalPipeline<P>;
#else
using PipelineTargetTp = StageCollection<StageBinary<P>>;
#endif
std::unordered_map<uint64_t, PipelineTargetTp> m_pipelineCache;
StageConverter<P, PipelineStage::Vertex> m_vertexConverter;
StageConverter<P, PipelineStage::Fragment> m_fragmentConverter;
StageConverter<P, PipelineStage::Geometry> m_geometryConverter;
StageConverter<P, PipelineStage::Control> m_controlConverter;
StageConverter<P, PipelineStage::Evaluation> m_evaluationConverter;
using PipelineTypes = typename ShaderDB<P>::PipelineTypes;
template <typename ToTp, typename FromTp>
static constexpr bool is_pipeline_constructible_v =
std::is_constructible<ToTp, PipelineConverter<P>&, FactoryCtx&, FromTp>::value;
template <typename FinalTp, typename OriginTp, typename... AllTypes>
struct is_eventually_constructible : std::false_type {};
template <typename FinalTp, typename OriginTp, typename ToTp, typename T, typename... Targs>
struct _is_eventually_constructible
: std::conditional_t<is_pipeline_constructible_v<FinalTp, OriginTp>, std::true_type,
std::conditional_t<is_pipeline_constructible_v<ToTp, OriginTp>,
is_eventually_constructible<FinalTp, ToTp, PipelineTypes>,
_is_eventually_constructible<FinalTp, OriginTp, T, Targs...>>> {};
template <typename FinalTp, typename OriginTp, typename ToTp>
struct _is_eventually_constructible<FinalTp, OriginTp, ToTp, null_t> : std::false_type {};
template <typename FinalTp, typename OriginTp, typename... AllTypes>
struct is_eventually_constructible<FinalTp, OriginTp, pack<AllTypes...>>
: _is_eventually_constructible<FinalTp, OriginTp, AllTypes...> {};
template <typename FinalTp, typename OriginTp>
static constexpr bool is_eventually_constructible_v =
is_eventually_constructible<FinalTp, OriginTp, PipelineTypes>::value;
template <typename FinalTp, typename OriginTp, typename ToTp, typename T, typename... Targs>
struct _next_type {
using type =
std::conditional_t<is_pipeline_constructible_v<FinalTp, ToTp> && is_eventually_constructible_v<ToTp, OriginTp>,
ToTp, typename _next_type<FinalTp, OriginTp, T, Targs...>::type>;
};
template <typename FinalTp, typename OriginTp, typename ToTp>
struct _next_type<FinalTp, OriginTp, ToTp, null_t> {
using type = null_t;
};
template <typename FinalTp, typename OriginTp, typename... AllTypes>
struct next_type {
using type = null_t;
};
template <typename FinalTp, typename OriginTp, typename... AllTypes>
struct next_type<FinalTp, OriginTp, pack<AllTypes...>> : _next_type<FinalTp, OriginTp, AllTypes...> {};
template <typename FinalTp, typename OriginTp>
using next_type_t = typename next_type<FinalTp, OriginTp, PipelineTypes>::type;
template <class ToTp, class FromTp>
std::enable_if_t<!is_pipeline_constructible_v<ToTp, FromTp>, ToTp> _Do(FactoryCtx& ctx, const FromTp& in) {
using NextTp = next_type_t<ToTp, FromTp>;
return ToTp(*this, ctx, _Do<NextTp, FromTp>(ctx, in));
}
template <class ToTp, class FromTp>
std::enable_if_t<is_pipeline_constructible_v<ToTp, FromTp>, ToTp> _Do(FactoryCtx& ctx, const FromTp& in) {
return ToTp(*this, ctx, in);
}
template <class ToTp, class FromTp>
ToTp Do(FactoryCtx& ctx, const FromTp& in) {
/* No idea why this fails; it works fine with manual template arguments (clang bug?) */
// static_assert(is_eventually_constructible_v<ToTp, FromTp>, "Unable to resolve pipeline conversion chain");
return _Do<ToTp, FromTp>(ctx, in);
}
public:
PipelineConverter(boo::IGraphicsDataFactory* gfxF) : PipelineConverterBase(gfxF, P::Enum) {}
#if HECL_RUNTIME
bool loadFromFile(FactoryCtx& ctx, const hecl::SystemChar* path);
#endif
template <class FromTp>
PipelineTargetTp convert(FactoryCtx& ctx, const FromTp& in) {
if (FromTp::HasHash) {
uint64_t hash = in.Hash();
auto search = m_pipelineCache.find(hash);
if (search != m_pipelineCache.end())
return search->second;
return m_pipelineCache.insert(std::make_pair(hash, Do<PipelineTargetTp>(ctx, in))).first->second;
}
return Do<PipelineTargetTp>(ctx, in);
}
StageConverter<P, PipelineStage::Vertex>& getVertexConverter() { return m_vertexConverter; }
StageConverter<P, PipelineStage::Fragment>& getFragmentConverter() { return m_fragmentConverter; }
StageConverter<P, PipelineStage::Geometry>& getGeometryConverter() { return m_geometryConverter; }
StageConverter<P, PipelineStage::Control>& getControlConverter() { return m_controlConverter; }
StageConverter<P, PipelineStage::Evaluation>& getEvaluationConverter() { return m_evaluationConverter; }
};
#if HECL_RUNTIME
template <class FromTp>
inline boo::ObjToken<boo::IShaderPipeline> PipelineConverterBase::convert(FactoryCtx& ctx, const FromTp& in) {
assert(ctx.platform() == m_platform && "PipelineConverterBase platform mismatch");
switch (m_platform) {
#if BOO_HAS_GL
case boo::IGraphicsDataFactory::Platform::OpenGL:
return static_cast<PipelineConverter<PlatformType::OpenGL>&>(*this).convert(ctx, in).pipeline();
#endif
#if BOO_HAS_VULKAN
case boo::IGraphicsDataFactory::Platform::Vulkan:
return static_cast<PipelineConverter<PlatformType::Vulkan>&>(*this).convert(ctx, in).pipeline();
#endif
#if _WIN32
case boo::IGraphicsDataFactory::Platform::D3D11:
return static_cast<PipelineConverter<PlatformType::D3D11>&>(*this).convert(ctx, in).pipeline();
#endif
#if BOO_HAS_METAL
case boo::IGraphicsDataFactory::Platform::Metal:
return static_cast<PipelineConverter<PlatformType::Metal>&>(*this).convert(ctx, in).pipeline();
#endif
#if BOO_HAS_NX
case boo::IGraphicsDataFactory::Platform::NX:
return static_cast<PipelineConverter<PlatformType::NX>&>(*this).convert(ctx, in).pipeline();
#endif
default:
return {};
}
}
template <class FromTp>
inline boo::ObjToken<boo::IShaderPipeline> PipelineConverterBase::convert(const FromTp& in) {
boo::ObjToken<boo::IShaderPipeline> ret;
m_gfxF->commitTransaction([this, &ret, &in](boo::IGraphicsDataFactory::Context& ctx) {
ret = convert(ctx, in);
return true;
} BooTrace);
return ret;
}
inline std::unique_ptr<PipelineConverterBase> NewPipelineConverter(boo::IGraphicsDataFactory* gfxF) {
switch (gfxF->platform()) {
#if BOO_HAS_GL
case boo::IGraphicsDataFactory::Platform::OpenGL:
return std::make_unique<PipelineConverter<PlatformType::OpenGL>>(gfxF);
#endif
#if BOO_HAS_VULKAN
case boo::IGraphicsDataFactory::Platform::Vulkan:
return std::make_unique<PipelineConverter<PlatformType::Vulkan>>(gfxF);
#endif
#if _WIN32
case boo::IGraphicsDataFactory::Platform::D3D11:
return std::make_unique<PipelineConverter<PlatformType::D3D11>>(gfxF);
#endif
#if BOO_HAS_METAL
case boo::IGraphicsDataFactory::Platform::Metal:
setenv("HECL_NO_METAL_COMPILER", "1", 1);
return std::make_unique<PipelineConverter<PlatformType::Metal>>(gfxF);
#endif
#if BOO_HAS_NX
case boo::IGraphicsDataFactory::Platform::NX:
return std::make_unique<PipelineConverter<PlatformType::NX>>(gfxF);
#endif
default:
return {};
}
}
extern PipelineConverterBase* conv;
#endif
} // namespace hecl