diff --git a/include/nbl/asset/material_compiler/CMaterialCompilerGLSLBackendCommon.h b/include/nbl/asset/material_compiler/CGLSLBackendCommon.h similarity index 95% rename from include/nbl/asset/material_compiler/CMaterialCompilerGLSLBackendCommon.h rename to include/nbl/asset/material_compiler/CGLSLBackendCommon.h index 2e88b1c048..fe32d87d29 100644 --- a/include/nbl/asset/material_compiler/CMaterialCompilerGLSLBackendCommon.h +++ b/include/nbl/asset/material_compiler/CGLSLBackendCommon.h @@ -1,9 +1,8 @@ -// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. +// Copyright (C) 2018-2022 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __NBL_ASSET_C_MITSUBA_MATERIAL_COMPILER_GLSL_BACKEND_COMMON_H_INCLUDED__ -#define __NBL_ASSET_C_MITSUBA_MATERIAL_COMPILER_GLSL_BACKEND_COMMON_H_INCLUDED__ +#ifndef _NBL_ASSET_MATERIAL_COMPILER_C_GLSL_BACKEND_COMMON_H_INCLUDED_ +#define _NBL_ASSET_MATERIAL_COMPILER_C_GLSL_BACKEND_COMMON_H_INCLUDED_ #include @@ -17,38 +16,30 @@ namespace nbl::asset::material_compiler { - -// TODO: we need a GLSL to C++ compatibility wrapper +// +namespace impl +{ #define uint uint32_t #define uvec2 uint64_t -struct nbl_glsl_MC_oriented_material_t -{ - uvec2 emissive; - uint prefetch_offset; - uint prefetch_count; - uint instr_offset; - uint rem_pdf_count; - uint nprecomp_count; - uint genchoice_count; -}; -struct nbl_glsl_MC_material_data_t -{ - nbl_glsl_MC_oriented_material_t front; - nbl_glsl_MC_oriented_material_t back; -}; +#include #undef uint #undef uvec2 -using oriented_material_t = nbl_glsl_MC_oriented_material_t; -using material_data_t = nbl_glsl_MC_material_data_t; - +} +// TODO: remove template class ITraversalGenerator; -class CMaterialCompilerGLSLBackendCommon +class CGLSLBackendCommon { -public: + public: + using material_data_t = impl::nbl_glsl_MC_material_data_t; + using oriented_material_t = impl::nbl_glsl_MC_oriented_material_t; + + + +// TODO: rewrite all below struct instr_stream { using instr_t = uint64_t; @@ -589,12 +580,12 @@ class CMaterialCompilerGLSLBackendCommon template friend class ITraversalGenerator; - friend class CMaterialCompilerGLSLBackendCommon; + friend class CGLSLBackendCommon; //users should not touch this core::vector bsdfData; // TODO: HARDER DEDUPLICATION, hash & compare contents not only pointers! - core::unordered_map bsdfDataIndexMap; + core::unordered_map bsdfDataIndexMap; using VTallocKey = std::pair; struct VTallocKeyHash @@ -705,7 +696,7 @@ class CMaterialCompilerGLSLBackendCommon core::unordered_set NDFs; //one element for each input IR root node - core::unordered_map streams; + core::unordered_map streams; //has to go after #version and before required user-provided descriptors and functions std::string fragmentShaderSource_declarations; diff --git a/include/nbl/asset/material_compiler/CGLSLRasterBackend.h b/include/nbl/asset/material_compiler/CGLSLRasterBackend.h new file mode 100644 index 0000000000..65ca1894b0 --- /dev/null +++ b/include/nbl/asset/material_compiler/CGLSLRasterBackend.h @@ -0,0 +1,22 @@ +// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h +#ifndef _NBL_ASSET_MATERIAL_COMPILER_C_GLSL_RASTER_BACKEND_H_INCLUDED_ +#define _NBL_ASSET_MATERIAL_COMPILER_C_GLSL_RASTER_BACKEND_H_INCLUDED_ + +#include + +namespace nbl::asset::material_compiler +{ + +class CGLSLRasterBackend : public CGLSLBackendCommon +{ + using base_t = CGLSLBackendCommon; + + public: + result_t compile(SContext* _ctx, IR* _ir, E_GENERATOR_STREAM_TYPE _generatorChoiceStream=EGST_PRESENT) override; +}; + +} + +#endif \ No newline at end of file diff --git a/include/nbl/asset/material_compiler/CMaterialCompilerGLSLRasterBackend.h b/include/nbl/asset/material_compiler/CMaterialCompilerGLSLRasterBackend.h deleted file mode 100644 index 75bb4acb11..0000000000 --- a/include/nbl/asset/material_compiler/CMaterialCompilerGLSLRasterBackend.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. -// This file is part of the "Nabla Engine". -// For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __NBL_ASSET_C_MITSUBA_MATERIAL_COMPILER_GLSL_RASTER_BACKEND_H_INCLUDED__ -#define __NBL_ASSET_C_MITSUBA_MATERIAL_COMPILER_GLSL_RASTER_BACKEND_H_INCLUDED__ - -#include - -namespace nbl::asset::material_compiler -{ - -class CMaterialCompilerGLSLRasterBackend : public CMaterialCompilerGLSLBackendCommon -{ - using base_t = CMaterialCompilerGLSLBackendCommon; - - public: - result_t compile(SContext* _ctx, IR* _ir, E_GENERATOR_STREAM_TYPE _generatorChoiceStream=EGST_PRESENT) override; -}; - -} - -#endif \ No newline at end of file diff --git a/include/nbl/asset/material_compiler/IFrontend.h b/include/nbl/asset/material_compiler/IFrontend.h deleted file mode 100644 index ec908a6356..0000000000 --- a/include/nbl/asset/material_compiler/IFrontend.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __NBL_MATERIAL_COMPILER_I_FRONTEND_H_INCLUDED__ -#define __NBL_MATERIAL_COMPILER_I_FRONTEND_H_INCLUDED__ - -#include -#include - -namespace nbl::asset::material_compiler -{ - -class IFrontend : public core::IReferenceCounted -{ - public: - virtual core::smart_refctd_ptr compileToIR(); -}; - -} - -#endif \ No newline at end of file diff --git a/include/nbl/asset/material_compiler/IR.h b/include/nbl/asset/material_compiler/IR.h index b7b86add42..41a48a6697 100644 --- a/include/nbl/asset/material_compiler/IR.h +++ b/include/nbl/asset/material_compiler/IR.h @@ -1,489 +1,455 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h -#ifndef __NBL_ASSET_MATERIAL_COMPILER_IR_H_INCLUDED__ -#define __NBL_ASSET_MATERIAL_COMPILER_IR_H_INCLUDED__ +#ifndef _NBL_ASSET_MATERIAL_COMPILER_IR_H_INCLUDED__ +#define _NBL_ASSET_MATERIAL_COMPILER_IR_H_INCLUDED__ #include -#include // delete #include #include -#include // delete namespace nbl::asset::material_compiler { -/** - -TODO: -- Split `INode` into `INode` + `IInternalNode` -- rework `IInternalNode` child pointers to offsets -- Merkle Tree / Hash Consing - -**/ +// TODO: Merkle Tree / Hash Consing class IR : public core::IReferenceCounted { - class SBackingMemManager - { - _NBL_STATIC_INLINE_CONSTEXPR size_t INITIAL_MEM_SIZE = 1ull<<20; - _NBL_STATIC_INLINE_CONSTEXPR size_t MAX_MEM_SIZE = 1ull<<24; - _NBL_STATIC_INLINE_CONSTEXPR size_t ALIGNMENT = _NBL_SIMD_ALIGNMENT; - - uint8_t* mem; - size_t currSz; - using addr_alctr_t = core::LinearAddressAllocator; - addr_alctr_t addrAlctr; - public: - SBackingMemManager() : mem(nullptr), currSz(INITIAL_MEM_SIZE), addrAlctr(nullptr, 0u, 0u, ALIGNMENT, MAX_MEM_SIZE) { - mem = reinterpret_cast(_NBL_ALIGNED_MALLOC(currSz, ALIGNMENT)); - } - ~SBackingMemManager() { - _NBL_ALIGNED_FREE(mem); - } + IR() : memMgr() {} - uint8_t* alloc(size_t bytes) - { - auto addr = addrAlctr.alloc_addr(bytes, ALIGNMENT); - assert(addr != addr_alctr_t::invalid_address); - //TODO reallocation will invalidate all pointers to nodes, so... - //1) never reallocate (just have reasonably big buffer for nodes) - //2) make some node_handle class that will work as pointer but is based on offset instead of actual address - if (addr+bytes > currSz) { - size_t newSz = currSz<<1; - if (newSz > MAX_MEM_SIZE) { - addrAlctr.free_addr(addr, bytes); - return nullptr; - } + struct node_handle_t + { + uint32_t byteOffset; - void* newMem = _NBL_ALIGNED_MALLOC(newSz, ALIGNMENT); - memcpy(newMem, mem, currSz); - _NBL_ALIGNED_FREE(mem); - mem = reinterpret_cast(newMem); - currSz = newSz; + inline bool operator!=(const node_handle_t& other) const + { + return byteOffset!=other.byteOffset; } + inline bool operator==(const node_handle_t& other) const + { + return !operator!=(other); + } + }; + static inline constexpr node_handle_t invalid_node = {0xdeadbeefu}; - return mem+addr; - } - - uint32_t getAllocatedSize() const + class INode { - return addrAlctr.get_allocated_size(); - } + public: + enum E_SYMBOL : uint8_t + { + ES_GEOM_MODIFIER, + ES_EMISSION, + ES_OPACITY, + ES_BSDF, + ES_BSDF_COMBINER, + ES_UNINITIALIZED = 0xffu + }; + + using color_t = core::vector3df_SIMD; + struct STextureSource + { + core::smart_refctd_ptr image; + core::smart_refctd_ptr sampler; + float scale; - void freeLastAllocatedBytes(uint32_t _bytes) - { - assert(addrAlctr.get_allocated_size() >= _bytes); - const uint32_t newCursor = addrAlctr.get_allocated_size() - _bytes; - addrAlctr.reset(newCursor); - } - }; + inline bool operator==(const STextureSource& rhs) const { return image == rhs.image && sampler == rhs.sampler && scale == rhs.scale; } + }; - public: - IR() : memMgr() {} + template + union SParameter + { + inline SParameter() : texture{ nullptr,nullptr,core::nan() } {} + inline SParameter(const type_of_const& c) : SParameter() + { + *this = c; + } + inline SParameter(type_of_const&& c) : SParameter(c) {} + inline SParameter(const STextureSource& c) : SParameter() + { + *this = t; + } + inline SParameter(STextureSource&& t) : SParameter() + { + *this = std::move(t); + } + inline SParameter(const SParameter& other) : SParameter() + { + *this = other; + } + inline SParameter(SParameter&& other) : SParameter() + { + *this = std::move(other); + } - struct INode - { - enum E_SYMBOL: uint8_t - { - ES_GEOM_MODIFIER, - ES_EMISSION, - ES_OPACITY, - ES_BSDF, - ES_BSDF_COMBINER, - ES_UNINITIALIZED=0xffu - }; + inline bool isConstant() const { return core::isnan(texture.scale); } + inline ~SParameter() + { + if (!isConstant()) + texture.~STextureSource(); + } - struct STextureSource - { - core::smart_refctd_ptr image; - core::smart_refctd_ptr sampler; - float scale; + inline SParameter& operator=(const type_of_const& c) + { + // drop pointers properly + if (!isConstant()) + texture.~STextureSource(); + constant = c; + texture.scale = core::nan(); - bool operator==(const STextureSource& rhs) const { return image==rhs.image && sampler==rhs.sampler && scale==rhs.scale; } - }; + return *this; + } + inline SParameter& operator=(const STextureSource& t) + { + return operator=(STextureSource(t)); + } + inline SParameter& operator=(STextureSource&& t) + { + // if wasn't a texture before, need to prevent contents being reinterpreted as pointers + if (isConstant()) + memset(&texture, 0, offsetof(STextureSource, scale)); + texture = std::move(t); + // just in case the scale was a NaN + if (isConstant()) + texture.scale = 0.f; + + return *this; + } + inline SParameter& operator=(const SParameter& rhs) + { + if (rhs.isConstant()) + return operator=(rhs.constant); + else + return operator=(rhs.texture); + } + inline SParameter& operator=(SParameter&& rhs) + { + if (rhs.isConstant()) + return operator=(rhs.constant); + else + return operator=(std::move(rhs.texture)); + } - template - union SParameter - { - inline SParameter() : texture{nullptr,nullptr,core::nan()} {} - inline SParameter(const type_of_const& c) : SParameter() - { - *this = c; - } - inline SParameter(type_of_const&& c) : SParameter(c) {} - inline SParameter(const STextureSource& c) : SParameter() - { - *this = t; - } - inline SParameter(STextureSource&& t) : SParameter() - { - *this = std::move(t); - } - inline SParameter(const SParameter& other) : SParameter() - { - *this = other; - } - inline SParameter(SParameter&& other) : SParameter() - { - *this = std::move(other); - } + inline bool operator==(const SParameter& rhs) const + { + if (isConstant()) + { + if (rhs.isConstant()) + return constant == rhs.constant; + } + else if (!rhs.isConstant()) + return texture == rhs.texture; + return false; + } - inline bool isConstant() const {return core::isnan(texture.scale);} - inline ~SParameter() - { - if (!isConstant()) - texture.~STextureSource(); - } - - inline SParameter& operator=(const type_of_const& c) - { - // drop pointers properly - if (!isConstant()) - texture.~STextureSource(); - constant = c; - texture.scale = core::nan(); + type_of_const constant; + STextureSource texture; + }; - return *this; - } - inline SParameter& operator=(const STextureSource& t) - { - return operator=(STextureSource(t)); - } - inline SParameter& operator=(STextureSource&& t) - { - // if wasn't a texture before, need to prevent contents being reinterpreted as pointers - if (isConstant()) - memset(&texture,0,offsetof(STextureSource,scale)); - texture = std::move(t); - // just in case the scale was a NaN - if (isConstant()) - texture.scale = 0.f; - - return *this; - } - inline SParameter& operator=(const SParameter& rhs) + // + virtual E_SYMBOL getSymbol() const = 0; + + // + virtual bool cloneInto(INode* dst) const = 0; + + // + virtual uint32_t getChildCount() const = 0; + + // + inline const node_handle_t* getChildrenArray() const { - if (rhs.isConstant()) - return operator=(rhs.constant); - else - return operator=(rhs.texture); + return reinterpret_cast(reinterpret_cast(this)+getSize()-getChildrenStorageSize()); } - inline SParameter& operator=(SParameter&& rhs) + inline node_handle_t* getChildrenArray() { - if (rhs.isConstant()) - return operator=(rhs.constant); - else - return operator=(std::move(rhs.texture)); + return const_cast(const_cast(this)->getChildrenArray()); } - inline bool operator==(const SParameter& rhs) const + // + class children_range_t { - if (isConstant()) - { - if (rhs.isConstant()) - return constant == rhs.constant; - } - else if (!rhs.isConstant()) - return texture == rhs.texture; - return false; - } - - type_of_const constant; - STextureSource texture; - }; + public: + const node_handle_t* m_begin; + const node_handle_t* m_end; - _NBL_STATIC_INLINE_CONSTEXPR size_t MAX_CHILDREN = 16ull; - /* - * Possible TODO: - * we could implement the children array in the future as N nodes allocated just after this one (one would only need the child count)... - but this would only be possible if the nodes were uniform bytesize. - That way there would be no artificial limit on max children in our IR (backends will still have limits) - */ - struct children_array_t - { - INode* array[MAX_CHILDREN] {}; - size_t count = 0ull; + inline operator bool() const {return m_begin!=m_end;} - inline bool operator!=(const children_array_t& rhs) const + const node_handle_t* begin() const {return m_begin;} + const node_handle_t* end() const {return m_end;} + }; + inline const children_range_t getChildren() const { - if (count != rhs.count) - return true; - - for (uint32_t i = 0u; i < count; ++i) - if (array[i]!=rhs.array[i]) - return true; - return false; + auto begin = getChildrenArray(); + return {begin,begin+getChildCount()}; } - inline bool operator==(const children_array_t& rhs) const + + // + inline virtual ~INode() { - return !operator!=(rhs); + // clear out the vtable ptr + memset(this,0,sizeof(INode)); } - inline bool find(E_SYMBOL s, size_t* ix = nullptr) const - { - auto found = std::find_if(begin(),end(),[s](const INode* child){return child->symbol==s;}); - if (found != (array+count)) - { - if (ix) - ix[0] = found-array; - return true; - } + inline static bool alive(const INode* node) + { + // check by checking vtable ptr + for (auto val=reinterpret_cast(node++); ptrdiff_t(val) - static inline children_array_t createChildrenArray(Contents... children) - { - children_array_t a; - const INode* ch[]{ children... }; - memcpy(a.array, ch, sizeof(ch)); - a.count = sizeof...(children); - return a; - } - - using color_t = core::vector3df_SIMD; + protected: + friend class IR; - explicit INode(E_SYMBOL s) : symbol(s) {} - virtual ~INode() = default; - - // TODO: Why does every INode have children!? Leaf BxDFs do not need this! - children_array_t children; - E_SYMBOL symbol; + // + virtual size_t getSize() const = 0; + inline size_t getChildrenStorageSize() const + { + return sizeof(node_handle_t)*getChildCount(); + } }; - - void deinitTmpNodes() + template + inline const NodeType* getNode(const node_handle_t handle) const { - for (INode* n : tmp) - n->~INode(); - tmp.clear(); - memMgr.freeLastAllocatedBytes(tmpSize); - tmpSize = 0u; + if (handle.byteOffset(memMgr.data()+handle.byteOffset); + return nullptr; } - - void addRootNode(INode* node) + template + inline NodeType* getNode(const node_handle_t handle) { - roots.push_back(node); + return const_cast(const_cast(this)->getNode(handle)); } template - NodeType* allocNode(Args&& ...args) + inline node_handle_t allocNode(const uint32_t childCount, Args&& ...args) { - tmpSize = 0u; - return allocNode_impl(std::forward(args)...); + auto retval = allocTmpNode(childCount,std::forward(args)...); + if (retval.byteOffset - NodeType* allocRootNode(Args&& ...args) + + inline bool addRootNode(const node_handle_t node) { - auto* root = allocNode(std::forward(args)...); - addRootNode(root); - return root; + if (node.byteOffset - NodeType* allocTmpNode(Args&& ...args) + inline node_handle_t allocTmpNode(const uint32_t childCount, Args&& ...args) { - const uint32_t cursor = memMgr.getAllocatedSize(); - auto* node = allocNode_impl(std::forward(args)...); - tmp.push_back(node); - tmpSize += (memMgr.getAllocatedSize() - cursor); - return node; + auto retval = memMgr.alloc(NodeType::size_of(childCount)); + auto ptr = getNode(retval); + if (ptr) + new (ptr) NodeType(childCount,std::forward(args)...); + return retval; } - INode* copyNode(const INode* _rhs) - { - INode* node = nullptr; - switch (_rhs->symbol) + inline void deinitTmpNodes() { - case INode::ES_GEOM_MODIFIER: - { - auto* rhs = static_cast(_rhs); - node = allocNode(rhs->type); - *static_cast(node) = *rhs; - } - break; - case INode::ES_EMISSION: - { - auto* rhs = static_cast(_rhs); - node = allocNode(); - *static_cast(node) = *rhs; - } - break; - case INode::ES_OPACITY: - { - auto* rhs = static_cast(_rhs); - node = allocNode(); - *static_cast(node) = *rhs; + deleteRange(firstTmp); + firstTmp.byteOffset = memMgr.getAllocatedSize(); } - break; - case INode::ES_BSDF: - { - auto* rhs_bsdf = static_cast(_rhs); - switch (rhs_bsdf->type) - { - case CBSDFNode::ET_MICROFACET_DIFFTRANS: - { - auto* rhs = static_cast(_rhs); - node = allocNode(); - *static_cast(node) = *rhs; - } - break; - case CBSDFNode::ET_MICROFACET_DIFFUSE: - { - auto* rhs = static_cast(_rhs); - node = allocNode(); - *static_cast(node) = *rhs; - } - break; - case CBSDFNode::ET_MICROFACET_SPECULAR: - { - auto* rhs = static_cast(_rhs); - node = allocNode(); - *static_cast(node) = *rhs; - } - break; - case CBSDFNode::ET_MICROFACET_COATING: - { - auto* rhs = static_cast(_rhs); - node = allocNode(); - *static_cast(node) = *rhs; - } - break; - case CBSDFNode::ET_MICROFACET_DIELECTRIC: - { - auto* rhs = static_cast(_rhs); - node = allocNode(); - *static_cast(node) = *rhs; - } - break; - default: - { - node = allocNode(rhs_bsdf->type); - *static_cast(node) = *rhs_bsdf; - } - } - } - break; - case INode::ES_BSDF_COMBINER: + inline node_handle_t copyNode(const INode* _rhs) { - auto* rhs_combiner = static_cast(_rhs); - switch (rhs_combiner->type) + const size_t sz = _rhs->getSize(); + const auto allocation = memMgr.alloc(sz); + auto copy = getNode(allocation); + if (!copy) + return invalid_node; + if (!_rhs->cloneInto(copy)) { - case CBSDFCombinerNode::ET_WEIGHT_BLEND: - { - auto* rhs = static_cast(_rhs); - node = allocNode(); - *static_cast(node) = *rhs; - } - break; - case CBSDFCombinerNode::ET_MIX: - { - auto* rhs = static_cast(_rhs); - node = allocNode(); - *static_cast(node) = *rhs; - } - break; - default: - { - node = allocNode(rhs_combiner->type); - *static_cast(node) = *rhs_combiner; - } - break; + memMgr.trimBackDown(allocation); + return invalid_node; } + firstTmp.byteOffset = memMgr.getAllocatedSize(); + return allocation; } - break; - default: - assert(false); - return nullptr; + template + inline NodeT* copyNode(const INode* _rhs) + { + return getNode(copyNode(_rhs)); } - return node; - } + // + class ILeafNode : public INode + { + public: + inline uint32_t getChildCount() const final override {return 0u;} + }; + template + class IFixedChildCountNode : public INode + { + public: + inline uint32_t getChildCount() const final override + { + return k_childrenCount; + } - struct CGeomModifierNode : public INode - { - enum E_TYPE + protected: + static inline constexpr uint32_t k_childrenCount = kChildrenCount; + }; + class IVariableChildCountNode : public INode { - ET_DISPLACEMENT, - ET_HEIGHT, - ET_NORMAL, - ET_DERIVATIVE + public: + inline uint32_t getChildCount() const final override + { + return m_childrenCount; + } + + protected: + uint32_t m_childrenCount; }; - enum E_SOURCE + template + class Finalizer final : public FinalNodeT { - ESRC_UV_FUNCTION, - ESRC_TEXTURE + public: + template + Finalizer(const uint32_t childCount, Args&&... args) : FinalNodeT(std::forward(args)...) + { + if constexpr (std::is_base_of_v) + { + IVariableChildCountNode::m_childrenCount = childCount; + } + else + if constexpr (!std::is_base_of_v) + { + assert(k_childrenCount==childCount); + } + } + + static inline size_t size_of(const uint32_t childCount) + { + if constexpr (std::is_base_of_v) + return FinalNodeT::size_of(childCount); + else + return sizeof(FinalNodeT)+sizeof(node_handle_t)*childCount; + } + + inline size_t getSize() const override final {return size_of(getChildCount()); } + + inline bool cloneInto(INode* dst) const override final + { + auto casted = dynamic_cast(dst); + if (!casted) + return false; + memcpy(casted->getChildrenArray(),INode::getChildrenArray(),INode::getChildrenStorageSize()); + casted->operator=(*static_cast(this)); + return true; + } }; - CGeomModifierNode(E_TYPE t) : INode(ES_GEOM_MODIFIER), type(t) {} + struct IGeomModifierNode : public IFixedChildCountNode<1> + { + enum E_TYPE + { + ET_DISPLACEMENT, + ET_HEIGHT, + ET_NORMAL, + ET_DERIVATIVE + }; + /* + enum E_SOURCE + { + ESRC_UV_FUNCTION, + ESRC_TEXTURE + }; + */ + + IGeomModifierNode(E_TYPE t) : type(t) {} + + E_SYMBOL getSymbol() const override final { return ES_GEOM_MODIFIER; } - E_TYPE type; - //no other (than texture) source supported for now (uncomment in the future) [far future TODO] - //E_SOURCE source; - //TODO some union member for when source==ESRC_UV_FUNCTION, no idea what type - //in fact when we want to translate MDL function of (u,v) into this IR we could just create an image being a 2D plot of this function with some reasonable quantization (pixel dimensions) - //union { + E_TYPE type; + //no other (than texture) source supported for now (uncomment in the future) [far future TODO] + //TODO some union member for when source==ESRC_UV_FUNCTION, no idea what type + //in fact when we want to translate MDL function of (u,v) into this IR we could just create an image being a 2D plot of this function with some reasonable quantization (pixel dimensions) + //union { STextureSource texture; - //}; - }; + //}; + }; + using CGeomModifierNode = Finalizer; - struct CEmissionNode : INode - { - CEmissionNode() : INode(ES_EMISSION) {} + struct IOpacityNode : IFixedChildCountNode<1> // TODO: kill? and replace by blend with transmission? + { + E_SYMBOL getSymbol() const override final { return ES_OPACITY; } - color_t intensity = color_t(1.f); - }; + SParameter opacity; + }; + using COpacityNode = Finalizer; - struct COpacityNode : INode - { - COpacityNode() : INode(ES_OPACITY) {} + struct IBSDFCombinerNode + { + public: + enum E_TYPE + { + //mix of N BSDFs + ET_MIX, + //blend of 2 BSDFs weighted by constant or texture + ET_WEIGHT_BLEND, + //for support of nvidia MDL's df::fresnel_layer + ET_LOL_MDL_SUX_BROKEN_FRESNEL_BLEND, + //blend of 2 BSDFs weighted by custom direction-based curve + ET_CUSTOM_CURVE_BLEND + }; + inline E_TYPE getType() const {return type;} + + protected: + IBSDFCombinerNode(E_TYPE t) : type(t) {} + + E_TYPE type; + }; + struct IBSDFBlendNode : IFixedChildCountNode<2>, IBSDFCombinerNode + { + IBSDFBlendNode() : IBSDFCombinerNode(ET_WEIGHT_BLEND) {} - SParameter opacity; - }; + E_SYMBOL getSymbol() const override final { return ES_BSDF_COMBINER; } - struct CBSDFCombinerNode : INode - { - enum E_TYPE - { - //mix of N BSDFs - ET_MIX, - //blend of 2 BSDFs weighted by constant or texture - ET_WEIGHT_BLEND, - //for support of nvidia MDL's df::fresnel_layer - ET_LOL_MDL_SUX_BROKEN_FRESNEL_BLEND, - //blend of 2 BSDFs weighted by custom direction-based curve - ET_CUSTOM_CURVE_BLEND + SParameter weight; }; + using CBSDFBlendNode = Finalizer; + struct IBSDFMixNode : IVariableChildCountNode, IBSDFCombinerNode + { + IBSDFMixNode() : IBSDFCombinerNode(ET_MIX) {} - E_TYPE type; + E_SYMBOL getSymbol() const override final { return ES_BSDF_COMBINER; } - CBSDFCombinerNode(E_TYPE t) : INode(ES_BSDF_COMBINER), type(t) {} - }; - struct CBSDFBlendNode : CBSDFCombinerNode - { - CBSDFBlendNode() : CBSDFCombinerNode(ET_WEIGHT_BLEND) {} + static inline size_t size_of(const uint32_t childrenCount) + { + return sizeof(IBSDFMixNode)+sizeof(float)*(childrenCount-1u)+sizeof(node_handle_t)*childrenCount; + } - SParameter weight; - }; - struct CBSDFMixNode : CBSDFCombinerNode - { - CBSDFMixNode() : CBSDFCombinerNode(ET_MIX) {} + inline IBSDFMixNode& operator=(const IBSDFMixNode& other) + { + IBSDFCombinerNode::operator=(other); + std::copy_n(other.weights,other.getChildCount(),weights); + return *this; + } - float weights[MAX_CHILDREN]; - }; + float weights[1]; + }; + using CBSDFMixNode = Finalizer; - struct CBSDFNode : INode + struct IEmissionNode : ILeafNode + { + IEmissionNode() : ILeafNode() {} + + E_SYMBOL getSymbol() const override {return ES_EMISSION;} + + color_t intensity = color_t(1.f); // TODO: hoist? + }; + using CEmissionNode = Finalizer; + + struct IBSDFNode : ILeafNode { enum E_TYPE { @@ -496,124 +462,159 @@ class IR : public core::IReferenceCounted //ET_SHEEN, }; - CBSDFNode(E_TYPE t) : - INode(ES_BSDF), - type(t), - eta(1.33f), - etaK(0.f) - {} + inline IBSDFNode(E_TYPE t) : ILeafNode(), type(t) {} + + inline E_SYMBOL getSymbol() const override { return ES_BSDF; } E_TYPE type; - // TODO: why does this base class have IoR!? Diffuse inherits from this!!! - color_t eta, etaK; }; - struct CMicrofacetSpecularBSDFNode : CBSDFNode + struct IMicrofacetBSDFNode : IBSDFNode { - enum E_NDF - { - ENDF_BECKMANN, - ENDF_GGX, - ENDF_ASHIKHMIN_SHIRLEY, - ENDF_PHONG - }; - // TODO: Remove, the NDF fixes the geometrical shadowing and masking function. - enum E_SHADOWING_TERM - { - EST_SMITH, - EST_VCAVITIES - }; + using IBSDFNode::IBSDFNode; - CMicrofacetSpecularBSDFNode() : CBSDFNode(ET_MICROFACET_SPECULAR) {} - - void setSmooth(E_NDF _ndf = ENDF_GGX) + virtual void setSmooth() { - ndf = _ndf; alpha_u = 0.f; alpha_v = alpha_u; } - E_NDF ndf = ENDF_GGX; - E_SHADOWING_TERM shadowing = EST_SMITH; SParameter alpha_u = 0.f; SParameter alpha_v = 0.f; - - protected: - CMicrofacetSpecularBSDFNode(E_TYPE t) : CBSDFNode(t) {} }; - struct CMicrofacetDiffuseBxDFBase : CBSDFNode + struct IMicrofacetDiffuseBxDFBase : IMicrofacetBSDFNode { - CMicrofacetDiffuseBxDFBase(E_TYPE t) : CBSDFNode(t) {} - - void setSmooth() + IMicrofacetDiffuseBxDFBase(const E_TYPE t) : IMicrofacetBSDFNode(t) { - alpha_u = 0.f; - alpha_v = alpha_u; + assert(t == ET_MICROFACET_DIFFTRANS || t == ET_MICROFACET_DIFFUSE); } + }; + struct IMicrofacetDiffuseBSDFNode : IMicrofacetDiffuseBxDFBase + { + IMicrofacetDiffuseBSDFNode() : IMicrofacetDiffuseBxDFBase(ET_MICROFACET_DIFFUSE) {} - SParameter alpha_u = 0.f; - SParameter alpha_v = 0.f; + SParameter reflectance = color_t(1.f); // TODO: optimization, hoist Energy Loss Parameters out of BxDFs }; - struct CMicrofacetDiffuseBSDFNode : CMicrofacetDiffuseBxDFBase + using CMicrofacetDiffuseBSDFNode = Finalizer; + struct IMicrofacetDifftransBSDFNode : IMicrofacetDiffuseBxDFBase { - CMicrofacetDiffuseBSDFNode() : CMicrofacetDiffuseBxDFBase(ET_MICROFACET_DIFFUSE) {} + IMicrofacetDifftransBSDFNode() : IMicrofacetDiffuseBxDFBase(ET_MICROFACET_DIFFTRANS) {} - SParameter reflectance = color_t(1.f); + SParameter transmittance = color_t(0.5f); // TODO: optimization, hoist Energy Loss Parameters out of BxDFs }; - struct CMicrofacetDifftransBSDFNode : CMicrofacetDiffuseBxDFBase + using CMicrofacetDifftransBSDFNode = Finalizer; + struct ICookTorranceBSDFNode : IMicrofacetBSDFNode { - CMicrofacetDifftransBSDFNode() : CMicrofacetDiffuseBxDFBase(ET_MICROFACET_DIFFTRANS) {} + public: + enum E_NDF : uint8_t + { + ENDF_BECKMANN, + ENDF_GGX, + ENDF_ASHIKHMIN_SHIRLEY, + ENDF_PHONG + }; + + void setSmooth() override + { + ndf = ENDF_GGX; + } + + INode::color_t eta, etaK; + E_NDF ndf = ENDF_GGX; - SParameter transmittance = color_t(0.5f); + protected: + ICookTorranceBSDFNode(const IBSDFNode::E_TYPE t) + : IMicrofacetBSDFNode(t), eta(1.33f), etaK(0.f) {} + }; + struct IMicrofacetSpecularBSDFNode : ICookTorranceBSDFNode + { + IMicrofacetSpecularBSDFNode() : ICookTorranceBSDFNode(ET_MICROFACET_SPECULAR) {} }; - struct CMicrofacetCoatingBSDFNode : CMicrofacetSpecularBSDFNode + using CMicrofacetSpecularBSDFNode = Finalizer; + struct IMicrofacetCoatingBSDFNode : ICookTorranceBSDFNode { - CMicrofacetCoatingBSDFNode() : CMicrofacetSpecularBSDFNode(ET_MICROFACET_COATING) {} + IMicrofacetCoatingBSDFNode() : ICookTorranceBSDFNode(ET_MICROFACET_COATING) {} SParameter thicknessSigmaA; }; - struct CMicrofacetDielectricBSDFNode : CMicrofacetSpecularBSDFNode + using CMicrofacetCoatingBSDFNode = Finalizer; + struct IMicrofacetDielectricBSDFNode : ICookTorranceBSDFNode { - CMicrofacetDielectricBSDFNode() : CMicrofacetSpecularBSDFNode(ET_MICROFACET_DIELECTRIC) {} + IMicrofacetDielectricBSDFNode() : ICookTorranceBSDFNode(ET_MICROFACET_DIELECTRIC) {} + bool thin = false; }; + using CMicrofacetDielectricBSDFNode = Finalizer; - SBackingMemManager memMgr; - core::vector roots; - - core::vector tmp; - uint32_t tmpSize = 0u; - protected: - ~IR() + inline ~IR() { - //call destructors on all nodes - for (auto* root : roots) - { - core::stack s; - s.push(root); - while (!s.empty()) + deleteRange({ 0u }); + } + + + core::vector m_roots; + + + class SBackingMemManager + { + core::vector mem; + + public: + SBackingMemManager() { - auto* n = s.top(); - s.pop(); - for (auto* c : n->children) - s.push(c); + mem.reserve(0x1u<<20); + } - if (n->symbol!=INode::ES_UNINITIALIZED) - { - n->~INode(); - n->symbol = INode::ES_UNINITIALIZED; - } + inline uint8_t* data() {return const_cast(const_cast(this)->data());} + inline const uint8_t* data() const {return reinterpret_cast(mem.data());} + + inline node_handle_t alloc(size_t bytes) + { + node_handle_t retval = {getAllocatedSize()}; + mem.resize(mem.size()+bytes); + return retval; } - } - } - template - NodeType* allocNode_impl(Args&& ...args) + inline uint32_t getAllocatedSize() const + { + return static_cast(mem.size()); + } + + inline void trimBackDown(const node_handle_t _end) + { + mem.resize(_end.byteOffset); + } + }; + SBackingMemManager memMgr; + // this stuff assumes the use of a linear allocator + inline void deleteRange(node_handle_t begin) { - uint8_t* ptr = memMgr.alloc(sizeof(NodeType)); - return new (ptr) NodeType(std::forward(args)...); + for (auto offset=begin; offset.byteOffsetgetSize(); + assert(INode::alive(n)); + n->~INode(); + } + memMgr.trimBackDown(begin); } + node_handle_t firstTmp = {0u}; +}; + +} + + +namespace std +{ + +template <> +struct hash +{ + std::size_t operator()(const nbl::asset::material_compiler::IR::node_handle_t& handle) const + { + return std::hash()(handle.byteOffset); + } }; } diff --git a/include/nbl/builtin/glsl/ext/MitsubaLoader/instance_data_struct.glsl b/include/nbl/builtin/glsl/ext/MitsubaLoader/instance_data_struct.glsl index f523c81032..60afa50e31 100644 --- a/include/nbl/builtin/glsl/ext/MitsubaLoader/instance_data_struct.glsl +++ b/include/nbl/builtin/glsl/ext/MitsubaLoader/instance_data_struct.glsl @@ -1,18 +1,19 @@ #ifndef _NBL_BUILTIN_GLSL_EXT_MITSUBA_LOADER_INSTANCE_DATA_STRUCT_INCLUDED_ #define _NBL_BUILTIN_GLSL_EXT_MITSUBA_LOADER_INSTANCE_DATA_STRUCT_INCLUDED_ - -#include +#include struct nbl_glsl_ext_Mitsuba_Loader_instance_data_t { mat4x3 tform; + // TODO: remove, faster to invert in shader probably vec3 normalMatrixRow0; uint padding0; vec3 normalMatrixRow1; uint padding1; vec3 normalMatrixRow2; uint determinantSignBit; + // end of TODO nbl_glsl_MC_material_data_t material; }; diff --git a/include/nbl/builtin/glsl/material_compiler/common_invariant_declarations.glsl b/include/nbl/builtin/glsl/material_compiler/common_invariant_declarations.glsl index 62d028a206..a115359466 100644 --- a/include/nbl/builtin/glsl/material_compiler/common_invariant_declarations.glsl +++ b/include/nbl/builtin/glsl/material_compiler/common_invariant_declarations.glsl @@ -1,7 +1,6 @@ -// Copyright (C) 2020-2021 - DevSH Graphics Programming Sp. z O.O. +// Copyright (C) 2020-2022 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - #ifndef _NBL_BUILTIN_GLSL_MATERIAL_COMPILER_COMMON_INVARIANT_DECLARATIONS_INCLUDED_ #define _NBL_BUILTIN_GLSL_MATERIAL_COMPILER_COMMON_INVARIANT_DECLARATIONS_INCLUDED_ @@ -78,53 +77,8 @@ void nbl_glsl_MC_finalizeMicrofacet(inout nbl_glsl_MC_microfacet_t mf) mf.BdotH2 = mf.inner.BdotH * mf.inner.BdotH; } -#include -struct nbl_glsl_MC_oriented_material_t -{ - uvec2 emissive; - // TODO: derive/define upper bounds for instruction counts and bitpack them! - uint prefetch_offset; - uint prefetch_count; - uint instr_offset; - uint rem_pdf_count; - uint nprecomp_count; - uint genchoice_count; -}; -vec3 nbl_glsl_MC_oriented_material_t_getEmissive(in nbl_glsl_MC_oriented_material_t orientedMaterial) -{ - return nbl_glsl_decodeRGB19E7(orientedMaterial.emissive); -} -//rem'n'pdf and eval use the same instruction stream -nbl_glsl_MC_instr_stream_t nbl_glsl_MC_oriented_material_t_getEvalStream(in nbl_glsl_MC_oriented_material_t orientedMaterial) -{ - return nbl_glsl_MC_instr_stream_t( orientedMaterial.instr_offset,orientedMaterial.rem_pdf_count ); -} -nbl_glsl_MC_instr_stream_t nbl_glsl_MC_oriented_material_t_getRemAndPdfStream(in nbl_glsl_MC_oriented_material_t orientedMaterial) -{ - return nbl_glsl_MC_instr_stream_t( orientedMaterial.instr_offset,orientedMaterial.rem_pdf_count ); -} -nbl_glsl_MC_instr_stream_t nbl_glsl_MC_oriented_material_t_getGenChoiceStream(in nbl_glsl_MC_oriented_material_t orientedMaterial) -{ - return nbl_glsl_MC_instr_stream_t( orientedMaterial.instr_offset+orientedMaterial.rem_pdf_count,orientedMaterial.genchoice_count ); -} -nbl_glsl_MC_instr_stream_t nbl_glsl_MC_oriented_material_t_getTexPrefetchStream(in nbl_glsl_MC_oriented_material_t orientedMaterial) -{ - return nbl_glsl_MC_instr_stream_t( orientedMaterial.prefetch_offset,orientedMaterial.prefetch_count ); -} -nbl_glsl_MC_instr_stream_t nbl_glsl_MC_oriented_material_t_getNormalPrecompStream(in nbl_glsl_MC_oriented_material_t orientedMaterial) -{ - return nbl_glsl_MC_instr_stream_t( orientedMaterial.instr_offset+orientedMaterial.rem_pdf_count+orientedMaterial.genchoice_count,orientedMaterial.nprecomp_count ); -} +#include -struct nbl_glsl_MC_material_data_t -{ - nbl_glsl_MC_oriented_material_t front; - nbl_glsl_MC_oriented_material_t back; -}; -nbl_glsl_MC_oriented_material_t nbl_glsl_MC_material_data_t_getOriented(in nbl_glsl_MC_material_data_t material, in bool frontface) -{ - return frontface ? material.front:material.back; -} #endif \ No newline at end of file diff --git a/include/nbl/builtin/glsl/material_compiler/material_data.glsl b/include/nbl/builtin/glsl/material_compiler/material_data.glsl new file mode 100644 index 0000000000..09f8ecdaa0 --- /dev/null +++ b/include/nbl/builtin/glsl/material_compiler/material_data.glsl @@ -0,0 +1,24 @@ +// Copyright (C) 2020-2022 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h +#ifndef _NBL_BUILTIN_GLSL_MATERIAL_COMPILER_MATERIAL_DATA_INCLUDED_ +#define _NBL_BUILTIN_GLSL_MATERIAL_COMPILER_MATERIAL_DATA_INCLUDED_ + + +#include + + +struct nbl_glsl_MC_material_data_t +{ + nbl_glsl_MC_oriented_material_t front; + nbl_glsl_MC_oriented_material_t back; +}; + +#ifndef __cplusplus +nbl_glsl_MC_oriented_material_t nbl_glsl_MC_material_data_t_getOriented(in nbl_glsl_MC_material_data_t material, in bool frontface) +{ + return frontface ? material.front:material.back; +} +#endif + +#endif \ No newline at end of file diff --git a/include/nbl/builtin/glsl/material_compiler/oriented_material.glsl b/include/nbl/builtin/glsl/material_compiler/oriented_material.glsl new file mode 100644 index 0000000000..e713e4756e --- /dev/null +++ b/include/nbl/builtin/glsl/material_compiler/oriented_material.glsl @@ -0,0 +1,48 @@ +// Copyright (C) 2020-2022 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h +#ifndef _NBL_BUILTIN_GLSL_MATERIAL_COMPILER_ORIENTED_MATERIAL_INCLUDED_ +#define _NBL_BUILTIN_GLSL_MATERIAL_COMPILER_ORIENTED_MATERIAL_INCLUDED_ + +struct nbl_glsl_MC_oriented_material_t +{ + uvec2 emissive; + // TODO: derive/define upper bounds for instruction counts and bitpack them! + uint prefetch_offset; + uint prefetch_count; + uint instr_offset; + uint rem_pdf_count; + uint nprecomp_count; + uint genchoice_count; +}; + +#ifndef __cplusplus +#include +vec3 nbl_glsl_MC_oriented_material_t_getEmissive(in nbl_glsl_MC_oriented_material_t orientedMaterial) +{ + return nbl_glsl_decodeRGB19E7(orientedMaterial.emissive); +} +//rem'n'pdf and eval use the same instruction stream +nbl_glsl_MC_instr_stream_t nbl_glsl_MC_oriented_material_t_getEvalStream(in nbl_glsl_MC_oriented_material_t orientedMaterial) +{ + return nbl_glsl_MC_instr_stream_t( orientedMaterial.instr_offset,orientedMaterial.rem_pdf_count ); +} +nbl_glsl_MC_instr_stream_t nbl_glsl_MC_oriented_material_t_getRemAndPdfStream(in nbl_glsl_MC_oriented_material_t orientedMaterial) +{ + return nbl_glsl_MC_instr_stream_t( orientedMaterial.instr_offset,orientedMaterial.rem_pdf_count ); +} +nbl_glsl_MC_instr_stream_t nbl_glsl_MC_oriented_material_t_getGenChoiceStream(in nbl_glsl_MC_oriented_material_t orientedMaterial) +{ + return nbl_glsl_MC_instr_stream_t( orientedMaterial.instr_offset+orientedMaterial.rem_pdf_count,orientedMaterial.genchoice_count ); +} +nbl_glsl_MC_instr_stream_t nbl_glsl_MC_oriented_material_t_getTexPrefetchStream(in nbl_glsl_MC_oriented_material_t orientedMaterial) +{ + return nbl_glsl_MC_instr_stream_t( orientedMaterial.prefetch_offset,orientedMaterial.prefetch_count ); +} +nbl_glsl_MC_instr_stream_t nbl_glsl_MC_oriented_material_t_getNormalPrecompStream(in nbl_glsl_MC_oriented_material_t orientedMaterial) +{ + return nbl_glsl_MC_instr_stream_t( orientedMaterial.instr_offset+orientedMaterial.rem_pdf_count+orientedMaterial.genchoice_count,orientedMaterial.nprecomp_count ); +} +#endif + +#endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CElementBSDF.h b/include/nbl/ext/MitsubaLoader/CElementBSDF.h index 060ace88fb..456cbcbc94 100644 --- a/include/nbl/ext/MitsubaLoader/CElementBSDF.h +++ b/include/nbl/ext/MitsubaLoader/CElementBSDF.h @@ -1,19 +1,13 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __C_ELEMENT_BSDF_H_INCLUDED__ -#define __C_ELEMENT_BSDF_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_BSDF_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_BSDF_H_INCLUDED_ #include "nbl/ext/MitsubaLoader/CElementTexture.h" -namespace nbl -{ -namespace ext +namespace nbl::ext::MitsubaLoader { -namespace MitsubaLoader -{ - class CElementBSDF : public IElement { @@ -415,10 +409,6 @@ class CElementBSDF : public IElement }; }; - - -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CElementEmitter.h b/include/nbl/ext/MitsubaLoader/CElementEmitter.h index edfa792acd..9527d4072d 100644 --- a/include/nbl/ext/MitsubaLoader/CElementEmitter.h +++ b/include/nbl/ext/MitsubaLoader/CElementEmitter.h @@ -1,20 +1,15 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h +#ifndef _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_EMITTER_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_EMITTER_H_INCLUDED_ -#ifndef __C_ELEMENT_EMITTER_H_INCLUDED__ -#define __C_ELEMENT_EMITTER_H_INCLUDED__ - +#include "vectorSIMD.h" #include -#include "vectorSIMD.h" #include "nbl/ext/MitsubaLoader/CElementTexture.h" -namespace nbl -{ -namespace ext -{ -namespace MitsubaLoader +namespace nbl::ext::MitsubaLoader { @@ -288,10 +283,6 @@ class CElementEmitter : public IElement }; }; - - -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CElementFactory.h b/include/nbl/ext/MitsubaLoader/CElementFactory.h index 7543504b1d..86b7800aae 100644 --- a/include/nbl/ext/MitsubaLoader/CElementFactory.h +++ b/include/nbl/ext/MitsubaLoader/CElementFactory.h @@ -1,19 +1,14 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __I_ELEMENT_FACTORY_H_INCLUDED__ -#define __I_ELEMENT_FACTORY_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_FACTORY_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_FACTORY_H_INCLUDED_ #include "nbl/ext/MitsubaLoader/CElementSensor.h" #include "nbl/ext/MitsubaLoader/CElementIntegrator.h" #include "nbl/ext/MitsubaLoader/CElementShape.h" -namespace nbl -{ -namespace ext -{ -namespace MitsubaLoader +namespace nbl::ext::MitsubaLoader { class ParserManager; @@ -33,9 +28,6 @@ class CElementFactory static return_type processRef(const char** _atts, ParserManager* _util); }; - -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CElementFilm.h b/include/nbl/ext/MitsubaLoader/CElementFilm.h index 2a1ff38d14..8aabd8cfbb 100644 --- a/include/nbl/ext/MitsubaLoader/CElementFilm.h +++ b/include/nbl/ext/MitsubaLoader/CElementFilm.h @@ -1,21 +1,17 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h +#ifndef _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_FILM_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_FILM_H_INCLUDED_ -#ifndef __C_ELEMENT_FILM_H_INCLUDED__ -#define __C_ELEMENT_FILM_H_INCLUDED__ #include "nbl/macros.h" #include "nbl/ext/MitsubaLoader/CElementRFilter.h" -namespace nbl -{ -namespace ext -{ -namespace MitsubaLoader -{ +namespace nbl::ext::MitsubaLoader +{ class CElementFilm : public IElement { @@ -144,9 +140,6 @@ class CElementFilm : public IElement float envmapRegularizationFactor = 0.5f; // 1.0f means based envmap luminance, 0.0f means uniform }; - -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CElementIntegrator.h b/include/nbl/ext/MitsubaLoader/CElementIntegrator.h index dd76b79124..c08fe01ddc 100644 --- a/include/nbl/ext/MitsubaLoader/CElementIntegrator.h +++ b/include/nbl/ext/MitsubaLoader/CElementIntegrator.h @@ -1,19 +1,13 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __C_ELEMENT_INTEGRATOR_H_INCLUDED__ -#define __C_ELEMENT_INTEGRATOR_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_INTEGRATOR_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_INTEGRATOR_H_INCLUDED_ #include "nbl/ext/MitsubaLoader/IElement.h" -namespace nbl -{ -namespace ext +namespace nbl::ext::MitsubaLoader { -namespace MitsubaLoader -{ - class CElementIntegrator : public IElement { @@ -332,10 +326,6 @@ class CElementIntegrator : public IElement }; }; - - -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CElementRFilter.h b/include/nbl/ext/MitsubaLoader/CElementRFilter.h index 775a2c69d4..98b2525191 100644 --- a/include/nbl/ext/MitsubaLoader/CElementRFilter.h +++ b/include/nbl/ext/MitsubaLoader/CElementRFilter.h @@ -1,22 +1,15 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __C_ELEMENT_R_FILTER_H_INCLUDED__ -#define __C_ELEMENT_R_FILTER_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_R_FILTER_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_R_FILTER_H_INCLUDED_ #include "nbl/ext/MitsubaLoader/PropertyElement.h" - #include "nbl/ext/MitsubaLoader/IElement.h" -namespace nbl -{ -namespace ext -{ -namespace MitsubaLoader +namespace nbl::ext::MitsubaLoader { - class CElementRFilter : public IElement { public: @@ -66,9 +59,6 @@ class CElementRFilter : public IElement }; }; - -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CElementSampler.h b/include/nbl/ext/MitsubaLoader/CElementSampler.h index 621623770d..a574141455 100644 --- a/include/nbl/ext/MitsubaLoader/CElementSampler.h +++ b/include/nbl/ext/MitsubaLoader/CElementSampler.h @@ -1,17 +1,12 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __C_ELEMENT_SAMPLER_H_INCLUDED__ -#define __C_ELEMENT_SAMPLER_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_SAMPLER_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_SAMPLER_H_INCLUDED_ #include "nbl/ext/MitsubaLoader/IElement.h" -namespace nbl -{ -namespace ext -{ -namespace MitsubaLoader +namespace nbl::ext::MitsubaLoader { class CGlobalMitsubaMetadata; @@ -48,9 +43,6 @@ class CElementSampler : public IElement }; }; - -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CElementSensor.h b/include/nbl/ext/MitsubaLoader/CElementSensor.h index b18f8d9b59..f1567aa5c4 100644 --- a/include/nbl/ext/MitsubaLoader/CElementSensor.h +++ b/include/nbl/ext/MitsubaLoader/CElementSensor.h @@ -1,24 +1,17 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __C_ELEMENT_SENSOR_H_INCLUDED__ -#define __C_ELEMENT_SENSOR_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_SENSOR_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_SENSOR_H_INCLUDED_ #include "nbl/ext/MitsubaLoader/IElement.h" #include "nbl/ext/MitsubaLoader/CElementTransform.h" #include "nbl/ext/MitsubaLoader/CElementFilm.h" #include "nbl/ext/MitsubaLoader/CElementSampler.h" - -namespace nbl -{ -namespace ext -{ -namespace MitsubaLoader +namespace nbl::ext::MitsubaLoader { - class CElementSensor : public IElement { public: @@ -218,9 +211,6 @@ class CElementSensor : public IElement CElementSampler sampler; }; - -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CElementShape.h b/include/nbl/ext/MitsubaLoader/CElementShape.h index 205023afea..8aeb2bfc18 100644 --- a/include/nbl/ext/MitsubaLoader/CElementShape.h +++ b/include/nbl/ext/MitsubaLoader/CElementShape.h @@ -1,24 +1,17 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __C_ELEMENT_SHAPE_H_INCLUDED__ -#define __C_ELEMENT_SHAPE_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_SHAPE_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_SHAPE_H_INCLUDED_ #include "nbl/ext/MitsubaLoader/IElement.h" #include "nbl/ext/MitsubaLoader/CElementTransform.h" #include "nbl/ext/MitsubaLoader/CElementBSDF.h" #include "nbl/ext/MitsubaLoader/CElementEmitter.h" - -namespace nbl -{ -namespace ext -{ -namespace MitsubaLoader +namespace nbl::ext::MitsubaLoader { - class CElementShape : public IElement { public: @@ -279,9 +272,6 @@ class CElementShape : public IElement CElementEmitter*emitter; }; - -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CElementTexture.h b/include/nbl/ext/MitsubaLoader/CElementTexture.h index 1a6385cb49..efbe474288 100644 --- a/include/nbl/ext/MitsubaLoader/CElementTexture.h +++ b/include/nbl/ext/MitsubaLoader/CElementTexture.h @@ -1,20 +1,14 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __C_ELEMENT_TEXTURE_H_INCLUDED__ -#define __C_ELEMENT_TEXTURE_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_TEXTURE_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_TEXTURE_H_INCLUDED_ #include "nbl/ext/MitsubaLoader/PropertyElement.h" #include "nbl/ext/MitsubaLoader/IElement.h" -namespace nbl -{ -namespace ext +namespace nbl::ext::MitsubaLoader { -namespace MitsubaLoader -{ - class CElementTexture : public IElement { @@ -255,10 +249,6 @@ class CElementTexture : public IElement }; }; - - -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CElementTransform.h b/include/nbl/ext/MitsubaLoader/CElementTransform.h index d518f69e6c..ecf75831b3 100644 --- a/include/nbl/ext/MitsubaLoader/CElementTransform.h +++ b/include/nbl/ext/MitsubaLoader/CElementTransform.h @@ -1,21 +1,14 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __C_ELEMENT_TRANSFORM_H_INCLUDED__ -#define __C_ELEMENT_TRANSFORM_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_TRANSFORM_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_ELEMENT_TRANSFORM_H_INCLUDED_ #include "nbl/ext/MitsubaLoader/IElement.h" - -namespace nbl -{ -namespace ext -{ -namespace MitsubaLoader +namespace nbl::ext::MitsubaLoader { - class CElementTransform : public IElement { public: @@ -38,8 +31,6 @@ class CElementTransform : public IElement core::matrix4SIMD matrix; }; -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CMaterialCompilerFrontend.h b/include/nbl/ext/MitsubaLoader/CMaterialCompilerFrontend.h new file mode 100644 index 0000000000..899c200731 --- /dev/null +++ b/include/nbl/ext/MitsubaLoader/CMaterialCompilerFrontend.h @@ -0,0 +1,79 @@ +// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h +#ifndef _NBL_EXT_MITSUBA_LOADER_C_MATERIAL_COMPILER_FRONTEND_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_MATERIAL_COMPILER_FRONTEND_H_INCLUDED_ + +#include "nbl/core/Types.h" + +#include "nbl/asset/material_compiler/IR.h" + +#include "nbl/ext/MitsubaLoader/CElementBSDF.h" + +namespace nbl::ext::MitsubaLoader +{ + +struct SContext; + +class CMaterialCompilerFrontend final +{ + public: + using node_handle_t = asset::material_compiler::IR::node_handle_t; + enum E_IMAGE_VIEW_SEMANTIC : uint8_t + { + EIVS_IDENTITIY, + EIVS_BLEND_WEIGHT, + EIVS_NORMAL_MAP, + EIVS_BUMP_MAP, + EIVS_COUNT + }; + + // TODO: embed hash val in the element for speed + struct MerkleTree + { + const CElementBSDF* bsdf; + bool frontface; + + struct hash + { + std::size_t operator()(const MerkleTree& node) const; + }; + struct equal_to + { + bool operator()(const MerkleTree& lhs, const MerkleTree& rhs) const; + }; + }; + using HashCons = core::unordered_map; + + struct front_and_back_t + { + node_handle_t front; + node_handle_t back; + }; + static front_and_back_t compileToIRTree(SContext& ctx, const CElementBSDF* _root); + + private: + static bool unwindTwosided(const CElementBSDF* &bsdf) + { + const auto orig_bsdf = bsdf; + while (bsdf->type==CElementBSDF::TWO_SIDED) + { + // sanity checks + static_assert(bsdf->twosided.MaxChildCount == 1); + assert(bsdf->meta_common.childCount==1); + assert(bsdf->twosided.childCount==1); + + bsdf = bsdf->meta_common.bsdf[0]; + } + return bsdf!=orig_bsdf; + } + static node_handle_t createIRNode(SContext& ctx, const CElementBSDF* _bsdf, const bool frontface); + + using tex_ass_type = std::tuple, core::smart_refctd_ptr, float>; + static tex_ass_type getTexture(const SContext& _loaderContext, const CElementTexture* _element, const E_IMAGE_VIEW_SEMANTIC semantic=EIVS_IDENTITIY); + static tex_ass_type getErrorTexture(const SContext& _loaderContext); +}; + +} + +#endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CMitsubaLoader.h b/include/nbl/ext/MitsubaLoader/CMitsubaLoader.h index 3f70d2f9c6..9ac6533a04 100644 --- a/include/nbl/ext/MitsubaLoader/CMitsubaLoader.h +++ b/include/nbl/ext/MitsubaLoader/CMitsubaLoader.h @@ -1,9 +1,8 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __C_MITSUBA_LOADER_H_INCLUDED__ -#define __C_MITSUBA_LOADER_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_C_MITSUBA_LOADER_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_MITSUBA_LOADER_H_INCLUDED_ #include "nbl/asset/asset.h" @@ -19,51 +18,56 @@ namespace nbl::ext::MitsubaLoader { - -class CElementBSDF; -class CMitsubaMaterialCompilerFrontend; - - -// TODO: we need a GLSL to C++ compatibility wrapper -//#include "nbl/builtin/glsl/ext/MitsubaLoader/instance_data_struct.glsl" +namespace impl +{ #define uint uint32_t #define uvec2 uint64_t #define mat4x3 nbl::core::matrix3x4SIMD -#define nbl_glsl_MC_material_data_t asset::material_compiler::material_data_t -struct nbl_glsl_ext_Mitsuba_Loader_instance_data_t +#define nbl_glsl_MC_material_data_t asset::material_compiler::impl::nbl_glsl_MC_material_data_t +struct vec3 { - struct vec3 - { - float x, y, z; - }; - mat4x3 tform; - vec3 normalMatrixRow0; - uint padding0; - vec3 normalMatrixRow1; - uint padding1; - vec3 normalMatrixRow2; - uint determinantSignBit; - nbl_glsl_MC_material_data_t material; + float x, y, z; }; +#include #undef uint #undef uvec2 #undef mat4x3 #undef nbl_glsl_MC_material_data_t -using instance_data_t = nbl_glsl_ext_Mitsuba_Loader_instance_data_t; +} + +class CElementBSDF; +class CMaterialCompilerFrontend; class CMitsubaLoader : public asset::IRenderpassIndependentPipelineLoader { friend class CMitsubaMaterialCompilerFrontend; + public: + using instance_data_t = impl::nbl_glsl_ext_Mitsuba_Loader_instance_data_t; //! Constructor CMitsubaLoader(asset::IAssetManager* _manager, io::IFileSystem* _fs); void initialize() override; - protected: - io::IFileSystem* m_filesystem; + //! Check if the file might be loaded by this class + /** Check might look into the file. + \param file File handle to check. + \return True if file seems to be loadable. */ + bool isALoadableFileFormat(io::IReadFile* _file) const override; + + //! Returns an array of string literals terminated by nullptr + const char** getAssociatedFileExtensions() const override; + + //! Returns the assets loaded by the loader + /** Bits of the returned value correspond to each IAsset::E_TYPE + enumeration member, and the return value cannot be 0. */ + uint64_t getSupportedAssetTypesBitfield() const override { return asset::IAsset::ET_MESH/*|asset::IAsset::ET_SCENE|asset::IAsset::ET_IMPLEMENTATION_SPECIFIC_METADATA*/; } + //! Loads an asset from an opened file, returns nullptr in case of failure. + asset::SAssetBundle loadAsset(io::IReadFile* _file, const asset::IAssetLoader::SAssetLoadParams& _params, asset::IAssetLoader::IAssetLoaderOverride* _override = nullptr, uint32_t _hierarchyLevel = 0u) override; + + protected: //! Destructor virtual ~CMitsubaLoader() = default; @@ -74,31 +78,17 @@ class CMitsubaLoader : public asset::IRenderpassIndependentPipelineLoader core::vector loadShapeGroup(SContext& ctx, uint32_t hierarchyLevel, const CElementShape::ShapeGroup* shapegroup, const core::matrix3x4SIMD& relTform); SContext::shape_ass_type loadBasicShape(SContext& ctx, uint32_t hierarchyLevel, CElementShape* shape, const core::matrix3x4SIMD& relTform); - void cacheTexture(SContext& ctx, uint32_t hierarchyLevel, const CElementTexture* texture, const CMitsubaMaterialCompilerFrontend::E_IMAGE_VIEW_SEMANTIC semantic); + void cacheTexture(SContext& ctx, uint32_t hierarchyLevel, const CElementTexture* texture, const CMaterialCompilerFrontend::E_IMAGE_VIEW_SEMANTIC semantic); SContext::bsdf_type getBSDFtreeTraversal(SContext& ctx, const CElementBSDF* bsdf); SContext::bsdf_type genBSDFtreeTraversal(SContext& ctx, const CElementBSDF* bsdf); template - core::smart_refctd_ptr createDS0(const SContext& _ctx, asset::ICPUPipelineLayout* _layout, const asset::material_compiler::CMaterialCompilerGLSLBackendCommon::result_t& _compResult, Iter meshBegin, Iter meshEnd); + core::smart_refctd_ptr createDS0(const SContext& _ctx, asset::ICPUPipelineLayout* _layout, const asset::material_compiler::CGLSLBackendCommon::result_t& _compResult, Iter meshBegin, Iter meshEnd); - public: - //! Check if the file might be loaded by this class - /** Check might look into the file. - \param file File handle to check. - \return True if file seems to be loadable. */ - bool isALoadableFileFormat(io::IReadFile* _file) const override; - //! Returns an array of string literals terminated by nullptr - const char** getAssociatedFileExtensions() const override; - - //! Returns the assets loaded by the loader - /** Bits of the returned value correspond to each IAsset::E_TYPE - enumeration member, and the return value cannot be 0. */ - uint64_t getSupportedAssetTypesBitfield() const override { return asset::IAsset::ET_MESH/*|asset::IAsset::ET_SCENE|asset::IAsset::ET_IMPLEMENTATION_SPECIFIC_METADATA*/; } - - //! Loads an asset from an opened file, returns nullptr in case of failure. - asset::SAssetBundle loadAsset(io::IReadFile* _file, const asset::IAssetLoader::SAssetLoadParams& _params, asset::IAssetLoader::IAssetLoaderOverride* _override = nullptr, uint32_t _hierarchyLevel = 0u) override; + // members + io::IFileSystem* m_filesystem; }; } diff --git a/include/nbl/ext/MitsubaLoader/CMitsubaMaterialCompilerFrontend.h b/include/nbl/ext/MitsubaLoader/CMitsubaMaterialCompilerFrontend.h deleted file mode 100644 index f92399f813..0000000000 --- a/include/nbl/ext/MitsubaLoader/CMitsubaMaterialCompilerFrontend.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. -// This file is part of the "Nabla Engine". -// For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __C_MITSUBA_MATERIAL_COMPILER_FRONTEND_H_INCLUDED__ -#define __C_MITSUBA_MATERIAL_COMPILER_FRONTEND_H_INCLUDED__ - -#include "nbl/core/Types.h" - -#include "nbl/asset/material_compiler/IR.h" - -#include "nbl/ext/MitsubaLoader/CElementBSDF.h" - -namespace nbl::ext::MitsubaLoader -{ - -struct SContext; - -class CMitsubaMaterialCompilerFrontend -{ - public: - using IRNode = asset::material_compiler::IR::INode; - enum E_IMAGE_VIEW_SEMANTIC : uint8_t - { - EIVS_IDENTITIY, - EIVS_BLEND_WEIGHT, - EIVS_NORMAL_MAP, - EIVS_BUMP_MAP, - EIVS_COUNT - }; - - struct front_and_back_t - { - IRNode* front; - IRNode* back; - }; - - explicit CMitsubaMaterialCompilerFrontend(const SContext* _ctx) : m_loaderContext(_ctx) {} - - front_and_back_t compileToIRTree(asset::material_compiler::IR* ir, const CElementBSDF* _bsdf); - - private: - using tex_ass_type = std::tuple,core::smart_refctd_ptr,float>; - - const SContext* m_loaderContext; - - std::pair unwindTextureScale(const CElementTexture* _element) const; - - tex_ass_type getTexture(const CElementTexture* _element, const E_IMAGE_VIEW_SEMANTIC semantic=EIVS_IDENTITIY) const; - - tex_ass_type getErrorTexture() const; - - IRNode* createIRNode(asset::material_compiler::IR* ir, const CElementBSDF* _bsdf); -}; - -} - -#endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CMitsubaMetadata.h b/include/nbl/ext/MitsubaLoader/CMitsubaMetadata.h index 087d59b772..99512026a2 100644 --- a/include/nbl/ext/MitsubaLoader/CMitsubaMetadata.h +++ b/include/nbl/ext/MitsubaLoader/CMitsubaMetadata.h @@ -1,9 +1,8 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __NBL_C_MITSUBA_METADATA_H_INCLUDED__ -#define __NBL_C_MITSUBA_METADATA_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_C_MITSUBA_METADATA_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_MITSUBA_METADATA_H_INCLUDED_ #include "nbl/core/compile_config.h" #include "nbl/asset/metadata/IAssetMetadata.h" @@ -15,15 +14,10 @@ #include "nbl/ext/MitsubaLoader/CElementSensor.h" #include "nbl/ext/MitsubaLoader/CElementShape.h" -namespace nbl -{ -namespace ext -{ -namespace MitsubaLoader +namespace nbl::ext::MitsubaLoader { //! A class to derive mitsuba mesh loader metadata objects from - class CMitsubaMetadata : public asset::IAssetMetadata { public: @@ -76,7 +70,7 @@ class CMitsubaMetadata : public asset::IAssetMetadata CElementEmitter frontEmitter; // type is invalid if not used CElementEmitter backEmitter; // type is invalid if not used - CMitsubaMaterialCompilerFrontend::front_and_back_t bsdf; + CMaterialCompilerFrontend::front_and_back_t bsdf; }; core::SRange m_instanceAuxData; @@ -109,7 +103,7 @@ class CMitsubaMetadata : public asset::IAssetMetadata { } - _NBL_STATIC_INLINE_CONSTEXPR const char* LoaderName = "ext::MitsubaLoader::CMitsubaLoader"; + static inline constexpr char* LoaderName = "ext::MitsubaLoader::CMitsubaLoader"; const char* getLoaderName() const override { return LoaderName; } //! @@ -203,8 +197,6 @@ class CMitsubaMetadata : public asset::IAssetMetadata } }; -} -} } #endif diff --git a/include/nbl/ext/MitsubaLoader/CMitsubaSerializedMetadata.h b/include/nbl/ext/MitsubaLoader/CMitsubaSerializedMetadata.h index 7be0bb89d6..69160ea63b 100644 --- a/include/nbl/ext/MitsubaLoader/CMitsubaSerializedMetadata.h +++ b/include/nbl/ext/MitsubaLoader/CMitsubaSerializedMetadata.h @@ -1,19 +1,14 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __NBL_C_MITSUBA_SERIALIZED_PIPELINE_METADATA_H_INCLUDED__ -#define __NBL_C_MITSUBA_SERIALIZED_PIPELINE_METADATA_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_C_SERIALIZED_PIPELINE_METADATA_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_SERIALIZED_PIPELINE_METADATA_H_INCLUDED_ #include "nbl/asset/ICPURenderpassIndependentPipeline.h" #include "nbl/asset/ICPUMesh.h" #include "nbl/asset/metadata/IAssetMetadata.h" -namespace nbl -{ -namespace ext -{ -namespace MitsubaLoader +namespace nbl::ext::MitsubaLoader { class CMitsubaSerializedMetadata final : public asset::IAssetMetadata @@ -81,8 +76,6 @@ class CMitsubaSerializedMetadata final : public asset::IAssetMetadata } }; -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/CSerializedLoader.h b/include/nbl/ext/MitsubaLoader/CSerializedLoader.h index 4a6a0fedc6..e67fab6e1c 100644 --- a/include/nbl/ext/MitsubaLoader/CSerializedLoader.h +++ b/include/nbl/ext/MitsubaLoader/CSerializedLoader.h @@ -1,17 +1,12 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __C_SERIALIZED_LOADER_H_INCLUDED__ -#define __C_SERIALIZED_LOADER_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_C_SERIALIZED_LOADER_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_C_SERIALIZED_LOADER_H_INCLUDED_ #include "nbl/asset/asset.h" -namespace nbl -{ -namespace ext -{ -namespace MitsubaLoader +namespace nbl::ext::MitsubaLoader { //! Meshloader capable of loading obj meshes. @@ -70,9 +65,6 @@ class CSerializedLoader final : public asset::IRenderpassIndependentPipelineLoad }; }; - -} -} } #endif diff --git a/include/nbl/ext/MitsubaLoader/IElement.h b/include/nbl/ext/MitsubaLoader/IElement.h index 47d8b43543..f80212410f 100644 --- a/include/nbl/ext/MitsubaLoader/IElement.h +++ b/include/nbl/ext/MitsubaLoader/IElement.h @@ -1,19 +1,13 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __I_ELEMENT_H_INCLUDED__ -#define __I_ELEMENT_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_I_ELEMENT_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_I_ELEMENT_H_INCLUDED_ #include "nbl/asset/interchange/IAssetLoader.h" #include "nbl/ext/MitsubaLoader/PropertyElement.h" - -namespace nbl -{ -namespace ext -{ -namespace MitsubaLoader +namespace nbl::ext::MitsubaLoader { @@ -42,7 +36,7 @@ class IElement TRANSFORM, ANIMATION }; - public: + std::string id; IElement(const char* _id) : id(_id ? _id:"") {} @@ -111,8 +105,6 @@ class IElement } }; -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/ParserUtil.h b/include/nbl/ext/MitsubaLoader/ParserUtil.h index 967e8bf17b..c1249fd3b4 100644 --- a/include/nbl/ext/MitsubaLoader/ParserUtil.h +++ b/include/nbl/ext/MitsubaLoader/ParserUtil.h @@ -1,9 +1,8 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __I_PARSER_UTIL_H_INCLUDED__ -#define __I_PARSER_UTIL_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_I_PARSER_UTIL_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_I_PARSER_UTIL_H_INCLUDED_ #include "nbl/core/core.h" @@ -19,23 +18,15 @@ #include -namespace nbl -{ -namespace ext +namespace nbl::ext::MitsubaLoader { -namespace MitsubaLoader -{ - - -class ParserLog +struct ParserLog { -public: /*prints this message: Mitsuba loader error: Invalid .xml file structure: message */ static void invalidXMLFileStructure(const std::string& errorMessage); - }; @@ -127,8 +118,6 @@ class ParserManager friend class CElementFactory; }; -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/PropertyElement.h b/include/nbl/ext/MitsubaLoader/PropertyElement.h index 138d36fa0b..256bbe4d5d 100644 --- a/include/nbl/ext/MitsubaLoader/PropertyElement.h +++ b/include/nbl/ext/MitsubaLoader/PropertyElement.h @@ -1,19 +1,15 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __PROPERTY_ELEMENT_H_INCLUDED__ -#define __PROPERTY_ELEMENT_H_INCLUDED__ +#ifndef _NBL_EXT_MITSUBA_LOADER_PROPERTY_ELEMENT_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_PROPERTY_ELEMENT_H_INCLUDED_ #include "nbl/core/core.h" #include "matrix4SIMD.h" + #include -namespace nbl -{ -namespace ext -{ -namespace MitsubaLoader +namespace nbl::ext::MitsubaLoader { struct SPropertyElementData @@ -317,8 +313,6 @@ class CPropertyElementManager }; -} -} } #endif \ No newline at end of file diff --git a/include/nbl/ext/MitsubaLoader/SContext.h b/include/nbl/ext/MitsubaLoader/SContext.h index 6bf41176d3..c7a34863e4 100644 --- a/include/nbl/ext/MitsubaLoader/SContext.h +++ b/include/nbl/ext/MitsubaLoader/SContext.h @@ -1,253 +1,247 @@ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h - -#ifndef __C_MITSUBA_LOADER_CONTEXT_H_INCLUDED__ -#define __C_MITSUBA_LOADER_CONTEXT_H_INCLUDED__ - +#ifndef _NBL_EXT_MITSUBA_LOADER_S_CONTEXT_H_INCLUDED_ +#define _NBL_EXT_MITSUBA_LOADER_S_CONTEXT_H_INCLUDED_ #include "nbl/asset/ICPUMesh.h" #include "nbl/asset/utils/IGeometryCreator.h" -#include "nbl/asset/material_compiler/CMaterialCompilerGLSLRasterBackend.h" +#include "nbl/asset/material_compiler/CGLSLRasterBackend.h" -#include "nbl/ext/MitsubaLoader/CMitsubaMaterialCompilerFrontend.h" +#include "nbl/ext/MitsubaLoader/CMaterialCompilerFrontend.h" #include "nbl/ext/MitsubaLoader/CElementShape.h" -namespace nbl +namespace nbl::ext::MitsubaLoader { -namespace ext -{ -namespace MitsubaLoader + +struct SContext { + SContext( + const asset::IGeometryCreator* _geomCreator, + const asset::IMeshManipulator* _manipulator, + const asset::IAssetLoader::SAssetLoadContext& _params, + asset::IAssetLoader::IAssetLoaderOverride* _override, + CMitsubaMetadata* _metadata + ); + + const asset::IGeometryCreator* creator; + const asset::IMeshManipulator* manipulator; + const asset::IAssetLoader::SAssetLoadContext inner; + asset::IAssetLoader::IAssetLoaderOverride* override_; + CMitsubaMetadata* meta; + + static inline constexpr uint32_t VT_PAGE_SZ_LOG2 = 7u;//128 + static inline constexpr uint32_t VT_PHYSICAL_PAGE_TEX_TILES_PER_DIM_LOG2 = 4u;//16 + static inline constexpr uint32_t VT_PAGE_PADDING = 8u; + static inline constexpr uint32_t VT_MAX_ALLOCATABLE_TEX_SZ_LOG2 = 12u;//4096 + + // + using group_ass_type = core::vector>; + //core::map groupCache; + // + using shape_ass_type = core::smart_refctd_ptr; + core::map shapeCache; + //image, sampler + using tex_ass_type = std::tuple,core::smart_refctd_ptr>; + //image, scale + core::map,float> derivMapCache; + + // + static std::string imageViewCacheKey(const CElementTexture::Bitmap& bitmap, const CMaterialCompilerFrontend::E_IMAGE_VIEW_SEMANTIC semantic) + { + std::string key = bitmap.filename.svalue; + switch (bitmap.channel) + { + case CElementTexture::Bitmap::CHANNEL::R: + key += "?rrrr"; + break; + case CElementTexture::Bitmap::CHANNEL::G: + key += "?gggg"; + break; + case CElementTexture::Bitmap::CHANNEL::B: + key += "?bbbb"; + break; + case CElementTexture::Bitmap::CHANNEL::A: + key += "?aaaa"; + break; + default: + break; + } + switch (semantic) + { + case CMaterialCompilerFrontend::EIVS_BLEND_WEIGHT: + key += "?blend"; + break; + case CMaterialCompilerFrontend::EIVS_NORMAL_MAP: + key += "?deriv?n"; + break; + case CMaterialCompilerFrontend::EIVS_BUMP_MAP: + key += "?deriv?h"; + { + static const char* wrap[5] + { + "?repeat", + "?mirror", + "?clamp", + "?zero", + "?one" + }; + key += wrap[bitmap.wrapModeU]; + key += wrap[bitmap.wrapModeV]; + } + break; + default: + break; + } + key += "?view"; + return key; + } - struct SContext + static auto computeSamplerParameters(const CElementTexture::Bitmap& bitmap) { - SContext( - const asset::IGeometryCreator* _geomCreator, - const asset::IMeshManipulator* _manipulator, - const asset::IAssetLoader::SAssetLoadContext& _params, - asset::IAssetLoader::IAssetLoaderOverride* _override, - CMitsubaMetadata* _metadata - ); - - const asset::IGeometryCreator* creator; - const asset::IMeshManipulator* manipulator; - const asset::IAssetLoader::SAssetLoadContext inner; - asset::IAssetLoader::IAssetLoaderOverride* override_; - CMitsubaMetadata* meta; - - _NBL_STATIC_INLINE_CONSTEXPR uint32_t VT_PAGE_SZ_LOG2 = 7u;//128 - _NBL_STATIC_INLINE_CONSTEXPR uint32_t VT_PHYSICAL_PAGE_TEX_TILES_PER_DIM_LOG2 = 4u;//16 - _NBL_STATIC_INLINE_CONSTEXPR uint32_t VT_PAGE_PADDING = 8u; - _NBL_STATIC_INLINE_CONSTEXPR uint32_t VT_MAX_ALLOCATABLE_TEX_SZ_LOG2 = 12u;//4096 - - // - using group_ass_type = core::vector>; - //core::map groupCache; - // - using shape_ass_type = core::smart_refctd_ptr; - core::map shapeCache; - //image, sampler - using tex_ass_type = std::tuple,core::smart_refctd_ptr>; - //image, scale - core::map,float> derivMapCache; - - // - static std::string imageViewCacheKey(const CElementTexture::Bitmap& bitmap, const CMitsubaMaterialCompilerFrontend::E_IMAGE_VIEW_SEMANTIC semantic) + asset::ICPUSampler::SParams params; + auto getWrapMode = [](CElementTexture::Bitmap::WRAP_MODE mode) { - std::string key = bitmap.filename.svalue; - switch (bitmap.channel) + switch (mode) { - case CElementTexture::Bitmap::CHANNEL::R: - key += "?rrrr"; + case CElementTexture::Bitmap::WRAP_MODE::CLAMP: + return asset::ISampler::ETC_CLAMP_TO_EDGE; break; - case CElementTexture::Bitmap::CHANNEL::G: - key += "?gggg"; + case CElementTexture::Bitmap::WRAP_MODE::MIRROR: + return asset::ISampler::ETC_MIRROR; break; - case CElementTexture::Bitmap::CHANNEL::B: - key += "?bbbb"; + case CElementTexture::Bitmap::WRAP_MODE::ONE: + _NBL_DEBUG_BREAK_IF(true); // TODO : replace whole texture? break; - case CElementTexture::Bitmap::CHANNEL::A: - key += "?aaaa"; + case CElementTexture::Bitmap::WRAP_MODE::ZERO: + _NBL_DEBUG_BREAK_IF(true); // TODO : replace whole texture? break; default: break; } - switch (semantic) - { - case CMitsubaMaterialCompilerFrontend::EIVS_BLEND_WEIGHT: - key += "?blend"; - break; - case CMitsubaMaterialCompilerFrontend::EIVS_NORMAL_MAP: - key += "?deriv?n"; - break; - case CMitsubaMaterialCompilerFrontend::EIVS_BUMP_MAP: - key += "?deriv?h"; - { - static const char* wrap[5] - { - "?repeat", - "?mirror", - "?clamp", - "?zero", - "?one" - }; - key += wrap[bitmap.wrapModeU]; - key += wrap[bitmap.wrapModeV]; - } - break; - default: - break; - } - key += "?view"; - return key; - } - - static auto computeSamplerParameters(const CElementTexture::Bitmap& bitmap) + return asset::ISampler::ETC_REPEAT; + }; + params.TextureWrapU = getWrapMode(bitmap.wrapModeU); + params.TextureWrapV = getWrapMode(bitmap.wrapModeV); + params.TextureWrapW = asset::ISampler::ETC_REPEAT; + params.BorderColor = asset::ISampler::ETBC_FLOAT_OPAQUE_BLACK; + switch (bitmap.filterType) { - asset::ICPUSampler::SParams params; - auto getWrapMode = [](CElementTexture::Bitmap::WRAP_MODE mode) - { - switch (mode) - { - case CElementTexture::Bitmap::WRAP_MODE::CLAMP: - return asset::ISampler::ETC_CLAMP_TO_EDGE; - break; - case CElementTexture::Bitmap::WRAP_MODE::MIRROR: - return asset::ISampler::ETC_MIRROR; - break; - case CElementTexture::Bitmap::WRAP_MODE::ONE: - _NBL_DEBUG_BREAK_IF(true); // TODO : replace whole texture? - break; - case CElementTexture::Bitmap::WRAP_MODE::ZERO: - _NBL_DEBUG_BREAK_IF(true); // TODO : replace whole texture? - break; - default: - break; - } - return asset::ISampler::ETC_REPEAT; - }; - params.TextureWrapU = getWrapMode(bitmap.wrapModeU); - params.TextureWrapV = getWrapMode(bitmap.wrapModeV); - params.TextureWrapW = asset::ISampler::ETC_REPEAT; - params.BorderColor = asset::ISampler::ETBC_FLOAT_OPAQUE_BLACK; - switch (bitmap.filterType) - { - case CElementTexture::Bitmap::FILTER_TYPE::EWA: - [[fallthrough]]; // we dont support this fancy stuff - case CElementTexture::Bitmap::FILTER_TYPE::TRILINEAR: - params.MinFilter = asset::ISampler::ETF_LINEAR; - params.MaxFilter = asset::ISampler::ETF_LINEAR; - params.MipmapMode = asset::ISampler::ESMM_LINEAR; - break; - default: - params.MinFilter = asset::ISampler::ETF_NEAREST; - params.MaxFilter = asset::ISampler::ETF_NEAREST; - params.MipmapMode = asset::ISampler::ESMM_NEAREST; - break; - } - params.AnisotropicFilter = core::max(core::findMSB(bitmap.maxAnisotropy),1u); - params.CompareEnable = false; - params.CompareFunc = asset::ISampler::ECO_NEVER; - params.LodBias = 0.f; - params.MaxLod = 10000.f; - params.MinLod = 0.f; - return params; + case CElementTexture::Bitmap::FILTER_TYPE::EWA: + [[fallthrough]]; // we dont support this fancy stuff + case CElementTexture::Bitmap::FILTER_TYPE::TRILINEAR: + params.MinFilter = asset::ISampler::ETF_LINEAR; + params.MaxFilter = asset::ISampler::ETF_LINEAR; + params.MipmapMode = asset::ISampler::ESMM_LINEAR; + break; + default: + params.MinFilter = asset::ISampler::ETF_NEAREST; + params.MaxFilter = asset::ISampler::ETF_NEAREST; + params.MipmapMode = asset::ISampler::ESMM_NEAREST; + break; } - // TODO: commonalize this to all loaders - static std::string samplerCacheKey(const std::string& base, const asset::ICPUSampler::SParams& samplerParams) - { - std::string samplerCacheKey = base; + params.AnisotropicFilter = core::max(core::findMSB(bitmap.maxAnisotropy),1u); + params.CompareEnable = false; + params.CompareFunc = asset::ISampler::ECO_NEVER; + params.LodBias = 0.f; + params.MaxLod = 10000.f; + params.MinLod = 0.f; + return params; + } + // TODO: commonalize this to all loaders + static std::string samplerCacheKey(const std::string& base, const asset::ICPUSampler::SParams& samplerParams) + { + std::string samplerCacheKey = base; - if (samplerParams.MinFilter==asset::ISampler::ETF_LINEAR) - samplerCacheKey += "?trilinear"; - else - samplerCacheKey += "?nearest"; + if (samplerParams.MinFilter==asset::ISampler::ETF_LINEAR) + samplerCacheKey += "?trilinear"; + else + samplerCacheKey += "?nearest"; - static const char* wrapModeName[] = - { - "?repeat", - "?clamp_to_edge", - "?clamp_to_border", - "?mirror", - "?mirror_clamp_to_edge", - "?mirror_clamp_to_border" - }; - samplerCacheKey += wrapModeName[samplerParams.TextureWrapU]; - samplerCacheKey += wrapModeName[samplerParams.TextureWrapV]; - - return samplerCacheKey; - } - std::string samplerCacheKey(const asset::ICPUSampler::SParams& samplerParams) const + static const char* wrapModeName[] = { - return samplerCacheKey(samplerCacheKeyBase,samplerParams); - } + "?repeat", + "?clamp_to_edge", + "?clamp_to_border", + "?mirror", + "?mirror_clamp_to_edge", + "?mirror_clamp_to_border" + }; + samplerCacheKey += wrapModeName[samplerParams.TextureWrapU]; + samplerCacheKey += wrapModeName[samplerParams.TextureWrapV]; - //index of root node in IR - using bsdf_type = const CMitsubaMaterialCompilerFrontend::front_and_back_t; - //caches instr buffer instr-wise offset (.first) and instruction count (.second) for each bsdf node - core::unordered_map instrStreamCache; + return samplerCacheKey; + } + std::string samplerCacheKey(const asset::ICPUSampler::SParams& samplerParams) const + { + return samplerCacheKey(samplerCacheKeyBase,samplerParams); + } - struct SInstanceData - { - SInstanceData(core::matrix3x4SIMD _tform, SContext::bsdf_type _bsdf, const std::string& _id, const CElementEmitter& _emitterFront, const CElementEmitter& _emitterBack) : - tform(_tform), bsdf(_bsdf), + //index of root node in IR + using bsdf_type = const CMaterialCompilerFrontend::front_and_back_t; + //caches instr buffer instr-wise offset (.first) and instruction count (.second) for each bsdf node + core::unordered_map instrStreamCache; // TODO: remove + + struct SInstanceData + { + SInstanceData(core::matrix3x4SIMD _tform, SContext::bsdf_type _bsdf, const std::string& _id, const CElementEmitter& _emitterFront, const CElementEmitter& _emitterBack) : + tform(_tform), bsdf(_bsdf), #if defined(_NBL_DEBUG) || defined(_NBL_RELWITHDEBINFO) - bsdf_id(_id), + bsdf_id(_id), #endif - emitter{_emitterFront, _emitterBack} - {} + emitter{_emitterFront, _emitterBack} + {} - core::matrix3x4SIMD tform; - SContext::bsdf_type bsdf; + core::matrix3x4SIMD tform; + SContext::bsdf_type bsdf; #if defined(_NBL_DEBUG) || defined(_NBL_RELWITHDEBINFO) - std::string bsdf_id; + std::string bsdf_id; #endif - struct { - // type is invalid if not used - CElementEmitter front; - CElementEmitter back; - } emitter; - }; - core::unordered_multimap mapMesh2instanceData; + struct { + // type is invalid if not used + CElementEmitter front; + CElementEmitter back; + } emitter; + }; + core::unordered_multimap mapMesh2instanceData; - struct SPipelineCacheKey + struct SPipelineCacheKey + { + asset::SVertexInputParams vtxParams; + asset::SPrimitiveAssemblyParams primParams; + + inline bool operator==(const SPipelineCacheKey& rhs) const { - asset::SVertexInputParams vtxParams; - asset::SPrimitiveAssemblyParams primParams; + return memcmp(&vtxParams, &rhs.vtxParams, sizeof(vtxParams)) == 0 && memcmp(&primParams, &rhs.primParams, sizeof(primParams)) == 0; + } - inline bool operator==(const SPipelineCacheKey& rhs) const + struct hash + { + inline size_t operator()(const SPipelineCacheKey& k) const { - return memcmp(&vtxParams, &rhs.vtxParams, sizeof(vtxParams)) == 0 && memcmp(&primParams, &rhs.primParams, sizeof(primParams)) == 0; + constexpr size_t BYTESZ = sizeof(k.vtxParams) + sizeof(k.primParams); + uint8_t mem[BYTESZ]{}; + uint8_t* ptr = mem; + memcpy(ptr, &k.vtxParams, sizeof(k.vtxParams)); + ptr += sizeof(k.vtxParams); + memcpy(ptr, &k.primParams, sizeof(k.primParams)); + ptr += sizeof(k.primParams); + + return std::hash{}(std::string_view(reinterpret_cast(mem), BYTESZ)); } - - struct hash - { - inline size_t operator()(const SPipelineCacheKey& k) const - { - constexpr size_t BYTESZ = sizeof(k.vtxParams) + sizeof(k.primParams); - uint8_t mem[BYTESZ]{}; - uint8_t* ptr = mem; - memcpy(ptr, &k.vtxParams, sizeof(k.vtxParams)); - ptr += sizeof(k.vtxParams); - memcpy(ptr, &k.primParams, sizeof(k.primParams)); - ptr += sizeof(k.primParams); - - return std::hash{}(std::string_view(reinterpret_cast(mem), BYTESZ)); - } - }; }; - core::unordered_map, SPipelineCacheKey::hash> pipelineCache; + }; + core::unordered_map, SPipelineCacheKey::hash> pipelineCache; - //material compiler - core::smart_refctd_ptr ir; - CMitsubaMaterialCompilerFrontend frontend; - asset::material_compiler::CMaterialCompilerGLSLRasterBackend::SContext backend_ctx; - asset::material_compiler::CMaterialCompilerGLSLRasterBackend backend; + //material compiler + CMaterialCompilerFrontend::HashCons frontend_ctx; + core::smart_refctd_ptr ir; + asset::material_compiler::CGLSLRasterBackend::SContext backend_ctx; + asset::material_compiler::CGLSLRasterBackend backend; - const std::string samplerCacheKeyBase; - }; + const std::string samplerCacheKeyBase; +}; -}}} +} #endif \ No newline at end of file diff --git a/src/nbl/CMakeLists.txt b/src/nbl/CMakeLists.txt index 4fa583c755..8529b37f44 100644 --- a/src/nbl/CMakeLists.txt +++ b/src/nbl/CMakeLists.txt @@ -200,8 +200,8 @@ set(NBL_ASSET_SOURCES ${NBL_ROOT_PATH}/src/nbl/asset/interchange/CGLIWriter.cpp # Material compiler - ${NBL_ROOT_PATH}/src/nbl/asset/material_compiler/CMaterialCompilerGLSLBackendCommon.cpp - ${NBL_ROOT_PATH}/src/nbl/asset/material_compiler/CMaterialCompilerGLSLRasterBackend.cpp + ${NBL_ROOT_PATH}/src/nbl/asset/material_compiler/CGLSLBackendCommon.cpp + ${NBL_ROOT_PATH}/src/nbl/asset/material_compiler/CGLSLRasterBackend.cpp ) set(NBL_VIDEO_SOURCES # Allocators diff --git a/src/nbl/asset/material_compiler/CMaterialCompilerGLSLBackendCommon.cpp b/src/nbl/asset/material_compiler/CGLSLBackendCommon.cpp similarity index 81% rename from src/nbl/asset/material_compiler/CMaterialCompilerGLSLBackendCommon.cpp rename to src/nbl/asset/material_compiler/CGLSLBackendCommon.cpp index 66a006fd4d..0418c217f3 100644 --- a/src/nbl/asset/material_compiler/CMaterialCompilerGLSLBackendCommon.cpp +++ b/src/nbl/asset/material_compiler/CGLSLBackendCommon.cpp @@ -1,92 +1,92 @@ -// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. +// Copyright (C) 2018-2022 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h +#include -#include -#include -#include - -namespace nbl -{ -namespace asset -{ -namespace material_compiler +namespace nbl::asset::material_compiler { -using instr_stream = CMaterialCompilerGLSLBackendCommon::instr_stream; +using instr_stream = CGLSLBackendCommon::instr_stream; using instr_t = instr_stream::instr_t; using traversal_t = instr_stream::traversal_t; - -using tmp_bxdf_translation_cache_t = core::unordered_map; - - -// good idea to make this tree translator "catch" duplicate subtrees -class CInterpreter +// TODO: replace with hash consing +using tmp_bxdf_translation_cache_t = core::unordered_map; +// TODO: more extreme deduplication, use hash consing! +class CIdGenerator { public: - static const IR::INode* translateMixIntoBlends(IR* ir, const IR::INode* _mix); - - static std::pair processSubtree(IR* ir, const IR::INode* tree, IR::INode::children_array_t& next, tmp_bxdf_translation_cache_t* coatTranslationCache); + using id_t = instr_stream::instr_id_t; - protected: - static inline IR::INode* getCoatNode(IR* ir, tmp_bxdf_translation_cache_t* cache, const IR::CMicrofacetCoatingBSDFNode* coat_blend) + id_t get_id(const IR::node_handle_t _node) { - if (auto found = cache->find(coat_blend); found != cache->end()) + if (auto found = m_cache.find(_node); found != m_cache.end()) return found->second; - // the coating is a dielectric, but it cannot transmit so make it a conductor - auto* coat = ir->allocTmpNode(); - { - coat->alpha_u = coat_blend->alpha_u; - coat->alpha_v = coat_blend->alpha_v; - coat->eta = coat_blend->eta; - coat->ndf = coat_blend->ndf; - coat->shadowing = coat_blend->shadowing; - } - cache->insert({ coat_blend, coat }); + id_t id = gen_id(); + m_cache.insert({ _node, id }); - return coat; + return id; } - static inline IR::INode* getDeltaTransmissionNode(IR* ir, tmp_bxdf_translation_cache_t* cache, const IR::COpacityNode* coat_blend) - { - if (auto found = cache->find(coat_blend); found != cache->end()) - return found->second; - auto* coat = ir->allocTmpNode(IR::CBSDFNode::ET_DELTA_TRANSMISSION); - cache->insert({ coat_blend, coat }); - - return coat; + private: + id_t gen_id() + { + return gen++; } + + id_t gen = 0u; + core::unordered_map m_cache; }; -// TODO: more extreme deduplication? -class CIdGenerator +// good idea to make this tree translator "catch" duplicate subtrees +class CInterpreter { public: - using id_t = instr_stream::instr_id_t; + static IR::node_handle_t translateMixIntoBlends(IR* ir, const IR::IBSDFCombinerNode* _mix); - id_t get_id(const IR::INode* _node) + struct codegen_t { - if (auto found = m_cache.find(_node); found != m_cache.end()) + instr_t instruction; + IR::node_handle_t branchNode; + }; + static codegen_t processSubtree(IR* ir, const IR::node_handle_t branch, tmp_bxdf_translation_cache_t* coatTranslationCache); + + protected: + static inline IR::node_handle_t getCoatNode(IR* ir, tmp_bxdf_translation_cache_t* cache, const IR::node_handle_t combined_coating) + { + auto pCombinedCoating = ir->getNode(combined_coating); + assert(pCombinedCoating); + if (auto found = cache->find(combined_coating); found != cache->end()) return found->second; - id_t id = gen_id(); - m_cache.insert({ _node, id }); + // the coating is a dielectric, but it cannot transmit so make it a conductor + auto coating = ir->allocTmpNode(1u); + auto pCoating = ir->getNode(coating); + { + pCoating->alpha_u = pCombinedCoating->alpha_u; + pCoating->alpha_v = pCombinedCoating->alpha_v; + pCoating->eta = pCombinedCoating->eta; + pCoating->ndf = pCombinedCoating->ndf; + } + cache->insert({ combined_coating, coating }); - return id; + return coating; } - - private: - id_t gen_id() + static inline IR::node_handle_t getDeltaTransmissionNode(IR* ir, tmp_bxdf_translation_cache_t* cache, const IR::node_handle_t opacity) { - return gen++; - } + auto pOpacity = ir->getNode(opacity); + assert(pOpacity); + if (auto found = cache->find(opacity); found != cache->end()) + return found->second; - id_t gen = 0u; - core::unordered_map m_cache; + auto transmission = ir->allocTmpNode(IR::IBSDFNode::ET_DELTA_TRANSMISSION); + cache->insert({ opacity, transmission }); + + return transmission; + } }; @@ -99,10 +99,11 @@ template class ITraversalGenerator { protected: - using SContext = CMaterialCompilerGLSLBackendCommon::SContext; + using SContext = CGLSLBackendCommon::SContext; SContext* m_ctx; IR* m_ir; + // merge ID geenrator and translation Cache CIdGenerator* m_id_gen; tmp_bxdf_translation_cache_t* m_translationCache; @@ -112,15 +113,13 @@ class ITraversalGenerator //rem_and_pdf: instructions not preceded with OP_BUMPMAP (resulting from node without any bumpmap above in tree) will have normal ID = ~0 uint32_t m_firstFreeNormalID = static_cast(-1); - const uint32_t m_registerBudget; - // right now it only gets used to inherit normalID from parent instruction virtual void writeInheritableBitfields(instr_t& dst, instr_t parent) const { } // Extra operations performed on instruction just before it is pushed on stack - virtual void onBeforeStackPush(instr_t& instr, const IR::INode* node) const + virtual void onBeforeStackPush(instr_t& instr, const IR::node_handle_t node) const { instr_stream::instr_id_t id = m_id_gen->get_id(node); instr_stream::setInstrId(instr, id); @@ -141,11 +140,11 @@ class ITraversalGenerator ); } - std::pair processSubtree(const IR::INode* tree, IR::INode::children_array_t& next) + auto processSubtree(const IR::node_handle_t branch) { // TODO deduplication (find identical IR subtrees, make them share instruction streams), hash consing? // Merkle Tree, LLVM had some nice blogposts about how their LTO works with hashmaps that can match subtrees in the context of type definitions - return CInterpreter::processSubtree(m_ir, tree, next, m_translationCache); + return CInterpreter::processSubtree(m_ir,branch,m_translationCache); } void setBSDFData(instr_stream::intermediate::SBSDFUnion& _dst, instr_stream::E_OPCODE _op, const IR::INode* _node) @@ -259,14 +258,15 @@ class ITraversalGenerator } } - size_t getBSDFDataIndex(instr_stream::E_OPCODE _op, const IR::INode* _node) + uint32_t getBSDFDataIndex(const instr_stream::E_OPCODE _op, const IR::node_handle_t _node) { switch (_op) { - case instr_stream::OP_INVALID: [[fallthrough]]; - case instr_stream::OP_NOOP: - return 0ull; - default: break; + case instr_stream::OP_INVALID: [[fallthrough]]; + case instr_stream::OP_NOOP: + return 0u; + default: + break; } // TODO: better deduplication @@ -323,10 +323,10 @@ class ITraversalGenerator // returns if the instruction actually got pushed template - bool push(const instr_t _instr, const IR::INode* _node, const IR::INode::children_array_t& _children, instr_t _parent, Params&& ...args) + bool push(const CInterpreter::codegen_t& code, const instr_t _parent, Params&& ...args) { - // a copy of the instruction gets pushed (some flags get changed) - instr_t instr = _instr; + // a copy of the instruction gets pushed (some flags get changed) + instr_t instr = code.instruction; // right now this only deals with the normal ID writeInheritableBitfields(instr, _parent); switch (instr_stream::getOpcode(instr)) @@ -343,8 +343,8 @@ class ITraversalGenerator case instr_stream::OP_BLEND: [[fallthrough]]; case instr_stream::OP_NOOP: [[fallthrough]]; case instr_stream::OP_DELTRATRANS: - onBeforeStackPush(instr,_node); - m_stack.push(stack_el_t(instr,_node,_children,std::forward(args)...)); + onBeforeStackPush(instr,code.branchNode); + m_stack.push(stack_el_t(instr,code.branchNode,std::forward(args)...)); return true; break; } @@ -352,7 +352,7 @@ class ITraversalGenerator } // set pointer to BSDF parameter data once its known - instr_t finalizeInstr(instr_t _instr, const IR::INode* _node, uint32_t _bsdfBufOffset) + instr_t finalizeInstr(instr_t _instr, const IR::node_handle_t _node, uint32_t _bsdfBufOffset) { constexpr instr_stream::E_NDF ndfMap[4] { @@ -376,50 +376,50 @@ class ITraversalGenerator const instr_stream::E_OPCODE op = instr_stream::getOpcode(_instr); switch (op) { - case instr_stream::OP_DIFFUSE: - { - auto* node = static_cast(_node); - if (!node->alpha_u.isConstant()) - _instr = core::bitfieldInsert(_instr, 1u, instr_stream::BITFIELDS_SHIFT_ALPHA_U_TEX, 1); - if (!node->reflectance.isConstant()) - _instr = core::bitfieldInsert(_instr, 1u, instr_stream::BITFIELDS_SHIFT_REFL_TEX, 1); - } - break; - case instr_stream::OP_DIELECTRIC: [[fallthrough]]; - case instr_stream::OP_THINDIELECTRIC: [[fallthrough]]; - case instr_stream::OP_CONDUCTOR: - { - auto* node = static_cast(_node); - _instr = handleSpecularBitfields(_instr, node); - } - break; - case instr_stream::OP_COATING: - { - auto* coat = static_cast(_node); + case instr_stream::OP_DIFFUSE: + { + auto* node = ir->getNode(_node); + if (!node->alpha_u.isConstant()) + _instr = core::bitfieldInsert(_instr, 1u, instr_stream::BITFIELDS_SHIFT_ALPHA_U_TEX, 1); + if (!node->reflectance.isConstant()) + _instr = core::bitfieldInsert(_instr, 1u, instr_stream::BITFIELDS_SHIFT_REFL_TEX, 1); + } + break; + case instr_stream::OP_DIELECTRIC: [[fallthrough]]; + case instr_stream::OP_THINDIELECTRIC: [[fallthrough]]; + case instr_stream::OP_CONDUCTOR: + { + auto* node = static_cast(_node); + _instr = handleSpecularBitfields(_instr, node); + } + break; + case instr_stream::OP_COATING: + { + auto* coat = static_cast(_node); - //_instr = handleSpecularBitfields(_instr, coat); - if (!coat->thicknessSigmaA.isConstant()) - _instr = core::bitfieldInsert(_instr, 1u, instr_stream::BITFIELDS_SHIFT_SIGMA_A_TEX, 1); - } - break; - case instr_stream::OP_BLEND: - { - auto* blend = static_cast(_node); - assert(blend->type == IR::CBSDFCombinerNode::ET_WEIGHT_BLEND); + //_instr = handleSpecularBitfields(_instr, coat); + if (!coat->thicknessSigmaA.isConstant()) + _instr = core::bitfieldInsert(_instr, 1u, instr_stream::BITFIELDS_SHIFT_SIGMA_A_TEX, 1); + } + break; + case instr_stream::OP_BLEND: + { + auto* blend = static_cast(_node); + assert(blend->type == IR::CBSDFCombinerNode::ET_WEIGHT_BLEND); - if (!static_cast(_node)->weight.isConstant()) - _instr = core::bitfieldInsert(_instr, 1u, instr_stream::BITFIELDS_SHIFT_WEIGHT_TEX, 1); - } - case instr_stream::OP_DIFFTRANS: - { - auto* difftrans = static_cast(_node); + if (!static_cast(_node)->weight.isConstant()) + _instr = core::bitfieldInsert(_instr, 1u, instr_stream::BITFIELDS_SHIFT_WEIGHT_TEX, 1); + } + case instr_stream::OP_DIFFTRANS: + { + auto* difftrans = static_cast(_node); - if (!difftrans->alpha_u.isConstant()) - _instr = core::bitfieldInsert(_instr, 1u, instr_stream::BITFIELDS_SHIFT_ALPHA_U_TEX, 1); - if (!difftrans->transmittance.isConstant()) - _instr = core::bitfieldInsert(_instr, 1u, instr_stream::BITFIELDS_SHIFT_TRANS_TEX, 1); - } - break; + if (!difftrans->alpha_u.isConstant()) + _instr = core::bitfieldInsert(_instr, 1u, instr_stream::BITFIELDS_SHIFT_ALPHA_U_TEX, 1); + if (!difftrans->transmittance.isConstant()) + _instr = core::bitfieldInsert(_instr, 1u, instr_stream::BITFIELDS_SHIFT_TRANS_TEX, 1); + } + break; } _instr = core::bitfieldInsert(_instr, _bsdfBufOffset, instr_stream::BITFIELDS_BSDF_BUF_OFFSET_SHIFT, instr_stream::BITFIELDS_BSDF_BUF_OFFSET_WIDTH); @@ -427,36 +427,14 @@ class ITraversalGenerator return _instr; } - public: - ITraversalGenerator(SContext* _ctx, IR* _ir, CIdGenerator* _id_gen, tmp_bxdf_translation_cache_t* _cache, uint32_t _registerBudget) : - m_ctx(_ctx), m_ir(_ir), m_id_gen(_id_gen), m_translationCache(_cache), m_registerBudget(_registerBudget) {} - - virtual traversal_t genTraversal(const IR::INode* _root, uint32_t& _out_usedRegs) = 0; + ITraversalGenerator(SContext* _ctx, IR* _ir, CIdGenerator* _id_gen, tmp_bxdf_translation_cache_t* _cache) : + m_ctx(_ctx), m_ir(_ir), m_id_gen(_id_gen), m_translationCache(_cache) {} }; namespace remainder_and_pdf { -// not dwords, full regs for all output -inline uint32_t getNumberOfSrcRegsForOpcode(instr_stream::E_OPCODE _op) -{ - if (_op == instr_stream::OP_BLEND || _op == instr_stream::OP_COATING) - return 2u; - else if (_op == instr_stream::OP_BUMPMAP) - return 1u; - return 0u; -} - -inline core::vector3du32_SIMD getRegisters(const instr_t& i) -{ - return core::vector3du32_SIMD( - (i>>instr_stream::remainder_and_pdf::INSTR_REG_DST_SHIFT), - (i>>instr_stream::remainder_and_pdf::INSTR_REG_SRC1_SHIFT), - (i>>instr_stream::remainder_and_pdf::INSTR_REG_SRC2_SHIFT) - ) & core::vector3du32_SIMD(instr_stream::remainder_and_pdf::INSTR_REG_MASK); -} - class CTraversalManipulator { public: @@ -537,26 +515,21 @@ class CTraversalManipulator struct stack_el { - stack_el(instr_t i, const IR::INode* n, const IR::INode::children_array_t& ch, bool v) : - instr(i), node(n), children(ch), visited(v) - {} - instr_t instr; - const IR::INode* node; - IR::INode::children_array_t children; + IR::node_handle_t node; bool visited; }; class CTraversalGenerator : public ITraversalGenerator { using base_t = ITraversalGenerator; - uint32_t m_regsPerRes; + const uint32_t m_registerBudget; + const uint32_t m_regsPerRes; CTraversalManipulator::id2pos_map_t m_id2pos; public: CTraversalGenerator(SContext* _ctx, IR* _ir, CIdGenerator* _id_gen, tmp_bxdf_translation_cache_t* _cache, uint32_t _regCount, uint32_t _regsPerResult) : - base_t(_ctx, _ir, _id_gen, _cache, _regCount), m_regsPerRes(_regsPerResult) - {} + base_t(_ctx, _ir, _id_gen, _cache), m_registerBudget(_regCount), m_regsPerRes(_regsPerResult) {} const auto& getId2PosMapping() const { return m_id2pos; } @@ -567,45 +540,44 @@ class CTraversalGenerator : public ITraversalGenerator dst = core::bitfieldInsert(dst, parent>>instr_stream::INSTR_NORMAL_ID_SHIFT, instr_stream::INSTR_NORMAL_ID_SHIFT, instr_stream::INSTR_NORMAL_ID_WIDTH); } - traversal_t genTraversal(const IR::INode* _root, uint32_t& _out_usedRegs) override; + traversal_t genTraversal(const IR::node_handle_t _root, uint32_t& _out_usedRegs); }; } namespace gen_choice { - struct stack_el - { - stack_el(instr_t i, const IR::INode* n, const IR::INode::children_array_t& ch, uint32_t p) : - instr(i), node(n), children(ch), parentIx(p) - {} - instr_t instr; - const IR::INode* node; - IR::INode::children_array_t children; - uint32_t parentIx; - }; - class CTraversalGenerator : public ITraversalGenerator - { +struct stack_el +{ + instr_t instr; + IR::node_handle_t node; + uint32_t parentIx; +}; +class CTraversalGenerator : public ITraversalGenerator +{ using base_t = ITraversalGenerator; uint32_t m_firstFreeNormalID = 0u; public: - using base_t::base_t; + CTraversalGenerator(SContext* _ctx, IR* _ir, CIdGenerator* _id_gen, tmp_bxdf_translation_cache_t* _cache) : base_t(_ctx, _ir, _id_gen, _cache) {} + + traversal_t genTraversal(const IR::node_handle_t _root); +}; - traversal_t genTraversal(const IR::INode* _root, uint32_t& _out_usedRegs) override; - }; } namespace tex_prefetch { static instr_stream::tex_prefetch::prefetch_stream_t genTraversal(const traversal_t& _t, const core::vector& _bsdfData, core::unordered_map& _tex2reg, uint32_t _firstFreeReg, uint32_t& _out_usedRegs, uint32_t& _out_regCntFlags); } -const IR::INode* CInterpreter::translateMixIntoBlends(IR* ir, const IR::INode* _mix) +// TODO: hoist to become a generalpurpose OP on the IR +IR::node_handle_t CInterpreter::translateMixIntoBlends(IR* ir, const IR::IBSDFCombinerNode* _mix) { + assert(_mix->getType() == IR::IBSDFCombinerNode::ET_MIX); auto* mix = static_cast(_mix); - assert(mix->symbol == IR::INode::ES_BSDF_COMBINER); + // TODO: translate it to use a stack struct q_el { const IR::INode* node; @@ -634,114 +606,121 @@ const IR::INode* CInterpreter::translateMixIntoBlends(IR* ir, const IR::INode* _ return q.front().node; } -std::pair CInterpreter::processSubtree(IR* ir, const IR::INode* tree, IR::INode::children_array_t& out_next, tmp_bxdf_translation_cache_t* cache) +CInterpreter::codegen_t CInterpreter::processSubtree(IR* ir, IR::node_handle_t branch, tmp_bxdf_translation_cache_t* cache) { instr_t instr = instr_stream::OP_INVALID; - switch (tree->symbol) - { - case IR::INode::ES_GEOM_MODIFIER: + switch (ir->getNode(branch)->getSymbol()) { - auto* node = static_cast(tree); - - if (node->type == IR::CGeomModifierNode::ET_DERIVATIVE) - instr = instr_stream::OP_BUMPMAP; - else - instr = instr_stream::OP_INVALID; - - out_next = node->children; - } - break; - case IR::INode::ES_BSDF_COMBINER: - { - auto* node = static_cast(tree); - switch (node->type) + case IR::INode::ES_GEOM_MODIFIER: { - case IR::CBSDFCombinerNode::ET_WEIGHT_BLEND: - out_next = node->children; - instr = instr_stream::OP_BLEND; - break; - case IR::CBSDFCombinerNode::ET_MIX: - { - tree = translateMixIntoBlends(ir, node); - instr = instr_stream::OP_BLEND; - out_next = tree->children; - } - break; - } - } - break; - case IR::INode::ES_OPACITY: - { - auto* opacity = static_cast(tree); - auto* blend = ir->allocTmpNode(); - blend->weight = opacity->opacity; - auto* deltatrans = getDeltaTransmissionNode(ir, cache, opacity); - assert(opacity->children.count == 1u); - auto* bxdf = const_cast(opacity->children[0]); - blend->children = IR::INode::createChildrenArray(deltatrans,bxdf); - out_next = blend->children; - - tree = blend; - instr = instr_stream::OP_BLEND; - } - break; - case IR::INode::ES_BSDF: - { - auto* node = static_cast(tree); - switch (node->type) - { - case IR::CBSDFNode::ET_MICROFACET_DIFFTRANS: - instr = instr_stream::OP_DIFFTRANS; break; - case IR::CBSDFNode::ET_MICROFACET_DIFFUSE: - instr = instr_stream::OP_DIFFUSE; break; - case IR::CBSDFNode::ET_MICROFACET_SPECULAR: - instr = instr_stream::OP_CONDUCTOR; break; - case IR::CBSDFNode::ET_DELTA_TRANSMISSION: - instr = instr_stream::OP_DELTRATRANS; break; - case IR::CBSDFNode::ET_MICROFACET_COATING: - { - auto* coat_blend = static_cast(node); - auto* coat = getCoatNode(ir, cache, coat_blend); - - assert(node->children.count == 1u); - auto* coated = const_cast(node->children[0]); + auto* node = ir->getNode(branch); - instr = instr_stream::OP_COATING; - - assert(coated->symbol == IR::INode::ES_BSDF); - if (coated->symbol != IR::INode::ES_BSDF) - instr = instr_stream::OP_INVALID; - const IR::CBSDFNode::E_TYPE coated_bxdf = static_cast(coated)->type; - const bool is_coated_diffuse = (coated_bxdf == IR::CBSDFNode::ET_MICROFACET_DIFFUSE || coated_bxdf == IR::CBSDFNode::ET_MICROFACET_DIFFTRANS); - //assert(is_coated_diffuse); - // we dont support coating over non-diffuse materials - // so we ignore coating layer and process only the coated material - if (!is_coated_diffuse) - { - os::Printer::log("Material compiler GLSL: Coating over non-diffuse materials is not supported. Ignoring coating layer!", ELL_WARNING); - - auto retval = processSubtree(ir, coated, out_next, cache); - instr = retval.first; - tree = retval.second; - } + if (node->type == IR::CGeomModifierNode::ET_DERIVATIVE) + instr = instr_stream::OP_BUMPMAP; else + instr = instr_stream::OP_INVALID; + break; + } + case IR::INode::ES_BSDF_COMBINER: + { + auto* node = ir->getNode(branch); + switch (node->getType()) { - out_next = IR::INode::createChildrenArray(coat, coated); + case IR::IBSDFCombinerNode::ET_WEIGHT_BLEND: + instr = instr_stream::OP_BLEND; + break; + case IR::IBSDFCombinerNode::ET_MIX: + { + branch = translateMixIntoBlends(ir,node); + instr = instr_stream::OP_BLEND; + break; + } } + break; } + case IR::INode::ES_OPACITY: + { + // original node + auto* opacity = ir->getNode(branch); + // pure transmission + auto deltatrans = getDeltaTransmissionNode(ir,cache,branch); + // blend between them + branch = ir->allocTmpNode(2u); + auto* blend = ir->getNode(branch); + blend->weight = opacity->opacity; + blend->getChildrenArray()[0] = deltatrans; + blend->getChildrenArray()[1] = opacity->getChildrenArray()[0]; + instr = instr_stream::OP_BLEND; break; - case IR::CBSDFNode::ET_MICROFACET_DIELECTRIC: + } + case IR::INode::ES_BSDF: { - auto* dielectric = static_cast(node); - instr = dielectric->thin ? instr_stream::OP_THINDIELECTRIC : instr_stream::OP_DIELECTRIC; + auto* node = ir->getNode(branch); + switch (node->type) + { + case IR::IBSDFNode::ET_MICROFACET_DIFFTRANS: + instr = instr_stream::OP_DIFFTRANS; + break; + case IR::IBSDFNode::ET_MICROFACET_DIFFUSE: + instr = instr_stream::OP_DIFFUSE; + break; + case IR::IBSDFNode::ET_MICROFACET_SPECULAR: + instr = instr_stream::OP_CONDUCTOR; + break; + case IR::IBSDFNode::ET_DELTA_TRANSMISSION: + instr = instr_stream::OP_DELTRATRANS; + break; + case IR::IBSDFNode::ET_MICROFACET_COATING: + { + // original node + auto* combined_coating = ir->getNode(branch); + // substrate + auto coated = combined_coating->getChildrenArray()[0]; + auto pCoated = ir->getNode(coated); + if (pCoated) + { + os::Printer::log("Material compiler GLSL: Coating over non-BxDF IR node, FATAL ERROR!",ELL_ERROR); + instr = instr_stream::OP_INVALID; + break; + } + // we dont support coating over non-diffuse materials + switch (pCoated->type) + { + case IR::IBSDFNode::ET_MICROFACET_DIFFTRANS: [[fallthorough]] + case IR::IBSDFNode::ET_MICROFACET_DIFFUSE: + { + // translated coating layer + auto coating = getCoatNode(ir, cache, branch); + // blend between them + branch = ir->allocTmpNode(2u); + auto* blend = ir->getNode(branch); + blend->weight = opacity->opacity; + blend->getChildrenArray()[0] = coating; + blend->getChildrenArray()[1] = coated; + instr = instr_stream::OP_COATING; + break; + } + // so we ignore coating layer and process only the coated material + default: + //assert(false); + os::Printer::log("Material compiler GLSL: Coating over non-diffuse materials is not supported. Ignoring coating layer!", ELL_WARNING); + return processSubtree(ir,coated,cache); + break; + } + break; + } + case IR::IBSDFNode::ET_MICROFACET_DIELECTRIC: + { + auto* dielectric = static_cast(node); + instr = dielectric->thin ? instr_stream::OP_THINDIELECTRIC:instr_stream::OP_DIELECTRIC; + } + break; + } } break; - } - } - break; } - return {instr,tree}; + return {instr,branch}; } void remainder_and_pdf::CTraversalManipulator::reorderBumpMapStreams_impl(traversal_t& _input, traversal_t& _output, const substream_t& _stream) @@ -918,24 +897,22 @@ auto remainder_and_pdf::CTraversalManipulator::specifyRegisters(uint32_t regBudg return id2pos; } -traversal_t remainder_and_pdf::CTraversalGenerator::genTraversal(const IR::INode* _root, uint32_t& _out_usedRegs) +traversal_t remainder_and_pdf::CTraversalGenerator::genTraversal(const IR::node_handle_t _root, uint32_t& _out_usedRegs) { traversal_t traversal; // push the whole IR tree while on-line translating into a binary tree, generating a DFS traversal on the stack { - IR::INode::children_array_t next; - const IR::INode* node; - instr_t instr; - std::tie(instr, node) = processSubtree(_root, next); - push(instr, node, next, instr, false); + instr_t nullParent = {}; + push(processSubtree(_root), nullParent, false); } while (!m_stack.empty()) { auto& top = m_stack.top(); const instr_stream::E_OPCODE op = instr_stream::getOpcode(top.instr); _NBL_DEBUG_BREAK_IF(op == instr_stream::OP_INVALID); - if (top.children.count==0u || top.visited) + auto children = m_ir->getNode(top.node)->getChildren(); + if (!children || top.visited) { // post-order traversal emits stuff after all children have already been visited const uint32_t bsdfBufIx = getBSDFDataIndex(instr_stream::getOpcode(top.instr), top.node); @@ -947,19 +924,15 @@ traversal_t remainder_and_pdf::CTraversalGenerator::genTraversal(const IR::INode { top.visited = true; - size_t pushedCount = 0ull; - for (auto it = top.children.end() - 1; it != top.children.begin() - 1; --it) + bool allGotPushed = true; + // because we use a stack, children need pushing in reverse + for (auto it=children.end()-1; it!=children.begin()-1; --it) { // we actually rewrite nodes with K>2 children into an unbalanced chain of 2-children nodes // TODO: https://github.com/Devsh-Graphics-Programming/Nabla/issues/287#issuecomment-994732437 - const IR::INode* node = nullptr; - IR::INode::children_array_t next2; - instr_t instr2; - std::tie(instr2, node) = processSubtree(*it, next2); - pushedCount += push(instr2, node, next2, top.instr, false); + allGotPushed = push(processSubtree(*it), top.instr, false) && allGotPushed; } - _NBL_DEBUG_BREAK_IF(pushedCount > 2ull); // TODO: this is probably wrong, some nodes can have only 1 child? - _NBL_DEBUG_BREAK_IF(pushedCount < top.children.count); + _NBL_DEBUG_BREAK_IF(allGotPushed); } } @@ -972,7 +945,7 @@ traversal_t remainder_and_pdf::CTraversalGenerator::genTraversal(const IR::INode } // generator choice doesn't use any registers because it chooses BxDF tree branches stochastically -traversal_t gen_choice::CTraversalGenerator::genTraversal(const IR::INode* _root, uint32_t& _out_usedRegs) +traversal_t gen_choice::CTraversalGenerator::genTraversal(const IR::node_handle_t _root) { constexpr uint32_t INVALID_INDEX = 0xdeadbeefu; @@ -980,11 +953,8 @@ traversal_t gen_choice::CTraversalGenerator::genTraversal(const IR::INode* _root // push the whole IR tree while on-line translating into a binary tree, generating a DFS traversal on the stack { - IR::INode::children_array_t next; - const IR::INode* node; - instr_t instr; - std::tie(instr, node) = processSubtree(_root, next); - push(instr, node, next, instr, INVALID_INDEX); + instr_t nullParent = {}; + push(processSubtree(_root), nullParent, INVALID_INDEX); } while (!m_stack.empty()) { @@ -1004,28 +974,22 @@ traversal_t gen_choice::CTraversalGenerator::genTraversal(const IR::INode* _root std::count_if(traversal.begin(), traversal.begin()+currIx, [](instr_stream::instr_t i) { return instr_stream::getOpcode(i) == instr_stream::OP_NOOP; }); parent = core::bitfieldInsert(parent, rightJump, instr_stream::gen_choice::INSTR_RIGHT_JUMP_SHIFT, instr_stream::gen_choice::INSTR_RIGHT_JUMP_WIDTH); } - + + bool allGotPushed = true; + // because we use a stack, children need pushing in reverse + auto children = m_ir->getNode(top.node)->getChildren(); + for (auto it=children.end()-1; it!=children.begin()-1; --it) { - size_t pushedCount = 0ull; - for (auto it = top.children.end() - 1; it != top.children.begin() - 1; --it) - { - const IR::INode* node = nullptr; - IR::INode::children_array_t next2; - instr_t instr2; - std::tie(instr2, node) = processSubtree(*it, next2); - pushedCount += push(instr2, node, next2, top.instr, it == top.children.begin()+1 ? currIx : INVALID_INDEX); - } - _NBL_DEBUG_BREAK_IF(pushedCount > 2ull); - _NBL_DEBUG_BREAK_IF(pushedCount < top.children.count); + // we actually rewrite nodes with K>2 children into an unbalanced chain of 2-children nodes + // TODO: https://github.com/Devsh-Graphics-Programming/Nabla/issues/287#issuecomment-994732437 + allGotPushed = push(processSubtree(*it), top.instr, it==(children.begin()+1) ? currIx:INVALID_INDEX) && allGotPushed; } + _NBL_DEBUG_BREAK_IF(allGotPushed); } //remove NOOPs filterNOOPs(traversal); - // no registers used because stochastic descent - _out_usedRegs = 0u; - return traversal; } @@ -1087,7 +1051,7 @@ instr_stream::tex_prefetch::prefetch_stream_t tex_prefetch::genTraversal( return prefetch_stream; } -std::string CMaterialCompilerGLSLBackendCommon::genPreprocDefinitions(const result_t& _res, E_GENERATOR_STREAM_TYPE _generatorChoiceStream) +std::string CGLSLBackendCommon::genPreprocDefinitions(const result_t& _res, E_GENERATOR_STREAM_TYPE _generatorChoiceStream) { using namespace std::string_literals; @@ -1197,7 +1161,8 @@ std::string CMaterialCompilerGLSLBackendCommon::genPreprocDefinitions(const resu return defs; } -auto CMaterialCompilerGLSLBackendCommon::compile(SContext* _ctx, IR* _ir, E_GENERATOR_STREAM_TYPE _generatorChoiceStream) -> result_t + +auto CGLSLBackendCommon::compile(SContext* _ctx, IR* _ir, E_GENERATOR_STREAM_TYPE _generatorChoiceStream) -> result_t { result_t res; res.noNormPrecompStream = true; @@ -1205,7 +1170,7 @@ auto CMaterialCompilerGLSLBackendCommon::compile(SContext* _ctx, IR* _ir, E_GENE res.usedRegisterCount = 0u; res.globalPrefetchRegCountFlags = 0u; - for (const IR::INode* root : _ir->roots) + for (const auto root : _ir->getRootNodes()) { uint32_t remainingRegisters = instr_stream::MAX_REGISTER_COUNT; @@ -1219,7 +1184,7 @@ auto CMaterialCompilerGLSLBackendCommon::compile(SContext* _ctx, IR* _ir, E_GENE uint32_t usedRegs{}; traversal_t rem_pdf_stream; { - // TODO: investigate compression of return value registers from 11 to 5 DWORDs + // TODO: investigate compression of return value registers from full float to shared exponent or half floats const uint32_t regsPerRes = [_generatorChoiceStream]() -> auto { // In case of presence of generator choice stream, remainder_and_pdf stream has 2 roles in raster backend: @@ -1254,10 +1219,10 @@ auto CMaterialCompilerGLSLBackendCommon::compile(SContext* _ctx, IR* _ir, E_GENE traversal_t gen_choice_stream; if (_generatorChoiceStream!=EGST_ABSENT) { - gen_choice::CTraversalGenerator gen(_ctx, _ir, &id_gen, &translationCache, 0u); + gen_choice::CTraversalGenerator gen(_ctx, _ir, &id_gen, &translationCache); // generator stream does not consume any registers uint32_t dummyUsedRegs; - gen_choice_stream = gen.genTraversal(root,dummyUsedRegs); + gen_choice_stream = gen.genTraversal(root); assert(dummyUsedRegs==0u); // final instructions in generator choice need to know which instruction in the remainder&pdf stream corresponds to the same BxDF @@ -1435,8 +1400,33 @@ R"( return res; } + +namespace remainder_and_pdf +{ + +// not dwords, full regs for all output +inline uint32_t getNumberOfSrcRegsForOpcode(instr_stream::E_OPCODE _op) +{ + if (_op == instr_stream::OP_BLEND || _op == instr_stream::OP_COATING) + return 2u; + else if (_op == instr_stream::OP_BUMPMAP) + return 1u; + return 0u; +} + +inline core::vector3du32_SIMD getRegisters(const instr_t& i) +{ + return core::vector3du32_SIMD( + (i>>instr_stream::remainder_and_pdf::INSTR_REG_DST_SHIFT), + (i>>instr_stream::remainder_and_pdf::INSTR_REG_SRC1_SHIFT), + (i>>instr_stream::remainder_and_pdf::INSTR_REG_SRC2_SHIFT) + ) & core::vector3du32_SIMD(instr_stream::remainder_and_pdf::INSTR_REG_MASK); +} + } -void material_compiler::CMaterialCompilerGLSLBackendCommon::debugPrint(std::ostream& _out, const result_t::instr_streams_t& _streams, const result_t& _res, const SContext* _ctx) const + + +void CGLSLBackendCommon::debugPrint(std::ostream& _out, const result_t::instr_streams_t& _streams, const result_t& _res, const SContext* _ctx) const { _out << "####### remainder_and_pdf stream\n"; auto rem_and_pdf = _streams.get_rem_and_pdf(); @@ -1461,8 +1451,6 @@ void material_compiler::CMaterialCompilerGLSLBackendCommon::debugPrint(std::ostr auto gen_choice = _streams.get_gen_choice(); for (uint32_t i = 0u; i < gen_choice.count; ++i) { - using namespace gen_choice; - const instr_t instr = _res.instructions[gen_choice.first + i]; debugPrintInstr(_out, instr, _res, _ctx); if (instr_stream::getOpcode(instr) == instr_stream::OP_BUMPMAP) @@ -1478,8 +1466,6 @@ void material_compiler::CMaterialCompilerGLSLBackendCommon::debugPrint(std::ostr auto tex_prefetch = _streams.get_tex_prefetch(); for (uint32_t i = 0u; i < tex_prefetch.count; ++i) { - using namespace tex_prefetch; - const instr_stream::tex_prefetch::prefetch_instr_t& instr = _res.prefetch_stream[tex_prefetch.first + i]; const auto& vtid = instr.tex_data.vtid; @@ -1507,7 +1493,7 @@ void material_compiler::CMaterialCompilerGLSLBackendCommon::debugPrint(std::ostr } } -void material_compiler::CMaterialCompilerGLSLBackendCommon::debugPrintInstr(std::ostream& _out, instr_t instr, const result_t& _res, const SContext* _ctx) const +void CGLSLBackendCommon::debugPrintInstr(std::ostream& _out, instr_t instr, const result_t& _res, const SContext* _ctx) const { auto texDataStr = [](const instr_stream::STextureData& td) { return "{ " + std::to_string(reinterpret_cast(td.vtid)) + ", " + std::to_string(reinterpret_cast(td.scale)) + " }"; @@ -1621,8 +1607,9 @@ void material_compiler::CMaterialCompilerGLSLBackendCommon::debugPrintInstr(std: //_out << "Bump reg " << data.bumpmap.bumpmap.prefetch_reg << "\n"; break; default: break; - } } -}} +} + +} \ No newline at end of file diff --git a/src/nbl/asset/material_compiler/CMaterialCompilerGLSLRasterBackend.cpp b/src/nbl/asset/material_compiler/CGLSLRasterBackend.cpp similarity index 67% rename from src/nbl/asset/material_compiler/CMaterialCompilerGLSLRasterBackend.cpp rename to src/nbl/asset/material_compiler/CGLSLRasterBackend.cpp index f9ff623f10..617940b16e 100644 --- a/src/nbl/asset/material_compiler/CMaterialCompilerGLSLRasterBackend.cpp +++ b/src/nbl/asset/material_compiler/CGLSLRasterBackend.cpp @@ -2,12 +2,12 @@ // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h -#include +#include namespace nbl::asset::material_compiler { -auto CMaterialCompilerGLSLRasterBackend::compile(SContext* _ctx, IR* _ir, E_GENERATOR_STREAM_TYPE _generatorChoiceStream) -> result_t +auto CGLSLRasterBackend::compile(SContext* _ctx, IR* _ir, E_GENERATOR_STREAM_TYPE _generatorChoiceStream) -> result_t { result_t res = base_t::compile(_ctx, _ir, _generatorChoiceStream); diff --git a/src/nbl/builtin/CMakeLists.txt b/src/nbl/builtin/CMakeLists.txt index dc584dd286..f92212c1a6 100644 --- a/src/nbl/builtin/CMakeLists.txt +++ b/src/nbl/builtin/CMakeLists.txt @@ -87,6 +87,8 @@ set(nbl_resources_to_embed "nbl/builtin/glsl/material_compiler/common.glsl" "nbl/builtin/glsl/material_compiler/common_declarations.glsl" "nbl/builtin/glsl/material_compiler/common_invariant_declarations.glsl" + "nbl/builtin/glsl/material_compiler/material_data.glsl" + "nbl/builtin/glsl/material_compiler/oriented_material.glsl" "nbl/builtin/glsl/material_compiler/rasterization/impl.glsl" # random numbers "nbl/builtin/glsl/random/xoroshiro.glsl" diff --git a/src/nbl/ext/MitsubaLoader/CMakeLists.txt b/src/nbl/ext/MitsubaLoader/CMakeLists.txt index 4077dc4712..b32fde72ca 100644 --- a/src/nbl/ext/MitsubaLoader/CMakeLists.txt +++ b/src/nbl/ext/MitsubaLoader/CMakeLists.txt @@ -22,7 +22,7 @@ set(NBL_EXT_MITSUBA_LOADER_H ${NBL_EXT_INTERNAL_INCLUDE_DIR}/ParserUtil.h ${NBL_EXT_INTERNAL_INCLUDE_DIR}/CSerializedLoader.h ${NBL_EXT_INTERNAL_INCLUDE_DIR}/CMitsubaLoader.h - ${NBL_EXT_INTERNAL_INCLUDE_DIR}/CMitsubaMaterialCompilerFrontend.h + ${NBL_EXT_INTERNAL_INCLUDE_DIR}/CMaterialCompilerFrontend.h ) set(NBL_EXT_MITSUBA_LOADER_SRC @@ -41,7 +41,7 @@ set(NBL_EXT_MITSUBA_LOADER_SRC ParserUtil.cpp CSerializedLoader.cpp CMitsubaLoader.cpp - CMitsubaMaterialCompilerFrontend.cpp + CMaterialCompilerFrontend.cpp ) set(NBL_EXT_MITSUBA_LOADER_EXTERNAL_INCLUDE diff --git a/src/nbl/ext/MitsubaLoader/CMaterialCompilerFrontend.cpp b/src/nbl/ext/MitsubaLoader/CMaterialCompilerFrontend.cpp new file mode 100644 index 0000000000..d0015cef10 --- /dev/null +++ b/src/nbl/ext/MitsubaLoader/CMaterialCompilerFrontend.cpp @@ -0,0 +1,391 @@ +// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h +#include "nbl/ext/MitsubaLoader/CMaterialCompilerFrontend.h" +#include "nbl/ext/MitsubaLoader/SContext.h" + +namespace nbl::ext::MitsubaLoader +{ + +auto CMaterialCompilerFrontend::getTexture(const SContext& _loaderContext, const CElementTexture* _element, const E_IMAGE_VIEW_SEMANTIC semantic) -> tex_ass_type +{ + // first unwind the texture Scales + float scale = 1.f; + while (_element && _element->type==CElementTexture::SCALE) + { + scale *= _element->scale.scale; + _element = _element->scale.texture; + } + _NBL_DEBUG_BREAK_IF(_element && _element->type!=CElementTexture::BITMAP); + if (!_element) + { + os::Printer::log("[ERROR] Could Not Find Texture, dangling reference after scale unroll, substituting 2x2 Magenta Checkerboard Error Texture.", ELL_ERROR); + return getErrorTexture(_loaderContext); + } + + asset::IAsset::E_TYPE types[2]{ asset::IAsset::ET_IMAGE_VIEW, asset::IAsset::ET_TERMINATING_ZERO }; + const auto key = _loaderContext.imageViewCacheKey(_element->bitmap,semantic); + auto viewBundle = _loaderContext.override_->findCachedAsset(key,types,_loaderContext.inner,0u); + if (!viewBundle.getContents().empty()) + { + auto view = core::smart_refctd_ptr_static_cast(viewBundle.getContents().begin()[0]); + + // TODO: here for the bumpmap bug + auto found = _loaderContext.derivMapCache.find(view->getCreationParameters().image); + if (found!=_loaderContext.derivMapCache.end()) + { + const float normalizationFactor = found->second; + scale *= normalizationFactor; + } + + types[0] = asset::IAsset::ET_SAMPLER; + const std::string samplerKey = _loaderContext.samplerCacheKey(_loaderContext.computeSamplerParameters(_element->bitmap)); + auto samplerBundle = _loaderContext.override_->findCachedAsset(samplerKey, types, _loaderContext.inner, 0u); + assert(!samplerBundle.getContents().empty()); + auto sampler = core::smart_refctd_ptr_static_cast(samplerBundle.getContents().begin()[0]); + + return {view, sampler, scale}; + } + return { nullptr, nullptr, core::nan()}; +} + +auto CMaterialCompilerFrontend::getErrorTexture(const SContext& _loaderContext) -> tex_ass_type +{ + constexpr const char* ERR_TEX_CACHE_NAME = "nbl/builtin/image_view/dummy2d"; + constexpr const char* ERR_SMPLR_CACHE_NAME = "nbl/builtin/sampler/default"; + + asset::IAsset::E_TYPE types[2]{ asset::IAsset::ET_IMAGE_VIEW, asset::IAsset::ET_TERMINATING_ZERO }; + auto bundle = _loaderContext.override_->findCachedAsset(ERR_TEX_CACHE_NAME, types, _loaderContext.inner, 0u); + assert(!bundle.getContents().empty()); // this shouldnt ever happen since ERR_TEX_CACHE_NAME is builtin asset + + auto view = core::smart_refctd_ptr_static_cast(bundle.getContents().begin()[0]); + + types[0] = asset::IAsset::ET_SAMPLER; + auto sbundle = _loaderContext.override_->findCachedAsset(ERR_SMPLR_CACHE_NAME, types, _loaderContext.inner, 0u); + assert(!sbundle.getContents().empty()); // this shouldnt ever happen since ERR_SMPLR_CACHE_NAME is builtin asset + + auto smplr = core::smart_refctd_ptr_static_cast(sbundle.getContents().begin()[0]); + + return { view, smplr, 1.f }; +} + +auto CMaterialCompilerFrontend::createIRNode(SContext& ctx, const CElementBSDF* _bsdf, const bool frontface) -> node_handle_t +{ + using namespace asset::material_compiler; + + + auto getFloatOrTexture = [&ctx](const CElementTexture::FloatOrTexture& src) -> IR::INode::SParameter + { + if (src.value.type == SPropertyElementData::INVALID) + { + IR::INode::STextureSource tex; + std::tie(tex.image, tex.sampler, tex.scale) = getTexture(ctx,src.texture); + return tex; + } + else + return src.value.fvalue; + }; + auto getSpectrumOrTexture = [&ctx](const CElementTexture::SpectrumOrTexture& src, const E_IMAGE_VIEW_SEMANTIC semantic=EIVS_IDENTITIY) -> IR::INode::SParameter + { + if (src.value.type == SPropertyElementData::INVALID) + { + IR::INode::STextureSource tex; + std::tie(tex.image, tex.sampler, tex.scale) = getTexture(ctx,src.texture,semantic); + return tex; + } + else + return src.value.vvalue; + }; + + auto setAlpha = [&getFloatOrTexture](IR::IMicrofacetBSDFNode* node, const bool rough, const auto& _bsdfEl) -> void + { + if (rough) + { + using bsdf_t = std::remove_const_t>; + if constexpr (std::is_same_v || std::is_same_v) + node->alpha_u = getFloatOrTexture(_bsdfEl.alpha); + else + node->alpha_u = getFloatOrTexture(_bsdfEl.alphaU); + node->alpha_v = node->alpha_u; + if constexpr (std::is_base_of_v) + { + constexpr IR::CMicrofacetSpecularBSDFNode::E_NDF ndfMap[4] = + { + IR::CMicrofacetSpecularBSDFNode::ENDF_BECKMANN, + IR::CMicrofacetSpecularBSDFNode::ENDF_GGX, + IR::CMicrofacetSpecularBSDFNode::ENDF_PHONG, + IR::CMicrofacetSpecularBSDFNode::ENDF_ASHIKHMIN_SHIRLEY + }; + auto& ndf = static_cast(node)->ndf; + ndf = ndfMap[_bsdfEl.distribution]; + if (ndf==IR::CMicrofacetSpecularBSDFNode::ENDF_ASHIKHMIN_SHIRLEY) + node->alpha_v = getFloatOrTexture(_bsdfEl.alphaV); + } + } + else + node->setSmooth(); + }; + + auto& hashCons = ctx.frontend_ctx; + auto ir_node = IR::invalid_node; + auto findAndSetChild = [&hashCons,_bsdf,frontface](IR::INode* pNode, const uint32_t childIx) -> node_handle_t + { + const CElementBSDF* child = _bsdf->type==CElementBSDF::COATING ? _bsdf->coating.bsdf[childIx]:_bsdf->meta_common.bsdf[childIx]; + const bool twosided = unwindTwosided(child); + auto found = hashCons.find({child,frontface||twosided}); + assert(found!=hashCons.end()); + return pNode->getChildrenArray()[childIx] = std::get(*found); + }; + auto* ir = ctx.ir.get(); + const auto type = _bsdf->type; + switch (type) + { + case CElementBSDF::MASK: + { + IR::INode::SParameter opacity = getSpectrumOrTexture(_bsdf->mask.opacity,EIVS_BLEND_WEIGHT); + ir_node = ir->allocNode(1); + auto pNode = ir->getNode(ir_node); + pNode->opacity = std::move(opacity); + findAndSetChild(pNode,0u); + break; + } + case CElementBSDF::DIFFUSE: + case CElementBSDF::ROUGHDIFFUSE: + { + assert(frontface); // hash consing should have replaced this one with black diffuse + ir_node = ir->allocNode(0); + auto pNode = ir->getNode(ir_node); + setAlpha(pNode,type==CElementBSDF::ROUGHDIFFUSE,_bsdf->diffuse); + pNode->reflectance = getSpectrumOrTexture(_bsdf->diffuse.reflectance); + break; + } + case CElementBSDF::CONDUCTOR: + case CElementBSDF::ROUGHCONDUCTOR: + { + assert(frontface); // hash consing should have replaced this one with black diffuse + ir_node = ir->allocNode(0); + auto pNode = ir->getNode(ir_node); + setAlpha(pNode,type==CElementBSDF::ROUGHCONDUCTOR,_bsdf->conductor); + const float extEta = _bsdf->conductor.extEta; + pNode->eta = _bsdf->conductor.eta.vvalue/extEta; + pNode->etaK = _bsdf->conductor.k.vvalue/extEta; + // IR TODO: first check if eta=1 or etaK=INF (no idea actually what would cause pitch black fresnel), then replace with NOOP + break; + } + case CElementBSDF::DIFFUSE_TRANSMITTER: + { + ir_node = ir->allocNode(0); + auto pNode = ir->getNode(ir_node); + pNode->setSmooth(); + pNode->transmittance = getSpectrumOrTexture(_bsdf->difftrans.transmittance); + break; + } + case CElementBSDF::PLASTIC: + case CElementBSDF::ROUGHPLASTIC: + { + assert(frontface); // hash consing should have replaced this one with black diffuse + const bool rough = type==CElementBSDF::ROUGHPLASTIC; + + ir_node = ir->allocNode(1); + auto coat = ir->getNode(ir_node); + setAlpha(coat,rough,_bsdf->plastic); + coat->eta = IR::INode::color_t(_bsdf->plastic.intIOR/_bsdf->plastic.extIOR); + + { + CElementBSDF tmp("impl_tmp_diffuse_element"); + tmp.type = rough ? CElementBSDF::ROUGHDIFFUSE:CElementBSDF::DIFFUSE; + tmp.diffuse.alpha = _bsdf->plastic.alpha; + tmp.diffuse.reflectance = _bsdf->plastic.diffuseReflectance; + coat->getChildrenArray()[0] = createIRNode(ctx,&tmp,frontface); + } + break; + } + case CElementBSDF::DIELECTRIC: + case CElementBSDF::THINDIELECTRIC: + case CElementBSDF::ROUGHDIELECTRIC: + { + ir_node = ir->allocNode(0); + auto dielectric = ir->getNode(ir_node); + setAlpha(dielectric,type==CElementBSDF::ROUGHDIELECTRIC,_bsdf->dielectric); + dielectric->thin = type==CElementBSDF::THINDIELECTRIC; + if (frontface || dielectric->thin) + dielectric->eta = IR::INode::color_t(_bsdf->dielectric.intIOR/_bsdf->dielectric.extIOR); + else + dielectric->eta = IR::INode::color_t(_bsdf->dielectric.extIOR/_bsdf->dielectric.intIOR); + break; + } + case CElementBSDF::BUMPMAP: + { + ir_node = ir->allocNode(1,IR::CGeomModifierNode::ET_DERIVATIVE); + auto* pNode = ir->getNode(ir_node); + //no other source supported for now (uncomment in the future) [far future TODO] + //node->source = IR::CGeomModifierNode::ESRC_TEXTURE; + + std::tie(pNode->texture.image,pNode->texture.sampler,pNode->texture.scale) = + getTexture(ctx,_bsdf->bumpmap.texture,_bsdf->bumpmap.wasNormal ? EIVS_NORMAL_MAP:EIVS_BUMP_MAP); + + findAndSetChild(pNode,0); + break; + } + case CElementBSDF::COATING: + case CElementBSDF::ROUGHCOATING: + { + assert(frontface); // hash consing should have replaced this one with black diffuse + + const bool rough = type==CElementBSDF::ROUGHDIELECTRIC; + + ir_node = ir->allocNode(1u); + auto* coat = ir->getNode(ir_node); + setAlpha(coat,rough,_bsdf->coating); + + coat->eta = IR::INode::color_t(_bsdf->dielectric.intIOR/_bsdf->dielectric.extIOR); + + const float thickness = _bsdf->coating.thickness; + coat->thicknessSigmaA = getSpectrumOrTexture(_bsdf->coating.sigmaA); + if (coat->thicknessSigmaA.isConstant()) + coat->thicknessSigmaA.constant *= thickness; + else + coat->thicknessSigmaA.texture.scale *= thickness; + + findAndSetChild(coat,0); + break; + } + break; + case CElementBSDF::BLEND_BSDF: + { + ir_node = ir->allocNode(2); + auto* pNode = ir->getNode(ir_node); + if (_bsdf->blendbsdf.weight.value.type == SPropertyElementData::INVALID) + { + std::tie(pNode->weight.texture.image,pNode->weight.texture.sampler,pNode->weight.texture.scale) = + getTexture(ctx,_bsdf->blendbsdf.weight.texture,EIVS_BLEND_WEIGHT); + assert(!core::isnan(pNode->weight.texture.scale)); + } + else + pNode->weight = IR::INode::color_t(_bsdf->blendbsdf.weight.value.fvalue); + findAndSetChild(pNode,0); + findAndSetChild(pNode,1); + } + break; + case CElementBSDF::MIXTURE_BSDF: + { + ir_node = ir->allocNode(_bsdf->mixturebsdf.childCount); + auto* pNode = ir->getNode(ir_node); + const auto* weightIt = _bsdf->mixturebsdf.weights; + for (size_t i=0u; igetChildCount(); i++) + { + pNode->weights[i] = *(weightIt++); + findAndSetChild(pNode,i); + } + break; + } + default: + break; + } + assert(ir_node!=IR::invalid_node); + const bool inserted = std::get(hashCons.insert({{_bsdf,frontface},ir_node})); + assert(inserted); + return ir_node; +} + +auto CMaterialCompilerFrontend::compileToIRTree(SContext& ctx, const CElementBSDF* _root) -> front_and_back_t +{ + using namespace asset::material_compiler; + + auto traverseForSide = [&ctx,_root](const bool frontface) -> node_handle_t + { + auto root = IR::invalid_node; + //create frontface IR + struct DFSData + { + const CElementBSDF* bsdf; + // to do Post-Order DFS we need to visit parent twice + uint8_t visited : 1; + + CElementBSDF::Type type() const { return bsdf->type; } + }; + core::stack dfs; + auto& hashCons = ctx.frontend_ctx; + auto pre = [&](const CElementBSDF* _bsdf) + { + DFSData el = {_bsdf}; + const bool twosided = unwindTwosided(el.bsdf); + // + auto found = hashCons.find({el.bsdf,frontface||twosided}); + if (found!=hashCons.end()) + root = std::get(*found); + else + { + // we traversed the tree before, we must be able to find an entry for a front facing branch! + assert(!twosided); + // only meta nodes get pushed onto stack + if (el.bsdf->isMeta()) + { + el.visited = false; + dfs.push(std::move(el)); + } + else + root = createIRNode(ctx,el.bsdf,frontface); + } + }; + pre(_root); + while (!dfs.empty()) + { + auto& parent = dfs.top(); + assert(parent.type()!=CElementBSDF::TWO_SIDED); + assert(parent.bsdf->isMeta()); + + if (parent.visited) + { + dfs.pop(); + auto found = hashCons.find({parent.bsdf,frontface}); + if (found!=hashCons.end()) + root = std::get(*found); + else + root = createIRNode(ctx,parent.bsdf,frontface); + } + else + { + parent.visited = true; + + const bool isCoating = parent.type()==CElementBSDF::COATING; + const auto childCount = isCoating ? parent.bsdf->coating.childCount:parent.bsdf->meta_common.childCount; + for (auto i=0u; icoating.bsdf[i]:parent.bsdf->meta_common.bsdf[i]; + pre(child); + } + } + } + ctx.ir->addRootNode(root); + return root; + }; + + // set up an invalid/vanta-black/NOOP node first + if (!ctx.frontend_ctx.empty()) + { + CElementBSDF invalid("invalid_vanta_black_noop"); + invalid.type = CElementBSDF::DIFFUSE; + invalid.diffuse.reflectance = 0.f; + createIRNode(ctx,&invalid,true); + } + + // its important to generate the IR for the front-face first, so that backface can reuse + // any twosided or orientation agnostic nodes which are in the consing cache + front_and_back_t retval; + retval.front = traverseForSide(true); + retval.back = traverseForSide(false); + return retval; +} + +bool CMaterialCompilerFrontend::MerkleTree::equal_to::operator()(const MerkleTree& lhs, const MerkleTree& rhs) const +{ + return lhs.bsdf==rhs.bsdf && lhs.frontface==rhs.frontface; +} + +std::size_t CMaterialCompilerFrontend::MerkleTree::hash::operator()(const MerkleTree& node) const +{ + return ptrdiff_t(node.bsdf); +} + +} \ No newline at end of file diff --git a/src/nbl/ext/MitsubaLoader/CMitsubaLoader.cpp b/src/nbl/ext/MitsubaLoader/CMitsubaLoader.cpp index 3d587c088d..a7bfd7154e 100644 --- a/src/nbl/ext/MitsubaLoader/CMitsubaLoader.cpp +++ b/src/nbl/ext/MitsubaLoader/CMitsubaLoader.cpp @@ -1,4 +1,3 @@ -#include "..\..\..\..\include\nbl\ext\MitsubaLoader\CMitsubaLoader.h" // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h @@ -218,7 +217,7 @@ static core::smart_refctd_ptr createAndCacheVertex return vs; } -static core::smart_refctd_ptr createFragmentShader(const asset::material_compiler::CMaterialCompilerGLSLBackendCommon::result_t& _mcRes, size_t _VTstorageViewCount) +static core::smart_refctd_ptr createFragmentShader(const asset::material_compiler::CGLSLBackendCommon::result_t& _mcRes, size_t _VTstorageViewCount) { std::string source = FRAGMENT_SHADER_PROLOGUE + @@ -944,7 +943,7 @@ SContext::shape_ass_type CMitsubaLoader::loadBasicShape(SContext& ctx, uint32_t return mesh; } -void CMitsubaLoader::cacheTexture(SContext& ctx, uint32_t hierarchyLevel, const CElementTexture* tex, const CMitsubaMaterialCompilerFrontend::E_IMAGE_VIEW_SEMANTIC semantic) +void CMitsubaLoader::cacheTexture(SContext& ctx, uint32_t hierarchyLevel, const CElementTexture* tex, const CMaterialCompilerFrontend::E_IMAGE_VIEW_SEMANTIC semantic) { if (!tex) return; @@ -967,7 +966,7 @@ void CMitsubaLoader::cacheTexture(SContext& ctx, uint32_t hierarchyLevel, const { auto loadParams = ctx.inner.params; // always restore, the only reason we haven't found a view is because either the image wasnt loaded yet, or its going to be processed with channel extraction or derivative mapping - const uint32_t restoreLevels = semantic==CMitsubaMaterialCompilerFrontend::EIVS_IDENTITIY&&tex->bitmap.channel==CElementTexture::Bitmap::CHANNEL::INVALID ? 0u:2u; // all the way to the buffer providing the pixels + const uint32_t restoreLevels = semantic==CMaterialCompilerFrontend::EIVS_IDENTITIY&&tex->bitmap.channel==CElementTexture::Bitmap::CHANNEL::INVALID ? 0u:2u; // all the way to the buffer providing the pixels loadParams.restoreLevels = std::max(loadParams.restoreLevels,hierarchyLevel+restoreLevels); // load using the actual filename, not the cache key asset::SAssetBundle bundle = interm_getAssetInHierarchy(m_assetMgr,tex->bitmap.filename.svalue,loadParams,hierarchyLevel,ctx.override_); @@ -995,8 +994,8 @@ void CMitsubaLoader::cacheTexture(SContext& ctx, uint32_t hierarchyLevel, const } switch (semantic) { - case CMitsubaMaterialCompilerFrontend::EIVS_IDENTITIY: - case CMitsubaMaterialCompilerFrontend::EIVS_BLEND_WEIGHT: + case CMaterialCompilerFrontend::EIVS_IDENTITIY: + case CMaterialCompilerFrontend::EIVS_BLEND_WEIGHT: { switch (tex->bitmap.channel) { @@ -1020,16 +1019,16 @@ void CMitsubaLoader::cacheTexture(SContext& ctx, uint32_t hierarchyLevel, const case CElementTexture::Bitmap::CHANNEL::INVALID: [[fallthrough]]; default: - if (semantic==CMitsubaMaterialCompilerFrontend::EIVS_BLEND_WEIGHT && asset::getFormatChannelCount(viewParams.image->getCreationParameters().format)<3u) + if (semantic==CMaterialCompilerFrontend::EIVS_BLEND_WEIGHT && asset::getFormatChannelCount(viewParams.image->getCreationParameters().format)<3u) viewParams.image = createSingleChannelImage(viewParams.image.get(),asset::ICPUImageView::SComponentMapping::ES_IDENTITY); break; } } break; - case CMitsubaMaterialCompilerFrontend::EIVS_NORMAL_MAP: + case CMaterialCompilerFrontend::EIVS_NORMAL_MAP: viewParams.image = createDerivMap(ctx,viewParams.image.get(),samplerParams,true); break; - case CMitsubaMaterialCompilerFrontend::EIVS_BUMP_MAP: + case CMaterialCompilerFrontend::EIVS_BUMP_MAP: viewParams.image = createDerivMap(ctx,viewParams.image.get(),samplerParams,false); break; default: @@ -1082,7 +1081,7 @@ void CMitsubaLoader::cacheTexture(SContext& ctx, uint32_t hierarchyLevel, const auto CMitsubaLoader::getBSDFtreeTraversal(SContext& ctx, const CElementBSDF* bsdf) -> SContext::bsdf_type { if (!bsdf) - return {nullptr,nullptr}; + return {asset::material_compiler::IR::invalid_node,asset::material_compiler::IR::invalid_node}; auto found = ctx.instrStreamCache.find(bsdf); if (found!=ctx.instrStreamCache.end()) @@ -1095,7 +1094,7 @@ auto CMitsubaLoader::getBSDFtreeTraversal(SContext& ctx, const CElementBSDF* bsd auto CMitsubaLoader::genBSDFtreeTraversal(SContext& ctx, const CElementBSDF* _bsdf) -> SContext::bsdf_type { { - auto cachePropertyTexture = [&](const auto& const_or_tex, const CMitsubaMaterialCompilerFrontend::E_IMAGE_VIEW_SEMANTIC semantic=CMitsubaMaterialCompilerFrontend::EIVS_IDENTITIY) -> void + auto cachePropertyTexture = [&](const auto& const_or_tex, const CMaterialCompilerFrontend::E_IMAGE_VIEW_SEMANTIC semantic=CMaterialCompilerFrontend::EIVS_IDENTITIY) -> void { if (const_or_tex.value.type==SPropertyElementData::INVALID) cacheTexture(ctx,0u,const_or_tex.texture,semantic); @@ -1157,28 +1156,28 @@ auto CMitsubaLoader::genBSDFtreeTraversal(SContext& ctx, const CElementBSDF* _bs cachePropertyTexture(bsdf->plastic.alphaV); break; case CElementBSDF::BUMPMAP: - cacheTexture(ctx,0u,bsdf->bumpmap.texture,bsdf->bumpmap.wasNormal ? CMitsubaMaterialCompilerFrontend::EIVS_NORMAL_MAP:CMitsubaMaterialCompilerFrontend::EIVS_BUMP_MAP); + cacheTexture(ctx,0u,bsdf->bumpmap.texture,bsdf->bumpmap.wasNormal ? CMaterialCompilerFrontend::EIVS_NORMAL_MAP:CMaterialCompilerFrontend::EIVS_BUMP_MAP); break; case CElementBSDF::BLEND_BSDF: - cachePropertyTexture(bsdf->blendbsdf.weight,CMitsubaMaterialCompilerFrontend::EIVS_BLEND_WEIGHT); + cachePropertyTexture(bsdf->blendbsdf.weight,CMaterialCompilerFrontend::EIVS_BLEND_WEIGHT); break; case CElementBSDF::MASK: - cachePropertyTexture(bsdf->mask.opacity,CMitsubaMaterialCompilerFrontend::EIVS_BLEND_WEIGHT); + cachePropertyTexture(bsdf->mask.opacity,CMaterialCompilerFrontend::EIVS_BLEND_WEIGHT); break; default: break; } } } - return ctx.frontend.compileToIRTree(ctx.ir.get(), _bsdf); + return CMaterialCompilerFrontend::compileToIRTree(ctx,_bsdf); } // TODO: this function shouldn't really exist because the backend should produce this directly @Crisspl -asset::material_compiler::oriented_material_t impl_backendToGLSLStream(const core::vectorSIMDf& emissive, const asset::material_compiler::CMaterialCompilerGLSLBackendCommon::result_t::instr_streams_t* streams) +asset::material_compiler::CGLSLBackendCommon::oriented_material_t impl_backendToGLSLStream(const core::vectorSIMDf& emissive, const asset::material_compiler::CGLSLBackendCommon::result_t::instr_streams_t* streams) { - asset::material_compiler::oriented_material_t orientedMaterial; + asset::material_compiler::CGLSLBackendCommon::oriented_material_t orientedMaterial; orientedMaterial.emissive = core::rgb32f_to_rgb19e7(emissive.pointer); if(streams) { @@ -1204,7 +1203,7 @@ asset::material_compiler::oriented_material_t impl_backendToGLSLStream(const cor // Also sets instance data buffer offset into meshbuffers' base instance template -inline core::smart_refctd_ptr CMitsubaLoader::createDS0(const SContext& _ctx, asset::ICPUPipelineLayout* _layout, const asset::material_compiler::CMaterialCompilerGLSLBackendCommon::result_t& _compResult, Iter meshBegin, Iter meshEnd) +inline core::smart_refctd_ptr CMitsubaLoader::createDS0(const SContext& _ctx, asset::ICPUPipelineLayout* _layout, const asset::material_compiler::CGLSLBackendCommon::result_t& _compResult, Iter meshBegin, Iter meshEnd) { auto* ds0layout = _layout->getDescriptorSetLayout(0u); @@ -1267,7 +1266,7 @@ inline core::smart_refctd_ptr CMitsubaLoader::createDS #ifdef DEBUG_MITSUBA_LOADER std::ofstream ofile("log.txt"); #endif - core::vector instanceData; + core::vector instanceData; for (auto it=meshBegin; it != meshEnd; ++it) { auto mesh = it->first.get(); @@ -1279,7 +1278,7 @@ inline core::smart_refctd_ptr CMitsubaLoader::createDS auto baseInstanceDataIt = meshMeta->m_instances.begin(); for (const auto& inst : meshMeta->m_instanceAuxData) { - nbl_glsl_ext_Mitsuba_Loader_instance_data_t instData; + instance_data_t instData; instData.tform = baseInstanceDataIt->worldTform; instData.tform.getSub3x3InverseTranspose(reinterpret_cast(instData.normalMatrixRow0)); @@ -1291,7 +1290,7 @@ inline core::smart_refctd_ptr CMitsubaLoader::createDS auto bsdf_back = bsdf.back; auto streams_it = _compResult.streams.find(bsdf_front); { - const asset::material_compiler::CMaterialCompilerGLSLBackendCommon::result_t::instr_streams_t* streams = + const asset::material_compiler::CGLSLBackendCommon::result_t::instr_streams_t* streams = (streams_it != _compResult.streams.end()) ? &streams_it->second : nullptr; #ifdef DEBUG_MITSUBA_LOADER @@ -1307,7 +1306,7 @@ inline core::smart_refctd_ptr CMitsubaLoader::createDS } streams_it = _compResult.streams.find(bsdf_back); { - const asset::material_compiler::CMaterialCompilerGLSLBackendCommon::result_t::instr_streams_t* streams = + const asset::material_compiler::CGLSLBackendCommon::result_t::instr_streams_t* streams = (streams_it != _compResult.streams.end()) ? &streams_it->second : nullptr; #ifdef DEBUG_MITSUBA_LOADER @@ -1331,7 +1330,7 @@ inline core::smart_refctd_ptr CMitsubaLoader::createDS #endif d = ds0->getDescriptors(INSTANCE_DATA_BINDING).begin(); { - auto instDataBuf = core::make_smart_refctd_ptr(instanceData.size()*sizeof(nbl_glsl_ext_Mitsuba_Loader_instance_data_t)); + auto instDataBuf = core::make_smart_refctd_ptr(instanceData.size()*sizeof(instance_data_t)); memcpy(instDataBuf->getPointer(), instanceData.data(), instDataBuf->getSize()); d->buffer.offset = 0u; @@ -1351,7 +1350,7 @@ SContext::SContext( asset::IAssetLoader::IAssetLoaderOverride* _override, CMitsubaMetadata* _metadata ) : creator(_geomCreator), manipulator(_manipulator), inner(_ctx), override_(_override), meta(_metadata), - ir(core::make_smart_refctd_ptr()), frontend(this), + frontend_ctx{}, ir(core::make_smart_refctd_ptr()), samplerCacheKeyBase(inner.mainFile->getFileName().c_str() + "?sampler"s) { backend_ctx.vt.vt = core::make_smart_refctd_ptr( diff --git a/src/nbl/ext/MitsubaLoader/CMitsubaMaterialCompilerFrontend.cpp b/src/nbl/ext/MitsubaLoader/CMitsubaMaterialCompilerFrontend.cpp deleted file mode 100644 index af19d2cea9..0000000000 --- a/src/nbl/ext/MitsubaLoader/CMitsubaMaterialCompilerFrontend.cpp +++ /dev/null @@ -1,478 +0,0 @@ -// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. -// This file is part of the "Nabla Engine". -// For conditions of distribution and use, see copyright notice in nabla.h - -#include "nbl/ext/MitsubaLoader/CMitsubaMaterialCompilerFrontend.h" -#include "nbl/ext/MitsubaLoader/SContext.h" - -namespace nbl::ext::MitsubaLoader -{ - -std::pair CMitsubaMaterialCompilerFrontend::unwindTextureScale(const CElementTexture* _element) const -{ - float scale = 1.f; - while (_element && _element->type==CElementTexture::SCALE) - { - scale *= _element->scale.scale; - _element = _element->scale.texture; - } - _NBL_DEBUG_BREAK_IF(_element && _element->type!=CElementTexture::BITMAP); - - return {_element,scale}; -} -auto CMitsubaMaterialCompilerFrontend::getTexture(const CElementTexture* _element, const E_IMAGE_VIEW_SEMANTIC semantic) const -> tex_ass_type -{ - float scale = 1.f; - std::tie(_element, scale) = unwindTextureScale(_element); - if (!_element) - { - os::Printer::log("[ERROR] Could Not Find Texture, dangling reference after scale unroll, substituting 2x2 Magenta Checkerboard Error Texture.", ELL_ERROR); - return getErrorTexture(); - } - - asset::IAsset::E_TYPE types[2]{ asset::IAsset::ET_IMAGE_VIEW, asset::IAsset::ET_TERMINATING_ZERO }; - const auto key = SContext::imageViewCacheKey(_element->bitmap,semantic); - auto viewBundle = m_loaderContext->override_->findCachedAsset(key,types,m_loaderContext->inner,0u); - if (!viewBundle.getContents().empty()) - { - auto view = core::smart_refctd_ptr_static_cast(viewBundle.getContents().begin()[0]); - - auto found = m_loaderContext->derivMapCache.find(view->getCreationParameters().image); - if (found!=m_loaderContext->derivMapCache.end()) - { - const float normalizationFactor = found->second; - scale *= normalizationFactor; - } - - types[0] = asset::IAsset::ET_SAMPLER; - const std::string samplerKey = m_loaderContext->samplerCacheKey(SContext::computeSamplerParameters(_element->bitmap)); - auto samplerBundle = m_loaderContext->override_->findCachedAsset(samplerKey, types, m_loaderContext->inner, 0u); - assert(!samplerBundle.getContents().empty()); - auto sampler = core::smart_refctd_ptr_static_cast(samplerBundle.getContents().begin()[0]); - - return {view, sampler, scale}; - } - return { nullptr, nullptr, scale }; -} - -auto CMitsubaMaterialCompilerFrontend::getErrorTexture() const -> tex_ass_type -{ - constexpr const char* ERR_TEX_CACHE_NAME = "nbl/builtin/image_view/dummy2d"; - constexpr const char* ERR_SMPLR_CACHE_NAME = "nbl/builtin/sampler/default"; - - asset::IAsset::E_TYPE types[2]{ asset::IAsset::ET_IMAGE_VIEW, asset::IAsset::ET_TERMINATING_ZERO }; - auto bundle = m_loaderContext->override_->findCachedAsset(ERR_TEX_CACHE_NAME, types, m_loaderContext->inner, 0u); - assert(!bundle.getContents().empty()); // this shouldnt ever happen since ERR_TEX_CACHE_NAME is builtin asset - - auto view = core::smart_refctd_ptr_static_cast(bundle.getContents().begin()[0]); - - types[0] = asset::IAsset::ET_SAMPLER; - auto sbundle = m_loaderContext->override_->findCachedAsset(ERR_SMPLR_CACHE_NAME, types, m_loaderContext->inner, 0u); - assert(!sbundle.getContents().empty()); // this shouldnt ever happen since ERR_SMPLR_CACHE_NAME is builtin asset - - auto smplr = core::smart_refctd_ptr_static_cast(sbundle.getContents().begin()[0]); - - return { view, smplr, 1.f }; -} - - auto CMitsubaMaterialCompilerFrontend::createIRNode(asset::material_compiler::IR* ir, const CElementBSDF* _bsdf) -> IRNode* - { - using namespace asset; - using namespace material_compiler; - - auto getFloatOrTexture = [this](const CElementTexture::FloatOrTexture& src, IR::INode::SParameter& dst) - { - if (src.value.type == SPropertyElementData::INVALID) - { - IR::INode::STextureSource tex; - std::tie(tex.image, tex.sampler, tex.scale) = getTexture(src.texture); - dst = std::move(tex); - } - else dst = src.value.fvalue; - }; - auto getSpectrumOrTexture = [this](const CElementTexture::SpectrumOrTexture& src, IR::INode::SParameter& dst, const E_IMAGE_VIEW_SEMANTIC semantic=EIVS_IDENTITIY) -> void - { - if (src.value.type == SPropertyElementData::INVALID) - { - IR::INode::STextureSource tex; - std::tie(tex.image, tex.sampler, tex.scale) = getTexture(src.texture,semantic); - dst = std::move(tex); - } - else - dst = src.value.vvalue; - }; - - constexpr IR::CMicrofacetSpecularBSDFNode::E_NDF ndfMap[4]{ - IR::CMicrofacetSpecularBSDFNode::ENDF_BECKMANN, - IR::CMicrofacetSpecularBSDFNode::ENDF_GGX, - IR::CMicrofacetSpecularBSDFNode::ENDF_PHONG, - IR::CMicrofacetSpecularBSDFNode::ENDF_ASHIKHMIN_SHIRLEY - }; - - const auto type = _bsdf->type; - IRNode* ir_node = nullptr; - switch (type) - { - case CElementBSDF::TWO_SIDED: - //TWO_SIDED is not translated into IR node directly - break; - case CElementBSDF::MASK: - ir_node = ir->allocNode(); - ir_node->children.count = 1u; - getSpectrumOrTexture(_bsdf->mask.opacity,static_cast(ir_node)->opacity,EIVS_BLEND_WEIGHT); - break; - case CElementBSDF::DIFFUSE: - case CElementBSDF::ROUGHDIFFUSE: - ir_node = ir->allocNode(); - getSpectrumOrTexture(_bsdf->diffuse.reflectance, static_cast(ir_node)->reflectance); - if (type == CElementBSDF::ROUGHDIFFUSE) - { - getFloatOrTexture(_bsdf->diffuse.alpha, static_cast(ir_node)->alpha_u); - static_cast(ir_node)->alpha_v = static_cast(ir_node)->alpha_u; - } - else - { - static_cast(ir_node)->setSmooth(); - } - break; - case CElementBSDF::CONDUCTOR: - case CElementBSDF::ROUGHCONDUCTOR: - { - ir_node = ir->allocNode(); - auto* node = static_cast(ir_node); - node->shadowing = IR::CMicrofacetSpecularBSDFNode::EST_SMITH; - const float extEta = _bsdf->conductor.extEta; - node->eta = _bsdf->conductor.eta.vvalue/extEta; - node->etaK = _bsdf->conductor.k.vvalue/extEta; - - if (type == CElementBSDF::ROUGHCONDUCTOR) - { - node->ndf = ndfMap[_bsdf->conductor.distribution]; - getFloatOrTexture(_bsdf->conductor.alphaU, node->alpha_u); - if (node->ndf == IR::CMicrofacetSpecularBSDFNode::ENDF_ASHIKHMIN_SHIRLEY) - getFloatOrTexture(_bsdf->conductor.alphaV, node->alpha_v); - else - node->alpha_v = node->alpha_u; - } - else - { - node->setSmooth(); - } - } - break; - case CElementBSDF::DIFFUSE_TRANSMITTER: - { - ir_node = ir->allocNode(); - auto* node = static_cast(ir_node); - node->setSmooth(); - - getSpectrumOrTexture(_bsdf->difftrans.transmittance, node->transmittance); - } - break; - case CElementBSDF::PLASTIC: - case CElementBSDF::ROUGHPLASTIC: - { - ir_node = ir->allocNode(); - auto* coat = static_cast(ir_node); - coat->children.count = 1u; - - auto& coated = ir_node->children[0]; - coated = ir->allocNode(); - - const float eta = _bsdf->plastic.intIOR/_bsdf->plastic.extIOR; - - coat->shadowing = IR::CMicrofacetSpecularBSDFNode::EST_SMITH; - coat->eta = IR::INode::color_t(eta); - if (type == CElementBSDF::ROUGHPLASTIC) - { - coat->ndf = ndfMap[_bsdf->plastic.distribution]; - getFloatOrTexture(_bsdf->plastic.alphaU, coat->alpha_u); - if (coat->ndf == IR::CMicrofacetSpecularBSDFNode::ENDF_ASHIKHMIN_SHIRLEY) - getFloatOrTexture(_bsdf->plastic.alphaV, coat->alpha_v); - else - coat->alpha_v = coat->alpha_u; - } - else coat->setSmooth(); - - auto* node_diffuse = static_cast(coated); - getSpectrumOrTexture(_bsdf->plastic.diffuseReflectance, node_diffuse->reflectance); - node_diffuse->alpha_u = coat->alpha_u; - node_diffuse->alpha_v = coat->alpha_v; - node_diffuse->eta = coat->eta; - } - break; - case CElementBSDF::DIELECTRIC: - case CElementBSDF::THINDIELECTRIC: - case CElementBSDF::ROUGHDIELECTRIC: - { - auto* dielectric = ir->allocNode(); - ir_node = dielectric; - - const float eta = _bsdf->dielectric.intIOR/_bsdf->dielectric.extIOR; - _NBL_DEBUG_BREAK_IF(eta==1.f); - if (eta==1.f) - os::Printer::log("WARNING: Dielectric with IoR=1.0!", _bsdf->id, ELL_ERROR); - - dielectric->shadowing = IR::CMicrofacetSpecularBSDFNode::EST_SMITH; - dielectric->eta = IR::INode::color_t(eta); - if (type == CElementBSDF::ROUGHDIELECTRIC) - { - dielectric->ndf = ndfMap[_bsdf->dielectric.distribution]; - getFloatOrTexture(_bsdf->dielectric.alphaU, dielectric->alpha_u); - if (dielectric->ndf == IR::CMicrofacetSpecularBSDFNode::ENDF_ASHIKHMIN_SHIRLEY) - getFloatOrTexture(_bsdf->dielectric.alphaV, dielectric->alpha_v); - else - dielectric->alpha_v = dielectric->alpha_u; - } - else - { - dielectric->setSmooth(); - } - - dielectric->thin = (type == CElementBSDF::THINDIELECTRIC); - } - break; - case CElementBSDF::BUMPMAP: - { - ir_node = ir->allocNode(IR::CGeomModifierNode::ET_DERIVATIVE); - ir_node->children.count = 1u; - - auto* node = static_cast(ir_node); - //no other source supported for now (uncomment in the future) [far future TODO] - //node->source = IR::CGeomModifierNode::ESRC_TEXTURE; - - std::tie(node->texture.image,node->texture.sampler,node->texture.scale) = - getTexture(_bsdf->bumpmap.texture,_bsdf->bumpmap.wasNormal ? EIVS_NORMAL_MAP:EIVS_BUMP_MAP); - } - break; - case CElementBSDF::COATING: - case CElementBSDF::ROUGHCOATING: - { - ir_node = ir->allocNode(); - ir_node->children.count = 1u; - - const float eta = _bsdf->dielectric.intIOR/_bsdf->dielectric.extIOR; - - auto* node = static_cast(ir_node); - - const float thickness = _bsdf->coating.thickness; - getSpectrumOrTexture(_bsdf->coating.sigmaA, node->thicknessSigmaA); - if (node->thicknessSigmaA.isConstant()) - node->thicknessSigmaA.constant *= thickness; - else - node->thicknessSigmaA.texture.scale *= thickness; - - node->eta = IR::INode::color_t(eta); - node->shadowing = IR::CMicrofacetCoatingBSDFNode::EST_SMITH; - if (type == CElementBSDF::ROUGHCOATING) - { - node->ndf = ndfMap[_bsdf->coating.distribution]; - getFloatOrTexture(_bsdf->coating.alphaU, node->alpha_u); - if (node->ndf == IR::CMicrofacetSpecularBSDFNode::ENDF_ASHIKHMIN_SHIRLEY) - getFloatOrTexture(_bsdf->coating.alphaV, node->alpha_v); - else - node->alpha_v = node->alpha_u; - } - else - { - node->setSmooth(); - } - } - break; - case CElementBSDF::BLEND_BSDF: - { - ir_node = ir->allocNode(); - ir_node->children.count = 2u; - - auto* node = static_cast(ir_node); - if (_bsdf->blendbsdf.weight.value.type == SPropertyElementData::INVALID) - { - std::tie(node->weight.texture.image, node->weight.texture.sampler, node->weight.texture.scale) = - getTexture(_bsdf->blendbsdf.weight.texture,EIVS_BLEND_WEIGHT); - assert(!core::isnan(node->weight.texture.scale)); - } - else - node->weight = IR::INode::color_t(_bsdf->blendbsdf.weight.value.fvalue); - } - break; - case CElementBSDF::MIXTURE_BSDF: - { - ir_node = ir->allocNode(); - auto* node = static_cast(ir_node); - const size_t cnt = _bsdf->mixturebsdf.childCount; - ir_node->children.count = cnt; - const auto* weightIt = _bsdf->mixturebsdf.weights; - for (size_t i=0u; iweights[i] = *(weightIt++); - } - break; - } - - return ir_node; - } - -auto CMitsubaMaterialCompilerFrontend::compileToIRTree(asset::material_compiler::IR* ir, const CElementBSDF* _bsdf) -> front_and_back_t -{ - using namespace asset; - using namespace material_compiler; - - auto getFloatOrTexture = [this](const CElementTexture::FloatOrTexture& src, IR::INode::SParameter& dst) - { - if (src.value.type == SPropertyElementData::INVALID) - { - IR::INode::STextureSource tex; - std::tie(tex.image, tex.sampler, tex.scale) = getTexture(src.texture); - dst = std::move(tex); - } - else dst = src.value.fvalue; - }; - auto getSpectrumOrTexture = [this](const CElementTexture::SpectrumOrTexture& src, IR::INode::SParameter& dst) - { - if (src.value.type == SPropertyElementData::INVALID) - { - IR::INode::STextureSource tex; - std::tie(tex.image, tex.sampler, tex.scale) = getTexture(src.texture); - dst = std::move(tex); - } - else dst = src.value.vvalue; - }; - - struct SNode - { - const CElementBSDF* bsdf; - IRNode* ir_node = nullptr; - uint32_t parent_ix = static_cast(-1); - uint32_t child_num = 0u; - bool twosided = false; - bool front = true; - - CElementBSDF::Type type() const { return bsdf->type; } - }; - auto node_parent = [](const SNode& node, core::vector& traversal) { return &traversal[node.parent_ix]; }; - - core::vector bfs; - { - core::queue q; - { - SNode root{ _bsdf }; - root.twosided = (root.type() == CElementBSDF::TWO_SIDED); - q.push(root); - } - - while (q.size()) - { - SNode parent = q.front(); - q.pop(); - //node.ir_node = createIRNode(node.bsdf); - - if (parent.bsdf->isMeta()) - { - const uint32_t child_count = (parent.bsdf->type == CElementBSDF::COATING) ? parent.bsdf->coating.childCount : parent.bsdf->meta_common.childCount; - for (uint32_t i = 0u; i < child_count; ++i) - { - SNode child_node; - child_node.bsdf = (parent.bsdf->type == CElementBSDF::COATING) ? parent.bsdf->coating.bsdf[i] : parent.bsdf->meta_common.bsdf[i]; - child_node.parent_ix = parent.type() == CElementBSDF::TWO_SIDED ? parent.parent_ix : bfs.size(); - child_node.twosided = (child_node.type() == CElementBSDF::TWO_SIDED) || parent.twosided; - child_node.child_num = (parent.type() == CElementBSDF::TWO_SIDED) ? parent.child_num : i; - child_node.front = parent.front; - if (parent.type() == CElementBSDF::TWO_SIDED && i == 1u) - child_node.front = false; - q.push(child_node); - } - } - if (parent.type() != CElementBSDF::TWO_SIDED) - bfs.push_back(parent); - } - } - - auto createBackfaceNodeFromFrontface = [&ir](const IRNode* front) -> IRNode* - { - switch (front->symbol) - { - case IRNode::ES_BSDF_COMBINER: [[fallthrough]]; - case IRNode::ES_OPACITY: [[fallthrough]]; - case IRNode::ES_GEOM_MODIFIER: [[fallthrough]]; - case IRNode::ES_EMISSION: - return ir->copyNode(front); - case IRNode::ES_BSDF: - { - auto* bsdf = static_cast(front); - if (bsdf->type == IR::CBSDFNode::ET_MICROFACET_DIELECTRIC) - { - auto* dielectric = static_cast(bsdf); - auto* copy = static_cast(ir->copyNode(front)); - if (!copy->thin) //we're always outside in case of thin dielectric - copy->eta = IRNode::color_t(1.f) / copy->eta; - - return copy; - } - else if (bsdf->type == IR::CBSDFNode::ET_MICROFACET_DIFFTRANS) - return ir->copyNode(front); - } - [[fallthrough]]; // intentional - default: - { - // black diffuse otherwise - auto* invalid = ir->allocNode(); - invalid->setSmooth(); - invalid->reflectance = IR::INode::color_t(0.f); - - return invalid; - } - } - }; - - //create frontface IR - IRNode* frontroot = nullptr; - for (auto& node : bfs) - { - if (!node.front) - continue; - - IRNode** dst = nullptr; - if (node.parent_ix >= bfs.size()) - dst = &frontroot; - else - dst = const_cast(&node_parent(node, bfs)->ir_node->children[node.child_num]); - - node.ir_node = *dst = createIRNode(ir, node.bsdf); - } - IRNode* backroot = nullptr; - for (uint32_t i = 0u; i < bfs.size(); ++i) - { - SNode& node = bfs[i]; - - IRNode* ir_node = nullptr; - if (!node.twosided) - ir_node = createBackfaceNodeFromFrontface(node.ir_node); - else - { - if (node.front) - { - if ((i+1u) < bfs.size() && bfs[i+1u].twosided && !bfs[i+1u].front) - continue; // will take backface node in next iteration - //otherwise copy the one from front (same bsdf on both sides_ - ir_node = ir->copyNode(node.ir_node); - } - else - ir_node = createIRNode(ir, node.bsdf); - } - node.ir_node = ir_node; - - IRNode** dst = nullptr; - if (node.parent_ix >= bfs.size()) - dst = &backroot; - else - dst = const_cast(&node_parent(node, bfs)->ir_node->children[node.child_num]); - - *dst = ir_node; - } - - ir->addRootNode(frontroot); - ir->addRootNode(backroot); - - return { frontroot, backroot }; -} - -} \ No newline at end of file