Nameless Engine
Loading...
Searching...
No Matches
ne::ShaderManager Class Reference

#include <ShaderManager.h>

Classes

struct  ShaderData
 

Public Member Functions

 ShaderManager (Renderer *pRenderer)
 
 ShaderManager (const ShaderManager &)=delete
 
ShaderManageroperator= (const ShaderManager &)=delete
 
std::optional< ErrorcompileShaders (std::vector< ShaderDescription > vShadersToCompile, const std::function< void(size_t iCompiledShaderCount, size_t iTotalShadersToCompile)> &onProgress, const std::function< void(ShaderDescription shaderDescription, std::variant< std::string, Error > error)> &onError, const std::function< void()> &onCompleted)
 
bool isShaderNameCanBeUsed (const std::string &sShaderName)
 
bool markShaderToBeRemoved (const std::string &sShaderName)
 
void performSelfValidation ()
 

Protected Member Functions

void setRendererConfigurationForShaders (const std::set< ShaderMacro > &configuration, ShaderType shaderType)
 
void compileShaderTask (size_t iQueryId, const std::shared_ptr< std::atomic< size_t > > &pCompiledShaderCount, size_t iTotalShaderCount, ShaderDescription shaderDescription, const std::function< void(size_t iCompiledShaderCount, size_t iTotalShadersToCompile)> &onProgress, const std::function< void(ShaderDescription shaderDescription, std::variant< std::string, Error > error)> &onError, const std::function< void()> &onCompleted)
 
std::optional< std::shared_ptr< ShaderPack > > getShader (const std::string &sShaderName)
 
void releaseShaderBytecodeIfNotUsed (const std::string &sShaderName)
 
void removeShaderIfMarkedToBeRemoved (const std::string &sShaderName)
 
std::optional< ErrorrefreshShaderCache ()
 

Private Attributes

std::unique_ptr< ShaderCacheManagerpShaderCacheManager
 
std::pair< std::recursive_mutex, ShaderDatamtxShaderData
 
std::atomic< size_t > iTotalCompileShadersQueries = 0
 
Renderer *const pRenderer = nullptr
 

Static Private Attributes

static const std::array< char, 65 > vValidCharactersForShaderName
 
static const size_t iMaximumShaderNameLength = 40
 

Friends

class ShaderUser
 
class Renderer
 

Detailed Description

Handles shader compilation and controls shader registry.

Constructor & Destructor Documentation

◆ ShaderManager()

ne::ShaderManager::ShaderManager ( Renderer pRenderer)

Constructor.

Parameters
pRendererParent renderer that uses this shader manager.

Member Function Documentation

◆ compileShaders()

std::optional< Error > ne::ShaderManager::compileShaders ( std::vector< ShaderDescription vShadersToCompile,
const std::function< void(size_t iCompiledShaderCount, size_t iTotalShadersToCompile)> &  onProgress,
const std::function< void(ShaderDescription shaderDescription, std::variant< std::string, Error > error)> &  onError,
const std::function< void()> &  onCompleted 
)

Add shaders to be asynchronously compiled.

Compiled shaders are stored on disk, when a shader is needed it will be automatically loaded from disk into memory and when no longer being used it will be released from memory (stored on disk again).

Remarks
If a shader was already compiled previously compilation results will be stored in the shader cache on the disk and if the cache is currently valid (for ex. shader source file has not changed, included shader source files also not changed, defined shader macros not changed, build configuration not changed and etc.), shader compilation will be skipped and instead the shader will be loaded from the cache (which is faster than compiling the shader).
Parameters
vShadersToCompileArray of shaders to compile. Use isShaderNameCanBeUsed to check if a shader name is free (unique).
onProgressCallback function that will be called when each shader is compiled. This will also be called when all shaders are compiled (together with 'onCompleted'). The first argument is number of compiled shaders and the second one is total number of shaders to compile.
onErrorCallback function that will be called if an error occurred. This might be one of the two things: shader compilation error/warning (shader contains error) or internal error (engine failed to compile shader). If there was a shader compilation error/warning, this shader will be marked as processed and onProgress will be called (but this shader will not be added to shader manager and will not be available, you will need to fix the error and add this shader again).
onCompletedCallback function that will be called once all shaders are compiled.
Remarks
Note that all callback functions will be queued to be executed on the main thread and will be called later from the main thread before next frame is rendered. Because callbacks are called from the main thread it's safe to call functions that are marked as "should only be called from the main thread" from the callback functions. If you are using member functions as callbacks you need to make sure that the owner object of these member functions will not be deleted until onCompleted is called.
Returns
An error if something went wrong.

◆ compileShaderTask()

void ne::ShaderManager::compileShaderTask ( size_t  iQueryId,
const std::shared_ptr< std::atomic< size_t > > &  pCompiledShaderCount,
size_t  iTotalShaderCount,
ShaderDescription  shaderDescription,
const std::function< void(size_t iCompiledShaderCount, size_t iTotalShadersToCompile)> &  onProgress,
const std::function< void(ShaderDescription shaderDescription, std::variant< std::string, Error > error)> &  onError,
const std::function< void()> &  onCompleted 
)
protected

Compiles each shader. Executed as a thread pooled task to do this work asynchronously.

Parameters
iQueryIdUnique number used to differentiate different calls compileShaders.
pCompiledShaderCountCurrent total number of shaders compiled (in query).
iTotalShaderCountTotal number of shaders to compile in this query (might be bigger than the size of the vShadersToCompile argument because the query is divided in smaller tasks).
shaderDescriptionShader to compile.
onProgressCallback function that will be called when each shader is compiled. This will also be called when all shaders are compiled (together with 'onCompleted'). The first argument is number of compiled shaders and the second one is total number of shaders to compile.
onErrorCallback function that will be called if an error occurred. This might be one of the two things: shader compilation error/warning (shader contains error) or internal error (engine failed somewhere). If there was a shader compilation error/warning, this shader will be marked as processed and onProgress will be called (but this shader will not be added to shader manager and will not be available, use will need to fix the error and add this shader again).
onCompletedCallback function that will be called once all shaders are compiled.

◆ getShader()

std::optional< std::shared_ptr< ShaderPack > > ne::ShaderManager::getShader ( const std::string &  sShaderName)
protected
Warning
Should only be called by ShaderUser class.

Returns compiled shader (compiled using compileShaders).

Parameters
sShaderNameName of this shader.
Returns
Empty if the shader with the specified name was not found, valid pointer otherwise.

◆ isShaderNameCanBeUsed()

bool ne::ShaderManager::isShaderNameCanBeUsed ( const std::string &  sShaderName)

Checks if the shader name is free (no shader with this name found) to be used in compileShaders.

Parameters
sShaderNameName to check.
Returns
true if can be used (no shader with this name found), false otherwise.

◆ markShaderToBeRemoved()

bool ne::ShaderManager::markShaderToBeRemoved ( const std::string &  sShaderName)

Removes the shader if nobody is referencing it, otherwise marks shader to be removed later.

Typically you would not use this function as we expect you to make one call to compileShaders in the beginning of the game to compile ALL of your shaders (for all levels) and never remove them as compiled shaders are not stored in memory, they are stored on disk and when actually needed/used loaded from disk to memory. If some shader was used but no longer needed it will be released from memory until someone will need it again.

If somebody is still referencing this shader, the shader will be added to "to remove" array and will be removed later when nobody is referencing this shader (specifically when only one std::shared_ptr<Shader> instance pointing to this shader will exist (it will exist in ShaderManager as ShaderManager stores pointer to each shader)).

Parameters
sShaderNameShader name to be marked for removal.
Returns
'true' if someone is still referencing this shader and it cannot be removed right now, thus shader's name still cannot be used in compileShaders. Returns 'false' if nobody was referencing this shader and it was removed, thus shader's name can now be used in compileShaders.

◆ performSelfValidation()

void ne::ShaderManager::performSelfValidation ( )

Analyzes the current state to see if any shader-related errors have place (like unused shaders in memory or etc.). Fixes errors and reports them in log.

◆ refreshShaderCache()

std::optional< Error > ne::ShaderManager::refreshShaderCache ( )
protected

Looks if any of the global shader cache parameters changed (such as build mode, shader model, etc.), clears shader cache directory and creates a fresh new shader cache directory with up to date info.

Remarks
If no global shader cache metadata file existed it will create it.
Returns
An error if something went wrong.

◆ releaseShaderBytecodeIfNotUsed()

void ne::ShaderManager::releaseShaderBytecodeIfNotUsed ( const std::string &  sShaderName)
protected

Looks if the specified shader is not used by anyone and releases shader bytecode from memory if it was previously loaded.

Parameters
sShaderNameName of the shader to release bytecode.

◆ removeShaderIfMarkedToBeRemoved()

void ne::ShaderManager::removeShaderIfMarkedToBeRemoved ( const std::string &  sShaderName)
protected

Looks if this shader was marked "to be removed" and that it's not being used by anyone else, if this is correct removes the shader.

Parameters
sShaderNameName of the shader to remove.

◆ setRendererConfigurationForShaders()

void ne::ShaderManager::setRendererConfigurationForShaders ( const std::set< ShaderMacro > &  configuration,
ShaderType  shaderType 
)
protected

Sets renderer's shader configuration for specific types of shaders.

Warning
If the configuration is changed we will try to release old shader resources from the memory. Make sure no object is holding shared pointers to old shaders (with old configuration), otherwise there would be an error printed in the logs.
Parameters
configurationConfiguration to set.
shaderTypeTypes of shaders to set the configuration to.

Member Data Documentation

◆ iMaximumShaderNameLength

const size_t ne::ShaderManager::iMaximumShaderNameLength = 40
inlinestaticprivate

Maximum length of a shader name.

◆ iTotalCompileShadersQueries

std::atomic<size_t> ne::ShaderManager::iTotalCompileShadersQueries = 0
private

Total number of "compile shaders" queries. Used to differentiate calls to compileShaderTask.

◆ mtxShaderData

std::pair<std::recursive_mutex, ShaderData> ne::ShaderManager::mtxShaderData
private

Internal shader data guarded by mutex.

◆ pRenderer

Renderer* const ne::ShaderManager::pRenderer = nullptr
private

Do not delete. Parent renderer that uses this shader manager.

◆ pShaderCacheManager

std::unique_ptr<ShaderCacheManager> ne::ShaderManager::pShaderCacheManager
private

Handles everything related to shader cache.

◆ vValidCharactersForShaderName

const std::array<char, 65> ne::ShaderManager::vValidCharactersForShaderName
inlinestaticprivate
Initial value:
= {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '_', '-'}

Array of characters that can be used for shader name. We limit amount of valid characters because we store compiled shaders on disk and different filesystems have different limitations for file names.


The documentation for this class was generated from the following files: