Huge shader infrastructure refactor

This commit is contained in:
Jack Andersen 2018-10-06 16:53:57 -10:00
parent 170ff23843
commit 0ee18025dd
35 changed files with 2976 additions and 2309 deletions

1
hecl/.gitignore vendored
View File

@ -1,2 +1,3 @@
DataSpecRegistry.hpp
include/hecl/ApplicationReps.hpp
.DS_Store

View File

@ -0,0 +1,60 @@
include_guard(GLOBAL)
unset(HECL_APPLICATION_REPS_TARGETS_LIST CACHE)
unset(HECL_APPLICATION_REPS_INCLUDES_LIST CACHE)
unset(HECL_APPLICATION_PIPELINE_REPS_UNIVERSAL CACHE)
unset(HECL_APPLICATION_PIPELINE_REPS CACHE)
unset(HECL_APPLICATION_STAGE_REPS CACHE)
# add_pipeline_rep(my::fully::qualified::class my_class_header.hpp [UNIVERSAL])
function(add_pipeline_rep name header)
if(IS_ABSOLUTE ${header})
set(theHeader ${header})
else()
set(theHeader ${CMAKE_CURRENT_SOURCE_DIR}/${header})
endif()
if (NOT ${theHeader} IN_LIST HECL_APPLICATION_REPS_INCLUDES_LIST)
set(HECL_APPLICATION_REPS_INCLUDES_LIST "${HECL_APPLICATION_REPS_INCLUDES_LIST};${theHeader}" CACHE INTERNAL "")
endif()
if ("${ARGV2}" STREQUAL "UNIVERSAL")
set(HECL_APPLICATION_PIPELINE_REPS_UNIVERSAL "${HECL_APPLICATION_PIPELINE_REPS_UNIVERSAL};${name}" CACHE INTERNAL "")
else()
set(HECL_APPLICATION_PIPELINE_REPS "${HECL_APPLICATION_PIPELINE_REPS};${name}" CACHE INTERNAL "")
endif()
endfunction()
# add_stage_rep(my::fully::qualified::class my_class_header.hpp)
function(add_stage_rep name header)
if(IS_ABSOLUTE ${header})
set(theHeader ${header})
else()
set(theHeader ${CMAKE_CURRENT_SOURCE_DIR}/${header})
endif()
if (NOT ${theHeader} IN_LIST HECL_APPLICATION_REPS_INCLUDES_LIST)
set(HECL_APPLICATION_REPS_INCLUDES_LIST "${HECL_APPLICATION_REPS_INCLUDES_LIST};${theHeader}" CACHE INTERNAL "")
endif()
set(HECL_APPLICATION_STAGE_REPS "${HECL_APPLICATION_STAGE_REPS};${name}" CACHE INTERNAL "")
endfunction()
function(add_shader_target target)
if (NOT ${target} IN_LIST HECL_APPLICATION_REPS_TARGETS_LIST)
set(HECL_APPLICATION_REPS_TARGETS_LIST "${HECL_APPLICATION_REPS_TARGETS_LIST};${target}" CACHE INTERNAL "")
endif()
endfunction()
function(add_shader file)
get_filename_component(name ${file} NAME)
get_filename_component(dir ${file} DIRECTORY)
shaderc(${CMAKE_CURRENT_BINARY_DIR}/${dir}/shader_${name} ${file}.shader)
add_stage_rep(shader_${name} ${CMAKE_CURRENT_BINARY_DIR}/${dir}/shader_${name}.hpp)
add_pipeline_rep(shader_${name} ${CMAKE_CURRENT_BINARY_DIR}/${dir}/shader_${name}.hpp UNIVERSAL)
add_library(shader_${name} ${CMAKE_CURRENT_BINARY_DIR}/${dir}/shader_${name}.hpp ${CMAKE_CURRENT_BINARY_DIR}/${dir}/shader_${name}.cpp)
add_shader_target(shader_${name})
endfunction()
function(add_special_shader name)
add_stage_rep(${name} ${name}.hpp)
add_pipeline_rep(${name} ${name}.hpp UNIVERSAL)
add_library(${name} ${name}.hpp ${ARGN})
add_shader_target(${name})
endfunction()

View File

@ -14,14 +14,53 @@ else()
endif()
endif()
include(ApplicationTools.cmake)
add_shader(test/test)
configure_file(DataSpecRegistry.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/DataSpecRegistry.hpp @ONLY)
unset(HECL_APPLICATION_REPS_INCLUDES_LOCAL)
foreach(theHeader ${HECL_APPLICATION_REPS_INCLUDES_LIST})
set(HECL_APPLICATION_REPS_INCLUDES_LOCAL "${HECL_APPLICATION_REPS_INCLUDES_LOCAL}#include \"${theHeader}\"\n")
endforeach()
unset(HECL_APPLICATION_PIPELINE_REPS_UNIVERSAL_LOCAL)
foreach(name ${HECL_APPLICATION_PIPELINE_REPS_UNIVERSAL})
set(HECL_APPLICATION_PIPELINE_REPS_UNIVERSAL_LOCAL "${HECL_APPLICATION_PIPELINE_REPS_UNIVERSAL_LOCAL}UNIVERSAL_PIPELINES_${name} \\\n")
endforeach()
unset(HECL_APPLICATION_PIPELINE_REPS_OPENGL_LOCAL)
unset(HECL_APPLICATION_PIPELINE_REPS_VULKAN_LOCAL)
unset(HECL_APPLICATION_PIPELINE_REPS_D3D11_LOCAL)
unset(HECL_APPLICATION_PIPELINE_REPS_METAL_LOCAL)
unset(HECL_APPLICATION_PIPELINE_REPS_NX_LOCAL)
foreach(name ${HECL_APPLICATION_PIPELINE_REPS})
set(HECL_APPLICATION_PIPELINE_REPS_OPENGL_LOCAL "${HECL_APPLICATION_PIPELINE_REPS_OPENGL_LOCAL}OPENGL_PIPELINES_${name} \\\n")
set(HECL_APPLICATION_PIPELINE_REPS_VULKAN_LOCAL "${HECL_APPLICATION_PIPELINE_REPS_VULKAN_LOCAL}VULKAN_PIPELINES_${name} \\\n")
set(HECL_APPLICATION_PIPELINE_REPS_D3D11_LOCAL "${HECL_APPLICATION_PIPELINE_REPS_D3D11_LOCAL}D3D11_PIPELINES_${name} \\\n")
set(HECL_APPLICATION_PIPELINE_REPS_METAL_LOCAL "${HECL_APPLICATION_PIPELINE_REPS_METAL_LOCAL}METAL_PIPELINES_${name} \\\n")
set(HECL_APPLICATION_PIPELINE_REPS_NX_LOCAL "${HECL_APPLICATION_PIPELINE_REPS_NX_LOCAL}NX_PIPELINES_${name} \\\n")
endforeach()
unset(HECL_APPLICATION_STAGE_REPS_OPENGL_LOCAL)
unset(HECL_APPLICATION_STAGE_REPS_VULKAN_LOCAL)
unset(HECL_APPLICATION_STAGE_REPS_D3D11_LOCAL)
unset(HECL_APPLICATION_STAGE_REPS_METAL_LOCAL)
unset(HECL_APPLICATION_STAGE_REPS_NX_LOCAL)
foreach(name ${HECL_APPLICATION_STAGE_REPS})
set(HECL_APPLICATION_STAGE_REPS_OPENGL_LOCAL "${HECL_APPLICATION_STAGE_REPS_OPENGL_LOCAL}OPENGL_STAGES_${name} \\\n")
set(HECL_APPLICATION_STAGE_REPS_VULKAN_LOCAL "${HECL_APPLICATION_STAGE_REPS_VULKAN_LOCAL}VULKAN_STAGES_${name} \\\n")
set(HECL_APPLICATION_STAGE_REPS_D3D11_LOCAL "${HECL_APPLICATION_STAGE_REPS_D3D11_LOCAL}D3D11_STAGES_${name} \\\n")
set(HECL_APPLICATION_STAGE_REPS_METAL_LOCAL "${HECL_APPLICATION_STAGE_REPS_METAL_LOCAL}METAL_STAGES_${name} \\\n")
set(HECL_APPLICATION_STAGE_REPS_NX_LOCAL "${HECL_APPLICATION_STAGE_REPS_NX_LOCAL}NX_STAGES_${name} \\\n")
endforeach()
configure_file(include/hecl/ApplicationReps.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/include/hecl/ApplicationReps.hpp @ONLY)
set(ATHENA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern/athena/include)
set(ATHENA_INCLUDE_DIR ${ATHENA_INCLUDE_DIR} PARENT_SCOPE)
set(SQUISH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern/libSquish)
set(SQUISH_INCLUDE_DIR ${SQUISH_INCLUDE_DIR} PARENT_SCOPE)
set(BOO_INCLUDE_DIR extern/boo/include)
set(BOO_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern/boo/include)
add_subdirectory(bintoc)
@ -41,7 +80,7 @@ if(NOT TARGET atdna)
endif()
add_definitions(${BOO_SYS_DEFINES})
include_directories(include blender ${LOGVISOR_INCLUDE_DIR} ${ATHENA_INCLUDE_DIR}
include_directories(include blender shaderc ${LOGVISOR_INCLUDE_DIR} ${ATHENA_INCLUDE_DIR}
${BOO_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ${BOO_SYS_INCLUDES})
add_subdirectory(lib)
add_subdirectory(blender)

View File

@ -1,6 +1,6 @@
if(NOT CMAKE_CROSSCOMPILING)
add_executable(bintoc bintoc.c)
macro(bintoc out in sym)
function(bintoc out in sym)
if(IS_ABSOLUTE ${out})
set(theOut ${out})
else()
@ -16,7 +16,7 @@ macro(bintoc out in sym)
add_custom_command(OUTPUT ${theOut}
COMMAND $<TARGET_FILE:bintoc> ARGS ${theIn} ${theOut} ${sym}
DEPENDS ${theIn} bintoc)
endmacro()
endfunction()
##################
# Package Export #

View File

@ -8,7 +8,7 @@ if(NOT TARGET bintoc AND NOT bintoc_BINARY_DIR)
include("${BINTOC_CMAKE_DIR}/hecl-bintocTargets.cmake")
endif()
macro(bintoc out in sym)
function(bintoc out in sym)
if(IS_ABSOLUTE ${out})
set(theOut ${out})
else()
@ -24,4 +24,4 @@ macro(bintoc out in sym)
add_custom_command(OUTPUT ${theOut}
COMMAND $<TARGET_FILE:bintoc> ARGS ${theIn} ${theOut} ${sym}
DEPENDS ${theIn})
endmacro()
endfunction()

2
hecl/extern/athena vendored

@ -1 +1 @@
Subproject commit 488acc867523ddce51bdf8e6975a4271997363dc
Subproject commit 5f2611702d4989097a850d8a5705184392d8510c

2
hecl/extern/boo vendored

@ -1 +1 @@
Subproject commit 08d632a8bd88b9a79884c2fe1cb36c00ddc400a8
Subproject commit c29d837ab58b9dd8be67a7f2358b84e94f6ee7f9

View File

@ -0,0 +1,35 @@
/* CMake-curated application reps header */
#define STAGE_SPECIALIZATIONS(T, P) \
T<P, hecl::PipelineStage::Vertex>, \
T<P, hecl::PipelineStage::Fragment>, \
T<P, hecl::PipelineStage::Geometry>, \
T<P, hecl::PipelineStage::Control>, \
T<P, hecl::PipelineStage::Evaluation>,
@HECL_APPLICATION_REPS_INCLUDES_LOCAL@
#define HECL_APPLICATION_PIPELINE_REPS_UNIVERSAL \
@HECL_APPLICATION_PIPELINE_REPS_UNIVERSAL_LOCAL@
#define HECL_APPLICATION_PIPELINE_REPS_OPENGL \
@HECL_APPLICATION_PIPELINE_REPS_OPENGL_LOCAL@
#define HECL_APPLICATION_PIPELINE_REPS_VULKAN \
@HECL_APPLICATION_PIPELINE_REPS_VULKAN_LOCAL@
#define HECL_APPLICATION_PIPELINE_REPS_D3D11 \
@HECL_APPLICATION_PIPELINE_REPS_D3D11_LOCAL@
#define HECL_APPLICATION_PIPELINE_REPS_METAL \
@HECL_APPLICATION_PIPELINE_REPS_METAL_LOCAL@
#define HECL_APPLICATION_PIPELINE_REPS_NX \
@HECL_APPLICATION_PIPELINE_REPS_NX_LOCAL@
#define HECL_APPLICATION_STAGE_REPS_OPENGL \
@HECL_APPLICATION_STAGE_REPS_OPENGL_LOCAL@
#define HECL_APPLICATION_STAGE_REPS_VULKAN \
@HECL_APPLICATION_STAGE_REPS_VULKAN_LOCAL@
#define HECL_APPLICATION_STAGE_REPS_D3D11 \
@HECL_APPLICATION_STAGE_REPS_D3D11_LOCAL@
#define HECL_APPLICATION_STAGE_REPS_METAL \
@HECL_APPLICATION_STAGE_REPS_METAL_LOCAL@
#define HECL_APPLICATION_STAGE_REPS_NX \
@HECL_APPLICATION_STAGE_REPS_NX_LOCAL@

View File

@ -75,6 +75,167 @@ public:
virtual void reset(const IR& ir, Diagnostics& diag)=0;
};
/**
* @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;
};
};
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)
: 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)
{hash ^= m_meta;}
ShaderTag(const hecl::Frontend::IR& ir, uint8_t c, uint8_t u, uint8_t w, uint8_t s, boo::Primitive pt,
Backend::ReflectionType reflectionType, bool depthTest, bool depthWrite, bool backfaceCulling)
: Hash(ir.m_hash), 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)
{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)
: 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)
{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;}
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;
}
};
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
{
Function lighting;
Function post;
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;
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)
: texCount(texCount), texs(texs), srcFactor(srcFactor), dstFactor(dstFactor), depthTest(depthTest),
cullMode(cullMode), noDepthWrite(noDepthWrite), noColorWrite(noColorWrite), noAlphaWrite(noAlphaWrite),
noAlphaOverwrite(noAlphaOverwrite), noReflection(noReflection) {}
mutable uint64_t m_hash = 0;
void calculateHash() const
{
XXH64_state_t st;
XXH64_reset(&st, 0);
if (!lighting.m_source.empty())
XXH64_update(&st, lighting.m_source.data(), lighting.m_source.size());
if (!post.m_source.empty())
XXH64_update(&st, post.m_source.data(), post.m_source.size());
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;
}
};
}
namespace std
{
template <> struct hash<hecl::Backend::ShaderTag>
{
size_t operator()(const hecl::Backend::ShaderTag& val) const noexcept
{return val.valSizeT();}
};
}
#endif // HECLBACKEND_HPP

View File

@ -12,15 +12,15 @@ namespace hecl::Backend
struct GLSL : ProgrammableCommon
{
void reset(const IR& ir, Diagnostics& diag);
std::string makeVert(const char* glslVer, unsigned col, unsigned uv, unsigned w,
std::string makeVert(unsigned col, unsigned uv, unsigned w,
unsigned skinSlots, size_t extTexCount,
const TextureInfo* extTexs, ReflectionType reflectionType) const;
std::string makeFrag(const char* glslVer, bool alphaTest, ReflectionType reflectionType,
const ShaderFunction& lighting=ShaderFunction()) const;
std::string makeFrag(const char* glslVer, bool alphaTest,
std::string makeFrag(bool alphaTest, ReflectionType reflectionType,
const Function& lighting=Function()) const;
std::string makeFrag(bool alphaTest,
ReflectionType reflectionType,
const ShaderFunction& lighting,
const ShaderFunction& post,
const Function& lighting,
const Function& post,
size_t extTexCount, const TextureInfo* extTexs) const;
private:

View File

@ -13,10 +13,10 @@ struct HLSL : ProgrammableCommon
unsigned skinSlots, size_t extTexCount,
const TextureInfo* extTexs, ReflectionType reflectionType) const;
std::string makeFrag(bool alphaTest, ReflectionType reflectionType,
const ShaderFunction& lighting=ShaderFunction()) const;
const Function& lighting=Function()) const;
std::string makeFrag(bool alphaTest, ReflectionType reflectionType,
const ShaderFunction& lighting,
const ShaderFunction& post, size_t extTexCount,
const Function& lighting,
const Function& post, size_t extTexCount,
const TextureInfo* extTexs) const;
private:

View File

@ -1,8 +1,6 @@
#ifndef HECLBACKEND_METAL_HPP
#define HECLBACKEND_METAL_HPP
#if BOO_HAS_METAL
#include "ProgrammableCommon.hpp"
namespace hecl::Backend
@ -16,10 +14,10 @@ struct Metal : ProgrammableCommon
const TextureInfo* extTexs, ReflectionType reflectionType) const;
std::string makeFrag(size_t blockCount, const char** blockNames, bool alphaTest,
ReflectionType reflectionType,
const ShaderFunction& lighting=ShaderFunction()) const;
const Function& lighting=Function()) const;
std::string makeFrag(size_t blockCount, const char** blockNames, bool alphaTest,
ReflectionType reflectionType, const ShaderFunction& lighting,
const ShaderFunction& post, size_t extTexCount,
ReflectionType reflectionType, const Function& lighting,
const Function& post, size_t extTexCount,
const TextureInfo* extTexs) const;
private:
@ -46,5 +44,4 @@ private:
}
#endif // BOO_HAS_METAL
#endif // HECLBACKEND_METAL_HPP

View File

@ -13,8 +13,6 @@ namespace hecl::Backend
struct ProgrammableCommon : IBackend
{
using ShaderFunction = Runtime::ShaderCacheExtensions::Function;
std::string m_colorExpr;
std::string m_alphaExpr;
BlendFactor m_blendSrc;

View File

@ -0,0 +1,67 @@
#pragma once
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
#include "boo/graphicsdev/GL.hpp"
#include "boo/graphicsdev/Vulkan.hpp"
#include "boo/graphicsdev/D3D.hpp"
#include "boo/graphicsdev/Metal.hpp"
namespace hecl
{
namespace PlatformType
{
using PlatformEnum = boo::IGraphicsDataFactory::Platform;
struct Null {};
struct OpenGL { static constexpr PlatformEnum Enum = PlatformEnum::OpenGL; static const char* Name;
#if BOO_HAS_GL
using Context = boo::GLDataFactory::Context;
#endif
};
inline const char* OpenGL::Name = "OpenGL";
struct D3D11 { static constexpr PlatformEnum Enum = PlatformEnum::D3D11; static const char* Name;
#if _WIN32
using Context = boo::D3DDataFactory::Context;
#endif
};
inline const char* D3D11::Name = "D3D11";
struct Metal { static constexpr PlatformEnum Enum = PlatformEnum::Metal; static const char* Name;
#if BOO_HAS_METAL
using Context = boo::MetalDataFactory::Context;
#endif
};
inline const char* Metal::Name = "Metal";
struct Vulkan { static constexpr PlatformEnum Enum = PlatformEnum::Vulkan; static const char* Name;
#if BOO_HAS_VULKAN
using Context = boo::VulkanDataFactory::Context;
#endif
};
inline const char* Vulkan::Name = "Vulkan";
struct NX { static constexpr PlatformEnum Enum = PlatformEnum::NX; static const char* Name;
#if BOO_HAS_NX
using Context = boo::NXDataFactory::Context;
#endif
};
inline const char* NX::Name = "NX";
}
namespace PipelineStage
{
using StageEnum = boo::PipelineStage;
struct Null { static constexpr StageEnum Enum = StageEnum::Null; static const char* Name; };
inline const char* Null::Name = "Null";
struct Vertex { static constexpr StageEnum Enum = StageEnum::Vertex; static const char* Name; };
inline const char* Vertex::Name = "Vertex";
struct Fragment { static constexpr StageEnum Enum = StageEnum::Fragment; static const char* Name; };
inline const char* Fragment::Name = "Fragment";
struct Geometry { static constexpr StageEnum Enum = StageEnum::Geometry; static const char* Name; };
inline const char* Geometry::Name = "Geometry";
struct Control { static constexpr StageEnum Enum = StageEnum::Control; static const char* Name; };
inline const char* Control::Name = "Control";
struct Evaluation { static constexpr StageEnum Enum = StageEnum::Evaluation; static const char* Name; };
inline const char* Evaluation::Name = "Evaluation";
}
template<typename P, typename S>
std::pair<std::shared_ptr<uint8_t[]>, size_t> CompileShader(std::string_view text);
}

View File

@ -0,0 +1,592 @@
#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; }
};
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());
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
}

View File

@ -0,0 +1,211 @@
#pragma once
#include "Compilers.hpp"
extern "C" unsigned long long XXH64 (const void* input, size_t length, unsigned long long seed);
#define HECL_RUNTIME 1
namespace hecl
{
using AdditionalPipelineInfo = boo::AdditionalPipelineInfo;
enum class StageTargetType
{
SourceText,
Binary,
Runtime
};
enum class PipelineTargetType
{
StageSourceTextCollection,
StageBinaryCollection,
StageRuntimeCollection,
FinalPipeline
};
template<typename P, typename S>
class StageConverter;
template<typename P>
class PipelineConverter;
#if HECL_RUNTIME
using FactoryCtx = boo::IGraphicsDataFactory::Context;
#else
struct FactoryCtx {};
#endif
template<typename P, typename S>
class StageRep
{
public:
using Platform = P;
using Stage = S;
};
template<typename P>
class PipelineRep
{
public:
using Platform = P;
};
class GeneralShader : public hecl::PipelineRep<hecl::PlatformType::Null> {};
class TessellationShader : public hecl::PipelineRep<hecl::PlatformType::Null> {};
template<typename P, typename S>
class StageSourceText : public StageRep<P, S>
{
std::string_view m_text;
uint64_t m_hash;
public:
static constexpr StageTargetType TargetType = StageTargetType::SourceText;
static constexpr PipelineTargetType PipelineTarget = PipelineTargetType::StageSourceTextCollection;
static constexpr bool HasHash = true;
uint64_t Hash() const { return m_hash; }
explicit StageSourceText(std::string_view text)
{
m_hash = XXH64(m_text.data(), m_text.size(), 0);
}
std::string_view text() const { return m_text; }
};
template<typename P, typename S>
class StageBinary : public StageRep<P, S>
{
std::shared_ptr<uint8_t[]> m_ownedData;
const uint8_t* m_data = nullptr;
size_t m_size = 0;
uint64_t m_hash = 0;
public:
static constexpr StageTargetType TargetType = StageTargetType::Binary;
static constexpr PipelineTargetType PipelineTarget = PipelineTargetType::StageBinaryCollection;
static constexpr bool HasHash = true;
uint64_t Hash() const { return m_hash; }
StageBinary(const uint8_t* data, size_t size)
: m_data(data), m_size(size)
{ m_hash = XXH64(m_data, m_size, 0); }
StageBinary(std::shared_ptr<uint8_t[]> data, size_t size)
: m_ownedData(std::move(data)),
m_data(m_ownedData.get()), m_size(size)
{ m_hash = XXH64(m_data, m_size, 0); }
explicit StageBinary(std::pair<std::shared_ptr<uint8_t[]>, size_t> data)
: StageBinary(data.first, data.second) {}
StageBinary(StageConverter<P, S>& conv, FactoryCtx& ctx, const StageSourceText<P, S>& in)
: StageBinary(CompileShader<P, S>(in.text())) {}
const uint8_t* data() const { return m_data; }
size_t size() const { return m_size; }
};
template<typename P>
class FinalPipeline;
template<typename P>
class HECLBackend;
template <class T>
using __IsStageSubclass = typename std::disjunction<
std::is_base_of<StageRep<typename T::Platform, PipelineStage::Vertex>, T>,
std::is_base_of<StageRep<typename T::Platform, PipelineStage::Fragment>, T>,
std::is_base_of<StageRep<typename T::Platform, PipelineStage::Geometry>, T>,
std::is_base_of<StageRep<typename T::Platform, PipelineStage::Control>, T>,
std::is_base_of<StageRep<typename T::Platform, PipelineStage::Evaluation>, T>>;
template <class T>
inline constexpr bool __IsStageSubclass_v = __IsStageSubclass<T>::value;
template<typename T> class StageCollection;
template<template<typename, typename> class T, typename P, typename... Rest>
class StageCollection<T<P, Rest...>> : public PipelineRep<P>
{
using base = PipelineRep<P>;
friend class FinalPipeline<P>;
static_assert(__IsStageSubclass_v<T<P, PipelineStage::Vertex>>,
"Stage Collection may only be specialized with StageRep subclasses");
T<P, PipelineStage::Vertex> m_vertex;
T<P, PipelineStage::Fragment> m_fragment;
T<P, PipelineStage::Geometry> m_geometry;
T<P, PipelineStage::Control> m_control;
T<P, PipelineStage::Evaluation> m_evaluation;
AdditionalPipelineInfo m_additionalInfo;
std::vector<boo::VertexElementDescriptor> m_vtxFmtData;
boo::VertexFormatInfo m_vtxFmt;
uint64_t m_hash;
public:
static constexpr PipelineTargetType TargetType = T<P, PipelineStage::Vertex>::PipelineTarget;
static constexpr bool HasHash = T<P, PipelineStage::Vertex>::HasHash;
template<typename U = StageCollection<T<P, Rest...>>>
std::enable_if_t<U::HasHash, uint64_t> Hash() const { return m_hash; }
template<typename U = StageCollection<T<P, Rest...>>>
void MakeHash(std::enable_if_t<!U::HasHash>* = 0) {}
template<typename U = StageCollection<T<P, Rest...>>>
void MakeHash(std::enable_if_t<U::HasHash>* = 0)
{
m_hash = 0;
m_hash ^= m_vertex.Hash();
m_hash ^= m_fragment.Hash();
m_hash ^= m_geometry.Hash();
m_hash ^= m_control.Hash();
m_hash ^= m_evaluation.Hash();
m_hash ^= XXH64(&m_additionalInfo, sizeof(m_additionalInfo), 0);
}
StageCollection(PipelineConverter<P>& conv, FactoryCtx& ctx, const HECLBackend<P>& in);
template<typename I>
StageCollection(PipelineConverter<P>& conv, FactoryCtx& ctx, const I& in,
typename std::enable_if_t<std::is_base_of_v<GeneralShader, I>>* = 0)
{
m_vertex = conv.getVertexConverter().convert(ctx, in);
m_fragment = conv.getFragmentConverter().convert(ctx, in);
m_vtxFmt = in.VtxFmt;
m_additionalInfo = in.PipelineInfo;
MakeHash();
}
template<typename I>
StageCollection(PipelineConverter<P>& conv, FactoryCtx& ctx, const I& in,
typename std::enable_if_t<std::is_base_of_v<TessellationShader, I>>* = 0)
{
m_vertex = conv.getVertexConverter().convert(ctx, in);
m_fragment = conv.getFragmentConverter().convert(ctx, in);
if (in.HasTessellation)
{
m_control = conv.getControlConverter().convert(ctx, in);
m_evaluation = conv.getEvaluationConverter().convert(ctx, in);
}
m_vtxFmt = in.VtxFmt;
m_additionalInfo = in.PipelineInfo;
MakeHash();
}
StageCollection(const T<P, PipelineStage::Vertex>& vertex,
const T<P, PipelineStage::Fragment>& fragment,
const T<P, PipelineStage::Geometry>& geometry,
const T<P, PipelineStage::Control>& control,
const T<P, PipelineStage::Evaluation>& evaluation,
const AdditionalPipelineInfo& info,
const boo::VertexFormatInfo& vtxFmt)
: m_vertex(vertex), m_fragment(fragment), m_geometry(geometry),
m_control(control), m_evaluation(evaluation), m_additionalInfo(info),
m_vtxFmt(vtxFmt) {}
};
}
#define _STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, P) \
template <> const hecl::StageBinary<P, hecl::PipelineStage::Vertex> \
T<P, hecl::PipelineStage::Vertex>::Prototype; \
template <> const hecl::StageBinary<P, hecl::PipelineStage::Fragment> \
T<P, hecl::PipelineStage::Fragment>::Prototype; \
template <> const hecl::StageBinary<P, hecl::PipelineStage::Geometry> \
T<P, hecl::PipelineStage::Geometry>::Prototype; \
template <> const hecl::StageBinary<P, hecl::PipelineStage::Control> \
T<P, hecl::PipelineStage::Control>::Prototype; \
template <> const hecl::StageBinary<P, hecl::PipelineStage::Evaluation> \
T<P, hecl::PipelineStage::Evaluation>::Prototype;
#define STAGEOBJECT_PROTOTYPE_DECLARATIONS(T) \
_STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::OpenGL) \
_STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::Vulkan) \
_STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::D3D11) \
_STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::Metal) \
_STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, hecl::PlatformType::NX)

View File

@ -2,11 +2,7 @@
#define HECLRUNTIME_HPP
#include "hecl.hpp"
#include "Frontend.hpp"
#include "Backend/Backend.hpp"
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
#include "athena/DNA.hpp"
#include "athena/FileReader.hpp"
#include <unordered_map>
namespace hecl
@ -33,256 +29,6 @@ public:
SystemStringView getStoreRoot() const {return m_storeRoot;}
};
/**
* @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;
};
};
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)
: 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)
{hash ^= m_meta;}
ShaderTag(const hecl::Frontend::IR& ir, uint8_t c, uint8_t u, uint8_t w, uint8_t s, boo::Primitive pt,
Backend::ReflectionType reflectionType, bool depthTest, bool depthWrite, bool backfaceCulling)
: Hash(ir.m_hash), 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)
{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)
: 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)
{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;}
uint64_t getMetaData() const {return m_meta;}
/* For shader constructors that require vertex format up-front (HLSL) */
boo::ObjToken<boo::IVertexFormat> newVertexFormat(boo::IGraphicsDataFactory::Context& ctx) const;
};
/**
* @brief Simple binary data and tag container for cache interaction
*/
class ShaderCachedData
{
friend class ShaderCacheManager;
ShaderCachedData() = default;
public:
ShaderCachedData(const ShaderTag& tag, size_t decompSz)
: m_tag(tag), m_data(new uint8_t[decompSz]), m_sz(decompSz) {}
ShaderTag m_tag;
std::unique_ptr<uint8_t[]> m_data;
size_t m_sz;
operator bool() const {return m_tag.operator bool();}
};
/**
* @brief Optional cache extensions allowing the client to specify shader transformations in bulk
*/
class ShaderCacheExtensions
{
friend class ShaderCacheManager;
boo::IGraphicsDataFactory::Platform m_plat;
ShaderCacheExtensions() : m_plat(boo::IGraphicsDataFactory::Platform::Null) {}
uint64_t hashExtensions() const;
public:
struct Function
{
const char* m_source = nullptr;
const char* m_entry = nullptr;
Function() = default;
Function(const char* source, const char* entry)
: m_source(source), m_entry(entry) {}
};
struct ExtensionSlot
{
Function lighting;
Function post;
size_t blockCount = 0;
const char** blockNames = 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;
};
std::vector<ExtensionSlot> m_extensionSlots;
ShaderCacheExtensions(boo::IGraphicsDataFactory::Platform plat) : m_plat(plat)
{
/* Index-0 has special default-meaning */
m_extensionSlots.emplace_back();
}
operator bool() const {return m_plat != boo::IGraphicsDataFactory::Platform::Null;}
/* Strings must remain resident!! (intended to be stored static const) */
unsigned registerExtensionSlot(Function lighting, Function post,
size_t blockCount, const char** blockNames,
size_t texCount, const Backend::TextureInfo* texs,
Backend::BlendFactor srcFactor, Backend::BlendFactor dstFactor,
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)
{
m_extensionSlots.emplace_back();
ExtensionSlot& slot = m_extensionSlots.back();
slot.lighting = lighting;
slot.post = post;
slot.blockCount = blockCount;
slot.blockNames = blockNames;
slot.texCount = texCount;
slot.texs = texs;
slot.srcFactor = srcFactor;
slot.dstFactor = dstFactor;
slot.depthTest = depthTest;
slot.cullMode = cullMode;
slot.noDepthWrite = noDepthWrite;
slot.noColorWrite = noColorWrite;
slot.noAlphaWrite = noAlphaWrite;
slot.noAlphaOverwrite = noAlphaOverwrite;
slot.noReflection = noReflection;
return m_extensionSlots.size() - 1;
}
};
/**
* @brief Interface for binding HECL backends to the ShaderCacheManager
*/
class IShaderBackendFactory
{
friend class ShaderCacheManager;
protected:
using FReturnExtensionShader = std::function<void(const boo::ObjToken<boo::IShaderPipeline>&)>;
virtual ShaderCachedData buildShaderFromIR(const ShaderTag& tag,
const hecl::Frontend::IR& ir,
hecl::Frontend::Diagnostics& diag,
boo::IGraphicsDataFactory::Context& ctx,
boo::ObjToken<boo::IShaderPipeline>& objOut)=0;
virtual boo::ObjToken<boo::IShaderPipeline> buildShaderFromCache(const ShaderCachedData& data,
boo::IGraphicsDataFactory::Context& ctx)=0;
virtual ShaderCachedData buildExtendedShaderFromIR(const ShaderTag& tag,
const hecl::Frontend::IR& ir,
hecl::Frontend::Diagnostics& diag,
const std::vector<ShaderCacheExtensions::ExtensionSlot>& extensionSlots,
boo::IGraphicsDataFactory::Context& ctx,
FReturnExtensionShader returnFunc)=0;
virtual bool buildExtendedShaderFromCache(const ShaderCachedData& data,
const std::vector<ShaderCacheExtensions::ExtensionSlot>& extensionSlots,
boo::IGraphicsDataFactory::Context& ctx,
FReturnExtensionShader returnFunc)=0;
public:
virtual ~IShaderBackendFactory() = default;
};
/**
* @brief Stores token and pipeline set for sharing with ref-counting
*/
struct ShaderPipelines
{
std::vector<boo::ObjToken<boo::IShaderPipeline>> m_pipelines;
};
/**
* @brief Maintains index/data file pair containing platform-dependent cached shader data
*/
class ShaderCacheManager
{
const FileStoreManager& m_storeMgr;
ShaderCacheExtensions m_extensions;
uint64_t m_extensionsHash = 0;
std::unique_ptr<IShaderBackendFactory> m_factory;
athena::io::FileReader m_idxFr;
athena::io::FileReader m_datFr;
hecl::Frontend::Frontend FE;
struct IndexEntry : athena::io::DNA<athena::Big>
{
AT_DECL_DNA
Value<atUint64> m_hash;
Value<atUint64> m_meta;
Value<atUint64> m_compOffset;
Value<atUint32> m_compSize;
Value<atUint32> m_decompSize;
};
std::vector<IndexEntry> m_entries;
std::unordered_map<Hash, size_t> m_entryLookup;
std::unordered_map<Hash, std::shared_ptr<ShaderPipelines>> m_pipelineLookup;
uint64_t m_timeHash = 0;
void bootstrapIndex();
ShaderCachedData lookupData(const Hash& hash);
bool addData(const ShaderCachedData& data);
boo::ObjToken<boo::IShaderPipeline> buildFromCache(const ShaderCachedData& foundData,
boo::IGraphicsDataFactory::Context& ctx);
std::vector<boo::ObjToken<boo::IShaderPipeline>> buildExtendedFromCache(const ShaderCachedData& foundData,
boo::IGraphicsDataFactory::Context& ctx);
public:
ShaderCacheManager(const FileStoreManager& storeMgr,
boo::IGraphicsDataFactory* gfxFactory,
ShaderCacheExtensions&& extension);
ShaderCacheManager(const FileStoreManager& storeMgr,
boo::IGraphicsDataFactory* gfxFactory)
: ShaderCacheManager(storeMgr, gfxFactory, ShaderCacheExtensions()) {}
void reload();
void clearCachedPipelines() { m_pipelineLookup.clear(); }
std::shared_ptr<ShaderPipelines> buildShader(const ShaderTag& tag, std::string_view source,
std::string_view diagName,
boo::IGraphicsDataFactory& factory);
std::shared_ptr<ShaderPipelines> buildShader(const ShaderTag& tag, const hecl::Frontend::IR& ir,
std::string_view diagName,
boo::IGraphicsDataFactory& factory);
std::shared_ptr<ShaderPipelines> buildExtendedShader(const ShaderTag& tag, std::string_view source,
std::string_view diagName,
boo::IGraphicsDataFactory& factory);
std::shared_ptr<ShaderPipelines> buildExtendedShader(const ShaderTag& tag, const hecl::Frontend::IR& ir,
std::string_view diagName,
boo::IGraphicsDataFactory& factory);
};
/**
* @brief Integrated reader/constructor/container for HMDL data
*/
@ -290,24 +36,19 @@ struct HMDLData
{
boo::ObjToken<boo::IGraphicsBufferS> m_vbo;
boo::ObjToken<boo::IGraphicsBufferS> m_ibo;
boo::ObjToken<boo::IVertexFormat> m_vtxFmt;
std::unique_ptr<boo::VertexElementDescriptor[]> m_vtxFmtData;
boo::VertexFormatInfo m_vtxFmt;
HMDLData(boo::IGraphicsDataFactory::Context& ctx,
const void* metaData, const void* vbo, const void* ibo);
/* For binding constructors that require vertex format up front (GLSL) */
static boo::ObjToken<boo::IVertexFormat>
NewVertexFormat(boo::IGraphicsDataFactory::Context& ctx, const HMDLMeta& meta,
const boo::ObjToken<boo::IGraphicsBuffer>& vbo={},
const boo::ObjToken<boo::IGraphicsBuffer>& ibo={});
boo::ObjToken<boo::IShaderDataBinding>
newShaderDataBindng(boo::IGraphicsDataFactory::Context& ctx,
const boo::ObjToken<boo::IShaderPipeline>& shader,
size_t ubufCount, const boo::ObjToken<boo::IGraphicsBuffer>* ubufs,
const boo::PipelineStage* ubufStages,
size_t texCount, const boo::ObjToken<boo::ITexture>* texs)
{return ctx.newShaderDataBinding(shader, m_vtxFmt, m_vbo.get(), nullptr, m_ibo.get(),
{return ctx.newShaderDataBinding(shader, m_vbo.get(), nullptr, m_ibo.get(),
ubufCount, ubufs, ubufStages, nullptr, nullptr,
texCount, texs, nullptr, nullptr);}
};
@ -315,13 +56,4 @@ struct HMDLData
}
}
namespace std
{
template <> struct hash<hecl::Runtime::ShaderTag>
{
size_t operator()(const hecl::Runtime::ShaderTag& val) const noexcept
{return val.valSizeT();}
};
}
#endif // HECLRUNTIME_HPP

View File

@ -1,11 +1,7 @@
if(WIN32)
set(PLAT_SRCS HLSL.cpp)
endif()
if(APPLE)
set(PLAT_SRCS Metal.cpp)
endif()
if(NOT WINDOWS_STORE)
list(APPEND PLAT_SRCS GLSL.cpp)
list(APPEND PLAT_SRCS GLSL.cpp HLSL.cpp Metal.cpp)
else()
list(APPEND PLAT_SRCS HLSL.cpp)
endif()
set(BACKEND_SOURCES

View File

@ -1,9 +1,8 @@
#include "hecl/Backend/GLSL.hpp"
#include "hecl/Runtime.hpp"
#include <athena/MemoryReader.hpp>
#include <athena/MemoryWriter.hpp>
#include <boo/graphicsdev/GL.hpp>
#include <boo/graphicsdev/Vulkan.hpp>
#include "athena/MemoryReader.hpp"
#include "athena/MemoryWriter.hpp"
#include "boo/graphicsdev/GLSLMacros.hpp"
static logvisor::Module Log("hecl::Backend::GLSL");
@ -150,12 +149,12 @@ void GLSL::reset(const IR& ir, Diagnostics& diag)
ProgrammableCommon::reset(ir, diag, "GLSL");
}
std::string GLSL::makeVert(const char* glslVer, unsigned col, unsigned uv, unsigned w,
std::string GLSL::makeVert(unsigned col, unsigned uv, unsigned w,
unsigned s, size_t extTexCount,
const TextureInfo* extTexs, ReflectionType reflectionType) const
{
extTexCount = std::min(int(extTexCount), BOO_GLSL_MAX_TEXTURE_COUNT - int(m_tcgs.size()));
std::string retval = std::string(glslVer) + "\n" BOO_GLSL_BINDING_HEAD +
std::string retval =
GenerateVertInStruct(col, uv, w) + "\n" +
GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + "\n" +
GenerateVertUniformStruct(s, reflectionType != ReflectionType::None) +
@ -221,11 +220,11 @@ std::string GLSL::makeVert(const char* glslVer, unsigned col, unsigned uv, unsig
return retval + "}\n";
}
std::string GLSL::makeFrag(const char* glslVer, bool alphaTest,
ReflectionType reflectionType, const ShaderFunction& lighting) const
std::string GLSL::makeFrag(bool alphaTest,
ReflectionType reflectionType, const Function& lighting) const
{
std::string lightingSrc;
if (lighting.m_source)
if (!lighting.m_source.empty())
lightingSrc = lighting.m_source;
else
lightingSrc = "const vec4 colorReg0 = vec4(1.0);\n"
@ -245,8 +244,8 @@ std::string GLSL::makeFrag(const char* glslVer, bool alphaTest,
texMapDecl += hecl::Format("TBINDING%u uniform sampler2D reflectionTex;\n",
m_texMapEnd);
std::string retval = std::string(glslVer) +
"\n#extension GL_ARB_shader_image_load_store: enable\n" BOO_GLSL_BINDING_HEAD +
std::string retval =
std::string("#extension GL_ARB_shader_image_load_store: enable\n") +
GenerateVertToFragStruct(0, reflectionType != ReflectionType::None) +
(!alphaTest ?
"#ifdef GL_ARB_shader_image_load_store\n"
@ -261,8 +260,9 @@ std::string GLSL::makeFrag(const char* glslVer, bool alphaTest,
if (m_lighting)
{
if (lighting.m_entry)
retval += hecl::Format(" vec4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz));\n", lighting.m_entry);
if (!lighting.m_entry.empty())
retval += hecl::Format(" vec4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz));\n",
lighting.m_entry.data());
else
retval += " vec4 lighting = vec4(1.0,1.0,1.0,1.0);\n";
}
@ -282,14 +282,14 @@ std::string GLSL::makeFrag(const char* glslVer, bool alphaTest,
return retval + (alphaTest ? GenerateAlphaTest() : "") + "}\n";
}
std::string GLSL::makeFrag(const char* glslVer, bool alphaTest,
std::string GLSL::makeFrag(bool alphaTest,
ReflectionType reflectionType,
const ShaderFunction& lighting,
const ShaderFunction& post,
const Function& lighting,
const Function& post,
size_t extTexCount, const TextureInfo* extTexs) const
{
std::string lightingSrc;
if (lighting.m_source)
if (!lighting.m_source.empty())
lightingSrc = lighting.m_source;
else
lightingSrc = "const vec4 colorReg0 = vec4(1.0);\n"
@ -299,11 +299,11 @@ std::string GLSL::makeFrag(const char* glslVer, bool alphaTest,
"\n";
std::string postSrc;
if (post.m_source)
if (!post.m_source.empty())
postSrc = post.m_source;
std::string postEntry;
if (post.m_entry)
if (!post.m_entry.empty())
postEntry = post.m_entry;
std::string texMapDecl;
@ -324,8 +324,8 @@ std::string GLSL::makeFrag(const char* glslVer, bool alphaTest,
extTex.mapIdx, extTex.mapIdx);
}
std::string retval = std::string(glslVer) +
"\n#extension GL_ARB_shader_image_load_store: enable\n" BOO_GLSL_BINDING_HEAD +
std::string retval =
std::string("#extension GL_ARB_shader_image_load_store: enable\n") +
GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) +
(!alphaTest ?
"\n#ifdef GL_ARB_shader_image_load_store\n"
@ -340,8 +340,9 @@ std::string GLSL::makeFrag(const char* glslVer, bool alphaTest,
if (m_lighting)
{
if (lighting.m_entry)
retval += hecl::Format(" vec4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz));\n", lighting.m_entry);
if (!lighting.m_entry.empty())
retval += hecl::Format(" vec4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz));\n",
lighting.m_entry.data());
else
retval += " vec4 lighting = vec4(1.0,1.0,1.0,1.0);\n";
}
@ -363,599 +364,3 @@ std::string GLSL::makeFrag(const char* glslVer, bool alphaTest,
}
namespace hecl::Runtime
{
static const char* STD_BLOCKNAMES[] = {HECL_GLSL_VERT_UNIFORM_BLOCK_NAME,
HECL_GLSL_TEXMTX_UNIFORM_BLOCK_NAME};
static const char* STD_TEXNAMES[] =
{
"tex0",
"tex1",
"tex2",
"tex3",
"tex4",
"tex5",
"tex6",
"tex7"
};
static const char* EXT_TEXNAMES[] =
{
"extTex0",
"extTex1",
"extTex2",
"extTex3",
"extTex4",
"extTex5",
"extTex6",
"extTex7"
};
struct GLSLBackendFactory : IShaderBackendFactory
{
Backend::GLSL m_backend;
ShaderCachedData buildShaderFromIR(const ShaderTag& tag,
const hecl::Frontend::IR& ir,
hecl::Frontend::Diagnostics& diag,
boo::IGraphicsDataFactory::Context& ctx,
boo::ObjToken<boo::IShaderPipeline>& objOut)
{
m_backend.reset(ir, diag);
size_t cachedSz = 3;
std::string vertSource =
m_backend.makeVert("#version 330",
tag.getColorCount(), tag.getUvCount(), tag.getWeightCount(),
tag.getSkinSlotCount(), 0, nullptr, tag.getReflectionType());
cachedSz += vertSource.size() + 1;
std::string fragSource = m_backend.makeFrag("#version 330",
tag.getDepthWrite() && m_backend.m_blendDst == hecl::Backend::BlendFactor::InvSrcAlpha,
tag.getReflectionType());
cachedSz += fragSource.size() + 1;
if (m_backend.m_texMapEnd > 8)
Log.report(logvisor::Fatal, "maximum of 8 texture maps supported");
objOut =
static_cast<boo::GLDataFactory::Context&>(ctx).
newShaderPipeline(vertSource.c_str(), fragSource.c_str(),
m_backend.m_texMapEnd, STD_TEXNAMES,
2, STD_BLOCKNAMES,
boo::BlendFactor(m_backend.m_blendSrc),
boo::BlendFactor(m_backend.m_blendDst),
tag.getPrimType(), tag.getDepthTest() ? boo::ZTest::LEqual : boo::ZTest::None,
tag.getDepthWrite(), true, false,
tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None);
if (!objOut)
Log.report(logvisor::Fatal, "unable to build shader");
ShaderCachedData dataOut(tag, cachedSz);
athena::io::MemoryWriter w(dataOut.m_data.get(), dataOut.m_sz);
w.writeUByte(m_backend.m_texMapEnd);
w.writeUByte(atUint8(m_backend.m_blendSrc));
w.writeUByte(atUint8(m_backend.m_blendDst));
w.writeString(vertSource);
w.writeString(fragSource);
return dataOut;
}
boo::ObjToken<boo::IShaderPipeline> buildShaderFromCache(const ShaderCachedData& data,
boo::IGraphicsDataFactory::Context& ctx)
{
const ShaderTag& tag = data.m_tag;
athena::io::MemoryReader r(data.m_data.get(), data.m_sz, false, false);
atUint8 texMapEnd = r.readUByte();
boo::BlendFactor blendSrc = boo::BlendFactor(r.readUByte());
boo::BlendFactor blendDst = boo::BlendFactor(r.readUByte());
std::string vertSource = r.readString();
std::string fragSource = r.readString();
if (r.hasError())
return nullptr;
if (texMapEnd > 8)
Log.report(logvisor::Fatal, "maximum of 8 texture maps supported");
auto ret =
static_cast<boo::GLDataFactory::Context&>(ctx).
newShaderPipeline(vertSource.c_str(), fragSource.c_str(),
texMapEnd, STD_TEXNAMES,
2, STD_BLOCKNAMES,
blendSrc, blendDst, tag.getPrimType(),
tag.getDepthTest() ? boo::ZTest::LEqual : boo::ZTest::None,
tag.getDepthWrite(), true, false,
tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None);
if (!ret)
Log.report(logvisor::Fatal, "unable to build shader");
return ret;
}
ShaderCachedData buildExtendedShaderFromIR(const ShaderTag& tag,
const hecl::Frontend::IR& ir,
hecl::Frontend::Diagnostics& diag,
const std::vector<ShaderCacheExtensions::ExtensionSlot>& extensionSlots,
boo::IGraphicsDataFactory::Context& ctx,
FReturnExtensionShader returnFunc)
{
m_backend.reset(ir, diag);
size_t cachedSz = 3;
if (m_backend.m_texMapEnd > 8)
Log.report(logvisor::Fatal, "maximum of 8 texture maps supported");
std::vector<std::pair<std::string, std::string>> sources;
sources.reserve(extensionSlots.size());
for (const ShaderCacheExtensions::ExtensionSlot& slot : extensionSlots)
{
size_t bc = 2;
const char** bn = STD_BLOCKNAMES;
if (slot.blockCount)
{
bc = slot.blockCount;
bn = slot.blockNames;
}
sources.emplace_back(m_backend.makeVert("#version 330",
tag.getColorCount(), tag.getUvCount(), tag.getWeightCount(),
tag.getSkinSlotCount(), slot.texCount,
slot.texs, tag.getReflectionType()),
m_backend.makeFrag("#version 330",
tag.getDepthWrite() && m_backend.m_blendDst == hecl::Backend::BlendFactor::InvSrcAlpha,
tag.getReflectionType(), slot.lighting, slot.post, slot.texCount, slot.texs));
cachedSz += sources.back().first.size() + 1;
cachedSz += sources.back().second.size() + 1;
boo::ZTest zTest;
switch (slot.depthTest)
{
case hecl::Backend::ZTest::Original:
default:
zTest = tag.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;
}
const char* ExtTexnames[8];
for (int i=0 ; i<8 ; ++i)
ExtTexnames[i] = STD_TEXNAMES[i];
for (int i=0 ; i<slot.texCount ; ++i)
ExtTexnames[slot.texs[i].mapIdx] = EXT_TEXNAMES[slot.texs[i].mapIdx];
auto ret =
static_cast<boo::GLDataFactory::Context&>(ctx).
newShaderPipeline(sources.back().first.c_str(), sources.back().second.c_str(),
8, ExtTexnames, bc, bn,
boo::BlendFactor((slot.srcFactor == hecl::Backend::BlendFactor::Original) ? m_backend.m_blendSrc : slot.srcFactor),
boo::BlendFactor((slot.dstFactor == hecl::Backend::BlendFactor::Original) ? m_backend.m_blendDst : slot.dstFactor),
tag.getPrimType(), zTest, slot.noDepthWrite ? false : tag.getDepthWrite(), !slot.noColorWrite, !slot.noAlphaWrite,
(slot.cullMode == hecl::Backend::CullMode::Original) ?
(tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None) :
boo::CullMode(slot.cullMode), !slot.noAlphaOverwrite);
if (!ret)
Log.report(logvisor::Fatal, "unable to build shader");
returnFunc(ret);
}
ShaderCachedData dataOut(tag, cachedSz);
athena::io::MemoryWriter w(dataOut.m_data.get(), dataOut.m_sz);
w.writeUByte(m_backend.m_texMapEnd);
w.writeUByte(atUint8(m_backend.m_blendSrc));
w.writeUByte(atUint8(m_backend.m_blendDst));
for (const std::pair<std::string, std::string>& pair : sources)
{
w.writeString(pair.first);
w.writeString(pair.second);
}
return dataOut;
}
bool buildExtendedShaderFromCache(const ShaderCachedData& data,
const std::vector<ShaderCacheExtensions::ExtensionSlot>& extensionSlots,
boo::IGraphicsDataFactory::Context& ctx,
FReturnExtensionShader returnFunc)
{
const ShaderTag& tag = data.m_tag;
athena::io::MemoryReader r(data.m_data.get(), data.m_sz, false, false);
atUint8 texMapEnd = r.readUByte();
hecl::Backend::BlendFactor blendSrc = hecl::Backend::BlendFactor(r.readUByte());
hecl::Backend::BlendFactor blendDst = hecl::Backend::BlendFactor(r.readUByte());
if (r.hasError())
return false;
if (texMapEnd > 8)
Log.report(logvisor::Fatal, "maximum of 8 texture maps supported");
for (const ShaderCacheExtensions::ExtensionSlot& slot : extensionSlots)
{
size_t bc = 2;
const char** bn = STD_BLOCKNAMES;
if (slot.blockCount)
{
bc = slot.blockCount;
bn = slot.blockNames;
}
std::string vertSource = r.readString();
std::string fragSource = r.readString();
if (r.hasError())
return false;
boo::ZTest zTest;
switch (slot.depthTest)
{
case hecl::Backend::ZTest::Original:
default:
zTest = tag.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;
}
const char* ExtTexnames[8];
for (int i=0 ; i<8 ; ++i)
ExtTexnames[i] = STD_TEXNAMES[i];
for (int i=0 ; i<slot.texCount ; ++i)
ExtTexnames[slot.texs[i].mapIdx] = EXT_TEXNAMES[slot.texs[i].mapIdx];
auto ret =
static_cast<boo::GLDataFactory::Context&>(ctx).
newShaderPipeline(vertSource.c_str(), fragSource.c_str(),
8, ExtTexnames, bc, bn,
boo::BlendFactor((slot.srcFactor == hecl::Backend::BlendFactor::Original) ? blendSrc : slot.srcFactor),
boo::BlendFactor((slot.dstFactor == hecl::Backend::BlendFactor::Original) ? blendDst : slot.dstFactor),
tag.getPrimType(), zTest, slot.noDepthWrite ? false : tag.getDepthWrite(), !slot.noColorWrite, !slot.noAlphaWrite,
(slot.cullMode == hecl::Backend::CullMode::Original) ?
(tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None) :
boo::CullMode(slot.cullMode), !slot.noAlphaOverwrite);
if (!ret)
Log.report(logvisor::Fatal, "unable to build shader");
returnFunc(ret);
}
return true;
}
};
IShaderBackendFactory* _NewGLSLBackendFactory()
{
return new struct GLSLBackendFactory();
}
#if BOO_HAS_VULKAN
struct SPIRVBackendFactory : IShaderBackendFactory
{
Backend::GLSL m_backend;
ShaderCachedData buildShaderFromIR(const ShaderTag& tag,
const hecl::Frontend::IR& ir,
hecl::Frontend::Diagnostics& diag,
boo::IGraphicsDataFactory::Context& ctx,
boo::ObjToken<boo::IShaderPipeline>& objOut)
{
m_backend.reset(ir, diag);
std::string vertSource =
m_backend.makeVert("#version 330",
tag.getColorCount(), tag.getUvCount(), tag.getWeightCount(),
tag.getSkinSlotCount(), 0, nullptr,
tag.getReflectionType());
std::string fragSource = m_backend.makeFrag("#version 330",
tag.getDepthWrite() && m_backend.m_blendDst == hecl::Backend::BlendFactor::InvSrcAlpha,
tag.getReflectionType());
std::vector<unsigned int> vertBlob;
std::vector<unsigned int> fragBlob;
std::vector<unsigned char> pipelineBlob;
objOut =
static_cast<boo::VulkanDataFactory::Context&>(ctx).
newShaderPipeline(vertSource.c_str(), fragSource.c_str(),
&vertBlob, &fragBlob, &pipelineBlob, tag.newVertexFormat(ctx),
boo::BlendFactor(m_backend.m_blendSrc), boo::BlendFactor(m_backend.m_blendDst),
tag.getPrimType(), tag.getDepthTest() ? boo::ZTest::LEqual : boo::ZTest::None,
tag.getDepthWrite(), true, false,
tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None);
if (!objOut)
Log.report(logvisor::Fatal, "unable to build shader");
atUint32 vertSz = vertBlob.size() * sizeof(unsigned int);
atUint32 fragSz = fragBlob.size() * sizeof(unsigned int);
atUint32 pipelineSz = pipelineBlob.size();
size_t cachedSz = 15 + vertSz + fragSz + pipelineSz;
ShaderCachedData dataOut(tag, cachedSz);
athena::io::MemoryWriter w(dataOut.m_data.get(), dataOut.m_sz);
w.writeUByte(atUint8(m_backend.m_texMapEnd));
w.writeUByte(atUint8(m_backend.m_blendSrc));
w.writeUByte(atUint8(m_backend.m_blendDst));
if (vertBlob.size())
{
w.writeUint32Big(vertSz);
w.writeUBytes((atUint8*)vertBlob.data(), vertSz);
}
else
w.writeUint32Big(0);
if (fragBlob.size())
{
w.writeUint32Big(fragSz);
w.writeUBytes((atUint8*)fragBlob.data(), fragSz);
}
else
w.writeUint32Big(0);
if (pipelineBlob.size())
{
w.writeUint32Big(pipelineSz);
w.writeUBytes((atUint8*)pipelineBlob.data(), pipelineSz);
}
else
w.writeUint32Big(0);
return dataOut;
}
boo::ObjToken<boo::IShaderPipeline>
buildShaderFromCache(const ShaderCachedData& data,
boo::IGraphicsDataFactory::Context& ctx)
{
const ShaderTag& tag = data.m_tag;
athena::io::MemoryReader r(data.m_data.get(), data.m_sz, false, false);
size_t texCount = size_t(r.readByte());
boo::BlendFactor blendSrc = boo::BlendFactor(r.readUByte());
boo::BlendFactor blendDst = boo::BlendFactor(r.readUByte());
atUint32 vertSz = r.readUint32Big();
std::vector<unsigned int> vertBlob(vertSz / sizeof(unsigned int));
if (vertSz)
r.readUBytesToBuf(vertBlob.data(), vertSz);
atUint32 fragSz = r.readUint32Big();
std::vector<unsigned int> fragBlob(fragSz / sizeof(unsigned int));
if (fragSz)
r.readUBytesToBuf(fragBlob.data(), fragSz);
atUint32 pipelineSz = r.readUint32Big();
std::vector<unsigned char> pipelineBlob(pipelineSz);
if (pipelineSz)
r.readUBytesToBuf(pipelineBlob.data(), pipelineSz);
if (r.hasError())
return nullptr;
boo::ObjToken<boo::IShaderPipeline> ret =
static_cast<boo::VulkanDataFactory::Context&>(ctx).
newShaderPipeline(nullptr, nullptr,
&vertBlob, &fragBlob, &pipelineBlob,
tag.newVertexFormat(ctx),
blendSrc, blendDst, tag.getPrimType(),
tag.getDepthTest() ? boo::ZTest::LEqual : boo::ZTest::None,
tag.getDepthWrite(), true, false,
tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None);
if (!ret)
Log.report(logvisor::Fatal, "unable to build shader");
return ret;
}
ShaderCachedData buildExtendedShaderFromIR(const ShaderTag& tag,
const hecl::Frontend::IR& ir,
hecl::Frontend::Diagnostics& diag,
const std::vector<ShaderCacheExtensions::ExtensionSlot>& extensionSlots,
boo::IGraphicsDataFactory::Context& ctx,
FReturnExtensionShader returnFunc)
{
m_backend.reset(ir, diag);
struct Blobs
{
std::vector<unsigned int> vert;
std::vector<unsigned int> frag;
std::vector<unsigned char> pipeline;
};
std::vector<Blobs> pipeBlobs;
pipeBlobs.reserve(extensionSlots.size());
size_t cachedSz = 3 + 12 * extensionSlots.size();
for (const ShaderCacheExtensions::ExtensionSlot& slot : extensionSlots)
{
std::string vertSource =
m_backend.makeVert("#version 330",
tag.getColorCount(), tag.getUvCount(), tag.getWeightCount(),
tag.getSkinSlotCount(), slot.texCount, slot.texs,
tag.getReflectionType());
std::string fragSource = m_backend.makeFrag("#version 330",
tag.getDepthWrite() && m_backend.m_blendDst == hecl::Backend::BlendFactor::InvSrcAlpha,
tag.getReflectionType(), slot.lighting, slot.post, slot.texCount, slot.texs);
pipeBlobs.emplace_back();
Blobs& pipeBlob = pipeBlobs.back();
boo::ObjToken<boo::IShaderPipeline> ret =
static_cast<boo::VulkanDataFactory::Context&>(ctx).
newShaderPipeline(vertSource.c_str(), fragSource.c_str(),
&pipeBlob.vert, &pipeBlob.frag, &pipeBlob.pipeline,
tag.newVertexFormat(ctx),
boo::BlendFactor((slot.srcFactor == hecl::Backend::BlendFactor::Original) ?
m_backend.m_blendSrc : slot.srcFactor),
boo::BlendFactor((slot.dstFactor == hecl::Backend::BlendFactor::Original) ?
m_backend.m_blendDst : slot.dstFactor),
tag.getPrimType(), tag.getDepthTest() ? boo::ZTest::LEqual : boo::ZTest::None,
slot.noDepthWrite ? false : tag.getDepthWrite(),
!slot.noColorWrite, !slot.noAlphaWrite,
(slot.cullMode == hecl::Backend::CullMode::Original) ?
(tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None) :
boo::CullMode(slot.cullMode), !slot.noAlphaOverwrite);
if (!ret)
Log.report(logvisor::Fatal, "unable to build shader");
cachedSz += pipeBlob.vert.size() * sizeof(unsigned int);
cachedSz += pipeBlob.frag.size() * sizeof(unsigned int);
cachedSz += pipeBlob.pipeline.size();
returnFunc(ret);
}
ShaderCachedData dataOut(tag, cachedSz);
athena::io::MemoryWriter w(dataOut.m_data.get(), dataOut.m_sz);
w.writeUByte(atUint8(m_backend.m_texMapEnd));
w.writeUByte(atUint8(m_backend.m_blendSrc));
w.writeUByte(atUint8(m_backend.m_blendDst));
for (const Blobs& pipeBlob : pipeBlobs)
{
size_t vertBlobSz = pipeBlob.vert.size() * sizeof(unsigned int);
size_t fragBlobSz = pipeBlob.frag.size() * sizeof(unsigned int);
size_t pipeBlobSz = pipeBlob.pipeline.size();
if (vertBlobSz)
{
w.writeUint32Big(vertBlobSz);
w.writeUBytes((atUint8*)pipeBlob.vert.data(), vertBlobSz);
}
else
w.writeUint32Big(0);
if (fragBlobSz)
{
w.writeUint32Big(fragBlobSz);
w.writeUBytes((atUint8*)pipeBlob.frag.data(), fragBlobSz);
}
else
w.writeUint32Big(0);
if (pipeBlobSz)
{
w.writeUint32Big(pipeBlobSz);
w.writeUBytes((atUint8*)pipeBlob.pipeline.data(), pipeBlobSz);
}
else
w.writeUint32Big(0);
}
return dataOut;
}
bool buildExtendedShaderFromCache(const ShaderCachedData& data,
const std::vector<ShaderCacheExtensions::ExtensionSlot>& extensionSlots,
boo::IGraphicsDataFactory::Context& ctx,
FReturnExtensionShader returnFunc)
{
const ShaderTag& tag = data.m_tag;
athena::io::MemoryReader r(data.m_data.get(), data.m_sz);
size_t texCount = size_t(r.readByte());
hecl::Backend::BlendFactor blendSrc = hecl::Backend::BlendFactor(r.readUByte());
hecl::Backend::BlendFactor blendDst = hecl::Backend::BlendFactor(r.readUByte());
if (r.hasError())
return false;
for (const ShaderCacheExtensions::ExtensionSlot& slot : extensionSlots)
{
atUint32 vertSz = r.readUint32Big();
std::vector<unsigned int> vertBlob(vertSz / sizeof(unsigned int));
if (vertSz)
r.readUBytesToBuf(vertBlob.data(), vertSz);
atUint32 fragSz = r.readUint32Big();
std::vector<unsigned int> fragBlob(fragSz / sizeof(unsigned int));
if (fragSz)
r.readUBytesToBuf(fragBlob.data(), fragSz);
atUint32 pipelineSz = r.readUint32Big();
std::vector<unsigned char> pipelineBlob(pipelineSz);
if (pipelineSz)
r.readUBytesToBuf(pipelineBlob.data(), pipelineSz);
if (r.hasError())
return false;
boo::ZTest zTest;
switch (slot.depthTest)
{
case hecl::Backend::ZTest::Original:
default:
zTest = tag.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;
}
boo::ObjToken<boo::IShaderPipeline> ret =
static_cast<boo::VulkanDataFactory::Context&>(ctx).
newShaderPipeline(nullptr, nullptr,
&vertBlob, &fragBlob, &pipelineBlob,
tag.newVertexFormat(ctx),
boo::BlendFactor((slot.srcFactor == hecl::Backend::BlendFactor::Original) ? blendSrc : slot.srcFactor),
boo::BlendFactor((slot.dstFactor == hecl::Backend::BlendFactor::Original) ? blendDst : slot.dstFactor),
tag.getPrimType(), zTest, slot.noDepthWrite ? false : tag.getDepthWrite(),
!slot.noColorWrite, !slot.noAlphaWrite,
(slot.cullMode == hecl::Backend::CullMode::Original) ?
(tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None) :
boo::CullMode(slot.cullMode), !slot.noAlphaOverwrite);
if (!ret)
Log.report(logvisor::Fatal, "unable to build shader");
returnFunc(ret);
}
return true;
}
};
IShaderBackendFactory* _NewSPIRVBackendFactory()
{
return new struct SPIRVBackendFactory();
}
#endif
}

View File

@ -215,10 +215,10 @@ std::string HLSL::makeVert(unsigned col, unsigned uv, unsigned w,
}
std::string HLSL::makeFrag(bool alphaTest, ReflectionType reflectionType,
const ShaderFunction& lighting) const
const Function& lighting) const
{
std::string lightingSrc;
if (lighting.m_source)
if (!lighting.m_source.empty())
lightingSrc = lighting.m_source;
else
lightingSrc = "static const float4 colorReg0 = float4(1.0, 1.0, 1.0, 1.0);\n"
@ -248,8 +248,9 @@ std::string HLSL::makeFrag(bool alphaTest, ReflectionType reflectionType,
if (m_lighting)
{
if (lighting.m_entry)
retval += hecl::Format(" float4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n", lighting.m_entry);
if (!lighting.m_entry.empty())
retval += hecl::Format(" float4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n",
lighting.m_entry.data());
else
retval += " float4 lighting = float4(1.0,1.0,1.0,1.0);\n";
}
@ -271,12 +272,12 @@ std::string HLSL::makeFrag(bool alphaTest, ReflectionType reflectionType,
}
std::string HLSL::makeFrag(bool alphaTest, ReflectionType reflectionType,
const ShaderFunction& lighting,
const ShaderFunction& post, size_t extTexCount,
const Function& lighting,
const Function& post, size_t extTexCount,
const TextureInfo* extTexs) const
{
std::string lightingSrc;
if (lighting.m_source)
if (!lighting.m_source.empty())
lightingSrc = lighting.m_source;
else
lightingSrc = "static const float4 colorReg0 = float4(1.0, 1.0, 1.0, 1.0);\n"
@ -285,11 +286,11 @@ std::string HLSL::makeFrag(bool alphaTest, ReflectionType reflectionType,
"static const float4 mulColor = float4(1.0, 1.0, 1.0, 1.0);\n";
std::string postSrc;
if (post.m_source)
if (!post.m_source.empty())
postSrc = post.m_source;
std::string postEntry;
if (post.m_entry)
if (!post.m_entry.empty())
postEntry = post.m_entry;
std::string texMapDecl;
@ -323,8 +324,9 @@ std::string HLSL::makeFrag(bool alphaTest, ReflectionType reflectionType,
if (m_lighting)
{
if (lighting.m_entry)
retval += hecl::Format(" float4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n", lighting.m_entry);
if (!lighting.m_entry.empty())
retval += hecl::Format(" float4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n",
lighting.m_entry.data());
else
retval += " float4 lighting = float4(1.0,1.0,1.0,1.0);\n";
}
@ -346,344 +348,3 @@ std::string HLSL::makeFrag(bool alphaTest, ReflectionType reflectionType,
}
}
namespace hecl::Runtime
{
struct HLSLBackendFactory : IShaderBackendFactory
{
Backend::HLSL m_backend;
ShaderCachedData buildShaderFromIR(const ShaderTag& tag,
const hecl::Frontend::IR& ir,
hecl::Frontend::Diagnostics& diag,
boo::IGraphicsDataFactory::Context& ctx,
boo::ObjToken<boo::IShaderPipeline>& objOut)
{
m_backend.reset(ir, diag);
std::string vertSource =
m_backend.makeVert(tag.getColorCount(), tag.getUvCount(), tag.getWeightCount(),
tag.getSkinSlotCount(), 0, nullptr,
tag.getReflectionType());
std::string fragSource = m_backend.makeFrag(tag.getDepthWrite() && m_backend.m_blendDst == hecl::Backend::BlendFactor::InvSrcAlpha,
tag.getReflectionType());
ComPtr<ID3DBlob> vertBlob;
ComPtr<ID3DBlob> fragBlob;
ComPtr<ID3DBlob> pipelineBlob;
objOut =
static_cast<boo::D3DDataFactory::Context&>(ctx).
newShaderPipeline(vertSource.c_str(), fragSource.c_str(),
ReferenceComPtr(vertBlob), ReferenceComPtr(fragBlob), ReferenceComPtr(pipelineBlob),
tag.newVertexFormat(ctx),
boo::BlendFactor(m_backend.m_blendSrc),
boo::BlendFactor(m_backend.m_blendDst),
tag.getPrimType(),
tag.getDepthTest() ? boo::ZTest::LEqual : boo::ZTest::None, tag.getDepthWrite(), true, false,
tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None);
if (!objOut)
Log.report(logvisor::Fatal, "unable to build shader");
atUint32 vertSz = 0;
atUint32 fragSz = 0;
atUint32 pipelineSz = 0;
if (vertBlob)
vertSz = vertBlob->GetBufferSize();
if (fragBlob)
fragSz = fragBlob->GetBufferSize();
if (pipelineBlob)
pipelineSz = pipelineBlob->GetBufferSize();
size_t cachedSz = 14 + vertSz + fragSz + pipelineSz;
ShaderCachedData dataOut(tag, cachedSz);
athena::io::MemoryWriter w(dataOut.m_data.get(), dataOut.m_sz);
w.writeUByte(atUint8(m_backend.m_blendSrc));
w.writeUByte(atUint8(m_backend.m_blendDst));
if (vertBlob)
{
w.writeUint32Big(vertSz);
w.writeUBytes((atUint8*)vertBlob->GetBufferPointer(), vertSz);
}
else
w.writeUint32Big(0);
if (fragBlob)
{
w.writeUint32Big(fragSz);
w.writeUBytes((atUint8*)fragBlob->GetBufferPointer(), fragSz);
}
else
w.writeUint32Big(0);
if (pipelineBlob)
{
w.writeUint32Big(pipelineSz);
w.writeUBytes((atUint8*)pipelineBlob->GetBufferPointer(), pipelineSz);
}
else
w.writeUint32Big(0);
return dataOut;
}
boo::ObjToken<boo::IShaderPipeline>
buildShaderFromCache(const ShaderCachedData& data,
boo::IGraphicsDataFactory::Context& ctx)
{
const ShaderTag& tag = data.m_tag;
athena::io::MemoryReader r(data.m_data.get(), data.m_sz, false, false);
boo::BlendFactor blendSrc = boo::BlendFactor(r.readUByte());
boo::BlendFactor blendDst = boo::BlendFactor(r.readUByte());
if (r.hasError())
return nullptr;
atUint32 vertSz = r.readUint32Big();
ComPtr<ID3DBlob> vertBlob;
if (vertSz)
{
D3DCreateBlobPROC(vertSz, &vertBlob);
r.readUBytesToBuf(vertBlob->GetBufferPointer(), vertSz);
}
atUint32 fragSz = r.readUint32Big();
ComPtr<ID3DBlob> fragBlob;
if (fragSz)
{
D3DCreateBlobPROC(fragSz, &fragBlob);
r.readUBytesToBuf(fragBlob->GetBufferPointer(), fragSz);
}
atUint32 pipelineSz = r.readUint32Big();
ComPtr<ID3DBlob> pipelineBlob;
if (pipelineSz)
{
D3DCreateBlobPROC(pipelineSz, &pipelineBlob);
r.readUBytesToBuf(pipelineBlob->GetBufferPointer(), pipelineSz);
}
if (r.hasError())
return nullptr;
boo::ObjToken<boo::IShaderPipeline> ret =
static_cast<boo::D3DDataFactory::Context&>(ctx).
newShaderPipeline(nullptr, nullptr,
ReferenceComPtr(vertBlob), ReferenceComPtr(fragBlob), ReferenceComPtr(pipelineBlob),
tag.newVertexFormat(ctx),
blendSrc, blendDst, tag.getPrimType(),
tag.getDepthTest() ? boo::ZTest::LEqual : boo::ZTest::None, tag.getDepthWrite(), true, false,
tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None);
if (!ret)
Log.report(logvisor::Fatal, "unable to build shader");
return ret;
}
ShaderCachedData buildExtendedShaderFromIR(const ShaderTag& tag,
const hecl::Frontend::IR& ir,
hecl::Frontend::Diagnostics& diag,
const std::vector<ShaderCacheExtensions::ExtensionSlot>& extensionSlots,
boo::IGraphicsDataFactory::Context& ctx,
FReturnExtensionShader returnFunc)
{
m_backend.reset(ir, diag);
struct Blobs
{
ComPtr<ID3DBlob> vert;
ComPtr<ID3DBlob> frag;
ComPtr<ID3DBlob> pipeline;
};
std::vector<Blobs> pipeBlobs;
pipeBlobs.reserve(extensionSlots.size());
size_t cachedSz = 2 + 12 * extensionSlots.size();
for (const ShaderCacheExtensions::ExtensionSlot& slot : extensionSlots)
{
std::string vertSource =
m_backend.makeVert(tag.getColorCount(), tag.getUvCount(), tag.getWeightCount(),
tag.getSkinSlotCount(), slot.texCount, slot.texs,
tag.getReflectionType());
std::string fragSource = m_backend.makeFrag(tag.getDepthWrite() && m_backend.m_blendDst == hecl::Backend::BlendFactor::InvSrcAlpha,
tag.getReflectionType(), slot.lighting, slot.post, slot.texCount, slot.texs);
pipeBlobs.emplace_back();
Blobs& thisPipeBlobs = pipeBlobs.back();
boo::ZTest zTest;
switch (slot.depthTest)
{
case hecl::Backend::ZTest::Original:
default:
zTest = tag.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;
}
boo::ObjToken<boo::IShaderPipeline> ret =
static_cast<boo::D3DDataFactory::Context&>(ctx).
newShaderPipeline(vertSource.c_str(), fragSource.c_str(),
ReferenceComPtr(thisPipeBlobs.vert), ReferenceComPtr(thisPipeBlobs.frag), ReferenceComPtr(thisPipeBlobs.pipeline),
tag.newVertexFormat(ctx),
boo::BlendFactor((slot.srcFactor == hecl::Backend::BlendFactor::Original) ? m_backend.m_blendSrc : slot.srcFactor),
boo::BlendFactor((slot.dstFactor == hecl::Backend::BlendFactor::Original) ? m_backend.m_blendDst : slot.dstFactor),
tag.getPrimType(), zTest, slot.noDepthWrite ? false : tag.getDepthWrite(),
!slot.noColorWrite, !slot.noAlphaWrite,
(slot.cullMode == hecl::Backend::CullMode::Original) ?
(tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None) :
boo::CullMode(slot.cullMode), !slot.noAlphaOverwrite);
if (!ret)
Log.report(logvisor::Fatal, "unable to build shader");
if (thisPipeBlobs.vert)
cachedSz += thisPipeBlobs.vert->GetBufferSize();
if (thisPipeBlobs.frag)
cachedSz += thisPipeBlobs.frag->GetBufferSize();
if (thisPipeBlobs.pipeline)
cachedSz += thisPipeBlobs.pipeline->GetBufferSize();
returnFunc(ret);
}
ShaderCachedData dataOut(tag, cachedSz);
athena::io::MemoryWriter w(dataOut.m_data.get(), dataOut.m_sz);
w.writeUByte(atUint8(m_backend.m_blendSrc));
w.writeUByte(atUint8(m_backend.m_blendDst));
for (const Blobs& blobs : pipeBlobs)
{
if (blobs.vert)
{
w.writeUint32Big(blobs.vert->GetBufferSize());
w.writeUBytes((atUint8*)blobs.vert->GetBufferPointer(), blobs.vert->GetBufferSize());
}
else
w.writeUint32Big(0);
if (blobs.frag)
{
w.writeUint32Big(blobs.frag->GetBufferSize());
w.writeUBytes((atUint8*)blobs.frag->GetBufferPointer(), blobs.frag->GetBufferSize());
}
else
w.writeUint32Big(0);
if (blobs.pipeline)
{
w.writeUint32Big(blobs.pipeline->GetBufferSize());
w.writeUBytes((atUint8*)blobs.pipeline->GetBufferPointer(), blobs.pipeline->GetBufferSize());
}
else
w.writeUint32Big(0);
}
return dataOut;
}
bool buildExtendedShaderFromCache(const ShaderCachedData& data,
const std::vector<ShaderCacheExtensions::ExtensionSlot>& extensionSlots,
boo::IGraphicsDataFactory::Context& ctx,
FReturnExtensionShader returnFunc)
{
const ShaderTag& tag = data.m_tag;
athena::io::MemoryReader r(data.m_data.get(), data.m_sz, false, false);
hecl::Backend::BlendFactor blendSrc = hecl::Backend::BlendFactor(r.readUByte());
hecl::Backend::BlendFactor blendDst = hecl::Backend::BlendFactor(r.readUByte());
if (r.hasError())
return false;
for (const ShaderCacheExtensions::ExtensionSlot& slot : extensionSlots)
{
atUint32 vertSz = r.readUint32Big();
ComPtr<ID3DBlob> vertBlob;
if (vertSz)
{
D3DCreateBlobPROC(vertSz, &vertBlob);
r.readUBytesToBuf(vertBlob->GetBufferPointer(), vertSz);
}
atUint32 fragSz = r.readUint32Big();
ComPtr<ID3DBlob> fragBlob;
if (fragSz)
{
D3DCreateBlobPROC(fragSz, &fragBlob);
r.readUBytesToBuf(fragBlob->GetBufferPointer(), fragSz);
}
atUint32 pipelineSz = r.readUint32Big();
ComPtr<ID3DBlob> pipelineBlob;
if (pipelineSz)
{
D3DCreateBlobPROC(pipelineSz, &pipelineBlob);
r.readUBytesToBuf(pipelineBlob->GetBufferPointer(), pipelineSz);
}
if (r.hasError())
return false;
boo::ZTest zTest;
switch (slot.depthTest)
{
case hecl::Backend::ZTest::Original:
default:
zTest = tag.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;
}
boo::ObjToken<boo::IShaderPipeline> ret =
static_cast<boo::D3DDataFactory::Context&>(ctx).
newShaderPipeline(nullptr, nullptr,
ReferenceComPtr(vertBlob), ReferenceComPtr(fragBlob), ReferenceComPtr(pipelineBlob),
tag.newVertexFormat(ctx),
boo::BlendFactor((slot.srcFactor == hecl::Backend::BlendFactor::Original) ? blendSrc : slot.srcFactor),
boo::BlendFactor((slot.dstFactor == hecl::Backend::BlendFactor::Original) ? blendDst : slot.dstFactor),
tag.getPrimType(), zTest, slot.noDepthWrite ? false : tag.getDepthWrite(),
!slot.noColorWrite, !slot.noAlphaWrite,
(slot.cullMode == hecl::Backend::CullMode::Original) ?
(tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None) :
boo::CullMode(slot.cullMode), !slot.noAlphaOverwrite);
if (!ret)
Log.report(logvisor::Fatal, "unable to build shader");
returnFunc(ret);
}
return true;
}
};
IShaderBackendFactory* _NewHLSLBackendFactory()
{
return new struct HLSLBackendFactory();
}
}

View File

@ -1,5 +1,4 @@
#include "hecl/Backend/Metal.hpp"
#if BOO_HAS_METAL
#include <athena/MemoryReader.hpp>
#include <athena/MemoryWriter.hpp>
#include <boo/graphicsdev/Metal.hpp>
@ -223,10 +222,10 @@ std::string Metal::makeVert(unsigned col, unsigned uv, unsigned w,
}
std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest,
ReflectionType reflectionType, const ShaderFunction& lighting) const
ReflectionType reflectionType, const Function& lighting) const
{
std::string lightingSrc;
if (lighting.m_source)
if (!lighting.m_source.empty())
lightingSrc = lighting.m_source;
std::string texMapDecl;
@ -259,7 +258,7 @@ std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alp
"{\n"
" FragOut out;\n";
if (lighting.m_source)
if (!lighting.m_source.empty())
{
retval += " float4 colorReg0 = block0.colorReg0;\n"
" float4 colorReg1 = block0.colorReg1;\n"
@ -276,8 +275,9 @@ std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alp
if (m_lighting)
{
if (lighting.m_entry)
retval += hecl::Format(" float4 lighting = %s(%s, vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n", lighting.m_entry, blockCall.c_str());
if (!lighting.m_entry.empty())
retval += hecl::Format(" float4 lighting = %s(%s, vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n",
lighting.m_entry.data(), blockCall.c_str());
else
retval += " float4 lighting = float4(1.0,1.0,1.0,1.0);\n";
}
@ -301,24 +301,24 @@ std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alp
}
std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest,
ReflectionType reflectionType, const ShaderFunction& lighting,
const ShaderFunction& post, size_t extTexCount,
ReflectionType reflectionType, const Function& lighting,
const Function& post, size_t extTexCount,
const TextureInfo* extTexs) const
{
std::string lightingSrc;
if (lighting.m_source)
if (!lighting.m_source.empty())
lightingSrc = lighting.m_source;
std::string postSrc;
if (post.m_source)
if (!post.m_source.empty())
postSrc = post.m_source;
std::string lightingEntry;
if (lighting.m_entry)
if (!lighting.m_entry.empty())
lightingEntry = lighting.m_entry;
std::string postEntry;
if (post.m_entry)
if (!post.m_entry.empty())
postEntry = post.m_entry;
int extTexBits = 0;
@ -371,7 +371,7 @@ std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alp
"{\n"
" FragOut out;\n";
if (lighting.m_source)
if (!lighting.m_source.empty())
{
retval += " float4 colorReg0 = block0.colorReg0;\n"
" float4 colorReg1 = block0.colorReg1;\n"
@ -388,10 +388,10 @@ std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alp
if (m_lighting)
{
if (lighting.m_entry)
if (!lighting.m_entry.empty())
{
retval += " float4 lighting = " + lightingEntry + "(" + blockCall + ", vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf" +
(!strncmp(lighting.m_entry, "EXT", 3) ? (extTexCall.size() ? (", samp, clampSamp," + extTexCall) : "") : "") + ");\n";
(!strncmp(lighting.m_entry.data(), "EXT", 3) ? (extTexCall.size() ? (", samp, clampSamp," + extTexCall) : "") : "") + ");\n";
}
else
retval += " float4 lighting = float4(1.0,1.0,1.0,1.0);\n";
@ -408,14 +408,14 @@ std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alp
{
retval += " out.color = " + postEntry + "(" +
(postEntry.size() ? ("vtf, " + (blockCall.size() ? (blockCall + ", ") : "") +
(!strncmp(post.m_entry, "EXT", 3) ? (extTexCall.size() ? ("samp, clampSamp," + extTexCall + ", ") : "") : "")) : "") +
(!strncmp(post.m_entry.data(), "EXT", 3) ? (extTexCall.size() ? ("samp, clampSamp," + extTexCall + ", ") : "") : "")) : "") +
"float4(" + m_colorExpr + " + " + reflectionExpr + ", " + m_alphaExpr + ")) * mulColor;\n";
}
else
{
retval += " out.color = " + postEntry + "(" +
(postEntry.size() ? ("vtf, " + (blockCall.size() ? (blockCall + ", ") : "") +
(!strncmp(post.m_entry, "EXT", 3) ? (extTexCall.size() ? ("samp, clampSamp," + extTexCall + ", ") : "") : "")) : "") +
(!strncmp(post.m_entry.data(), "EXT", 3) ? (extTexCall.size() ? ("samp, clampSamp," + extTexCall + ", ") : "") : "")) : "") +
"float4(" + m_colorExpr + " + " + reflectionExpr + ", 1.0)) * mulColor;\n";
}
@ -427,265 +427,3 @@ std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alp
}
namespace hecl::Runtime
{
struct MetalBackendFactory : IShaderBackendFactory
{
Backend::Metal m_backend;
ShaderCachedData buildShaderFromIR(const ShaderTag& tag,
const hecl::Frontend::IR& ir,
hecl::Frontend::Diagnostics& diag,
boo::IGraphicsDataFactory::Context& ctx,
boo::ObjToken<boo::IShaderPipeline>& objOut)
{
m_backend.reset(ir, diag);
size_t cachedSz = 2;
std::string vertSource =
m_backend.makeVert(tag.getColorCount(), tag.getUvCount(), tag.getWeightCount(),
tag.getSkinSlotCount(), 0, nullptr, tag.getReflectionType());
std::string fragSource = m_backend.makeFrag(0, nullptr,
tag.getDepthWrite() && m_backend.m_blendDst == hecl::Backend::BlendFactor::InvSrcAlpha,
tag.getReflectionType());
std::vector<uint8_t> vertBlob;
std::vector<uint8_t> fragBlob;
objOut =
static_cast<boo::MetalDataFactory::Context&>(ctx).
newShaderPipeline(vertSource.c_str(), fragSource.c_str(),
&vertBlob, &fragBlob,
tag.newVertexFormat(ctx),
boo::BlendFactor(m_backend.m_blendSrc),
boo::BlendFactor(m_backend.m_blendDst),
tag.getPrimType(),
tag.getDepthTest() ? boo::ZTest::LEqual : boo::ZTest::None, tag.getDepthWrite(), true, true,
tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None);
if (!objOut)
Log.report(logvisor::Fatal, "unable to build shader");
cachedSz += vertBlob.size() + 4;
cachedSz += fragBlob.size() + 4;
ShaderCachedData dataOut(tag, cachedSz);
athena::io::MemoryWriter w(dataOut.m_data.get(), dataOut.m_sz);
w.writeUByte(atUint8(m_backend.m_blendSrc));
w.writeUByte(atUint8(m_backend.m_blendDst));
w.writeUint32Big(vertBlob.size());
w.writeUBytes(vertBlob.data(), vertBlob.size());
w.writeUint32Big(fragBlob.size());
w.writeUBytes(fragBlob.data(), fragBlob.size());
return dataOut;
}
boo::ObjToken<boo::IShaderPipeline> buildShaderFromCache(const ShaderCachedData& data,
boo::IGraphicsDataFactory::Context& ctx)
{
const ShaderTag& tag = data.m_tag;
athena::io::MemoryReader r(data.m_data.get(), data.m_sz, false, false);
boo::BlendFactor blendSrc = boo::BlendFactor(r.readUByte());
boo::BlendFactor blendDst = boo::BlendFactor(r.readUByte());
std::vector<uint8_t> vertBlob;
std::vector<uint8_t> fragBlob;
atUint32 vertLen = r.readUint32Big();
if (vertLen)
{
vertBlob.resize(vertLen);
r.readUBytesToBuf(&vertBlob[0], vertLen);
}
atUint32 fragLen = r.readUint32Big();
if (fragLen)
{
fragBlob.resize(fragLen);
r.readUBytesToBuf(&fragBlob[0], fragLen);
}
if (r.hasError())
return nullptr;
auto ret =
static_cast<boo::MetalDataFactory::Context&>(ctx).
newShaderPipeline(nullptr, nullptr,
&vertBlob, &fragBlob,
tag.newVertexFormat(ctx),
blendSrc, blendDst, tag.getPrimType(),
tag.getDepthTest() ? boo::ZTest::LEqual : boo::ZTest::None, tag.getDepthWrite(), true, true,
tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None);
if (!ret)
Log.report(logvisor::Fatal, "unable to build shader");
return ret;
}
ShaderCachedData buildExtendedShaderFromIR(const ShaderTag& tag,
const hecl::Frontend::IR& ir,
hecl::Frontend::Diagnostics& diag,
const std::vector<ShaderCacheExtensions::ExtensionSlot>& extensionSlots,
boo::IGraphicsDataFactory::Context& ctx,
FReturnExtensionShader returnFunc)
{
m_backend.reset(ir, diag);
size_t cachedSz = 2;
std::vector<std::pair<std::vector<uint8_t>, std::vector<uint8_t>>> blobs;
blobs.reserve(extensionSlots.size());
for (const ShaderCacheExtensions::ExtensionSlot& slot : extensionSlots)
{
std::string vertSource =
m_backend.makeVert(tag.getColorCount(), tag.getUvCount(), tag.getWeightCount(),
tag.getSkinSlotCount(), slot.texCount, slot.texs,
slot.noReflection ? Backend::ReflectionType::None : tag.getReflectionType());
std::string fragSource =
m_backend.makeFrag(slot.blockCount, slot.blockNames,
tag.getDepthWrite() && m_backend.m_blendDst == hecl::Backend::BlendFactor::InvSrcAlpha,
slot.noReflection ? Backend::ReflectionType::None : tag.getReflectionType(),
slot.lighting, slot.post, slot.texCount, slot.texs);
boo::ZTest zTest;
switch (slot.depthTest)
{
case hecl::Backend::ZTest::Original:
default:
zTest = tag.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;
}
blobs.emplace_back();
auto ret =
static_cast<boo::MetalDataFactory::Context&>(ctx).
newShaderPipeline(vertSource.c_str(), fragSource.c_str(),
&blobs.back().first, &blobs.back().second,
tag.newVertexFormat(ctx),
boo::BlendFactor((slot.srcFactor == hecl::Backend::BlendFactor::Original) ? m_backend.m_blendSrc : slot.srcFactor),
boo::BlendFactor((slot.dstFactor == hecl::Backend::BlendFactor::Original) ? m_backend.m_blendDst : slot.dstFactor),
tag.getPrimType(), zTest, slot.noDepthWrite ? false : tag.getDepthWrite(),
!slot.noColorWrite, !slot.noAlphaWrite,
(slot.cullMode == hecl::Backend::CullMode::Original) ?
(tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None) :
boo::CullMode(slot.cullMode), !slot.noAlphaOverwrite);
if (!ret)
Log.report(logvisor::Fatal, "unable to build shader");
cachedSz += blobs.back().first.size() + 4;
cachedSz += blobs.back().second.size() + 4;
returnFunc(ret);
}
ShaderCachedData dataOut(tag, cachedSz);
athena::io::MemoryWriter w(dataOut.m_data.get(), dataOut.m_sz);
w.writeUByte(atUint8(m_backend.m_blendSrc));
w.writeUByte(atUint8(m_backend.m_blendDst));
for (auto& blob : blobs)
{
w.writeUint32Big(blob.first.size());
w.writeUBytes(blob.first.data(), blob.first.size());
w.writeUint32Big(blob.second.size());
w.writeUBytes(blob.second.data(), blob.second.size());
}
return dataOut;
}
bool buildExtendedShaderFromCache(const ShaderCachedData& data,
const std::vector<ShaderCacheExtensions::ExtensionSlot>& extensionSlots,
boo::IGraphicsDataFactory::Context& ctx,
FReturnExtensionShader returnFunc)
{
const ShaderTag& tag = data.m_tag;
athena::io::MemoryReader r(data.m_data.get(), data.m_sz, false, false);
hecl::Backend::BlendFactor blendSrc = hecl::Backend::BlendFactor(r.readUByte());
hecl::Backend::BlendFactor blendDst = hecl::Backend::BlendFactor(r.readUByte());
if (r.hasError())
return false;
for (const ShaderCacheExtensions::ExtensionSlot& slot : extensionSlots)
{
std::vector<uint8_t> vertBlob;
std::vector<uint8_t> fragBlob;
atUint32 vertLen = r.readUint32Big();
if (vertLen)
{
vertBlob.resize(vertLen);
r.readUBytesToBuf(&vertBlob[0], vertLen);
}
atUint32 fragLen = r.readUint32Big();
if (fragLen)
{
fragBlob.resize(fragLen);
r.readUBytesToBuf(&fragBlob[0], fragLen);
}
if (r.hasError())
return false;
boo::ZTest zTest;
switch (slot.depthTest)
{
case hecl::Backend::ZTest::Original:
default:
zTest = tag.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;
}
auto ret =
static_cast<boo::MetalDataFactory::Context&>(ctx).
newShaderPipeline(nullptr, nullptr,
&vertBlob, &fragBlob,
tag.newVertexFormat(ctx),
boo::BlendFactor((slot.srcFactor == hecl::Backend::BlendFactor::Original) ? blendSrc : slot.srcFactor),
boo::BlendFactor((slot.dstFactor == hecl::Backend::BlendFactor::Original) ? blendDst : slot.dstFactor),
tag.getPrimType(), zTest, slot.noDepthWrite ? false : tag.getDepthWrite(),
!slot.noColorWrite, !slot.noAlphaWrite,
(slot.cullMode == hecl::Backend::CullMode::Original) ?
(tag.getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None) :
boo::CullMode(slot.cullMode), !slot.noAlphaOverwrite);
if (!ret)
Log.report(logvisor::Fatal, "unable to build shader");
returnFunc(ret);
}
return true;
}
};
IShaderBackendFactory* _NewMetalBackendFactory()
{
return new struct MetalBackendFactory();
}
}
#endif

View File

@ -6,6 +6,8 @@ macro(hecl_add_list rel_path a_list)
set(${a_list} "${tmp_list}" PARENT_SCOPE)
endmacro(hecl_add_list)
include_directories(../extern/boo/glslang ../extern/boo)
add_subdirectory(Blender)
add_subdirectory(Backend)
add_subdirectory(Frontend)
@ -17,7 +19,6 @@ endif()
atdna(atdna_HMDLMeta.cpp ../include/hecl/HMDLMeta.hpp)
atdna(atdna_Frontend.cpp ../include/hecl/Frontend.hpp)
atdna(atdna_Runtime.cpp ../include/hecl/Runtime.hpp)
atdna(atdna_CVar.cpp ../include/hecl/CVar.hpp)
if("${CMAKE_BUILD_TYPE}" STREQUAL "Release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
@ -50,7 +51,10 @@ set(HECL_HEADERS
../include/hecl/BitVector.hpp
../include/hecl/MathExtras.hpp
../include/hecl/UniformBufferPool.hpp
../include/hecl/VertexBufferPool.hpp)
../include/hecl/VertexBufferPool.hpp
../include/hecl/PipelineBase.hpp
../include/hecl/Pipeline.hpp
../include/hecl/Compilers.hpp)
set(COMMON_SOURCES
hecl.cpp
MultiProgressPrinter.cpp
@ -63,9 +67,10 @@ set(COMMON_SOURCES
ClientProcess.cpp
SteamFinder.cpp
WideStringConvert.cpp
Compilers.cpp
Pipeline.cpp
atdna_HMDLMeta.cpp
atdna_Frontend.cpp
atdna_Runtime.cpp
atdna_CVar.cpp)
add_library(hecl-full
@ -81,10 +86,15 @@ add_library(hecl-light
${COMMON_SOURCES}
${HECL_HEADERS}
${PLAT_SRCS})
add_library(hecl-compilers Compilers.cpp)
add_dependencies(hecl-full ${HECL_APPLICATION_REPS_TARGETS_LIST})
add_dependencies(hecl-light ${HECL_APPLICATION_REPS_TARGETS_LIST})
if(COMMAND add_sanitizers)
add_sanitizers(hecl-full)
add_sanitizers(hecl-light)
add_sanitizers(hecl-compilers)
endif()
if(WINDOWS_STORE)

261
hecl/lib/Compilers.cpp Normal file
View File

@ -0,0 +1,261 @@
#include "hecl/Compilers.hpp"
#include "boo/graphicsdev/GLSLMacros.hpp"
#include "logvisor/logvisor.hpp"
#if BOO_HAS_VULKAN
#include <glslang/Public/ShaderLang.h>
#include <StandAlone/ResourceLimits.h>
#include <SPIRV/GlslangToSpv.h>
#include <SPIRV/disassemble.h>
#endif
namespace hecl
{
logvisor::Module Log("hecl::Compilers");
template<typename P> struct ShaderCompiler {};
template<> struct ShaderCompiler<PlatformType::OpenGL>
{
template<typename S>
static std::pair<std::shared_ptr<uint8_t[]>, size_t> Compile(std::string_view text)
{
std::string str = "#version 330\n";
str += BOO_GLSL_BINDING_HEAD;
str += text;
std::pair<std::shared_ptr<uint8_t[]>, size_t> ret(new uint8_t[str.size() + 1], str.size() + 1);
memcpy(ret.first.get(), str.data(), str.size() + 1);
return ret;
}
};
template<> struct ShaderCompiler<PlatformType::Vulkan>
{
static constexpr EShLanguage ShaderTypes[] =
{
EShLangVertex, /* Invalid */
EShLangVertex,
EShLangFragment,
EShLangGeometry,
EShLangTessControl,
EShLangTessEvaluation
};
template<typename S>
static std::pair<std::shared_ptr<uint8_t[]>, size_t> Compile(std::string_view text)
{
EShLanguage lang = ShaderTypes[int(S::Enum)];
const EShMessages messages = EShMessages(EShMsgSpvRules | EShMsgVulkanRules);
glslang::TShader shader(lang);
const char* strings[] = { "#version 330\n", BOO_GLSL_BINDING_HEAD, text.data() };
shader.setStrings(strings, 3);
if (!shader.parse(&glslang::DefaultTBuiltInResource, 110, false, messages))
{
printf("%s\n", text.data());
Log.report(logvisor::Fatal, "unable to compile shader\n%s", shader.getInfoLog());
return {};
}
glslang::TProgram prog;
prog.addShader(&shader);
if (!prog.link(messages))
{
Log.report(logvisor::Fatal, "unable to link shader program\n%s", prog.getInfoLog());
return {};
}
std::vector<unsigned int> out;
glslang::GlslangToSpv(*prog.getIntermediate(lang), out);
std::pair<std::shared_ptr<uint8_t[]>, size_t> ret(new uint8_t[out.size() * 4], out.size() * 4);
memcpy(ret.first.get(), out.data(), ret.second);
return ret;
}
};
template<> struct ShaderCompiler<PlatformType::NX>
{
template<typename S>
static std::pair<std::shared_ptr<uint8_t[]>, size_t> Compile(std::string_view text)
{
std::string str = "#version 330\n";
str += BOO_GLSL_BINDING_HEAD;
str += text;
std::pair<std::shared_ptr<uint8_t[]>, size_t> ret(new uint8_t[str.size() + 1], str.size() + 1);
memcpy(ret.first.get(), str.data(), str.size() + 1);
return ret;
}
};
template<typename P, typename S>
std::pair<std::shared_ptr<uint8_t[]>, size_t> CompileShader(std::string_view text)
{
return ShaderCompiler<P>::template Compile<S>(text);
}
#define SPECIALIZE_COMPILE_SHADER(P) \
template std::pair<std::shared_ptr<uint8_t[]>, size_t> CompileShader<P, PipelineStage::Vertex>(std::string_view text); \
template std::pair<std::shared_ptr<uint8_t[]>, size_t> CompileShader<P, PipelineStage::Fragment>(std::string_view text); \
template std::pair<std::shared_ptr<uint8_t[]>, size_t> CompileShader<P, PipelineStage::Geometry>(std::string_view text); \
template std::pair<std::shared_ptr<uint8_t[]>, size_t> CompileShader<P, PipelineStage::Control>(std::string_view text); \
template std::pair<std::shared_ptr<uint8_t[]>, size_t> CompileShader<P, PipelineStage::Evaluation>(std::string_view text);
SPECIALIZE_COMPILE_SHADER(PlatformType::OpenGL)
SPECIALIZE_COMPILE_SHADER(PlatformType::Vulkan)
#if _WIN32
SPECIALIZE_COMPILE_SHADER(PlatformType::D3D11)
#endif
#if __APPLE__
SPECIALIZE_COMPILE_SHADER(PlatformType::Metal)
#endif
#if HECL_NOUVEAU_NX
SPECIALIZE_COMPILE_SHADER(PlatformType::NX)
#endif
#if _WIN32
static const char* ShaderTypes[] =
{
"vs_5_0",
"ps_5_0",
"gs_5_0",
"hs_5_0",
"ds_5_0"
};
template<>
std::vector<uint8_t> CompileShader<PlatformType::D3D11>(std::string_view text, PipelineStage stage)
{
ComPtr<ID3DBlob> errBlob;
ComPtr<ID3DBlob> blobOut;
if (FAILED(D3DCompilePROC(text.data(), text.size(), "Boo HLSL Source", nullptr, nullptr, "main",
ShaderTypes[int(stage)], BOO_D3DCOMPILE_FLAG, 0, &blobOut, &errBlob)))
{
printf("%s\n", source);
Log.report(logvisor::Fatal, "error compiling shader: %s", errBlob->GetBufferPointer());
return {};
}
std::vector<uint8_t> ret(blobOut.GetBufferSize());
memcpy(ret.data(), blobOut.GetBufferPointer(), blobOut.GetBufferSize());
return ret;
};
#endif
#if BOO_HAS_METAL
static int HasMetalCompiler = -1;
static void CheckForMetalCompiler()
{
pid_t pid = fork();
if (!pid)
{
execlp("xcrun", "xcrun", "-sdk", "macosx", "metal", NULL);
/* xcrun returns 72 if metal command not found;
* emulate that if xcrun not found */
exit(72);
}
int status, ret;
while ((ret = waitpid(pid, &status, 0)) < 0 && errno == EINTR) {}
if (ret < 0)
HasMetalCompiler = 0;
else
HasMetalCompiler = WEXITSTATUS(status) == 1;
}
template<>
std::vector<uint8_t> CompileShader<PlatformType::Metal>(std::string_view text, PipelineStage stage)
{
if (HasMetalCompiler == -1)
CheckForMetalCompiler();
std::vector<uint8_t> blobOut;
if (!HasMetalCompiler)
{
/* Cache the source if there's no compiler */
size_t sourceLen = strlen(source);
/* First byte unset to indicate source data */
blobOut.resize(sourceLen + 2);
memcpy(&blobOut[1], source, sourceLen);
}
else
{
/* Cache the binary otherwise */
int compilerOut[2];
int compilerIn[2];
pipe(compilerOut);
pipe(compilerIn);
/* Pipe source write to compiler */
pid_t compilerPid = fork();
if (!compilerPid)
{
dup2(compilerIn[0], STDIN_FILENO);
dup2(compilerOut[1], STDOUT_FILENO);
close(compilerOut[0]);
close(compilerOut[1]);
close(compilerIn[0]);
close(compilerIn[1]);
execlp("xcrun", "xcrun", "-sdk", "macosx", "metal", "-o", "/dev/stdout", "-Wno-unused-variable",
"-Wno-unused-const-variable", "-Wno-unused-function", "-x", "metal", "-", NULL);
fprintf(stderr, "execlp fail %s\n", strerror(errno));
exit(1);
}
close(compilerIn[0]);
close(compilerOut[1]);
/* Pipe compiler to linker */
pid_t linkerPid = fork();
if (!linkerPid)
{
dup2(compilerOut[0], STDIN_FILENO);
close(compilerOut[0]);
close(compilerIn[1]);
/* metallib doesn't like outputting to a pipe, so temp file will have to do */
execlp("xcrun", "xcrun", "-sdk", "macosx", "metallib", "-", "-o", m_libfile, NULL);
fprintf(stderr, "execlp fail %s\n", strerror(errno));
exit(1);
}
close(compilerOut[0]);
/* Stream in source */
const char* inPtr = source;
size_t inRem = strlen(source);
while (inRem)
{
ssize_t writeRes = write(compilerIn[1], inPtr, inRem);
if (writeRes < 0)
{
fprintf(stderr, "write fail %s\n", strerror(errno));
break;
}
inPtr += writeRes;
inRem -= writeRes;
}
close(compilerIn[1]);
/* Wait for completion */
int compilerStat, linkerStat;
if (waitpid(compilerPid, &compilerStat, 0) < 0 || waitpid(linkerPid, &linkerStat, 0) < 0)
{
fprintf(stderr, "waitpid fail %s\n", strerror(errno));
return {};
}
if (WEXITSTATUS(compilerStat) || WEXITSTATUS(linkerStat))
return {};
/* Copy temp file into buffer with first byte set to indicate binary data */
FILE* fin = fopen(m_libfile, "rb");
fseek(fin, 0, SEEK_END);
long libLen = ftell(fin);
fseek(fin, 0, SEEK_SET);
blobOut.resize(libLen + 1);
blobOut[0] = 1;
fread(&blobOut[1], 1, libLen, fin);
fclose(fin);
}
return blobOut;
}
#endif
}

View File

@ -490,14 +490,6 @@ void Console::dumpLog()
void Console::RegisterLogger(Console* con)
{
/* Determine if console logger already added */
for (auto& logger : logvisor::MainLoggers)
{
if (typeid(logger.get()) == typeid(LogVisorAdapter))
return;
}
/* Otherwise construct new console logger */
logvisor::MainLoggers.emplace_back(new LogVisorAdapter(con));
}

181
hecl/lib/Pipeline.cpp Normal file
View File

@ -0,0 +1,181 @@
#include "hecl/Pipeline.hpp"
#include "athena/FileReader.hpp"
#include <zlib.h>
namespace hecl
{
#if HECL_RUNTIME
PipelineConverterBase* conv = nullptr;
class ShaderCacheZipStream : public athena::io::IStreamReader
{
std::unique_ptr<uint8_t[]> m_compBuf;
athena::io::FileReader m_reader;
z_stream m_zstrm = {};
public:
explicit ShaderCacheZipStream(const hecl::SystemChar* path)
: m_reader(path)
{
if (m_reader.hasError())
return;
if (m_reader.readUint32Big() != SBIG('SHAD'))
return;
m_compBuf.reset(new uint8_t[4096]);
m_zstrm.next_in = m_compBuf.get();
m_zstrm.avail_in = 0;
inflateInit(&m_zstrm);
}
~ShaderCacheZipStream()
{
inflateEnd(&m_zstrm);
}
operator bool() const { return m_compBuf.operator bool(); }
atUint64 readUBytesToBuf(void *buf, atUint64 len)
{
m_zstrm.next_out = (Bytef*)buf;
m_zstrm.avail_out = len;
m_zstrm.total_out = 0;
while (m_zstrm.avail_out != 0)
{
if (m_zstrm.avail_in == 0)
{
atUint64 readSz = m_reader.readUBytesToBuf(m_compBuf.get(), 4096);
m_zstrm.avail_in = readSz;
m_zstrm.next_in = m_compBuf.get();
}
int inflateRet = inflate(&m_zstrm, Z_NO_FLUSH);
if (inflateRet != Z_OK)
break;
}
return m_zstrm.total_out;
}
void seek(atInt64, athena::SeekOrigin) {}
atUint64 position() const {return 0;}
atUint64 length() const {return 0;}
};
template<typename P, typename S>
void StageConverter<P, S>::loadFromStream(FactoryCtx& ctx, ShaderCacheZipStream& r)
{
uint32_t count = r.readUint32Big();
for (uint32_t i = 0; i < count; ++i)
{
uint64_t hash = r.readUint64Big();
uint32_t size = r.readUint32Big();
std::shared_ptr<uint8_t[]> data(new uint8_t[size]);
r.readUBytesToBuf(data.get(), size);
m_stageCache.insert(std::make_pair(hash, Do<StageTargetTp>(ctx, StageBinary<P, S>(data, size))));
}
}
static boo::AdditionalPipelineInfo ReadAdditionalInfo(ShaderCacheZipStream& r)
{
boo::AdditionalPipelineInfo additionalInfo;
additionalInfo.srcFac = boo::BlendFactor(r.readUint32Big());
additionalInfo.dstFac = boo::BlendFactor(r.readUint32Big());
additionalInfo.prim = boo::Primitive(r.readUint32Big());
additionalInfo.depthTest = boo::ZTest(r.readUint32Big());
additionalInfo.depthWrite = r.readBool();
additionalInfo.colorWrite = r.readBool();
additionalInfo.alphaWrite = r.readBool();
additionalInfo.culling = boo::CullMode(r.readUint32Big());
additionalInfo.patchSize = r.readUint32Big();
additionalInfo.overwriteAlpha = r.readBool();
additionalInfo.depthAttachment = r.readBool();
return additionalInfo;
}
static std::vector<boo::VertexElementDescriptor> ReadVertexFormat(ShaderCacheZipStream& r)
{
std::vector<boo::VertexElementDescriptor> ret;
uint32_t count = r.readUint32Big();
ret.reserve(count);
for (int i = 0; i < count; ++i)
{
ret.emplace_back();
ret.back().semantic = boo::VertexSemantic(r.readUint32Big());
ret.back().semanticIdx = int(r.readUint32Big());
}
return ret;
}
template<typename P>
bool PipelineConverter<P>::loadFromFile(FactoryCtx& ctx, const hecl::SystemChar* path)
{
ShaderCacheZipStream r(path);
if (!r)
return false;
m_vertexConverter.loadFromStream(ctx, r);
m_fragmentConverter.loadFromStream(ctx, r);
m_geometryConverter.loadFromStream(ctx, r);
m_controlConverter.loadFromStream(ctx, r);
m_evaluationConverter.loadFromStream(ctx, r);
uint32_t count = r.readUint32Big();
for (uint32_t i = 0; i < count; ++i)
{
uint64_t hash = r.readUint64Big();
StageRuntimeObject<P, PipelineStage::Vertex> vertex;
StageRuntimeObject<P, PipelineStage::Fragment> fragment;
StageRuntimeObject<P, PipelineStage::Geometry> geometry;
StageRuntimeObject<P, PipelineStage::Control> control;
StageRuntimeObject<P, PipelineStage::Evaluation> evaluation;
if (uint64_t vhash = r.readUint64Big())
vertex = m_vertexConverter.m_stageCache.find(vhash)->second;
if (uint64_t fhash = r.readUint64Big())
fragment = m_fragmentConverter.m_stageCache.find(fhash)->second;
if (uint64_t ghash = r.readUint64Big())
geometry = m_geometryConverter.m_stageCache.find(ghash)->second;
if (uint64_t chash = r.readUint64Big())
control = m_controlConverter.m_stageCache.find(chash)->second;
if (uint64_t ehash = r.readUint64Big())
evaluation = m_evaluationConverter.m_stageCache.find(ehash)->second;
boo::AdditionalPipelineInfo additionalInfo = ReadAdditionalInfo(r);
std::vector<boo::VertexElementDescriptor> vtxFmt = ReadVertexFormat(r);
m_pipelineCache.insert(std::make_pair(hash, FinalPipeline<P>(*this, ctx,
StageCollection<StageRuntimeObject<P, PipelineStage::Null>>
(vertex, fragment, geometry, control, evaluation, additionalInfo,
boo::VertexFormatInfo(vtxFmt.size(), vtxFmt.data())))));
}
return true;
}
#define SPECIALIZE_STAGE_CONVERTER(P) \
template class StageConverter<P, PipelineStage::Vertex>; \
template class StageConverter<P, PipelineStage::Fragment>; \
template class StageConverter<P, PipelineStage::Geometry>; \
template class StageConverter<P, PipelineStage::Control>; \
template class StageConverter<P, PipelineStage::Evaluation>;
#if BOO_HAS_GL
template class PipelineConverter<PlatformType::OpenGL>;
SPECIALIZE_STAGE_CONVERTER(PlatformType::OpenGL)
#endif
#if BOO_HAS_VULKAN
template class PipelineConverter<PlatformType::Vulkan>;
SPECIALIZE_STAGE_CONVERTER(PlatformType::Vulkan)
#endif
#if _WIN32
template class PipelineConverter<PlatformType::D3D11>;
SPECIALIZE_STAGE_CONVERTER(PlatformType::D3D11)
#endif
#if BOO_HAS_METAL
template class PipelineConverter<PlatformType::Metal>;
SPECIALIZE_STAGE_CONVERTER(PlatformType::Metal)
#endif
#if BOO_HAS_NX
template class PipelineConverter<PlatformType::NX>;
SPECIALIZE_STAGE_CONVERTER(PlatformType::NX)
#endif
#endif
}

View File

@ -1,6 +1,5 @@
set(RUNTIME_SOURCES
FileStoreManager.cpp
ShaderCacheManager.cpp
HMDL_RT.cpp)
hecl_add_list(Runtime RUNTIME_SOURCES)

View File

@ -20,83 +20,32 @@ HMDLData::HMDLData(boo::IGraphicsDataFactory::Context& ctx,
m_vbo = ctx.newStaticBuffer(boo::BufferUse::Vertex, vbo, meta.vertStride, meta.vertCount);
m_ibo = ctx.newStaticBuffer(boo::BufferUse::Index, ibo, 4, meta.indexCount);
if (ctx.bindingNeedsVertexFormat())
m_vtxFmt = NewVertexFormat(ctx, meta, m_vbo.get(), m_ibo.get());
}
/* For binding constructors that require vertex format up front (GLSL) */
boo::ObjToken<boo::IVertexFormat>
HMDLData::NewVertexFormat(boo::IGraphicsDataFactory::Context& ctx, const HMDLMeta& meta,
const boo::ObjToken<boo::IGraphicsBuffer>& vbo,
const boo::ObjToken<boo::IGraphicsBuffer>& ibo)
{
size_t elemCount = 2 + meta.colorCount + meta.uvCount + meta.weightCount;
std::unique_ptr<boo::VertexElementDescriptor[]> vdescs(new boo::VertexElementDescriptor[elemCount]);
for (size_t i=0 ; i<elemCount ; ++i)
{
vdescs[i].vertBuffer = vbo;
vdescs[i].indexBuffer = ibo;
}
m_vtxFmtData.reset(new boo::VertexElementDescriptor[elemCount]);
vdescs[0].semantic = boo::VertexSemantic::Position3;
vdescs[1].semantic = boo::VertexSemantic::Normal3;
m_vtxFmtData[0].semantic = boo::VertexSemantic::Position3;
m_vtxFmtData[1].semantic = boo::VertexSemantic::Normal3;
size_t e = 2;
for (size_t i=0 ; i<meta.colorCount ; ++i, ++e)
{
vdescs[e].semantic = boo::VertexSemantic::ColorUNorm;
vdescs[e].semanticIdx = i;
m_vtxFmtData[e].semantic = boo::VertexSemantic::ColorUNorm;
m_vtxFmtData[e].semanticIdx = i;
}
for (size_t i=0 ; i<meta.uvCount ; ++i, ++e)
{
vdescs[e].semantic = boo::VertexSemantic::UV2;
vdescs[e].semanticIdx = i;
m_vtxFmtData[e].semantic = boo::VertexSemantic::UV2;
m_vtxFmtData[e].semanticIdx = i;
}
for (size_t i=0 ; i<meta.weightCount ; ++i, ++e)
{
vdescs[e].semantic = boo::VertexSemantic::Weight;
vdescs[e].semanticIdx = i;
m_vtxFmtData[e].semantic = boo::VertexSemantic::Weight;
m_vtxFmtData[e].semanticIdx = i;
}
return ctx.newVertexFormat(elemCount, vdescs.get());
}
/* For shader constructors that require vertex format up-front (HLSL/Metal/Vulkan) */
boo::ObjToken<boo::IVertexFormat> ShaderTag::newVertexFormat(boo::IGraphicsDataFactory::Context& ctx) const
{
size_t elemCount = 2 + m_colorCount + m_uvCount + m_weightCount;
std::unique_ptr<boo::VertexElementDescriptor[]> vdescs(new boo::VertexElementDescriptor[elemCount]);
for (size_t i=0 ; i<elemCount ; ++i)
{
vdescs[i].vertBuffer = nullptr;
vdescs[i].indexBuffer = nullptr;
}
vdescs[0].semantic = boo::VertexSemantic::Position3;
vdescs[1].semantic = boo::VertexSemantic::Normal3;
size_t e = 2;
for (size_t i=0 ; i<m_colorCount ; ++i, ++e)
{
vdescs[e].semantic = boo::VertexSemantic::ColorUNorm;
vdescs[e].semanticIdx = i;
}
for (size_t i=0 ; i<m_uvCount ; ++i, ++e)
{
vdescs[e].semantic = boo::VertexSemantic::UV2;
vdescs[e].semanticIdx = i;
}
for (size_t i=0 ; i<m_weightCount ; ++i, ++e)
{
vdescs[e].semantic = boo::VertexSemantic::Weight;
vdescs[e].semanticIdx = i;
}
return ctx.newVertexFormat(elemCount, vdescs.get());
m_vtxFmt = boo::VertexFormatInfo(elemCount, m_vtxFmtData.get());
}
}

View File

@ -1,590 +0,0 @@
#include "hecl/Runtime.hpp"
#include <athena/FileReader.hpp>
#include <athena/FileWriter.hpp>
#include <zlib.h>
#include <algorithm>
#include <ctime>
#include "hecl/Backend/GLSL.hpp"
#include "hecl/Backend/Metal.hpp"
#undef min
#undef max
namespace hecl::Runtime
{
#if BOO_HAS_GL
IShaderBackendFactory* _NewGLSLBackendFactory();
#endif
#if _WIN32
IShaderBackendFactory* _NewHLSLBackendFactory();
#endif
#if BOO_HAS_METAL
IShaderBackendFactory* _NewMetalBackendFactory();
#endif
#if BOO_HAS_VULKAN
IShaderBackendFactory* _NewSPIRVBackendFactory();
#endif
static logvisor::Module SCM_Log("ShaderCacheManager");
static uint64_t IDX_MAGIC = SBig(uint64_t(0xDEADFEEDC001D00D));
static uint64_t DAT_MAGIC = SBig(uint64_t(0xC001D00DDEADBABE));
static uint64_t ZERO64 = 0;
static uint64_t timeHash()
{
char buf[80];
time_t now;
struct tm* timeinfo;
time(&now);
timeinfo = localtime(&now);
strftime(buf, 80, "%Y-%m-%dT%H:%M:%S+%H:%M", timeinfo);
Hash tmp(buf, 80);
return tmp.val64();
}
static void UpdateFunctionHash(XXH64_state_t* st, const ShaderCacheExtensions::Function& func)
{
if (func.m_source)
XXH64_update(st, func.m_source, strlen(func.m_source));
if (func.m_entry)
XXH64_update(st, func.m_entry, strlen(func.m_entry));
}
template<typename T>
static void UpdateFieldHash(XXH64_state_t* st, T field)
{
XXH64_update(st, &field, sizeof(field));
}
uint64_t ShaderCacheExtensions::hashExtensions() const
{
XXH64_state_t st;
XXH64_reset(&st, 0);
for (const ExtensionSlot& slot : m_extensionSlots)
{
UpdateFunctionHash(&st, slot.lighting);
UpdateFunctionHash(&st, slot.post);
UpdateFieldHash(&st, slot.srcFactor);
UpdateFieldHash(&st, slot.dstFactor);
UpdateFieldHash(&st, slot.depthTest);
UpdateFieldHash(&st, slot.cullMode);
UpdateFieldHash(&st, slot.noDepthWrite);
UpdateFieldHash(&st, slot.noColorWrite);
UpdateFieldHash(&st, slot.noAlphaWrite);
UpdateFieldHash(&st, slot.noAlphaOverwrite);
UpdateFieldHash(&st, slot.noReflection);
}
return XXH64_digest(&st);
}
void ShaderCacheManager::bootstrapIndex()
{
m_timeHash = timeHash();
m_idxFr.close();
m_datFr.close();
#if _WIN32
SystemString idxFilename = m_idxFr.wfilename();
#else
SystemString idxFilename = m_idxFr.filename();
#endif
FILE* idxFp = hecl::Fopen(idxFilename.c_str(), _S("wb"));
if (!idxFp)
SCM_Log.report(logvisor::Fatal, _S("unable to write shader cache index at %s"),
idxFilename.c_str());
fwrite(&IDX_MAGIC, 1, 8, idxFp);
fwrite(&m_timeHash, 1, 8, idxFp);
fwrite(&m_extensionsHash, 1, 8, idxFp);
fwrite(&ZERO64, 1, 8, idxFp);
fclose(idxFp);
#if _WIN32
SystemString datFilename = m_datFr.wfilename();
#else
SystemString datFilename = m_datFr.filename();
#endif
FILE* datFp = hecl::Fopen(datFilename.c_str(), _S("wb"));
if (!datFp)
SCM_Log.report(logvisor::Fatal, _S("unable to write shader cache data at %s"),
datFilename.c_str());
fwrite(&DAT_MAGIC, 1, 8, datFp);
fwrite(&m_timeHash, 1, 8, datFp);
fclose(datFp);
m_idxFr.open();
m_datFr.open();
}
ShaderCacheManager::ShaderCacheManager(const FileStoreManager& storeMgr,
boo::IGraphicsDataFactory* gfxFactory,
ShaderCacheExtensions&& extension)
: m_storeMgr(storeMgr),
m_extensions(std::move(extension)),
m_idxFr(SystemString(storeMgr.getStoreRoot()) + _S("/shadercache") +
gfxFactory->platformName() + _S(".idx"), 32*1024, false),
m_datFr(SystemString(storeMgr.getStoreRoot()) + _S("/shadercache") +
gfxFactory->platformName() + _S(".dat"), 32*1024, false)
{
boo::IGraphicsDataFactory::Platform plat = gfxFactory->platform();
if (m_extensions && m_extensions.m_plat != plat)
SCM_Log.report(logvisor::Fatal, "ShaderCacheExtension backend mismatch (should be %s)",
gfxFactory->platformName());
m_extensionsHash = m_extensions.hashExtensions();
switch (plat)
{
#if BOO_HAS_GL
case boo::IGraphicsDataFactory::Platform::OpenGL:
m_factory.reset(_NewGLSLBackendFactory());
break;
#endif
#if _WIN32
case boo::IGraphicsDataFactory::Platform::D3D11:
m_factory.reset(_NewHLSLBackendFactory());
break;
#endif
#if BOO_HAS_METAL
case boo::IGraphicsDataFactory::Platform::Metal:
m_factory.reset(_NewMetalBackendFactory());
break;
#endif
#if BOO_HAS_VULKAN
case boo::IGraphicsDataFactory::Platform::Vulkan:
m_factory.reset(_NewSPIRVBackendFactory());
break;
#endif
default:
SCM_Log.report(logvisor::Fatal, _S("unsupported backend %s"), gfxFactory->platformName());
}
reload();
}
void ShaderCacheManager::reload()
{
m_entries.clear();
m_entryLookup.clear();
m_timeHash = 0;
/* Attempt to open existing index */
m_idxFr.seek(0, athena::Begin);
m_datFr.seek(0, athena::Begin);
if (m_idxFr.hasError() || m_datFr.hasError())
{
bootstrapIndex();
return;
}
else
{
uint64_t idxMagic;
size_t rb = m_idxFr.readUBytesToBuf(&idxMagic, 8);
if (rb != 8 || idxMagic != IDX_MAGIC)
{
bootstrapIndex();
return;
}
uint64_t datMagic;
rb = m_datFr.readUBytesToBuf(&datMagic, 8);
if (rb != 8 || datMagic != DAT_MAGIC)
{
bootstrapIndex();
return;
}
uint64_t idxRand, datRand;
rb = m_idxFr.readUBytesToBuf(&idxRand, 8);
size_t rb2 = m_datFr.readUBytesToBuf(&datRand, 8);
if (rb != 8 || rb2 != 8 || idxRand != datRand)
{
bootstrapIndex();
return;
}
m_timeHash = idxRand;
}
atUint64 extensionsHash;
size_t rb = m_idxFr.readUBytesToBuf(&extensionsHash, 8);
if (rb != 8 || extensionsHash != m_extensionsHash)
{
bootstrapIndex();
return;
}
atUint64 idxCount = m_idxFr.readUint64Big();
if (m_idxFr.position() != 32)
{
bootstrapIndex();
return;
}
/* Read existing entries */
if (idxCount)
{
m_entries.reserve(idxCount);
m_entryLookup.reserve(idxCount);
for (atUint64 i=0 ; i<idxCount ; ++i)
{
m_entries.emplace_back();
IndexEntry& ent = m_entries.back();
ent.read(m_idxFr);
m_entryLookup[ent.m_hash] = m_entries.size() - 1;
}
}
}
ShaderCachedData ShaderCacheManager::lookupData(const Hash& hash)
{
auto search = m_entryLookup.find(hash);
if (search == m_entryLookup.cend())
return {};
const IndexEntry& ent = m_entries[search->second];
if (ent.m_compOffset + ent.m_compSize > m_datFr.length())
{
SCM_Log.report(logvisor::Warning, "shader cache not long enough to read entry, might be corrupt");
return {};
}
/* File-streamed decompression */
m_datFr.seek(ent.m_compOffset, athena::Begin);
ShaderCachedData ret(ShaderTag(ent.m_hash, ent.m_meta), ent.m_decompSize);
uint8_t compDat[2048];
z_stream z = {};
inflateInit(&z);
z.avail_out = ent.m_decompSize;
z.next_out = ret.m_data.get();
while (z.avail_out)
{
z.avail_in = std::min(size_t(2048), size_t(ent.m_compSize - z.total_in));
m_datFr.readUBytesToBuf(compDat, z.avail_in);
z.next_in = compDat;
int ret = inflate(&z, Z_NO_FLUSH);
if (ret == Z_STREAM_END)
break;
if (ret != Z_OK)
{
inflateEnd(&z);
return {};
}
}
inflateEnd(&z);
return ret;
}
bool ShaderCacheManager::addData(const ShaderCachedData& data)
{
m_idxFr.close();
m_datFr.close();
/* Perform one-shot buffer compression */
uLong cBound = compressBound(data.m_sz);
void* compBuf = malloc(cBound);
if (compress((Bytef*)compBuf, &cBound, (Bytef*)data.m_data.get(), data.m_sz) != Z_OK)
SCM_Log.report(logvisor::Fatal, "unable to deflate data");
/* Open index for writing (non overwriting) */
athena::io::FileWriter idxFw(m_idxFr.filename(), false);
if (idxFw.hasError())
SCM_Log.report(logvisor::Fatal, _S("unable to append shader cache index at %s"),
m_idxFr.filename().c_str());
/* Open data for writing (non overwriting) */
athena::io::FileWriter datFw(m_datFr.filename(), false);
if (datFw.hasError())
SCM_Log.report(logvisor::Fatal, _S("unable to append shader cache data at %s"),
m_datFr.filename().c_str());
size_t targetOffset = 0;
auto search = m_entryLookup.find(data.m_tag);
if (search != m_entryLookup.cend())
{
/* Hash already present, attempt to replace data */
IndexEntry& ent = m_entries[search->second];
if (search->second == m_entries.size() - 1)
{
/* Replacing final entry; simply write-over */
ent.m_meta = data.m_tag.getMetaData();
ent.m_compSize = cBound;
ent.m_decompSize = data.m_sz;
targetOffset = ent.m_compOffset;
idxFw.seek(search->second * 32 + 32);
ent.write(idxFw);
}
else
{
/* Replacing non-final entry; write into available space */
IndexEntry& nent = m_entries[search->second+1];
size_t space = nent.m_compOffset - ent.m_compOffset;
if (cBound <= space)
{
ent.m_meta = data.m_tag.getMetaData();
ent.m_compSize = cBound;
ent.m_decompSize = data.m_sz;
targetOffset = ent.m_compOffset;
idxFw.seek(search->second * 32 + 32);
ent.write(idxFw);
}
else
{
/* Not enough space; null-entry and add to end */
ent.m_hash = 0;
ent.m_meta = 0;
ent.m_compOffset = 0;
ent.m_compSize = 0;
ent.m_decompSize = 0;
idxFw.seek(search->second * 32 + 32);
ent.write(idxFw);
}
}
}
if (!targetOffset)
{
/* New index entry at end */
idxFw.seek(24, athena::Begin);
idxFw.writeUint64Big(m_entries.size() + 1);
idxFw.seek(m_entries.size() * 32 + 32, athena::Begin);
datFw.seek(0, athena::End);
m_entryLookup[data.m_tag] = m_entries.size();
m_entries.emplace_back();
IndexEntry& ent = m_entries.back();
ent.m_hash = data.m_tag.val64();
ent.m_meta = data.m_tag.getMetaData();
ent.m_compOffset = datFw.position();
ent.m_compSize = cBound;
ent.m_decompSize = data.m_sz;
ent.write(idxFw);
datFw.writeUBytes((atUint8*)compBuf, cBound);
}
else
{
/* Reusing index entry and data space */
datFw.seek(targetOffset, athena::Begin);
datFw.writeUBytes((atUint8*)compBuf, cBound);
}
free(compBuf);
idxFw.close();
datFw.close();
m_idxFr.open();
m_datFr.open();
return true;
}
boo::ObjToken<boo::IShaderPipeline>
ShaderCacheManager::buildFromCache(const ShaderCachedData& foundData,
boo::IGraphicsDataFactory::Context& ctx)
{
return m_factory->buildShaderFromCache(foundData, ctx);
}
std::shared_ptr<ShaderPipelines>
ShaderCacheManager::buildShader(const ShaderTag& tag, std::string_view source,
std::string_view diagName,
boo::IGraphicsDataFactory& factory)
{
auto search = m_pipelineLookup.find(tag);
if (search != m_pipelineLookup.cend())
return search->second;
std::shared_ptr<ShaderPipelines> ret = std::make_shared<ShaderPipelines>();
ShaderCachedData foundData = lookupData(tag);
if (foundData)
{
factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx)
{
SCM_Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.data(), tag.val64());
boo::ObjToken<boo::IShaderPipeline> build = buildFromCache(foundData, ctx);
if (build)
{
ret->m_pipelines.push_back(build);
return true;
}
return false;
} BooTrace);
if (ret->m_pipelines.size())
{
m_pipelineLookup[tag] = ret;
return ret;
}
SCM_Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.data());
}
factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx)
{
hecl::Frontend::IR ir = FE.compileSource(source, diagName);
SCM_Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.data(), tag.val64());
FE.getDiagnostics().reset(diagName);
boo::ObjToken<boo::IShaderPipeline> build;
addData(m_factory->buildShaderFromIR(tag, ir, FE.getDiagnostics(), ctx, build));
ret->m_pipelines.push_back(build);
return true;
} BooTrace);
m_pipelineLookup[tag] = ret;
return ret;
}
std::shared_ptr<ShaderPipelines>
ShaderCacheManager::buildShader(const ShaderTag& tag, const hecl::Frontend::IR& ir,
std::string_view diagName,
boo::IGraphicsDataFactory& factory)
{
auto search = m_pipelineLookup.find(tag);
if (search != m_pipelineLookup.cend())
return search->second;
std::shared_ptr<ShaderPipelines> ret = std::make_shared<ShaderPipelines>();
ShaderCachedData foundData = lookupData(tag);
if (foundData)
{
factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx)
{
SCM_Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.data(), tag.val64());
boo::ObjToken<boo::IShaderPipeline> build = buildFromCache(foundData, ctx);
if (build)
{
ret->m_pipelines.push_back(build);
return true;
}
return false;
} BooTrace);
if (ret->m_pipelines.size())
{
m_pipelineLookup[tag] = ret;
return ret;
}
SCM_Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.data());
}
factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx)
{
SCM_Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.data(), tag.val64());
FE.getDiagnostics().reset(diagName);
boo::ObjToken<boo::IShaderPipeline> build;
addData(m_factory->buildShaderFromIR(tag, ir, FE.getDiagnostics(), ctx, build));
ret->m_pipelines.push_back(build);
return true;
} BooTrace);
m_pipelineLookup[tag] = ret;
return ret;
}
std::vector<boo::ObjToken<boo::IShaderPipeline>>
ShaderCacheManager::buildExtendedFromCache(const ShaderCachedData& foundData,
boo::IGraphicsDataFactory::Context& ctx)
{
std::vector<boo::ObjToken<boo::IShaderPipeline>> shaders;
shaders.reserve(m_extensions.m_extensionSlots.size());
if (!m_factory->buildExtendedShaderFromCache(foundData, m_extensions.m_extensionSlots, ctx,
[&](const boo::ObjToken<boo::IShaderPipeline>& shader){shaders.push_back(shader);}))
return {};
if (shaders.size() != m_extensions.m_extensionSlots.size())
SCM_Log.report(logvisor::Fatal, "buildShaderFromCache returned %" PRISize " times, expected %" PRISize,
shaders.size(), m_extensions.m_extensionSlots.size());
return shaders;
}
std::shared_ptr<ShaderPipelines>
ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, std::string_view source,
std::string_view diagName,
boo::IGraphicsDataFactory& factory)
{
auto search = m_pipelineLookup.find(tag);
if (search != m_pipelineLookup.cend())
return search->second;
std::shared_ptr<ShaderPipelines> ret = std::make_shared<ShaderPipelines>();
ShaderCachedData foundData = lookupData(tag);
if (foundData)
{
factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx)
{
SCM_Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.data(), tag.val64());
ret->m_pipelines = buildExtendedFromCache(foundData, ctx);
return ret->m_pipelines.size() != 0;
} BooTrace);
if (ret->m_pipelines.size())
{
m_pipelineLookup[tag] = ret;
return ret;
}
SCM_Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.data());
}
hecl::Frontend::IR ir = FE.compileSource(source, diagName);
factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx)
{
ret->m_pipelines.reserve(m_extensions.m_extensionSlots.size());
FE.getDiagnostics().reset(diagName);
SCM_Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.data(), tag.val64());
ShaderCachedData data =
m_factory->buildExtendedShaderFromIR(tag, ir, FE.getDiagnostics(), m_extensions.m_extensionSlots, ctx,
[&](const boo::ObjToken<boo::IShaderPipeline>& shader){ret->m_pipelines.push_back(shader);});
if (ret->m_pipelines.size() != m_extensions.m_extensionSlots.size())
SCM_Log.report(logvisor::Fatal, "buildShaderFromIR returned %" PRISize " times, expected %" PRISize,
ret->m_pipelines.size(), m_extensions.m_extensionSlots.size());
addData(data);
return true;
} BooTrace);
m_pipelineLookup[tag] = ret;
return ret;
}
std::shared_ptr<ShaderPipelines>
ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, const hecl::Frontend::IR& ir,
std::string_view diagName,
boo::IGraphicsDataFactory& factory)
{
auto search = m_pipelineLookup.find(tag);
if (search != m_pipelineLookup.cend())
return search->second;
std::shared_ptr<ShaderPipelines> ret = std::make_shared<ShaderPipelines>();
ShaderCachedData foundData = lookupData(tag);
if (foundData)
{
factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx)
{
SCM_Log.report(logvisor::Info, "building cached shader '%s' %016llX", diagName.data(), tag.val64());
ret->m_pipelines = buildExtendedFromCache(foundData, ctx);
return ret->m_pipelines.size() != 0;
} BooTrace);
if (ret->m_pipelines.size() != 0)
{
m_pipelineLookup[tag] = ret;
return ret;
}
SCM_Log.report(logvisor::Warning, "invalid cache read, rebuilding shader '%s'", diagName.data());
}
factory.commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx)
{
ret->m_pipelines.reserve(m_extensions.m_extensionSlots.size());
FE.getDiagnostics().reset(diagName);
SCM_Log.report(logvisor::Info, "building shader '%s' %016llX", diagName.data(), tag.val64());
ShaderCachedData data =
m_factory->buildExtendedShaderFromIR(tag, ir, FE.getDiagnostics(), m_extensions.m_extensionSlots, ctx,
[&](const boo::ObjToken<boo::IShaderPipeline>& shader){ret->m_pipelines.push_back(shader);});
if (ret->m_pipelines.size() != m_extensions.m_extensionSlots.size())
SCM_Log.report(logvisor::Fatal, "buildShaderFromIR returned %" PRISize " times, expected %" PRISize,
ret->m_pipelines.size(), m_extensions.m_extensionSlots.size());
addData(data);
return true;
} BooTrace);
m_pipelineLookup[tag] = ret;
return ret;
}
}

View File

@ -0,0 +1,43 @@
include_directories(../include
${CMAKE_CURRENT_SOURCE_DIR}/../extern/athena/include
${CMAKE_CURRENT_SOURCE_DIR}/../extern/boo
${CMAKE_CURRENT_SOURCE_DIR}/../extern/boo/include
${CMAKE_CURRENT_SOURCE_DIR}/../extern/boo/logvisor/include)
add_library(shaderc_lib shaderc.cpp shaderc.hpp)
add_executable(shaderc main.cpp)
target_link_libraries(shaderc shaderc_lib hecl-compilers glslang soxr xxhash OSDependent OGLCompiler
SPIRV glslang-default-resource-limits athena-core logvisor)
if (NOT WIN32)
target_link_libraries(shaderc pthread)
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
target_link_libraries(shaderc execinfo)
else()
target_link_libraries(shaderc dl)
endif()
endif()
if(COMMAND add_sanitizers)
add_sanitizers(shaderc_lib)
add_sanitizers(shaderc)
endif()
function(shaderc out)
if(IS_ABSOLUTE ${out})
set(theOut ${out})
else()
set(theOut ${CMAKE_CURRENT_BINARY_DIR}/${out})
endif()
unset(theInsList)
foreach(in ${ARGN})
if(IS_ABSOLUTE ${in})
list(APPEND theInsList ${in})
else()
list(APPEND theInsList ${CMAKE_CURRENT_SOURCE_DIR}/${in})
endif()
endforeach()
get_filename_component(outDir ${theOut} DIRECTORY)
file(MAKE_DIRECTORY ${outDir})
file(RELATIVE_PATH outRel ${CMAKE_BINARY_DIR} ${theOut})
add_custom_command(OUTPUT ${theOut}.cpp ${theOut}.hpp
COMMAND $<TARGET_FILE:shaderc> ARGS -o ${theOut} ${theInsList}
DEPENDS ${theInsList} shaderc COMMENT "Compiling shader ${outRel}.shader")
endfunction()

130
hecl/shaderc/main.cpp Normal file
View File

@ -0,0 +1,130 @@
#include "shaderc.hpp"
#include "logvisor/logvisor.hpp"
#include "athena/FileWriter.hpp"
#include "glslang/Public/ShaderLang.h"
#include "hecl/hecl.hpp"
static logvisor::Module Log("shaderc");
#if _WIN32
int wmain(int argc, const hecl::SystemChar** argv)
#else
int main(int argc, const hecl::SystemChar** argv)
#endif
{
logvisor::RegisterConsoleLogger();
logvisor::RegisterStandardExceptions();
if (argc == 1)
{
Log.report(logvisor::Info, "Usage: shaderc -o <out-base> [-D definevar=defineval]... <in-files>...");
return 0;
}
hecl::SystemString outPath;
hecl::shaderc::Compiler c;
for (int i = 1; i < argc; ++i)
{
if (argv[i][0] == '-')
{
if (argv[i][1] == 'o')
{
if (argv[i][2])
{
outPath = &argv[i][2];
}
else if (i + 1 < argc)
{
++i;
outPath = argv[i];
}
else
{
Log.report(logvisor::Error, "Invalid -o argument");
return 1;
}
}
else if (argv[i][1] == 'D')
{
const hecl::SystemChar* define;
if (argv[i][2])
{
define = &argv[i][2];
}
else if (i + 1 < argc)
{
++i;
define = argv[i];
}
else
{
Log.report(logvisor::Error, "Invalid -D argument");
return 1;
}
hecl::SystemUTF8Conv conv(define);
const char* defineU8 = conv.c_str();
if (char* equals = strchr(defineU8, '='))
c.addDefine(std::string(defineU8, equals - defineU8), equals + 1);
else
c.addDefine(defineU8, "");
}
else
{
Log.report(logvisor::Error, "Unrecognized flag option '%c'", argv[i][1]);
return 1;
}
}
else
{
c.addInputFile(argv[i]);
}
}
if (outPath.empty())
{
Log.report(logvisor::Error, "-o option is required");
return 1;
}
hecl::SystemStringView baseName;
auto slashPos = outPath.find_last_of("/\\");
if (slashPos != hecl::SystemString::npos)
baseName = outPath.data() + slashPos + 1;
else
baseName = outPath;
if (!glslang::InitializeProcess())
{
Log.report(logvisor::Error, "Unable to initialize glslang");
return 1;
}
hecl::SystemUTF8Conv conv(baseName);
std::pair<std::string, std::string> ret;
if (!c.compile(conv.str(), ret))
return 1;
{
hecl::SystemString headerPath = outPath + _S(".hpp");
athena::io::FileWriter w(headerPath);
if (w.hasError())
{
Log.report(logvisor::Error, _S("Error opening '%s' for writing"), headerPath.c_str());
return 1;
}
w.writeBytes(ret.first.data(), ret.first.size());
}
{
hecl::SystemString impPath = outPath + _S(".cpp");
athena::io::FileWriter w(impPath);
if (w.hasError())
{
Log.report(logvisor::Error, _S("Error opening '%s' for writing"), impPath.c_str());
return 1;
}
w.writeBytes(ret.second.data(), ret.second.size());
}
return 0;
}

948
hecl/shaderc/shaderc.cpp Normal file
View File

@ -0,0 +1,948 @@
#include "shaderc.hpp"
#include "athena/FileReader.hpp"
#include "logvisor/logvisor.hpp"
#include "hecl/hecl.hpp"
#include "hecl/PipelineBase.hpp"
#include <algorithm>
#include <regex>
#include <unordered_map>
#include <set>
using namespace std::literals;
namespace hecl::shaderc
{
static logvisor::Module Log("shaderc");
static constexpr std::regex::flag_type RegexFlags = std::regex::ECMAScript|std::regex::optimize;
#if __GNUC__
__attribute__((__format__ (__printf__, 1, 2)))
#endif
static std::string Format(const char* format, ...)
{
char resultBuf[FORMAT_BUF_SZ];
va_list va;
va_start(va, format);
int printSz = vsnprintf(resultBuf, FORMAT_BUF_SZ, format, va);
va_end(va);
return std::string(resultBuf, printSz);
}
const std::string* Compiler::getFileContents(SystemStringView path)
{
auto search = m_fileContents.find(path.data());
if (search == m_fileContents.end())
{
athena::io::FileReader r(path);
if (r.hasError())
return nullptr;
auto len = r.length();
auto data = r.readBytes(len);
search = m_fileContents.insert(std::make_pair(path.data(), std::string((char*)data.get(), len))).first;
}
return &search->second;
}
void Compiler::addInputFile(SystemStringView file)
{
if (std::find(m_inputFiles.begin(), m_inputFiles.end(), file) == m_inputFiles.end())
m_inputFiles.emplace_back(file);
}
void Compiler::addDefine(std::string_view var, std::string_view val)
{
m_defines[var.data()] = val;
}
static const char* ShaderHeaderTemplate =
"class Shader_%s : public hecl::GeneralShader\n"
"{\n"
"public:\n"
" static const boo::VertexFormatInfo VtxFmt;\n"
" static const boo::AdditionalPipelineInfo PipelineInfo;\n"
" static constexpr bool HasHash = true;\n"
" static constexpr uint64_t Hash() { return 0x%016llX; }\n"
"};\n\n";
static const char* StageObjectHeaderTemplate =
"template<typename P, typename S>\n"
"class StageObject_%s : public hecl::StageBinary<P, S>\n"
"{\n"
" static const hecl::StageBinary<P, S> Prototype;\n"
"public:\n"
" StageObject_%s(hecl::StageConverter<P, S>& conv, hecl::FactoryCtx& ctx, const Shader_%s& in)\n"
" : hecl::StageBinary<P, S>(Prototype) {}\n"
"};\n"
"STAGEOBJECT_PROTOTYPE_DECLARATIONS(StageObject_%s)\n\n";
static const char* StageObjectImplTemplate =
"template<>\n"
"const hecl::StageBinary<hecl::PlatformType::%s, hecl::PipelineStage::%s>\n"
"StageObject_%s<hecl::PlatformType::%s, hecl::PipelineStage::%s>::Prototype = \n"
"{%s_%s_%s_data, sizeof(%s_%s_%s_data)};\n\n";
struct CompileSubStageAction
{
template<typename P, typename S>
static bool Do(const std::string& name, const std::string& basename, const std::string& stage, std::string& implOut)
{
implOut += Format(StageObjectImplTemplate, P::Name, S::Name, name.c_str(), P::Name, S::Name,
basename.c_str(), P::Name, S::Name, basename.c_str(), P::Name, S::Name);
return true;
}
};
struct CompileStageAction
{
template<typename P, typename S>
static bool Do(const std::string& name, const std::string& basename, const std::string& stage, std::string& implOut)
{
std::pair<std::shared_ptr<uint8_t[]>, size_t> data = CompileShader<P, S>(stage);
if (data.second == 0)
return false;
implOut += Format("static const uint8_t %s_%s_%s_data[] = {\n", name.c_str(), P::Name, S::Name);
for (size_t i = 0; i < data.second; )
{
implOut += " ";
for (int j = 0; j < 10 && i < data.second ; ++i, ++j)
implOut += Format("0x%02X, ", data.first[i]);
implOut += "\n";
}
implOut += "};\n\n";
implOut += Format(StageObjectImplTemplate, P::Name, S::Name, name.c_str(), P::Name, S::Name,
name.c_str(), P::Name, S::Name, name.c_str(), P::Name, S::Name);
return true;
}
};
template<typename Action, typename P>
bool Compiler::StageAction(StageType type,
const std::string& name, const std::string& basename, const std::string& stage,
std::string& implOut)
{
switch (type)
{
case StageType::Vertex:
return Action::template Do<P, PipelineStage::Vertex>(name, basename, stage, implOut);
case StageType::Fragment:
return Action::template Do<P, PipelineStage::Fragment>(name, basename, stage, implOut);
case StageType::Geometry:
return Action::template Do<P, PipelineStage::Geometry>(name, basename, stage, implOut);
case StageType::Control:
return Action::template Do<P, PipelineStage::Control>(name, basename, stage, implOut);
case StageType::Evaluation:
return Action::template Do<P, PipelineStage::Evaluation>(name, basename, stage, implOut);
default:
break;
}
Log.report(logvisor::Error, "Unknown stage type");
return false;
}
static const std::regex regWord(R"((\w+))", RegexFlags);
template<typename Action>
bool Compiler::StageAction(const std::string& platforms, StageType type,
const std::string& name, const std::string& basename, const std::string& stage,
std::string& implOut)
{
std::smatch match;
auto begin = platforms.cbegin();
auto end = platforms.cend();
while (std::regex_search(begin, end, match, regWord))
{
std::string plat = match[1].str();
std::transform(plat.begin(), plat.end(), plat.begin(), ::tolower);
if (plat == "glsl")
{
if (!StageAction<Action, PlatformType::OpenGL>(type, name, basename, stage, implOut) ||
!StageAction<Action, PlatformType::Vulkan>(type, name, basename, stage, implOut)
#if HECL_NOUVEAU_NX
|| !StageAction<Action, PlatformType::NX>(type, name, basename, stage, implOut)
#endif
)
return false;
}
else if (plat == "opengl")
{
if (!StageAction<Action, PlatformType::OpenGL>(type, name, basename, stage, implOut))
return false;
}
else if (plat == "vulkan")
{
if (!StageAction<Action, PlatformType::Vulkan>(type, name, basename, stage, implOut))
return false;
}
else if (plat == "nx")
{
#if HECL_NOUVEAU_NX
if (!StageAction<Action, PlatformType::NX>(type, name, basename, stage, implOut))
return false;
#endif
}
else if (plat == "d3d11" || plat == "hlsl")
{
#if _WIN32
if (!StageAction<Action, PlatformType::D3D11>(type, name, basename, stage, implOut))
return false;
#endif
}
else if (plat == "metal")
{
#if __APPLE__
if (!StageAction<Action, PlatformType::Metal>(type, name, basename, stage, implOut))
return false;
#endif
}
else
{
Log.report(logvisor::Error, "Unknown platform '%s'", plat.c_str());
return false;
}
begin = match.suffix().first;
}
return true;
}
static const std::regex regInclude(R"(#\s*include\s+\"(.*)\")", RegexFlags);
static const std::regex regDefine(R"(#\s*define\s+(\w+)\s*(.*))", RegexFlags);
static const std::regex regShaderEx(R"(#\s*shader\s+(\w+)\s*:\s*(\w+))", RegexFlags);
static const std::regex regShader(R"(#\s*shader\s+(\w+))", RegexFlags);
static const std::regex regAttributeEx(R"(#\s*attribute\s+(\w+)\s+([0-9]+))", RegexFlags);
static const std::regex regAttribute(R"(#\s*attribute\s+(\w+))", RegexFlags);
static const std::regex regInstAttributeEx(R"(#\s*instattribute\s+(\w+)\s+([0-9]+))", RegexFlags);
static const std::regex regInstAttribute(R"(#\s*instattribute\s+(\w+))", RegexFlags);
static const std::regex regSrcFac(R"(#\s*srcfac\s+(\w+))", RegexFlags);
static const std::regex regDstFac(R"(#\s*dstfac\s+(\w+))", RegexFlags);
static const std::regex regPrim(R"(#\s*primitive\s+(\w+))", RegexFlags);
static const std::regex regZTest(R"(#\s*depthtest\s+(\w+))", RegexFlags);
static const std::regex regDepthWrite(R"(#\s*depthwrite\s+(\w+))", RegexFlags);
static const std::regex regColorWrite(R"(#\s*colorwrite\s+(\w+))", RegexFlags);
static const std::regex regAlphaWrite(R"(#\s*alphawrite\s+(\w+))", RegexFlags);
static const std::regex regCulling(R"(#\s*culling\s+(\w+))", RegexFlags);
static const std::regex regPatchSize(R"(#\s*patchsize\s+(\w+))", RegexFlags);
static const std::regex regOverwriteAlpha(R"(#\s*overwritealpha\s+(\w+))", RegexFlags);
static const std::regex regDepthAttachment(R"(#\s*depthattachment\s+(\w+))", RegexFlags);
static const std::regex regVertex(R"(#\s*vertex\s+(.*))", RegexFlags);
static const std::regex regFragment(R"(#\s*fragment\s+(.*))", RegexFlags);
static const std::regex regGeometry(R"(#\s*geometry\s+(.*))", RegexFlags);
static const std::regex regControl(R"(#\s*control\s+(.*))", RegexFlags);
static const std::regex regEvaluation(R"(#\s*evaluation\s+(.*))", RegexFlags);
bool Compiler::includeFile(SystemStringView file, std::string& out, int depth)
{
if (depth > 32)
{
Log.report(logvisor::Error, _S("Too many levels of includes (>32) at '%s'"), file.data());
return false;
}
const std::string* data = getFileContents(file);
if (!data)
{
Log.report(logvisor::Error, _S("Unable to access '%s'"), file.data());
return false;
}
const std::string& sdata = *data;
SystemString directory;
auto slashPos = file.find_last_of("/\\");
if (slashPos != SystemString::npos)
directory = SystemString(file.begin(), file.begin() + slashPos);
else
directory = _S(".");
auto begin = sdata.cbegin();
auto end = sdata.cend();
while (begin != end)
{
std::string::const_iterator nextBegin;
auto findPos = sdata.find('\n', begin - sdata.begin());
if (findPos == std::string::npos)
nextBegin = end;
else
nextBegin = sdata.begin() + findPos + 1;
std::smatch subMatch;
if (std::regex_search(begin, nextBegin, subMatch, regInclude))
{
std::string path = subMatch[1].str();
if (path.empty())
{
Log.report(logvisor::Error, _S("Empty path provided to include in '%s'"), file.data());
return false;
}
hecl::SystemString pathStr(hecl::SystemStringConv(path).sys_str());
if (!hecl::IsAbsolute(pathStr))
pathStr = directory + _S('/') + pathStr;
if (!includeFile(pathStr, out, depth + 1))
return false;
}
else
{
out.insert(out.end(), begin, nextBegin);
}
begin = nextBegin;
}
return true;
}
static std::string_view BlendFactorToStr(boo::BlendFactor fac)
{
switch (fac)
{
case boo::BlendFactor::Zero:
default:
return "boo::BlendFactor::Zero"sv;
case boo::BlendFactor::One:
return "boo::BlendFactor::One"sv;
case boo::BlendFactor::SrcColor:
return "boo::BlendFactor::SrcColor"sv;
case boo::BlendFactor::InvSrcColor:
return "boo::BlendFactor::InvSrcColor"sv;
case boo::BlendFactor::DstColor:
return "boo::BlendFactor::DstColor"sv;
case boo::BlendFactor::InvDstColor:
return "boo::BlendFactor::InvDstColor"sv;
case boo::BlendFactor::SrcAlpha:
return "boo::BlendFactor::SrcAlpha"sv;
case boo::BlendFactor::InvSrcAlpha:
return "boo::BlendFactor::InvSrcAlpha"sv;
case boo::BlendFactor::DstAlpha:
return "boo::BlendFactor::DstAlpha"sv;
case boo::BlendFactor::InvDstAlpha:
return "boo::BlendFactor::InvDstAlpha"sv;
case boo::BlendFactor::SrcColor1:
return "boo::BlendFactor::SrcColor1"sv;
case boo::BlendFactor::InvSrcColor1:
return "boo::BlendFactor::InvSrcColor1"sv;
case boo::BlendFactor::Subtract:
return "boo::BlendFactor::Subtract"sv;
}
}
static bool StrToBlendFactor(std::string str, boo::BlendFactor& fac)
{
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
if (str == "zero")
fac = boo::BlendFactor::Zero;
else if (str == "one")
fac = boo::BlendFactor::One;
else if (str == "srccolor")
fac = boo::BlendFactor::SrcColor;
else if (str == "invsrccolor")
fac = boo::BlendFactor::InvSrcColor;
else if (str == "dstcolor")
fac = boo::BlendFactor::DstColor;
else if (str == "invdstcolor")
fac = boo::BlendFactor::InvDstColor;
else if (str == "srcalpha")
fac = boo::BlendFactor::SrcAlpha;
else if (str == "invsrcalpha")
fac = boo::BlendFactor::InvSrcAlpha;
else if (str == "dstalpha")
fac = boo::BlendFactor::DstAlpha;
else if (str == "invdstalpha")
fac = boo::BlendFactor::InvDstAlpha;
else if (str == "srccolor1")
fac = boo::BlendFactor::SrcColor1;
else if (str == "invsrccolor1")
fac = boo::BlendFactor::InvSrcColor1;
else if (str == "subtract")
fac = boo::BlendFactor::Subtract;
else
{
Log.report(logvisor::Error, "Unrecognized blend mode '%s'", str.c_str());
return false;
}
return true;
}
static std::string_view PrimitiveToStr(boo::Primitive prim)
{
switch (prim)
{
case boo::Primitive::Triangles:
default:
return "boo::Primitive::Triangles"sv;
case boo::Primitive::TriStrips:
return "boo::Primitive::TriStrips"sv;
case boo::Primitive::Patches:
return "boo::Primitive::Patches"sv;
}
}
static bool StrToPrimitive(std::string str, boo::Primitive& prim)
{
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
if (str == "triangles")
prim = boo::Primitive::Triangles;
else if (str == "tristrips")
prim = boo::Primitive::TriStrips;
else if (str == "patches")
prim = boo::Primitive::Patches;
else
{
Log.report(logvisor::Error, "Unrecognized primitive '%s'", str.c_str());
return false;
}
return true;
}
static std::string_view ZTestToStr(boo::ZTest ztest)
{
switch (ztest)
{
case boo::ZTest::None:
default:
return "boo::ZTest::None"sv;
case boo::ZTest::LEqual:
return "boo::ZTest::LEqual"sv;
case boo::ZTest::Greater:
return "boo::ZTest::Greater"sv;
case boo::ZTest::GEqual:
return "boo::ZTest::GEqual"sv;
case boo::ZTest::Equal:
return "boo::ZTest::Equal"sv;
}
}
static bool StrToZTest(std::string str, boo::ZTest& ztest)
{
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
if (str == "none")
ztest = boo::ZTest::None;
else if (str == "lequal")
ztest = boo::ZTest::LEqual;
else if (str == "greater")
ztest = boo::ZTest::Greater;
else if (str == "gequal")
ztest = boo::ZTest::GEqual;
else if (str == "equal")
ztest = boo::ZTest::Equal;
else
{
Log.report(logvisor::Error, "Unrecognized ztest '%s'", str.c_str());
return false;
}
return true;
}
static std::string_view CullModeToStr(boo::CullMode cull)
{
switch (cull)
{
case boo::CullMode::None:
default:
return "boo::CullMode::None"sv;
case boo::CullMode::Backface:
return "boo::CullMode::Backface"sv;
case boo::CullMode::Frontface:
return "boo::CullMode::Frontface"sv;
}
}
static bool StrToCullMode(std::string str, boo::CullMode& cull)
{
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
if (str == "none")
cull = boo::CullMode::None;
else if (str == "backface")
cull = boo::CullMode::Backface;
else if (str == "frontface")
cull = boo::CullMode::Frontface;
else
{
Log.report(logvisor::Error, "Unrecognized cull mode '%s'", str.c_str());
return false;
}
return true;
}
static std::string_view BoolToStr(bool b)
{
return b ? "true"sv : "false"sv;
}
static bool StrToBool(std::string str, bool& b)
{
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
if (strtol(str.c_str(), nullptr, 0))
b = true;
else if (str == "true")
b = true;
else if (str == "false")
b = false;
else
{
Log.report(logvisor::Error, "Unrecognized bool '%s'", str.c_str());
return false;
}
return true;
}
bool Compiler::compileFile(SystemStringView file, std::string_view baseName, std::pair<std::string, std::string>& out)
{
std::string includesPass;
if (!includeFile(file, includesPass))
return false;
std::string shaderName(baseName);
std::string shaderBase;
std::vector<std::pair<boo::VertexSemantic, int>> shaderAttributes;
bool shaderAttributesReset = false;
boo::AdditionalPipelineInfo shaderInfo = {};
std::string stagePlatforms;
StageType stageType;
auto stageBegin = includesPass.cend();
auto stageEnd = includesPass.cend();
std::unordered_map<std::string, std::pair<std::bitset<6>, std::set<std::string>>> shaderStageUses;
std::unordered_map<std::string, std::string> shaderBases;
auto _DoCompile = [&]()
{
if (stageBegin == includesPass.end())
return true;
if (shaderName.empty())
{
Log.report(logvisor::Error, "`#shader <name>` must be issued before stages");
return false;
}
std::string stage(stageBegin, stageEnd);
for (const auto& define : m_defines)
{
std::string::size_type pos = 0;
while ((pos = stage.find(define.first, pos)) != std::string::npos)
{
stage = std::string(stage.begin(), stage.begin() + pos) + define.second +
std::string(stage.begin() + pos + define.first.size(), stage.end());
}
}
stageBegin = includesPass.end();
std::pair<std::bitset<6>, std::set<std::string>>& uses = shaderStageUses[shaderName];
uses.first.set(size_t(stageType));
uses.second.insert(stagePlatforms);
return StageAction<CompileStageAction>(stagePlatforms, stageType, shaderName,
shaderBase, stage, out.second);
};
auto DoCompile = [&](std::string platform, StageType type,
std::string::const_iterator end, std::string::const_iterator begin)
{
stageEnd = end;
bool ret = _DoCompile();
stagePlatforms = std::move(platform);
stageType = type;
stageBegin = begin;
return ret;
};
auto DoShader = [&]()
{
if (shaderBase.empty() && shaderStageUses.find(shaderName) == shaderStageUses.cend())
return true;
std::pair<std::bitset<6>, std::set<std::string>>& uses = shaderStageUses[shaderName];
if (uses.first.test(5))
return true;
out.first += Format(ShaderHeaderTemplate, shaderName.c_str(),
XXH64(shaderName.c_str(), shaderName.size(), 0));
out.first += Format(StageObjectHeaderTemplate, shaderName.c_str(), shaderName.c_str(),
shaderName.c_str(), shaderName.c_str());
if (!shaderBase.empty())
{
shaderBases[shaderName] = shaderBase;
for (int i = 0; i < 5; ++i)
{
if (uses.first.test(size_t(i)))
continue;
std::string useBase = shaderBase;
std::unordered_map<std::string, std::pair<std::bitset<6>, std::set<std::string>>>::const_iterator
baseUses = shaderStageUses.find(useBase);
while (baseUses == shaderStageUses.cend() || !baseUses->second.first.test(size_t(i)))
{
auto search = shaderBases.find(useBase);
if (search == shaderBases.cend())
break;
useBase = search->second;
baseUses = shaderStageUses.find(useBase);
}
if (baseUses == shaderStageUses.cend() || !baseUses->second.first.test(size_t(i)))
continue;
for (const std::string& basePlatforms : baseUses->second.second)
{
StageAction<CompileSubStageAction>(basePlatforms, StageType(i), shaderName,
useBase, {}, out.second);
}
}
shaderBase.clear();
}
out.second += Format("static const boo::VertexElementDescriptor %s_vtxfmtelems[] = {\n", shaderName.c_str());
for (const auto& attr : shaderAttributes)
{
const char* fmt;
switch (attr.first & boo::VertexSemantic::SemanticMask)
{
case boo::VertexSemantic::Position3:
fmt = "{boo::VertexSemantic::Position3%s, %d},\n";
break;
case boo::VertexSemantic::Position4:
fmt = "{boo::VertexSemantic::Position4%s, %d},\n";
break;
case boo::VertexSemantic::Normal3:
fmt = "{boo::VertexSemantic::Normal3%s, %d},\n";
break;
case boo::VertexSemantic::Normal4:
fmt = "{boo::VertexSemantic::Normal4%s, %d},\n";
break;
case boo::VertexSemantic::Color:
fmt = "{boo::VertexSemantic::Color%s, %d},\n";
break;
case boo::VertexSemantic::ColorUNorm:
fmt = "{boo::VertexSemantic::ColorUNorm%s, %d},\n";
break;
case boo::VertexSemantic::UV2:
fmt = "{boo::VertexSemantic::UV2%s, %d},\n";
break;
case boo::VertexSemantic::UV4:
fmt = "{boo::VertexSemantic::UV4%s, %d},\n";
break;
case boo::VertexSemantic::Weight:
fmt = "{boo::VertexSemantic::Weight%s, %d},\n";
break;
case boo::VertexSemantic::ModelView:
fmt = "{boo::VertexSemantic::ModelView%s, %d},\n";
break;
default:
fmt = "{boo::VertexSemantic::None%s, %d},\n";
break;
}
out.second += Format(fmt,
(attr.first & boo::VertexSemantic::Instanced) != boo::VertexSemantic::None ?
" | boo::VertexSemantic::Instanced" : "", attr.second);
}
out.second += "};\n";
out.second += Format("const boo::VertexFormatInfo Shader_%s::VtxFmt = { %s_vtxfmtelems };\n\n",
shaderName.c_str(), shaderName.c_str());
out.second += Format("const boo::AdditionalPipelineInfo Shader_%s::PipelineInfo = {\n", shaderName.c_str());
out.second += BlendFactorToStr(shaderInfo.srcFac); out.second += ", ";
out.second += BlendFactorToStr(shaderInfo.dstFac); out.second += ", ";
out.second += PrimitiveToStr(shaderInfo.prim); out.second += ", ";
out.second += ZTestToStr(shaderInfo.depthTest); out.second += ",\n";
out.second += BoolToStr(shaderInfo.depthWrite); out.second += ", ";
out.second += BoolToStr(shaderInfo.colorWrite); out.second += ", ";
out.second += BoolToStr(shaderInfo.alphaWrite); out.second += ", ";
out.second += CullModeToStr(shaderInfo.culling); out.second += ", ";
out.second += Format("%d, ", shaderInfo.patchSize);
out.second += BoolToStr(shaderInfo.overwriteAlpha); out.second += ", ";
out.second += BoolToStr(shaderInfo.depthAttachment); out.second += ", ";
out.second += "};\n\n";
uses.first.set(5);
return true;
};
auto AddAttribute = [&](std::string semantic, std::string idx, bool inst)
{
if (shaderAttributesReset)
{
shaderAttributes.clear();
shaderAttributesReset = false;
}
boo::VertexSemantic orsem = inst ? boo::VertexSemantic::Instanced : boo::VertexSemantic::None;
int idxNum = int(strtoul(idx.c_str(), nullptr, 10));
std::transform(semantic.begin(), semantic.end(), semantic.begin(), ::tolower);
if (semantic == "position3")
shaderAttributes.push_back(std::make_pair(boo::VertexSemantic::Position3 | orsem, idxNum));
else if (semantic == "position4")
shaderAttributes.push_back(std::make_pair(boo::VertexSemantic::Position4 | orsem, idxNum));
else if (semantic == "normal3")
shaderAttributes.push_back(std::make_pair(boo::VertexSemantic::Normal3 | orsem, idxNum));
else if (semantic == "normal4")
shaderAttributes.push_back(std::make_pair(boo::VertexSemantic::Normal4 | orsem, idxNum));
else if (semantic == "color")
shaderAttributes.push_back(std::make_pair(boo::VertexSemantic::Color | orsem, idxNum));
else if (semantic == "colorunorm")
shaderAttributes.push_back(std::make_pair(boo::VertexSemantic::ColorUNorm | orsem, idxNum));
else if (semantic == "uv2")
shaderAttributes.push_back(std::make_pair(boo::VertexSemantic::UV2 | orsem, idxNum));
else if (semantic == "uv4")
shaderAttributes.push_back(std::make_pair(boo::VertexSemantic::UV4 | orsem, idxNum));
else if (semantic == "weight")
shaderAttributes.push_back(std::make_pair(boo::VertexSemantic::Weight | orsem, idxNum));
else if (semantic == "modelview")
shaderAttributes.push_back(std::make_pair(boo::VertexSemantic::ModelView | orsem, idxNum));
else
{
Log.report(logvisor::Error, "Unrecognized vertex semantic '%s'", semantic.c_str());
return false;
}
return true;
};
auto begin = includesPass.cbegin();
auto end = includesPass.cend();
std::string* defineContinue = nullptr;
while (begin != end)
{
std::string::const_iterator nextBegin;
auto findPos = includesPass.find('\n', begin - includesPass.cbegin());
if (findPos == std::string::npos)
nextBegin = end;
else
nextBegin = includesPass.cbegin() + findPos + 1;
std::smatch subMatch;
if (defineContinue)
{
std::string extraLine;
if (findPos == std::string::npos)
extraLine = std::string(begin, end);
else
extraLine = std::string(begin, includesPass.cbegin() + findPos);
*defineContinue += extraLine;
if (!defineContinue->empty() && defineContinue->back() == '\\')
defineContinue->pop_back();
else
defineContinue = nullptr;
}
else if (std::regex_search(begin, nextBegin, subMatch, regDefine))
{
std::string& defOut = m_defines[subMatch[1].str()];
defOut = subMatch[2].str();
if (!defOut.empty() && defOut.back() == '\\')
{
defOut.pop_back();
defineContinue = &defOut;
}
}
else if (std::regex_search(begin, nextBegin, subMatch, regShaderEx))
{
stageEnd = begin;
if (!_DoCompile() || !DoShader())
return false;
shaderName = subMatch[1].str();
shaderBase = subMatch[2].str();
shaderAttributesReset = true;
//shaderAttributes.clear();
//shaderInfo = boo::AdditionalPipelineInfo();
}
else if (std::regex_search(begin, nextBegin, subMatch, regShader))
{
stageEnd = begin;
if (!_DoCompile() || !DoShader())
return false;
shaderName = subMatch[1].str();
shaderAttributesReset = true;
//shaderAttributes.clear();
//shaderInfo = boo::AdditionalPipelineInfo();
}
else if (std::regex_search(begin, nextBegin, subMatch, regAttributeEx))
{
if (!AddAttribute(subMatch[1].str(), subMatch[2].str(), false))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regAttribute))
{
if (!AddAttribute(subMatch[1].str(), "0", false))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regInstAttributeEx))
{
if (!AddAttribute(subMatch[1].str(), subMatch[2].str(), true))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regInstAttribute))
{
if (!AddAttribute(subMatch[1].str(), "0", true))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regSrcFac))
{
if (!StrToBlendFactor(subMatch[1].str(), shaderInfo.srcFac))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regDstFac))
{
if (!StrToBlendFactor(subMatch[1].str(), shaderInfo.dstFac))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regPrim))
{
if (!StrToPrimitive(subMatch[1].str(), shaderInfo.prim))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regZTest))
{
if (!StrToZTest(subMatch[1].str(), shaderInfo.depthTest))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regDepthWrite))
{
if (!StrToBool(subMatch[1].str(), shaderInfo.depthWrite))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regColorWrite))
{
if (!StrToBool(subMatch[1].str(), shaderInfo.colorWrite))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regAlphaWrite))
{
if (!StrToBool(subMatch[1].str(), shaderInfo.alphaWrite))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regCulling))
{
if (!StrToCullMode(subMatch[1].str(), shaderInfo.culling))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regPatchSize))
{
auto str = subMatch[1].str();
char* endptr;
shaderInfo.patchSize = uint32_t(strtoul(str.c_str(), &endptr, 0));
if (endptr == str.c_str())
{
Log.report(logvisor::Error, "Non-unsigned-integer value for #patchsize directive");
return false;
}
}
else if (std::regex_search(begin, nextBegin, subMatch, regOverwriteAlpha))
{
if (!StrToBool(subMatch[1].str(), shaderInfo.overwriteAlpha))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regDepthAttachment))
{
if (!StrToBool(subMatch[1].str(), shaderInfo.depthAttachment))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regVertex))
{
if (!DoCompile(subMatch[1].str(), StageType::Vertex, begin, nextBegin))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regFragment))
{
if (!DoCompile(subMatch[1].str(), StageType::Fragment, begin, nextBegin))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regGeometry))
{
if (!DoCompile(subMatch[1].str(), StageType::Geometry, begin, nextBegin))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regControl))
{
if (!DoCompile(subMatch[1].str(), StageType::Control, begin, nextBegin))
return false;
}
else if (std::regex_search(begin, nextBegin, subMatch, regEvaluation))
{
if (!DoCompile(subMatch[1].str(), StageType::Evaluation, begin, nextBegin))
return false;
}
begin = nextBegin;
}
stageEnd = begin;
if (!_DoCompile() || !DoShader())
return false;
out.first += "#define UNIVERSAL_PIPELINES_";
out.first += baseName;
for (const auto& shader : shaderStageUses)
{
out.first += " \\\n";
out.first += "::Shader_";
out.first += shader.first;
}
out.first += "\n";
out.first += "#define OPENGL_STAGES_";
out.first += baseName;
for (const auto& shader : shaderStageUses)
{
out.first += " \\\n";
out.first += "STAGE_SPECIALIZATIONS(::StageObject_";
out.first += shader.first;
out.first += ", hecl::PlatformType::OpenGL)";
}
out.first += "\n";
out.first += "#define VULKAN_STAGES_";
out.first += baseName;
for (const auto& shader : shaderStageUses)
{
out.first += " \\\n";
out.first += "STAGE_SPECIALIZATIONS(::StageObject_";
out.first += shader.first;
out.first += ", hecl::PlatformType::Vulkan)";
}
out.first += "\n";
out.first += "#define D3D11_STAGES_";
out.first += baseName;
for (const auto& shader : shaderStageUses)
{
out.first += " \\\n";
out.first += "STAGE_SPECIALIZATIONS(::StageObject_";
out.first += shader.first;
out.first += ", hecl::PlatformType::D3D11)";
}
out.first += "\n";
out.first += "#define METAL_STAGES_";
out.first += baseName;
for (const auto& shader : shaderStageUses)
{
out.first += " \\\n";
out.first += "STAGE_SPECIALIZATIONS(::StageObject_";
out.first += shader.first;
out.first += ", hecl::PlatformType::Metal)";
}
out.first += "\n";
out.first += "#define NX_STAGES_";
out.first += baseName;
for (const auto& shader : shaderStageUses)
{
out.first += " \\\n";
out.first += "STAGE_SPECIALIZATIONS(::StageObject_";
out.first += shader.first;
out.first += ", hecl::PlatformType::NX)";
}
out.first += "\n";
return true;
}
bool Compiler::compile(std::string_view baseName, std::pair<std::string, std::string>& out)
{
out =
{
"#pragma once\n"
"#include \"hecl/PipelineBase.hpp\"\n\n",
Format("#include \"%s.hpp\"\n\n", baseName.data())
};
for (const auto& file : m_inputFiles)
if (!compileFile(file, baseName, out))
return false;
return true;
}
}

41
hecl/shaderc/shaderc.hpp Normal file
View File

@ -0,0 +1,41 @@
#pragma once
#include "hecl/SystemChar.hpp"
#include <string>
#include <vector>
#include <unordered_map>
namespace hecl::shaderc
{
class Compiler
{
enum class StageType
{
Vertex,
Fragment,
Geometry,
Control,
Evaluation
};
std::vector<SystemString> m_inputFiles;
std::unordered_map<SystemString, std::string> m_fileContents;
const std::string* getFileContents(SystemStringView path);
std::unordered_map<std::string, std::string> m_defines;
template<typename Action, typename P>
static bool StageAction(StageType type,
const std::string& name, const std::string& basename, const std::string& stage,
std::string& implOut);
template<typename Action>
static bool StageAction(const std::string& platforms, StageType type,
const std::string& name, const std::string& basename, const std::string& stage,
std::string& implOut);
bool includeFile(SystemStringView file, std::string& out, int depth = 0);
bool compileFile(SystemStringView file, std::string_view baseName, std::pair<std::string, std::string>& out);
public:
void addInputFile(SystemStringView file);
void addDefine(std::string_view var, std::string_view val);
bool compile(std::string_view baseName, std::pair<std::string, std::string>& out);
};
}

View File

@ -1,8 +1,9 @@
add_executable(heclTest WIN32 main.cpp)
target_link_libraries(heclTest
${HECL_APPLICATION_REPS_TARGETS_LIST}
hecl-full hecl-blender-addon
athena-core athena-libyaml xxhash logvisor boo
${ZLIB_LIBRARIES} ${LZO_LIB} ${BOO_SYS_LIBS})
if(COMMAND add_sanitizers)
add_sanitizers(heclTest)
endif()
endif()

View File

@ -2,9 +2,11 @@
#include "logvisor/logvisor.hpp"
#include "hecl/Console.hpp"
#include "hecl/CVarManager.hpp"
#include <athena/MemoryWriter.hpp>
#include "athena/MemoryWriter.hpp"
#include "hecl/Runtime.hpp"
#include "hecl/Backend/Backend.hpp"
#include "hecl/HMDLMeta.hpp"
#include "hecl/Pipeline.hpp"
#include <cmath>
#include <thread>
#include <mutex>
@ -62,7 +64,8 @@ struct HECLApplicationCallback : boo::IApplicationCallback
m_cvarManager(m_fileStoreMgr),
m_console(&m_cvarManager)
{
m_console.registerCommand("quit"sv, "Quits application"sv, "", std::bind(&HECLApplicationCallback::quit, this, std::placeholders::_1, std::placeholders::_2));
m_console.registerCommand("quit"sv, "Quits application"sv, "",
std::bind(&HECLApplicationCallback::quit, this, std::placeholders::_1, std::placeholders::_2));
}
virtual ~HECLApplicationCallback();
@ -77,7 +80,8 @@ struct HECLApplicationCallback : boo::IApplicationCallback
boo::ObjToken<boo::ITextureR> renderTex;
boo::ObjToken<boo::IGraphicsBuffer> vubo;
boo::ObjToken<boo::IShaderDataBinding> binding;
boo::ObjToken<boo::IShaderPipeline> pipeline, pipeline2;
boo::ObjToken<boo::IShaderDataBinding> binding, binding2;
struct VertexUBO
{
@ -108,104 +112,88 @@ struct HECLApplicationCallback : boo::IApplicationCallback
for (int j=0 ; j<256 ; ++j)
{
tex[i][j][0] = uint8_t(i);
tex[i][j][1] = uint8_t(i);
tex[i][j][1] = uint8_t(j);
tex[i][j][2] = 0;
tex[i][j][3] = 0xff;
}
std::mutex initmt;
std::condition_variable initcv;
std::mutex loadmt;
std::condition_variable loadcv;
std::unique_lock<std::mutex> outerLk(initmt);
std::thread loaderThr([&]()
boo::IGraphicsDataFactory* gfxF = m_mainWindow->getMainContextDataFactory();
if (gfxF->platform() == boo::IGraphicsDataFactory::Platform::Vulkan)
vuboData.modelview[1][1] = -1.f;
/* Pipeline converter */
std::unique_ptr<hecl::PipelineConverterBase> conv = hecl::NewPipelineConverter(gfxF);
/* Compile HECL shader */
static std::string testShader = "HECLOpaque(Texture(0, UV(0)))";
//static std::string testShader = "HECLOpaque(vec3(1.0,1.0,1.0),1.0)";
hecl::Backend::ShaderTag testShaderTag(testShader, 0, 1, 0, 0, boo::Primitive::TriStrips,
hecl::Backend::ReflectionType::None, false, false, false);
hecl::Frontend::Frontend FE;
hecl::HECLIR irObj(FE.compileSource(testShader, "booTest"), testShaderTag, 0);
gfxF->commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx)
{
std::unique_lock<std::mutex> innerLk(initmt);
boo::IGraphicsDataFactory* gfxF = m_mainWindow->getLoadContextDataFactory();
pipeline = conv->convert(ctx, irObj);
pipeline2 = conv->convert(ctx, Shader_test{});
/* HECL managers */
hecl::Runtime::FileStoreManager fileMgr(app->getUniqueName());
hecl::Runtime::ShaderCacheManager shaderMgr(fileMgr, gfxF);
boo::SWindowRect mainWindowRect = m_mainWindow->getWindowFrame();
renderTex = ctx.newRenderTexture(size_t(mainWindowRect.size[0]), size_t(mainWindowRect.size[1]),
boo::TextureClampMode::Repeat, 1, 0);
/* Compile HECL shader */
static std::string testShader = "HECLOpaque(Texture(0, UV(0)))";
//static std::string testShader = "HECLOpaque(vec3(1.0,1.0,1.0),1.0)";
hecl::Runtime::ShaderTag testShaderTag(testShader, 0, 1, 0, 0, boo::Primitive::TriStrips,
hecl::Backend::ReflectionType::None, false, false, false);
std::shared_ptr<hecl::Runtime::ShaderPipelines> testShaderObj =
shaderMgr.buildShader(testShaderTag, testShader, "testShader", *gfxF);
/* Generate meta structure (usually statically serialized) */
hecl::HMDLMeta testMeta;
testMeta.topology = hecl::HMDLTopology::TriStrips;
testMeta.vertStride = 32;
testMeta.vertCount = 4;
testMeta.indexCount = 4;
testMeta.colorCount = 0;
testMeta.uvCount = 1;
testMeta.weightCount = 0;
testMeta.bankCount = 0;
gfxF->commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx)
/* Binary form of meta structure */
atUint8 testMetaBuf[HECL_HMDL_META_SZ];
athena::io::MemoryWriter testMetaWriter(testMetaBuf, HECL_HMDL_META_SZ);
testMeta.write(testMetaWriter);
/* Make Tri-strip VBO */
struct Vert
{
boo::SWindowRect mainWindowRect = m_mainWindow->getWindowFrame();
renderTex = ctx.newRenderTexture(size_t(mainWindowRect.size[0]), size_t(mainWindowRect.size[1]),
boo::TextureClampMode::Repeat, 0, 0);
/* Generate meta structure (usually statically serialized) */
hecl::HMDLMeta testMeta;
testMeta.topology = hecl::HMDLTopology::TriStrips;
testMeta.vertStride = 32;
testMeta.vertCount = 4;
testMeta.indexCount = 4;
testMeta.colorCount = 0;
testMeta.uvCount = 1;
testMeta.weightCount = 0;
testMeta.bankCount = 0;
/* Binary form of meta structure */
atUint8 testMetaBuf[HECL_HMDL_META_SZ];
athena::io::MemoryWriter testMetaWriter(testMetaBuf, HECL_HMDL_META_SZ);
testMeta.write(testMetaWriter);
/* Make Tri-strip VBO */
struct Vert
{
float pos[3];
float norm[3];
float uv[2];
};
static const Vert quad[4] =
{
{{0.5,0.5},{},{1.0,1.0}},
{{-0.5,0.5},{},{0.0,1.0}},
{{0.5,-0.5},{},{1.0,0.0}},
{{-0.5,-0.5},{},{0.0,0.0}}
};
/* Now simple IBO */
static const uint32_t ibo[4] = {0,1,2,3};
/* Construct quad mesh against boo factory */
hecl::Runtime::HMDLData testData(ctx, testMetaBuf, quad, ibo);
boo::ObjToken<boo::ITexture> texture =
ctx.newStaticTexture(256, 256, 1, boo::TextureFormat::RGBA8, boo::TextureClampMode::Repeat, tex, 256*256*4).get();
/* Make vertex uniform buffer */
vubo = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(VertexUBO), 1).get();
/* Assemble data binding */
binding = testData.newShaderDataBindng(ctx, testShaderObj->m_pipelines[0], 1, &vubo, nullptr, 1, &texture);
return true;
} BooTrace);
/* Return control to main thread */
innerLk.unlock();
initcv.notify_one();
/* Wait for exit */
std::unique_lock<std::mutex> lk(loadmt);
while (m_running)
float pos[3];
float norm[3];
float uv[2];
};
static const Vert quad[4] =
{
loadcv.wait(lk);
}
});
initcv.wait(outerLk);
{{0.5,0.5},{},{1.0,1.0}},
{{-0.5,0.5},{},{0.0,1.0}},
{{0.5,-0.5},{},{1.0,0.0}},
{{-0.5,-0.5},{},{0.0,0.0}}
};
/* Now simple IBO */
static const uint32_t ibo[4] = {0,1,2,3};
/* Construct quad mesh against boo factory */
hecl::Runtime::HMDLData testData(ctx, testMetaBuf, quad, ibo);
boo::ObjToken<boo::ITexture> texture =
ctx.newStaticTexture(256, 256, 1, boo::TextureFormat::RGBA8, boo::TextureClampMode::Repeat, tex, 256*256*4).get();
/* Make vertex uniform buffer */
vubo = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(VertexUBO), 1).get();
/* Assemble data binding */
binding = testData.newShaderDataBindng(ctx, pipeline, 1, &vubo, nullptr, 1, &texture);
binding2 = testData.newShaderDataBindng(ctx, pipeline2, 1, &vubo, nullptr, 1, &texture);
return true;
} BooTrace);
m_mainWindow->showWindow();
m_windowCb.m_latestSize = m_mainWindow->getWindowFrame();
boo::IGraphicsCommandQueue* gfxQ = m_mainWindow->getCommandQueue();
m_mainWindow->getMainContextDataFactory();
size_t frameIdx = 0;
while (m_running)
@ -242,7 +230,7 @@ struct HECLApplicationCallback : boo::IApplicationCallback
vuboData.modelview[3][1] = cosf(frameIdx / 60.0f) * 0.5f;
vubo.cast<boo::IGraphicsBufferD>()->load(&vuboData, sizeof(vuboData));
gfxQ->setShaderDataBinding(binding);
gfxQ->setShaderDataBinding(binding2);
gfxQ->drawIndexed(0, 4);
gfxQ->resolveDisplay(renderTex);
m_console.draw(gfxQ);
@ -251,12 +239,8 @@ struct HECLApplicationCallback : boo::IApplicationCallback
++frameIdx;
}
std::unique_lock<std::mutex> finallk(loadmt);
m_cvarManager.serialize();
finallk.unlock();
gfxQ->stopRenderer();
loadcv.notify_one();
loaderThr.join();
return 0;
}
void appQuitting(boo::IApplication* /*app*/)

25
hecl/test/test.shader Normal file
View File

@ -0,0 +1,25 @@
#culling none
#attribute position3
#attribute normal3
#attribute uv2
#vertex glsl
layout(location=0) in vec3 in_pos;
layout(location=1) in vec3 in_norm;
layout(location=2) in vec2 in_uv;
SBINDING(0) out vec2 out_uv;
void main()
{
gl_Position = vec4(in_pos, 1.0);
out_uv = in_uv;
}
#fragment glsl
precision highp float;
TBINDING0 uniform sampler2D texs[1];
layout(location=0) out vec4 out_frag;
SBINDING(0) in vec2 out_uv;
void main()
{
out_frag = texture(texs[0], out_uv);
}