From 6ae4f6ed1151a9d0284b626e7672db4afddb6175 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sun, 15 Nov 2015 18:30:06 -1000 Subject: [PATCH] Additions to test --- hecl/blender/BlenderConnection.hpp | 11 +- hecl/blender/HMDL.cpp | 2 +- hecl/extern/libBoo | 2 +- hecl/include/HECL/Backend/GLSL.hpp | 6 +- .../HECL/Backend/ProgrammableCommon.hpp | 13 +- hecl/include/HECL/Frontend.hpp | 11 +- hecl/include/HECL/HECL.hpp | 5 +- hecl/include/HECL/Runtime.hpp | 182 ++++++++++--- hecl/lib/Backend/GLSL.cpp | 257 +++++++++++++++--- hecl/lib/Backend/ProgrammableCommon.cpp | 6 +- hecl/lib/Frontend/Lexer.cpp | 3 +- hecl/lib/Runtime/FileStoreManager.cpp | 15 +- hecl/lib/Runtime/ShaderCacheManager.cpp | 200 +++++++++++--- hecl/test/main.cpp | 122 ++++++++- 14 files changed, 698 insertions(+), 137 deletions(-) diff --git a/hecl/blender/BlenderConnection.hpp b/hecl/blender/BlenderConnection.hpp index 0f3224a64..896ada165 100644 --- a/hecl/blender/BlenderConnection.hpp +++ b/hecl/blender/BlenderConnection.hpp @@ -713,27 +713,22 @@ public: struct Surface; private: friend struct BlenderConnection::DataStream::Mesh; - HMDLBuffers(const HMDLMeta& meta, + HMDLBuffers(HMDLMeta&& meta, size_t vboSz, const std::vector& iboData, std::vector&& surfaces, const BlenderConnection::DataStream::Mesh::SkinBanks& skinBanks) - : m_metaSz(HECL_HMDL_META_SZ), m_metaData(new uint8_t[HECL_HMDL_META_SZ]), + : m_meta(std::move(meta)), m_vboSz(vboSz), m_vboData(new uint8_t[vboSz]), m_iboSz(iboData.size()*4), m_iboData(new uint8_t[iboData.size()*4]), m_surfaces(std::move(surfaces)), m_skinBanks(skinBanks) { - { - Athena::io::MemoryWriter w(m_metaData.get(), HECL_HMDL_META_SZ); - meta.write(w); - } { Athena::io::MemoryWriter w(m_iboData.get(), m_iboSz); w.enumerateLittle(iboData); } } public: - size_t m_metaSz; - std::unique_ptr m_metaData; + HMDLMeta m_meta; size_t m_vboSz; std::unique_ptr m_vboData; size_t m_iboSz; diff --git a/hecl/blender/HMDL.cpp b/hecl/blender/HMDL.cpp index 635c4f8db..ca0c18549 100644 --- a/hecl/blender/HMDL.cpp +++ b/hecl/blender/HMDL.cpp @@ -68,7 +68,7 @@ HMDLBuffers BlenderConnection::DataStream::Mesh::getHMDLBuffers() const metaOut.indexCount = iboData.size(); size_t vboSz = metaOut.vertCount * metaOut.vertStride; - HMDLBuffers ret(metaOut, vboSz, iboData, std::move(outSurfaces), skinBanks); + HMDLBuffers ret(std::move(metaOut), vboSz, iboData, std::move(outSurfaces), skinBanks); Athena::io::MemoryWriter vboW(ret.m_vboData.get(), vboSz); for (const std::pair& sv : vertPool) { diff --git a/hecl/extern/libBoo b/hecl/extern/libBoo index ddcbc102b..d75c675f7 160000 --- a/hecl/extern/libBoo +++ b/hecl/extern/libBoo @@ -1 +1 @@ -Subproject commit ddcbc102bab8cda86c0d93a859f6e2c1d8db0bd7 +Subproject commit d75c675f7a98c0eb40a3b216211328c1728aa479 diff --git a/hecl/include/HECL/Backend/GLSL.hpp b/hecl/include/HECL/Backend/GLSL.hpp index 23862464c..461bb6fe2 100644 --- a/hecl/include/HECL/Backend/GLSL.hpp +++ b/hecl/include/HECL/Backend/GLSL.hpp @@ -14,10 +14,10 @@ struct GLSL : ProgrammableCommon std::string makeVert(const char* glslVer, unsigned col, unsigned uv, unsigned w, unsigned skinSlots, unsigned texMtxs) const; std::string makeFrag(const char* glslVer, - const char* lightingSource, const char* lightingEntry) const; + const ShaderFunction& lighting=ShaderFunction()) const; std::string makeFrag(const char* glslVer, - const char* lightingSource, const char* lightingEntry, - const char* postSource, const char* postEntry) const; + const ShaderFunction& lighting, + const ShaderFunction& post) const; private: std::string GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const; diff --git a/hecl/include/HECL/Backend/ProgrammableCommon.hpp b/hecl/include/HECL/Backend/ProgrammableCommon.hpp index ba0a69694..feb9480a4 100644 --- a/hecl/include/HECL/Backend/ProgrammableCommon.hpp +++ b/hecl/include/HECL/Backend/ProgrammableCommon.hpp @@ -2,6 +2,7 @@ #define HECLBACKEND_PROGCOMMON_HPP #include "Backend.hpp" +#include "HECL/Runtime.hpp" #include #include #include @@ -15,6 +16,8 @@ namespace Backend struct ProgrammableCommon : IBackend { + using ShaderFunction = Runtime::ShaderCacheExtensions::Function; + std::string m_colorExpr; std::string m_alphaExpr; boo::BlendFactor m_blendSrc; @@ -27,6 +30,7 @@ struct ProgrammableCommon : IBackend int tcgIdx = -1; }; std::vector m_texSamplings; + unsigned m_texMapEnd = 0; enum TexGenSrc { @@ -59,9 +63,14 @@ private: const IR::Instruction& inst, int mtx); - std::string EmitSamplingUse(unsigned samplingIdx) const + std::string EmitSamplingUseRGB(unsigned samplingIdx) const { - return HECL::Format("sampling%u", samplingIdx); + return HECL::Format("sampling%u.rgb", samplingIdx); + } + + std::string EmitSamplingUseAlpha(unsigned samplingIdx) const + { + return HECL::Format("sampling%u.a", samplingIdx); } std::string EmitColorRegUse(unsigned idx) const diff --git a/hecl/include/HECL/Frontend.hpp b/hecl/include/HECL/Frontend.hpp index aea074235..a8ec9c609 100644 --- a/hecl/include/HECL/Frontend.hpp +++ b/hecl/include/HECL/Frontend.hpp @@ -29,6 +29,7 @@ class Diagnostics std::string sourceDiagString(const SourceLocation& l, bool ansi=false) const; public: void reset(const std::string& name, const std::string& source) {m_name = name; m_source = source;} + void reset(const std::string& name) {m_name = name; m_source.clear();} void setBackend(const std::string& backend) {m_backend = backend;} void setBackend(const char* backend) {m_backend = backend;} void reportParserErr(const SourceLocation& l, const char* format, ...); @@ -288,11 +289,13 @@ struct IR : BigDNA Instruction(Athena::io::IStreamReader& reader) {read(reader);} }; + atUint64 m_hash = 0; atUint16 m_regCount = 0; std::vector m_instructions; void read(Athena::io::IStreamReader& reader) { + m_hash = reader.readUint64Big(); m_regCount = reader.readUint16Big(); atUint16 instCount = reader.readUint16Big(); m_instructions.clear(); @@ -303,6 +306,7 @@ struct IR : BigDNA void write(Athena::io::IStreamWriter& writer) const { + writer.writeUint64Big(m_hash); writer.writeUint16Big(m_regCount); writer.writeUint16Big(m_instructions.size()); for (const Instruction& inst : m_instructions) @@ -311,7 +315,7 @@ struct IR : BigDNA size_t binarySize(size_t sz) const { - sz += 4; + sz += 12; for (const Instruction& inst : m_instructions) sz = inst.binarySize(sz); return sz; @@ -358,7 +362,7 @@ class Lexer public: void reset(); void consumeAllTokens(Parser& parser); - IR compileIR() const; + IR compileIR(atUint64 hash) const; Lexer(Diagnostics& diag) : m_diag(diag) {} }; @@ -371,10 +375,11 @@ class Frontend public: IR compileSource(const std::string& source, const std::string& diagName) { + Hash hash(source); m_diag.reset(diagName, source); m_parser.reset(source); m_lexer.consumeAllTokens(m_parser); - return m_lexer.compileIR(); + return m_lexer.compileIR(hash); } Diagnostics& getDiagnostics() {return m_diag;} diff --git a/hecl/include/HECL/HECL.hpp b/hecl/include/HECL/HECL.hpp index 93f275bf7..6180eb6c9 100644 --- a/hecl/include/HECL/HECL.hpp +++ b/hecl/include/HECL/HECL.hpp @@ -388,7 +388,8 @@ public: */ class Hash { - unsigned long long hash = 0; +protected: + uint64_t hash = 0; public: Hash() = default; operator bool() const {return hash != 0;} @@ -398,7 +399,7 @@ public: : hash(XXH64((uint8_t*)str.data(), str.size(), 0)) {} Hash(const std::wstring& str) : hash(XXH64((uint8_t*)str.data(), str.size()*2, 0)) {} - Hash(unsigned long long hashin) + Hash(uint64_t hashin) : hash(hashin) {} Hash(const Hash& other) {hash = other.hash;} uint32_t val32() const {return uint32_t(hash);} diff --git a/hecl/include/HECL/Runtime.hpp b/hecl/include/HECL/Runtime.hpp index d43ab5f26..6f3775c7b 100644 --- a/hecl/include/HECL/Runtime.hpp +++ b/hecl/include/HECL/Runtime.hpp @@ -2,6 +2,7 @@ #define HECLRUNTIME_HPP #include "HECL.hpp" +#include "Frontend.hpp" #include #include #include @@ -25,18 +26,6 @@ public: const SystemString& getStoreRoot() const {return m_storeRoot;} }; -/** - * @brief Shader formats that may be identified within ShaderHash - */ -enum ShaderFormat : uint8_t -{ - ShaderFormatNone, - ShaderFormatGLSL, - ShaderFormatHLSL, - ShaderFormatMetal, - ShaderFormatSpirV -}; - /** * @brief Hash subclass for identifying shaders and their metadata */ @@ -47,34 +36,144 @@ class ShaderTag : public Hash uint64_t m_meta = 0; struct { - ShaderFormat m_fmt; uint8_t m_colorCount; uint8_t m_uvCount; uint8_t m_weightCount; + uint8_t m_skinSlotCount; + uint8_t m_texMtxCount; + bool m_depthTest:1; + bool m_depthWrite:1; + bool m_backfaceCulling:1; }; }; public: ShaderTag() = default; - ShaderTag(const void* buf, size_t len, ShaderFormat fmt, uint8_t c, uint8_t u, uint8_t w) - : Hash(buf, len), m_fmt(fmt), m_colorCount(c), m_uvCount(u), m_weightCount(w) {} - ShaderTag(unsigned long long hashin, uint64_t meta) - : Hash(hashin), m_meta(meta) {} - ShaderTag(const ShaderTag& other) : Hash(other) {} - ShaderFormat getShaderFormat() const {return m_fmt;} + ShaderTag(const std::string& source, uint8_t c, uint8_t u, uint8_t w, uint8_t s, uint8_t t, + bool depthTest, bool depthWrite, bool backfaceCulling) + : Hash(source), m_colorCount(c), m_uvCount(u), m_weightCount(w), m_skinSlotCount(s), m_texMtxCount(t), + 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, uint8_t t, + bool depthTest, bool depthWrite, bool backfaceCulling) + : Hash(ir.m_hash), m_colorCount(c), m_uvCount(u), m_weightCount(w), m_skinSlotCount(s), m_texMtxCount(t), + 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, uint8_t t, + bool depthTest, bool depthWrite, bool backfaceCulling) + : Hash(hashin), m_colorCount(c), m_uvCount(u), m_weightCount(w), m_skinSlotCount(s), m_texMtxCount(t), + 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;} + uint8_t getTexMtxCount() const {return m_texMtxCount;} + 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;} }; +/** + * @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 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::PlatformNull) {} + + 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; + }; + std::vector 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::PlatformNull;} + + /* Strings must remain resident!! (intended to be stored static const) */ + unsigned registerExtensionSlot(Function lighting, Function post) + { + m_extensionSlots.emplace_back(); + m_extensionSlots.back().lighting = lighting; + m_extensionSlots.back().post = post; + return m_extensionSlots.size() - 1; + } +}; + +/** + * @brief Interface for binding HECL backends to the ShaderCacheManager + */ +class IShaderBackendFactory +{ + friend class ShaderCacheManager; +protected: + using FReturnExtensionShader = std::function; + virtual ShaderCachedData buildShaderFromIR(const ShaderTag& tag, + const HECL::Frontend::IR& ir, + HECL::Frontend::Diagnostics& diag, + boo::IShaderPipeline** objOut)=0; + virtual boo::IShaderPipeline* buildShaderFromCache(const ShaderCachedData& data)=0; + virtual ShaderCachedData buildExtendedShaderFromIR(const ShaderTag& tag, + const HECL::Frontend::IR& ir, + HECL::Frontend::Diagnostics& diag, + const std::vector& extensionSlots, + FReturnExtensionShader returnFunc)=0; + virtual void buildExtendedShaderFromCache(const ShaderCachedData& data, + const std::vector& extensionSlots, + FReturnExtensionShader returnFunc)=0; +public: + virtual ~IShaderBackendFactory() {} +}; + /** * @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 m_factory; Athena::io::FileReader m_idxFr; Athena::io::FileReader m_datFr; + HECL::Frontend::Frontend FE; struct IndexEntry : Athena::io::DNA { DECL_DNA @@ -87,29 +186,28 @@ class ShaderCacheManager std::vector m_entries; std::unordered_map m_entryLookup; uint64_t m_timeHash = 0; - void BootstrapIndex(); + void bootstrapIndex(); + ShaderCachedData lookupData(const Hash& hash); + bool addData(const ShaderCachedData& data); + boo::IShaderPipeline* buildFromCache(const ShaderCachedData& foundData); + std::vector buildExtendedFromCache(const ShaderCachedData& foundData); public: - ShaderCacheManager(const FileStoreManager& storeMgr) - : m_storeMgr(storeMgr), - m_idxFr(storeMgr.getStoreRoot() + _S("/shadercache.idx")), - m_datFr(storeMgr.getStoreRoot() + _S("/shadercache.dat")) - {reload();} + ShaderCacheManager(const FileStoreManager& storeMgr, + boo::IGraphicsDataFactory* gfxFactory, + ShaderCacheExtensions&& extension); + ShaderCacheManager(const FileStoreManager& storeMgr, + boo::IGraphicsDataFactory* gfxFactory) + : ShaderCacheManager(storeMgr, gfxFactory, ShaderCacheExtensions()) {} void reload(); - class CachedData - { - friend class ShaderCacheManager; - CachedData() = default; - CachedData(unsigned long long hashin, uint64_t meta, size_t decompSz) - : m_tag(hashin, meta), m_data(new uint8_t[decompSz]), m_sz(decompSz) {} - public: - ShaderTag m_tag; - std::unique_ptr m_data; - size_t m_sz; - operator bool() const {return m_tag.operator bool();} - }; - CachedData lookupData(const Hash& hash); - bool addData(const ShaderTag& hash, const void* data, size_t sz); + boo::IShaderPipeline* buildShader(const ShaderTag& tag, const std::string& source, + const std::string& diagName); + boo::IShaderPipeline* buildShader(const ShaderTag& tag, const HECL::Frontend::IR& ir, + const std::string& diagName); + std::vector buildExtendedShader(const ShaderTag& tag, const std::string& source, + const std::string& diagName); + std::vector buildExtendedShader(const ShaderTag& tag, const HECL::Frontend::IR& ir, + const std::string& diagName); }; /** @@ -123,6 +221,12 @@ struct HMDLData HMDLData(boo::IGraphicsDataFactory* factory, const void* metaData, const void* vbo, const void* ibo); + + boo::IShaderDataBinding* newShaderDataBindng(boo::IGraphicsDataFactory* factory, + boo::IShaderPipeline* shader, + size_t ubufCount, boo::IGraphicsBuffer** ubufs, + size_t texCount, boo::ITexture** texs) + {return factory->newShaderDataBinding(shader, m_vtxFmt, m_vbo, m_ibo, ubufCount, ubufs, texCount, texs);} }; } diff --git a/hecl/lib/Backend/GLSL.cpp b/hecl/lib/Backend/GLSL.cpp index a6684436f..faf2708eb 100644 --- a/hecl/lib/Backend/GLSL.cpp +++ b/hecl/lib/Backend/GLSL.cpp @@ -1,5 +1,10 @@ #include "HECL/Backend/GLSL.hpp" -#include +#include "HECL/Runtime.hpp" +#include +#include +#include + +static LogVisor::LogModule Log("HECL::Backend::GLSL"); namespace HECL { @@ -11,9 +16,9 @@ std::string GLSL::EmitTexGenSource2(TexGenSrc src, int uvIdx) const switch (src) { case TG_POS: - return "posIn.xy;\n"; + return "posIn.xy\n"; case TG_NRM: - return "normIn.xy;\n"; + return "normIn.xy\n"; case TG_UV: return HECL::Format("uvIn[%u]", uvIdx); default: break; @@ -26,9 +31,9 @@ std::string GLSL::EmitTexGenSource4(TexGenSrc src, int uvIdx) const switch (src) { case TG_POS: - return "vec4(posIn, 1.0);\n"; + return "vec4(posIn, 1.0)\n"; case TG_NRM: - return "vec4(normIn, 1.0);\n"; + return "vec4(normIn, 1.0)\n"; case TG_UV: return HECL::Format("vec4(uvIn[%u], 0.0, 1.0)", uvIdx); default: break; @@ -81,7 +86,7 @@ std::string GLSL::GenerateVertUniformStruct(unsigned skinSlots, unsigned texMtxs { if (skinSlots == 0) skinSlots = 1; - std::string retval = HECL::Format("struct HECLVertUniform\n" + std::string retval = HECL::Format("uniform HECLVertUniform\n" "{\n" " mat4 mv[%u];\n" " mat4 mvInv[%u];\n" @@ -89,7 +94,7 @@ std::string GLSL::GenerateVertUniformStruct(unsigned skinSlots, unsigned texMtxs skinSlots, skinSlots); if (texMtxs) retval += HECL::Format(" mat4 texMtxs[%u];\n", texMtxs); - return retval + "};\n"; + return retval + "} vu;\n"; } void GLSL::reset(const IR& ir, Diagnostics& diag) @@ -99,26 +104,25 @@ void GLSL::reset(const IR& ir, Diagnostics& diag) } std::string GLSL::makeVert(const char* glslVer, unsigned col, unsigned uv, unsigned w, - unsigned skinSlots, unsigned texMtxs) const + unsigned s, unsigned tm) const { std::string retval = std::string(glslVer) + "\n" + GenerateVertInStruct(col, uv, w) + "\n" + GenerateVertToFragStruct() + "\n" + - GenerateVertUniformStruct(skinSlots, texMtxs) + - "layout(location=0) uniform HECLVertUniform vu;\n" + GenerateVertUniformStruct(s, tm) + "out VertToFrag vtf;\n\n" "void main()\n{\n"; - if (skinSlots) + if (s) { /* skinned */ retval += " vec4 posAccum = vec4(0.0,0.0,0.0,0.0);\n" " vec4 normAccum = vec4(0.0,0.0,0.0,0.0);\n"; - for (size_t i=0 ; i(gfxFactory)) {} + + ShaderCachedData buildShaderFromIR(const ShaderTag& tag, + const HECL::Frontend::IR& ir, + HECL::Frontend::Diagnostics& diag, + 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(), tag.getTexMtxCount()); + cachedSz += vertSource.size() + 1; + + std::string fragSource = m_backend.makeFrag("#version 330"); + cachedSz += fragSource.size() + 1; + *objOut = + m_gfxFactory->newShaderPipeline(vertSource.c_str(), fragSource.c_str(), + m_backend.m_texMapEnd, "texs", + 1, STD_BLOCKNAMES, + m_backend.m_blendSrc, m_backend.m_blendDst, + tag.getDepthTest(), tag.getDepthWrite(), + tag.getBackfaceCulling()); + if (!*objOut) + Log.report(LogVisor::FatalError, "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(m_backend.m_blendSrc); + w.writeUByte(m_backend.m_blendDst); + w.writeString(vertSource); + w.writeString(fragSource); + + return dataOut; + } + + boo::IShaderPipeline* buildShaderFromCache(const ShaderCachedData& data) + { + const ShaderTag& tag = data.m_tag; + Athena::io::MemoryReader r(data.m_data.get(), data.m_sz); + 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(); + boo::IShaderPipeline* ret = + m_gfxFactory->newShaderPipeline(vertSource.c_str(), fragSource.c_str(), + texMapEnd, "texs", + 1, STD_BLOCKNAMES, + blendSrc, blendDst, + tag.getDepthTest(), tag.getDepthWrite(), + tag.getBackfaceCulling()); + if (!ret) + Log.report(LogVisor::FatalError, "unable to build shader"); + return ret; + } + + ShaderCachedData buildExtendedShaderFromIR(const ShaderTag& tag, + const HECL::Frontend::IR& ir, + HECL::Frontend::Diagnostics& diag, + const std::vector& extensionSlots, + FReturnExtensionShader returnFunc) + { + 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(), tag.getTexMtxCount()); + cachedSz += vertSource.size() + 1; + + std::vector fragSources; + fragSources.reserve(extensionSlots.size()); + for (const ShaderCacheExtensions::ExtensionSlot& slot : extensionSlots) + { + fragSources.push_back(m_backend.makeFrag("#version 330", slot.lighting, slot.post)); + cachedSz += fragSources.back().size() + 1; + boo::IShaderPipeline* ret = + m_gfxFactory->newShaderPipeline(vertSource.c_str(), fragSources.back().c_str(), + m_backend.m_texMapEnd, "texs", + 1, STD_BLOCKNAMES, + m_backend.m_blendSrc, m_backend.m_blendDst, + tag.getDepthTest(), tag.getDepthWrite(), + tag.getBackfaceCulling()); + if (!ret) + Log.report(LogVisor::FatalError, "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(m_backend.m_blendSrc); + w.writeUByte(m_backend.m_blendDst); + w.writeString(vertSource); + for (const std::string src : fragSources) + w.writeString(src); + + return dataOut; + } + + void buildExtendedShaderFromCache(const ShaderCachedData& data, + const std::vector& extensionSlots, + FReturnExtensionShader returnFunc) + { + const ShaderTag& tag = data.m_tag; + Athena::io::MemoryReader r(data.m_data.get(), data.m_sz); + atUint8 texMapEnd = r.readUByte(); + boo::BlendFactor blendSrc = boo::BlendFactor(r.readUByte()); + boo::BlendFactor blendDst = boo::BlendFactor(r.readUByte()); + std::string vertSource = r.readString(); + for (const ShaderCacheExtensions::ExtensionSlot& slot : extensionSlots) + { + std::string fragSource = r.readString(); + boo::IShaderPipeline* ret = + m_gfxFactory->newShaderPipeline(vertSource.c_str(), fragSource.c_str(), + texMapEnd, "texs", + 1, STD_BLOCKNAMES, + blendSrc, blendDst, + tag.getDepthTest(), tag.getDepthWrite(), + tag.getBackfaceCulling()); + if (!ret) + Log.report(LogVisor::FatalError, "unable to build shader"); + returnFunc(ret); + } + } +}; + +IShaderBackendFactory* _NewGLSLBackendFactory(boo::IGraphicsDataFactory* gfxFactory) +{ + return new struct GLSLBackendFactory(gfxFactory); } } diff --git a/hecl/lib/Backend/ProgrammableCommon.cpp b/hecl/lib/Backend/ProgrammableCommon.cpp index b98cb9af1..741351fdd 100644 --- a/hecl/lib/Backend/ProgrammableCommon.cpp +++ b/hecl/lib/Backend/ProgrammableCommon.cpp @@ -34,6 +34,8 @@ unsigned ProgrammableCommon::addTexSampling(unsigned mapIdx, unsigned tcgIdx) TexSampling& samp = m_texSamplings.back(); samp.mapIdx = mapIdx; samp.tcgIdx = tcgIdx; + if (m_texMapEnd < mapIdx + 1) + m_texMapEnd = mapIdx + 1; return m_texSamplings.size() - 1; } @@ -92,7 +94,7 @@ std::string ProgrammableCommon::RecursiveTraceColor(const IR& ir, Diagnostics& d const IR::Instruction& tcgInst = inst.getChildInst(ir, 1); unsigned texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, -1); - return EmitSamplingUse(addTexSampling(mapIdx, texGenIdx)); + return EmitSamplingUseRGB(addTexSampling(mapIdx, texGenIdx)); } else if (!name.compare("ColorReg")) { @@ -177,7 +179,7 @@ std::string ProgrammableCommon::RecursiveTraceAlpha(const IR& ir, Diagnostics& d const IR::Instruction& tcgInst = inst.getChildInst(ir, 1); unsigned texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, -1); - return EmitSamplingUse(addTexSampling(mapIdx, texGenIdx)); + return EmitSamplingUseAlpha(addTexSampling(mapIdx, texGenIdx)); } else if (!name.compare("ColorReg")) { diff --git a/hecl/lib/Frontend/Lexer.cpp b/hecl/lib/Frontend/Lexer.cpp index d9c080efc..200f202d9 100644 --- a/hecl/lib/Frontend/Lexer.cpp +++ b/hecl/lib/Frontend/Lexer.cpp @@ -706,12 +706,13 @@ void Lexer::RecursiveFuncCompile(IR& ir, const Lexer::OperationNode* funcNode, I ir.m_regCount = tgt; } -IR Lexer::compileIR() const +IR Lexer::compileIR(atUint64 hash) const { if (!m_root) m_diag.reportCompileErr(SourceLocation(), "unable to compile HECL-IR for invalid source"); IR ir; + ir.m_hash = hash; RecursiveFuncCompile(ir, m_root, 0); return ir; } diff --git a/hecl/lib/Runtime/FileStoreManager.cpp b/hecl/lib/Runtime/FileStoreManager.cpp index a897ee835..821b2af5d 100644 --- a/hecl/lib/Runtime/FileStoreManager.cpp +++ b/hecl/lib/Runtime/FileStoreManager.cpp @@ -28,16 +28,27 @@ FileStoreManager::FileStoreManager(const SystemString& domain) HECL::MakeDir(path.c_str()); m_storeRoot = path; #elif __APPLE__ + const char* home = getenv("HOME"); + if (!home) + Log.report(LogVisor::FatalError, "unable to locate $HOME for file store"); + std::string path(home); + path += "/Library/Application Support/HECL Runtime"; + if (mkdir(path.c_str(), 0755) && errno != EEXIST) + Log.report(LogVisor::FatalError, "unable to mkdir at %s", path.c_str()); + path += '/' + domain; + if (mkdir(path.c_str(), 0755) && errno != EEXIST) + Log.report(LogVisor::FatalError, "unable to mkdir at %s", path.c_str()); + m_storeRoot = path; #else const char* home = getenv("HOME"); if (!home) Log.report(LogVisor::FatalError, "unable to locate $HOME for file store"); std::string path(home); path += "/.heclrun"; - if (mkdir(path.c_str(), 0755)) + if (mkdir(path.c_str(), 0755) && errno != EEXIST) Log.report(LogVisor::FatalError, "unable to mkdir at %s", path.c_str()); path += '/' + domain; - if (mkdir(path.c_str(), 0755)) + if (mkdir(path.c_str(), 0755) && errno != EEXIST) Log.report(LogVisor::FatalError, "unable to mkdir at %s", path.c_str()); m_storeRoot = path; #endif diff --git a/hecl/lib/Runtime/ShaderCacheManager.cpp b/hecl/lib/Runtime/ShaderCacheManager.cpp index b32b5c0f8..b2be8845a 100644 --- a/hecl/lib/Runtime/ShaderCacheManager.cpp +++ b/hecl/lib/Runtime/ShaderCacheManager.cpp @@ -5,10 +5,14 @@ #include #include +#include "HECL/Backend/GLSL.hpp" + namespace HECL { namespace Runtime { +IShaderBackendFactory* _NewGLSLBackendFactory(boo::IGraphicsDataFactory* gfxFactory); + static LogVisor::LogModule Log("ShaderCacheManager"); static uint64_t IDX_MAGIC = SBig(0xDEADFEEDC001D00D); static uint64_t DAT_MAGIC = SBig(0xC001D00DDEADBABE); @@ -27,7 +31,26 @@ static uint64_t timeHash() return tmp.val64(); } -void ShaderCacheManager::BootstrapIndex() +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)); +} +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); + } + return XXH64_digest(&st); +} + +void ShaderCacheManager::bootstrapIndex() { m_timeHash = timeHash(); m_idxFr.close(); @@ -45,7 +68,7 @@ void ShaderCacheManager::BootstrapIndex() idxFilename.c_str()); fwrite(&IDX_MAGIC, 1, 8, idxFp); fwrite(&m_timeHash, 1, 8, idxFp); - fwrite(&ZERO64, 1, 8, idxFp); + fwrite(&m_extensionsHash, 1, 8, idxFp); fwrite(&ZERO64, 1, 8, idxFp); fclose(idxFp); @@ -67,6 +90,32 @@ void ShaderCacheManager::BootstrapIndex() m_datFr.open(); } +ShaderCacheManager::ShaderCacheManager(const FileStoreManager& storeMgr, + boo::IGraphicsDataFactory* gfxFactory, + ShaderCacheExtensions&& extension) +: m_storeMgr(storeMgr), + m_extensions(std::move(extension)), + m_idxFr(storeMgr.getStoreRoot() + _S("/shadercache") + gfxFactory->platformName() + _S(".idx")), + m_datFr(storeMgr.getStoreRoot() + _S("/shadercache") + gfxFactory->platformName() + _S(".dat")) +{ + boo::IGraphicsDataFactory::Platform plat = gfxFactory->platform(); + if (m_extensions && m_extensions.m_plat != plat) + Log.report(LogVisor::FatalError, "ShaderCacheExtension backend mismatch (should be %s)", + gfxFactory->platformName()); + m_extensionsHash = m_extensions.hashExtensions(); + + switch (plat) + { + case boo::IGraphicsDataFactory::PlatformOGL: + m_factory.reset(_NewGLSLBackendFactory(gfxFactory)); + break; + default: + Log.report(LogVisor::FatalError, "unsupported backend %s", gfxFactory->platformName()); + } + + reload(); +} + void ShaderCacheManager::reload() { m_entries.clear(); @@ -78,7 +127,7 @@ void ShaderCacheManager::reload() m_datFr.seek(0, Athena::Begin); if (m_idxFr.hasError() || m_datFr.hasError()) { - BootstrapIndex(); + bootstrapIndex(); return; } else @@ -87,7 +136,7 @@ void ShaderCacheManager::reload() size_t rb = m_idxFr.readUBytesToBuf(&idxMagic, 8); if (rb != 8 || idxMagic != IDX_MAGIC) { - BootstrapIndex(); + bootstrapIndex(); return; } @@ -95,7 +144,7 @@ void ShaderCacheManager::reload() rb = m_datFr.readUBytesToBuf(&datMagic, 8); if (rb != 8 || datMagic != DAT_MAGIC) { - BootstrapIndex(); + bootstrapIndex(); return; } @@ -104,47 +153,58 @@ void ShaderCacheManager::reload() size_t rb2 = m_datFr.readUBytesToBuf(&datRand, 8); if (rb != 8 || rb2 != 8 || idxRand != datRand) { - BootstrapIndex(); + bootstrapIndex(); return; } m_timeHash = idxRand; } - /* Read existing entries */ - atUint64 idxCount = m_idxFr.readUint64Big(); - if (m_idxFr.position() != 24) + atUint64 extensionsHash; + size_t rb = m_idxFr.readUBytesToBuf(&extensionsHash, 8); + if (rb != 8 || extensionsHash != m_extensionsHash) { - BootstrapIndex(); + bootstrapIndex(); return; } - m_entries.reserve(idxCount); - m_entryLookup.reserve(idxCount); - for (atUint64 i=0 ; isecond]; if (ent.m_compOffset + ent.m_compSize > m_datFr.length()) { Log.report(LogVisor::Warning, "shader cache not long enough to read entry, might be corrupt"); - return CachedData(); + return ShaderCachedData(); } /* File-streamed decompression */ m_datFr.seek(ent.m_compOffset, Athena::Begin); - CachedData ret(ent.m_hash, ent.m_meta, ent.m_decompSize); + ShaderCachedData ret(ShaderTag(ent.m_hash, ent.m_meta), ent.m_decompSize); uint8_t compDat[2048]; z_stream z = {}; inflateInit(&z); @@ -161,15 +221,15 @@ ShaderCacheManager::CachedData ShaderCacheManager::lookupData(const Hash& hash) return ret; } -bool ShaderCacheManager::addData(const ShaderTag& tag, const void* data, size_t sz) +bool ShaderCacheManager::addData(const ShaderCachedData& data) { m_idxFr.close(); m_datFr.close(); /* Perform one-shot buffer compression */ - uLong cBound = compressBound(sz); + uLong cBound = compressBound(data.m_sz); void* compBuf = malloc(cBound); - if (compress((Bytef*)compBuf, &cBound, (Bytef*)data, sz) != Z_OK) + if (compress((Bytef*)compBuf, &cBound, (Bytef*)data.m_data.get(), data.m_sz) != Z_OK) Log.report(LogVisor::FatalError, "unable to deflate data"); /* Open index for writing (non overwriting) */ @@ -185,7 +245,7 @@ bool ShaderCacheManager::addData(const ShaderTag& tag, const void* data, size_t m_datFr.filename().c_str()); size_t targetOffset = 0; - auto search = m_entryLookup.find(tag); + auto search = m_entryLookup.find(data.m_tag); if (search != m_entryLookup.cend()) { /* Hash already present, attempt to replace data */ @@ -193,9 +253,9 @@ bool ShaderCacheManager::addData(const ShaderTag& tag, const void* data, size_t if (search->second == m_entries.size() - 1) { /* Replacing final entry; simply write-over */ - ent.m_meta = tag.getMetaData(); + ent.m_meta = data.m_tag.getMetaData(); ent.m_compSize = cBound; - ent.m_decompSize = sz; + ent.m_decompSize = data.m_sz; targetOffset = ent.m_compOffset; idxFw.seek(search->second * 32 + 32); ent.write(idxFw); @@ -207,9 +267,9 @@ bool ShaderCacheManager::addData(const ShaderTag& tag, const void* data, size_t size_t space = nent.m_compOffset - ent.m_compOffset; if (cBound <= space) { - ent.m_meta = tag.getMetaData(); + ent.m_meta = data.m_tag.getMetaData(); ent.m_compSize = cBound; - ent.m_decompSize = sz; + ent.m_decompSize = data.m_sz; targetOffset = ent.m_compOffset; idxFw.seek(search->second * 32 + 32); ent.write(idxFw); @@ -235,15 +295,15 @@ bool ShaderCacheManager::addData(const ShaderTag& tag, const void* data, size_t idxFw.writeUint64Big(m_entries.size() + 1); idxFw.seek(m_entries.size() * 32 + 32, Athena::Begin); datFw.seek(0, Athena::End); - m_entryLookup[tag] = m_entries.size(); + m_entryLookup[data.m_tag] = m_entries.size(); m_entries.emplace_back(); IndexEntry& ent = m_entries.back(); - ent.m_hash = tag.val64(); - ent.m_meta = tag.getMetaData(); + 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 = sz; + ent.m_decompSize = data.m_sz; ent.write(idxFw); datFw.writeUBytes((atUint8*)compBuf, cBound); @@ -266,5 +326,79 @@ bool ShaderCacheManager::addData(const ShaderTag& tag, const void* data, size_t return true; } +boo::IShaderPipeline* +ShaderCacheManager::buildFromCache(const ShaderCachedData& foundData) +{ + return m_factory->buildShaderFromCache(foundData); +} + +boo::IShaderPipeline* +ShaderCacheManager::buildShader(const ShaderTag& tag, const std::string& source, + const std::string& diagName) +{ + ShaderCachedData foundData = lookupData(tag); + if (foundData) + return buildFromCache(foundData); + HECL::Frontend::IR ir = FE.compileSource(source, diagName); + return buildShader(tag, ir, diagName); +} + +boo::IShaderPipeline* +ShaderCacheManager::buildShader(const ShaderTag& tag, const HECL::Frontend::IR& ir, + const std::string& diagName) +{ + ShaderCachedData foundData = lookupData(tag); + if (foundData) + return buildFromCache(foundData); + FE.getDiagnostics().reset(diagName); + boo::IShaderPipeline* ret; + addData(m_factory->buildShaderFromIR(tag, ir, FE.getDiagnostics(), &ret)); + return ret; +} + +std::vector +ShaderCacheManager::buildExtendedFromCache(const ShaderCachedData& foundData) +{ + std::vector shaders; + shaders.reserve(m_extensions.m_extensionSlots.size()); + m_factory->buildExtendedShaderFromCache(foundData, m_extensions.m_extensionSlots, + [&](boo::IShaderPipeline* shader){shaders.push_back(shader);}); + if (shaders.size() != m_extensions.m_extensionSlots.size()) + Log.report(LogVisor::FatalError, "buildShaderFromCache returned %" PRISize " times, expected %" PRISize, + shaders.size(), m_extensions.m_extensionSlots.size()); + return shaders; +} + +std::vector +ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, const std::string& source, + const std::string& diagName) +{ + ShaderCachedData foundData = lookupData(tag); + if (foundData) + return buildExtendedFromCache(foundData); + HECL::Frontend::IR ir = FE.compileSource(source, diagName); + return buildExtendedShader(tag, ir, diagName); +} + +std::vector +ShaderCacheManager::buildExtendedShader(const ShaderTag& tag, const HECL::Frontend::IR& ir, + const std::string& diagName) +{ + ShaderCachedData foundData = lookupData(tag); + if (foundData) + return buildExtendedFromCache(foundData); + std::vector shaders; + shaders.reserve(m_extensions.m_extensionSlots.size()); + FE.getDiagnostics().reset(diagName); + ShaderCachedData data = + m_factory->buildExtendedShaderFromIR(tag, ir, FE.getDiagnostics(), m_extensions.m_extensionSlots, + [&](boo::IShaderPipeline* shader){shaders.push_back(shader);}); + if (shaders.size() != m_extensions.m_extensionSlots.size()) + Log.report(LogVisor::FatalError, "buildShaderFromIR returned %" PRISize " times, expected %" PRISize, + shaders.size(), m_extensions.m_extensionSlots.size()); + addData(data); + return shaders; +} + } } diff --git a/hecl/test/main.cpp b/hecl/test/main.cpp index da2964612..eaf39fe12 100644 --- a/hecl/test/main.cpp +++ b/hecl/test/main.cpp @@ -1,6 +1,10 @@ #include #include +#include #include "HECL/Runtime.hpp" +#include "HECL/HMDLMeta.hpp" + +#include struct HECLWindowCallback : boo::IWindowCallback { @@ -26,9 +30,7 @@ struct HECLApplicationCallback : boo::IApplicationCallback bool m_running = true; int appMain(boo::IApplication* app) { - HECL::Runtime::FileStoreManager fileMgr(app->getUniqueName()); - HECL::Runtime::ShaderCacheManager shaderMgr(fileMgr); - + /* Setup boo window */ m_mainWindow = app->newWindow(_S("HECL Test")); m_mainWindow->setCallback(&m_windowCb); m_mainWindow->showWindow(); @@ -36,7 +38,99 @@ struct HECLApplicationCallback : boo::IApplicationCallback boo::IGraphicsDataFactory* gfxF = m_mainWindow->getLoadContextDataFactory(); boo::SWindowRect mainWindowRect = m_mainWindow->getWindowFrame(); boo::ITextureR* renderTex = gfxF->newRenderTexture(mainWindowRect.size[0], mainWindowRect.size[1], 1); + + /* HECL managers */ + HECL::Runtime::FileStoreManager fileMgr(app->getUniqueName()); + HECL::Runtime::ShaderCacheManager shaderMgr(fileMgr, gfxF); + + /* Compile HECL shader */ + static std::string testShader = "HECLOpaque(Texture(0, UV(0)))"; + HECL::Runtime::ShaderTag testShaderTag(testShader, 0, 1, 0, 0, 0, false, false, false); + boo::IShaderPipeline* testShaderObj = + shaderMgr.buildShader(testShaderTag, testShader, "testShader"); + + /* Generate meta structure (usually statically serialized) */ + HECL::HMDLMeta testMeta; + testMeta.topology = HECL::TopologyTriStrips; + testMeta.vertStride = 32; + testMeta.vertCount = 4; + testMeta.indexCount = 4; + testMeta.colorCount = 0; + testMeta.uvCount = 1; + testMeta.weightCount = 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(gfxF, testMetaBuf, quad, ibo); + + /* Make ramp texture */ + using Pixel = uint8_t[4]; + static Pixel tex[256][256]; + for (int i=0 ; i<256 ; ++i) + for (int j=0 ; j<256 ; ++j) + { + tex[i][j][0] = i; + tex[i][j][1] = j; + tex[i][j][2] = 0; + tex[i][j][3] = 0xff; + } + boo::ITexture* texture = + gfxF->newStaticTexture(256, 256, 1, boo::TextureFormatRGBA8, tex, 256*256*4); + + /* Make vertex uniform buffer */ + struct VertexUBO + { + float modelview[4][4] = {}; + float modelviewInv[4][4] = {}; + float projection[4][4] = {}; + VertexUBO() + { + modelview[0][0] = 1.0; + modelview[1][1] = 1.0; + modelview[2][2] = 1.0; + modelview[3][3] = 1.0; + modelviewInv[0][0] = 1.0; + modelviewInv[1][1] = 1.0; + modelviewInv[2][2] = 1.0; + modelviewInv[3][3] = 1.0; + projection[0][0] = 1.0; + projection[1][1] = 1.0; + projection[2][2] = 1.0; + projection[3][3] = 1.0; + } + } vuboData; + boo::IGraphicsBufferD* vubo = + gfxF->newDynamicBuffer(boo::BufferUseUniform, sizeof(VertexUBO), 1); + + /* Assemble data binding */ + boo::IShaderDataBinding* binding = + testData.newShaderDataBindng(gfxF, testShaderObj, 1, (boo::IGraphicsBuffer**)&vubo, 1, &texture); + gfxF->commit(); + + size_t frameIdx = 0; while (m_running) { m_mainWindow->waitForRetrace(); @@ -56,9 +150,23 @@ struct HECLApplicationCallback : boo::IApplicationCallback } gfxQ->setRenderTarget(renderTex); + boo::SWindowRect r = m_windowCb.m_latestSize; + r.location[0] = 0; + r.location[1] = 0; + gfxQ->setViewport(r); + float rgba[] = {sinf(frameIdx / 60.0), cosf(frameIdx / 60.0), 0.0, 1.0}; + gfxQ->setClearColor(rgba); gfxQ->clearTarget(); + gfxQ->setDrawPrimitive(boo::PrimitiveTriStrips); + + vubo->load(&vuboData, sizeof(vuboData)); + + gfxQ->setShaderDataBinding(binding); + gfxQ->draw(0, 4); gfxQ->resolveDisplay(renderTex); gfxQ->execute(); + + ++frameIdx; } return 0; } @@ -68,16 +176,22 @@ struct HECLApplicationCallback : boo::IApplicationCallback } }; +void AthenaExcHandler(const Athena::error::Level& level, + const char* file, const char* function, + int line, const char* fmt, ...) +{} + #if _WIN32 int wmain(int argc, const boo::SystemChar** argv) #else int main(int argc, const boo::SystemChar** argv) #endif { + atSetExceptionHandler(AthenaExcHandler); LogVisor::RegisterConsoleLogger(); HECLApplicationCallback appCb; int ret = boo::ApplicationRun(boo::IApplication::PLAT_AUTO, - appCb, _S("hecl"), _S("HECL"), argc, argv); + appCb, _S("heclTest"), _S("HECL Test"), argc, argv); printf("IM DYING!!\n"); return ret; }