refactor: add shader pass and backend variants

This commit is contained in:
2026-04-02 16:10:50 +08:00
parent 35d9b1d465
commit 70ced2d91f
4 changed files with 297 additions and 2 deletions

View File

@@ -22,6 +22,13 @@ enum class ShaderLanguage : Core::uint8 {
SPIRV
};
enum class ShaderBackend : Core::uint8 {
Generic = 0,
D3D12,
OpenGL,
Vulkan
};
struct ShaderUniform {
Containers::String name;
Core::uint32 location;
@@ -36,6 +43,27 @@ struct ShaderAttribute {
Core::uint32 type;
};
struct ShaderPassTagEntry {
Containers::String name;
Containers::String value;
};
struct ShaderStageVariant {
ShaderType stage = ShaderType::Fragment;
ShaderLanguage language = ShaderLanguage::GLSL;
ShaderBackend backend = ShaderBackend::Generic;
Containers::String entryPoint;
Containers::String profile;
Containers::String sourceCode;
Containers::Array<Core::uint8> compiledBinary;
};
struct ShaderPass {
Containers::String name;
Containers::Array<ShaderPassTagEntry> tags;
Containers::Array<ShaderStageVariant> variants;
};
class Shader : public IResource {
public:
Shader();
@@ -49,10 +77,10 @@ public:
size_t GetMemorySize() const override { return m_memorySize; }
void Release() override;
void SetShaderType(ShaderType type) { m_shaderType = type; }
void SetShaderType(ShaderType type);
ShaderType GetShaderType() const { return m_shaderType; }
void SetShaderLanguage(ShaderLanguage lang) { m_language = lang; }
void SetShaderLanguage(ShaderLanguage lang);
ShaderLanguage GetShaderLanguage() const { return m_language; }
void SetSourceCode(const Containers::String& source);
@@ -66,11 +94,33 @@ public:
void AddAttribute(const ShaderAttribute& attribute);
const Containers::Array<ShaderAttribute>& GetAttributes() const { return m_attributes; }
void AddPass(const ShaderPass& pass);
void ClearPasses();
Core::uint32 GetPassCount() const { return static_cast<Core::uint32>(m_passes.Size()); }
const Containers::Array<ShaderPass>& GetPasses() const { return m_passes; }
void AddPassVariant(const Containers::String& passName, const ShaderStageVariant& variant);
void SetPassTag(
const Containers::String& passName,
const Containers::String& tagName,
const Containers::String& tagValue);
bool HasPass(const Containers::String& passName) const;
const ShaderPass* FindPass(const Containers::String& passName) const;
ShaderPass* FindPass(const Containers::String& passName);
const ShaderStageVariant* FindVariant(
const Containers::String& passName,
ShaderType stage,
ShaderBackend backend = ShaderBackend::Generic) const;
class IRHIShader* GetRHIResource() const { return m_rhiResource; }
void SetRHIResource(class IRHIShader* resource);
private:
ShaderPass& GetOrCreatePass(const Containers::String& passName);
ShaderStageVariant& GetOrCreateLegacyVariant();
void SyncLegacyVariant();
ShaderType m_shaderType = ShaderType::Fragment;
ShaderLanguage m_language = ShaderLanguage::GLSL;
@@ -79,6 +129,7 @@ private:
Containers::Array<ShaderUniform> m_uniforms;
Containers::Array<ShaderAttribute> m_attributes;
Containers::Array<ShaderPass> m_passes;
class IRHIShader* m_rhiResource = nullptr;
};

View File

@@ -3,25 +3,46 @@
namespace XCEngine {
namespace Resources {
namespace {
const char* kLegacyShaderPassName = "Default";
} // namespace
Shader::Shader() = default;
Shader::~Shader() = default;
void Shader::Release() {
m_shaderType = ShaderType::Fragment;
m_language = ShaderLanguage::GLSL;
m_sourceCode.Clear();
m_compiledBinary.Clear();
m_uniforms.Clear();
m_attributes.Clear();
m_passes.Clear();
m_rhiResource = nullptr;
m_isValid = false;
}
void Shader::SetShaderType(ShaderType type) {
m_shaderType = type;
SyncLegacyVariant();
}
void Shader::SetShaderLanguage(ShaderLanguage lang) {
m_language = lang;
SyncLegacyVariant();
}
void Shader::SetSourceCode(const Containers::String& source) {
m_sourceCode = source;
SyncLegacyVariant();
}
void Shader::SetCompiledBinary(const Containers::Array<Core::uint8>& binary) {
m_compiledBinary = binary;
SyncLegacyVariant();
}
void Shader::AddUniform(const ShaderUniform& uniform) {
@@ -32,9 +53,123 @@ void Shader::AddAttribute(const ShaderAttribute& attribute) {
m_attributes.PushBack(attribute);
}
void Shader::AddPass(const ShaderPass& pass) {
m_passes.PushBack(pass);
}
void Shader::ClearPasses() {
m_passes.Clear();
}
void Shader::AddPassVariant(
const Containers::String& passName,
const ShaderStageVariant& variant) {
ShaderPass& pass = GetOrCreatePass(passName);
pass.variants.PushBack(variant);
}
void Shader::SetPassTag(
const Containers::String& passName,
const Containers::String& tagName,
const Containers::String& tagValue) {
ShaderPass& pass = GetOrCreatePass(passName);
for (ShaderPassTagEntry& tag : pass.tags) {
if (tag.name == tagName) {
tag.value = tagValue;
return;
}
}
ShaderPassTagEntry& tag = pass.tags.EmplaceBack();
tag.name = tagName;
tag.value = tagValue;
}
bool Shader::HasPass(const Containers::String& passName) const {
return FindPass(passName) != nullptr;
}
const ShaderPass* Shader::FindPass(const Containers::String& passName) const {
for (const ShaderPass& pass : m_passes) {
if (pass.name == passName) {
return &pass;
}
}
return nullptr;
}
ShaderPass* Shader::FindPass(const Containers::String& passName) {
for (ShaderPass& pass : m_passes) {
if (pass.name == passName) {
return &pass;
}
}
return nullptr;
}
const ShaderStageVariant* Shader::FindVariant(
const Containers::String& passName,
ShaderType stage,
ShaderBackend backend) const {
const ShaderPass* pass = FindPass(passName);
if (pass == nullptr) {
return nullptr;
}
const ShaderStageVariant* genericVariant = nullptr;
for (const ShaderStageVariant& variant : pass->variants) {
if (variant.stage != stage) {
continue;
}
if (variant.backend == backend) {
return &variant;
}
if (variant.backend == ShaderBackend::Generic && genericVariant == nullptr) {
genericVariant = &variant;
}
}
return genericVariant;
}
void Shader::SetRHIResource(class IRHIShader* resource) {
m_rhiResource = resource;
}
ShaderPass& Shader::GetOrCreatePass(const Containers::String& passName) {
if (ShaderPass* pass = FindPass(passName)) {
return *pass;
}
ShaderPass& pass = m_passes.EmplaceBack();
pass.name = passName;
return pass;
}
ShaderStageVariant& Shader::GetOrCreateLegacyVariant() {
ShaderPass& pass = GetOrCreatePass(kLegacyShaderPassName);
for (ShaderStageVariant& variant : pass.variants) {
if (variant.backend == ShaderBackend::Generic) {
return variant;
}
}
ShaderStageVariant& variant = pass.variants.EmplaceBack();
variant.backend = ShaderBackend::Generic;
return variant;
}
void Shader::SyncLegacyVariant() {
ShaderStageVariant& variant = GetOrCreateLegacyVariant();
variant.stage = m_shaderType;
variant.language = m_language;
variant.sourceCode = m_sourceCode;
variant.compiledBinary = m_compiledBinary;
}
} // namespace Resources
} // namespace XCEngine