gl_state: Rework to enable individual applies
This commit is contained in:
		| @@ -63,7 +63,6 @@ public: | |||||||
|         UpdatePipeline(); |         UpdatePipeline(); | ||||||
|         state.draw.shader_program = 0; |         state.draw.shader_program = 0; | ||||||
|         state.draw.program_pipeline = pipeline.handle; |         state.draw.program_pipeline = pipeline.handle; | ||||||
|         state.geometry_shaders.enabled = (gs != 0); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
| private: | private: | ||||||
|   | |||||||
| @@ -10,16 +10,62 @@ | |||||||
|  |  | ||||||
| namespace OpenGL { | namespace OpenGL { | ||||||
|  |  | ||||||
| OpenGLState OpenGLState::cur_state; | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||||||
|  |  | ||||||
|  | OpenGLState OpenGLState::cur_state; | ||||||
| bool OpenGLState::s_rgb_used; | bool OpenGLState::s_rgb_used; | ||||||
|  |  | ||||||
|  | namespace { | ||||||
|  |  | ||||||
|  | template <typename T> | ||||||
|  | bool UpdateValue(T& current_value, const T new_value) { | ||||||
|  |     const bool changed = current_value != new_value; | ||||||
|  |     current_value = new_value; | ||||||
|  |     return changed; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename T1, typename T2> | ||||||
|  | bool UpdateTie(T1 current_value, const T2 new_value) { | ||||||
|  |     const bool changed = current_value != new_value; | ||||||
|  |     current_value = new_value; | ||||||
|  |     return changed; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Enable(GLenum cap, bool enable) { | ||||||
|  |     if (enable) { | ||||||
|  |         glEnable(cap); | ||||||
|  |     } else { | ||||||
|  |         glDisable(cap); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Enable(GLenum cap, GLuint index, bool enable) { | ||||||
|  |     if (enable) { | ||||||
|  |         glEnablei(cap, index); | ||||||
|  |     } else { | ||||||
|  |         glDisablei(cap, index); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Enable(GLenum cap, bool& current_value, bool new_value) { | ||||||
|  |     if (UpdateValue(current_value, new_value)) | ||||||
|  |         Enable(cap, new_value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Enable(GLenum cap, GLuint index, bool& current_value, bool new_value) { | ||||||
|  |     if (UpdateValue(current_value, new_value)) | ||||||
|  |         Enable(cap, index, new_value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // namespace | ||||||
|  |  | ||||||
| OpenGLState::OpenGLState() { | OpenGLState::OpenGLState() { | ||||||
|     // These all match default OpenGL values |     // These all match default OpenGL values | ||||||
|     geometry_shaders.enabled = false; |  | ||||||
|     framebuffer_srgb.enabled = false; |     framebuffer_srgb.enabled = false; | ||||||
|  |  | ||||||
|     multisample_control.alpha_to_coverage = false; |     multisample_control.alpha_to_coverage = false; | ||||||
|     multisample_control.alpha_to_one = false; |     multisample_control.alpha_to_one = false; | ||||||
|  |  | ||||||
|     cull.enabled = false; |     cull.enabled = false; | ||||||
|     cull.mode = GL_BACK; |     cull.mode = GL_BACK; | ||||||
|     cull.front_face = GL_CCW; |     cull.front_face = GL_CCW; | ||||||
| @@ -30,14 +76,15 @@ OpenGLState::OpenGLState() { | |||||||
|  |  | ||||||
|     primitive_restart.enabled = false; |     primitive_restart.enabled = false; | ||||||
|     primitive_restart.index = 0; |     primitive_restart.index = 0; | ||||||
|  |  | ||||||
|     for (auto& item : color_mask) { |     for (auto& item : color_mask) { | ||||||
|         item.red_enabled = GL_TRUE; |         item.red_enabled = GL_TRUE; | ||||||
|         item.green_enabled = GL_TRUE; |         item.green_enabled = GL_TRUE; | ||||||
|         item.blue_enabled = GL_TRUE; |         item.blue_enabled = GL_TRUE; | ||||||
|         item.alpha_enabled = GL_TRUE; |         item.alpha_enabled = GL_TRUE; | ||||||
|     } |     } | ||||||
|     stencil.test_enabled = false; |  | ||||||
|     auto reset_stencil = [](auto& config) { |     const auto ResetStencil = [](auto& config) { | ||||||
|         config.test_func = GL_ALWAYS; |         config.test_func = GL_ALWAYS; | ||||||
|         config.test_ref = 0; |         config.test_ref = 0; | ||||||
|         config.test_mask = 0xFFFFFFFF; |         config.test_mask = 0xFFFFFFFF; | ||||||
| @@ -46,8 +93,10 @@ OpenGLState::OpenGLState() { | |||||||
|         config.action_depth_pass = GL_KEEP; |         config.action_depth_pass = GL_KEEP; | ||||||
|         config.action_stencil_fail = GL_KEEP; |         config.action_stencil_fail = GL_KEEP; | ||||||
|     }; |     }; | ||||||
|     reset_stencil(stencil.front); |     stencil.test_enabled = false; | ||||||
|     reset_stencil(stencil.back); |     ResetStencil(stencil.front); | ||||||
|  |     ResetStencil(stencil.back); | ||||||
|  |  | ||||||
|     for (auto& item : viewports) { |     for (auto& item : viewports) { | ||||||
|         item.x = 0; |         item.x = 0; | ||||||
|         item.y = 0; |         item.y = 0; | ||||||
| @@ -61,6 +110,7 @@ OpenGLState::OpenGLState() { | |||||||
|         item.scissor.width = 0; |         item.scissor.width = 0; | ||||||
|         item.scissor.height = 0; |         item.scissor.height = 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     for (auto& item : blend) { |     for (auto& item : blend) { | ||||||
|         item.enabled = true; |         item.enabled = true; | ||||||
|         item.rgb_equation = GL_FUNC_ADD; |         item.rgb_equation = GL_FUNC_ADD; | ||||||
| @@ -70,11 +120,14 @@ OpenGLState::OpenGLState() { | |||||||
|         item.src_a_func = GL_ONE; |         item.src_a_func = GL_ONE; | ||||||
|         item.dst_a_func = GL_ZERO; |         item.dst_a_func = GL_ZERO; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     independant_blend.enabled = false; |     independant_blend.enabled = false; | ||||||
|  |  | ||||||
|     blend_color.red = 0.0f; |     blend_color.red = 0.0f; | ||||||
|     blend_color.green = 0.0f; |     blend_color.green = 0.0f; | ||||||
|     blend_color.blue = 0.0f; |     blend_color.blue = 0.0f; | ||||||
|     blend_color.alpha = 0.0f; |     blend_color.alpha = 0.0f; | ||||||
|  |  | ||||||
|     logic_op.enabled = false; |     logic_op.enabled = false; | ||||||
|     logic_op.operation = GL_COPY; |     logic_op.operation = GL_COPY; | ||||||
|  |  | ||||||
| @@ -91,9 +144,12 @@ OpenGLState::OpenGLState() { | |||||||
|     clip_distance = {}; |     clip_distance = {}; | ||||||
|  |  | ||||||
|     point.size = 1; |     point.size = 1; | ||||||
|  |  | ||||||
|     fragment_color_clamp.enabled = false; |     fragment_color_clamp.enabled = false; | ||||||
|  |  | ||||||
|     depth_clamp.far_plane = false; |     depth_clamp.far_plane = false; | ||||||
|     depth_clamp.near_plane = false; |     depth_clamp.near_plane = false; | ||||||
|  |  | ||||||
|     polygon_offset.fill_enable = false; |     polygon_offset.fill_enable = false; | ||||||
|     polygon_offset.line_enable = false; |     polygon_offset.line_enable = false; | ||||||
|     polygon_offset.point_enable = false; |     polygon_offset.point_enable = false; | ||||||
| @@ -103,18 +159,87 @@ OpenGLState::OpenGLState() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void OpenGLState::ApplyDefaultState() { | void OpenGLState::ApplyDefaultState() { | ||||||
|  |     glEnable(GL_BLEND); | ||||||
|     glDisable(GL_FRAMEBUFFER_SRGB); |     glDisable(GL_FRAMEBUFFER_SRGB); | ||||||
|     glDisable(GL_CULL_FACE); |     glDisable(GL_CULL_FACE); | ||||||
|     glDisable(GL_DEPTH_TEST); |     glDisable(GL_DEPTH_TEST); | ||||||
|     glDisable(GL_PRIMITIVE_RESTART); |     glDisable(GL_PRIMITIVE_RESTART); | ||||||
|     glDisable(GL_STENCIL_TEST); |     glDisable(GL_STENCIL_TEST); | ||||||
|     glEnable(GL_BLEND); |  | ||||||
|     glDisable(GL_COLOR_LOGIC_OP); |     glDisable(GL_COLOR_LOGIC_OP); | ||||||
|     glDisable(GL_SCISSOR_TEST); |     glDisable(GL_SCISSOR_TEST); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyFramebufferState() const { | ||||||
|  |     if (UpdateValue(cur_state.draw.read_framebuffer, draw.read_framebuffer)) { | ||||||
|  |         glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); | ||||||
|  |     } | ||||||
|  |     if (UpdateValue(cur_state.draw.draw_framebuffer, draw.draw_framebuffer)) { | ||||||
|  |         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.draw_framebuffer); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyVertexArrayState() const { | ||||||
|  |     if (UpdateValue(cur_state.draw.vertex_array, draw.vertex_array)) { | ||||||
|  |         glBindVertexArray(draw.vertex_array); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyShaderProgram() const { | ||||||
|  |     if (UpdateValue(cur_state.draw.shader_program, draw.shader_program)) { | ||||||
|  |         glUseProgram(draw.shader_program); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyProgramPipeline() const { | ||||||
|  |     if (UpdateValue(cur_state.draw.program_pipeline, draw.program_pipeline)) { | ||||||
|  |         glBindProgramPipeline(draw.program_pipeline); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyClipDistances() const { | ||||||
|  |     for (std::size_t i = 0; i < clip_distance.size(); ++i) { | ||||||
|  |         Enable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i), cur_state.clip_distance[i], | ||||||
|  |                clip_distance[i]); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyPointSize() const { | ||||||
|  |     if (UpdateValue(cur_state.point.size, point.size)) { | ||||||
|  |         glPointSize(point.size); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyFragmentColorClamp() const { | ||||||
|  |     if (UpdateValue(cur_state.fragment_color_clamp.enabled, fragment_color_clamp.enabled)) { | ||||||
|  |         glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, | ||||||
|  |                      fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyMultisample() const { | ||||||
|  |     Enable(GL_SAMPLE_ALPHA_TO_COVERAGE, cur_state.multisample_control.alpha_to_coverage, | ||||||
|  |            multisample_control.alpha_to_coverage); | ||||||
|  |     Enable(GL_SAMPLE_ALPHA_TO_ONE, cur_state.multisample_control.alpha_to_one, | ||||||
|  |            multisample_control.alpha_to_one); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyDepthClamp() const { | ||||||
|  |     if (depth_clamp.far_plane == cur_state.depth_clamp.far_plane && | ||||||
|  |         depth_clamp.near_plane == cur_state.depth_clamp.near_plane) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     cur_state.depth_clamp = depth_clamp; | ||||||
|  |  | ||||||
|  |     UNIMPLEMENTED_IF_MSG(depth_clamp.far_plane != depth_clamp.near_plane, | ||||||
|  |                          "Unimplemented Depth Clamp Separation!"); | ||||||
|  |  | ||||||
|  |     Enable(GL_DEPTH_CLAMP, depth_clamp.far_plane || depth_clamp.near_plane); | ||||||
|  | } | ||||||
|  |  | ||||||
| void OpenGLState::ApplySRgb() const { | void OpenGLState::ApplySRgb() const { | ||||||
|     if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) { |     if (cur_state.framebuffer_srgb.enabled == framebuffer_srgb.enabled) | ||||||
|  |         return; | ||||||
|  |     cur_state.framebuffer_srgb.enabled = framebuffer_srgb.enabled; | ||||||
|     if (framebuffer_srgb.enabled) { |     if (framebuffer_srgb.enabled) { | ||||||
|         // Track if sRGB is used |         // Track if sRGB is used | ||||||
|         s_rgb_used = true; |         s_rgb_used = true; | ||||||
| @@ -123,112 +248,291 @@ void OpenGLState::ApplySRgb() const { | |||||||
|         glDisable(GL_FRAMEBUFFER_SRGB); |         glDisable(GL_FRAMEBUFFER_SRGB); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| } |  | ||||||
|  |  | ||||||
| void OpenGLState::ApplyCulling() const { | void OpenGLState::ApplyCulling() const { | ||||||
|     if (cull.enabled != cur_state.cull.enabled) { |     Enable(GL_CULL_FACE, cur_state.cull.enabled, cull.enabled); | ||||||
|         if (cull.enabled) { |  | ||||||
|             glEnable(GL_CULL_FACE); |  | ||||||
|         } else { |  | ||||||
|             glDisable(GL_CULL_FACE); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (cull.mode != cur_state.cull.mode) { |     if (UpdateValue(cur_state.cull.mode, cull.mode)) { | ||||||
|         glCullFace(cull.mode); |         glCullFace(cull.mode); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (cull.front_face != cur_state.cull.front_face) { |     if (UpdateValue(cur_state.cull.front_face, cull.front_face)) { | ||||||
|         glFrontFace(cull.front_face); |         glFrontFace(cull.front_face); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void OpenGLState::ApplyColorMask() const { | void OpenGLState::ApplyColorMask() const { | ||||||
|     if (independant_blend.enabled) { |     for (std::size_t i = 0; i < Maxwell::NumRenderTargets; ++i) { | ||||||
|         for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { |  | ||||||
|         const auto& updated = color_mask[i]; |         const auto& updated = color_mask[i]; | ||||||
|             const auto& current = cur_state.color_mask[i]; |         auto& current = cur_state.color_mask[i]; | ||||||
|         if (updated.red_enabled != current.red_enabled || |         if (updated.red_enabled != current.red_enabled || | ||||||
|             updated.green_enabled != current.green_enabled || |             updated.green_enabled != current.green_enabled || | ||||||
|             updated.blue_enabled != current.blue_enabled || |             updated.blue_enabled != current.blue_enabled || | ||||||
|             updated.alpha_enabled != current.alpha_enabled) { |             updated.alpha_enabled != current.alpha_enabled) { | ||||||
|  |             current = updated; | ||||||
|             glColorMaski(static_cast<GLuint>(i), updated.red_enabled, updated.green_enabled, |             glColorMaski(static_cast<GLuint>(i), updated.red_enabled, updated.green_enabled, | ||||||
|                          updated.blue_enabled, updated.alpha_enabled); |                          updated.blue_enabled, updated.alpha_enabled); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     } else { |  | ||||||
|         const auto& updated = color_mask[0]; |  | ||||||
|         const auto& current = cur_state.color_mask[0]; |  | ||||||
|         if (updated.red_enabled != current.red_enabled || |  | ||||||
|             updated.green_enabled != current.green_enabled || |  | ||||||
|             updated.blue_enabled != current.blue_enabled || |  | ||||||
|             updated.alpha_enabled != current.alpha_enabled) { |  | ||||||
|             glColorMask(updated.red_enabled, updated.green_enabled, updated.blue_enabled, |  | ||||||
|                         updated.alpha_enabled); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void OpenGLState::ApplyDepth() const { | void OpenGLState::ApplyDepth() const { | ||||||
|     if (depth.test_enabled != cur_state.depth.test_enabled) { |     Enable(GL_DEPTH_TEST, cur_state.depth.test_enabled, depth.test_enabled); | ||||||
|         if (depth.test_enabled) { |  | ||||||
|             glEnable(GL_DEPTH_TEST); |  | ||||||
|         } else { |  | ||||||
|             glDisable(GL_DEPTH_TEST); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (depth.test_func != cur_state.depth.test_func) { |     if (cur_state.depth.test_func != depth.test_func) { | ||||||
|  |         cur_state.depth.test_func = depth.test_func; | ||||||
|         glDepthFunc(depth.test_func); |         glDepthFunc(depth.test_func); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (depth.write_mask != cur_state.depth.write_mask) { |     if (cur_state.depth.write_mask != depth.write_mask) { | ||||||
|  |         cur_state.depth.write_mask = depth.write_mask; | ||||||
|         glDepthMask(depth.write_mask); |         glDepthMask(depth.write_mask); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void OpenGLState::ApplyPrimitiveRestart() const { | void OpenGLState::ApplyPrimitiveRestart() const { | ||||||
|     if (primitive_restart.enabled != cur_state.primitive_restart.enabled) { |     Enable(GL_PRIMITIVE_RESTART, cur_state.primitive_restart.enabled, primitive_restart.enabled); | ||||||
|         if (primitive_restart.enabled) { |  | ||||||
|             glEnable(GL_PRIMITIVE_RESTART); |  | ||||||
|         } else { |  | ||||||
|             glDisable(GL_PRIMITIVE_RESTART); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (primitive_restart.index != cur_state.primitive_restart.index) { |     if (cur_state.primitive_restart.index != primitive_restart.index) { | ||||||
|  |         cur_state.primitive_restart.index = primitive_restart.index; | ||||||
|         glPrimitiveRestartIndex(primitive_restart.index); |         glPrimitiveRestartIndex(primitive_restart.index); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void OpenGLState::ApplyStencilTest() const { | void OpenGLState::ApplyStencilTest() const { | ||||||
|     if (stencil.test_enabled != cur_state.stencil.test_enabled) { |     Enable(GL_STENCIL_TEST, cur_state.stencil.test_enabled, stencil.test_enabled); | ||||||
|         if (stencil.test_enabled) { |  | ||||||
|             glEnable(GL_STENCIL_TEST); |  | ||||||
|         } else { |  | ||||||
|             glDisable(GL_STENCIL_TEST); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const auto ConfigStencil = [](GLenum face, const auto& config, const auto& prev_config) { |     const auto ConfigStencil = [](GLenum face, const auto& config, auto& current) { | ||||||
|         if (config.test_func != prev_config.test_func || config.test_ref != prev_config.test_ref || |         if (current.test_func != config.test_func || current.test_ref != config.test_ref || | ||||||
|             config.test_mask != prev_config.test_mask) { |             current.test_mask != config.test_mask) { | ||||||
|  |             current.test_func = config.test_func; | ||||||
|  |             current.test_ref = config.test_ref; | ||||||
|  |             current.test_mask = config.test_mask; | ||||||
|             glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask); |             glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask); | ||||||
|         } |         } | ||||||
|         if (config.action_depth_fail != prev_config.action_depth_fail || |         if (current.action_depth_fail != config.action_depth_fail || | ||||||
|             config.action_depth_pass != prev_config.action_depth_pass || |             current.action_depth_pass != config.action_depth_pass || | ||||||
|             config.action_stencil_fail != prev_config.action_stencil_fail) { |             current.action_stencil_fail != config.action_stencil_fail) { | ||||||
|  |             current.action_depth_fail = config.action_depth_fail; | ||||||
|  |             current.action_depth_pass = config.action_depth_pass; | ||||||
|  |             current.action_stencil_fail = config.action_stencil_fail; | ||||||
|             glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail, |             glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail, | ||||||
|                                 config.action_depth_pass); |                                 config.action_depth_pass); | ||||||
|         } |         } | ||||||
|         if (config.write_mask != prev_config.write_mask) { |         if (current.write_mask != config.write_mask) { | ||||||
|  |             current.write_mask = config.write_mask; | ||||||
|             glStencilMaskSeparate(face, config.write_mask); |             glStencilMaskSeparate(face, config.write_mask); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|     ConfigStencil(GL_FRONT, stencil.front, cur_state.stencil.front); |     ConfigStencil(GL_FRONT, stencil.front, cur_state.stencil.front); | ||||||
|     ConfigStencil(GL_BACK, stencil.back, cur_state.stencil.back); |     ConfigStencil(GL_BACK, stencil.back, cur_state.stencil.back); | ||||||
| } | } | ||||||
| // Viewport does not affects glClearBuffer so emulate viewport using scissor test |  | ||||||
|  | void OpenGLState::ApplyViewport() const { | ||||||
|  |     for (GLuint i = 0; i < static_cast<GLuint>(Maxwell::NumViewports); ++i) { | ||||||
|  |         const auto& updated = viewports[i]; | ||||||
|  |         auto& current = cur_state.viewports[i]; | ||||||
|  |  | ||||||
|  |         if (current.x != updated.x || current.y != updated.y || current.width != updated.width || | ||||||
|  |             current.height != updated.height) { | ||||||
|  |             current.x = updated.x; | ||||||
|  |             current.y = updated.y; | ||||||
|  |             current.width = updated.width; | ||||||
|  |             current.height = updated.height; | ||||||
|  |             glViewportIndexedf(i, static_cast<GLfloat>(updated.x), static_cast<GLfloat>(updated.y), | ||||||
|  |                                static_cast<GLfloat>(updated.width), | ||||||
|  |                                static_cast<GLfloat>(updated.height)); | ||||||
|  |         } | ||||||
|  |         if (current.depth_range_near != updated.depth_range_near || | ||||||
|  |             current.depth_range_far != updated.depth_range_far) { | ||||||
|  |             current.depth_range_near = updated.depth_range_near; | ||||||
|  |             current.depth_range_far = updated.depth_range_far; | ||||||
|  |             glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Enable(GL_SCISSOR_TEST, i, current.scissor.enabled, updated.scissor.enabled); | ||||||
|  |  | ||||||
|  |         if (current.scissor.x != updated.scissor.x || current.scissor.y != updated.scissor.y || | ||||||
|  |             current.scissor.width != updated.scissor.width || | ||||||
|  |             current.scissor.height != updated.scissor.height) { | ||||||
|  |             current.scissor.x = updated.scissor.x; | ||||||
|  |             current.scissor.y = updated.scissor.y; | ||||||
|  |             current.scissor.width = updated.scissor.width; | ||||||
|  |             current.scissor.height = updated.scissor.height; | ||||||
|  |             glScissorIndexed(i, updated.scissor.x, updated.scissor.y, updated.scissor.width, | ||||||
|  |                              updated.scissor.height); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyGlobalBlending() const { | ||||||
|  |     const Blend& updated = blend[0]; | ||||||
|  |     Blend& current = cur_state.blend[0]; | ||||||
|  |  | ||||||
|  |     Enable(GL_BLEND, current.enabled, updated.enabled); | ||||||
|  |  | ||||||
|  |     if (current.src_rgb_func != updated.src_rgb_func || | ||||||
|  |         current.dst_rgb_func != updated.dst_rgb_func || current.src_a_func != updated.src_a_func || | ||||||
|  |         current.dst_a_func != updated.dst_a_func) { | ||||||
|  |         current.src_rgb_func = updated.src_rgb_func; | ||||||
|  |         current.dst_rgb_func = updated.dst_rgb_func; | ||||||
|  |         current.src_a_func = updated.src_a_func; | ||||||
|  |         current.dst_a_func = updated.dst_a_func; | ||||||
|  |         glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func, | ||||||
|  |                             updated.dst_a_func); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (current.rgb_equation != updated.rgb_equation || current.a_equation != updated.a_equation) { | ||||||
|  |         current.rgb_equation = updated.rgb_equation; | ||||||
|  |         current.a_equation = updated.a_equation; | ||||||
|  |         glBlendEquationSeparate(updated.rgb_equation, updated.a_equation); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const { | ||||||
|  |     const Blend& updated = blend[target]; | ||||||
|  |     Blend& current = cur_state.blend[target]; | ||||||
|  |  | ||||||
|  |     if (current.enabled != updated.enabled || force) { | ||||||
|  |         current.enabled = updated.enabled; | ||||||
|  |         Enable(GL_BLEND, static_cast<GLuint>(target), updated.enabled); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (UpdateTie(std::tie(current.src_rgb_func, current.dst_rgb_func, current.src_a_func, | ||||||
|  |                            current.dst_a_func), | ||||||
|  |                   std::tie(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func, | ||||||
|  |                            updated.dst_a_func))) { | ||||||
|  |         glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func, | ||||||
|  |                              updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (UpdateTie(std::tie(current.rgb_equation, current.a_equation), | ||||||
|  |                   std::tie(updated.rgb_equation, updated.a_equation))) { | ||||||
|  |         glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation, | ||||||
|  |                                  updated.a_equation); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyBlending() const { | ||||||
|  |     if (independant_blend.enabled) { | ||||||
|  |         const bool force = independant_blend.enabled != cur_state.independant_blend.enabled; | ||||||
|  |         for (std::size_t target = 0; target < Maxwell::NumRenderTargets; ++target) { | ||||||
|  |             ApplyTargetBlending(target, force); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         ApplyGlobalBlending(); | ||||||
|  |     } | ||||||
|  |     cur_state.independant_blend.enabled = independant_blend.enabled; | ||||||
|  |  | ||||||
|  |     if (UpdateTie( | ||||||
|  |             std::tie(cur_state.blend_color.red, cur_state.blend_color.green, | ||||||
|  |                      cur_state.blend_color.blue, cur_state.blend_color.alpha), | ||||||
|  |             std::tie(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha))) { | ||||||
|  |         glBlendColor(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyLogicOp() const { | ||||||
|  |     Enable(GL_COLOR_LOGIC_OP, cur_state.logic_op.enabled, logic_op.enabled); | ||||||
|  |  | ||||||
|  |     if (UpdateValue(cur_state.logic_op.operation, logic_op.operation)) { | ||||||
|  |         glLogicOp(logic_op.operation); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyPolygonOffset() const { | ||||||
|  |     Enable(GL_POLYGON_OFFSET_FILL, cur_state.polygon_offset.fill_enable, | ||||||
|  |            polygon_offset.fill_enable); | ||||||
|  |     Enable(GL_POLYGON_OFFSET_LINE, cur_state.polygon_offset.line_enable, | ||||||
|  |            polygon_offset.line_enable); | ||||||
|  |     Enable(GL_POLYGON_OFFSET_POINT, cur_state.polygon_offset.point_enable, | ||||||
|  |            polygon_offset.point_enable); | ||||||
|  |  | ||||||
|  |     if (UpdateTie(std::tie(cur_state.polygon_offset.factor, cur_state.polygon_offset.units, | ||||||
|  |                            cur_state.polygon_offset.clamp), | ||||||
|  |                   std::tie(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp))) { | ||||||
|  |         if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) { | ||||||
|  |             glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp); | ||||||
|  |         } else { | ||||||
|  |             UNIMPLEMENTED_IF_MSG(polygon_offset.clamp != 0, | ||||||
|  |                                  "Unimplemented Depth polygon offset clamp."); | ||||||
|  |             glPolygonOffset(polygon_offset.factor, polygon_offset.units); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplyTextures() const { | ||||||
|  |     bool has_delta{}; | ||||||
|  |     std::size_t first{}; | ||||||
|  |     std::size_t last{}; | ||||||
|  |     std::array<GLuint, Maxwell::NumTextureSamplers> textures; | ||||||
|  |  | ||||||
|  |     for (std::size_t i = 0; i < std::size(texture_units); ++i) { | ||||||
|  |         const auto& texture_unit = texture_units[i]; | ||||||
|  |         auto& cur_state_texture_unit = cur_state.texture_units[i]; | ||||||
|  |         textures[i] = texture_unit.texture; | ||||||
|  |         if (cur_state_texture_unit.texture == textures[i]) | ||||||
|  |             continue; | ||||||
|  |         cur_state_texture_unit.texture = textures[i]; | ||||||
|  |         if (!has_delta) { | ||||||
|  |             first = i; | ||||||
|  |             has_delta = true; | ||||||
|  |         } | ||||||
|  |         last = i; | ||||||
|  |     } | ||||||
|  |     if (has_delta) { | ||||||
|  |         glBindTextures(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1), | ||||||
|  |                        textures.data() + first); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::ApplySamplers() const { | ||||||
|  |     bool has_delta{}; | ||||||
|  |     std::size_t first{}; | ||||||
|  |     std::size_t last{}; | ||||||
|  |     std::array<GLuint, Maxwell::NumTextureSamplers> samplers; | ||||||
|  |  | ||||||
|  |     for (std::size_t i = 0; i < std::size(samplers); ++i) { | ||||||
|  |         if (cur_state.texture_units[i].sampler == texture_units[i].sampler) | ||||||
|  |             continue; | ||||||
|  |         cur_state.texture_units[i].sampler = texture_units[i].sampler; | ||||||
|  |         samplers[i] = texture_units[i].sampler; | ||||||
|  |         if (!has_delta) { | ||||||
|  |             first = i; | ||||||
|  |             has_delta = true; | ||||||
|  |         } | ||||||
|  |         last = i; | ||||||
|  |     } | ||||||
|  |     if (has_delta) { | ||||||
|  |         glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1), | ||||||
|  |                        samplers.data() + first); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void OpenGLState::Apply() const { | ||||||
|  |     ApplyFramebufferState(); | ||||||
|  |     ApplyVertexArrayState(); | ||||||
|  |     ApplyShaderProgram(); | ||||||
|  |     ApplyProgramPipeline(); | ||||||
|  |     ApplyClipDistances(); | ||||||
|  |     ApplyPointSize(); | ||||||
|  |     ApplyFragmentColorClamp(); | ||||||
|  |     ApplyMultisample(); | ||||||
|  |     ApplyDepthClamp(); | ||||||
|  |     ApplyColorMask(); | ||||||
|  |     ApplyViewport(); | ||||||
|  |     ApplyStencilTest(); | ||||||
|  |     ApplySRgb(); | ||||||
|  |     ApplyCulling(); | ||||||
|  |     ApplyDepth(); | ||||||
|  |     ApplyPrimitiveRestart(); | ||||||
|  |     ApplyBlending(); | ||||||
|  |     ApplyLogicOp(); | ||||||
|  |     ApplyTextures(); | ||||||
|  |     ApplySamplers(); | ||||||
|  |     ApplyPolygonOffset(); | ||||||
|  | } | ||||||
|  |  | ||||||
| void OpenGLState::EmulateViewportWithScissor() { | void OpenGLState::EmulateViewportWithScissor() { | ||||||
|     auto& current = viewports[0]; |     auto& current = viewports[0]; | ||||||
|     if (current.scissor.enabled) { |     if (current.scissor.enabled) { | ||||||
| @@ -251,332 +555,6 @@ void OpenGLState::EmulateViewportWithScissor() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void OpenGLState::ApplyViewport() const { |  | ||||||
|     if (geometry_shaders.enabled) { |  | ||||||
|         for (GLuint i = 0; i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumViewports); |  | ||||||
|              i++) { |  | ||||||
|             const auto& current = cur_state.viewports[i]; |  | ||||||
|             const auto& updated = viewports[i]; |  | ||||||
|             if (updated.x != current.x || updated.y != current.y || |  | ||||||
|                 updated.width != current.width || updated.height != current.height) { |  | ||||||
|                 glViewportIndexedf( |  | ||||||
|                     i, static_cast<GLfloat>(updated.x), static_cast<GLfloat>(updated.y), |  | ||||||
|                     static_cast<GLfloat>(updated.width), static_cast<GLfloat>(updated.height)); |  | ||||||
|             } |  | ||||||
|             if (updated.depth_range_near != current.depth_range_near || |  | ||||||
|                 updated.depth_range_far != current.depth_range_far) { |  | ||||||
|                 glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (updated.scissor.enabled != current.scissor.enabled) { |  | ||||||
|                 if (updated.scissor.enabled) { |  | ||||||
|                     glEnablei(GL_SCISSOR_TEST, i); |  | ||||||
|                 } else { |  | ||||||
|                     glDisablei(GL_SCISSOR_TEST, i); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (updated.scissor.x != current.scissor.x || updated.scissor.y != current.scissor.y || |  | ||||||
|                 updated.scissor.width != current.scissor.width || |  | ||||||
|                 updated.scissor.height != current.scissor.height) { |  | ||||||
|                 glScissorIndexed(i, updated.scissor.x, updated.scissor.y, updated.scissor.width, |  | ||||||
|                                  updated.scissor.height); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         const auto& current = cur_state.viewports[0]; |  | ||||||
|         const auto& updated = viewports[0]; |  | ||||||
|         if (updated.x != current.x || updated.y != current.y || updated.width != current.width || |  | ||||||
|             updated.height != current.height) { |  | ||||||
|             glViewport(updated.x, updated.y, updated.width, updated.height); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (updated.depth_range_near != current.depth_range_near || |  | ||||||
|             updated.depth_range_far != current.depth_range_far) { |  | ||||||
|             glDepthRange(updated.depth_range_near, updated.depth_range_far); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (updated.scissor.enabled != current.scissor.enabled) { |  | ||||||
|             if (updated.scissor.enabled) { |  | ||||||
|                 glEnable(GL_SCISSOR_TEST); |  | ||||||
|             } else { |  | ||||||
|                 glDisable(GL_SCISSOR_TEST); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (updated.scissor.x != current.scissor.x || updated.scissor.y != current.scissor.y || |  | ||||||
|             updated.scissor.width != current.scissor.width || |  | ||||||
|             updated.scissor.height != current.scissor.height) { |  | ||||||
|             glScissor(updated.scissor.x, updated.scissor.y, updated.scissor.width, |  | ||||||
|                       updated.scissor.height); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OpenGLState::ApplyGlobalBlending() const { |  | ||||||
|     const Blend& current = cur_state.blend[0]; |  | ||||||
|     const Blend& updated = blend[0]; |  | ||||||
|     if (updated.enabled != current.enabled) { |  | ||||||
|         if (updated.enabled) { |  | ||||||
|             glEnable(GL_BLEND); |  | ||||||
|         } else { |  | ||||||
|             glDisable(GL_BLEND); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     if (!updated.enabled) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     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_a_func != current.dst_a_func) { |  | ||||||
|         glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func, |  | ||||||
|                             updated.dst_a_func); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (updated.rgb_equation != current.rgb_equation || updated.a_equation != current.a_equation) { |  | ||||||
|         glBlendEquationSeparate(updated.rgb_equation, updated.a_equation); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const { |  | ||||||
|     const Blend& updated = blend[target]; |  | ||||||
|     const Blend& current = cur_state.blend[target]; |  | ||||||
|     if (updated.enabled != current.enabled || force) { |  | ||||||
|         if (updated.enabled) { |  | ||||||
|             glEnablei(GL_BLEND, static_cast<GLuint>(target)); |  | ||||||
|         } else { |  | ||||||
|             glDisablei(GL_BLEND, static_cast<GLuint>(target)); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     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_a_func != current.dst_a_func) { |  | ||||||
|         glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func, |  | ||||||
|                              updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (updated.rgb_equation != current.rgb_equation || updated.a_equation != current.a_equation) { |  | ||||||
|         glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation, |  | ||||||
|                                  updated.a_equation); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OpenGLState::ApplyBlending() const { |  | ||||||
|     if (independant_blend.enabled) { |  | ||||||
|         for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { |  | ||||||
|             ApplyTargetBlending(i, |  | ||||||
|                                 independant_blend.enabled != cur_state.independant_blend.enabled); |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         ApplyGlobalBlending(); |  | ||||||
|     } |  | ||||||
|     if (blend_color.red != cur_state.blend_color.red || |  | ||||||
|         blend_color.green != cur_state.blend_color.green || |  | ||||||
|         blend_color.blue != cur_state.blend_color.blue || |  | ||||||
|         blend_color.alpha != cur_state.blend_color.alpha) { |  | ||||||
|         glBlendColor(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OpenGLState::ApplyLogicOp() const { |  | ||||||
|     if (logic_op.enabled != cur_state.logic_op.enabled) { |  | ||||||
|         if (logic_op.enabled) { |  | ||||||
|             glEnable(GL_COLOR_LOGIC_OP); |  | ||||||
|         } else { |  | ||||||
|             glDisable(GL_COLOR_LOGIC_OP); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (logic_op.operation != cur_state.logic_op.operation) { |  | ||||||
|         glLogicOp(logic_op.operation); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OpenGLState::ApplyPolygonOffset() const { |  | ||||||
|     const bool fill_enable_changed = |  | ||||||
|         polygon_offset.fill_enable != cur_state.polygon_offset.fill_enable; |  | ||||||
|     const bool line_enable_changed = |  | ||||||
|         polygon_offset.line_enable != cur_state.polygon_offset.line_enable; |  | ||||||
|     const bool point_enable_changed = |  | ||||||
|         polygon_offset.point_enable != cur_state.polygon_offset.point_enable; |  | ||||||
|     const bool factor_changed = polygon_offset.factor != cur_state.polygon_offset.factor; |  | ||||||
|     const bool units_changed = polygon_offset.units != cur_state.polygon_offset.units; |  | ||||||
|     const bool clamp_changed = polygon_offset.clamp != cur_state.polygon_offset.clamp; |  | ||||||
|  |  | ||||||
|     if (fill_enable_changed) { |  | ||||||
|         if (polygon_offset.fill_enable) { |  | ||||||
|             glEnable(GL_POLYGON_OFFSET_FILL); |  | ||||||
|         } else { |  | ||||||
|             glDisable(GL_POLYGON_OFFSET_FILL); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (line_enable_changed) { |  | ||||||
|         if (polygon_offset.line_enable) { |  | ||||||
|             glEnable(GL_POLYGON_OFFSET_LINE); |  | ||||||
|         } else { |  | ||||||
|             glDisable(GL_POLYGON_OFFSET_LINE); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (point_enable_changed) { |  | ||||||
|         if (polygon_offset.point_enable) { |  | ||||||
|             glEnable(GL_POLYGON_OFFSET_POINT); |  | ||||||
|         } else { |  | ||||||
|             glDisable(GL_POLYGON_OFFSET_POINT); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (factor_changed || units_changed || clamp_changed) { |  | ||||||
|         if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) { |  | ||||||
|             glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp); |  | ||||||
|         } else { |  | ||||||
|             glPolygonOffset(polygon_offset.factor, polygon_offset.units); |  | ||||||
|             UNIMPLEMENTED_IF_MSG(polygon_offset.clamp != 0, |  | ||||||
|                                  "Unimplemented Depth polygon offset clamp."); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OpenGLState::ApplyTextures() const { |  | ||||||
|     bool has_delta{}; |  | ||||||
|     std::size_t first{}; |  | ||||||
|     std::size_t last{}; |  | ||||||
|     std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> textures; |  | ||||||
|  |  | ||||||
|     for (std::size_t i = 0; i < std::size(texture_units); ++i) { |  | ||||||
|         const auto& texture_unit = texture_units[i]; |  | ||||||
|         const auto& cur_state_texture_unit = cur_state.texture_units[i]; |  | ||||||
|         textures[i] = texture_unit.texture; |  | ||||||
|  |  | ||||||
|         if (textures[i] != cur_state_texture_unit.texture) { |  | ||||||
|             if (!has_delta) { |  | ||||||
|                 first = i; |  | ||||||
|                 has_delta = true; |  | ||||||
|             } |  | ||||||
|             last = i; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (has_delta) { |  | ||||||
|         glBindTextures(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1), |  | ||||||
|                        textures.data() + first); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OpenGLState::ApplySamplers() const { |  | ||||||
|     bool has_delta{}; |  | ||||||
|     std::size_t first{}; |  | ||||||
|     std::size_t last{}; |  | ||||||
|     std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers; |  | ||||||
|     for (std::size_t i = 0; i < std::size(samplers); ++i) { |  | ||||||
|         samplers[i] = texture_units[i].sampler; |  | ||||||
|         if (samplers[i] != cur_state.texture_units[i].sampler) { |  | ||||||
|             if (!has_delta) { |  | ||||||
|                 first = i; |  | ||||||
|                 has_delta = true; |  | ||||||
|             } |  | ||||||
|             last = i; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     if (has_delta) { |  | ||||||
|         glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1), |  | ||||||
|                        samplers.data() + first); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OpenGLState::ApplyFramebufferState() const { |  | ||||||
|     if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { |  | ||||||
|         glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); |  | ||||||
|     } |  | ||||||
|     if (draw.draw_framebuffer != cur_state.draw.draw_framebuffer) { |  | ||||||
|         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.draw_framebuffer); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OpenGLState::ApplyVertexArrayState() const { |  | ||||||
|     if (draw.vertex_array != cur_state.draw.vertex_array) { |  | ||||||
|         glBindVertexArray(draw.vertex_array); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OpenGLState::ApplyDepthClamp() const { |  | ||||||
|     if (depth_clamp.far_plane == cur_state.depth_clamp.far_plane && |  | ||||||
|         depth_clamp.near_plane == cur_state.depth_clamp.near_plane) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     UNIMPLEMENTED_IF_MSG(depth_clamp.far_plane != depth_clamp.near_plane, |  | ||||||
|                          "Unimplemented Depth Clamp Separation!"); |  | ||||||
|  |  | ||||||
|     if (depth_clamp.far_plane || depth_clamp.near_plane) { |  | ||||||
|         glEnable(GL_DEPTH_CLAMP); |  | ||||||
|     } else { |  | ||||||
|         glDisable(GL_DEPTH_CLAMP); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OpenGLState::Apply() const { |  | ||||||
|     ApplyFramebufferState(); |  | ||||||
|     ApplyVertexArrayState(); |  | ||||||
|  |  | ||||||
|     // Shader program |  | ||||||
|     if (draw.shader_program != cur_state.draw.shader_program) { |  | ||||||
|         glUseProgram(draw.shader_program); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Program pipeline |  | ||||||
|     if (draw.program_pipeline != cur_state.draw.program_pipeline) { |  | ||||||
|         glBindProgramPipeline(draw.program_pipeline); |  | ||||||
|     } |  | ||||||
|     // Clip distance |  | ||||||
|     for (std::size_t i = 0; i < clip_distance.size(); ++i) { |  | ||||||
|         if (clip_distance[i] != cur_state.clip_distance[i]) { |  | ||||||
|             if (clip_distance[i]) { |  | ||||||
|                 glEnable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i)); |  | ||||||
|             } else { |  | ||||||
|                 glDisable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i)); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     // Point |  | ||||||
|     if (point.size != cur_state.point.size) { |  | ||||||
|         glPointSize(point.size); |  | ||||||
|     } |  | ||||||
|     if (fragment_color_clamp.enabled != cur_state.fragment_color_clamp.enabled) { |  | ||||||
|         glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, |  | ||||||
|                      fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE); |  | ||||||
|     } |  | ||||||
|     if (multisample_control.alpha_to_coverage != cur_state.multisample_control.alpha_to_coverage) { |  | ||||||
|         if (multisample_control.alpha_to_coverage) { |  | ||||||
|             glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); |  | ||||||
|         } else { |  | ||||||
|             glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     if (multisample_control.alpha_to_one != cur_state.multisample_control.alpha_to_one) { |  | ||||||
|         if (multisample_control.alpha_to_one) { |  | ||||||
|             glEnable(GL_SAMPLE_ALPHA_TO_ONE); |  | ||||||
|         } else { |  | ||||||
|             glDisable(GL_SAMPLE_ALPHA_TO_ONE); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     ApplyDepthClamp(); |  | ||||||
|     ApplyColorMask(); |  | ||||||
|     ApplyViewport(); |  | ||||||
|     ApplyStencilTest(); |  | ||||||
|     ApplySRgb(); |  | ||||||
|     ApplyCulling(); |  | ||||||
|     ApplyDepth(); |  | ||||||
|     ApplyPrimitiveRestart(); |  | ||||||
|     ApplyBlending(); |  | ||||||
|     ApplyLogicOp(); |  | ||||||
|     ApplyTextures(); |  | ||||||
|     ApplySamplers(); |  | ||||||
|     ApplyPolygonOffset(); |  | ||||||
|     cur_state = *this; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| OpenGLState& OpenGLState::UnbindTexture(GLuint handle) { | OpenGLState& OpenGLState::UnbindTexture(GLuint handle) { | ||||||
|     for (auto& unit : texture_units) { |     for (auto& unit : texture_units) { | ||||||
|         if (unit.texture == handle) { |         if (unit.texture == handle) { | ||||||
|   | |||||||
| @@ -53,10 +53,6 @@ public: | |||||||
|         bool near_plane; |         bool near_plane; | ||||||
|     } depth_clamp; // GL_DEPTH_CLAMP |     } depth_clamp; // GL_DEPTH_CLAMP | ||||||
|  |  | ||||||
|     struct { |  | ||||||
|         bool enabled; // viewports arrays are only supported when geometry shaders are enabled. |  | ||||||
|     } geometry_shaders; |  | ||||||
|  |  | ||||||
|     struct { |     struct { | ||||||
|         bool enabled;      // GL_CULL_FACE |         bool enabled;      // GL_CULL_FACE | ||||||
|         GLenum mode;       // GL_CULL_FACE_MODE |         GLenum mode;       // GL_CULL_FACE_MODE | ||||||
| @@ -184,34 +180,26 @@ public: | |||||||
|     static OpenGLState GetCurState() { |     static OpenGLState GetCurState() { | ||||||
|         return cur_state; |         return cur_state; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     static bool GetsRGBUsed() { |     static bool GetsRGBUsed() { | ||||||
|         return s_rgb_used; |         return s_rgb_used; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     static void ClearsRGBUsed() { |     static void ClearsRGBUsed() { | ||||||
|         s_rgb_used = false; |         s_rgb_used = false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Apply this state as the current OpenGL state |     /// Apply this state as the current OpenGL state | ||||||
|     void Apply() const; |     void Apply() const; | ||||||
|     /// Apply only the state affecting the framebuffer |  | ||||||
|     void ApplyFramebufferState() const; |  | ||||||
|     /// Apply only the state affecting the vertex array |  | ||||||
|     void ApplyVertexArrayState() const; |  | ||||||
|     /// Set the initial OpenGL state |  | ||||||
|     static void ApplyDefaultState(); |  | ||||||
|     /// Resets any references to the given resource |  | ||||||
|     OpenGLState& UnbindTexture(GLuint handle); |  | ||||||
|     OpenGLState& ResetSampler(GLuint handle); |  | ||||||
|     OpenGLState& ResetProgram(GLuint handle); |  | ||||||
|     OpenGLState& ResetPipeline(GLuint handle); |  | ||||||
|     OpenGLState& ResetVertexArray(GLuint handle); |  | ||||||
|     OpenGLState& ResetFramebuffer(GLuint handle); |  | ||||||
|     void EmulateViewportWithScissor(); |  | ||||||
|  |  | ||||||
| private: |     void ApplyFramebufferState() const; | ||||||
|     static OpenGLState cur_state; |     void ApplyVertexArrayState() const; | ||||||
|     // Workaround for sRGB problems caused by |     void ApplyShaderProgram() const; | ||||||
|     // QT not supporting srgb output |     void ApplyProgramPipeline() const; | ||||||
|     static bool s_rgb_used; |     void ApplyClipDistances() const; | ||||||
|  |     void ApplyPointSize() const; | ||||||
|  |     void ApplyFragmentColorClamp() const; | ||||||
|  |     void ApplyMultisample() const; | ||||||
|     void ApplySRgb() const; |     void ApplySRgb() const; | ||||||
|     void ApplyCulling() const; |     void ApplyCulling() const; | ||||||
|     void ApplyColorMask() const; |     void ApplyColorMask() const; | ||||||
| @@ -227,6 +215,26 @@ private: | |||||||
|     void ApplySamplers() const; |     void ApplySamplers() const; | ||||||
|     void ApplyDepthClamp() const; |     void ApplyDepthClamp() const; | ||||||
|     void ApplyPolygonOffset() const; |     void ApplyPolygonOffset() const; | ||||||
|  |  | ||||||
|  |     /// Set the initial OpenGL state | ||||||
|  |     static void ApplyDefaultState(); | ||||||
|  |  | ||||||
|  |     /// Resets any references to the given resource | ||||||
|  |     OpenGLState& UnbindTexture(GLuint handle); | ||||||
|  |     OpenGLState& ResetSampler(GLuint handle); | ||||||
|  |     OpenGLState& ResetProgram(GLuint handle); | ||||||
|  |     OpenGLState& ResetPipeline(GLuint handle); | ||||||
|  |     OpenGLState& ResetVertexArray(GLuint handle); | ||||||
|  |     OpenGLState& ResetFramebuffer(GLuint handle); | ||||||
|  |  | ||||||
|  |     /// Viewport does not affects glClearBuffer so emulate viewport using scissor test | ||||||
|  |     void EmulateViewportWithScissor(); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     static OpenGLState cur_state; | ||||||
|  |  | ||||||
|  |     // Workaround for sRGB problems caused by QT not supporting srgb output | ||||||
|  |     static bool s_rgb_used; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace OpenGL | } // namespace OpenGL | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user