mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-12-08 11:44:55 +00:00
Start wiring up wgpu+winit
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
|
||||
//#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
|
||||
#include <xxhash/xxhash.h>
|
||||
|
||||
#include "hecl.hpp"
|
||||
@@ -87,213 +87,213 @@ struct TextureInfo {
|
||||
|
||||
enum class ReflectionType { None, Simple, Indirect };
|
||||
|
||||
/**
|
||||
* @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;
|
||||
bool m_alphaTest : 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,
|
||||
bool alphaTest)
|
||||
: 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;
|
||||
m_alphaTest = alphaTest;
|
||||
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,
|
||||
bool alphaTest)
|
||||
: 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;
|
||||
m_alphaTest = alphaTest;
|
||||
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; }
|
||||
bool getAlphaTest() const { return m_alphaTest; }
|
||||
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;
|
||||
}
|
||||
|
||||
boo::AdditionalPipelineInfo additionalInfo(const ExtensionSlot& ext,
|
||||
std::pair<BlendFactor, BlendFactor> blendFactors) const;
|
||||
};
|
||||
|
||||
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 {
|
||||
const char* shaderMacro = 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;
|
||||
bool forceAlphaTest = false;
|
||||
bool diffuseOnly = false;
|
||||
|
||||
constexpr 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, bool forceAlphaTest = false, bool diffuseOnly = false) noexcept
|
||||
: texCount(texCount)
|
||||
, texs(texs)
|
||||
, srcFactor(srcFactor)
|
||||
, dstFactor(dstFactor)
|
||||
, depthTest(depthTest)
|
||||
, cullMode(cullMode)
|
||||
, noDepthWrite(noDepthWrite)
|
||||
, noColorWrite(noColorWrite)
|
||||
, noAlphaWrite(noAlphaWrite)
|
||||
, noAlphaOverwrite(noAlphaOverwrite)
|
||||
, noReflection(noReflection)
|
||||
, forceAlphaTest(forceAlphaTest)
|
||||
, diffuseOnly(diffuseOnly) {}
|
||||
|
||||
mutable uint64_t m_hash = 0;
|
||||
void calculateHash() const {
|
||||
XXH64_state_t st;
|
||||
XXH64_reset(&st, 0);
|
||||
XXH64_update(&st, shaderMacro, strlen(shaderMacro));
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
inline boo::AdditionalPipelineInfo ShaderTag::additionalInfo(const ExtensionSlot& ext,
|
||||
std::pair<BlendFactor, BlendFactor> blendFactors) const {
|
||||
boo::ZTest zTest;
|
||||
switch (ext.depthTest) {
|
||||
case hecl::Backend::ZTest::Original:
|
||||
default:
|
||||
zTest = 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;
|
||||
}
|
||||
|
||||
BlendFactor srcFactor = m_alphaTest ? BlendFactor::One : blendFactors.first;
|
||||
BlendFactor dstFactor = m_alphaTest ? BlendFactor::Zero : blendFactors.second;
|
||||
return {boo::BlendFactor((ext.srcFactor == BlendFactor::Original) ? srcFactor : ext.srcFactor),
|
||||
boo::BlendFactor((ext.dstFactor == BlendFactor::Original) ? dstFactor : ext.dstFactor),
|
||||
getPrimType(),
|
||||
zTest,
|
||||
ext.noDepthWrite ? false : getDepthWrite(),
|
||||
!ext.noColorWrite,
|
||||
!ext.noAlphaWrite,
|
||||
(ext.cullMode == hecl::Backend::CullMode::Original)
|
||||
? (getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None)
|
||||
: boo::CullMode(ext.cullMode),
|
||||
!ext.noAlphaOverwrite};
|
||||
}
|
||||
|
||||
///**
|
||||
// * @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;
|
||||
// bool m_alphaTest : 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,
|
||||
// bool alphaTest)
|
||||
// : 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;
|
||||
// m_alphaTest = alphaTest;
|
||||
// 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,
|
||||
// bool alphaTest)
|
||||
// : 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;
|
||||
// m_alphaTest = alphaTest;
|
||||
// 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; }
|
||||
// bool getAlphaTest() const { return m_alphaTest; }
|
||||
// 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;
|
||||
// }
|
||||
//
|
||||
// boo::AdditionalPipelineInfo additionalInfo(const ExtensionSlot& ext,
|
||||
// std::pair<BlendFactor, BlendFactor> blendFactors) const;
|
||||
//};
|
||||
//
|
||||
//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 {
|
||||
// const char* shaderMacro = 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;
|
||||
// bool forceAlphaTest = false;
|
||||
// bool diffuseOnly = false;
|
||||
//
|
||||
// constexpr 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, bool forceAlphaTest = false, bool diffuseOnly = false) noexcept
|
||||
// : texCount(texCount)
|
||||
// , texs(texs)
|
||||
// , srcFactor(srcFactor)
|
||||
// , dstFactor(dstFactor)
|
||||
// , depthTest(depthTest)
|
||||
// , cullMode(cullMode)
|
||||
// , noDepthWrite(noDepthWrite)
|
||||
// , noColorWrite(noColorWrite)
|
||||
// , noAlphaWrite(noAlphaWrite)
|
||||
// , noAlphaOverwrite(noAlphaOverwrite)
|
||||
// , noReflection(noReflection)
|
||||
// , forceAlphaTest(forceAlphaTest)
|
||||
// , diffuseOnly(diffuseOnly) {}
|
||||
//
|
||||
// mutable uint64_t m_hash = 0;
|
||||
// void calculateHash() const {
|
||||
// XXH64_state_t st;
|
||||
// XXH64_reset(&st, 0);
|
||||
// XXH64_update(&st, shaderMacro, strlen(shaderMacro));
|
||||
// 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;
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//inline boo::AdditionalPipelineInfo ShaderTag::additionalInfo(const ExtensionSlot& ext,
|
||||
// std::pair<BlendFactor, BlendFactor> blendFactors) const {
|
||||
// boo::ZTest zTest;
|
||||
// switch (ext.depthTest) {
|
||||
// case hecl::Backend::ZTest::Original:
|
||||
// default:
|
||||
// zTest = 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;
|
||||
// }
|
||||
//
|
||||
// BlendFactor srcFactor = m_alphaTest ? BlendFactor::One : blendFactors.first;
|
||||
// BlendFactor dstFactor = m_alphaTest ? BlendFactor::Zero : blendFactors.second;
|
||||
// return {boo::BlendFactor((ext.srcFactor == BlendFactor::Original) ? srcFactor : ext.srcFactor),
|
||||
// boo::BlendFactor((ext.dstFactor == BlendFactor::Original) ? dstFactor : ext.dstFactor),
|
||||
// getPrimType(),
|
||||
// zTest,
|
||||
// ext.noDepthWrite ? false : getDepthWrite(),
|
||||
// !ext.noColorWrite,
|
||||
// !ext.noAlphaWrite,
|
||||
// (ext.cullMode == hecl::Backend::CullMode::Original)
|
||||
// ? (getBackfaceCulling() ? boo::CullMode::Backface : boo::CullMode::None)
|
||||
// : boo::CullMode(ext.cullMode),
|
||||
// !ext.noAlphaOverwrite};
|
||||
//}
|
||||
//
|
||||
} // namespace hecl::Backend
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<hecl::Backend::ShaderTag> {
|
||||
size_t operator()(const hecl::Backend::ShaderTag& val) const noexcept { return val.valSizeT(); }
|
||||
};
|
||||
} // namespace std
|
||||
//
|
||||
//namespace std {
|
||||
//template <>
|
||||
//struct hash<hecl::Backend::ShaderTag> {
|
||||
// size_t operator()(const hecl::Backend::ShaderTag& val) const noexcept { return val.valSizeT(); }
|
||||
//};
|
||||
//} // namespace std
|
||||
|
||||
@@ -98,10 +98,6 @@ public:
|
||||
|
||||
void proc();
|
||||
|
||||
void list(class Console* con, const std::vector<std::string>& args);
|
||||
void setCVar(class Console* con, const std::vector<std::string>& args);
|
||||
void getCVar(class Console* con, const std::vector<std::string>& args);
|
||||
|
||||
void setDeveloperMode(bool v, bool setDeserialized = false);
|
||||
void setCheatsEnabled(bool v, bool setDeserialized = false);
|
||||
bool restartRequired() const;
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <boo/graphicsdev/D3D.hpp>
|
||||
#include <boo/graphicsdev/GL.hpp>
|
||||
#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
|
||||
#include <boo/graphicsdev/Metal.hpp>
|
||||
#include <boo/graphicsdev/Vulkan.hpp>
|
||||
|
||||
namespace hecl {
|
||||
|
||||
namespace PlatformType {
|
||||
using PlatformEnum = boo::IGraphicsDataFactory::Platform;
|
||||
struct Null {};
|
||||
struct OpenGL {
|
||||
static constexpr PlatformEnum Enum = PlatformEnum::OpenGL;
|
||||
static constexpr char Name[] = "OpenGL";
|
||||
#if BOO_HAS_GL
|
||||
using Context = boo::GLDataFactory::Context;
|
||||
#endif
|
||||
};
|
||||
struct D3D11 {
|
||||
static constexpr PlatformEnum Enum = PlatformEnum::D3D11;
|
||||
static constexpr char Name[] = "D3D11";
|
||||
#if _WIN32
|
||||
using Context = boo::D3D11DataFactory::Context;
|
||||
#endif
|
||||
};
|
||||
struct Metal {
|
||||
static constexpr PlatformEnum Enum = PlatformEnum::Metal;
|
||||
static constexpr char Name[] = "Metal";
|
||||
#if BOO_HAS_METAL
|
||||
using Context = boo::MetalDataFactory::Context;
|
||||
#endif
|
||||
};
|
||||
struct Vulkan {
|
||||
static constexpr PlatformEnum Enum = PlatformEnum::Vulkan;
|
||||
static constexpr char Name[] = "Vulkan";
|
||||
#if BOO_HAS_VULKAN
|
||||
using Context = boo::VulkanDataFactory::Context;
|
||||
#endif
|
||||
};
|
||||
struct NX {
|
||||
static constexpr PlatformEnum Enum = PlatformEnum::NX;
|
||||
static constexpr char Name[] = "NX";
|
||||
#if BOO_HAS_NX
|
||||
using Context = boo::NXDataFactory::Context;
|
||||
#endif
|
||||
};
|
||||
} // namespace PlatformType
|
||||
|
||||
namespace PipelineStage {
|
||||
using StageEnum = boo::PipelineStage;
|
||||
struct Null {
|
||||
static constexpr StageEnum Enum = StageEnum::Null;
|
||||
static constexpr char Name[] = "Null";
|
||||
};
|
||||
struct Vertex {
|
||||
static constexpr StageEnum Enum = StageEnum::Vertex;
|
||||
static constexpr char Name[] = "Vertex";
|
||||
};
|
||||
struct Fragment {
|
||||
static constexpr StageEnum Enum = StageEnum::Fragment;
|
||||
static constexpr char Name[] = "Fragment";
|
||||
};
|
||||
struct Geometry {
|
||||
static constexpr StageEnum Enum = StageEnum::Geometry;
|
||||
static constexpr char Name[] = "Geometry";
|
||||
};
|
||||
struct Control {
|
||||
static constexpr StageEnum Enum = StageEnum::Control;
|
||||
static constexpr char Name[] = "Control";
|
||||
};
|
||||
struct Evaluation {
|
||||
static constexpr StageEnum Enum = StageEnum::Evaluation;
|
||||
static constexpr char Name[] = "Evaluation";
|
||||
};
|
||||
} // namespace PipelineStage
|
||||
|
||||
#ifdef _LIBCPP_VERSION
|
||||
using StageBinaryData = std::shared_ptr<uint8_t>;
|
||||
inline StageBinaryData MakeStageBinaryData(size_t sz) {
|
||||
return StageBinaryData(new uint8_t[sz], std::default_delete<uint8_t[]>{});
|
||||
}
|
||||
#else
|
||||
using StageBinaryData = std::shared_ptr<uint8_t[]>;
|
||||
inline StageBinaryData MakeStageBinaryData(size_t sz) { return StageBinaryData(new uint8_t[sz]); }
|
||||
#endif
|
||||
|
||||
template <typename P, typename S>
|
||||
std::pair<StageBinaryData, size_t> CompileShader(std::string_view text);
|
||||
|
||||
} // namespace hecl
|
||||
@@ -1,107 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <boo/System.hpp>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
namespace boo {
|
||||
class IWindow;
|
||||
|
||||
enum class EModifierKey;
|
||||
enum class ESpecialKey;
|
||||
|
||||
struct IGraphicsCommandQueue;
|
||||
} // namespace boo
|
||||
|
||||
namespace hecl {
|
||||
class CVarManager;
|
||||
class CVar;
|
||||
struct SConsoleCommand {
|
||||
enum class ECommandFlags { Normal = 0, Cheat = (1 << 0), Developer = (1 << 1) };
|
||||
std::string m_displayName;
|
||||
std::string m_helpString;
|
||||
std::string m_usage;
|
||||
std::function<void(class Console*, const std::vector<std::string>&)> m_func;
|
||||
ECommandFlags m_flags;
|
||||
};
|
||||
ENABLE_BITWISE_ENUM(SConsoleCommand::ECommandFlags)
|
||||
|
||||
class Console {
|
||||
friend class LogVisorAdapter;
|
||||
struct LogVisorAdapter : logvisor::ILogger {
|
||||
Console* m_con;
|
||||
LogVisorAdapter(Console* con) : logvisor::ILogger(log_typeid(LogVisorAdapter)), m_con(con) {}
|
||||
|
||||
~LogVisorAdapter() override = default;
|
||||
void report(const char* modName, logvisor::Level severity, fmt::string_view format, fmt::format_args args) override;
|
||||
void reportSource(const char* modName, logvisor::Level severity, const char* file, unsigned linenum,
|
||||
fmt::string_view format, fmt::format_args args) override;
|
||||
};
|
||||
|
||||
public:
|
||||
static Console* m_instance;
|
||||
enum class Level {
|
||||
Info, /**< Non-error informative message */
|
||||
Warning, /**< Non-error warning message */
|
||||
Error, /**< Recoverable error message */
|
||||
Fatal /**< Non-recoverable error message (Kept for compatibility with logvisor) */
|
||||
};
|
||||
|
||||
enum class State { Closed, Closing, Opened, Opening };
|
||||
|
||||
private:
|
||||
CVarManager* m_cvarMgr = nullptr;
|
||||
boo::IWindow* m_window = nullptr;
|
||||
std::unordered_map<std::string, SConsoleCommand> m_commands;
|
||||
std::vector<std::pair<std::string, Level>> m_log;
|
||||
int m_logOffset = 0;
|
||||
std::string m_commandString;
|
||||
std::vector<std::string> m_commandHistory;
|
||||
int m_cursorPosition = -1;
|
||||
int m_currentCommand = -1;
|
||||
size_t m_maxLines = 0;
|
||||
bool m_overwrite : 1;
|
||||
bool m_cursorAtEnd : 1;
|
||||
State m_state = State::Closed;
|
||||
CVar* m_conSpeed;
|
||||
CVar* m_conHeight;
|
||||
bool m_showCursor = true;
|
||||
float m_cursorTime = 0.f;
|
||||
|
||||
public:
|
||||
Console(CVarManager*);
|
||||
void registerCommand(std::string_view name, std::string_view helpText, std::string_view usage,
|
||||
std::function<void(Console*, const std::vector<std::string>&)>&& func,
|
||||
SConsoleCommand::ECommandFlags cmdFlags = SConsoleCommand::ECommandFlags::Normal);
|
||||
void unregisterCommand(std::string_view name);
|
||||
|
||||
void executeString(const std::string& strToExec);
|
||||
|
||||
void help(Console* con, const std::vector<std::string>& args);
|
||||
void listCommands(Console* con, const std::vector<std::string>& args);
|
||||
bool commandExists(std::string_view cmd) const;
|
||||
|
||||
void vreport(Level level, fmt::string_view format, fmt::format_args args);
|
||||
template <typename S, typename... Args, typename Char = fmt::char_t<S>>
|
||||
void report(Level level, const S& format, Args&&... args) {
|
||||
vreport(level, fmt::to_string_view<Char>(format),
|
||||
fmt::basic_format_args<fmt::buffer_context<Char>>(
|
||||
fmt::make_args_checked<Args...>(format, args...)));
|
||||
}
|
||||
|
||||
void init(boo::IWindow* ctx);
|
||||
void proc();
|
||||
void draw(boo::IGraphicsCommandQueue* gfxQ);
|
||||
void handleCharCode(unsigned long chr, boo::EModifierKey mod, bool repeat);
|
||||
void handleSpecialKeyDown(boo::ESpecialKey sp, boo::EModifierKey mod, bool repeat);
|
||||
void handleSpecialKeyUp(boo::ESpecialKey sp, boo::EModifierKey mod);
|
||||
void dumpLog();
|
||||
static Console* instance();
|
||||
static void RegisterLogger(Console* con);
|
||||
bool isOpen() const { return m_state == State::Opened; }
|
||||
};
|
||||
} // namespace hecl
|
||||
@@ -1,506 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "hecl/hecl.hpp"
|
||||
#include "hecl/PipelineBase.hpp"
|
||||
|
||||
#include <boo/BooObject.hpp>
|
||||
#include <boo/graphicsdev/IGraphicsDataFactory.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; }
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
template <typename... Args>
|
||||
struct pack {};
|
||||
struct null_t {};
|
||||
template <typename P>
|
||||
struct ShaderDB {};
|
||||
|
||||
#define STAGE_COLLECTION_SPECIALIZATIONS(T, P) StageCollection<T<P, PipelineStage::Null>>,
|
||||
#define PIPELINE_RUNTIME_SPECIALIZATIONS(P) \
|
||||
STAGE_COLLECTION_SPECIALIZATIONS(StageSourceText, P) STAGE_COLLECTION_SPECIALIZATIONS(StageBinary, P) \
|
||||
STAGE_COLLECTION_SPECIALIZATIONS(StageRuntimeObject, P) FinalPipeline<P>,
|
||||
#define PIPELINE_OFFLINE_SPECIALIZATIONS(P) STAGE_COLLECTION_SPECIALIZATIONS(StageSourceText, P)
|
||||
#define STAGE_RUNTIME_SPECIALIZATIONS(P, S) \
|
||||
StageBinary<P, S>, HECL_APPLICATION_STAGE_REPS(P, S) StageRuntimeObject<P, S>,
|
||||
#define STAGE_OFFLINE_SPECIALIZATIONS(P, S) HECL_APPLICATION_STAGE_REPS(P, S)
|
||||
|
||||
#define SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, S) \
|
||||
template <> \
|
||||
struct ShaderDB<P>::StageDB<S> { \
|
||||
using StageTypes = pack<STAGE_RUNTIME_SPECIALIZATIONS(P, S) null_t>; \
|
||||
};
|
||||
#define SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, S) \
|
||||
template <> \
|
||||
struct ShaderDB<P>::StageDB<S> { \
|
||||
using StageTypes = pack<null_t>; \
|
||||
};
|
||||
#define SPECIALIZE_OFFLINE_STAGE(P, S) \
|
||||
template <> \
|
||||
struct ShaderDB<P>::StageDB<S> { \
|
||||
using StageTypes = pack<STAGE_OFFLINE_SPECIALIZATIONS(P, S) null_t>; \
|
||||
};
|
||||
#define SPECIALIZE_RUNTIME_AVAILABLE_PLATFORM(P) \
|
||||
template <> \
|
||||
struct ShaderDB<P> { \
|
||||
using PipelineTypes = pack<PIPELINE_RUNTIME_SPECIALIZATIONS(P) null_t>; \
|
||||
template <typename S> \
|
||||
struct StageDB {}; \
|
||||
}; \
|
||||
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Vertex) \
|
||||
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Fragment) \
|
||||
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Geometry) \
|
||||
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Control) \
|
||||
SPECIALIZE_RUNTIME_AVAILABLE_STAGE(P, hecl::PipelineStage::Evaluation)
|
||||
#define SPECIALIZE_RUNTIME_UNAVAILABLE_PLATFORM(P) \
|
||||
template <> \
|
||||
struct ShaderDB<P> { \
|
||||
using PipelineTypes = pack<null_t>; \
|
||||
template <typename S> \
|
||||
struct StageDB {}; \
|
||||
}; \
|
||||
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Vertex) \
|
||||
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Fragment) \
|
||||
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Geometry) \
|
||||
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Control) \
|
||||
SPECIALIZE_RUNTIME_UNAVAILABLE_STAGE(P, hecl::PipelineStage::Evaluation)
|
||||
#define SPECIALIZE_OFFLINE_PLATFORM(P) \
|
||||
template <> \
|
||||
struct ShaderDB<P> { \
|
||||
using PipelineTypes = pack<PIPELINE_OFFLINE_SPECIALIZATIONS(P) null_t>; \
|
||||
template <typename S> \
|
||||
struct StageDB {}; \
|
||||
}; \
|
||||
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Vertex) \
|
||||
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Fragment) \
|
||||
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Geometry) \
|
||||
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Control) \
|
||||
SPECIALIZE_OFFLINE_STAGE(P, hecl::PipelineStage::Evaluation)
|
||||
|
||||
#if HECL_RUNTIME
|
||||
#if BOO_HAS_GL
|
||||
SPECIALIZE_RUNTIME_AVAILABLE_PLATFORM(hecl::PlatformType::OpenGL)
|
||||
#else
|
||||
SPECIALIZE_RUNTIME_UNAVAILABLE_PLATFORM(hecl::PlatformType::OpenGL)
|
||||
#endif
|
||||
#if BOO_HAS_VULKAN
|
||||
SPECIALIZE_RUNTIME_AVAILABLE_PLATFORM(hecl::PlatformType::Vulkan)
|
||||
#else
|
||||
SPECIALIZE_RUNTIME_UNAVAILABLE_PLATFORM(hecl::PlatformType::Vulkan)
|
||||
#endif
|
||||
#if _WIN32
|
||||
SPECIALIZE_RUNTIME_AVAILABLE_PLATFORM(hecl::PlatformType::D3D11)
|
||||
#else
|
||||
SPECIALIZE_RUNTIME_UNAVAILABLE_PLATFORM(hecl::PlatformType::D3D11)
|
||||
#endif
|
||||
#if BOO_HAS_METAL
|
||||
SPECIALIZE_RUNTIME_AVAILABLE_PLATFORM(hecl::PlatformType::Metal)
|
||||
#else
|
||||
SPECIALIZE_RUNTIME_UNAVAILABLE_PLATFORM(hecl::PlatformType::Metal)
|
||||
#endif
|
||||
#if BOO_HAS_NX
|
||||
SPECIALIZE_RUNTIME_AVAILABLE_PLATFORM(hecl::PlatformType::NX)
|
||||
#else
|
||||
SPECIALIZE_RUNTIME_UNAVAILABLE_PLATFORM(hecl::PlatformType::NX)
|
||||
#endif
|
||||
#else
|
||||
SPECIALIZE_OFFLINE_PLATFORM(hecl::PlatformType::OpenGL)
|
||||
SPECIALIZE_OFFLINE_PLATFORM(hecl::PlatformType::Vulkan)
|
||||
SPECIALIZE_OFFLINE_PLATFORM(hecl::PlatformType::D3D11)
|
||||
SPECIALIZE_OFFLINE_PLATFORM(hecl::PlatformType::Metal)
|
||||
SPECIALIZE_OFFLINE_PLATFORM(hecl::PlatformType::NX)
|
||||
#endif
|
||||
|
||||
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 ShaderDB<P>::template StageDB<S>::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 constexpr (FromTp::HasStageHash) {
|
||||
uint64_t hash = in.template StageHash<S>();
|
||||
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 ShaderDB<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 char* path);
|
||||
#endif
|
||||
|
||||
template <class FromTp>
|
||||
PipelineTargetTp convert(FactoryCtx& ctx, const FromTp& in) {
|
||||
if constexpr (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:
|
||||
setenv("HECL_NO_METAL_COMPILER", "1", 1);
|
||||
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
|
||||
|
||||
} // namespace hecl
|
||||
@@ -1,222 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "hecl/Compilers.hpp"
|
||||
|
||||
#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
|
||||
#include <xxhash/xxhash.h>
|
||||
|
||||
#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_text(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> {
|
||||
StageBinaryData 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(StageBinaryData 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<StageBinaryData, 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 <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);
|
||||
}
|
||||
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::conjunction_v<std::is_base_of<TessellationShader, I>,
|
||||
std::negation<std::is_same<P, PlatformType::Metal>>>>* = 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();
|
||||
}
|
||||
template <typename I>
|
||||
StageCollection(PipelineConverter<P>& conv, FactoryCtx& ctx, const I& in,
|
||||
typename std::enable_if_t<std::conjunction_v<std::is_base_of<TessellationShader, I>,
|
||||
std::is_same<P, PlatformType::Metal>>>* = 0) {
|
||||
if (in.HasTessellation) {
|
||||
m_control = conv.getControlConverter().convert(ctx, in);
|
||||
m_evaluation = conv.getEvaluationConverter().convert(ctx, in);
|
||||
} else {
|
||||
m_vertex = conv.getVertexConverter().convert(ctx, in);
|
||||
}
|
||||
m_fragment = conv.getFragmentConverter().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) {}
|
||||
};
|
||||
|
||||
} // namespace hecl
|
||||
|
||||
#ifndef _WIN32
|
||||
#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;
|
||||
#else
|
||||
#define _STAGEOBJECT_PROTOTYPE_DECLARATIONS(T, P)
|
||||
#endif
|
||||
|
||||
#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)
|
||||
@@ -1,13 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <boo/BooObject.hpp>
|
||||
#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
|
||||
//#include <boo/BooObject.hpp>
|
||||
//#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
|
||||
|
||||
namespace hecl {
|
||||
struct HMDLMeta;
|
||||
|
||||
namespace Runtime {
|
||||
|
||||
@@ -28,27 +27,27 @@ public:
|
||||
std::string_view getStoreRoot() const { return m_storeRoot; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Integrated reader/constructor/container for HMDL data
|
||||
*/
|
||||
struct HMDLData {
|
||||
boo::ObjToken<boo::IGraphicsBufferS> m_vbo;
|
||||
boo::ObjToken<boo::IGraphicsBufferS> m_ibo;
|
||||
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);
|
||||
|
||||
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_vbo.get(), nullptr, m_ibo.get(), ubufCount, ubufs, ubufStages, nullptr,
|
||||
nullptr, texCount, texs, nullptr, nullptr);
|
||||
}
|
||||
};
|
||||
///**
|
||||
// * @brief Integrated reader/constructor/container for HMDL data
|
||||
// */
|
||||
//struct HMDLData {
|
||||
// boo::ObjToken<boo::IGraphicsBufferS> m_vbo;
|
||||
// boo::ObjToken<boo::IGraphicsBufferS> m_ibo;
|
||||
// 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);
|
||||
//
|
||||
// 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_vbo.get(), nullptr, m_ibo.get(), ubufCount, ubufs, ubufStages, nullptr,
|
||||
// nullptr, texCount, texs, nullptr, nullptr);
|
||||
// }
|
||||
//};
|
||||
|
||||
} // namespace Runtime
|
||||
} // namespace hecl
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "hecl/BitVector.hpp"
|
||||
|
||||
#include <boo/BooObject.hpp>
|
||||
#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
|
||||
|
||||
namespace hecl {
|
||||
|
||||
#define HECL_UBUFPOOL_ALLOCATION_BLOCK 262144
|
||||
|
||||
/** This class provides a uniform structure for packing instanced uniform-buffer
|
||||
* data with consistent stride into a vector of 256K 'Buckets'.
|
||||
*
|
||||
* This results in a space-efficient way of managing GPU data of things like UI
|
||||
* widgets. These can potentially have numerous binding instances, so this avoids
|
||||
* allocating a full GPU buffer object for each. */
|
||||
template <typename UniformStruct>
|
||||
class UniformBufferPool {
|
||||
public:
|
||||
/* Resolve div_t type using ssize_t as basis */
|
||||
#if _WIN32
|
||||
using IndexTp = SSIZE_T;
|
||||
#else
|
||||
using IndexTp = ssize_t;
|
||||
#endif
|
||||
private:
|
||||
struct InvalidTp {};
|
||||
using DivTp = std::conditional_t<
|
||||
std::is_same<IndexTp, long long>::value, std::lldiv_t,
|
||||
std::conditional_t<std::is_same<IndexTp, long>::value, std::ldiv_t,
|
||||
std::conditional_t<std::is_same<IndexTp, int>::value, std::div_t, InvalidTp>>>;
|
||||
static_assert(!std::is_same<DivTp, InvalidTp>::value, "unsupported IndexTp for DivTp resolution");
|
||||
|
||||
/** Size of single element, rounded up to 256-multiple */
|
||||
static constexpr IndexTp m_stride = ROUND_UP_256(sizeof(UniformStruct));
|
||||
static_assert(m_stride <= HECL_UBUFPOOL_ALLOCATION_BLOCK, "Stride too large for uniform pool");
|
||||
|
||||
/** Number of rounded elements per 256K bucket */
|
||||
static constexpr IndexTp m_countPerBucket = HECL_UBUFPOOL_ALLOCATION_BLOCK / m_stride;
|
||||
|
||||
/** Buffer size per bucket (ideally 256K) */
|
||||
static constexpr IndexTp m_sizePerBucket = m_stride * m_countPerBucket;
|
||||
|
||||
/** BitVector indicating free allocation blocks */
|
||||
hecl::llvm::BitVector m_freeBlocks;
|
||||
|
||||
/** Efficient way to get bucket and block simultaneously */
|
||||
DivTp getBucketDiv(IndexTp idx) const { return std::div(idx, m_countPerBucket); }
|
||||
|
||||
/** Factory pointer for building additional buffers */
|
||||
boo::IGraphicsDataFactory* m_factory = nullptr;
|
||||
|
||||
/** Private bucket info */
|
||||
struct Bucket {
|
||||
boo::ObjToken<boo::IGraphicsBufferD> buffer;
|
||||
uint8_t* cpuBuffer = nullptr;
|
||||
std::atomic_size_t useCount = {};
|
||||
bool dirty = false;
|
||||
Bucket() = default;
|
||||
Bucket(const Bucket& other) = delete;
|
||||
Bucket& operator=(const Bucket& other) = delete;
|
||||
Bucket(Bucket&& other) = default;
|
||||
Bucket& operator=(Bucket&& other) = default;
|
||||
|
||||
void updateBuffer() {
|
||||
if (useCount == 0) {
|
||||
destroy();
|
||||
return;
|
||||
}
|
||||
if (dirty && cpuBuffer) {
|
||||
buffer->unmap();
|
||||
cpuBuffer = nullptr;
|
||||
}
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
void increment(UniformBufferPool& pool) {
|
||||
if (useCount.fetch_add(1) == 0 && !buffer)
|
||||
buffer = pool.m_factory->newPoolBuffer(boo::BufferUse::Uniform, pool.m_stride, pool.m_countPerBucket BooTrace);
|
||||
}
|
||||
|
||||
void decrement(UniformBufferPool& pool) {
|
||||
--useCount;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (cpuBuffer) {
|
||||
buffer->unmap();
|
||||
cpuBuffer = nullptr;
|
||||
}
|
||||
buffer.reset();
|
||||
}
|
||||
};
|
||||
std::vector<std::unique_ptr<Bucket>> m_buckets;
|
||||
|
||||
public:
|
||||
/** User block-owning token */
|
||||
class Token {
|
||||
friend class UniformBufferPool;
|
||||
UniformBufferPool* m_pool = nullptr;
|
||||
IndexTp m_index = -1;
|
||||
DivTp m_div;
|
||||
Token(UniformBufferPool* pool) : m_pool(pool) {
|
||||
auto& freeSpaces = pool->m_freeBlocks;
|
||||
int idx = freeSpaces.find_first();
|
||||
if (idx == -1) {
|
||||
pool->m_buckets.push_back(std::make_unique<Bucket>());
|
||||
m_index = freeSpaces.size();
|
||||
freeSpaces.resize(freeSpaces.size() + pool->m_countPerBucket, true);
|
||||
} else {
|
||||
m_index = idx;
|
||||
}
|
||||
freeSpaces.reset(m_index);
|
||||
m_div = pool->getBucketDiv(m_index);
|
||||
|
||||
Bucket& bucket = *m_pool->m_buckets[m_div.quot];
|
||||
bucket.increment(*m_pool);
|
||||
}
|
||||
|
||||
public:
|
||||
Token() = default;
|
||||
Token(const Token& other) = delete;
|
||||
Token& operator=(const Token& other) = delete;
|
||||
Token& operator=(Token&& other) noexcept {
|
||||
m_pool = other.m_pool;
|
||||
m_index = other.m_index;
|
||||
m_div = other.m_div;
|
||||
other.m_index = -1;
|
||||
return *this;
|
||||
}
|
||||
Token(Token&& other) noexcept : m_pool(other.m_pool), m_index(other.m_index), m_div(other.m_div) { other.m_index = -1; }
|
||||
|
||||
~Token() {
|
||||
if (m_index != -1) {
|
||||
m_pool->m_freeBlocks.set(m_index);
|
||||
Bucket& bucket = *m_pool->m_buckets[m_div.quot];
|
||||
bucket.decrement(*m_pool);
|
||||
}
|
||||
}
|
||||
|
||||
UniformStruct& access() {
|
||||
Bucket& bucket = *m_pool->m_buckets[m_div.quot];
|
||||
if (!bucket.cpuBuffer)
|
||||
bucket.cpuBuffer = reinterpret_cast<uint8_t*>(bucket.buffer->map(m_sizePerBucket));
|
||||
bucket.dirty = true;
|
||||
return reinterpret_cast<UniformStruct&>(bucket.cpuBuffer[m_div.rem * m_pool->m_stride]);
|
||||
}
|
||||
|
||||
std::pair<boo::ObjToken<boo::IGraphicsBufferD>, IndexTp> getBufferInfo() const {
|
||||
Bucket& bucket = *m_pool->m_buckets[m_div.quot];
|
||||
return {bucket.buffer, m_div.rem * m_pool->m_stride};
|
||||
}
|
||||
|
||||
explicit operator bool() const { return m_pool != nullptr && m_index != -1; }
|
||||
};
|
||||
|
||||
UniformBufferPool() = default;
|
||||
UniformBufferPool(const UniformBufferPool& other) = delete;
|
||||
UniformBufferPool& operator=(const UniformBufferPool& other) = delete;
|
||||
|
||||
/** Load dirty buffer data into GPU */
|
||||
void updateBuffers() {
|
||||
for (auto& bucket : m_buckets)
|
||||
bucket->updateBuffer();
|
||||
}
|
||||
|
||||
/** Allocate free block into client-owned Token */
|
||||
Token allocateBlock(boo::IGraphicsDataFactory* factory) {
|
||||
m_factory = factory;
|
||||
return Token(this);
|
||||
}
|
||||
|
||||
void doDestroy() {
|
||||
for (auto& bucket : m_buckets)
|
||||
bucket->buffer.reset();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace hecl
|
||||
@@ -1,195 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "hecl/BitVector.hpp"
|
||||
|
||||
#include <boo/BooObject.hpp>
|
||||
#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
|
||||
|
||||
namespace hecl {
|
||||
|
||||
#define HECL_VBUFPOOL_ALLOCATION_BLOCK 524288
|
||||
|
||||
/** This class provides a uniform structure for packing instanced vertex-buffer
|
||||
* data with consistent stride into a vector of 512K 'Buckets'.
|
||||
*
|
||||
* This results in a space-efficient way of managing GPU data of things like UI
|
||||
* widgets. These can potentially have numerous binding instances, so this avoids
|
||||
* allocating a full GPU buffer object for each. */
|
||||
template <typename VertStruct>
|
||||
class VertexBufferPool {
|
||||
public:
|
||||
/* Resolve div_t type using ssize_t as basis */
|
||||
#if _WIN32
|
||||
using IndexTp = SSIZE_T;
|
||||
#else
|
||||
using IndexTp = ssize_t;
|
||||
#endif
|
||||
private:
|
||||
struct InvalidTp {};
|
||||
using DivTp = std::conditional_t<
|
||||
std::is_same<IndexTp, long long>::value, std::lldiv_t,
|
||||
std::conditional_t<std::is_same<IndexTp, long>::value, std::ldiv_t,
|
||||
std::conditional_t<std::is_same<IndexTp, int>::value, std::div_t, InvalidTp>>>;
|
||||
static_assert(!std::is_same<DivTp, InvalidTp>::value, "unsupported IndexTp for DivTp resolution");
|
||||
|
||||
/** Size of single element */
|
||||
static constexpr IndexTp m_stride = sizeof(VertStruct);
|
||||
static_assert(m_stride <= HECL_VBUFPOOL_ALLOCATION_BLOCK, "Stride too large for vertex pool");
|
||||
|
||||
/** Number of elements per 256K bucket */
|
||||
static constexpr IndexTp m_countPerBucket = HECL_VBUFPOOL_ALLOCATION_BLOCK / m_stride;
|
||||
|
||||
/** Buffer size per bucket (ideally 256K) */
|
||||
static constexpr IndexTp m_sizePerBucket = m_stride * m_countPerBucket;
|
||||
|
||||
/** BitVector indicating free allocation elements */
|
||||
hecl::llvm::BitVector m_freeElements;
|
||||
|
||||
/** Efficient way to get bucket and element simultaneously */
|
||||
DivTp getBucketDiv(IndexTp idx) const { return std::div(idx, m_countPerBucket); }
|
||||
|
||||
/** Factory pointer for building additional buffers */
|
||||
boo::IGraphicsDataFactory* m_factory = nullptr;
|
||||
|
||||
/** Private bucket info */
|
||||
struct Bucket {
|
||||
boo::ObjToken<boo::IGraphicsBufferD> buffer;
|
||||
uint8_t* cpuBuffer = nullptr;
|
||||
std::atomic_size_t useCount = {};
|
||||
bool dirty = false;
|
||||
Bucket() = default;
|
||||
Bucket(const Bucket& other) = delete;
|
||||
Bucket& operator=(const Bucket& other) = delete;
|
||||
Bucket(Bucket&& other) = delete;
|
||||
Bucket& operator=(Bucket&& other) = delete;
|
||||
|
||||
void updateBuffer() {
|
||||
if (useCount == 0) {
|
||||
destroy();
|
||||
return;
|
||||
}
|
||||
if (dirty && cpuBuffer) {
|
||||
buffer->unmap();
|
||||
cpuBuffer = nullptr;
|
||||
}
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
void increment(VertexBufferPool& pool) {
|
||||
if (useCount.fetch_add(1) == 0 && !buffer)
|
||||
buffer = pool.m_factory->newPoolBuffer(boo::BufferUse::Vertex, pool.m_stride, pool.m_countPerBucket BooTrace);
|
||||
}
|
||||
|
||||
void decrement(VertexBufferPool& pool) {
|
||||
--useCount;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (cpuBuffer) {
|
||||
buffer->unmap();
|
||||
cpuBuffer = nullptr;
|
||||
}
|
||||
buffer.reset();
|
||||
}
|
||||
};
|
||||
std::vector<std::unique_ptr<Bucket>> m_buckets;
|
||||
|
||||
public:
|
||||
/** User element-owning token */
|
||||
class Token {
|
||||
friend class VertexBufferPool;
|
||||
VertexBufferPool* m_pool = nullptr;
|
||||
IndexTp m_index = -1;
|
||||
IndexTp m_count = 0;
|
||||
DivTp m_div;
|
||||
Token(VertexBufferPool* pool, IndexTp count) : m_pool(pool), m_count(count) {
|
||||
assert(count <= pool->m_countPerBucket && "unable to fit in bucket");
|
||||
auto& freeSpaces = pool->m_freeElements;
|
||||
int idx = freeSpaces.find_first_contiguous(count, pool->m_countPerBucket);
|
||||
if (idx == -1) {
|
||||
pool->m_buckets.push_back(std::make_unique<Bucket>());
|
||||
m_index = freeSpaces.size();
|
||||
freeSpaces.resize(freeSpaces.size() + pool->m_countPerBucket, true);
|
||||
} else {
|
||||
m_index = idx;
|
||||
}
|
||||
freeSpaces.reset(m_index, m_index + count);
|
||||
m_div = pool->getBucketDiv(m_index);
|
||||
|
||||
Bucket& bucket = *m_pool->m_buckets[m_div.quot];
|
||||
bucket.increment(*pool);
|
||||
}
|
||||
|
||||
public:
|
||||
Token() = default;
|
||||
Token(const Token& other) = delete;
|
||||
Token& operator=(const Token& other) = delete;
|
||||
Token& operator=(Token&& other) noexcept {
|
||||
m_pool = other.m_pool;
|
||||
m_index = other.m_index;
|
||||
m_count = other.m_count;
|
||||
m_div = other.m_div;
|
||||
other.m_index = -1;
|
||||
return *this;
|
||||
}
|
||||
Token(Token&& other) noexcept : m_pool(other.m_pool), m_index(other.m_index), m_count(other.m_count), m_div(other.m_div) {
|
||||
other.m_index = -1;
|
||||
}
|
||||
|
||||
~Token() {
|
||||
if (m_index != -1) {
|
||||
m_pool->m_freeElements.set(m_index, m_index + m_count);
|
||||
Bucket& bucket = *m_pool->m_buckets[m_div.quot];
|
||||
bucket.decrement(*m_pool);
|
||||
}
|
||||
}
|
||||
|
||||
VertStruct* access() {
|
||||
Bucket& bucket = *m_pool->m_buckets[m_div.quot];
|
||||
if (!bucket.cpuBuffer)
|
||||
bucket.cpuBuffer = reinterpret_cast<uint8_t*>(bucket.buffer->map(m_sizePerBucket));
|
||||
bucket.dirty = true;
|
||||
return reinterpret_cast<VertStruct*>(&bucket.cpuBuffer[m_div.rem * m_pool->m_stride]);
|
||||
}
|
||||
|
||||
std::pair<boo::ObjToken<boo::IGraphicsBufferD>, IndexTp> getBufferInfo() const {
|
||||
Bucket& bucket = *m_pool->m_buckets[m_div.quot];
|
||||
return {bucket.buffer, m_div.rem};
|
||||
}
|
||||
|
||||
explicit operator bool() const { return m_pool != nullptr && m_index != -1; }
|
||||
};
|
||||
|
||||
VertexBufferPool() = default;
|
||||
VertexBufferPool(const VertexBufferPool& other) = delete;
|
||||
VertexBufferPool& operator=(const VertexBufferPool& other) = delete;
|
||||
|
||||
/** Load dirty buffer data into GPU */
|
||||
void updateBuffers() {
|
||||
for (auto& bucket : m_buckets)
|
||||
bucket->updateBuffer();
|
||||
}
|
||||
|
||||
/** Allocate free block into client-owned Token */
|
||||
Token allocateBlock(boo::IGraphicsDataFactory* factory, IndexTp count) {
|
||||
m_factory = factory;
|
||||
return Token(this, count);
|
||||
}
|
||||
|
||||
void doDestroy() {
|
||||
for (auto& bucket : m_buckets)
|
||||
bucket->buffer.reset();
|
||||
}
|
||||
|
||||
static constexpr IndexTp bucketCapacity() { return m_countPerBucket; }
|
||||
};
|
||||
|
||||
} // namespace hecl
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <cstdlib>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <unistd.h>
|
||||
#if __linux__ || __APPLE__
|
||||
extern "C" int rep_closefrom(int lower);
|
||||
#define closefrom rep_closefrom
|
||||
@@ -45,7 +45,6 @@ extern "C" int rep_closefrom(int lower);
|
||||
#include "athena/Global.hpp"
|
||||
#include "logvisor/logvisor.hpp"
|
||||
#include "xxhash/xxhash.h"
|
||||
#include "FourCC.hpp"
|
||||
|
||||
|
||||
#if defined(__has_feature)
|
||||
|
||||
@@ -20,7 +20,7 @@ endif()
|
||||
set(HECL_HEADERS
|
||||
../include/hecl/CVar.hpp
|
||||
../include/hecl/CVarManager.hpp
|
||||
../include/hecl/Console.hpp
|
||||
# ../include/hecl/Console.hpp
|
||||
../include/hecl/CVarCommons.hpp
|
||||
../include/hecl/hecl.hpp
|
||||
../include/hecl/MultiProgressPrinter.hpp
|
||||
@@ -37,11 +37,9 @@ set(HECL_HEADERS
|
||||
../include/hecl/ClientProcess.hpp
|
||||
../include/hecl/BitVector.hpp
|
||||
../include/hecl/MathExtras.hpp
|
||||
../include/hecl/UniformBufferPool.hpp
|
||||
../include/hecl/VertexBufferPool.hpp
|
||||
../include/hecl/PipelineBase.hpp
|
||||
../include/hecl/Pipeline.hpp
|
||||
../include/hecl/Compilers.hpp)
|
||||
# ../include/hecl/UniformBufferPool.hpp
|
||||
# ../include/hecl/VertexBufferPool.hpp
|
||||
)
|
||||
set(COMMON_SOURCES
|
||||
hecl.cpp
|
||||
MultiProgressPrinter.cpp
|
||||
@@ -51,11 +49,10 @@ set(COMMON_SOURCES
|
||||
CVar.cpp
|
||||
CVarCommons.cpp
|
||||
CVarManager.cpp
|
||||
Console.cpp
|
||||
# Console.cpp
|
||||
ClientProcess.cpp
|
||||
SteamFinder.cpp
|
||||
WideStringConvert.cpp
|
||||
Compilers.cpp)
|
||||
WideStringConvert.cpp)
|
||||
|
||||
if(UNIX)
|
||||
list(APPEND PLAT_SRCS closefrom.c)
|
||||
@@ -68,7 +65,7 @@ add_library(hecl-full
|
||||
${COMMON_SOURCES}
|
||||
${HECL_HEADERS}
|
||||
${PLAT_SRCS}
|
||||
Pipeline.cpp)
|
||||
${FIND_BLENDER_SOURCES})
|
||||
target_include_directories(hecl-full PUBLIC ../include)
|
||||
target_link_libraries(hecl-full PUBLIC ${HECL_APPLICATION_REPS_TARGETS_LIST}
|
||||
hecl-blender-addon boo athena-core logvisor)
|
||||
@@ -83,7 +80,7 @@ add_library(hecl-light
|
||||
${PLAT_SRCS}
|
||||
${FIND_BLENDER_SOURCES})
|
||||
target_include_directories(hecl-light PUBLIC ../include)
|
||||
target_link_libraries(hecl-light PUBLIC ${HECL_APPLICATION_REPS_TARGETS_LIST} boo athena-core logvisor)
|
||||
target_link_libraries(hecl-light PUBLIC ${HECL_APPLICATION_REPS_TARGETS_LIST} boo athena-core logvisor aurora)
|
||||
if (WIN32)
|
||||
# For FindBlender
|
||||
target_link_libraries(hecl-light PUBLIC Version)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
|
||||
#include "hecl/Console.hpp"
|
||||
#include "hecl/hecl.hpp"
|
||||
#include "hecl/Runtime.hpp"
|
||||
|
||||
@@ -207,62 +206,6 @@ void CVarManager::serialize() {
|
||||
|
||||
CVarManager* CVarManager::instance() { return m_instance; }
|
||||
|
||||
void CVarManager::list(Console* con, const std::vector<std::string>& /*args*/) {
|
||||
for (const auto& cvar : m_cvars) {
|
||||
if (!cvar.second->isHidden())
|
||||
con->report(Console::Level::Info, FMT_STRING("{}: {}"), cvar.second->name(), cvar.second->help());
|
||||
}
|
||||
}
|
||||
|
||||
void CVarManager::setCVar(Console* con, const std::vector<std::string>& args) {
|
||||
if (args.size() < 2) {
|
||||
con->report(Console::Level::Info, FMT_STRING("Usage setCvar <cvar> <value>"));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string cvName = args[0];
|
||||
athena::utility::tolower(cvName);
|
||||
const auto iter = m_cvars.find(cvName);
|
||||
if (iter == m_cvars.end()) {
|
||||
con->report(Console::Level::Error, FMT_STRING("CVar '{}' does not exist"), args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& cv = iter->second;
|
||||
std::string oldVal = cv->value();
|
||||
std::string value = args[1];
|
||||
auto it = args.begin() + 2;
|
||||
for (; it != args.end(); ++it)
|
||||
value += " " + *it;
|
||||
|
||||
/* Check to make sure we're not redundantly assigning the value */
|
||||
if (cv->value() == value)
|
||||
return;
|
||||
|
||||
if (!cv->fromLiteralToType(value))
|
||||
con->report(Console::Level::Warning, FMT_STRING("Unable to set cvar '{}' to value '{}'"), cv->name(), value);
|
||||
else
|
||||
con->report(Console::Level::Info, FMT_STRING("Set '{}' from '{}' to '{}'"), cv->name(), oldVal, value);
|
||||
}
|
||||
|
||||
void CVarManager::getCVar(Console* con, const std::vector<std::string>& args) {
|
||||
if (args.empty()) {
|
||||
con->report(Console::Level::Info, FMT_STRING("Usage getCVar <cvar>"));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string cvName = args[0];
|
||||
athena::utility::tolower(cvName);
|
||||
const auto iter = m_cvars.find(cvName);
|
||||
if (iter == m_cvars.end()) {
|
||||
con->report(Console::Level::Error, FMT_STRING("CVar '{}' does not exist"), args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& cv = iter->second;
|
||||
con->report(Console::Level::Info, FMT_STRING("'{}' = '{}'"), cv->name(), cv->value());
|
||||
}
|
||||
|
||||
void CVarManager::setDeveloperMode(bool v, bool setDeserialized) {
|
||||
com_developer->unlock();
|
||||
com_developer->fromBoolean(v);
|
||||
|
||||
@@ -1,292 +0,0 @@
|
||||
#include "hecl/Compilers.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#include <boo/graphicsdev/GLSLMacros.hpp>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
#include <glslang/Public/ShaderLang.h>
|
||||
#include <StandAlone/ResourceLimits.h>
|
||||
#include <SPIRV/GlslangToSpv.h>
|
||||
#include <SPIRV/disassemble.h>
|
||||
|
||||
#if _WIN32
|
||||
#include <d3dcompiler.h>
|
||||
extern pD3DCompile D3DCompilePROC;
|
||||
#endif
|
||||
|
||||
#if __APPLE__
|
||||
#include <unistd.h>
|
||||
#include <memory>
|
||||
#endif
|
||||
|
||||
namespace hecl {
|
||||
logvisor::Module Log("hecl::Compilers");
|
||||
|
||||
template <typename P>
|
||||
struct ShaderCompiler {};
|
||||
|
||||
template <>
|
||||
struct ShaderCompiler<PlatformType::OpenGL> {
|
||||
template <typename S>
|
||||
static std::pair<StageBinaryData, size_t> Compile(std::string_view text) {
|
||||
std::string str = "#version 330\n";
|
||||
str += BOO_GLSL_BINDING_HEAD;
|
||||
str += text;
|
||||
std::pair<StageBinaryData, size_t> ret(MakeStageBinaryData(str.size() + 1), str.size() + 1);
|
||||
memcpy(ret.first.get(), str.data(), ret.second);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ShaderCompiler<PlatformType::Vulkan> {
|
||||
static constexpr EShLanguage ShaderTypes[] = {EShLangVertex, /* Invalid */
|
||||
EShLangVertex, EShLangFragment, EShLangGeometry,
|
||||
EShLangTessControl, EShLangTessEvaluation};
|
||||
|
||||
template <typename S>
|
||||
static std::pair<StageBinaryData, 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)) {
|
||||
fmt::print(FMT_STRING("{}\n"), text);
|
||||
Log.report(logvisor::Fatal, FMT_STRING("unable to compile shader\n{}"), shader.getInfoLog());
|
||||
return {};
|
||||
}
|
||||
|
||||
glslang::TProgram prog;
|
||||
prog.addShader(&shader);
|
||||
if (!prog.link(messages)) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("unable to link shader program\n{}"), prog.getInfoLog());
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<unsigned int> out;
|
||||
glslang::GlslangToSpv(*prog.getIntermediate(lang), out);
|
||||
std::pair<StageBinaryData, size_t> ret(MakeStageBinaryData(out.size() * 4), out.size() * 4);
|
||||
memcpy(ret.first.get(), out.data(), ret.second);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
#if _WIN32
|
||||
static const char* D3DShaderTypes[] = {nullptr, "vs_5_0", "ps_5_0", "gs_5_0", "hs_5_0", "ds_5_0"};
|
||||
template <>
|
||||
struct ShaderCompiler<PlatformType::D3D11> {
|
||||
#if _DEBUG && 0
|
||||
#define BOO_D3DCOMPILE_FLAG D3DCOMPILE_DEBUG | D3DCOMPILE_OPTIMIZATION_LEVEL0
|
||||
#else
|
||||
#define BOO_D3DCOMPILE_FLAG D3DCOMPILE_OPTIMIZATION_LEVEL3
|
||||
#endif
|
||||
template <typename S>
|
||||
static std::pair<StageBinaryData, size_t> Compile(std::string_view text) {
|
||||
ComPtr<ID3DBlob> errBlob;
|
||||
ComPtr<ID3DBlob> blobOut;
|
||||
if (FAILED(D3DCompilePROC(text.data(), text.size(), "Boo HLSL Source", nullptr, nullptr, "main",
|
||||
D3DShaderTypes[int(S::Enum)], BOO_D3DCOMPILE_FLAG, 0, &blobOut, &errBlob))) {
|
||||
fmt::print(FMT_STRING("{}\n"), text);
|
||||
Log.report(logvisor::Fatal, FMT_STRING("error compiling shader: {}"), (char*)errBlob->GetBufferPointer());
|
||||
return {};
|
||||
}
|
||||
std::pair<StageBinaryData, size_t> ret(MakeStageBinaryData(blobOut->GetBufferSize()), blobOut->GetBufferSize());
|
||||
memcpy(ret.first.get(), blobOut->GetBufferPointer(), blobOut->GetBufferSize());
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if __APPLE__
|
||||
template <>
|
||||
struct ShaderCompiler<PlatformType::Metal> {
|
||||
static bool m_didCompilerSearch;
|
||||
static bool m_hasCompiler;
|
||||
|
||||
static bool SearchForCompiler() {
|
||||
m_didCompilerSearch = true;
|
||||
const char* no_metal_compiler = getenv("HECL_NO_METAL_COMPILER");
|
||||
if (no_metal_compiler && atoi(no_metal_compiler))
|
||||
return false;
|
||||
|
||||
pid_t pid = fork();
|
||||
if (!pid) {
|
||||
execlp("xcrun", "xcrun", "-sdk", "macosx", "metal", "--version", nullptr);
|
||||
/* 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)
|
||||
return false;
|
||||
return WEXITSTATUS(status) == 0;
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
static std::pair<StageBinaryData, size_t> Compile(std::string_view text) {
|
||||
if (!m_didCompilerSearch)
|
||||
m_hasCompiler = SearchForCompiler();
|
||||
|
||||
std::string str =
|
||||
"#include <metal_stdlib>\n"
|
||||
"using namespace metal;\n";
|
||||
str += text;
|
||||
std::pair<StageBinaryData, size_t> ret;
|
||||
|
||||
if (!m_hasCompiler) {
|
||||
/* First byte unset to indicate source data */
|
||||
ret.first = MakeStageBinaryData(str.size() + 2);
|
||||
ret.first.get()[0] = 0;
|
||||
ret.second = str.size() + 2;
|
||||
memcpy(&ret.first.get()[1], str.data(), str.size() + 1);
|
||||
} else {
|
||||
int compilerOut[2];
|
||||
int compilerIn[2];
|
||||
pipe(compilerOut);
|
||||
pipe(compilerIn);
|
||||
|
||||
pid_t pid = getpid();
|
||||
const char* tmpdir = getenv("TMPDIR");
|
||||
std::string libFile = fmt::format(FMT_STRING("{}boo_metal_shader{}.metallib"), tmpdir, pid);
|
||||
|
||||
/* 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", "-c", "-x", "metal",
|
||||
#ifndef NDEBUG
|
||||
"-gline-tables-only", "-MO",
|
||||
#endif
|
||||
"-", nullptr);
|
||||
fmt::print(stderr, FMT_STRING("execlp fail {}\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", libFile.c_str(), nullptr);
|
||||
fmt::print(stderr, FMT_STRING("execlp fail {}\n"), strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
close(compilerOut[0]);
|
||||
|
||||
/* Stream in source */
|
||||
const char* inPtr = str.data();
|
||||
size_t inRem = str.size();
|
||||
while (inRem) {
|
||||
ssize_t writeRes = write(compilerIn[1], inPtr, inRem);
|
||||
if (writeRes < 0) {
|
||||
fmt::print(stderr, FMT_STRING("write fail {}\n"), strerror(errno));
|
||||
break;
|
||||
}
|
||||
inPtr += writeRes;
|
||||
inRem -= writeRes;
|
||||
}
|
||||
close(compilerIn[1]);
|
||||
|
||||
/* Wait for completion */
|
||||
int compilerStat, linkerStat;
|
||||
while (waitpid(compilerPid, &compilerStat, 0) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
Log.report(logvisor::Fatal, FMT_STRING("waitpid fail {}"), strerror(errno));
|
||||
return {};
|
||||
}
|
||||
|
||||
if (WEXITSTATUS(compilerStat)) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("compile fail"));
|
||||
return {};
|
||||
}
|
||||
|
||||
while (waitpid(linkerPid, &linkerStat, 0) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
Log.report(logvisor::Fatal, FMT_STRING("waitpid fail {}"), strerror(errno));
|
||||
return {};
|
||||
}
|
||||
|
||||
if (WEXITSTATUS(linkerStat)) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("link fail"));
|
||||
return {};
|
||||
}
|
||||
|
||||
/* Copy temp file into buffer with first byte set to indicate binary data */
|
||||
FILE* fin = fopen(libFile.c_str(), "rb");
|
||||
fseek(fin, 0, SEEK_END);
|
||||
long libLen = ftell(fin);
|
||||
fseek(fin, 0, SEEK_SET);
|
||||
ret.first = MakeStageBinaryData(libLen + 1);
|
||||
ret.first.get()[0] = 1;
|
||||
ret.second = libLen + 1;
|
||||
fread(&ret.first.get()[1], 1, libLen, fin);
|
||||
fclose(fin);
|
||||
unlink(libFile.c_str());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
bool ShaderCompiler<PlatformType::Metal>::m_didCompilerSearch = false;
|
||||
bool ShaderCompiler<PlatformType::Metal>::m_hasCompiler = false;
|
||||
#endif
|
||||
|
||||
#if HECL_NOUVEAU_NX
|
||||
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;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename P, typename S>
|
||||
std::pair<StageBinaryData, size_t> CompileShader(std::string_view text) {
|
||||
return ShaderCompiler<P>::template Compile<S>(text);
|
||||
}
|
||||
#define SPECIALIZE_COMPILE_SHADER(P) \
|
||||
template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Vertex>(std::string_view text); \
|
||||
template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Fragment>(std::string_view text); \
|
||||
template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Geometry>(std::string_view text); \
|
||||
template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Control>(std::string_view text); \
|
||||
template std::pair<StageBinaryData, 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
|
||||
|
||||
} // namespace hecl
|
||||
@@ -1,410 +0,0 @@
|
||||
#include <hecl/Console.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "hecl/CVar.hpp"
|
||||
#include "hecl/CVarManager.hpp"
|
||||
#include "hecl/hecl.hpp"
|
||||
|
||||
#include <athena/Utility.hpp>
|
||||
#include <boo/IWindow.hpp>
|
||||
#include <boo/graphicsdev/IGraphicsCommandQueue.hpp>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
namespace hecl {
|
||||
Console* Console::m_instance = nullptr;
|
||||
Console::Console(CVarManager* cvarMgr) : m_cvarMgr(cvarMgr), m_overwrite(false), m_cursorAtEnd(false) {
|
||||
m_instance = this;
|
||||
registerCommand("help", "Prints information about a given function", "<command>",
|
||||
[this](Console* console, const std::vector<std::string>& args) { help(console, args); });
|
||||
registerCommand("listCommands", "Prints a list of all available Commands", "",
|
||||
[this](Console* console, const std::vector<std::string>& args) { listCommands(console, args); });
|
||||
registerCommand("listCVars", "Lists all available CVars", "",
|
||||
[this](Console* console, const std::vector<std::string>& args) { m_cvarMgr->list(console, args); });
|
||||
registerCommand(
|
||||
"setCVar", "Sets a given Console Variable to the specified value", "<cvar> <value>",
|
||||
[this](Console* console, const std::vector<std::string>& args) { m_cvarMgr->setCVar(console, args); });
|
||||
registerCommand(
|
||||
"getCVar", "Prints the value stored in the specified Console Variable", "<cvar>",
|
||||
[this](Console* console, const std::vector<std::string>& args) { m_cvarMgr->getCVar(console, args); });
|
||||
}
|
||||
|
||||
void Console::registerCommand(std::string_view name, std::string_view helpText, std::string_view usage,
|
||||
std::function<void(Console*, const std::vector<std::string>&)>&& func,
|
||||
SConsoleCommand::ECommandFlags cmdFlags) {
|
||||
std::string lowName{name};
|
||||
athena::utility::tolower(lowName);
|
||||
|
||||
if (m_commands.find(lowName) != m_commands.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_commands.emplace(std::move(lowName), SConsoleCommand{std::string{name}, std::string{helpText}, std::string{usage},
|
||||
std::move(func), cmdFlags});
|
||||
}
|
||||
|
||||
void Console::unregisterCommand(std::string_view name) {
|
||||
std::string lowName{name};
|
||||
athena::utility::tolower(lowName);
|
||||
|
||||
const auto iter = m_commands.find(lowName);
|
||||
if (iter == m_commands.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_commands.erase(iter);
|
||||
}
|
||||
|
||||
void Console::executeString(const std::string& str) {
|
||||
if (str.empty())
|
||||
return;
|
||||
|
||||
/* First let's split semi-colon delimited commands */
|
||||
std::vector<std::string> commands = athena::utility::split(str, ';');
|
||||
|
||||
if (commands.empty())
|
||||
return;
|
||||
|
||||
for (std::string command : commands) {
|
||||
command = athena::utility::trim(command);
|
||||
std::vector<std::string> tmpArgs = athena::utility::split(command, ' ');
|
||||
if (tmpArgs.empty())
|
||||
continue;
|
||||
std::vector<std::string> args;
|
||||
args.reserve(tmpArgs.size());
|
||||
/* detect string literals */
|
||||
bool isInLiteral = false;
|
||||
std::string curLiteral;
|
||||
int depth = 0;
|
||||
for (std::string arg : tmpArgs) {
|
||||
if ((arg.front() == '\'' || arg.front() == '"')) {
|
||||
++depth;
|
||||
isInLiteral = true;
|
||||
curLiteral += arg;
|
||||
} else if ((arg.back() == '\'' || arg.back() == '"') && isInLiteral) {
|
||||
--depth;
|
||||
curLiteral += arg;
|
||||
args.push_back(curLiteral);
|
||||
if (depth <= 0) {
|
||||
depth = 0;
|
||||
isInLiteral = false;
|
||||
curLiteral.clear();
|
||||
}
|
||||
} else if (isInLiteral) {
|
||||
curLiteral += arg;
|
||||
} else {
|
||||
args.push_back(std::move(arg));
|
||||
}
|
||||
}
|
||||
|
||||
if (isInLiteral) {
|
||||
if ((curLiteral.back() != '\'' && curLiteral.back() != '"') || depth > 1) {
|
||||
report(Level::Warning, FMT_STRING("Unterminated string literal"));
|
||||
return;
|
||||
}
|
||||
args.push_back(std::move(curLiteral));
|
||||
}
|
||||
|
||||
std::string commandName = args[0];
|
||||
args.erase(args.begin());
|
||||
|
||||
std::string lowComName = commandName;
|
||||
athena::utility::tolower(lowComName);
|
||||
if (const auto iter = m_commands.find(lowComName); iter != m_commands.end()) {
|
||||
const SConsoleCommand& cmd = iter->second;
|
||||
if (bool(cmd.m_flags & SConsoleCommand::ECommandFlags::Developer) && !com_developer->toBoolean()) {
|
||||
report(Level::Error, FMT_STRING("This command can only be executed in developer mode"), commandName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bool(cmd.m_flags & SConsoleCommand::ECommandFlags::Cheat) && !com_enableCheats->toBoolean()) {
|
||||
report(Level::Error, FMT_STRING("This command can only be executed with cheats enabled"), commandName);
|
||||
return;
|
||||
}
|
||||
cmd.m_func(this, args);
|
||||
} else if (const CVar* cv = m_cvarMgr->findCVar(commandName)) {
|
||||
args.insert(args.begin(), std::move(commandName));
|
||||
if (args.size() > 1)
|
||||
m_cvarMgr->setCVar(this, args);
|
||||
else
|
||||
m_cvarMgr->getCVar(this, args);
|
||||
} else {
|
||||
report(Level::Error, FMT_STRING("'{}' is not a valid command or variable!"), commandName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Console::help(Console* /*con*/, const std::vector<std::string>& args) {
|
||||
if (args.empty()) {
|
||||
report(Level::Info, FMT_STRING("Expected usage: help <command>"));
|
||||
return;
|
||||
}
|
||||
std::string cmd = args.front();
|
||||
athena::utility::tolower(cmd);
|
||||
auto it = m_commands.find(cmd);
|
||||
if (it == m_commands.end()) {
|
||||
report(Level::Error, FMT_STRING("No such command '{}'"), args.front());
|
||||
return;
|
||||
}
|
||||
|
||||
report(Level::Info, FMT_STRING("{}: {}"), it->second.m_displayName, it->second.m_helpString);
|
||||
if (!it->second.m_usage.empty())
|
||||
report(Level::Info, FMT_STRING("Usage: {} {}"), it->second.m_displayName, it->second.m_usage);
|
||||
}
|
||||
|
||||
void Console::listCommands(Console* /*con*/, const std::vector<std::string>& /*args*/) {
|
||||
for (const auto& comPair : m_commands)
|
||||
report(Level::Info, FMT_STRING("'{}': {}"), comPair.second.m_displayName, comPair.second.m_helpString);
|
||||
}
|
||||
|
||||
bool Console::commandExists(std::string_view cmd) const {
|
||||
std::string cmdName{cmd};
|
||||
athena::utility::tolower(cmdName);
|
||||
|
||||
return m_commands.find(cmdName) != m_commands.end();
|
||||
}
|
||||
|
||||
void Console::vreport(Level level, fmt::string_view fmt, fmt::format_args args) {
|
||||
std::string tmp = fmt::vformat(fmt, args);
|
||||
std::vector<std::string> lines = athena::utility::split(tmp, '\n');
|
||||
for (std::string& line : lines) {
|
||||
m_log.emplace_back(std::move(line), level);
|
||||
}
|
||||
fmt::print(FMT_STRING("{}\n"), tmp);
|
||||
}
|
||||
|
||||
void Console::init(boo::IWindow* window) {
|
||||
m_window = window;
|
||||
}
|
||||
|
||||
void Console::proc() {
|
||||
if (m_state == State::Opened) {
|
||||
fmt::print(FMT_STRING("\r{} "), m_commandString);
|
||||
fflush(stdout);
|
||||
} else if (m_state == State::Opening)
|
||||
m_state = State::Opened;
|
||||
else if (m_state == State::Closing) {
|
||||
m_state = State::Closed;
|
||||
m_commandString.clear();
|
||||
}
|
||||
|
||||
if (m_cursorPosition > int(m_commandString.size() - 1))
|
||||
m_cursorPosition = int(m_commandString.size() - 1);
|
||||
if (m_cursorPosition < -1)
|
||||
m_cursorPosition = -1;
|
||||
|
||||
if (m_logOffset > int(m_log.size() - 1))
|
||||
m_logOffset = int(m_log.size() - 1);
|
||||
if (m_logOffset < 0)
|
||||
m_logOffset = 0;
|
||||
}
|
||||
|
||||
void Console::draw(boo::IGraphicsCommandQueue* /* gfxQ */) {
|
||||
}
|
||||
|
||||
void Console::handleCharCode(unsigned long chr, boo::EModifierKey /*mod*/, bool /*repeat*/) {
|
||||
if (chr == U'`' || chr == U'~') {
|
||||
if (m_state == State::Closed || m_state == State::Closing)
|
||||
m_state = State::Opening;
|
||||
else
|
||||
m_state = State::Closing;
|
||||
}
|
||||
|
||||
if (m_state == State::Opened) {
|
||||
if (!m_commandString.empty() && m_cursorPosition + 1 < int(m_commandString.size())) {
|
||||
if (m_overwrite)
|
||||
m_commandString[unsigned(m_cursorPosition + 1)] = char(chr);
|
||||
else
|
||||
m_commandString.insert(m_commandString.begin() + m_cursorPosition + 1, char(chr));
|
||||
} else
|
||||
m_commandString += char(chr);
|
||||
|
||||
++m_cursorPosition;
|
||||
}
|
||||
}
|
||||
|
||||
void Console::handleSpecialKeyDown(boo::ESpecialKey sp, boo::EModifierKey mod, bool /*repeat*/) {
|
||||
if (m_state != State::Opened) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (sp) {
|
||||
case boo::ESpecialKey::Insert:
|
||||
m_overwrite ^= 1;
|
||||
break;
|
||||
case boo::ESpecialKey::Backspace: {
|
||||
if (!m_commandString.empty()) {
|
||||
if (True(mod & boo::EModifierKey::Ctrl)) {
|
||||
size_t index = m_commandString.rfind(' ', size_t(m_cursorPosition - 1));
|
||||
|
||||
if (index == std::string::npos) {
|
||||
m_commandString.clear();
|
||||
m_cursorPosition = -1;
|
||||
} else {
|
||||
m_commandString.erase(index, (index - m_commandString.size()));
|
||||
m_cursorPosition = int(index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (m_cursorPosition < 0)
|
||||
break;
|
||||
|
||||
m_commandString.erase(size_t(m_cursorPosition), 1);
|
||||
--m_cursorPosition;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::Delete: {
|
||||
if (!m_commandString.empty()) {
|
||||
// Don't try to delete if the cursor is at the end of the line
|
||||
if ((m_cursorPosition + 1) >= int(m_commandString.size()))
|
||||
break;
|
||||
|
||||
if (True(mod & boo::EModifierKey::Ctrl)) {
|
||||
size_t index = m_commandString.find_first_of(' ', size_t(m_cursorPosition + 1));
|
||||
if (index != std::string::npos)
|
||||
m_commandString.erase(size_t(m_cursorPosition + 1), index + 1);
|
||||
else
|
||||
m_commandString.erase(size_t(m_cursorPosition + 1), size_t(m_cursorPosition + 1) - m_commandString.size());
|
||||
break;
|
||||
}
|
||||
m_commandString.erase(size_t(m_cursorPosition + 1), 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::PgUp: {
|
||||
if (m_logOffset < int(m_log.size() - m_maxLines) - 1)
|
||||
m_logOffset++;
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::PgDown: {
|
||||
if (m_logOffset > 0)
|
||||
m_logOffset--;
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::Enter: {
|
||||
fmt::print(FMT_STRING("\n"));
|
||||
executeString(m_commandString);
|
||||
m_cursorPosition = -1;
|
||||
m_commandHistory.insert(m_commandHistory.begin(), m_commandString);
|
||||
m_commandString.clear();
|
||||
m_showCursor = true;
|
||||
m_cursorTime = 0.f;
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::Left: {
|
||||
if (m_cursorPosition < 0)
|
||||
break;
|
||||
|
||||
if (True(mod & boo::EModifierKey::Ctrl))
|
||||
m_cursorPosition = int(m_commandString.rfind(' ', size_t(m_cursorPosition) - 1));
|
||||
else
|
||||
m_cursorPosition--;
|
||||
|
||||
m_showCursor = true;
|
||||
m_cursorTime = 0.f;
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::Right: {
|
||||
if (m_cursorPosition >= int(m_commandString.size() - 1))
|
||||
break;
|
||||
|
||||
if (True(mod & boo::EModifierKey::Ctrl)) {
|
||||
if (m_commandString[size_t(m_cursorPosition)] == ' ')
|
||||
m_cursorPosition++;
|
||||
|
||||
size_t tmpPos = m_commandString.find(' ', size_t(m_cursorPosition));
|
||||
if (tmpPos == std::string::npos)
|
||||
m_cursorPosition = int(m_commandString.size() - 1);
|
||||
else
|
||||
m_cursorPosition = int(tmpPos);
|
||||
} else
|
||||
m_cursorPosition++;
|
||||
|
||||
m_showCursor = true;
|
||||
m_cursorTime = 0.f;
|
||||
break;
|
||||
}
|
||||
|
||||
case boo::ESpecialKey::Up: {
|
||||
if (m_commandHistory.size() == 0)
|
||||
break;
|
||||
|
||||
m_currentCommand++;
|
||||
|
||||
if (m_currentCommand > int(m_commandHistory.size() - 1))
|
||||
m_currentCommand = int(m_commandHistory.size() - 1);
|
||||
|
||||
m_commandString = m_commandHistory[size_t(m_currentCommand)];
|
||||
m_cursorPosition = int(m_commandString.size() - 1);
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::Down: {
|
||||
if (m_commandHistory.empty())
|
||||
break;
|
||||
m_currentCommand--;
|
||||
if (m_currentCommand >= 0) {
|
||||
m_commandString = m_commandHistory[size_t(m_currentCommand)];
|
||||
} else if (m_currentCommand <= -1) {
|
||||
m_currentCommand = -1;
|
||||
m_commandString.clear();
|
||||
}
|
||||
m_cursorPosition = int(m_commandString.size());
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::Home:
|
||||
m_cursorPosition = -1;
|
||||
break;
|
||||
case boo::ESpecialKey::End:
|
||||
m_cursorPosition = int(m_commandString.size() - 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Console::handleSpecialKeyUp(boo::ESpecialKey /*sp*/, boo::EModifierKey /*mod*/) {}
|
||||
|
||||
void Console::LogVisorAdapter::report(const char* modName, logvisor::Level severity,
|
||||
fmt::string_view format, fmt::format_args args) {
|
||||
auto tmp = fmt::vformat(format, args);
|
||||
std::vector<std::string> lines = athena::utility::split(tmp, '\n');
|
||||
for (const std::string& line : lines) {
|
||||
auto v = fmt::format(FMT_STRING("[{}] {}"), modName, line);
|
||||
m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
|
||||
}
|
||||
}
|
||||
|
||||
void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level severity, const char* file,
|
||||
unsigned linenum, fmt::string_view format, fmt::format_args args) {
|
||||
auto tmp = fmt::vformat(format, args);
|
||||
auto v = fmt::format(FMT_STRING("[{}] {} {}:{}"), modName, tmp, file, linenum);
|
||||
m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
|
||||
}
|
||||
|
||||
void Console::dumpLog() {
|
||||
for (const auto& l : m_log) {
|
||||
switch (l.second) {
|
||||
case Level::Info:
|
||||
fmt::print(FMT_STRING("{}\n"), l.first);
|
||||
break;
|
||||
case Level::Warning:
|
||||
fmt::print(FMT_STRING("[Warning] {}\n"), l.first);
|
||||
break;
|
||||
case Level::Error:
|
||||
fmt::print(FMT_STRING("[ Error ] {}\n"), l.first);
|
||||
break;
|
||||
case Level::Fatal:
|
||||
fmt::print(FMT_STRING("[ Fatal ] {}\n"), l.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Console::RegisterLogger(Console* con) { logvisor::MainLoggers.emplace_back(new LogVisorAdapter(con)); }
|
||||
|
||||
Console* Console::instance() { return m_instance; }
|
||||
} // namespace hecl
|
||||
@@ -1,167 +0,0 @@
|
||||
#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 char* 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() override { inflateEnd(&m_zstrm); }
|
||||
explicit operator bool() const { return m_compBuf.operator bool(); }
|
||||
atUint64 readUBytesToBuf(void* buf, atUint64 len) override {
|
||||
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) override {}
|
||||
atUint64 position() const override { return 0; }
|
||||
atUint64 length() const override { 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();
|
||||
StageBinaryData data = MakeStageBinaryData(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 (uint32_t 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 char* 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
|
||||
|
||||
} // namespace hecl
|
||||
@@ -1,5 +1,4 @@
|
||||
set(RUNTIME_SOURCES
|
||||
FileStoreManager.cpp
|
||||
HMDL_RT.cpp)
|
||||
FileStoreManager.cpp)
|
||||
|
||||
hecl_add_list(Runtime RUNTIME_SOURCES)
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
#include "hecl/HMDLMeta.hpp"
|
||||
|
||||
#include "hecl/Runtime.hpp"
|
||||
|
||||
#include <athena/MemoryReader.hpp>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
namespace hecl::Runtime {
|
||||
static logvisor::Module HMDL_Log("HMDL");
|
||||
|
||||
HMDLData::HMDLData(boo::IGraphicsDataFactory::Context& ctx, const void* metaData, const void* vbo, const void* ibo) {
|
||||
HMDLMeta meta;
|
||||
{
|
||||
athena::io::MemoryReader r(metaData, HECL_HMDL_META_SZ);
|
||||
meta.read(r);
|
||||
}
|
||||
if (meta.magic != 'TACO')
|
||||
HMDL_Log.report(logvisor::Fatal, FMT_STRING("invalid HMDL magic"));
|
||||
|
||||
m_vbo = ctx.newStaticBuffer(boo::BufferUse::Vertex, vbo, meta.vertStride, meta.vertCount);
|
||||
m_ibo = ctx.newStaticBuffer(boo::BufferUse::Index, ibo, 4, meta.indexCount);
|
||||
|
||||
const size_t elemCount = 2 + meta.colorCount + meta.uvCount + meta.weightCount;
|
||||
m_vtxFmtData = std::make_unique<boo::VertexElementDescriptor[]>(elemCount);
|
||||
|
||||
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) {
|
||||
m_vtxFmtData[e].semantic = boo::VertexSemantic::ColorUNorm;
|
||||
m_vtxFmtData[e].semanticIdx = i;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < meta.uvCount; ++i, ++e) {
|
||||
m_vtxFmtData[e].semantic = boo::VertexSemantic::UV2;
|
||||
m_vtxFmtData[e].semanticIdx = i;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < meta.weightCount; ++i, ++e) {
|
||||
m_vtxFmtData[e].semantic = boo::VertexSemantic::Weight;
|
||||
m_vtxFmtData[e].semanticIdx = i;
|
||||
}
|
||||
|
||||
m_vtxFmt = boo::VertexFormatInfo(elemCount, m_vtxFmtData.get());
|
||||
}
|
||||
|
||||
} // namespace hecl::Runtime
|
||||
Reference in New Issue
Block a user