forked from suyu/suyu
Merge pull request #1470 from FernandoS27/alpha_testing
Implemented Alpha Test using Shader Emulation
This commit is contained in:
commit
75d807788c
7 changed files with 87 additions and 20 deletions
|
@ -643,8 +643,10 @@ public:
|
||||||
u32 d3d_cull_mode;
|
u32 d3d_cull_mode;
|
||||||
|
|
||||||
ComparisonOp depth_test_func;
|
ComparisonOp depth_test_func;
|
||||||
|
float alpha_test_ref;
|
||||||
|
ComparisonOp alpha_test_func;
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0xB);
|
INSERT_PADDING_WORDS(0x9);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u32 separate_alpha;
|
u32 separate_alpha;
|
||||||
|
|
|
@ -570,10 +570,11 @@ void RasterizerOpenGL::DrawArrays() {
|
||||||
SyncBlendState();
|
SyncBlendState();
|
||||||
SyncLogicOpState();
|
SyncLogicOpState();
|
||||||
SyncCullMode();
|
SyncCullMode();
|
||||||
SyncAlphaTest();
|
|
||||||
SyncScissorTest();
|
SyncScissorTest();
|
||||||
|
// Alpha Testing is synced on shaders.
|
||||||
SyncTransformFeedback();
|
SyncTransformFeedback();
|
||||||
SyncPointState();
|
SyncPointState();
|
||||||
|
CheckAlphaTests();
|
||||||
|
|
||||||
// TODO(bunnei): Sync framebuffer_scale uniform here
|
// TODO(bunnei): Sync framebuffer_scale uniform here
|
||||||
// TODO(bunnei): Sync scissorbox uniform(s) here
|
// TODO(bunnei): Sync scissorbox uniform(s) here
|
||||||
|
@ -1007,17 +1008,6 @@ 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::SyncAlphaTest() {
|
|
||||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
|
||||||
|
|
||||||
// TODO(Rodrigo): Alpha testing is a legacy OpenGL feature, but it can be
|
|
||||||
// implemented with a test+discard in fragment shaders.
|
|
||||||
if (regs.alpha_test_enabled != 0) {
|
|
||||||
LOG_CRITICAL(Render_OpenGL, "Alpha testing is not implemented");
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncScissorTest() {
|
void RasterizerOpenGL::SyncScissorTest() {
|
||||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||||
|
|
||||||
|
@ -1052,4 +1042,15 @@ void RasterizerOpenGL::SyncPointState() {
|
||||||
state.point.size = regs.point_size == 0 ? 1 : regs.point_size;
|
state.point.size = regs.point_size == 0 ? 1 : regs.point_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::CheckAlphaTests() {
|
||||||
|
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||||
|
|
||||||
|
if (regs.alpha_test_enabled != 0 && regs.rt_control.count > 1) {
|
||||||
|
LOG_CRITICAL(
|
||||||
|
Render_OpenGL,
|
||||||
|
"Alpha Testing is enabled with Multiple Render Targets, this behavior is undefined.");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -162,9 +162,6 @@ private:
|
||||||
/// Syncs the LogicOp state to match the guest state
|
/// Syncs the LogicOp state to match the guest state
|
||||||
void SyncLogicOpState();
|
void SyncLogicOpState();
|
||||||
|
|
||||||
/// Syncs the alpha test state to match the guest state
|
|
||||||
void SyncAlphaTest();
|
|
||||||
|
|
||||||
/// Syncs the scissor test state to match the guest state
|
/// Syncs the scissor test state to match the guest state
|
||||||
void SyncScissorTest();
|
void SyncScissorTest();
|
||||||
|
|
||||||
|
@ -174,6 +171,9 @@ private:
|
||||||
/// Syncs the point state to match the guest state
|
/// Syncs the point state to match the guest state
|
||||||
void SyncPointState();
|
void SyncPointState();
|
||||||
|
|
||||||
|
/// Check asserts for alpha testing.
|
||||||
|
void CheckAlphaTests();
|
||||||
|
|
||||||
bool has_ARB_direct_state_access = false;
|
bool has_ARB_direct_state_access = false;
|
||||||
bool has_ARB_multi_bind = false;
|
bool has_ARB_multi_bind = false;
|
||||||
bool has_ARB_separate_shader_objects = false;
|
bool has_ARB_separate_shader_objects = false;
|
||||||
|
|
|
@ -1266,9 +1266,29 @@ private:
|
||||||
|
|
||||||
ASSERT_MSG(header.ps.omap.sample_mask == 0, "Samplemask write is unimplemented");
|
ASSERT_MSG(header.ps.omap.sample_mask == 0, "Samplemask write is unimplemented");
|
||||||
|
|
||||||
|
shader.AddLine("if (alpha_test[0] != 0) {");
|
||||||
|
++shader.scope;
|
||||||
|
// We start on the register containing the alpha value in the first RT.
|
||||||
|
u32 current_reg = 3;
|
||||||
|
for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets;
|
||||||
|
++render_target) {
|
||||||
|
// TODO(Blinkhawk): verify the behavior of alpha testing on hardware when
|
||||||
|
// multiple render targets are used.
|
||||||
|
if (header.ps.IsColorComponentOutputEnabled(render_target, 0) ||
|
||||||
|
header.ps.IsColorComponentOutputEnabled(render_target, 1) ||
|
||||||
|
header.ps.IsColorComponentOutputEnabled(render_target, 2) ||
|
||||||
|
header.ps.IsColorComponentOutputEnabled(render_target, 3)) {
|
||||||
|
shader.AddLine(fmt::format("if (!AlphaFunc({})) discard;",
|
||||||
|
regs.GetRegisterAsFloat(current_reg)));
|
||||||
|
current_reg += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--shader.scope;
|
||||||
|
shader.AddLine('}');
|
||||||
|
|
||||||
// Write the color outputs using the data in the shader registers, disabled
|
// Write the color outputs using the data in the shader registers, disabled
|
||||||
// rendertargets/components are skipped in the register assignment.
|
// rendertargets/components are skipped in the register assignment.
|
||||||
u32 current_reg = 0;
|
current_reg = 0;
|
||||||
for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets;
|
for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets;
|
||||||
++render_target) {
|
++render_target) {
|
||||||
// TODO(Subv): Figure out how dual-source blending is configured in the Switch.
|
// TODO(Subv): Figure out how dual-source blending is configured in the Switch.
|
||||||
|
@ -3516,7 +3536,7 @@ private:
|
||||||
|
|
||||||
// Declarations
|
// Declarations
|
||||||
std::set<std::string> declr_predicates;
|
std::set<std::string> declr_predicates;
|
||||||
}; // namespace Decompiler
|
}; // namespace OpenGL::GLShader::Decompiler
|
||||||
|
|
||||||
std::string GetCommonDeclarations() {
|
std::string GetCommonDeclarations() {
|
||||||
return fmt::format("#define MAX_CONSTBUFFER_ELEMENTS {}\n",
|
return fmt::format("#define MAX_CONSTBUFFER_ELEMENTS {}\n",
|
||||||
|
|
|
@ -29,6 +29,7 @@ layout(std140) uniform vs_config {
|
||||||
vec4 viewport_flip;
|
vec4 viewport_flip;
|
||||||
uvec4 instance_id;
|
uvec4 instance_id;
|
||||||
uvec4 flip_stage;
|
uvec4 flip_stage;
|
||||||
|
uvec4 alpha_test;
|
||||||
};
|
};
|
||||||
)";
|
)";
|
||||||
|
|
||||||
|
@ -105,6 +106,7 @@ layout (std140) uniform gs_config {
|
||||||
vec4 viewport_flip;
|
vec4 viewport_flip;
|
||||||
uvec4 instance_id;
|
uvec4 instance_id;
|
||||||
uvec4 flip_stage;
|
uvec4 flip_stage;
|
||||||
|
uvec4 alpha_test;
|
||||||
};
|
};
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
@ -142,8 +144,33 @@ layout (std140) uniform fs_config {
|
||||||
vec4 viewport_flip;
|
vec4 viewport_flip;
|
||||||
uvec4 instance_id;
|
uvec4 instance_id;
|
||||||
uvec4 flip_stage;
|
uvec4 flip_stage;
|
||||||
|
uvec4 alpha_test;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool AlphaFunc(in float value) {
|
||||||
|
float ref = uintBitsToFloat(alpha_test[2]);
|
||||||
|
switch (alpha_test[1]) {
|
||||||
|
case 1:
|
||||||
|
return false;
|
||||||
|
case 2:
|
||||||
|
return value < ref;
|
||||||
|
case 3:
|
||||||
|
return value == ref;
|
||||||
|
case 4:
|
||||||
|
return value <= ref;
|
||||||
|
case 5:
|
||||||
|
return value > ref;
|
||||||
|
case 6:
|
||||||
|
return value != ref;
|
||||||
|
case 7:
|
||||||
|
return value >= ref;
|
||||||
|
case 8:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
exec_fragment();
|
exec_fragment();
|
||||||
}
|
}
|
||||||
|
@ -152,4 +179,4 @@ void main() {
|
||||||
out += program.first;
|
out += program.first;
|
||||||
return {out, program.second};
|
return {out, program.second};
|
||||||
}
|
}
|
||||||
} // namespace OpenGL::GLShader
|
} // namespace OpenGL::GLShader
|
||||||
|
|
|
@ -16,6 +16,17 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh
|
||||||
viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f;
|
viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f;
|
||||||
viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0f : 1.0f;
|
viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0f : 1.0f;
|
||||||
|
|
||||||
|
u32 func = static_cast<u32>(regs.alpha_test_func);
|
||||||
|
// Normalize the gl variants of opCompare to be the same as the normal variants
|
||||||
|
u32 op_gl_variant_base = static_cast<u32>(Tegra::Engines::Maxwell3D::Regs::ComparisonOp::Never);
|
||||||
|
if (func >= op_gl_variant_base) {
|
||||||
|
func = func - op_gl_variant_base + 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
alpha_test.enabled = regs.alpha_test_enabled;
|
||||||
|
alpha_test.func = func;
|
||||||
|
alpha_test.ref = regs.alpha_test_ref;
|
||||||
|
|
||||||
// We only assign the instance to the first component of the vector, the rest is just padding.
|
// We only assign the instance to the first component of the vector, the rest is just padding.
|
||||||
instance_id[0] = state.current_instance;
|
instance_id[0] = state.current_instance;
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,14 @@ struct MaxwellUniformData {
|
||||||
alignas(16) GLvec4 viewport_flip;
|
alignas(16) GLvec4 viewport_flip;
|
||||||
alignas(16) GLuvec4 instance_id;
|
alignas(16) GLuvec4 instance_id;
|
||||||
alignas(16) GLuvec4 flip_stage;
|
alignas(16) GLuvec4 flip_stage;
|
||||||
|
struct alignas(16) {
|
||||||
|
GLuint enabled;
|
||||||
|
GLuint func;
|
||||||
|
GLfloat ref;
|
||||||
|
GLuint padding;
|
||||||
|
} alpha_test;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(MaxwellUniformData) == 48, "MaxwellUniformData structure size is incorrect");
|
static_assert(sizeof(MaxwellUniformData) == 64, "MaxwellUniformData structure size is incorrect");
|
||||||
static_assert(sizeof(MaxwellUniformData) < 16384,
|
static_assert(sizeof(MaxwellUniformData) < 16384,
|
||||||
"MaxwellUniformData structure must be less than 16kb as per the OpenGL spec");
|
"MaxwellUniformData structure must be less than 16kb as per the OpenGL spec");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue