feat(RHI): add rendering state abstraction to RHICommandList

- Add DepthStencilState and BlendState structs to RHICommandList
- Add SetPrimitiveTopology, SetDepthStencilState, SetStencilRef,
  SetBlendState, SetBlendFactor virtual methods
- Implement new methods in OpenGL backend with full state control
- Implement stub methods in D3D12 backend (states controlled via PSO)
This commit is contained in:
2026-03-17 23:17:43 +08:00
parent 0b50a57239
commit 254f794cdc
4 changed files with 183 additions and 4 deletions

View File

@@ -522,5 +522,143 @@ void OpenGLCommandList::DrawIndexed(uint32_t indexCount, uint32_t instanceCount,
reinterpret_cast<const void*>(startIndex * sizeof(GLuint)), static_cast<GLsizei>(instanceCount));
}
static unsigned int ToGLPrimitiveTopology(PrimitiveTopology topology) {
switch (topology) {
case PrimitiveTopology::PointList: return GL_POINTS;
case PrimitiveTopology::LineList: return GL_LINES;
case PrimitiveTopology::LineStrip: return GL_LINE_STRIP;
case PrimitiveTopology::TriangleList: return GL_TRIANGLES;
case PrimitiveTopology::TriangleStrip: return GL_TRIANGLE_STRIP;
case PrimitiveTopology::LineListAdj: return GL_LINES_ADJACENCY;
case PrimitiveTopology::LineStripAdj: return GL_LINE_STRIP_ADJACENCY;
case PrimitiveTopology::TriangleListAdj: return GL_TRIANGLES_ADJACENCY;
case PrimitiveTopology::TriangleStripAdj: return GL_TRIANGLE_STRIP_ADJACENCY;
case PrimitiveTopology::PatchList: return GL_PATCHES;
default: return GL_TRIANGLES;
}
}
static unsigned int ToGLComparisonFunc(ComparisonFunc func) {
switch (func) {
case ComparisonFunc::Never: return GL_NEVER;
case ComparisonFunc::Less: return GL_LESS;
case ComparisonFunc::Equal: return GL_EQUAL;
case ComparisonFunc::LessEqual: return GL_LEQUAL;
case ComparisonFunc::Greater: return GL_GREATER;
case ComparisonFunc::NotEqual: return GL_NOTEQUAL;
case ComparisonFunc::GreaterEqual: return GL_GEQUAL;
case ComparisonFunc::Always: return GL_ALWAYS;
default: return GL_LESS;
}
}
static unsigned int ToGLStencilOp(StencilOp op) {
switch (op) {
case StencilOp::Keep: return GL_KEEP;
case StencilOp::Zero: return GL_ZERO;
case StencilOp::Replace: return GL_REPLACE;
case StencilOp::IncrSat: return GL_INCR;
case StencilOp::DecrSat: return GL_DECR;
case StencilOp::Invert: return GL_INVERT;
case StencilOp::Incr: return GL_INCR_WRAP;
case StencilOp::Decr: return GL_DECR_WRAP;
default: return GL_KEEP;
}
}
static unsigned int ToGLBlendFactor(BlendFactor factor) {
switch (factor) {
case BlendFactor::Zero: return GL_ZERO;
case BlendFactor::One: return GL_ONE;
case BlendFactor::SrcColor: return GL_SRC_COLOR;
case BlendFactor::InvSrcColor: return GL_ONE_MINUS_SRC_COLOR;
case BlendFactor::SrcAlpha: return GL_SRC_ALPHA;
case BlendFactor::InvSrcAlpha: return GL_ONE_MINUS_SRC_ALPHA;
case BlendFactor::DstAlpha: return GL_DST_ALPHA;
case BlendFactor::InvDstAlpha: return GL_ONE_MINUS_DST_ALPHA;
case BlendFactor::DstColor: return GL_DST_COLOR;
case BlendFactor::InvDstColor: return GL_ONE_MINUS_DST_COLOR;
case BlendFactor::SrcAlphaSat: return GL_SRC_ALPHA_SATURATE;
case BlendFactor::BlendFactor: return GL_CONSTANT_COLOR;
case BlendFactor::InvBlendFactor: return GL_ONE_MINUS_CONSTANT_COLOR;
case BlendFactor::Src1Color: return GL_SRC1_COLOR;
case BlendFactor::InvSrc1Color: return GL_ONE_MINUS_SRC1_COLOR;
case BlendFactor::Src1Alpha: return GL_SRC1_ALPHA;
case BlendFactor::InvSrc1Alpha: return GL_ONE_MINUS_SRC1_ALPHA;
default: return GL_ONE;
}
}
static unsigned int ToGLBlendOp(BlendOp op) {
switch (op) {
case BlendOp::Add: return GL_FUNC_ADD;
case BlendOp::Subtract: return GL_FUNC_SUBTRACT;
case BlendOp::ReverseSubtract: return GL_FUNC_REVERSE_SUBTRACT;
case BlendOp::Min: return GL_MIN;
case BlendOp::Max: return GL_MAX;
default: return GL_FUNC_ADD;
}
}
void OpenGLCommandList::SetPrimitiveTopology(PrimitiveTopology topology) {
m_primitiveType = ToGLPrimitiveTopology(topology);
}
void OpenGLCommandList::SetDepthStencilState(const DepthStencilState& state) {
if (state.depthEnable) {
glEnable(GL_DEPTH_TEST);
glDepthFunc(ToGLComparisonFunc(state.depthFunc));
glDepthMask(state.depthWriteMask ? GL_TRUE : GL_FALSE);
} else {
glDisable(GL_DEPTH_TEST);
}
if (state.stencilEnable) {
glEnable(GL_STENCIL_TEST);
glStencilMask(state.stencilWriteMask);
glStencilFunc(ToGLComparisonFunc(state.frontFace.stencilFunc), 0, state.stencilReadMask);
glStencilOp(
ToGLStencilOp(state.frontFace.stencilFailOp),
ToGLStencilOp(state.frontFace.stencilDepthFailOp),
ToGLStencilOp(state.frontFace.stencilPassOp)
);
} else {
glDisable(GL_STENCIL_TEST);
}
}
void OpenGLCommandList::SetStencilRef(uint8_t ref) {
glStencilFunc(GL_FRONT_AND_BACK, ref, 0xFF);
}
void OpenGLCommandList::SetBlendState(const BlendState& state) {
if (state.alphaToCoverageEnable) {
glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
} else {
glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
}
const auto& rt = state.renderTargets[0];
if (rt.blendEnable) {
glEnable(GL_BLEND);
glBlendFuncSeparate(
ToGLBlendFactor(rt.srcBlend),
ToGLBlendFactor(rt.dstBlend),
ToGLBlendFactor(rt.srcBlendAlpha),
ToGLBlendFactor(rt.dstBlendAlpha)
);
glBlendEquationSeparate(
ToGLBlendOp(rt.blendOp),
ToGLBlendOp(rt.blendOpAlpha)
);
} else {
glDisable(GL_BLEND);
}
}
void OpenGLCommandList::SetBlendFactor(const float factor[4]) {
glBlendColor(factor[0], factor[1], factor[2], factor[3]);
}
} // namespace RHI
} // namespace XCEngine