gl_state: Synchronize gl_state even when state is disabled

There are some potential edge cases where gl_state may fail to track the
state if a related state changes while the toggle is disabled or it
didn't change. This addresses that.
This commit is contained in:
ReinUsesLisp 2019-02-15 01:30:14 -03:00
parent 4327f430f1
commit 8dfc81239f
1 changed files with 61 additions and 83 deletions

View File

@ -11,7 +11,9 @@
namespace OpenGL { namespace OpenGL {
OpenGLState OpenGLState::cur_state; OpenGLState OpenGLState::cur_state;
bool OpenGLState::s_rgb_used; bool OpenGLState::s_rgb_used;
OpenGLState::OpenGLState() { OpenGLState::OpenGLState() {
// These all match default OpenGL values // These all match default OpenGL values
geometry_shaders.enabled = false; geometry_shaders.enabled = false;
@ -112,7 +114,6 @@ void OpenGLState::ApplyDefaultState() {
} }
void OpenGLState::ApplySRgb() const { void OpenGLState::ApplySRgb() const {
// sRGB
if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) { if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) {
if (framebuffer_srgb.enabled) { if (framebuffer_srgb.enabled) {
// Track if sRGB is used // Track if sRGB is used
@ -125,23 +126,20 @@ void OpenGLState::ApplySRgb() const {
} }
void OpenGLState::ApplyCulling() const { void OpenGLState::ApplyCulling() const {
// Culling if (cull.enabled != cur_state.cull.enabled) {
const bool cull_changed = cull.enabled != cur_state.cull.enabled;
if (cull_changed) {
if (cull.enabled) { if (cull.enabled) {
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
} else { } else {
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
} }
} }
if (cull.enabled) {
if (cull_changed || cull.mode != cur_state.cull.mode) {
glCullFace(cull.mode);
}
if (cull_changed || cull.front_face != cur_state.cull.front_face) { if (cull.mode != cur_state.cull.mode) {
glFrontFace(cull.front_face); glCullFace(cull.mode);
} }
if (cull.front_face != cur_state.cull.front_face) {
glFrontFace(cull.front_face);
} }
} }
@ -172,72 +170,63 @@ void OpenGLState::ApplyColorMask() const {
} }
void OpenGLState::ApplyDepth() const { void OpenGLState::ApplyDepth() const {
// Depth test if (depth.test_enabled != cur_state.depth.test_enabled) {
const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled;
if (depth_test_changed) {
if (depth.test_enabled) { if (depth.test_enabled) {
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
} else { } else {
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
} }
} }
if (depth.test_enabled &&
(depth_test_changed || depth.test_func != cur_state.depth.test_func)) { if (depth.test_func != cur_state.depth.test_func) {
glDepthFunc(depth.test_func); glDepthFunc(depth.test_func);
} }
// Depth mask
if (depth.write_mask != cur_state.depth.write_mask) { if (depth.write_mask != cur_state.depth.write_mask) {
glDepthMask(depth.write_mask); glDepthMask(depth.write_mask);
} }
} }
void OpenGLState::ApplyPrimitiveRestart() const { void OpenGLState::ApplyPrimitiveRestart() const {
const bool primitive_restart_changed = if (primitive_restart.enabled != cur_state.primitive_restart.enabled) {
primitive_restart.enabled != cur_state.primitive_restart.enabled;
if (primitive_restart_changed) {
if (primitive_restart.enabled) { if (primitive_restart.enabled) {
glEnable(GL_PRIMITIVE_RESTART); glEnable(GL_PRIMITIVE_RESTART);
} else { } else {
glDisable(GL_PRIMITIVE_RESTART); glDisable(GL_PRIMITIVE_RESTART);
} }
} }
if (primitive_restart_changed ||
(primitive_restart.enabled && if (primitive_restart.index != cur_state.primitive_restart.index) {
primitive_restart.index != cur_state.primitive_restart.index)) {
glPrimitiveRestartIndex(primitive_restart.index); glPrimitiveRestartIndex(primitive_restart.index);
} }
} }
void OpenGLState::ApplyStencilTest() const { void OpenGLState::ApplyStencilTest() const {
const bool stencil_test_changed = stencil.test_enabled != cur_state.stencil.test_enabled; if (stencil.test_enabled != cur_state.stencil.test_enabled) {
if (stencil_test_changed) {
if (stencil.test_enabled) { if (stencil.test_enabled) {
glEnable(GL_STENCIL_TEST); glEnable(GL_STENCIL_TEST);
} else { } else {
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);
} }
} }
if (stencil.test_enabled) {
auto config_stencil = [stencil_test_changed](GLenum face, const auto& config, const auto ConfigStencil = [](GLenum face, const auto& config, const auto& prev_config) {
const auto& prev_config) { if (config.test_func != prev_config.test_func || config.test_ref != prev_config.test_ref ||
if (stencil_test_changed || config.test_func != prev_config.test_func || config.test_mask != prev_config.test_mask) {
config.test_ref != prev_config.test_ref || glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask);
config.test_mask != prev_config.test_mask) { }
glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask); if (config.action_depth_fail != prev_config.action_depth_fail ||
} config.action_depth_pass != prev_config.action_depth_pass ||
if (stencil_test_changed || config.action_depth_fail != prev_config.action_depth_fail || config.action_stencil_fail != prev_config.action_stencil_fail) {
config.action_depth_pass != prev_config.action_depth_pass || glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail,
config.action_stencil_fail != prev_config.action_stencil_fail) { config.action_depth_pass);
glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail, }
config.action_depth_pass); if (config.write_mask != prev_config.write_mask) {
} glStencilMaskSeparate(face, config.write_mask);
if (config.write_mask != prev_config.write_mask) { }
glStencilMaskSeparate(face, config.write_mask); };
} ConfigStencil(GL_FRONT, stencil.front, cur_state.stencil.front);
}; ConfigStencil(GL_BACK, stencil.back, cur_state.stencil.back);
config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front);
config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
}
} }
// Viewport does not affects glClearBuffer so emulate viewport using scissor test // Viewport does not affects glClearBuffer so emulate viewport using scissor test
void OpenGLState::EmulateViewportWithScissor() { void OpenGLState::EmulateViewportWithScissor() {
@ -278,19 +267,18 @@ void OpenGLState::ApplyViewport() const {
updated.depth_range_far != current.depth_range_far) { updated.depth_range_far != current.depth_range_far) {
glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far); glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far);
} }
const bool scissor_changed = updated.scissor.enabled != current.scissor.enabled;
if (scissor_changed) { if (updated.scissor.enabled != current.scissor.enabled) {
if (updated.scissor.enabled) { if (updated.scissor.enabled) {
glEnablei(GL_SCISSOR_TEST, i); glEnablei(GL_SCISSOR_TEST, i);
} else { } else {
glDisablei(GL_SCISSOR_TEST, i); glDisablei(GL_SCISSOR_TEST, i);
} }
} }
if (updated.scissor.enabled &&
(scissor_changed || updated.scissor.x != current.scissor.x || if (updated.scissor.x != current.scissor.x || updated.scissor.y != current.scissor.y ||
updated.scissor.y != current.scissor.y || updated.scissor.width != current.scissor.width ||
updated.scissor.width != current.scissor.width || updated.scissor.height != current.scissor.height) {
updated.scissor.height != current.scissor.height)) {
glScissorIndexed(i, updated.scissor.x, updated.scissor.y, updated.scissor.width, glScissorIndexed(i, updated.scissor.x, updated.scissor.y, updated.scissor.width,
updated.scissor.height); updated.scissor.height);
} }
@ -302,22 +290,23 @@ void OpenGLState::ApplyViewport() const {
updated.height != current.height) { updated.height != current.height) {
glViewport(updated.x, updated.y, updated.width, updated.height); glViewport(updated.x, updated.y, updated.width, updated.height);
} }
if (updated.depth_range_near != current.depth_range_near || if (updated.depth_range_near != current.depth_range_near ||
updated.depth_range_far != current.depth_range_far) { updated.depth_range_far != current.depth_range_far) {
glDepthRange(updated.depth_range_near, updated.depth_range_far); glDepthRange(updated.depth_range_near, updated.depth_range_far);
} }
const bool scissor_changed = updated.scissor.enabled != current.scissor.enabled;
if (scissor_changed) { if (updated.scissor.enabled != current.scissor.enabled) {
if (updated.scissor.enabled) { if (updated.scissor.enabled) {
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
} else { } else {
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
} }
} }
if (updated.scissor.enabled && (scissor_changed || updated.scissor.x != current.scissor.x ||
updated.scissor.y != current.scissor.y || if (updated.scissor.x != current.scissor.x || updated.scissor.y != current.scissor.y ||
updated.scissor.width != current.scissor.width || updated.scissor.width != current.scissor.width ||
updated.scissor.height != current.scissor.height)) { updated.scissor.height != current.scissor.height) {
glScissor(updated.scissor.x, updated.scissor.y, updated.scissor.width, glScissor(updated.scissor.x, updated.scissor.y, updated.scissor.width,
updated.scissor.height); updated.scissor.height);
} }
@ -327,8 +316,7 @@ void OpenGLState::ApplyViewport() const {
void OpenGLState::ApplyGlobalBlending() const { void OpenGLState::ApplyGlobalBlending() const {
const Blend& current = cur_state.blend[0]; const Blend& current = cur_state.blend[0];
const Blend& updated = blend[0]; const Blend& updated = blend[0];
const bool blend_changed = updated.enabled != current.enabled; if (updated.enabled != current.enabled) {
if (blend_changed) {
if (updated.enabled) { if (updated.enabled) {
glEnable(GL_BLEND); glEnable(GL_BLEND);
} else { } else {
@ -338,15 +326,14 @@ void OpenGLState::ApplyGlobalBlending() const {
if (!updated.enabled) { if (!updated.enabled) {
return; return;
} }
if (blend_changed || updated.src_rgb_func != current.src_rgb_func || if (updated.src_rgb_func != current.src_rgb_func ||
updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func || updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func ||
updated.dst_a_func != current.dst_a_func) { updated.dst_a_func != current.dst_a_func) {
glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func, glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func,
updated.dst_a_func); updated.dst_a_func);
} }
if (blend_changed || updated.rgb_equation != current.rgb_equation || if (updated.rgb_equation != current.rgb_equation || updated.a_equation != current.a_equation) {
updated.a_equation != current.a_equation) {
glBlendEquationSeparate(updated.rgb_equation, updated.a_equation); glBlendEquationSeparate(updated.rgb_equation, updated.a_equation);
} }
} }
@ -354,26 +341,22 @@ void OpenGLState::ApplyGlobalBlending() const {
void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const { void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const {
const Blend& updated = blend[target]; const Blend& updated = blend[target];
const Blend& current = cur_state.blend[target]; const Blend& current = cur_state.blend[target];
const bool blend_changed = updated.enabled != current.enabled || force; if (updated.enabled != current.enabled || force) {
if (blend_changed) {
if (updated.enabled) { if (updated.enabled) {
glEnablei(GL_BLEND, static_cast<GLuint>(target)); glEnablei(GL_BLEND, static_cast<GLuint>(target));
} else { } else {
glDisablei(GL_BLEND, static_cast<GLuint>(target)); glDisablei(GL_BLEND, static_cast<GLuint>(target));
} }
} }
if (!updated.enabled) {
return; if (updated.src_rgb_func != current.src_rgb_func ||
}
if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func || updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func ||
updated.dst_a_func != current.dst_a_func) { updated.dst_a_func != current.dst_a_func) {
glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func, glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func,
updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func); updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
} }
if (blend_changed || updated.rgb_equation != current.rgb_equation || if (updated.rgb_equation != current.rgb_equation || updated.a_equation != current.a_equation) {
updated.a_equation != current.a_equation) {
glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation, glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation,
updated.a_equation); updated.a_equation);
} }
@ -397,8 +380,7 @@ void OpenGLState::ApplyBlending() const {
} }
void OpenGLState::ApplyLogicOp() const { void OpenGLState::ApplyLogicOp() const {
const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled; if (logic_op.enabled != cur_state.logic_op.enabled) {
if (logic_op_changed) {
if (logic_op.enabled) { if (logic_op.enabled) {
glEnable(GL_COLOR_LOGIC_OP); glEnable(GL_COLOR_LOGIC_OP);
} else { } else {
@ -406,14 +388,12 @@ void OpenGLState::ApplyLogicOp() const {
} }
} }
if (logic_op.enabled && if (logic_op.operation != cur_state.logic_op.operation) {
(logic_op_changed || logic_op.operation != cur_state.logic_op.operation)) {
glLogicOp(logic_op.operation); glLogicOp(logic_op.operation);
} }
} }
void OpenGLState::ApplyPolygonOffset() const { void OpenGLState::ApplyPolygonOffset() const {
const bool fill_enable_changed = const bool fill_enable_changed =
polygon_offset.fill_enable != cur_state.polygon_offset.fill_enable; polygon_offset.fill_enable != cur_state.polygon_offset.fill_enable;
const bool line_enable_changed = const bool line_enable_changed =
@ -448,9 +428,7 @@ void OpenGLState::ApplyPolygonOffset() const {
} }
} }
if ((polygon_offset.fill_enable || polygon_offset.line_enable || polygon_offset.point_enable) && if (factor_changed || units_changed || clamp_changed) {
(factor_changed || units_changed || clamp_changed)) {
if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) { if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) {
glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp); glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp);
} else { } else {
@ -528,9 +506,9 @@ void OpenGLState::ApplyDepthClamp() const {
depth_clamp.near_plane == cur_state.depth_clamp.near_plane) { depth_clamp.near_plane == cur_state.depth_clamp.near_plane) {
return; return;
} }
if (depth_clamp.far_plane != depth_clamp.near_plane) { UNIMPLEMENTED_IF_MSG(depth_clamp.far_plane != depth_clamp.near_plane,
UNIMPLEMENTED_MSG("Unimplemented Depth Clamp Separation!"); "Unimplemented Depth Clamp Separation!");
}
if (depth_clamp.far_plane || depth_clamp.near_plane) { if (depth_clamp.far_plane || depth_clamp.near_plane) {
glEnable(GL_DEPTH_CLAMP); glEnable(GL_DEPTH_CLAMP);
} else { } else {