153 perPassInfo[p].fill( defaultShaderInfo );
154 perPassStates[p].fill( {{},
false});
161 const bool isDepthPass =
IsDepthPass( renderStagePass );
165 const Str<64> vertSource = isDepthPass ? material->baseShaderData()._depthShaderVertSource : material->baseShaderData()._colourShaderVertSource;
166 const Str<64> fragSource = isDepthPass ? material->baseShaderData()._depthShaderFragSource : material->baseShaderData()._colourShaderFragSource;
168 Str<32> vertVariant = isDepthPass ? isShadowPass ? material->baseShaderData()._shadowShaderVertVariant
169 : material->baseShaderData()._depthShaderVertVariant
170 : material->baseShaderData()._colourShaderVertVariant;
172 Str<32> fragVariant = isDepthPass ? material->baseShaderData()._depthShaderFragVariant
173 : material->baseShaderData()._colourShaderFragVariant;
176 shaderDescriptor.
_name =
Str<256>(vertSource.c_str()) +
"_" + fragSource.c_str();
180 vertVariant +=
"Shadow";
181 fragVariant +=
"Shadow.VSM";
183 else if ( isDepthPass )
185 vertVariant +=
"PrePass";
186 fragVariant +=
"PrePass";
190 vertModule.
_variant = vertVariant.c_str();
191 vertModule.
_sourceFile = (vertSource +
".glsl").c_str();
193 shaderDescriptor._modules.push_back( vertModule );
195 if ( !isDepthPass || isZPrePass || isShadowPass || material->
hasTransparency() )
198 fragModule.
_variant = fragVariant.c_str();
199 fragModule.
_sourceFile = (fragSource +
".glsl").c_str();
202 shaderDescriptor._modules.push_back( fragModule );
205 return shaderDescriptor;
208 _recomputeShadersCBK = []()
224 DIVIDE_ASSERT( !nameSuffix.empty(),
"Material error: clone called without a valid name suffix!" );
229 cloneMat->_baseMaterial =
this;
230 cloneMat->_properties = this->_properties;
232 cloneMat->_computeShaderCBK = this->_computeShaderCBK;
233 cloneMat->_computeRenderStateCBK = this->_computeRenderStateCBK;
235 cloneMat->_topology = this->_topology;
236 cloneMat->_shaderAttributes = this->_shaderAttributes;
239 cloneMat->ignoreXMLData( this->ignoreXMLData() );
240 cloneMat->updatePriorirty( this->updatePriorirty() );
245 if ( texInfo.
_ptr != INVALID_HANDLE<Texture> )
248 cloneMat->setTexture(
262 auto& variantMapDst = cloneMat->_shaderInfo[s][p];
265 variantMapDst[v] = variantMapSrc[v].clone();
273 return cloneMatHandle;
280 if ( properties()._transparencyUpdated )
284 properties()._transparencyUpdated =
false;
286 if ( properties()._cullUpdated )
289 properties()._cullUpdated =
false;
294 properties()._needsNewShader =
false;
308 perPassStates[p].fill({{},
false});
320 for (
auto& state : perPassStates[p] )
333 if ( topology != _topology )
335 _topology = topology;
336 properties()._needsNewShader =
true;
339 const size_t newHash =
GetHash( shaderAttributes );
342 _shaderAttributes = shaderAttributes;
344 properties()._needsNewShader =
true;
363 _descriptorSetMainPass._bindingCount = {0u};
364 _descriptorSetSecondaryPass._bindingCount = { 0u };
365 _descriptorSetPrePass._bindingCount = { 0u };
366 _descriptorSetShadow._bindingCount = { 0u };
368 const U32 slot =
to_U32( textureUsageSlot );
376 if ( texInfo.
_ptr != INVALID_HANDLE<Texture> )
379 if ( texture != INVALID_HANDLE<Texture> && texInfo.
_ptr == texture )
386 texInfo.
_useInGeometryPasses = texture != INVALID_HANDLE<Texture> ? useInGeometryPasses :
false;
387 texInfo.
_ptr = texture;
391 properties()._usePackedOMR = (texture != INVALID_HANDLE<Texture> &&
Get(texture)->numChannels() > 2u);
400 properties()._needsNewShader =
true;
409 bool useInGeometryPasses)
412 return setTextureLocked(textureUsageSlot, texture, sampler, op, useInGeometryPasses);
419 const bool useInGeometryPasses )
422 return setTextureLocked( textureUsageSlot, texture, sampler, op, useInGeometryPasses );
433 properties()._needsNewShader =
true;
445 if ( info.
_shaderRef != INVALID_HANDLE<ShaderProgram> )
451 if ( ptr->descriptor() != shaderDescriptor )
454 ptr->resourceName().c_str(),
455 shaderDescriptor.
_name.c_str(),
513 _recomputeShadersCBK();
518 constexpr U8 maxRetries = 250;
520 bool justFinishedLoading =
false;
521 for (
U8 i = 0; i < maxRetries; ++i )
523 if ( !
canDraw( renderStagePass, justFinishedLoading ) )
536 return _context->imShaders()->imWorldShaderNoTexture();
544 if ( info.
_shaderRef != INVALID_HANDLE<ShaderProgram> )
551 return _context->imShaders()->imWorldShaderNoTexture();
558 shaderJustFinishedLoading =
false;
570 if ( info.
_shaderRef == INVALID_HANDLE<ShaderProgram> )
581 assert( info.
_shaderRef != INVALID_HANDLE<ShaderProgram> );
585 shaderJustFinishedLoading =
true;
611 const bool isDepthPass =
IsDepthPass( renderStagePass );
621 shaderDescriptor.
_globalDefines.emplace_back(
"MSAA_SCREEN_TARGET",
true );
626 shaderDescriptor.
_globalDefines.emplace_back(
"SHADOW_PASS",
true );
627 shaderDescriptor.
_globalDefines.emplace_back(
"SKIP_REFLECT_REFRACT",
true );
631 shaderDescriptor.
_globalDefines.emplace_back(
"ORTHO_PROJECTION",
true );
634 shaderDescriptor.
_globalDefines.emplace_back(
"WORLD_AO_PASS",
true );
638 else if ( isDepthPass )
641 shaderDescriptor.
_globalDefines.emplace_back(
"SKIP_REFLECT_REFRACT",
true );
645 shaderDescriptor.
_globalDefines.emplace_back(
"REFLECTION_PASS",
true );
649 shaderDescriptor.
_globalDefines.emplace_back(
"MAIN_DISPLAY_PASS",
true );
650 if ( !properties().isStatic() )
652 shaderDescriptor.
_globalDefines.emplace_back(
"HAS_VELOCITY",
true );
663 switch ( properties().shadingMode() )
667 shaderDescriptor.
_globalDefines.emplace_back(
"SHADING_MODE_FLAT",
true );
671 shaderDescriptor.
_globalDefines.emplace_back(
"SHADING_MODE_TOON",
true );
675 shaderDescriptor.
_globalDefines.emplace_back(
"SHADING_MODE_BLINN_PHONG",
true );
679 shaderDescriptor.
_globalDefines.emplace_back(
"SHADING_MODE_PBR_MR",
true );
683 shaderDescriptor.
_globalDefines.emplace_back(
"SHADING_MODE_PBR_SG",
true );
693 shaderDescriptor.
_globalDefines.emplace_back(
"COMPUTE_TBN",
true );
725 if ( properties().overrides().useAlphaDiscard() &&
753 shaderDescriptor.
_globalDefines.emplace_back( properties().isStatic() ?
"NODE_STATIC" :
"NODE_DYNAMIC",
true );
755 if ( properties().isInstanced() )
757 shaderDescriptor.
_globalDefines.emplace_back(
"OVERRIDE_DATA_IDX",
true );
760 if ( properties().hardwareSkinning() )
764 if ( !properties().texturesInFragmentStageOnly() )
766 shaderDescriptor.
_globalDefines.emplace_back(
"NEED_TEXTURE_DATA_ALL_STAGES",
true );
781 module.
_defines.emplace_back(
"DEFINE_PLACEHOLDER",
false );
787 if ( _textures[
to_base( slot )]._ptr == INVALID_HANDLE<Texture> )
792 if ( !isPrePass && !isShadowPass )
797 bool add = _textures[
to_base( slot )]._useInGeometryPasses;
800 if ( hasTransparency() )
829 add = properties().usePackedOMR();
833 add = !properties().usePackedOMR();
855 auto& shaders = passMapShaders[p];
864 if ( _baseMaterial !=
nullptr )
867 erase_if( _baseMaterial->_instances,
870 return Get(instance)->getGUID() == guid;
877 Get(instance)->_baseMaterial =
nullptr;
910 if ( properties().overrides().transparencyEnabled() )
921 if ( albedo != INVALID_HANDLE<Texture> &&
Get(albedo)->
hasTransparency() && !properties().overrides().ignoreTexDiffuseAlpha() )
928 if ( opacity != INVALID_HANDLE<Texture>)
930 const U8 channelCount =
NumChannels(
Get(opacity)->descriptor()._baseFormat );
931 properties()._translucencySource = (channelCount == 4 &&
Get(opacity)->hasTransparency())
937 properties()._needsNewShader = oldSource != properties().translucencySource();
948 ret._colourWrite.b[0] = ret._colourWrite.b[1] = ret._colourWrite.b[2] = ret._colourWrite.b[3] =
true;
953 ret._depthWriteEnabled =
true;
957 ret._colourWrite.b[2] = ret._colourWrite.b[3] =
false;
967 ret._colourWrite.b[0] = ret._colourWrite.b[1] = ret._colourWrite.b[2] = ret._colourWrite.b[3] =
false;
973 ret._depthWriteEnabled =
false;
981 ret._depthWriteEnabled =
false;
984 if ( _computeRenderStateCBK )
986 _computeRenderStateCBK(
this, renderStagePass, ret );
1012 textureOut = INVALID_HANDLE<Texture>;
1014 if ( hasTextureOverride )
1019 return properties().baseColour();
1024 textureOut = INVALID_HANDLE<Texture>;
1026 if ( hasTextureOverride )
1031 return properties().emissive();
1036 textureOut = INVALID_HANDLE<Texture>;
1037 hasTextureOverride =
false;
1039 return properties().ambient();
1044 textureOut = INVALID_HANDLE<Texture>;
1046 if ( hasTextureOverride )
1050 return properties().specular();
1055 textureOut = INVALID_HANDLE<Texture>;
1057 if ( hasTextureOverride )
1061 return properties().metallic();
1066 textureOut = INVALID_HANDLE<Texture>;
1068 if ( hasTextureOverride )
1072 return properties().roughness();
1077 textureOut = INVALID_HANDLE<Texture>;
1079 if ( hasTextureOverride )
1083 return properties().occlusion();
1088 const FColour3& specColour = properties().specular();
1095 dataOut.
_albedo.
set( properties().baseColour() );
1101 (properties().doubleSided() ? 1.f : 0.f) );
1105 properties().usePackedOMR() ? 1.f : 0.f );
1107 to_U8( properties().shadingMode() ),
1110 dataOut.
_data.
w = bestProbeID;
1121 useOpacityAlphaChannel ? 1.f : 0.f,
1122 properties().specGloss().x,
1123 properties().specGloss().y );
1134 auto& descriptor = isShadowPass
1135 ? _descriptorSetShadow
1137 ? _descriptorSetPrePass
1139 ? _descriptorSetMainPass
1140 : _descriptorSetSecondaryPass;
1142 if ( descriptor._bindingCount == 0u )
1146 if ( descriptor._bindingCount == 0u )
1176 Get(info._shaderRef)->recompile();
1185 pt.put( entryName +
".version", g_materialXMLVersion );
1187 properties().saveToXML( entryName, pt );
1194 if ( ignoreXMLData() )
1199 const size_t detectedVersion = pt.get<
size_t>( entryName +
".version", 0 );
1200 if ( detectedVersion != g_materialXMLVersion )
1206 properties().loadFromXML( entryName, pt );
1215 U32 blockIndex = 0u;
1217 const std::string stateNode =
Util::StringFormat(
"{}.RenderStates", entryName).c_str();
1218 const std::string blockNode =
Util::StringFormat(
"{}.RenderStateIndex.PerStagePass", entryName).c_str();
1227 if ( !
entry._isSet )
1232 auto& block =
entry._block;
1233 const size_t stateHash =
GetHash(block);
1234 if ( previousHashValues.find( stateHash ) == std::cend( previousHashValues ) )
1240 previousHashValues[stateHash] = blockIndex++;
1243 boost::property_tree::ptree stateTree;
1244 stateTree.put(
"StagePass.<xmlattr>.index", previousHashValues[stateHash] );
1245 stateTree.put(
"StagePass.<xmlattr>.stage", s );
1246 stateTree.put(
"StagePass.<xmlattr>.pass", p );
1247 stateTree.put(
"StagePass.<xmlattr>.variant", v );
1249 pt.add_child( blockNode, stateTree.get_child(
"StagePass" ) );
1259 static boost::property_tree::ptree g_emptyPtree;
1260 const std::string stateNode =
Util::StringFormat(
"{}.RenderStates", entryName).c_str();
1261 const std::string blockNode =
Util::StringFormat(
"{}.RenderStateIndex", entryName).c_str();
1262 for (
const auto& [tag, data] : pt.get_child( blockNode, g_emptyPtree ) )
1264 assert( tag ==
"PerStagePass" );
1271 const auto& it = previousBlocks.find( b );
1272 if ( it != cend( previousBlocks ) )
1282 previousBlocks[b] = block;
1291 U32 samplerCount = 0u;
1297 if ( tex != INVALID_HANDLE<Texture> )
1304 pt.put( textureNode +
".name", texture->assetName().c_str() );
1305 pt.put( textureNode +
".path", texture->assetLocation().string() );
1310 const size_t samplerHash =
GetHash(sampler);
1312 if ( previousHashValues.find( samplerHash ) == std::cend( previousHashValues ) )
1316 previousHashValues[samplerHash] = samplerCount;
1318 pt.put( textureNode +
".Sampler.id", previousHashValues[samplerHash] );
1319 pt.put( textureNode +
".UseForGeometry",
_textures[
to_base( usage )]._useInGeometryPasses );
1336 const std::string texName = pt.get<std::string>( textureNode +
".name",
"" );
1339 if ( texPath.empty() )
1344 if ( !texName.empty() )
1348 const bool useInGeometryPasses = pt.get<
bool>( textureNode +
".UseForGeometry",
_textures[
to_base( usage )]._useInGeometryPasses );
1349 const U32 index = pt.get<
U32>( textureNode +
".Sampler.id", 0 );
1350 const auto& it = previousSamplers.find( index );
1353 if ( it != cend( previousSamplers ) )
1355 sampler = it->second;
1360 previousSamplers[index] = sampler;
1369 srgb = pt.get<
bool>( textureNode +
".srgb", srgb);
1372 if ( crtTex == INVALID_HANDLE<Texture> )
1376 else if ( (
Get(crtTex)->assetLocation() /
Get(crtTex)->assetName()) == (texPath / texName) )
1384 texture.assetName( texName.c_str() );
1385 texture.assetLocation( texPath );
1386 texture.waitForReady(
true );
#define WAIT_FOR_CONDITION(...)
#define PROFILE_SCOPE_AUTO(CATEGORY)
virtual bool load(PlatformContext &context)
Loading and unloading interface.
ShaderComputeQueue & shaderComputeQueue() noexcept
FORCE_INLINE I64 getGUID() const noexcept
U32 update(U64 deltaTimeUS)
Returns a bit mask composed of UpdateResult flags.
void setRenderStateBlock(const RenderStateBlock &renderStateBlock, RenderStage stage, RenderPassType pass, RenderStagePass::VariantType variant=RenderStagePass::VariantType::COUNT)
void loadRenderStatesFromXML(const std::string &entryName, const boost::property_tree::ptree &pt)
bool setTextureLocked(TextureSlot textureUsageSlot, Handle< Texture > texture, SamplerDescriptor sampler, TextureOperation op, bool useInGeometryPasses)
FColour4 getBaseColour(bool &hasTextureOverride, Handle< Texture > &textureOut) const noexcept
Handle< ShaderProgram > computeAndGetProgramHandle(RenderStagePass renderStagePass)
bool canDraw(RenderStagePass renderStagePass, bool &shaderJustFinishedLoading)
Handle< Texture > getTexture(TextureSlot textureUsage) const
static constexpr F32 MAX_SHININESS
F32 getRoughness(bool &hasTextureOverride, Handle< Texture > &textureOut) const noexcept
static void RecomputeShaders()
bool hasTransparency() const noexcept
void getData(U32 bestProbeID, NodeMaterialData &dataOut)
void loadFromXML(const std::string &entryName, const boost::property_tree::ptree &pt)
F32 getMetallic(bool &hasTextureOverride, Handle< Texture > &textureOut) const noexcept
FColour3 getEmissive(bool &hasTextureOverride, Handle< Texture > &textureOut) const noexcept
void setShaderProgramInternal(ShaderProgramDescriptor shaderDescriptor, RenderStagePass stagePass)
FColour3 getAmbient(bool &hasTextureOverride, Handle< Texture > &textureOut) const noexcept
Handle< Material > clone(const std::string_view nameSuffix)
Return a new instance of this material with the name composed of the base material's name and the giv...
Material(const ResourceDescriptor< Material > &descriptor)
static void Update(U64 deltaTimeUS)
std::array< TextureInfo, to_base(TextureSlot::COUNT)> _textures
bool usesTextureInShader(TextureSlot slot, bool isPrePass, bool isShadowPass) const noexcept
DescriptorSet & getDescriptorSet(const RenderStagePass &renderStagePass)
void setTextureOperation(TextureSlot textureUsageSlot, TextureOperation op)
void saveTextureDataToXML(const std::string &entryName, boost::property_tree::ptree &pt) const
vector< Handle< Material > > _instances
SharedMutex _instanceLock
StatePassesPerStage< RenderStateBlockEntry > _defaultRenderStates
std::array< ModuleDefines, to_base(ShaderType::COUNT)> _extraShaderDefines
const RenderStateBlock & getOrCreateRenderStateBlock(RenderStagePass renderStagePass)
static bool s_shadersDirty
ShaderProgramInfo & shaderInfo(RenderStagePass renderStagePass)
FColour3 getSpecular(bool &hasTextureOverride, Handle< Texture > &textureOut) const noexcept
void updateTransparency()
bool setSampler(TextureSlot textureUsageSlot, SamplerDescriptor sampler)
StatePassesPerStage< ShaderProgramInfo > _shaderInfo
void getSortKeys(RenderStagePass renderStagePass, I64 &shaderKey, I64 &textureKey, bool &transparencyFlag) const
void setPipelineLayout(PrimitiveTopology topology, const AttributeMap &shaderAttributes)
bool setTexture(TextureSlot textureUsageSlot, Handle< Texture > texture, SamplerDescriptor sampler, TextureOperation op, bool useInGeometryPasses=false)
bool load(PlatformContext &context) override
Loading and unloading interface.
F32 getOcclusion(bool &hasTextureOverride, Handle< Texture > &textureOut) const noexcept
void computeAndAppendShaderDefines(ShaderProgramDescriptor &shaderDescriptor, RenderStagePass renderStagePass) const
size_t _shaderAttributesHash
void saveRenderStatesToXML(const std::string &entryName, boost::property_tree::ptree &pt) const
Handle< ShaderProgram > getProgramHandle(RenderStagePass renderStagePass) const
void loadTextureDataFromXML(const std::string &entryName, const boost::property_tree::ptree &pt)
void saveToXML(const std::string &entryName, boost::property_tree::ptree &pt) const
PlatformContext & context() noexcept
GFXDevice & gfx() noexcept
Configuration & config() noexcept
void addToQueueBack(const ShaderQueueElement &element)
void addToQueueFront(const ShaderQueueElement &element)
void process(ShaderQueueElement &element)
static constexpr U8 WORLD_AO_LAYER_INDEX
An API-independent representation of a texture.
void set(const T *v) noexcept
set the 4 components of the vector manually using a source pointer to a (large enough) array
static constexpr const char * attribLocation[]
static const char * shadingMode[]
static const char * materialDebugFlag[]
static const char * textureOperation[]
static const char * bumpMethod[]
static constexpr const char * textureSlot[]
constexpr Optick::Category::Type Streaming
constexpr Optick::Category::Type Scene
const char * RenderPassTypeToString(const RenderPassType pass) noexcept
TextureSlot StringToTextureSlot(std::string_view name)
BumpMethod StringToBumpMethod(std::string_view name)
const char * BumpMethodToString(BumpMethod bumpMethod) noexcept
const char * ShadingModeToString(ShadingMode shadingMode) noexcept
const char * TextureSlotToString(TextureSlot texUsage) noexcept
const char * MaterialDebugFlagToString(const MaterialDebugFlag unitType) noexcept
TextureOperation StringToTextureOperation(std::string_view operation)
const char * TextureOperationToString(TextureOperation textureOp) noexcept
const char * RenderStageToString(const RenderStage stage) noexcept
ShadingMode StringToShadingMode(std::string_view name)
MaterialDebugFlag StringToMaterialDebugFlag(std::string_view name)
Str StringFormat(const char *fmt, Args &&...args)
U32 PACK_UNORM4x8(const vec4< F32_NORM > &value)
SamplerDescriptor loadFromXML(const std::string &entryName, const boost::property_tree::ptree &pt)
void saveToXML(const SamplerDescriptor &sampler, const std::string &entryName, boost::property_tree::ptree &pt)
constexpr size_t g_materialXMLVersion
Handle console commands that start with a forward slash.
std::lock_guard< mutex > LockGuard
static constexpr bool IsDepthPass(const RenderStagePass stagePass) noexcept
constexpr U32 to_U32(const T value)
FORCE_INLINE void DestroyResource(Handle< T > &handle, const bool immediate=false)
@ RES_LOADED
The resource is available for usage.
@ TRIANGLE_STRIP_ADJACENCY
static constexpr bool IsZPrePass(const RenderStagePass stagePass) noexcept
vector< ModuleDefine > ModuleDefines
constexpr resolve_uac< A, B >::return_type add(const A &a, const B &b) noexcept
size_t GetHash(const PropertyDescriptor< T > &descriptor) noexcept
void SaveToXML(const TerrainDescriptor &descriptor, boost::property_tree::ptree &pt)
FORCE_INLINE Handle< T > GetResourceRef(const Handle< T > handle)
TextureOperation
How should each texture be added.
hashAlg::unordered_map< K, V, HashFun, Predicate > hashMap
std::shared_lock< mutex > SharedLock
@ EQUAL
Passes if the incoming YYY value is equal to the stored YYY value.
void WaitForReady(Resource *res)
static constexpr bool IsShadowPass(const RenderStagePass stagePass) noexcept
bool LoadFromXML(TerrainDescriptor &descriptor, const boost::property_tree::ptree &pt, std::string_view name)
void Set(DescriptorSetBindingData &dataInOut, ShaderBuffer *buffer, const BufferRange range) noexcept
DescriptorSetBinding & AddBinding(DescriptorSet &setInOut, U8 slot, U16 stageVisibilityMask)
FORCE_INLINE Handle< T > CreateResource(const ResourceDescriptor< T > &descriptor, bool &wasInCache, std::atomic_uint &taskCounter)
constexpr U8 to_U8(const T value)
::value constexpr T CLAMPED(T n, T min, T max) noexcept
std::scoped_lock< mutexes... > ScopedLock
@ BACK
Cull Back facing polygons (aka CW)
U8 NumChannels(GFXImageFormat format) noexcept
FORCE_INLINE T * Get(const Handle< T > handle)
Project const SceneEntry & entry
::value constexpr T CLAMPED_01(T n) noexcept
constexpr auto to_base(const Type value) -> Type
Divide::Configuration::Rendering::ShadowMapping::CSMSettings csm
struct Divide::Configuration::Rendering::ShadowMapping shadowMapping
struct Divide::Configuration::Rendering rendering
static NO_INLINE void printfn(const char *format, T &&... args)
DescriptorSetBindingData _data
bool _useInGeometryPasses
Setting this to false will fallback to auto-usage selection (e.g. opacity tex will be used for alpha ...
SamplerDescriptor _sampler
TextureOperation _operation
vec4< F32 > _emissiveAndParallax
vec4< U32 > _textureOperations
vector< ShaderModuleDescriptor > _modules
ModuleDefines _globalDefines
PropertyDescriptor< T > _propertyDescriptor
Handle< ShaderProgram > _shaderRef
ShaderBuildStage _shaderCompStage