mirror of https://github.com/AxioDL/metaforce.git
597 lines
22 KiB
C++
597 lines
22 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_tag.getDepthWrite() &&
|
|
m_backend.m_blendDst == hecl::Backend::BlendFactor::InvSrcAlpha,
|
|
m_tag.getReflectionType(), 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
|
|
|
|
#define STAGE_COLLECTION_SPECIALIZATIONS(T, P) StageCollection<T<P, PipelineStage::Null>>,
|
|
|
|
template<typename... Args> struct pack {};
|
|
struct null_t {};
|
|
template<typename P> struct TypeDB {};
|
|
template<> struct TypeDB<PlatformType::OpenGL>
|
|
{
|
|
using PipelineTypes = pack<
|
|
#if HECL_RUNTIME
|
|
#if BOO_HAS_GL
|
|
HECLBackend<PlatformType::OpenGL>,
|
|
STAGE_COLLECTION_SPECIALIZATIONS(StageSourceText, PlatformType::OpenGL)
|
|
STAGE_COLLECTION_SPECIALIZATIONS(StageBinary, PlatformType::OpenGL)
|
|
STAGE_COLLECTION_SPECIALIZATIONS(StageRuntimeObject, PlatformType::OpenGL)
|
|
FinalPipeline<PlatformType::OpenGL>,
|
|
#endif
|
|
#else
|
|
HECLBackend<PlatformType::OpenGL>,
|
|
STAGE_COLLECTION_SPECIALIZATIONS(StageSourceText, PlatformType::OpenGL)
|
|
#endif
|
|
null_t
|
|
>;
|
|
using StageTypes = pack<
|
|
#if HECL_RUNTIME
|
|
#if BOO_HAS_GL
|
|
STAGE_SPECIALIZATIONS(StageBinary, PlatformType::OpenGL)
|
|
HECL_APPLICATION_STAGE_REPS_OPENGL
|
|
STAGE_SPECIALIZATIONS(StageRuntimeObject, PlatformType::OpenGL)
|
|
#endif
|
|
#else
|
|
HECL_APPLICATION_STAGE_REPS_OPENGL
|
|
#endif
|
|
null_t
|
|
>;
|
|
};
|
|
template<> struct TypeDB<PlatformType::Vulkan>
|
|
{
|
|
using PipelineTypes = pack<
|
|
#if HECL_RUNTIME
|
|
#if BOO_HAS_VULKAN
|
|
HECLBackend<PlatformType::Vulkan>,
|
|
STAGE_COLLECTION_SPECIALIZATIONS(StageSourceText, PlatformType::Vulkan)
|
|
STAGE_COLLECTION_SPECIALIZATIONS(StageBinary, PlatformType::Vulkan)
|
|
STAGE_COLLECTION_SPECIALIZATIONS(StageRuntimeObject, PlatformType::Vulkan)
|
|
FinalPipeline<PlatformType::Vulkan>,
|
|
#endif
|
|
#else
|
|
HECLBackend<PlatformType::Vulkan>,
|
|
STAGE_COLLECTION_SPECIALIZATIONS(StageSourceText, PlatformType::Vulkan)
|
|
STAGE_COLLECTION_SPECIALIZATIONS(StageBinary, PlatformType::Vulkan)
|
|
#endif
|
|
null_t
|
|
>;
|
|
using StageTypes = pack<
|
|
#if HECL_RUNTIME
|
|
#if BOO_HAS_VULKAN
|
|
STAGE_SPECIALIZATIONS(StageBinary, PlatformType::Vulkan)
|
|
HECL_APPLICATION_STAGE_REPS_VULKAN
|
|
STAGE_SPECIALIZATIONS(StageRuntimeObject, PlatformType::Vulkan)
|
|
#endif
|
|
#else
|
|
HECL_APPLICATION_STAGE_REPS_VULKAN
|
|
#endif
|
|
null_t
|
|
>;
|
|
};
|
|
|
|
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 TypeDB<P>::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 TypeDB<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:
|
|
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
|
|
|
|
}
|