mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-27 09:12:46 +01:00
Add support for clear_flags register
This commit is contained in:
parent
69b3f98d3a
commit
54c2a4cafc
5 changed files with 95 additions and 28 deletions
|
@ -631,7 +631,16 @@ public:
|
||||||
}
|
}
|
||||||
} zeta;
|
} 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;
|
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(color_mask_common, 0x3E4);
|
||||||
ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
|
ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
|
||||||
ASSERT_REG_POSITION(zeta, 0x3F8);
|
ASSERT_REG_POSITION(zeta, 0x3F8);
|
||||||
|
ASSERT_REG_POSITION(clear_flags, 0x43E);
|
||||||
ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
|
ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
|
||||||
ASSERT_REG_POSITION(rt_control, 0x487);
|
ASSERT_REG_POSITION(rt_control, 0x487);
|
||||||
ASSERT_REG_POSITION(zeta_width, 0x48a);
|
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!");
|
ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!");
|
||||||
use_stencil = true;
|
use_stencil = true;
|
||||||
clear_state.stencil.test_enabled = 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) {
|
if (!use_color && !use_depth && !use_stencil) {
|
||||||
|
@ -553,6 +577,14 @@ void RasterizerOpenGL::Clear() {
|
||||||
|
|
||||||
ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false,
|
ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false,
|
||||||
regs.clear_buffers.RT.Value());
|
regs.clear_buffers.RT.Value());
|
||||||
|
if (regs.clear_flags.scissor) {
|
||||||
|
SyncScissorTest(clear_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regs.clear_flags.viewport) {
|
||||||
|
clear_state.EmulateViewportWithScissor();
|
||||||
|
}
|
||||||
|
|
||||||
clear_state.Apply();
|
clear_state.Apply();
|
||||||
|
|
||||||
if (use_color) {
|
if (use_color) {
|
||||||
|
@ -588,7 +620,7 @@ void RasterizerOpenGL::DrawArrays() {
|
||||||
SyncLogicOpState();
|
SyncLogicOpState();
|
||||||
SyncCullMode();
|
SyncCullMode();
|
||||||
SyncPrimitiveRestart();
|
SyncPrimitiveRestart();
|
||||||
SyncScissorTest();
|
SyncScissorTest(state);
|
||||||
// Alpha Testing is synced on shaders.
|
// Alpha Testing is synced on shaders.
|
||||||
SyncTransformFeedback();
|
SyncTransformFeedback();
|
||||||
SyncPointState();
|
SyncPointState();
|
||||||
|
@ -815,7 +847,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
|
||||||
}
|
}
|
||||||
const u32 bias = config.mip_lod_bias.Value();
|
const u32 bias = config.mip_lod_bias.Value();
|
||||||
// Sign extend the 13-bit 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;
|
const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f;
|
||||||
if (lod_bias != bias_lod) {
|
if (lod_bias != bias_lod) {
|
||||||
lod_bias = bias_lod;
|
lod_bias = bias_lod;
|
||||||
|
@ -947,8 +979,8 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
|
||||||
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 = viewport_rect.GetWidth();
|
||||||
viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight());
|
viewport.height = viewport_rect.GetHeight();
|
||||||
viewport.depth_range_far = regs.viewports[i].depth_range_far;
|
viewport.depth_range_far = regs.viewports[i].depth_range_far;
|
||||||
viewport.depth_range_near = regs.viewports[i].depth_range_near;
|
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);
|
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;
|
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||||
for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) {
|
for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) {
|
||||||
const auto& src = regs.scissor_test[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);
|
dst.enabled = (src.enable != 0);
|
||||||
if (dst.enabled == 0) {
|
if (dst.enabled == 0) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -91,19 +91,20 @@ private:
|
||||||
void SyncWithConfig(const Tegra::Texture::TSCEntry& info);
|
void SyncWithConfig(const Tegra::Texture::TSCEntry& info);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Tegra::Texture::TextureFilter mag_filter;
|
Tegra::Texture::TextureFilter mag_filter = Tegra::Texture::TextureFilter::Nearest;
|
||||||
Tegra::Texture::TextureFilter min_filter;
|
Tegra::Texture::TextureFilter min_filter = Tegra::Texture::TextureFilter::Nearest;
|
||||||
Tegra::Texture::TextureMipmapFilter mip_filter;
|
Tegra::Texture::TextureMipmapFilter mip_filter = Tegra::Texture::TextureMipmapFilter::None;
|
||||||
Tegra::Texture::WrapMode wrap_u;
|
Tegra::Texture::WrapMode wrap_u = Tegra::Texture::WrapMode::ClampToEdge;
|
||||||
Tegra::Texture::WrapMode wrap_v;
|
Tegra::Texture::WrapMode wrap_v = Tegra::Texture::WrapMode::ClampToEdge;
|
||||||
Tegra::Texture::WrapMode wrap_p;
|
Tegra::Texture::WrapMode wrap_p = Tegra::Texture::WrapMode::ClampToEdge;
|
||||||
bool uses_depth_compare;
|
bool uses_depth_compare = false;
|
||||||
Tegra::Texture::DepthCompareFunc depth_compare_func;
|
Tegra::Texture::DepthCompareFunc depth_compare_func =
|
||||||
GLvec4 border_color;
|
Tegra::Texture::DepthCompareFunc::Always;
|
||||||
float min_lod;
|
GLvec4 border_color = {};
|
||||||
float max_lod;
|
float min_lod = 0.0f;
|
||||||
float lod_bias;
|
float max_lod = 16.0f;
|
||||||
float max_anisotropic;
|
float lod_bias = 0.0f;
|
||||||
|
float max_anisotropic = 1.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -171,7 +172,7 @@ private:
|
||||||
void SyncMultiSampleState();
|
void SyncMultiSampleState();
|
||||||
|
|
||||||
/// Syncs the scissor test state to match the guest state
|
/// 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
|
/// Syncs the transform feedback state to match the guest state
|
||||||
void SyncTransformFeedback();
|
void SyncTransformFeedback();
|
||||||
|
|
|
@ -233,6 +233,28 @@ void OpenGLState::ApplyStencilTest() const {
|
||||||
config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
|
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 {
|
void OpenGLState::ApplyViewport() const {
|
||||||
if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) {
|
if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) {
|
||||||
|
@ -242,7 +264,9 @@ void OpenGLState::ApplyViewport() const {
|
||||||
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 ||
|
||||||
updated.width != current.width || updated.height != current.height) {
|
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 ||
|
if (updated.depth_range_near != current.depth_range_near ||
|
||||||
updated.depth_range_far != current.depth_range_far) {
|
updated.depth_range_far != current.depth_range_far) {
|
||||||
|
@ -270,8 +294,7 @@ void OpenGLState::ApplyViewport() const {
|
||||||
const auto& updated = viewports[0];
|
const auto& updated = viewports[0];
|
||||||
if (updated.x != current.x || updated.y != current.y || updated.width != current.width ||
|
if (updated.x != current.x || updated.y != current.y || updated.width != current.width ||
|
||||||
updated.height != current.height) {
|
updated.height != current.height) {
|
||||||
glViewport(static_cast<GLint>(updated.x), static_cast<GLint>(updated.y),
|
glViewport(updated.x, updated.y, updated.width, updated.height);
|
||||||
static_cast<GLsizei>(updated.width), static_cast<GLsizei>(updated.height));
|
|
||||||
}
|
}
|
||||||
if (updated.depth_range_near != current.depth_range_near ||
|
if (updated.depth_range_near != current.depth_range_near ||
|
||||||
updated.depth_range_far != current.depth_range_far) {
|
updated.depth_range_far != current.depth_range_far) {
|
||||||
|
|
|
@ -156,10 +156,10 @@ public:
|
||||||
} draw;
|
} draw;
|
||||||
|
|
||||||
struct viewport {
|
struct viewport {
|
||||||
GLfloat x;
|
GLint x;
|
||||||
GLfloat y;
|
GLint y;
|
||||||
GLfloat width;
|
GLint width;
|
||||||
GLfloat height;
|
GLint 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 {
|
struct {
|
||||||
|
@ -206,6 +206,7 @@ public:
|
||||||
OpenGLState& ResetBuffer(GLuint handle);
|
OpenGLState& ResetBuffer(GLuint handle);
|
||||||
OpenGLState& ResetVertexArray(GLuint handle);
|
OpenGLState& ResetVertexArray(GLuint handle);
|
||||||
OpenGLState& ResetFramebuffer(GLuint handle);
|
OpenGLState& ResetFramebuffer(GLuint handle);
|
||||||
|
void EmulateViewportWithScissor();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static OpenGLState cur_state;
|
static OpenGLState cur_state;
|
||||||
|
|
Loading…
Reference in a new issue