mirror of
				https://github.com/yuzu-emu/yuzu.git
				synced 2025-10-31 23:22:47 +00:00 
			
		
		
		
	
						commit
						6dc33fb812
					
				| @ -34,8 +34,8 @@ void Maxwell3D::InitializeRegisterDefaults() { | ||||
|     // Depth range near/far is not always set, but is expected to be the default 0.0f, 1.0f. This is
 | ||||
|     // needed for ARMS.
 | ||||
|     for (std::size_t viewport{}; viewport < Regs::NumViewports; ++viewport) { | ||||
|         regs.viewport[viewport].depth_range_near = 0.0f; | ||||
|         regs.viewport[viewport].depth_range_far = 1.0f; | ||||
|         regs.viewports[viewport].depth_range_near = 0.0f; | ||||
|         regs.viewports[viewport].depth_range_far = 1.0f; | ||||
|     } | ||||
|     // Doom and Bomberman seems to use the uninitialized registers and just enable blend
 | ||||
|     // so initialize blend registers with sane values
 | ||||
| @ -66,6 +66,9 @@ void Maxwell3D::InitializeRegisterDefaults() { | ||||
|     regs.stencil_back_func_func = Regs::ComparisonOp::Always; | ||||
|     regs.stencil_back_func_mask = 0xFFFFFFFF; | ||||
|     regs.stencil_back_mask = 0xFFFFFFFF; | ||||
|     // TODO(Rodrigo): Most games do not set a point size. I think this is a case of a
 | ||||
|     // register carrying a default value. Assume it's OpenGL's default (1).
 | ||||
|     regs.point_size = 1.0f; | ||||
| } | ||||
| 
 | ||||
| void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { | ||||
|  | ||||
| @ -480,34 +480,7 @@ public: | ||||
|             }; | ||||
|         }; | ||||
| 
 | ||||
|         bool IsShaderConfigEnabled(std::size_t index) const { | ||||
|             // The VertexB is always enabled.
 | ||||
|             if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) { | ||||
|                 return true; | ||||
|             } | ||||
|             return shader_config[index].enable != 0; | ||||
|         } | ||||
| 
 | ||||
|         union { | ||||
|             struct { | ||||
|                 INSERT_PADDING_WORDS(0x45); | ||||
| 
 | ||||
|                 struct { | ||||
|                     u32 upload_address; | ||||
|                     u32 data; | ||||
|                     u32 entry; | ||||
|                     u32 bind; | ||||
|                 } macros; | ||||
| 
 | ||||
|                 INSERT_PADDING_WORDS(0x188); | ||||
| 
 | ||||
|                 u32 tfb_enabled; | ||||
| 
 | ||||
|                 INSERT_PADDING_WORDS(0x2E); | ||||
| 
 | ||||
|                 RenderTargetConfig rt[NumRenderTargets]; | ||||
| 
 | ||||
|                 struct { | ||||
|         struct ViewportTransform { | ||||
|             f32 scale_x; | ||||
|             f32 scale_y; | ||||
|             f32 scale_z; | ||||
| @ -540,9 +513,22 @@ public: | ||||
|             s32 GetHeight() const { | ||||
|                 return static_cast<s32>(translate_y + std::fabs(scale_y)) - GetY(); | ||||
|             } | ||||
|                 } viewport_transform[NumViewports]; | ||||
|         }; | ||||
| 
 | ||||
|                 struct { | ||||
|         struct ScissorTest { | ||||
|             u32 enable; | ||||
|             union { | ||||
|                 BitField<0, 16, u32> min_x; | ||||
|                 BitField<16, 16, u32> max_x; | ||||
|             }; | ||||
|             union { | ||||
|                 BitField<0, 16, u32> min_y; | ||||
|                 BitField<16, 16, u32> max_y; | ||||
|             }; | ||||
|             u32 fill; | ||||
|         }; | ||||
| 
 | ||||
|         struct ViewPort { | ||||
|             union { | ||||
|                 BitField<0, 16, u32> x; | ||||
|                 BitField<16, 16, u32> width; | ||||
| @ -553,7 +539,38 @@ public: | ||||
|             }; | ||||
|             float depth_range_near; | ||||
|             float depth_range_far; | ||||
|                 } viewport[NumViewports]; | ||||
|         }; | ||||
| 
 | ||||
|         bool IsShaderConfigEnabled(std::size_t index) const { | ||||
|             // The VertexB is always enabled.
 | ||||
|             if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) { | ||||
|                 return true; | ||||
|             } | ||||
|             return shader_config[index].enable != 0; | ||||
|         } | ||||
| 
 | ||||
|         union { | ||||
|             struct { | ||||
|                 INSERT_PADDING_WORDS(0x45); | ||||
| 
 | ||||
|                 struct { | ||||
|                     u32 upload_address; | ||||
|                     u32 data; | ||||
|                     u32 entry; | ||||
|                     u32 bind; | ||||
|                 } macros; | ||||
| 
 | ||||
|                 INSERT_PADDING_WORDS(0x188); | ||||
| 
 | ||||
|                 u32 tfb_enabled; | ||||
| 
 | ||||
|                 INSERT_PADDING_WORDS(0x2E); | ||||
| 
 | ||||
|                 std::array<RenderTargetConfig, NumRenderTargets> rt; | ||||
| 
 | ||||
|                 std::array<ViewportTransform, NumViewports> viewport_transform; | ||||
| 
 | ||||
|                 std::array<ViewPort, NumViewports> viewports; | ||||
| 
 | ||||
|                 INSERT_PADDING_WORDS(0x1D); | ||||
| 
 | ||||
| @ -571,19 +588,9 @@ public: | ||||
| 
 | ||||
|                 INSERT_PADDING_WORDS(0x17); | ||||
| 
 | ||||
|                 struct { | ||||
|                     u32 enable; | ||||
|                     union { | ||||
|                         BitField<0, 16, u32> min_x; | ||||
|                         BitField<16, 16, u32> max_x; | ||||
|                     }; | ||||
|                     union { | ||||
|                         BitField<0, 16, u32> min_y; | ||||
|                         BitField<16, 16, u32> max_y; | ||||
|                     }; | ||||
|                 } scissor_test; | ||||
|                 std::array<ScissorTest, NumViewports> scissor_test; | ||||
| 
 | ||||
|                 INSERT_PADDING_WORDS(0x52); | ||||
|                 INSERT_PADDING_WORDS(0x15); | ||||
| 
 | ||||
|                 s32 stencil_back_func_ref; | ||||
|                 u32 stencil_back_mask; | ||||
| @ -700,7 +707,9 @@ public: | ||||
|                 u32 stencil_front_func_mask; | ||||
|                 u32 stencil_front_mask; | ||||
| 
 | ||||
|                 INSERT_PADDING_WORDS(0x3); | ||||
|                 INSERT_PADDING_WORDS(0x2); | ||||
| 
 | ||||
|                 u32 frag_color_clamp; | ||||
| 
 | ||||
|                 union { | ||||
|                     BitField<4, 1, u32> triangle_rast_flip; | ||||
| @ -718,7 +727,12 @@ public: | ||||
| 
 | ||||
|                 u32 zeta_enable; | ||||
| 
 | ||||
|                 INSERT_PADDING_WORDS(0x8); | ||||
|                 union { | ||||
|                     BitField<0, 1, u32> alpha_to_coverage; | ||||
|                     BitField<4, 1, u32> alpha_to_one; | ||||
|                 } multisample_control; | ||||
| 
 | ||||
|                 INSERT_PADDING_WORDS(0x7); | ||||
| 
 | ||||
|                 struct { | ||||
|                     u32 tsc_address_high; | ||||
| @ -1100,8 +1114,8 @@ private: | ||||
| ASSERT_REG_POSITION(macros, 0x45); | ||||
| ASSERT_REG_POSITION(tfb_enabled, 0x1D1); | ||||
| ASSERT_REG_POSITION(rt, 0x200); | ||||
| ASSERT_REG_POSITION(viewport_transform[0], 0x280); | ||||
| ASSERT_REG_POSITION(viewport, 0x300); | ||||
| ASSERT_REG_POSITION(viewport_transform, 0x280); | ||||
| ASSERT_REG_POSITION(viewports, 0x300); | ||||
| ASSERT_REG_POSITION(vertex_buffer, 0x35D); | ||||
| ASSERT_REG_POSITION(clear_color[0], 0x360); | ||||
| ASSERT_REG_POSITION(clear_depth, 0x364); | ||||
| @ -1136,10 +1150,12 @@ ASSERT_REG_POSITION(stencil_front_func_func, 0x4E4); | ||||
| ASSERT_REG_POSITION(stencil_front_func_ref, 0x4E5); | ||||
| ASSERT_REG_POSITION(stencil_front_func_mask, 0x4E6); | ||||
| ASSERT_REG_POSITION(stencil_front_mask, 0x4E7); | ||||
| ASSERT_REG_POSITION(frag_color_clamp, 0x4EA); | ||||
| ASSERT_REG_POSITION(screen_y_control, 0x4EB); | ||||
| ASSERT_REG_POSITION(vb_element_base, 0x50D); | ||||
| ASSERT_REG_POSITION(point_size, 0x546); | ||||
| ASSERT_REG_POSITION(zeta_enable, 0x54E); | ||||
| ASSERT_REG_POSITION(multisample_control, 0x54F); | ||||
| ASSERT_REG_POSITION(tsc, 0x557); | ||||
| ASSERT_REG_POSITION(tic, 0x55D); | ||||
| ASSERT_REG_POSITION(stencil_two_side_enable, 0x565); | ||||
|  | ||||
| @ -580,6 +580,8 @@ void RasterizerOpenGL::DrawArrays() { | ||||
| 
 | ||||
|     ConfigureFramebuffers(state); | ||||
|     SyncColorMask(); | ||||
|     SyncFragmentColorClampState(); | ||||
|     SyncMultiSampleState(); | ||||
|     SyncDepthTestState(); | ||||
|     SyncStencilTestState(); | ||||
|     SyncBlendState(); | ||||
| @ -640,7 +642,7 @@ void RasterizerOpenGL::DrawArrays() { | ||||
|     params.DispatchDraw(); | ||||
| 
 | ||||
|     // Disable scissor test
 | ||||
|     state.scissor.enabled = false; | ||||
|     state.viewports[0].scissor.enabled = false; | ||||
| 
 | ||||
|     accelerate_draw = AccelDraw::Disabled; | ||||
| 
 | ||||
| @ -731,9 +733,8 @@ void RasterizerOpenGL::SamplerInfo::Create() { | ||||
|     glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER); | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTextureInfo& info) { | ||||
| void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) { | ||||
|     const GLuint s = sampler.handle; | ||||
|     const Tegra::Texture::TSCEntry& config = info.tsc; | ||||
|     if (mag_filter != config.mag_filter) { | ||||
|         mag_filter = config.mag_filter; | ||||
|         glSamplerParameteri( | ||||
| @ -775,30 +776,50 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTex | ||||
|                             MaxwellToGL::DepthCompareFunc(depth_compare_func)); | ||||
|     } | ||||
| 
 | ||||
|     if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border || | ||||
|         wrap_p == Tegra::Texture::WrapMode::Border) { | ||||
|         const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g, | ||||
|                                           config.border_color_b, config.border_color_a}}; | ||||
|     GLvec4 new_border_color; | ||||
|     if (config.srgb_conversion) { | ||||
|         new_border_color[0] = config.srgb_border_color_r / 255.0f; | ||||
|         new_border_color[1] = config.srgb_border_color_g / 255.0f; | ||||
|         new_border_color[2] = config.srgb_border_color_g / 255.0f; | ||||
|     } else { | ||||
|         new_border_color[0] = config.border_color_r; | ||||
|         new_border_color[1] = config.border_color_g; | ||||
|         new_border_color[2] = config.border_color_b; | ||||
|     } | ||||
|     new_border_color[3] = config.border_color_a; | ||||
| 
 | ||||
|     if (border_color != new_border_color) { | ||||
|         border_color = new_border_color; | ||||
|         glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data()); | ||||
|     } | ||||
|     } | ||||
|     if (info.tic.use_header_opt_control == 0) { | ||||
| 
 | ||||
|     const float anisotropic_max = static_cast<float>(1 << config.max_anisotropy.Value()); | ||||
|     if (anisotropic_max != max_anisotropic) { | ||||
|         max_anisotropic = anisotropic_max; | ||||
|         if (GLAD_GL_ARB_texture_filter_anisotropic) { | ||||
|             glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY, | ||||
|                                 static_cast<float>(1 << info.tic.max_anisotropy.Value())); | ||||
|             glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY, max_anisotropic); | ||||
|         } else if (GLAD_GL_EXT_texture_filter_anisotropic) { | ||||
|             glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT, | ||||
|                                 static_cast<float>(1 << info.tic.max_anisotropy.Value())); | ||||
|             glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropic); | ||||
|         } | ||||
|         glSamplerParameterf(s, GL_TEXTURE_MIN_LOD, | ||||
|                             static_cast<float>(info.tic.res_min_mip_level.Value())); | ||||
|         glSamplerParameterf(s, GL_TEXTURE_MAX_LOD, | ||||
|                             static_cast<float>(info.tic.res_max_mip_level.Value() == 0 | ||||
|                                                    ? 16 | ||||
|                                                    : info.tic.res_max_mip_level.Value())); | ||||
|         glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, info.tic.mip_lod_bias.Value() / 256.f); | ||||
|     } | ||||
|     const float lod_min = static_cast<float>(config.min_lod_clamp.Value()) / 256.0f; | ||||
|     if (lod_min != min_lod) { | ||||
|         min_lod = lod_min; | ||||
|         glSamplerParameterf(s, GL_TEXTURE_MIN_LOD, min_lod); | ||||
|     } | ||||
| 
 | ||||
|     const float lod_max = static_cast<float>(config.max_lod_clamp.Value()) / 256.0f; | ||||
|     if (lod_max != max_lod) { | ||||
|         max_lod = lod_max; | ||||
|         glSamplerParameterf(s, GL_TEXTURE_MAX_LOD, max_lod); | ||||
|     } | ||||
|     const u32 bias = config.mip_lod_bias.Value(); | ||||
|     // Sign extend the 13-bit value.
 | ||||
|     const 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; | ||||
|         glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, lod_bias); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -897,7 +918,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         texture_samplers[current_bindpoint].SyncWithConfig(texture); | ||||
|         texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); | ||||
|         Surface surface = res_cache.GetTextureSurface(texture, entry); | ||||
|         if (surface != nullptr) { | ||||
|             state.texture_units[current_bindpoint].texture = surface->Texture().handle; | ||||
| @ -921,15 +942,15 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { | ||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||
|     for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { | ||||
|     for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { | ||||
|         const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; | ||||
|         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.depth_range_far = regs.viewport[i].depth_range_far; | ||||
|         viewport.depth_range_near = regs.viewport[i].depth_range_near; | ||||
|         viewport.depth_range_far = regs.viewports[i].depth_range_far; | ||||
|         viewport.depth_range_near = regs.viewports[i].depth_range_near; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -1020,7 +1041,9 @@ void RasterizerOpenGL::SyncStencilTestState() { | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncColorMask() { | ||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||
|     for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { | ||||
|     const std::size_t count = | ||||
|         regs.independent_blend_enable ? Tegra::Engines::Maxwell3D::Regs::NumRenderTargets : 1; | ||||
|     for (std::size_t i = 0; i < count; i++) { | ||||
|         const auto& source = regs.color_mask[regs.color_mask_common ? 0 : i]; | ||||
|         auto& dest = state.color_mask[i]; | ||||
|         dest.red_enabled = (source.R == 0) ? GL_FALSE : GL_TRUE; | ||||
| @ -1030,6 +1053,17 @@ void RasterizerOpenGL::SyncColorMask() { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncMultiSampleState() { | ||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||
|     state.multisample_control.alpha_to_coverage = regs.multisample_control.alpha_to_coverage != 0; | ||||
|     state.multisample_control.alpha_to_one = regs.multisample_control.alpha_to_one != 0; | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncFragmentColorClampState() { | ||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||
|     state.fragment_color_clamp.enabled = regs.frag_color_clamp != 0; | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncBlendState() { | ||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||
| 
 | ||||
| @ -1041,43 +1075,40 @@ void RasterizerOpenGL::SyncBlendState() { | ||||
|     state.independant_blend.enabled = regs.independent_blend_enable; | ||||
|     if (!state.independant_blend.enabled) { | ||||
|         auto& blend = state.blend[0]; | ||||
|         blend.enabled = regs.blend.enable[0] != 0; | ||||
|         blend.separate_alpha = regs.blend.separate_alpha; | ||||
|         blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb); | ||||
|         blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb); | ||||
|         blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb); | ||||
|         if (blend.separate_alpha) { | ||||
|             blend.a_equation = MaxwellToGL::BlendEquation(regs.blend.equation_a); | ||||
|             blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a); | ||||
|             blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_a); | ||||
|         const auto& src = regs.blend; | ||||
|         blend.enabled = src.enable[0] != 0; | ||||
|         if (blend.enabled) { | ||||
|             blend.rgb_equation = MaxwellToGL::BlendEquation(src.equation_rgb); | ||||
|             blend.src_rgb_func = MaxwellToGL::BlendFunc(src.factor_source_rgb); | ||||
|             blend.dst_rgb_func = MaxwellToGL::BlendFunc(src.factor_dest_rgb); | ||||
|             blend.a_equation = MaxwellToGL::BlendEquation(src.equation_a); | ||||
|             blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a); | ||||
|             blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_a); | ||||
|         } | ||||
|         for (size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { | ||||
|         for (std::size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { | ||||
|             state.blend[i].enabled = false; | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { | ||||
|     for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { | ||||
|         auto& blend = state.blend[i]; | ||||
|         const auto& src = regs.independent_blend[i]; | ||||
|         blend.enabled = regs.blend.enable[i] != 0; | ||||
|         if (!blend.enabled) | ||||
|             continue; | ||||
|         blend.separate_alpha = regs.independent_blend[i].separate_alpha; | ||||
|         blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_rgb); | ||||
|         blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_rgb); | ||||
|         blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_rgb); | ||||
|         if (blend.separate_alpha) { | ||||
|             blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_a); | ||||
|             blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_a); | ||||
|             blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_a); | ||||
|         } | ||||
|         blend.rgb_equation = MaxwellToGL::BlendEquation(src.equation_rgb); | ||||
|         blend.src_rgb_func = MaxwellToGL::BlendFunc(src.factor_source_rgb); | ||||
|         blend.dst_rgb_func = MaxwellToGL::BlendFunc(src.factor_dest_rgb); | ||||
|         blend.a_equation = MaxwellToGL::BlendEquation(src.equation_a); | ||||
|         blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a); | ||||
|         blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_a); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncLogicOpState() { | ||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||
| 
 | ||||
|     // TODO(Subv): Support more than just render target 0.
 | ||||
|     state.logic_op.enabled = regs.logic_op.enable != 0; | ||||
| 
 | ||||
|     if (!state.logic_op.enabled) | ||||
| @ -1090,19 +1121,21 @@ void RasterizerOpenGL::SyncLogicOpState() { | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncScissorTest() { | ||||
|     // TODO: what is the correct behavior here, a single scissor for all targets
 | ||||
|     // or scissor disabled for the rest of the targets?
 | ||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||
|     state.scissor.enabled = (regs.scissor_test.enable != 0); | ||||
|     if (regs.scissor_test.enable == 0) { | ||||
|     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; | ||||
|         dst.enabled = (src.enable != 0); | ||||
|         if (dst.enabled == 0) { | ||||
|             return; | ||||
|         } | ||||
|     const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x; | ||||
|     const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y; | ||||
|     state.scissor.x = regs.scissor_test.min_x; | ||||
|     state.scissor.y = regs.scissor_test.min_y; | ||||
|     state.scissor.width = width; | ||||
|     state.scissor.height = height; | ||||
|         const u32 width = src.max_x - src.min_x; | ||||
|         const u32 height = src.max_y - src.min_y; | ||||
|         dst.x = src.min_x; | ||||
|         dst.y = src.min_y; | ||||
|         dst.width = width; | ||||
|         dst.height = height; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncTransformFeedback() { | ||||
| @ -1116,11 +1149,7 @@ void RasterizerOpenGL::SyncTransformFeedback() { | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncPointState() { | ||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||
| 
 | ||||
|     // TODO(Rodrigo): Most games do not set a point size. I think this is a case of a
 | ||||
|     // register carrying a default value. For now, if the point size is zero, assume it's
 | ||||
|     // OpenGL's default (1).
 | ||||
|     state.point.size = regs.point_size == 0 ? 1 : regs.point_size; | ||||
|     state.point.size = regs.point_size; | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::CheckAlphaTests() { | ||||
|  | ||||
| @ -88,7 +88,7 @@ private: | ||||
|         /// SamplerInfo struct.
 | ||||
|         void Create(); | ||||
|         /// Syncs the sampler object with the config, updating any necessary state.
 | ||||
|         void SyncWithConfig(const Tegra::Texture::FullTextureInfo& info); | ||||
|         void SyncWithConfig(const Tegra::Texture::TSCEntry& info); | ||||
| 
 | ||||
|     private: | ||||
|         Tegra::Texture::TextureFilter mag_filter; | ||||
| @ -100,6 +100,10 @@ private: | ||||
|         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; | ||||
|     }; | ||||
| 
 | ||||
|     /**
 | ||||
| @ -160,6 +164,12 @@ private: | ||||
|     /// Syncs the LogicOp state to match the guest state
 | ||||
|     void SyncLogicOpState(); | ||||
| 
 | ||||
|     /// Syncs the the color clamp state
 | ||||
|     void SyncFragmentColorClampState(); | ||||
| 
 | ||||
|     /// Syncs the alpha coverage and alpha to one
 | ||||
|     void SyncMultiSampleState(); | ||||
| 
 | ||||
|     /// Syncs the scissor test state to match the guest state
 | ||||
|     void SyncScissorTest(); | ||||
| 
 | ||||
|  | ||||
| @ -67,6 +67,7 @@ public: | ||||
|         glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fs); | ||||
|         state.draw.shader_program = 0; | ||||
|         state.draw.program_pipeline = pipeline.handle; | ||||
|         state.geometry_shaders.enabled = (gs != 0); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|  | ||||
| @ -14,7 +14,10 @@ OpenGLState OpenGLState::cur_state; | ||||
| bool OpenGLState::s_rgb_used; | ||||
| OpenGLState::OpenGLState() { | ||||
|     // These all match default OpenGL values
 | ||||
|     geometry_shaders.enabled = false; | ||||
|     framebuffer_srgb.enabled = false; | ||||
|     multisample_control.alpha_to_coverage = false; | ||||
|     multisample_control.alpha_to_one = false; | ||||
|     cull.enabled = false; | ||||
|     cull.mode = GL_BACK; | ||||
|     cull.front_face = GL_CCW; | ||||
| @ -50,12 +53,12 @@ OpenGLState::OpenGLState() { | ||||
|         item.height = 0; | ||||
|         item.depth_range_near = 0.0f; | ||||
|         item.depth_range_far = 1.0f; | ||||
|         item.scissor.enabled = false; | ||||
|         item.scissor.x = 0; | ||||
|         item.scissor.y = 0; | ||||
|         item.scissor.width = 0; | ||||
|         item.scissor.height = 0; | ||||
|     } | ||||
|     scissor.enabled = false; | ||||
|     scissor.x = 0; | ||||
|     scissor.y = 0; | ||||
|     scissor.width = 0; | ||||
|     scissor.height = 0; | ||||
|     for (auto& item : blend) { | ||||
|         item.enabled = true; | ||||
|         item.rgb_equation = GL_FUNC_ADD; | ||||
| @ -88,6 +91,7 @@ OpenGLState::OpenGLState() { | ||||
|     clip_distance = {}; | ||||
| 
 | ||||
|     point.size = 1; | ||||
|     fragment_color_clamp.enabled = false; | ||||
| } | ||||
| 
 | ||||
| void OpenGLState::ApplyDefaultState() { | ||||
| @ -136,7 +140,7 @@ void OpenGLState::ApplyCulling() const { | ||||
| } | ||||
| 
 | ||||
| void OpenGLState::ApplyColorMask() const { | ||||
|     if (GLAD_GL_ARB_viewport_array) { | ||||
|     if (GLAD_GL_ARB_viewport_array && independant_blend.enabled) { | ||||
|         for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { | ||||
|             const auto& updated = color_mask[i]; | ||||
|             const auto& current = cur_state.color_mask[i]; | ||||
| @ -230,26 +234,10 @@ void OpenGLState::ApplyStencilTest() const { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void OpenGLState::ApplyScissor() const { | ||||
|     const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled; | ||||
|     if (scissor_changed) { | ||||
|         if (scissor.enabled) { | ||||
|             glEnable(GL_SCISSOR_TEST); | ||||
|         } else { | ||||
|             glDisable(GL_SCISSOR_TEST); | ||||
|         } | ||||
|     } | ||||
|     if (scissor.enabled && | ||||
|         (scissor_changed || scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y || | ||||
|          scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height)) { | ||||
|         glScissor(scissor.x, scissor.y, scissor.width, scissor.height); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void OpenGLState::ApplyViewport() const { | ||||
|     if (GLAD_GL_ARB_viewport_array) { | ||||
|         for (GLuint i = 0; | ||||
|              i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); i++) { | ||||
|     if (GLAD_GL_ARB_viewport_array && 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 || | ||||
| @ -260,6 +248,22 @@ void OpenGLState::ApplyViewport() const { | ||||
|                 updated.depth_range_far != current.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) { | ||||
|                     glEnablei(GL_SCISSOR_TEST, i); | ||||
|                 } else { | ||||
|                     glDisablei(GL_SCISSOR_TEST, i); | ||||
|                 } | ||||
|             } | ||||
|             if (updated.scissor.enabled && | ||||
|                 (scissor_changed || 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]; | ||||
| @ -273,6 +277,21 @@ void OpenGLState::ApplyViewport() const { | ||||
|             updated.depth_range_far != current.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) { | ||||
|                 glEnable(GL_SCISSOR_TEST); | ||||
|             } else { | ||||
|                 glDisable(GL_SCISSOR_TEST); | ||||
|             } | ||||
|         } | ||||
|         if (updated.scissor.enabled && (scissor_changed || 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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -290,10 +309,9 @@ void OpenGLState::ApplyGlobalBlending() const { | ||||
|     if (!updated.enabled) { | ||||
|         return; | ||||
|     } | ||||
|     if (updated.separate_alpha) { | ||||
|     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_a_func != current.dst_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) { | ||||
|         glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func, | ||||
|                             updated.dst_a_func); | ||||
|     } | ||||
| @ -302,16 +320,6 @@ void OpenGLState::ApplyGlobalBlending() const { | ||||
|         updated.a_equation != current.a_equation) { | ||||
|         glBlendEquationSeparate(updated.rgb_equation, updated.a_equation); | ||||
|     } | ||||
|     } else { | ||||
|         if (blend_changed || updated.src_rgb_func != current.src_rgb_func || | ||||
|             updated.dst_rgb_func != current.dst_rgb_func) { | ||||
|             glBlendFunc(updated.src_rgb_func, updated.dst_rgb_func); | ||||
|         } | ||||
| 
 | ||||
|         if (blend_changed || updated.rgb_equation != current.rgb_equation) { | ||||
|             glBlendEquation(updated.rgb_equation); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const { | ||||
| @ -328,10 +336,9 @@ void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const { | ||||
|     if (!updated.enabled) { | ||||
|         return; | ||||
|     } | ||||
|     if (updated.separate_alpha) { | ||||
|     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_a_func != current.dst_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) { | ||||
|         glBlendFuncSeparateiARB(static_cast<GLuint>(target), updated.src_rgb_func, | ||||
|                                 updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func); | ||||
|     } | ||||
| @ -341,17 +348,6 @@ void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const { | ||||
|         glBlendEquationSeparateiARB(static_cast<GLuint>(target), updated.rgb_equation, | ||||
|                                     updated.a_equation); | ||||
|     } | ||||
|     } else { | ||||
|         if (blend_changed || updated.src_rgb_func != current.src_rgb_func || | ||||
|             updated.dst_rgb_func != current.dst_rgb_func) { | ||||
|             glBlendFunciARB(static_cast<GLuint>(target), updated.src_rgb_func, | ||||
|                             updated.dst_rgb_func); | ||||
|         } | ||||
| 
 | ||||
|         if (blend_changed || updated.rgb_equation != current.rgb_equation) { | ||||
|             glBlendEquationiARB(static_cast<GLuint>(target), updated.rgb_equation); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void OpenGLState::ApplyBlending() const { | ||||
| @ -481,9 +477,29 @@ void OpenGLState::Apply() const { | ||||
|     if (point.size != cur_state.point.size) { | ||||
|         glPointSize(point.size); | ||||
|     } | ||||
|     if (GLAD_GL_ARB_color_buffer_float) { | ||||
|         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); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ApplyColorMask(); | ||||
|     ApplyViewport(); | ||||
|     ApplyScissor(); | ||||
|     ApplyStencilTest(); | ||||
|     ApplySRgb(); | ||||
|     ApplyCulling(); | ||||
|  | ||||
| @ -39,6 +39,19 @@ public: | ||||
|         bool enabled; // GL_FRAMEBUFFER_SRGB
 | ||||
|     } framebuffer_srgb; | ||||
| 
 | ||||
|     struct { | ||||
|         bool alpha_to_coverage; // GL_ALPHA_TO_COVERAGE
 | ||||
|         bool alpha_to_one;      // GL_ALPHA_TO_ONE
 | ||||
|     } multisample_control; | ||||
| 
 | ||||
|     struct { | ||||
|         bool enabled; // GL_CLAMP_FRAGMENT_COLOR_ARB
 | ||||
|     } fragment_color_clamp; | ||||
| 
 | ||||
|     struct { | ||||
|         bool enabled; // viewports arrays are only supported when geometry shaders are enabled.
 | ||||
|     } geometry_shaders; | ||||
| 
 | ||||
|     struct { | ||||
|         bool enabled;      // GL_CULL_FACE
 | ||||
|         GLenum mode;       // GL_CULL_FACE_MODE
 | ||||
| @ -79,7 +92,6 @@ public: | ||||
| 
 | ||||
|     struct Blend { | ||||
|         bool enabled;        // GL_BLEND
 | ||||
|         bool separate_alpha; // Independent blend enabled
 | ||||
|         GLenum rgb_equation; // GL_BLEND_EQUATION_RGB
 | ||||
|         GLenum a_equation;   // GL_BLEND_EQUATION_ALPHA
 | ||||
|         GLenum src_rgb_func; // GL_BLEND_SRC_RGB
 | ||||
| @ -150,9 +162,6 @@ public: | ||||
|         GLfloat height; | ||||
|         GLfloat depth_range_near; // GL_DEPTH_RANGE
 | ||||
|         GLfloat depth_range_far;  // GL_DEPTH_RANGE
 | ||||
|     }; | ||||
|     std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> viewports; | ||||
| 
 | ||||
|         struct { | ||||
|             bool enabled; // GL_SCISSOR_TEST
 | ||||
|             GLint x; | ||||
| @ -160,6 +169,8 @@ public: | ||||
|             GLsizei width; | ||||
|             GLsizei height; | ||||
|         } scissor; | ||||
|     }; | ||||
|     std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports; | ||||
| 
 | ||||
|     struct { | ||||
|         float size; // GL_POINT_SIZE
 | ||||
| @ -214,7 +225,6 @@ private: | ||||
|     void ApplyLogicOp() const; | ||||
|     void ApplyTextures() const; | ||||
|     void ApplySamplers() const; | ||||
|     void ApplyScissor() const; | ||||
| }; | ||||
| 
 | ||||
| } // namespace OpenGL
 | ||||
|  | ||||
| @ -180,6 +180,12 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { | ||||
|         return GL_CLAMP_TO_BORDER; | ||||
|     case Tegra::Texture::WrapMode::MirrorOnceClampToEdge: | ||||
|         return GL_MIRROR_CLAMP_TO_EDGE; | ||||
|     case Tegra::Texture::WrapMode::MirrorOnceBorder: | ||||
|         if (GL_EXT_texture_mirror_clamp) { | ||||
|             return GL_MIRROR_CLAMP_TO_BORDER_EXT; | ||||
|         } else { | ||||
|             return GL_MIRROR_CLAMP_TO_EDGE; | ||||
|         } | ||||
|     } | ||||
|     LOG_ERROR(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode)); | ||||
|     return GL_REPEAT; | ||||
|  | ||||
| @ -190,6 +190,7 @@ struct TICEntry { | ||||
|     union { | ||||
|         BitField<0, 4, u32> res_min_mip_level; | ||||
|         BitField<4, 4, u32> res_max_mip_level; | ||||
|         BitField<12, 12, u32> min_lod_clamp; | ||||
|     }; | ||||
| 
 | ||||
|     GPUVAddr Address() const { | ||||
| @ -284,13 +285,25 @@ struct TSCEntry { | ||||
|         BitField<6, 3, WrapMode> wrap_p; | ||||
|         BitField<9, 1, u32> depth_compare_enabled; | ||||
|         BitField<10, 3, DepthCompareFunc> depth_compare_func; | ||||
|         BitField<13, 1, u32> srgb_conversion; | ||||
|         BitField<20, 3, u32> max_anisotropy; | ||||
|     }; | ||||
|     union { | ||||
|         BitField<0, 2, TextureFilter> mag_filter; | ||||
|         BitField<4, 2, TextureFilter> min_filter; | ||||
|         BitField<6, 2, TextureMipmapFilter> mip_filter; | ||||
|         BitField<9, 1, u32> cubemap_interface_filtering; | ||||
|         BitField<12, 13, u32> mip_lod_bias; | ||||
|     }; | ||||
|     union { | ||||
|         BitField<0, 12, u32> min_lod_clamp; | ||||
|         BitField<12, 12, u32> max_lod_clamp; | ||||
|         BitField<24, 8, u32> srgb_border_color_r; | ||||
|     }; | ||||
|     union { | ||||
|         BitField<12, 8, u32> srgb_border_color_g; | ||||
|         BitField<20, 8, u32> srgb_border_color_b; | ||||
|     }; | ||||
|     INSERT_PADDING_BYTES(8); | ||||
|     float border_color_r; | ||||
|     float border_color_g; | ||||
|     float border_color_b; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 bunnei
						bunnei