fix viewport and scissor behavior
This commit is contained in:
		| @@ -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 |     // Depth range near/far is not always set, but is expected to be the default 0.0f, 1.0f. This is | ||||||
|     // needed for ARMS. |     // needed for ARMS. | ||||||
|     for (std::size_t viewport{}; viewport < Regs::NumViewports; ++viewport) { |     for (std::size_t viewport{}; viewport < Regs::NumViewports; ++viewport) { | ||||||
|         regs.viewport[viewport].depth_range_near = 0.0f; |         regs.viewports[viewport].depth_range_near = 0.0f; | ||||||
|         regs.viewport[viewport].depth_range_far = 1.0f; |         regs.viewports[viewport].depth_range_far = 1.0f; | ||||||
|     } |     } | ||||||
|     // Doom and Bomberman seems to use the uninitialized registers and just enable blend |     // Doom and Bomberman seems to use the uninitialized registers and just enable blend | ||||||
|     // so initialize blend registers with sane values |     // so initialize blend registers with sane values | ||||||
|   | |||||||
| @@ -505,9 +505,9 @@ public: | |||||||
|  |  | ||||||
|                 INSERT_PADDING_WORDS(0x2E); |                 INSERT_PADDING_WORDS(0x2E); | ||||||
|  |  | ||||||
|                 RenderTargetConfig rt[NumRenderTargets]; |                 std::array<RenderTargetConfig, NumRenderTargets> rt; | ||||||
|  |  | ||||||
|                 struct { |                 struct ViewportTransform { | ||||||
|                     f32 scale_x; |                     f32 scale_x; | ||||||
|                     f32 scale_y; |                     f32 scale_y; | ||||||
|                     f32 scale_z; |                     f32 scale_z; | ||||||
| @@ -540,9 +540,11 @@ public: | |||||||
|                     s32 GetHeight() const { |                     s32 GetHeight() const { | ||||||
|                         return static_cast<s32>(translate_y + std::fabs(scale_y)) - GetY(); |                         return static_cast<s32>(translate_y + std::fabs(scale_y)) - GetY(); | ||||||
|                     } |                     } | ||||||
|                 } viewport_transform[NumViewports]; |                 }; | ||||||
|  |  | ||||||
|                 struct { |                 std::array<ViewportTransform, NumViewports> viewport_transform; | ||||||
|  |  | ||||||
|  |                 struct ViewPort { | ||||||
|                     union { |                     union { | ||||||
|                         BitField<0, 16, u32> x; |                         BitField<0, 16, u32> x; | ||||||
|                         BitField<16, 16, u32> width; |                         BitField<16, 16, u32> width; | ||||||
| @@ -553,7 +555,9 @@ public: | |||||||
|                     }; |                     }; | ||||||
|                     float depth_range_near; |                     float depth_range_near; | ||||||
|                     float depth_range_far; |                     float depth_range_far; | ||||||
|                 } viewport[NumViewports]; |                 }; | ||||||
|  |  | ||||||
|  |                 std::array<ViewPort, NumViewports> viewports; | ||||||
|  |  | ||||||
|                 INSERT_PADDING_WORDS(0x1D); |                 INSERT_PADDING_WORDS(0x1D); | ||||||
|  |  | ||||||
| @@ -571,7 +575,7 @@ public: | |||||||
|  |  | ||||||
|                 INSERT_PADDING_WORDS(0x17); |                 INSERT_PADDING_WORDS(0x17); | ||||||
|  |  | ||||||
|                 struct { |                 struct ScissorTest { | ||||||
|                     u32 enable; |                     u32 enable; | ||||||
|                     union { |                     union { | ||||||
|                         BitField<0, 16, u32> min_x; |                         BitField<0, 16, u32> min_x; | ||||||
| @@ -581,9 +585,11 @@ public: | |||||||
|                         BitField<0, 16, u32> min_y; |                         BitField<0, 16, u32> min_y; | ||||||
|                         BitField<16, 16, u32> max_y; |                         BitField<16, 16, u32> max_y; | ||||||
|                     }; |                     }; | ||||||
|                 } scissor_test; |                     u32 fill; | ||||||
|  |                 }; | ||||||
|  |                 std::array<ScissorTest, NumViewports> scissor_test; | ||||||
|  |  | ||||||
|                 INSERT_PADDING_WORDS(0x52); |                 INSERT_PADDING_WORDS(0x15); | ||||||
|  |  | ||||||
|                 s32 stencil_back_func_ref; |                 s32 stencil_back_func_ref; | ||||||
|                 u32 stencil_back_mask; |                 u32 stencil_back_mask; | ||||||
| @@ -1100,8 +1106,8 @@ private: | |||||||
| ASSERT_REG_POSITION(macros, 0x45); | ASSERT_REG_POSITION(macros, 0x45); | ||||||
| ASSERT_REG_POSITION(tfb_enabled, 0x1D1); | ASSERT_REG_POSITION(tfb_enabled, 0x1D1); | ||||||
| ASSERT_REG_POSITION(rt, 0x200); | ASSERT_REG_POSITION(rt, 0x200); | ||||||
| ASSERT_REG_POSITION(viewport_transform[0], 0x280); | ASSERT_REG_POSITION(viewport_transform, 0x280); | ||||||
| ASSERT_REG_POSITION(viewport, 0x300); | ASSERT_REG_POSITION(viewports, 0x300); | ||||||
| ASSERT_REG_POSITION(vertex_buffer, 0x35D); | ASSERT_REG_POSITION(vertex_buffer, 0x35D); | ||||||
| ASSERT_REG_POSITION(clear_color[0], 0x360); | ASSERT_REG_POSITION(clear_color[0], 0x360); | ||||||
| ASSERT_REG_POSITION(clear_depth, 0x364); | ASSERT_REG_POSITION(clear_depth, 0x364); | ||||||
|   | |||||||
| @@ -642,7 +642,7 @@ void RasterizerOpenGL::DrawArrays() { | |||||||
|     params.DispatchDraw(); |     params.DispatchDraw(); | ||||||
|  |  | ||||||
|     // Disable scissor test |     // Disable scissor test | ||||||
|     state.scissor.enabled = false; |     state.viewports[0].scissor.enabled = false; | ||||||
|  |  | ||||||
|     accelerate_draw = AccelDraw::Disabled; |     accelerate_draw = AccelDraw::Disabled; | ||||||
|  |  | ||||||
| @@ -923,15 +923,15 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, | |||||||
|  |  | ||||||
| void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { | void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { | ||||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||||
|     for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { |     for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { | ||||||
|         const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; |         const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; | ||||||
|         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 = static_cast<GLfloat>(viewport_rect.GetWidth()); | ||||||
|         viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight()); |         viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight()); | ||||||
|         viewport.depth_range_far = regs.viewport[i].depth_range_far; |         viewport.depth_range_far = regs.viewports[i].depth_range_far; | ||||||
|         viewport.depth_range_near = regs.viewport[i].depth_range_near; |         viewport.depth_range_near = regs.viewports[i].depth_range_near; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1079,7 +1079,6 @@ void RasterizerOpenGL::SyncBlendState() { | |||||||
| void RasterizerOpenGL::SyncLogicOpState() { | void RasterizerOpenGL::SyncLogicOpState() { | ||||||
|     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |     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; |     state.logic_op.enabled = regs.logic_op.enable != 0; | ||||||
|  |  | ||||||
|     if (!state.logic_op.enabled) |     if (!state.logic_op.enabled) | ||||||
| @@ -1092,19 +1091,21 @@ void RasterizerOpenGL::SyncLogicOpState() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void RasterizerOpenGL::SyncScissorTest() { | 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; |     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||||||
|     state.scissor.enabled = (regs.scissor_test.enable != 0); |     for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { | ||||||
|     if (regs.scissor_test.enable == 0) { |         const auto& src = regs.scissor_test[i]; | ||||||
|         return; |         auto& dst = 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; | ||||||
|     } |     } | ||||||
|     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; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void RasterizerOpenGL::SyncTransformFeedback() { | void RasterizerOpenGL::SyncTransformFeedback() { | ||||||
|   | |||||||
| @@ -67,6 +67,7 @@ public: | |||||||
|         glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fs); |         glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fs); | ||||||
|         state.draw.shader_program = 0; |         state.draw.shader_program = 0; | ||||||
|         state.draw.program_pipeline = pipeline.handle; |         state.draw.program_pipeline = pipeline.handle; | ||||||
|  |         state.geometry_shaders.enabled = (gs != 0); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| private: | private: | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ OpenGLState OpenGLState::cur_state; | |||||||
| bool OpenGLState::s_rgb_used; | bool OpenGLState::s_rgb_used; | ||||||
| OpenGLState::OpenGLState() { | OpenGLState::OpenGLState() { | ||||||
|     // These all match default OpenGL values |     // These all match default OpenGL values | ||||||
|  |     geometry_shaders.enabled = false; | ||||||
|     framebuffer_srgb.enabled = false; |     framebuffer_srgb.enabled = false; | ||||||
|     cull.enabled = false; |     cull.enabled = false; | ||||||
|     cull.mode = GL_BACK; |     cull.mode = GL_BACK; | ||||||
| @@ -50,12 +51,12 @@ OpenGLState::OpenGLState() { | |||||||
|         item.height = 0; |         item.height = 0; | ||||||
|         item.depth_range_near = 0.0f; |         item.depth_range_near = 0.0f; | ||||||
|         item.depth_range_far = 1.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) { |     for (auto& item : blend) { | ||||||
|         item.enabled = true; |         item.enabled = true; | ||||||
|         item.rgb_equation = GL_FUNC_ADD; |         item.rgb_equation = GL_FUNC_ADD; | ||||||
| @@ -136,7 +137,7 @@ void OpenGLState::ApplyCulling() const { | |||||||
| } | } | ||||||
|  |  | ||||||
| void OpenGLState::ApplyColorMask() 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++) { |         for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { | ||||||
|             const auto& updated = color_mask[i]; |             const auto& updated = color_mask[i]; | ||||||
|             const auto& current = cur_state.color_mask[i]; |             const auto& current = cur_state.color_mask[i]; | ||||||
| @@ -230,26 +231,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 { | void OpenGLState::ApplyViewport() const { | ||||||
|     if (GLAD_GL_ARB_viewport_array) { |     if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) { | ||||||
|         for (GLuint i = 0; |         for (GLuint i = 0; i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumViewports); | ||||||
|              i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); i++) { |              i++) { | ||||||
|             const auto& current = cur_state.viewports[i]; |             const auto& current = cur_state.viewports[i]; | ||||||
|             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 || | ||||||
| @@ -260,6 +245,22 @@ void OpenGLState::ApplyViewport() const { | |||||||
|                 updated.depth_range_far != current.depth_range_far) { |                 updated.depth_range_far != current.depth_range_far) { | ||||||
|                 glDepthRangeIndexed(i, updated.depth_range_near, updated.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 { |     } else { | ||||||
|         const auto& current = cur_state.viewports[0]; |         const auto& current = cur_state.viewports[0]; | ||||||
| @@ -273,6 +274,21 @@ void OpenGLState::ApplyViewport() const { | |||||||
|             updated.depth_range_far != current.depth_range_far) { |             updated.depth_range_far != current.depth_range_far) { | ||||||
|             glDepthRange(updated.depth_range_near, updated.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); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -483,7 +499,6 @@ void OpenGLState::Apply() const { | |||||||
|     } |     } | ||||||
|     ApplyColorMask(); |     ApplyColorMask(); | ||||||
|     ApplyViewport(); |     ApplyViewport(); | ||||||
|     ApplyScissor(); |  | ||||||
|     ApplyStencilTest(); |     ApplyStencilTest(); | ||||||
|     ApplySRgb(); |     ApplySRgb(); | ||||||
|     ApplyCulling(); |     ApplyCulling(); | ||||||
|   | |||||||
| @@ -39,6 +39,10 @@ public: | |||||||
|         bool enabled; // GL_FRAMEBUFFER_SRGB |         bool enabled; // GL_FRAMEBUFFER_SRGB | ||||||
|     } framebuffer_srgb; |     } framebuffer_srgb; | ||||||
|  |  | ||||||
|  |     struct { | ||||||
|  |         bool enabled; // viewports arrays are only supported when geometry shaders are enabled. | ||||||
|  |     } geometry_shaders; | ||||||
|  |  | ||||||
|     struct { |     struct { | ||||||
|         bool enabled;      // GL_CULL_FACE |         bool enabled;      // GL_CULL_FACE | ||||||
|         GLenum mode;       // GL_CULL_FACE_MODE |         GLenum mode;       // GL_CULL_FACE_MODE | ||||||
| @@ -150,16 +154,15 @@ public: | |||||||
|         GLfloat height; |         GLfloat 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 { | ||||||
|  |             bool enabled; // GL_SCISSOR_TEST | ||||||
|  |             GLint x; | ||||||
|  |             GLint y; | ||||||
|  |             GLsizei width; | ||||||
|  |             GLsizei height; | ||||||
|  |         } scissor; | ||||||
|     }; |     }; | ||||||
|     std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> viewports; |     std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports; | ||||||
|  |  | ||||||
|     struct { |  | ||||||
|         bool enabled; // GL_SCISSOR_TEST |  | ||||||
|         GLint x; |  | ||||||
|         GLint y; |  | ||||||
|         GLsizei width; |  | ||||||
|         GLsizei height; |  | ||||||
|     } scissor; |  | ||||||
|  |  | ||||||
|     struct { |     struct { | ||||||
|         float size; // GL_POINT_SIZE |         float size; // GL_POINT_SIZE | ||||||
| @@ -214,7 +217,6 @@ private: | |||||||
|     void ApplyLogicOp() const; |     void ApplyLogicOp() const; | ||||||
|     void ApplyTextures() const; |     void ApplyTextures() const; | ||||||
|     void ApplySamplers() const; |     void ApplySamplers() const; | ||||||
|     void ApplyScissor() const; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace OpenGL | } // namespace OpenGL | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user