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; | ||||
| 
 | ||||
|                 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; | ||||
| 
 | ||||
| @ -1134,6 +1143,7 @@ ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7); | ||||
| ASSERT_REG_POSITION(color_mask_common, 0x3E4); | ||||
| ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); | ||||
| ASSERT_REG_POSITION(zeta, 0x3F8); | ||||
| ASSERT_REG_POSITION(clear_flags, 0x43E); | ||||
| ASSERT_REG_POSITION(vertex_attrib_format, 0x458); | ||||
| ASSERT_REG_POSITION(rt_control, 0x487); | ||||
| 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!"); | ||||
|         use_stencil = 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) { | ||||
| @ -553,6 +577,14 @@ void RasterizerOpenGL::Clear() { | ||||
| 
 | ||||
|     ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false, | ||||
|                           regs.clear_buffers.RT.Value()); | ||||
|     if (regs.clear_flags.scissor) { | ||||
|         SyncScissorTest(clear_state); | ||||
|     } | ||||
| 
 | ||||
|     if (regs.clear_flags.viewport) { | ||||
|         clear_state.EmulateViewportWithScissor(); | ||||
|     } | ||||
| 
 | ||||
|     clear_state.Apply(); | ||||
| 
 | ||||
|     if (use_color) { | ||||
| @ -588,7 +620,7 @@ void RasterizerOpenGL::DrawArrays() { | ||||
|     SyncLogicOpState(); | ||||
|     SyncCullMode(); | ||||
|     SyncPrimitiveRestart(); | ||||
|     SyncScissorTest(); | ||||
|     SyncScissorTest(state); | ||||
|     // Alpha Testing is synced on shaders.
 | ||||
|     SyncTransformFeedback(); | ||||
|     SyncPointState(); | ||||
| @ -815,7 +847,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr | ||||
|     } | ||||
|     const u32 bias = config.mip_lod_bias.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; | ||||
|     if (lod_bias != bias_lod) { | ||||
|         lod_bias = bias_lod; | ||||
| @ -947,8 +979,8 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { | ||||
|         auto& viewport = current_state.viewports[i]; | ||||
|         viewport.x = viewport_rect.left; | ||||
|         viewport.y = viewport_rect.bottom; | ||||
|         viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth()); | ||||
|         viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight()); | ||||
|         viewport.width = viewport_rect.GetWidth(); | ||||
|         viewport.height = viewport_rect.GetHeight(); | ||||
|         viewport.depth_range_far = regs.viewports[i].depth_range_far; | ||||
|         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); | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncScissorTest() { | ||||
| void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) { | ||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||
|     for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; 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); | ||||
|         if (dst.enabled == 0) { | ||||
|             return; | ||||
|  | ||||
| @ -91,19 +91,20 @@ private: | ||||
|         void SyncWithConfig(const Tegra::Texture::TSCEntry& info); | ||||
| 
 | ||||
|     private: | ||||
|         Tegra::Texture::TextureFilter mag_filter; | ||||
|         Tegra::Texture::TextureFilter min_filter; | ||||
|         Tegra::Texture::TextureMipmapFilter mip_filter; | ||||
|         Tegra::Texture::WrapMode wrap_u; | ||||
|         Tegra::Texture::WrapMode wrap_v; | ||||
|         Tegra::Texture::WrapMode wrap_p; | ||||
|         bool uses_depth_compare; | ||||
|         Tegra::Texture::DepthCompareFunc depth_compare_func; | ||||
|         GLvec4 border_color; | ||||
|         float min_lod; | ||||
|         float max_lod; | ||||
|         float lod_bias; | ||||
|         float max_anisotropic; | ||||
|         Tegra::Texture::TextureFilter mag_filter = Tegra::Texture::TextureFilter::Nearest; | ||||
|         Tegra::Texture::TextureFilter min_filter = Tegra::Texture::TextureFilter::Nearest; | ||||
|         Tegra::Texture::TextureMipmapFilter mip_filter = Tegra::Texture::TextureMipmapFilter::None; | ||||
|         Tegra::Texture::WrapMode wrap_u = Tegra::Texture::WrapMode::ClampToEdge; | ||||
|         Tegra::Texture::WrapMode wrap_v = Tegra::Texture::WrapMode::ClampToEdge; | ||||
|         Tegra::Texture::WrapMode wrap_p = Tegra::Texture::WrapMode::ClampToEdge; | ||||
|         bool uses_depth_compare = false; | ||||
|         Tegra::Texture::DepthCompareFunc depth_compare_func = | ||||
|             Tegra::Texture::DepthCompareFunc::Always; | ||||
|         GLvec4 border_color = {}; | ||||
|         float min_lod = 0.0f; | ||||
|         float max_lod = 16.0f; | ||||
|         float lod_bias = 0.0f; | ||||
|         float max_anisotropic = 1.0f; | ||||
|     }; | ||||
| 
 | ||||
|     /**
 | ||||
| @ -171,7 +172,7 @@ private: | ||||
|     void SyncMultiSampleState(); | ||||
| 
 | ||||
|     /// 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
 | ||||
|     void SyncTransformFeedback(); | ||||
|  | ||||
| @ -233,6 +233,28 @@ void OpenGLState::ApplyStencilTest() const { | ||||
|         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 { | ||||
|     if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) { | ||||
| @ -242,7 +264,9 @@ void OpenGLState::ApplyViewport() const { | ||||
|             const auto& updated = viewports[i]; | ||||
|             if (updated.x != current.x || updated.y != current.y || | ||||
|                 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 || | ||||
|                 updated.depth_range_far != current.depth_range_far) { | ||||
| @ -270,8 +294,7 @@ void OpenGLState::ApplyViewport() const { | ||||
|         const auto& updated = viewports[0]; | ||||
|         if (updated.x != current.x || updated.y != current.y || updated.width != current.width || | ||||
|             updated.height != current.height) { | ||||
|             glViewport(static_cast<GLint>(updated.x), static_cast<GLint>(updated.y), | ||||
|                        static_cast<GLsizei>(updated.width), static_cast<GLsizei>(updated.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) { | ||||
|  | ||||
| @ -156,10 +156,10 @@ public: | ||||
|     } draw; | ||||
| 
 | ||||
|     struct viewport { | ||||
|         GLfloat x; | ||||
|         GLfloat y; | ||||
|         GLfloat width; | ||||
|         GLfloat height; | ||||
|         GLint x; | ||||
|         GLint y; | ||||
|         GLint width; | ||||
|         GLint height; | ||||
|         GLfloat depth_range_near; // GL_DEPTH_RANGE
 | ||||
|         GLfloat depth_range_far;  // GL_DEPTH_RANGE
 | ||||
|         struct { | ||||
| @ -206,6 +206,7 @@ public: | ||||
|     OpenGLState& ResetBuffer(GLuint handle); | ||||
|     OpenGLState& ResetVertexArray(GLuint handle); | ||||
|     OpenGLState& ResetFramebuffer(GLuint handle); | ||||
|     void EmulateViewportWithScissor(); | ||||
| 
 | ||||
| private: | ||||
|     static OpenGLState cur_state; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user