#pragma once #include #include #include #include #include #include namespace XCEngine { namespace Rendering { 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::StencilOp ToRHIStencilOp(Resources::MaterialStencilOp op) { switch (op) { case Resources::MaterialStencilOp::Zero: return RHI::StencilOp::Zero; case Resources::MaterialStencilOp::Replace: return RHI::StencilOp::Replace; case Resources::MaterialStencilOp::IncrSat: return RHI::StencilOp::IncrSat; case Resources::MaterialStencilOp::DecrSat: return RHI::StencilOp::DecrSat; case Resources::MaterialStencilOp::Invert: return RHI::StencilOp::Invert; case Resources::MaterialStencilOp::IncrWrap: return RHI::StencilOp::Incr; case Resources::MaterialStencilOp::DecrWrap: return RHI::StencilOp::Decr; case Resources::MaterialStencilOp::Keep: default: return RHI::StencilOp::Keep; } } inline Resources::MaterialRenderState ResolveEffectiveRenderState( const Resources::ShaderPass* shaderPass, const Resources::Material* material) { Resources::MaterialRenderState renderState = {}; if (shaderPass != nullptr && shaderPass->hasFixedFunctionState) { renderState = shaderPass->fixedFunctionState; } else if (material != nullptr) { renderState = material->GetRenderState(); } if (material != nullptr && material->HasRenderStateOverride()) { renderState = material->GetRenderState(); } return renderState; } inline Resources::MaterialRenderState ApplyRenderStateBlock( Resources::MaterialRenderState renderState, const RenderStateBlock* renderStateBlock) { if (renderStateBlock == nullptr || !renderStateBlock->HasOverrides()) { return renderState; } if (renderStateBlock->HasDepthOverride()) { renderState.depthWriteEnable = renderStateBlock->depthState.writeEnabled; renderState.depthFunc = renderStateBlock->depthState.compareFunction; } if (renderStateBlock->HasStencilOverride()) { renderState.stencil.enabled = renderStateBlock->stencilState.enabled; renderState.stencil.readMask = renderStateBlock->stencilState.readMask; renderState.stencil.writeMask = renderStateBlock->stencilState.writeMask; renderState.stencil.reference = renderStateBlock->stencilReference; renderState.stencil.front.failOp = renderStateBlock->stencilState.frontFace.failOp; renderState.stencil.front.passOp = renderStateBlock->stencilState.frontFace.passOp; renderState.stencil.front.depthFailOp = renderStateBlock->stencilState.frontFace.depthFailOp; renderState.stencil.front.func = renderStateBlock->stencilState.frontFace.compareFunction; renderState.stencil.back.failOp = renderStateBlock->stencilState.backFace.failOp; renderState.stencil.back.passOp = renderStateBlock->stencilState.backFace.passOp; renderState.stencil.back.depthFailOp = renderStateBlock->stencilState.backFace.depthFailOp; renderState.stencil.back.func = renderStateBlock->stencilState.backFace.compareFunction; } return renderState; } inline RHI::RasterizerDesc BuildRasterizerState(const Resources::MaterialRenderState& renderState) { RHI::RasterizerDesc desc = {}; desc.fillMode = static_cast(RHI::FillMode::Solid); desc.cullMode = static_cast(RHI::CullMode::None); desc.frontFace = static_cast(RHI::FrontFace::CounterClockwise); desc.depthClipEnable = true; desc.cullMode = static_cast(ToRHICullMode(renderState.cullMode)); desc.depthBias = renderState.depthBiasUnits; desc.slopeScaledDepthBias = renderState.depthBiasFactor; return desc; } inline RHI::BlendDesc BuildBlendState(const Resources::MaterialRenderState& renderState) { RHI::BlendDesc desc = {}; desc.blendEnable = renderState.blendEnable; desc.srcBlend = static_cast(ToRHIBlendFactor(renderState.srcBlend)); desc.dstBlend = static_cast(ToRHIBlendFactor(renderState.dstBlend)); desc.srcBlendAlpha = static_cast(ToRHIBlendFactor(renderState.srcBlendAlpha)); desc.dstBlendAlpha = static_cast(ToRHIBlendFactor(renderState.dstBlendAlpha)); desc.blendOp = static_cast(ToRHIBlendOp(renderState.blendOp)); desc.blendOpAlpha = static_cast(ToRHIBlendOp(renderState.blendOpAlpha)); desc.colorWriteMask = renderState.colorWriteMask; return desc; } inline RHI::DepthStencilStateDesc BuildDepthStencilState(const Resources::MaterialRenderState& renderState) { RHI::DepthStencilStateDesc desc = {}; desc.depthTestEnable = renderState.depthTestEnable; desc.depthWriteEnable = renderState.depthWriteEnable; desc.depthFunc = static_cast(ToRHIComparisonFunc(renderState.depthFunc)); desc.stencilEnable = renderState.stencil.enabled; desc.stencilReadMask = renderState.stencil.readMask; desc.stencilWriteMask = renderState.stencil.writeMask; desc.front.failOp = static_cast(ToRHIStencilOp(renderState.stencil.front.failOp)); desc.front.passOp = static_cast(ToRHIStencilOp(renderState.stencil.front.passOp)); desc.front.depthFailOp = static_cast(ToRHIStencilOp(renderState.stencil.front.depthFailOp)); desc.front.func = static_cast(ToRHIComparisonFunc(renderState.stencil.front.func)); desc.back.failOp = static_cast(ToRHIStencilOp(renderState.stencil.back.failOp)); desc.back.passOp = static_cast(ToRHIStencilOp(renderState.stencil.back.passOp)); desc.back.depthFailOp = static_cast(ToRHIStencilOp(renderState.stencil.back.depthFailOp)); desc.back.func = static_cast(ToRHIComparisonFunc(renderState.stencil.back.func)); return desc; } inline void ApplyRenderState(const Resources::MaterialRenderState& renderState, RHI::GraphicsPipelineDesc& pipelineDesc) { pipelineDesc.rasterizerState = BuildRasterizerState(renderState); pipelineDesc.blendState = BuildBlendState(renderState); pipelineDesc.depthStencilState = BuildDepthStencilState(renderState); } inline void ApplyMaterialRenderState(const Resources::Material* material, RHI::GraphicsPipelineDesc& pipelineDesc) { ApplyRenderState(ResolveEffectiveRenderState(nullptr, material), pipelineDesc); } inline void ApplyResolvedRenderState( const Resources::ShaderPass* shaderPass, const Resources::Material* material, RHI::GraphicsPipelineDesc& pipelineDesc) { ApplyRenderState(ResolveEffectiveRenderState(shaderPass, material), pipelineDesc); } inline void ApplyDynamicRenderState( const Resources::MaterialRenderState& renderState, RHI::RHICommandList& commandList) { if (renderState.stencil.enabled) { commandList.SetStencilRef(renderState.stencil.reference); } } inline Resources::MaterialRenderState BuildStaticPipelineRenderStateKey( const Resources::MaterialRenderState& renderState) { Resources::MaterialRenderState keyState = renderState; keyState.stencil.reference = 0; return keyState; } 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); }; auto combineFloat = [&combine](float value) { Core::uint32 bits = 0; std::memcpy(&bits, &value, sizeof(bits)); combine(static_cast(bits)); }; combine(static_cast(state.blendEnable)); combine(static_cast(state.srcBlend)); combine(static_cast(state.dstBlend)); combine(static_cast(state.srcBlendAlpha)); combine(static_cast(state.dstBlendAlpha)); combine(static_cast(state.blendOp)); combine(static_cast(state.blendOpAlpha)); combine(static_cast(state.colorWriteMask)); combine(static_cast(state.depthTestEnable)); combine(static_cast(state.depthWriteEnable)); combine(static_cast(state.depthFunc)); combine(static_cast(state.cullMode)); combineFloat(state.depthBiasFactor); combine(static_cast(state.depthBiasUnits)); combine(static_cast(state.stencil.enabled)); combine(static_cast(state.stencil.readMask)); combine(static_cast(state.stencil.writeMask)); combine(static_cast(state.stencil.reference)); combine(static_cast(state.stencil.front.failOp)); combine(static_cast(state.stencil.front.passOp)); combine(static_cast(state.stencil.front.depthFailOp)); combine(static_cast(state.stencil.front.func)); combine(static_cast(state.stencil.back.failOp)); combine(static_cast(state.stencil.back.passOp)); combine(static_cast(state.stencil.back.depthFailOp)); combine(static_cast(state.stencil.back.func)); return hash; } }; } // namespace Rendering } // namespace XCEngine