diff options
Diffstat (limited to '')
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 338 |
1 files changed, 226 insertions, 112 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index a0527fe57..630a58e49 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -33,7 +33,8 @@ using Maxwell = Tegra::Engines::Maxwell3D::Regs; using PixelFormat = VideoCore::Surface::PixelFormat; using SurfaceType = VideoCore::Surface::SurfaceType; -MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(128, 128, 192)); +MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Format Setup", MP_RGB(128, 128, 192)); +MICROPROFILE_DEFINE(OpenGL_VB, "OpenGL", "Vertex Buffer Setup", MP_RGB(128, 128, 192)); MICROPROFILE_DEFINE(OpenGL_Shader, "OpenGL", "Shader Setup", MP_RGB(128, 128, 192)); MICROPROFILE_DEFINE(OpenGL_UBO, "OpenGL", "Const Buffer Setup", MP_RGB(128, 128, 192)); MICROPROFILE_DEFINE(OpenGL_Index, "OpenGL", "Index Buffer Setup", MP_RGB(128, 128, 192)); @@ -79,7 +80,8 @@ struct DrawParameters { }; RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info) - : emu_window{window}, screen_info{info}, buffer_cache(STREAM_BUFFER_SIZE) { + : res_cache{*this}, shader_cache{*this}, emu_window{window}, screen_info{info}, + buffer_cache(*this, STREAM_BUFFER_SIZE) { // Create sampler objects for (std::size_t i = 0; i < texture_samplers.size(); ++i) { texture_samplers[i].Create(); @@ -96,17 +98,10 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo has_ARB_direct_state_access = true; } else if (extension == "GL_ARB_multi_bind") { has_ARB_multi_bind = true; - } else if (extension == "GL_ARB_separate_shader_objects") { - has_ARB_separate_shader_objects = true; - } else if (extension == "GL_ARB_vertex_attrib_binding") { - has_ARB_vertex_attrib_binding = true; } } - ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported"); OpenGLState::ApplyDefaultState(); - // Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0 - state.clip_distance[0] = true; // Create render framebuffer framebuffer.Create(); @@ -122,18 +117,23 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo RasterizerOpenGL::~RasterizerOpenGL() {} -void RasterizerOpenGL::SetupVertexArrays() { - MICROPROFILE_SCOPE(OpenGL_VAO); - const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); +void RasterizerOpenGL::SetupVertexFormat() { + auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); const auto& regs = gpu.regs; + if (!gpu.dirty_flags.vertex_attrib_format) + return; + gpu.dirty_flags.vertex_attrib_format = false; + + MICROPROFILE_SCOPE(OpenGL_VAO); + auto [iter, is_cache_miss] = vertex_array_cache.try_emplace(regs.vertex_attrib_format); auto& VAO = iter->second; if (is_cache_miss) { VAO.Create(); state.draw.vertex_array = VAO.handle; - state.Apply(); + state.ApplyVertexBufferState(); // The index buffer binding is stored within the VAO. Stupid OpenGL, but easy to work // around. @@ -175,8 +175,13 @@ void RasterizerOpenGL::SetupVertexArrays() { } } state.draw.vertex_array = VAO.handle; - state.draw.vertex_buffer = buffer_cache.GetHandle(); - state.Apply(); + state.ApplyVertexBufferState(); +} + +void RasterizerOpenGL::SetupVertexBuffer() { + MICROPROFILE_SCOPE(OpenGL_VB); + const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); + const auto& regs = gpu.regs; // Upload all guest vertex arrays sequentially to our buffer for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { @@ -203,6 +208,9 @@ void RasterizerOpenGL::SetupVertexArrays() { glVertexBindingDivisor(index, 0); } } + + // Implicit set by glBindVertexBuffer. Stupid glstate handling... + state.draw.vertex_buffer = buffer_cache.GetHandle(); } DrawParameters RasterizerOpenGL::SetupDraw() { @@ -327,8 +335,6 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { index++; } } - - state.Apply(); } std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { @@ -397,8 +403,8 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { cached_pages.add({pages_interval, delta}); } -void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb, - bool preserve_contents, +void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool using_color_fb, + bool using_depth_fb, bool preserve_contents, std::optional<std::size_t> single_color_target) { MICROPROFILE_SCOPE(OpenGL_Framebuffer); const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; @@ -414,9 +420,9 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented"); // Bind the framebuffer surfaces - state.draw.draw_framebuffer = framebuffer.handle; - state.Apply(); - state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0; + current_state.draw.draw_framebuffer = framebuffer.handle; + current_state.ApplyFramebufferState(); + current_state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0; if (using_color_fb) { if (single_color_target) { @@ -494,10 +500,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); } - - SyncViewport(); - - state.Apply(); + SyncViewport(current_state); } void RasterizerOpenGL::Clear() { @@ -510,22 +513,23 @@ void RasterizerOpenGL::Clear() { bool use_stencil{}; OpenGLState clear_state; - clear_state.draw.draw_framebuffer = framebuffer.handle; - clear_state.color_mask.red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE; - clear_state.color_mask.green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE; - clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; - clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; - if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || regs.clear_buffers.A) { use_color = true; } + if (use_color) { + clear_state.color_mask[0].red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE; + clear_state.color_mask[0].green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE; + clear_state.color_mask[0].blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; + clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; + } if (regs.clear_buffers.Z) { ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); use_depth = true; // Always enable the depth write when clearing the depth buffer. The depth write mask is - // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true. + // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to + // true. clear_state.depth.test_enabled = true; clear_state.depth.test_func = GL_ALWAYS; } @@ -533,6 +537,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) { @@ -542,11 +570,16 @@ void RasterizerOpenGL::Clear() { ScopeAcquireGLContext acquire_context{emu_window}; - ConfigureFramebuffers(use_color, use_depth || use_stencil, false, + ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false, regs.clear_buffers.RT.Value()); - // Copy the sRGB setting to the clear state to avoid problem with - // specific driver implementations - clear_state.framebuffer_srgb.enabled = state.framebuffer_srgb.enabled; + if (regs.clear_flags.scissor) { + SyncScissorTest(clear_state); + } + + if (regs.clear_flags.viewport) { + clear_state.EmulateViewportWithScissor(); + } + clear_state.Apply(); if (use_color) { @@ -572,16 +605,17 @@ void RasterizerOpenGL::DrawArrays() { ScopeAcquireGLContext acquire_context{emu_window}; - ConfigureFramebuffers(); - + ConfigureFramebuffers(state); + SyncColorMask(); + SyncFragmentColorClampState(); + SyncMultiSampleState(); SyncDepthTestState(); SyncStencilTestState(); SyncBlendState(); SyncLogicOpState(); SyncCullMode(); SyncPrimitiveRestart(); - SyncDepthRange(); - SyncScissorTest(); + SyncScissorTest(state); // Alpha Testing is synced on shaders. SyncTransformFeedback(); SyncPointState(); @@ -594,7 +628,7 @@ void RasterizerOpenGL::DrawArrays() { const bool is_indexed = accelerate_draw == AccelDraw::Indexed; state.draw.vertex_buffer = buffer_cache.GetHandle(); - state.Apply(); + state.ApplyVertexBufferState(); std::size_t buffer_size = CalculateVertexArraysSize(); @@ -621,7 +655,8 @@ void RasterizerOpenGL::DrawArrays() { buffer_cache.Map(buffer_size); - SetupVertexArrays(); + SetupVertexFormat(); + SetupVertexBuffer(); DrawParameters params = SetupDraw(); SetupShaders(params.primitive_mode); @@ -634,7 +669,7 @@ void RasterizerOpenGL::DrawArrays() { params.DispatchDraw(); // Disable scissor test - state.scissor.enabled = false; + state.viewports[0].scissor.enabled = false; accelerate_draw = AccelDraw::Disabled; @@ -727,7 +762,6 @@ void RasterizerOpenGL::SamplerInfo::Create() { void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) { const GLuint s = sampler.handle; - if (mag_filter != config.mag_filter) { mag_filter = config.mag_filter; glSamplerParameteri( @@ -769,15 +803,51 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr 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}}; - if (border_color != new_border_color) { - border_color = new_border_color; - glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data()); + 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()); + } + + 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, max_anisotropic); + } else if (GLAD_GL_EXT_texture_filter_anisotropic) { + glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropic); } } + 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. + 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; + glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, lod_bias); + } } u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shader, @@ -897,14 +967,18 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, return current_unit + static_cast<u32>(entries.size()); } -void RasterizerOpenGL::SyncViewport() { +void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; - - state.viewport.x = viewport_rect.left; - state.viewport.y = viewport_rect.bottom; - state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth()); - state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight()); + 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 = 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; + } } void RasterizerOpenGL::SyncClipEnabled() { @@ -946,13 +1020,6 @@ void RasterizerOpenGL::SyncPrimitiveRestart() { state.primitive_restart.index = regs.primitive_restart.index; } -void RasterizerOpenGL::SyncDepthRange() { - const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - - state.depth.depth_range_near = regs.viewport->depth_range_near; - state.depth.depth_range_far = regs.viewport->depth_range_far; -} - void RasterizerOpenGL::SyncDepthTestState() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; @@ -973,9 +1040,6 @@ void RasterizerOpenGL::SyncStencilTestState() { return; } - // TODO(bunnei): Verify behavior when this is not set - ASSERT(regs.stencil_two_side_enable); - state.stencil.front.test_func = MaxwellToGL::ComparisonOp(regs.stencil_front_func_func); state.stencil.front.test_ref = regs.stencil_front_func_ref; state.stencil.front.test_mask = regs.stencil_front_func_mask; @@ -983,42 +1047,95 @@ void RasterizerOpenGL::SyncStencilTestState() { state.stencil.front.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_zfail); state.stencil.front.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_front_op_zpass); state.stencil.front.write_mask = regs.stencil_front_mask; + if (regs.stencil_two_side_enable) { + state.stencil.back.test_func = MaxwellToGL::ComparisonOp(regs.stencil_back_func_func); + state.stencil.back.test_ref = regs.stencil_back_func_ref; + state.stencil.back.test_mask = regs.stencil_back_func_mask; + state.stencil.back.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_fail); + state.stencil.back.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_zfail); + state.stencil.back.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_back_op_zpass); + state.stencil.back.write_mask = regs.stencil_back_mask; + } else { + state.stencil.back.test_func = GL_ALWAYS; + state.stencil.back.test_ref = 0; + state.stencil.back.test_mask = 0xFFFFFFFF; + state.stencil.back.write_mask = 0xFFFFFFFF; + state.stencil.back.action_stencil_fail = GL_KEEP; + state.stencil.back.action_depth_fail = GL_KEEP; + state.stencil.back.action_depth_pass = GL_KEEP; + } +} - state.stencil.back.test_func = MaxwellToGL::ComparisonOp(regs.stencil_back_func_func); - state.stencil.back.test_ref = regs.stencil_back_func_ref; - state.stencil.back.test_mask = regs.stencil_back_func_mask; - state.stencil.back.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_fail); - state.stencil.back.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_zfail); - state.stencil.back.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_back_op_zpass); - state.stencil.back.write_mask = regs.stencil_back_mask; +void RasterizerOpenGL::SyncColorMask() { + const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; + 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; + dest.green_enabled = (source.G == 0) ? GL_FALSE : GL_TRUE; + dest.blue_enabled = (source.B == 0) ? GL_FALSE : GL_TRUE; + dest.alpha_enabled = (source.A == 0) ? GL_FALSE : GL_TRUE; + } } -void RasterizerOpenGL::SyncBlendState() { +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; +} - // TODO(Subv): Support more than just render target 0. - state.blend.enabled = regs.blend.enable[0] != 0; +void RasterizerOpenGL::SyncFragmentColorClampState() { + const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; + state.fragment_color_clamp.enabled = regs.frag_color_clamp != 0; +} - if (!state.blend.enabled) - return; +void RasterizerOpenGL::SyncBlendState() { + const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - ASSERT_MSG(regs.logic_op.enable == 0, - "Blending and logic op can't be enabled at the same time."); + state.blend_color.red = regs.blend_color.r; + state.blend_color.green = regs.blend_color.g; + state.blend_color.blue = regs.blend_color.b; + state.blend_color.alpha = regs.blend_color.a; + + state.independant_blend.enabled = regs.independent_blend_enable; + if (!state.independant_blend.enabled) { + auto& blend = state.blend[0]; + 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 (std::size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { + state.blend[i].enabled = false; + } + return; + } - ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented"); - ASSERT_MSG(!regs.independent_blend[0].separate_alpha, "Unimplemented"); - state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_rgb); - state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_rgb); - state.blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_rgb); - state.blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_a); - state.blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_a); - state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_a); + 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.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) @@ -1030,19 +1147,21 @@ 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; - - state.scissor.enabled = (regs.scissor_test.enable != 0); - // TODO(Blinkhawk): Figure if the hardware supports scissor testing per viewport and how it's - // implemented. - if (regs.scissor_test.enable != 0) { - 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; + for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { + const auto& src = regs.scissor_test[i]; + auto& dst = current_state.viewports[i].scissor; + dst.enabled = (src.enable != 0); + if (dst.enabled == 0) { + return; + } + 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; } } @@ -1057,20 +1176,15 @@ 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() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; if (regs.alpha_test_enabled != 0 && regs.rt_control.count > 1) { - LOG_CRITICAL( - Render_OpenGL, - "Alpha Testing is enabled with Multiple Render Targets, this behavior is undefined."); + LOG_CRITICAL(Render_OpenGL, "Alpha Testing is enabled with Multiple Render Targets, " + "this behavior is undefined."); UNREACHABLE(); } } |