mirror of https://github.com/AxioDL/metaforce.git
Huge shader infrastructure refactor
This commit is contained in:
parent
170ff23843
commit
0ee18025dd
|
@ -1,2 +1,3 @@
|
|||
DataSpecRegistry.hpp
|
||||
include/hecl/ApplicationReps.hpp
|
||||
.DS_Store
|
||||
|
|
|
@ -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()
|
|
@ -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)
|
||||
|
|
|
@ -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 #
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 488acc867523ddce51bdf8e6975a4271997363dc
|
||||
Subproject commit 5f2611702d4989097a850d8a5705184392d8510c
|
|
@ -1 +1 @@
|
|||
Subproject commit 08d632a8bd88b9a79884c2fe1cb36c00ddc400a8
|
||||
Subproject commit c29d837ab58b9dd8be67a7f2358b84e94f6ee7f9
|
|
@ -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@
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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
|
||||
|
||||
}
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
set(RUNTIME_SOURCES
|
||||
FileStoreManager.cpp
|
||||
ShaderCacheManager.cpp
|
||||
HMDL_RT.cpp)
|
||||
|
||||
hecl_add_list(Runtime RUNTIME_SOURCES)
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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()
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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*/)
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue