Merge pull request #1785 from Tinob/master
Add support for clear_flags register
This commit is contained in:
		@@ -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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user