312 lines
13 KiB
C++
312 lines
13 KiB
C++
#pragma once
|
|
|
|
#include <cstring>
|
|
|
|
#include <XCEngine/Rendering/Execution/RenderStateBlock.h>
|
|
#include <XCEngine/RHI/RHICommandList.h>
|
|
#include <XCEngine/RHI/RHITypes.h>
|
|
#include <XCEngine/Resources/Material/Material.h>
|
|
#include <XCEngine/Resources/Shader/Shader.h>
|
|
|
|
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<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;
|
|
desc.cullMode = static_cast<uint32_t>(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<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::MaterialRenderState& renderState) {
|
|
RHI::DepthStencilStateDesc desc = {};
|
|
desc.depthTestEnable = renderState.depthTestEnable;
|
|
desc.depthWriteEnable = renderState.depthWriteEnable;
|
|
desc.depthFunc = static_cast<uint32_t>(ToRHIComparisonFunc(renderState.depthFunc));
|
|
desc.stencilEnable = renderState.stencil.enabled;
|
|
desc.stencilReadMask = renderState.stencil.readMask;
|
|
desc.stencilWriteMask = renderState.stencil.writeMask;
|
|
desc.front.failOp = static_cast<uint32_t>(ToRHIStencilOp(renderState.stencil.front.failOp));
|
|
desc.front.passOp = static_cast<uint32_t>(ToRHIStencilOp(renderState.stencil.front.passOp));
|
|
desc.front.depthFailOp = static_cast<uint32_t>(ToRHIStencilOp(renderState.stencil.front.depthFailOp));
|
|
desc.front.func = static_cast<uint32_t>(ToRHIComparisonFunc(renderState.stencil.front.func));
|
|
desc.back.failOp = static_cast<uint32_t>(ToRHIStencilOp(renderState.stencil.back.failOp));
|
|
desc.back.passOp = static_cast<uint32_t>(ToRHIStencilOp(renderState.stencil.back.passOp));
|
|
desc.back.depthFailOp = static_cast<uint32_t>(ToRHIStencilOp(renderState.stencil.back.depthFailOp));
|
|
desc.back.func = static_cast<uint32_t>(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<size_t>(bits));
|
|
};
|
|
|
|
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));
|
|
combineFloat(state.depthBiasFactor);
|
|
combine(static_cast<size_t>(state.depthBiasUnits));
|
|
combine(static_cast<size_t>(state.stencil.enabled));
|
|
combine(static_cast<size_t>(state.stencil.readMask));
|
|
combine(static_cast<size_t>(state.stencil.writeMask));
|
|
combine(static_cast<size_t>(state.stencil.reference));
|
|
combine(static_cast<size_t>(state.stencil.front.failOp));
|
|
combine(static_cast<size_t>(state.stencil.front.passOp));
|
|
combine(static_cast<size_t>(state.stencil.front.depthFailOp));
|
|
combine(static_cast<size_t>(state.stencil.front.func));
|
|
combine(static_cast<size_t>(state.stencil.back.failOp));
|
|
combine(static_cast<size_t>(state.stencil.back.passOp));
|
|
combine(static_cast<size_t>(state.stencil.back.depthFailOp));
|
|
combine(static_cast<size_t>(state.stencil.back.func));
|
|
return hash;
|
|
}
|
|
};
|
|
|
|
} // namespace Rendering
|
|
} // namespace XCEngine
|