forked from suyu/suyu
Add support to color mask to avoid issues in blending caused by wrong values in the alpha channel in some render targets.
This commit is contained in:
parent
145ae36963
commit
19038db489
5 changed files with 79 additions and 25 deletions
|
@ -462,6 +462,16 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ColorMask {
|
||||||
|
union {
|
||||||
|
u32 raw;
|
||||||
|
BitField<0, 4, u32> R;
|
||||||
|
BitField<4, 4, u32> G;
|
||||||
|
BitField<8, 4, u32> B;
|
||||||
|
BitField<12, 4, u32> A;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
bool IsShaderConfigEnabled(std::size_t index) const {
|
bool IsShaderConfigEnabled(std::size_t index) const {
|
||||||
// The VertexB is always enabled.
|
// The VertexB is always enabled.
|
||||||
if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) {
|
if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) {
|
||||||
|
@ -571,7 +581,11 @@ public:
|
||||||
u32 stencil_back_mask;
|
u32 stencil_back_mask;
|
||||||
u32 stencil_back_func_mask;
|
u32 stencil_back_func_mask;
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0x13);
|
INSERT_PADDING_WORDS(0xC);
|
||||||
|
|
||||||
|
u32 color_mask_common;
|
||||||
|
|
||||||
|
INSERT_PADDING_WORDS(0x6);
|
||||||
|
|
||||||
u32 rt_separate_frag_data;
|
u32 rt_separate_frag_data;
|
||||||
|
|
||||||
|
@ -847,8 +861,9 @@ public:
|
||||||
BitField<6, 4, u32> RT;
|
BitField<6, 4, u32> RT;
|
||||||
BitField<10, 11, u32> layer;
|
BitField<10, 11, u32> layer;
|
||||||
} clear_buffers;
|
} clear_buffers;
|
||||||
|
INSERT_PADDING_WORDS(0xB);
|
||||||
INSERT_PADDING_WORDS(0x4B);
|
std::array<ColorMask, NumRenderTargets> color_mask;
|
||||||
|
INSERT_PADDING_WORDS(0x38);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u32 query_address_high;
|
u32 query_address_high;
|
||||||
|
@ -1081,6 +1096,7 @@ ASSERT_REG_POSITION(scissor_test, 0x380);
|
||||||
ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
|
ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
|
||||||
ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
|
ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
|
||||||
ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
|
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(rt_separate_frag_data, 0x3EB);
|
||||||
ASSERT_REG_POSITION(zeta, 0x3F8);
|
ASSERT_REG_POSITION(zeta, 0x3F8);
|
||||||
ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
|
ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
|
||||||
|
@ -1127,6 +1143,7 @@ ASSERT_REG_POSITION(instanced_arrays, 0x620);
|
||||||
ASSERT_REG_POSITION(cull, 0x646);
|
ASSERT_REG_POSITION(cull, 0x646);
|
||||||
ASSERT_REG_POSITION(logic_op, 0x671);
|
ASSERT_REG_POSITION(logic_op, 0x671);
|
||||||
ASSERT_REG_POSITION(clear_buffers, 0x674);
|
ASSERT_REG_POSITION(clear_buffers, 0x674);
|
||||||
|
ASSERT_REG_POSITION(color_mask, 0x680);
|
||||||
ASSERT_REG_POSITION(query, 0x6C0);
|
ASSERT_REG_POSITION(query, 0x6C0);
|
||||||
ASSERT_REG_POSITION(vertex_array[0], 0x700);
|
ASSERT_REG_POSITION(vertex_array[0], 0x700);
|
||||||
ASSERT_REG_POSITION(independent_blend, 0x780);
|
ASSERT_REG_POSITION(independent_blend, 0x780);
|
||||||
|
|
|
@ -511,10 +511,10 @@ void RasterizerOpenGL::Clear() {
|
||||||
|
|
||||||
OpenGLState clear_state;
|
OpenGLState clear_state;
|
||||||
clear_state.draw.draw_framebuffer = framebuffer.handle;
|
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[0].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[0].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[0].blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE;
|
||||||
clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE;
|
clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE;
|
||||||
|
|
||||||
if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
|
if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
|
||||||
regs.clear_buffers.A) {
|
regs.clear_buffers.A) {
|
||||||
|
@ -573,7 +573,7 @@ void RasterizerOpenGL::DrawArrays() {
|
||||||
ScopeAcquireGLContext acquire_context{emu_window};
|
ScopeAcquireGLContext acquire_context{emu_window};
|
||||||
|
|
||||||
ConfigureFramebuffers();
|
ConfigureFramebuffers();
|
||||||
|
SyncColorMask();
|
||||||
SyncDepthTestState();
|
SyncDepthTestState();
|
||||||
SyncStencilTestState();
|
SyncStencilTestState();
|
||||||
SyncBlendState();
|
SyncBlendState();
|
||||||
|
@ -989,6 +989,18 @@ void RasterizerOpenGL::SyncStencilTestState() {
|
||||||
state.stencil.back.write_mask = regs.stencil_back_mask;
|
state.stencil.back.write_mask = regs.stencil_back_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::SyncColorMask() {
|
||||||
|
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||||
|
for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; 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::SyncBlendState() {
|
||||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||||
|
|
||||||
|
@ -1000,6 +1012,7 @@ void RasterizerOpenGL::SyncBlendState() {
|
||||||
state.independant_blend.enabled = regs.independent_blend_enable;
|
state.independant_blend.enabled = regs.independent_blend_enable;
|
||||||
if (!state.independant_blend.enabled) {
|
if (!state.independant_blend.enabled) {
|
||||||
auto& blend = state.blend[0];
|
auto& blend = state.blend[0];
|
||||||
|
blend.enabled = regs.blend.enable[0] != 0;
|
||||||
blend.separate_alpha = regs.blend.separate_alpha;
|
blend.separate_alpha = regs.blend.separate_alpha;
|
||||||
blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb);
|
blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb);
|
||||||
blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb);
|
blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb);
|
||||||
|
|
|
@ -169,6 +169,9 @@ private:
|
||||||
/// Syncs the point state to match the guest state
|
/// Syncs the point state to match the guest state
|
||||||
void SyncPointState();
|
void SyncPointState();
|
||||||
|
|
||||||
|
/// Syncs Color Mask
|
||||||
|
void SyncColorMask();
|
||||||
|
|
||||||
/// Check asserts for alpha testing.
|
/// Check asserts for alpha testing.
|
||||||
void CheckAlphaTests();
|
void CheckAlphaTests();
|
||||||
|
|
||||||
|
|
|
@ -25,12 +25,12 @@ OpenGLState::OpenGLState() {
|
||||||
|
|
||||||
primitive_restart.enabled = false;
|
primitive_restart.enabled = false;
|
||||||
primitive_restart.index = 0;
|
primitive_restart.index = 0;
|
||||||
|
for (auto& item : color_mask) {
|
||||||
color_mask.red_enabled = GL_TRUE;
|
item.red_enabled = GL_TRUE;
|
||||||
color_mask.green_enabled = GL_TRUE;
|
item.green_enabled = GL_TRUE;
|
||||||
color_mask.blue_enabled = GL_TRUE;
|
item.blue_enabled = GL_TRUE;
|
||||||
color_mask.alpha_enabled = GL_TRUE;
|
item.alpha_enabled = GL_TRUE;
|
||||||
|
}
|
||||||
stencil.test_enabled = false;
|
stencil.test_enabled = false;
|
||||||
auto reset_stencil = [](auto& config) {
|
auto reset_stencil = [](auto& config) {
|
||||||
config.test_func = GL_ALWAYS;
|
config.test_func = GL_ALWAYS;
|
||||||
|
@ -135,6 +135,32 @@ void OpenGLState::ApplyCulling() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLState::ApplyColorMask() const {
|
||||||
|
if (GLAD_GL_ARB_viewport_array) {
|
||||||
|
for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
|
||||||
|
const auto& updated = color_mask[i];
|
||||||
|
const auto& current = cur_state.color_mask[i];
|
||||||
|
if (updated.red_enabled != current.red_enabled ||
|
||||||
|
updated.green_enabled != current.green_enabled ||
|
||||||
|
updated.blue_enabled != current.blue_enabled ||
|
||||||
|
updated.alpha_enabled != current.alpha_enabled) {
|
||||||
|
glColorMaski(static_cast<GLuint>(i), updated.red_enabled, updated.green_enabled,
|
||||||
|
updated.blue_enabled, updated.alpha_enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const auto& updated = color_mask[0];
|
||||||
|
const auto& current = cur_state.color_mask[0];
|
||||||
|
if (updated.red_enabled != current.red_enabled ||
|
||||||
|
updated.green_enabled != current.green_enabled ||
|
||||||
|
updated.blue_enabled != current.blue_enabled ||
|
||||||
|
updated.alpha_enabled != current.alpha_enabled) {
|
||||||
|
glColorMask(updated.red_enabled, updated.green_enabled, updated.blue_enabled,
|
||||||
|
updated.alpha_enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLState::ApplyDepth() const {
|
void OpenGLState::ApplyDepth() const {
|
||||||
// Depth test
|
// Depth test
|
||||||
const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled;
|
const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled;
|
||||||
|
@ -444,18 +470,11 @@ void OpenGLState::Apply() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Color mask
|
|
||||||
if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
|
|
||||||
color_mask.green_enabled != cur_state.color_mask.green_enabled ||
|
|
||||||
color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
|
|
||||||
color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
|
|
||||||
glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled,
|
|
||||||
color_mask.alpha_enabled);
|
|
||||||
}
|
|
||||||
// Point
|
// Point
|
||||||
if (point.size != cur_state.point.size) {
|
if (point.size != cur_state.point.size) {
|
||||||
glPointSize(point.size);
|
glPointSize(point.size);
|
||||||
}
|
}
|
||||||
|
ApplyColorMask();
|
||||||
ApplyViewport();
|
ApplyViewport();
|
||||||
ApplyScissor();
|
ApplyScissor();
|
||||||
ApplyStencilTest();
|
ApplyStencilTest();
|
||||||
|
|
|
@ -56,13 +56,14 @@ public:
|
||||||
GLuint index;
|
GLuint index;
|
||||||
} primitive_restart; // GL_PRIMITIVE_RESTART
|
} primitive_restart; // GL_PRIMITIVE_RESTART
|
||||||
|
|
||||||
struct {
|
struct ColorMask {
|
||||||
GLboolean red_enabled;
|
GLboolean red_enabled;
|
||||||
GLboolean green_enabled;
|
GLboolean green_enabled;
|
||||||
GLboolean blue_enabled;
|
GLboolean blue_enabled;
|
||||||
GLboolean alpha_enabled;
|
GLboolean alpha_enabled;
|
||||||
} color_mask; // GL_COLOR_WRITEMASK
|
};
|
||||||
|
std::array<ColorMask, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets>
|
||||||
|
color_mask; // GL_COLOR_WRITEMASK
|
||||||
struct {
|
struct {
|
||||||
bool test_enabled; // GL_STENCIL_TEST
|
bool test_enabled; // GL_STENCIL_TEST
|
||||||
struct {
|
struct {
|
||||||
|
@ -198,6 +199,7 @@ private:
|
||||||
static bool s_rgb_used;
|
static bool s_rgb_used;
|
||||||
void ApplySRgb() const;
|
void ApplySRgb() const;
|
||||||
void ApplyCulling() const;
|
void ApplyCulling() const;
|
||||||
|
void ApplyColorMask() const;
|
||||||
void ApplyDepth() const;
|
void ApplyDepth() const;
|
||||||
void ApplyPrimitiveRestart() const;
|
void ApplyPrimitiveRestart() const;
|
||||||
void ApplyStencilTest() const;
|
void ApplyStencilTest() const;
|
||||||
|
|
Loading…
Reference in a new issue