Remove GPUShaderProgramsContainer to simplify GPUShader

This commit is contained in:
Wojtek Figat
2024-12-11 15:08:13 +01:00
parent 35e9e048f2
commit cedf4b1eb5
2 changed files with 23 additions and 118 deletions

View File

@@ -7,53 +7,7 @@
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Serialization/MemoryReadStream.h"
GPUShaderProgramsContainer::GPUShaderProgramsContainer()
: _shaders(64)
{
// TODO: test different values for _shaders capacity, test performance impact (less hash collisions but more memory?)
}
GPUShaderProgramsContainer::~GPUShaderProgramsContainer()
{
// Remember to delete all programs
_shaders.ClearDelete();
}
void GPUShaderProgramsContainer::Add(GPUShaderProgram* shader, int32 permutationIndex)
{
// Validate input
ASSERT(shader && Math::IsInRange(permutationIndex, 0, SHADER_PERMUTATIONS_MAX_COUNT - 1));
#if ENABLE_ASSERTION
if ((Get(shader->GetName(), permutationIndex) != nullptr))
{
CRASH;
}
#endif
// Store shader
const int32 hash = CalculateHash(shader->GetName(), permutationIndex);
_shaders.Add(hash, shader);
}
GPUShaderProgram* GPUShaderProgramsContainer::Get(const StringAnsiView& name, int32 permutationIndex) const
{
// Validate input
ASSERT(name.Length() > 0 && Math::IsInRange(permutationIndex, 0, SHADER_PERMUTATIONS_MAX_COUNT - 1));
// Find shader
GPUShaderProgram* result = nullptr;
const int32 hash = CalculateHash(name, permutationIndex);
_shaders.TryGet(hash, result);
return result;
}
void GPUShaderProgramsContainer::Clear()
{
_shaders.ClearDelete();
}
uint32 GPUShaderProgramsContainer::CalculateHash(const StringAnsiView& name, int32 permutationIndex)
static FORCE_INLINE uint32 HashPermutation(const StringAnsiView& name, int32 permutationIndex)
{
return GetHash(name) * 37 + permutationIndex;
}
@@ -73,7 +27,7 @@ bool GPUShader::Create(MemoryReadStream& stream)
stream.ReadInt32(&version);
if (version != GPU_SHADER_CACHE_VERSION)
{
LOG(Warning, "Unsupported shader version {0}. The supported version is {1}.", version, GPU_SHADER_CACHE_VERSION);
LOG(Warning, "Unsupported shader version {0}. The current version is {1}.", version, GPU_SHADER_CACHE_VERSION);
return true;
}
@@ -130,19 +84,21 @@ bool GPUShader::Create(MemoryReadStream& stream)
if (shader == nullptr)
{
#if !GPU_ALLOW_TESSELLATION_SHADERS
if (type == ShaderStage::Hull || type == ShaderStage::Domain)
continue;
if (type == ShaderStage::Hull || type == ShaderStage::Domain)
continue;
#endif
#if !GPU_ALLOW_GEOMETRY_SHADERS
if (type == ShaderStage::Geometry)
continue;
if (type == ShaderStage::Geometry)
continue;
#endif
LOG(Error, "Failed to create {} Shader program '{}' ({}).", ::ToString(type), String(initializer.Name), name);
return true;
}
// Add to collection
_shaders.Add(shader, permutationIndex);
// Add to the collection
const uint32 hash = HashPermutation(shader->GetName(), permutationIndex);
ASSERT_LOW_LAYER(!_shaders.ContainsKey(hash));
_shaders.Add(hash, shader);
}
}
@@ -183,17 +139,21 @@ bool GPUShader::Create(MemoryReadStream& stream)
return false;
}
bool GPUShader::HasShader(const StringAnsiView& name, int32 permutationIndex) const
{
const uint32 hash = HashPermutation(name, permutationIndex);
return _shaders.ContainsKey(hash);
}
GPUShaderProgram* GPUShader::GetShader(ShaderStage stage, const StringAnsiView& name, int32 permutationIndex) const
{
const auto shader = _shaders.Get(name, permutationIndex);
GPUShaderProgram* shader = nullptr;
const uint32 hash = HashPermutation(name, permutationIndex);
_shaders.TryGet(hash, shader);
#if BUILD_RELEASE
// Release build is more critical on that
ASSERT(shader != nullptr && shader->GetStage() == stage);
#else
if (shader == nullptr)
{
LOG(Error, "Missing {0} shader \'{1}\'[{2}]. Object: {3}.", ::ToString(stage), String(name), permutationIndex, ToString());
@@ -202,9 +162,7 @@ GPUShaderProgram* GPUShader::GetShader(ShaderStage stage, const StringAnsiView&
{
LOG(Error, "Invalid shader stage \'{1}\'[{2}]. Expected: {0}. Actual: {4}. Object: {3}.", ::ToString(stage), String(name), permutationIndex, ToString(), ::ToString(shader->GetStage()));
}
#endif
return shader;
}
@@ -224,5 +182,5 @@ void GPUShader::OnReleaseGPU()
}
}
_memoryUsage = 0;
_shaders.Clear();
_shaders.ClearDelete();
}

View File

@@ -14,64 +14,15 @@ class GPUShaderProgram;
/// </summary>
#define GPU_SHADER_CACHE_VERSION 9
/// <summary>
/// Represents collection of shader programs with permutations and custom names.
/// </summary>
class GPUShaderProgramsContainer
{
private:
Dictionary<int32, GPUShaderProgram*> _shaders;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramsContainer"/> class.
/// </summary>
GPUShaderProgramsContainer();
/// <summary>
/// Finalizes an instance of the <see cref="GPUShaderProgramsContainer"/> class.
/// </summary>
~GPUShaderProgramsContainer();
public:
/// <summary>
/// Adds a new shader program to the collection.
/// </summary>
/// <param name="shader">The shader to store.</param>
/// <param name="permutationIndex">The shader permutation index.</param>
void Add(GPUShaderProgram* shader, int32 permutationIndex);
/// <summary>
/// Gets a shader of given name and permutation index.
/// </summary>
/// <param name="name">The shader program name.</param>
/// <param name="permutationIndex">The shader permutation index.</param>
/// <returns>Stored shader program or null if cannot find it.</returns>
GPUShaderProgram* Get(const StringAnsiView& name, int32 permutationIndex) const;
/// <summary>
/// Clears collection (deletes all shaders).
/// </summary>
void Clear();
public:
/// <summary>
/// Calculates unique hash for given shader program name and its permutation index.
/// </summary>
/// <param name="name">The shader program name.</param>
/// <param name="permutationIndex">The shader program permutation index.</param>
/// <returns>Calculated hash value.</returns>
static uint32 CalculateHash(const StringAnsiView& name, int32 permutationIndex);
};
/// <summary>
/// The GPU resource with shader programs that can run on the GPU and are able to perform rendering calculation using textures, vertices and other resources.
/// </summary>
API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API GPUShader : public GPUResource
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUShader);
protected:
GPUShaderProgramsContainer _shaders;
Dictionary<uint32, GPUShaderProgram*> _shaders;
GPUConstantBuffer* _constantBuffers[MAX_CONSTANT_BUFFER_SLOTS];
GPUShader();
@@ -173,17 +124,13 @@ public:
return _constantBuffers[slot];
}
public:
/// <summary>
/// Determines whether the specified shader program is in the shader.
/// </summary>
/// <param name="name">The shader program name.</param>
/// <param name="permutationIndex">The shader permutation index.</param>
/// <returns><c>true</c> if the shader is valid; otherwise, <c>false</c>.</returns>
FORCE_INLINE bool HasShader(const StringAnsiView& name, int32 permutationIndex = 0) const
{
return _shaders.Get(name, permutationIndex) != nullptr;
}
bool HasShader(const StringAnsiView& name, int32 permutationIndex = 0) const;
protected:
GPUShaderProgram* GetShader(ShaderStage stage, const StringAnsiView& name, int32 permutationIndex) const;