Add support for clear_flags register

This commit is contained in:
Rodolfo Bogado 2018-11-21 00:40:32 -03:00
parent 69b3f98d3a
commit 54c2a4cafc
5 changed files with 95 additions and 28 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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();

View file

@ -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) {

View file

@ -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;