mirror of
				https://git.suyu.dev/suyu/suyu.git
				synced 2025-10-31 06:46:40 +08:00 
			
		
		
		
	Add support for clear_flags register
This commit is contained in:
		
							parent
							
								
									69b3f98d3a
								
							
						
					
					
						commit
						54c2a4cafc
					
				| @ -631,7 +631,16 @@ public: | |||||||
|                     } |                     } | ||||||
|                 } zeta; |                 } zeta; | ||||||
| 
 | 
 | ||||||
|                 INSERT_PADDING_WORDS(0x5B); |                 INSERT_PADDING_WORDS(0x41); | ||||||
|  | 
 | ||||||
|  |                 union { | ||||||
|  |                     BitField<0, 4, u32> stencil; | ||||||
|  |                     BitField<4, 4, u32> unknown; | ||||||
|  |                     BitField<8, 4, u32> scissor; | ||||||
|  |                     BitField<12, 4, u32> viewport; | ||||||
|  |                 } clear_flags; | ||||||
|  | 
 | ||||||
|  |                 INSERT_PADDING_WORDS(0x19); | ||||||
| 
 | 
 | ||||||
|                 std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format; |                 std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format; | ||||||
| 
 | 
 | ||||||
| @ -1134,6 +1143,7 @@ ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7); | |||||||
| ASSERT_REG_POSITION(color_mask_common, 0x3E4); | ASSERT_REG_POSITION(color_mask_common, 0x3E4); | ||||||
| ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); | ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); | ||||||
| ASSERT_REG_POSITION(zeta, 0x3F8); | ASSERT_REG_POSITION(zeta, 0x3F8); | ||||||
|  | ASSERT_REG_POSITION(clear_flags, 0x43E); | ||||||
| ASSERT_REG_POSITION(vertex_attrib_format, 0x458); | ASSERT_REG_POSITION(vertex_attrib_format, 0x458); | ||||||
| ASSERT_REG_POSITION(rt_control, 0x487); | ASSERT_REG_POSITION(rt_control, 0x487); | ||||||
| ASSERT_REG_POSITION(zeta_width, 0x48a); | ASSERT_REG_POSITION(zeta_width, 0x48a); | ||||||
|  | |||||||
| @ -542,6 +542,30 @@ void RasterizerOpenGL::Clear() { | |||||||
|         ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); |         ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); | ||||||
|         use_stencil = true; |         use_stencil = true; | ||||||
|         clear_state.stencil.test_enabled = true; |         clear_state.stencil.test_enabled = true; | ||||||
|  |         if (regs.clear_flags.stencil) { | ||||||
|  |             // Stencil affects the clear so fill it with the used masks
 | ||||||
|  |             clear_state.stencil.front.test_func = GL_ALWAYS; | ||||||
|  |             clear_state.stencil.front.test_mask = regs.stencil_front_func_mask; | ||||||
|  |             clear_state.stencil.front.action_stencil_fail = GL_KEEP; | ||||||
|  |             clear_state.stencil.front.action_depth_fail = GL_KEEP; | ||||||
|  |             clear_state.stencil.front.action_depth_pass = GL_KEEP; | ||||||
|  |             clear_state.stencil.front.write_mask = regs.stencil_front_mask; | ||||||
|  |             if (regs.stencil_two_side_enable) { | ||||||
|  |                 clear_state.stencil.back.test_func = GL_ALWAYS; | ||||||
|  |                 clear_state.stencil.back.test_mask = regs.stencil_back_func_mask; | ||||||
|  |                 clear_state.stencil.back.action_stencil_fail = GL_KEEP; | ||||||
|  |                 clear_state.stencil.back.action_depth_fail = GL_KEEP; | ||||||
|  |                 clear_state.stencil.back.action_depth_pass = GL_KEEP; | ||||||
|  |                 clear_state.stencil.back.write_mask = regs.stencil_back_mask; | ||||||
|  |             } else { | ||||||
|  |                 clear_state.stencil.back.test_func = GL_ALWAYS; | ||||||
|  |                 clear_state.stencil.back.test_mask = 0xFFFFFFFF; | ||||||
|  |                 clear_state.stencil.back.write_mask = 0xFFFFFFFF; | ||||||
|  |                 clear_state.stencil.back.action_stencil_fail = GL_KEEP; | ||||||
|  |                 clear_state.stencil.back.action_depth_fail = GL_KEEP; | ||||||
|  |                 clear_state.stencil.back.action_depth_pass = GL_KEEP; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!use_color && !use_depth && !use_stencil) { |     if (!use_color && !use_depth && !use_stencil) { | ||||||
| @ -553,6 +577,14 @@ void RasterizerOpenGL::Clear() { | |||||||
| 
 | 
 | ||||||
|     ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false, |     ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false, | ||||||
|                           regs.clear_buffers.RT.Value()); |                           regs.clear_buffers.RT.Value()); | ||||||
|  |     if (regs.clear_flags.scissor) { | ||||||
|  |         SyncScissorTest(clear_state); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (regs.clear_flags.viewport) { | ||||||
|  |         clear_state.EmulateViewportWithScissor(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     clear_state.Apply(); |     clear_state.Apply(); | ||||||
| 
 | 
 | ||||||
|     if (use_color) { |     if (use_color) { | ||||||
| @ -588,7 +620,7 @@ void RasterizerOpenGL::DrawArrays() { | |||||||
|     SyncLogicOpState(); |     SyncLogicOpState(); | ||||||
|     SyncCullMode(); |     SyncCullMode(); | ||||||
|     SyncPrimitiveRestart(); |     SyncPrimitiveRestart(); | ||||||
|     SyncScissorTest(); |     SyncScissorTest(state); | ||||||
|     // Alpha Testing is synced on shaders.
 |     // Alpha Testing is synced on shaders.
 | ||||||
|     SyncTransformFeedback(); |     SyncTransformFeedback(); | ||||||
|     SyncPointState(); |     SyncPointState(); | ||||||
| @ -815,7 +847,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr | |||||||
|     } |     } | ||||||
|     const u32 bias = config.mip_lod_bias.Value(); |     const u32 bias = config.mip_lod_bias.Value(); | ||||||
|     // Sign extend the 13-bit value.
 |     // Sign extend the 13-bit value.
 | ||||||
|     const u32 mask = 1U << (13 - 1); |     constexpr u32 mask = 1U << (13 - 1); | ||||||
|     const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f; |     const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f; | ||||||
|     if (lod_bias != bias_lod) { |     if (lod_bias != bias_lod) { | ||||||
|         lod_bias = bias_lod; |         lod_bias = bias_lod; | ||||||
| @ -947,8 +979,8 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { | |||||||
|         auto& viewport = current_state.viewports[i]; |         auto& viewport = current_state.viewports[i]; | ||||||
|         viewport.x = viewport_rect.left; |         viewport.x = viewport_rect.left; | ||||||
|         viewport.y = viewport_rect.bottom; |         viewport.y = viewport_rect.bottom; | ||||||
|         viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth()); |         viewport.width = viewport_rect.GetWidth(); | ||||||
|         viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight()); |         viewport.height = viewport_rect.GetHeight(); | ||||||
|         viewport.depth_range_far = regs.viewports[i].depth_range_far; |         viewport.depth_range_far = regs.viewports[i].depth_range_far; | ||||||
|         viewport.depth_range_near = regs.viewports[i].depth_range_near; |         viewport.depth_range_near = regs.viewports[i].depth_range_near; | ||||||
|     } |     } | ||||||
| @ -1120,11 +1152,11 @@ void RasterizerOpenGL::SyncLogicOpState() { | |||||||
|     state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); |     state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RasterizerOpenGL::SyncScissorTest() { | void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) { | ||||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||||
|     for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { |     for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { | ||||||
|         const auto& src = regs.scissor_test[i]; |         const auto& src = regs.scissor_test[i]; | ||||||
|         auto& dst = state.viewports[i].scissor; |         auto& dst = current_state.viewports[i].scissor; | ||||||
|         dst.enabled = (src.enable != 0); |         dst.enabled = (src.enable != 0); | ||||||
|         if (dst.enabled == 0) { |         if (dst.enabled == 0) { | ||||||
|             return; |             return; | ||||||
|  | |||||||
| @ -91,19 +91,20 @@ private: | |||||||
|         void SyncWithConfig(const Tegra::Texture::TSCEntry& info); |         void SyncWithConfig(const Tegra::Texture::TSCEntry& info); | ||||||
| 
 | 
 | ||||||
|     private: |     private: | ||||||
|         Tegra::Texture::TextureFilter mag_filter; |         Tegra::Texture::TextureFilter mag_filter = Tegra::Texture::TextureFilter::Nearest; | ||||||
|         Tegra::Texture::TextureFilter min_filter; |         Tegra::Texture::TextureFilter min_filter = Tegra::Texture::TextureFilter::Nearest; | ||||||
|         Tegra::Texture::TextureMipmapFilter mip_filter; |         Tegra::Texture::TextureMipmapFilter mip_filter = Tegra::Texture::TextureMipmapFilter::None; | ||||||
|         Tegra::Texture::WrapMode wrap_u; |         Tegra::Texture::WrapMode wrap_u = Tegra::Texture::WrapMode::ClampToEdge; | ||||||
|         Tegra::Texture::WrapMode wrap_v; |         Tegra::Texture::WrapMode wrap_v = Tegra::Texture::WrapMode::ClampToEdge; | ||||||
|         Tegra::Texture::WrapMode wrap_p; |         Tegra::Texture::WrapMode wrap_p = Tegra::Texture::WrapMode::ClampToEdge; | ||||||
|         bool uses_depth_compare; |         bool uses_depth_compare = false; | ||||||
|         Tegra::Texture::DepthCompareFunc depth_compare_func; |         Tegra::Texture::DepthCompareFunc depth_compare_func = | ||||||
|         GLvec4 border_color; |             Tegra::Texture::DepthCompareFunc::Always; | ||||||
|         float min_lod; |         GLvec4 border_color = {}; | ||||||
|         float max_lod; |         float min_lod = 0.0f; | ||||||
|         float lod_bias; |         float max_lod = 16.0f; | ||||||
|         float max_anisotropic; |         float lod_bias = 0.0f; | ||||||
|  |         float max_anisotropic = 1.0f; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
| @ -171,7 +172,7 @@ private: | |||||||
|     void SyncMultiSampleState(); |     void SyncMultiSampleState(); | ||||||
| 
 | 
 | ||||||
|     /// Syncs the scissor test state to match the guest state
 |     /// Syncs the scissor test state to match the guest state
 | ||||||
|     void SyncScissorTest(); |     void SyncScissorTest(OpenGLState& current_state); | ||||||
| 
 | 
 | ||||||
|     /// Syncs the transform feedback state to match the guest state
 |     /// Syncs the transform feedback state to match the guest state
 | ||||||
|     void SyncTransformFeedback(); |     void SyncTransformFeedback(); | ||||||
|  | |||||||
| @ -233,6 +233,28 @@ void OpenGLState::ApplyStencilTest() const { | |||||||
|         config_stencil(GL_BACK, stencil.back, cur_state.stencil.back); |         config_stencil(GL_BACK, stencil.back, cur_state.stencil.back); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | // Viewport does not affects glClearBuffer so emulate viewport using scissor test
 | ||||||
|  | void OpenGLState::EmulateViewportWithScissor() { | ||||||
|  |     auto& current = viewports[0]; | ||||||
|  |     if (current.scissor.enabled) { | ||||||
|  |         const GLint left = std::max(current.x, current.scissor.x); | ||||||
|  |         const GLint right = | ||||||
|  |             std::max(current.x + current.width, current.scissor.x + current.scissor.width); | ||||||
|  |         const GLint bottom = std::max(current.y, current.scissor.y); | ||||||
|  |         const GLint top = | ||||||
|  |             std::max(current.y + current.height, current.scissor.y + current.scissor.height); | ||||||
|  |         current.scissor.x = std::max(left, 0); | ||||||
|  |         current.scissor.y = std::max(bottom, 0); | ||||||
|  |         current.scissor.width = std::max(right - left, 0); | ||||||
|  |         current.scissor.height = std::max(top - bottom, 0); | ||||||
|  |     } else { | ||||||
|  |         current.scissor.enabled = true; | ||||||
|  |         current.scissor.x = current.x; | ||||||
|  |         current.scissor.y = current.y; | ||||||
|  |         current.scissor.width = current.width; | ||||||
|  |         current.scissor.height = current.height; | ||||||
|  |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| void OpenGLState::ApplyViewport() const { | void OpenGLState::ApplyViewport() const { | ||||||
|     if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) { |     if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) { | ||||||
| @ -242,7 +264,9 @@ void OpenGLState::ApplyViewport() const { | |||||||
|             const auto& updated = viewports[i]; |             const auto& updated = viewports[i]; | ||||||
|             if (updated.x != current.x || updated.y != current.y || |             if (updated.x != current.x || updated.y != current.y || | ||||||
|                 updated.width != current.width || updated.height != current.height) { |                 updated.width != current.width || updated.height != current.height) { | ||||||
|                 glViewportIndexedf(i, updated.x, updated.y, updated.width, 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 (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) { | ||||||
| @ -270,8 +294,7 @@ void OpenGLState::ApplyViewport() const { | |||||||
|         const auto& updated = viewports[0]; |         const auto& updated = viewports[0]; | ||||||
|         if (updated.x != current.x || updated.y != current.y || updated.width != current.width || |         if (updated.x != current.x || updated.y != current.y || updated.width != current.width || | ||||||
|             updated.height != current.height) { |             updated.height != current.height) { | ||||||
|             glViewport(static_cast<GLint>(updated.x), static_cast<GLint>(updated.y), |             glViewport(updated.x, updated.y, updated.width, updated.height); | ||||||
|                        static_cast<GLsizei>(updated.width), static_cast<GLsizei>(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) { | ||||||
|  | |||||||
| @ -156,10 +156,10 @@ public: | |||||||
|     } draw; |     } draw; | ||||||
| 
 | 
 | ||||||
|     struct viewport { |     struct viewport { | ||||||
|         GLfloat x; |         GLint x; | ||||||
|         GLfloat y; |         GLint y; | ||||||
|         GLfloat width; |         GLint width; | ||||||
|         GLfloat height; |         GLint height; | ||||||
|         GLfloat depth_range_near; // GL_DEPTH_RANGE
 |         GLfloat depth_range_near; // GL_DEPTH_RANGE
 | ||||||
|         GLfloat depth_range_far;  // GL_DEPTH_RANGE
 |         GLfloat depth_range_far;  // GL_DEPTH_RANGE
 | ||||||
|         struct { |         struct { | ||||||
| @ -206,6 +206,7 @@ public: | |||||||
|     OpenGLState& ResetBuffer(GLuint handle); |     OpenGLState& ResetBuffer(GLuint handle); | ||||||
|     OpenGLState& ResetVertexArray(GLuint handle); |     OpenGLState& ResetVertexArray(GLuint handle); | ||||||
|     OpenGLState& ResetFramebuffer(GLuint handle); |     OpenGLState& ResetFramebuffer(GLuint handle); | ||||||
|  |     void EmulateViewportWithScissor(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     static OpenGLState cur_state; |     static OpenGLState cur_state; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user