#include "hecl/Backend/Metal.hpp" #if BOO_HAS_METAL #include "hecl/Runtime.hpp" #include #include #include static logvisor::Module Log("hecl::Backend::Metal"); namespace hecl { namespace Backend { std::string Metal::EmitTexGenSource2(TexGenSrc src, int uvIdx) const { switch (src) { case TexGenSrc::Position: return "v.posIn.xy\n"; case TexGenSrc::Normal: return "v.normIn.xy\n"; case TexGenSrc::UV: return hecl::Format("v.uvIn%u", uvIdx); default: break; } return std::string(); } std::string Metal::EmitTexGenSource4(TexGenSrc src, int uvIdx) const { switch (src) { case TexGenSrc::Position: return "float4(v.posIn, 1.0)\n"; case TexGenSrc::Normal: return "float4(v.normIn, 1.0)\n"; case TexGenSrc::UV: return hecl::Format("float4(v.uvIn%u, 0.0, 1.0)", uvIdx); default: break; } return std::string(); } std::string Metal::GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const { std::string retval = "struct VertData\n" "{\n" " float3 posIn [[ attribute(0) ]];\n" " float3 normIn [[ attribute(1) ]];\n"; unsigned idx = 2; if (col) { for (unsigned i=0 ; i tex%u [[ texture(%u) ]]", i, i); } std::string blockCall; for (size_t i=0 ; i tex%u [[ texture(%u) ]]", i, i); } std::string blockCall; for (size_t i=0 ; i(ctx). newShaderPipeline(vertSource.c_str(), fragSource.c_str(), tag.newVertexFormat(ctx), m_rtHint, m_backend.m_blendSrc, m_backend.m_blendDst, tag.getPrimType(), tag.getDepthTest(), tag.getDepthWrite(), tag.getBackfaceCulling()); 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(atUint8(m_backend.m_blendSrc)); w.writeUByte(atUint8(m_backend.m_blendDst)); w.writeString(vertSource); w.writeString(fragSource); return dataOut; } boo::IShaderPipeline* buildShaderFromCache(const ShaderCachedData& data, boo::IGraphicsDataFactory::Context& ctx) { if (!m_rtHint) Log.report(logvisor::Fatal, "ShaderCacheManager::setRenderTargetHint must be called before making metal shaders"); const ShaderTag& tag = data.m_tag; athena::io::MemoryReader r(data.m_data.get(), data.m_sz); 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 = static_cast(ctx). newShaderPipeline(vertSource.c_str(), fragSource.c_str(), tag.newVertexFormat(ctx), m_rtHint, blendSrc, blendDst, tag.getPrimType(), tag.getDepthTest(), tag.getDepthWrite(), tag.getBackfaceCulling()); 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& extensionSlots, boo::IGraphicsDataFactory::Context& ctx, FReturnExtensionShader returnFunc) { if (!m_rtHint) Log.report(logvisor::Fatal, "ShaderCacheManager::setRenderTargetHint must be called before making metal shaders"); m_backend.reset(ir, diag); size_t cachedSz = 2; std::string vertSource = m_backend.makeVert(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(slot.blockCount, slot.blockNames, slot.lighting, slot.post)); cachedSz += fragSources.back().size() + 1; boo::IShaderPipeline* ret = static_cast(ctx). newShaderPipeline(vertSource.c_str(), fragSources.back().c_str(), tag.newVertexFormat(ctx), m_rtHint, m_backend.m_blendSrc, m_backend.m_blendDst, tag.getPrimType(), tag.getDepthTest(), tag.getDepthWrite(), tag.getBackfaceCulling()); 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(atUint8(m_backend.m_blendSrc)); w.writeUByte(atUint8(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, boo::IGraphicsDataFactory::Context& ctx, FReturnExtensionShader returnFunc) { if (!m_rtHint) Log.report(logvisor::Fatal, "ShaderCacheManager::setRenderTargetHint must be called before making metal shaders"); const ShaderTag& tag = data.m_tag; athena::io::MemoryReader r(data.m_data.get(), data.m_sz); 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 = static_cast(ctx). newShaderPipeline(vertSource.c_str(), fragSource.c_str(), tag.newVertexFormat(ctx), m_rtHint, blendSrc, blendDst, tag.getPrimType(), tag.getDepthTest(), tag.getDepthWrite(), tag.getBackfaceCulling()); if (!ret) Log.report(logvisor::Fatal, "unable to build shader"); returnFunc(ret); } } }; IShaderBackendFactory* _NewMetalBackendFactory() { return new struct MetalBackendFactory(); } } } #endif