Add material render state and pipeline caching

This commit is contained in:
2026-03-27 12:18:04 +08:00
parent 4b9a63098e
commit 9a5c187abc
9 changed files with 717 additions and 26 deletions

View File

@@ -1,5 +1,6 @@
#pragma once
#include <XCEngine/Rendering/RenderMaterialUtility.h>
#include <XCEngine/Rendering/RenderPipeline.h>
#include <XCEngine/Rendering/RenderResourceCache.h>
@@ -11,6 +12,8 @@
#include <XCEngine/RHI/RHISampler.h>
#include <XCEngine/RHI/RHITexture.h>
#include <unordered_map>
namespace XCEngine {
namespace Resources {
class Material;
@@ -44,6 +47,9 @@ private:
bool EnsureInitialized(const RenderContext& context);
bool CreatePipelineResources(const RenderContext& context);
void DestroyPipelineResources();
RHI::RHIPipelineState* GetOrCreatePipelineState(
const RenderContext& context,
const Resources::Material* material);
const Resources::Texture* ResolveTexture(const Resources::Material* material) const;
RHI::RHIResourceView* ResolveTextureView(const VisibleRenderItem& visibleItem);
@@ -65,7 +71,7 @@ private:
RHI::RHIDescriptorPool* m_samplerPool = nullptr;
RHI::RHIDescriptorSet* m_samplerSet = nullptr;
RHI::RHIPipelineLayout* m_pipelineLayout = nullptr;
RHI::RHIPipelineState* m_pipelineState = nullptr;
std::unordered_map<Resources::MaterialRenderState, RHI::RHIPipelineState*, MaterialRenderStateHash> m_pipelineStates;
RHI::RHISampler* m_sampler = nullptr;
RHI::RHITexture* m_fallbackTexture = nullptr;
RHI::RHIResourceView* m_fallbackTextureView = nullptr;

View File

@@ -2,6 +2,7 @@
#include <XCEngine/Components/MeshRendererComponent.h>
#include <XCEngine/Core/Types.h>
#include <XCEngine/RHI/RHITypes.h>
#include <XCEngine/Resources/Material/Material.h>
#include <XCEngine/Resources/Mesh/Mesh.h>
#include <XCEngine/Rendering/VisibleRenderObject.h>
@@ -93,5 +94,173 @@ inline bool MatchesBuiltinPass(const Resources::Material* material, BuiltinMater
}
}
inline RHI::CullMode ToRHICullMode(Resources::MaterialCullMode mode) {
switch (mode) {
case Resources::MaterialCullMode::Front:
return RHI::CullMode::Front;
case Resources::MaterialCullMode::Back:
return RHI::CullMode::Back;
case Resources::MaterialCullMode::None:
default:
return RHI::CullMode::None;
}
}
inline RHI::ComparisonFunc ToRHIComparisonFunc(Resources::MaterialComparisonFunc func) {
switch (func) {
case Resources::MaterialComparisonFunc::Never:
return RHI::ComparisonFunc::Never;
case Resources::MaterialComparisonFunc::Equal:
return RHI::ComparisonFunc::Equal;
case Resources::MaterialComparisonFunc::LessEqual:
return RHI::ComparisonFunc::LessEqual;
case Resources::MaterialComparisonFunc::Greater:
return RHI::ComparisonFunc::Greater;
case Resources::MaterialComparisonFunc::NotEqual:
return RHI::ComparisonFunc::NotEqual;
case Resources::MaterialComparisonFunc::GreaterEqual:
return RHI::ComparisonFunc::GreaterEqual;
case Resources::MaterialComparisonFunc::Always:
return RHI::ComparisonFunc::Always;
case Resources::MaterialComparisonFunc::Less:
default:
return RHI::ComparisonFunc::Less;
}
}
inline RHI::BlendFactor ToRHIBlendFactor(Resources::MaterialBlendFactor factor) {
switch (factor) {
case Resources::MaterialBlendFactor::Zero:
return RHI::BlendFactor::Zero;
case Resources::MaterialBlendFactor::SrcColor:
return RHI::BlendFactor::SrcColor;
case Resources::MaterialBlendFactor::InvSrcColor:
return RHI::BlendFactor::InvSrcColor;
case Resources::MaterialBlendFactor::SrcAlpha:
return RHI::BlendFactor::SrcAlpha;
case Resources::MaterialBlendFactor::InvSrcAlpha:
return RHI::BlendFactor::InvSrcAlpha;
case Resources::MaterialBlendFactor::DstAlpha:
return RHI::BlendFactor::DstAlpha;
case Resources::MaterialBlendFactor::InvDstAlpha:
return RHI::BlendFactor::InvDstAlpha;
case Resources::MaterialBlendFactor::DstColor:
return RHI::BlendFactor::DstColor;
case Resources::MaterialBlendFactor::InvDstColor:
return RHI::BlendFactor::InvDstColor;
case Resources::MaterialBlendFactor::SrcAlphaSat:
return RHI::BlendFactor::SrcAlphaSat;
case Resources::MaterialBlendFactor::BlendFactor:
return RHI::BlendFactor::BlendFactor;
case Resources::MaterialBlendFactor::InvBlendFactor:
return RHI::BlendFactor::InvBlendFactor;
case Resources::MaterialBlendFactor::Src1Color:
return RHI::BlendFactor::Src1Color;
case Resources::MaterialBlendFactor::InvSrc1Color:
return RHI::BlendFactor::InvSrc1Color;
case Resources::MaterialBlendFactor::Src1Alpha:
return RHI::BlendFactor::Src1Alpha;
case Resources::MaterialBlendFactor::InvSrc1Alpha:
return RHI::BlendFactor::InvSrc1Alpha;
case Resources::MaterialBlendFactor::One:
default:
return RHI::BlendFactor::One;
}
}
inline RHI::BlendOp ToRHIBlendOp(Resources::MaterialBlendOp op) {
switch (op) {
case Resources::MaterialBlendOp::Subtract:
return RHI::BlendOp::Subtract;
case Resources::MaterialBlendOp::ReverseSubtract:
return RHI::BlendOp::ReverseSubtract;
case Resources::MaterialBlendOp::Min:
return RHI::BlendOp::Min;
case Resources::MaterialBlendOp::Max:
return RHI::BlendOp::Max;
case Resources::MaterialBlendOp::Add:
default:
return RHI::BlendOp::Add;
}
}
inline RHI::RasterizerDesc BuildRasterizerState(const Resources::Material* material) {
RHI::RasterizerDesc desc = {};
desc.fillMode = static_cast<uint32_t>(RHI::FillMode::Solid);
desc.cullMode = static_cast<uint32_t>(RHI::CullMode::None);
desc.frontFace = static_cast<uint32_t>(RHI::FrontFace::CounterClockwise);
desc.depthClipEnable = true;
if (material != nullptr) {
const Resources::MaterialRenderState& renderState = material->GetRenderState();
desc.cullMode = static_cast<uint32_t>(ToRHICullMode(renderState.cullMode));
}
return desc;
}
inline RHI::BlendDesc BuildBlendState(const Resources::Material* material) {
RHI::BlendDesc desc = {};
if (material != nullptr) {
const Resources::MaterialRenderState& renderState = material->GetRenderState();
desc.blendEnable = renderState.blendEnable;
desc.srcBlend = static_cast<uint32_t>(ToRHIBlendFactor(renderState.srcBlend));
desc.dstBlend = static_cast<uint32_t>(ToRHIBlendFactor(renderState.dstBlend));
desc.srcBlendAlpha = static_cast<uint32_t>(ToRHIBlendFactor(renderState.srcBlendAlpha));
desc.dstBlendAlpha = static_cast<uint32_t>(ToRHIBlendFactor(renderState.dstBlendAlpha));
desc.blendOp = static_cast<uint32_t>(ToRHIBlendOp(renderState.blendOp));
desc.blendOpAlpha = static_cast<uint32_t>(ToRHIBlendOp(renderState.blendOpAlpha));
desc.colorWriteMask = renderState.colorWriteMask;
}
return desc;
}
inline RHI::DepthStencilStateDesc BuildDepthStencilState(const Resources::Material* material) {
RHI::DepthStencilStateDesc desc = {};
desc.depthTestEnable = true;
desc.depthWriteEnable = true;
desc.depthFunc = static_cast<uint32_t>(RHI::ComparisonFunc::Less);
desc.stencilEnable = false;
if (material != nullptr) {
const Resources::MaterialRenderState& renderState = material->GetRenderState();
desc.depthTestEnable = renderState.depthTestEnable;
desc.depthWriteEnable = renderState.depthWriteEnable;
desc.depthFunc = static_cast<uint32_t>(ToRHIComparisonFunc(renderState.depthFunc));
}
return desc;
}
inline void ApplyMaterialRenderState(const Resources::Material* material, RHI::GraphicsPipelineDesc& pipelineDesc) {
pipelineDesc.rasterizerState = BuildRasterizerState(material);
pipelineDesc.blendState = BuildBlendState(material);
pipelineDesc.depthStencilState = BuildDepthStencilState(material);
}
struct MaterialRenderStateHash {
size_t operator()(const Resources::MaterialRenderState& state) const noexcept {
size_t hash = 2166136261u;
auto combine = [&hash](size_t value) {
hash ^= value + 0x9e3779b9u + (hash << 6) + (hash >> 2);
};
combine(static_cast<size_t>(state.blendEnable));
combine(static_cast<size_t>(state.srcBlend));
combine(static_cast<size_t>(state.dstBlend));
combine(static_cast<size_t>(state.srcBlendAlpha));
combine(static_cast<size_t>(state.dstBlendAlpha));
combine(static_cast<size_t>(state.blendOp));
combine(static_cast<size_t>(state.blendOpAlpha));
combine(static_cast<size_t>(state.colorWriteMask));
combine(static_cast<size_t>(state.depthTestEnable));
combine(static_cast<size_t>(state.depthWriteEnable));
combine(static_cast<size_t>(state.depthFunc));
combine(static_cast<size_t>(state.cullMode));
return hash;
}
};
} // namespace Rendering
} // namespace XCEngine

View File

@@ -22,6 +22,87 @@ enum class MaterialRenderQueue : Core::int32 {
Overlay = 4000
};
enum class MaterialCullMode : Core::uint8 {
None = 0,
Front = 1,
Back = 2
};
enum class MaterialComparisonFunc : Core::uint8 {
Never = 0,
Less = 1,
Equal = 2,
LessEqual = 3,
Greater = 4,
NotEqual = 5,
GreaterEqual = 6,
Always = 7
};
enum class MaterialBlendOp : Core::uint8 {
Add = 0,
Subtract = 1,
ReverseSubtract = 2,
Min = 3,
Max = 4
};
enum class MaterialBlendFactor : Core::uint8 {
Zero = 0,
One = 1,
SrcColor = 2,
InvSrcColor = 3,
SrcAlpha = 4,
InvSrcAlpha = 5,
DstAlpha = 6,
InvDstAlpha = 7,
DstColor = 8,
InvDstColor = 9,
SrcAlphaSat = 10,
BlendFactor = 11,
InvBlendFactor = 12,
Src1Color = 13,
InvSrc1Color = 14,
Src1Alpha = 15,
InvSrc1Alpha = 16
};
struct MaterialRenderState {
bool blendEnable = false;
MaterialBlendFactor srcBlend = MaterialBlendFactor::One;
MaterialBlendFactor dstBlend = MaterialBlendFactor::Zero;
MaterialBlendFactor srcBlendAlpha = MaterialBlendFactor::One;
MaterialBlendFactor dstBlendAlpha = MaterialBlendFactor::Zero;
MaterialBlendOp blendOp = MaterialBlendOp::Add;
MaterialBlendOp blendOpAlpha = MaterialBlendOp::Add;
Core::uint8 colorWriteMask = 0xF;
bool depthTestEnable = true;
bool depthWriteEnable = true;
MaterialComparisonFunc depthFunc = MaterialComparisonFunc::Less;
MaterialCullMode cullMode = MaterialCullMode::None;
bool operator==(const MaterialRenderState& other) const {
return blendEnable == other.blendEnable &&
srcBlend == other.srcBlend &&
dstBlend == other.dstBlend &&
srcBlendAlpha == other.srcBlendAlpha &&
dstBlendAlpha == other.dstBlendAlpha &&
blendOp == other.blendOp &&
blendOpAlpha == other.blendOpAlpha &&
colorWriteMask == other.colorWriteMask &&
depthTestEnable == other.depthTestEnable &&
depthWriteEnable == other.depthWriteEnable &&
depthFunc == other.depthFunc &&
cullMode == other.cullMode;
}
bool operator!=(const MaterialRenderState& other) const {
return !(*this == other);
}
};
enum class MaterialPropertyType {
Float, Float2, Float3, Float4,
Int, Int2, Int3, Int4,
@@ -65,6 +146,9 @@ public:
void SetRenderQueue(MaterialRenderQueue renderQueue);
Core::int32 GetRenderQueue() const { return m_renderQueue; }
void SetRenderState(const MaterialRenderState& renderState);
const MaterialRenderState& GetRenderState() const { return m_renderState; }
void SetShaderPass(const Containers::String& shaderPass);
const Containers::String& GetShaderPass() const { return m_shaderPass; }
@@ -105,6 +189,7 @@ private:
ResourceHandle<class Shader> m_shader;
Core::int32 m_renderQueue = static_cast<Core::int32>(MaterialRenderQueue::Geometry);
MaterialRenderState m_renderState;
Containers::String m_shaderPass;
struct TagEntry {
Containers::String name;