Enhance OpenGLPipelineState with comprehensive state management

- Add BlendOp enum for blend operations
- Add PolygonMode enum for polygon rendering mode
- Add StencilOp enum for stencil operations
- Add ScissorState and LogicalOperation structs
- Add DepthStencilState: stencil enable, read/write mask, stencil ref, stencil func, stencil ops
- Add BlendState: blend equation, color write mask, blend factor
- Add RasterizerState: polygon mode, polygon offset, depth clip, scissor test, multisample
- Add ViewportState: float coordinates with min/max depth
- Add Apply methods for individual state groups
- Add AttachShader/DetachShader for program management
- Add getter methods for state structs
This commit is contained in:
2026-03-17 02:15:48 +08:00
parent 413f4c178f
commit 1de66b835d
2 changed files with 255 additions and 46 deletions

View File

@@ -1,37 +1,10 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLPipelineState.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
namespace XCEngine {
namespace RHI {
OpenGLPipelineState::OpenGLPipelineState() {
m_clearColor[0] = 0.1f;
m_clearColor[1] = 0.1f;
m_clearColor[2] = 0.1f;
m_clearColor[3] = 1.0f;
}
OpenGLPipelineState::~OpenGLPipelineState() {
}
void OpenGLPipelineState::SetDepthStencilState(const DepthStencilState& state) {
m_depthStencilState = state;
}
void OpenGLPipelineState::SetBlendState(const BlendState& state) {
m_blendState = state;
}
void OpenGLPipelineState::SetRasterizerState(const RasterizerState& state) {
m_rasterizerState = state;
}
void OpenGLPipelineState::SetViewport(const ViewportState& state) {
m_viewportState = state;
}
static unsigned int ToGLComparisonFunc(ComparisonFunc func) {
switch (func) {
case ComparisonFunc::Never: return GL_NEVER;
@@ -62,10 +35,25 @@ static unsigned int ToGLBlendFactor(BlendFactor factor) {
case BlendFactor::OneMinusConstantColor: return GL_ONE_MINUS_CONSTANT_COLOR;
case BlendFactor::ConstantAlpha: return GL_CONSTANT_ALPHA;
case BlendFactor::OneMinusConstantAlpha: return GL_ONE_MINUS_CONSTANT_ALPHA;
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;
}
}
static unsigned int ToGLCullFace(CullFace face) {
switch (face) {
case CullFace::Front: return GL_FRONT;
@@ -83,31 +71,124 @@ static unsigned int ToGLFrontFace(FrontFace face) {
}
}
static unsigned int ToGLPolygonMode(PolygonMode mode) {
switch (mode) {
case PolygonMode::Point: return GL_POINT;
case PolygonMode::Line: return GL_LINE;
case PolygonMode::Fill: return GL_FILL;
default: return GL_FILL;
}
}
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::Incr: return GL_INCR;
case StencilOp::IncrWrap: return GL_INCR_WRAP;
case StencilOp::Decr: return GL_DECR;
case StencilOp::DecrWrap: return GL_DECR_WRAP;
case StencilOp::Invert: return GL_INVERT;
default: return GL_KEEP;
}
}
OpenGLPipelineState::OpenGLPipelineState()
: m_program(0)
, m_programAttached(false) {
m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0.0f;
}
OpenGLPipelineState::~OpenGLPipelineState() {
}
void OpenGLPipelineState::SetDepthStencilState(const DepthStencilState& state) {
m_depthStencilState = state;
}
void OpenGLPipelineState::SetBlendState(const BlendState& state) {
m_blendState = state;
}
void OpenGLPipelineState::SetRasterizerState(const RasterizerState& state) {
m_rasterizerState = state;
}
void OpenGLPipelineState::SetViewport(const ViewportState& state) {
m_viewportState = state;
}
void OpenGLPipelineState::SetScissor(const ScissorState& state) {
m_scissorState = state;
}
void OpenGLPipelineState::SetLogicalOperation(const LogicalOperation& state) {
m_logicalOperation = state;
}
void OpenGLPipelineState::Apply() {
ApplyDepthStencil();
ApplyBlend();
ApplyRasterizer();
ApplyViewport();
ApplyScissor();
}
void OpenGLPipelineState::ApplyDepthStencil() {
if (m_depthStencilState.depthTestEnable) {
glEnable(GL_DEPTH_TEST);
glDepthFunc(ToGLComparisonFunc(m_depthStencilState.depthFunc));
glDepthMask(m_depthStencilState.depthWriteEnable ? GL_TRUE : GL_FALSE);
} else {
glDisable(GL_DEPTH_TEST);
}
glDepthMask(m_depthStencilState.depthWriteEnable ? GL_TRUE : GL_FALSE);
glDepthFunc(ToGLComparisonFunc(m_depthStencilState.depthFunc));
if (m_depthStencilState.stencilEnable) {
glEnable(GL_STENCIL_TEST);
glStencilMask(m_depthStencilState.stencilWriteMask);
glStencilFunc(ToGLComparisonFunc(m_depthStencilState.stencilFunc), m_depthStencilState.stencilRef, m_depthStencilState.stencilReadMask);
glStencilOp(
ToGLStencilOp(m_depthStencilState.stencilFailOp),
ToGLStencilOp(m_depthStencilState.stencilDepthFailOp),
ToGLStencilOp(m_depthStencilState.stencilDepthPassOp)
);
} else {
glDisable(GL_STENCIL_TEST);
}
}
void OpenGLPipelineState::ApplyBlend() {
if (m_blendState.blendEnable) {
glEnable(GL_BLEND);
glBlendFunc(
ToGLBlendFactor(m_blendState.srcBlend),
ToGLBlendFactor(m_blendState.dstBlend)
);
glBlendFuncSeparate(
ToGLBlendFactor(m_blendState.srcBlend),
ToGLBlendFactor(m_blendState.dstBlend),
ToGLBlendFactor(m_blendState.srcBlendAlpha),
ToGLBlendFactor(m_blendState.dstBlendAlpha)
);
glBlendEquationSeparate(
ToGLBlendOp(m_blendState.blendOp),
ToGLBlendOp(m_blendState.blendOpAlpha)
);
glBlendColor(
m_blendState.blendFactor[0],
m_blendState.blendFactor[1],
m_blendState.blendFactor[2],
m_blendState.blendFactor[3]
);
glColorMask(
(m_blendState.colorWriteMask & 1) != 0,
(m_blendState.colorWriteMask & 2) != 0,
(m_blendState.colorWriteMask & 4) != 0,
(m_blendState.colorWriteMask & 8) != 0
);
} else {
glDisable(GL_BLEND);
}
}
void OpenGLPipelineState::ApplyRasterizer() {
if (m_rasterizerState.cullFaceEnable) {
glEnable(GL_CULL_FACE);
glCullFace(ToGLCullFace(m_rasterizerState.cullFace));
@@ -116,15 +197,49 @@ void OpenGLPipelineState::Apply() {
glDisable(GL_CULL_FACE);
}
glViewport(
m_viewportState.x,
m_viewportState.y,
m_viewportState.width,
m_viewportState.height
);
glPolygonMode(GL_FRONT_AND_BACK, ToGLPolygonMode(m_rasterizerState.polygonMode));
if (m_rasterizerState.polygonOffsetFactor != 0.0f || m_rasterizerState.polygonOffsetUnits != 0.0f) {
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(m_rasterizerState.polygonOffsetFactor, m_rasterizerState.polygonOffsetUnits);
} else {
glDisable(GL_POLYGON_OFFSET_FILL);
}
if (m_rasterizerState.scissorTestEnable) {
glEnable(GL_SCISSOR_TEST);
} else {
glDisable(GL_SCISSOR_TEST);
}
if (m_rasterizerState.multisampleEnable) {
glEnable(GL_MULTISAMPLE);
} else {
glDisable(GL_MULTISAMPLE);
}
if (m_rasterizerState.sampleAlphaToCoverageEnable) {
glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
} else {
glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
}
}
void OpenGLPipelineState::ApplyViewport() {
glViewport((GLint)m_viewportState.x, (GLint)m_viewportState.y,
(GLsizei)m_viewportState.width, (GLsizei)m_viewportState.height);
glDepthRange(m_viewportState.minDepth, m_viewportState.maxDepth);
}
void OpenGLPipelineState::ApplyScissor() {
if (m_scissorState.enable) {
glEnable(GL_SCISSOR_TEST);
glScissor(m_scissorState.x, m_scissorState.y, m_scissorState.width, m_scissorState.height);
} else {
glDisable(GL_SCISSOR_TEST);
}
}
void OpenGLPipelineState::SetClearColor(float r, float g, float b, float a) {
m_clearColor[0] = r;
m_clearColor[1] = g;
@@ -135,11 +250,23 @@ void OpenGLPipelineState::SetClearColor(float r, float g, float b, float a) {
void OpenGLPipelineState::Clear(unsigned int buffers) {
unsigned int glBuffers = 0;
if (buffers & 0x1) glBuffers |= GL_COLOR_BUFFER_BIT;
if (buffers & 0x2) glBuffers |= GL_DEPTH_BUFFER_BIT;
if (buffers & 0x4) glBuffers |= GL_STENCIL_BUFFER_BIT;
if (buffers & 1) glBuffers |= GL_COLOR_BUFFER_BIT;
if (buffers & 2) glBuffers |= GL_DEPTH_BUFFER_BIT;
if (buffers & 4) glBuffers |= GL_STENCIL_BUFFER_BIT;
glClear(glBuffers);
}
void OpenGLPipelineState::AttachShader(unsigned int program) {
m_program = program;
m_programAttached = true;
glUseProgram(program);
}
void OpenGLPipelineState::DetachShader() {
m_program = 0;
m_programAttached = false;
glUseProgram(0);
}
} // namespace RHI
} // namespace XCEngine