gl_rasterizer: Move alpha testing to the OpenGL pipeline
Removes the alpha testing code from each fragment shader invocation.
This commit is contained in:
parent
df509486c4
commit
b76df62c00
8 changed files with 33 additions and 71 deletions
|
@ -663,13 +663,10 @@ void RasterizerOpenGL::DrawArrays() {
|
||||||
SyncCullMode();
|
SyncCullMode();
|
||||||
SyncPrimitiveRestart();
|
SyncPrimitiveRestart();
|
||||||
SyncScissorTest(state);
|
SyncScissorTest(state);
|
||||||
// Alpha Testing is synced on shaders.
|
|
||||||
SyncTransformFeedback();
|
SyncTransformFeedback();
|
||||||
SyncPointState();
|
SyncPointState();
|
||||||
CheckAlphaTests();
|
|
||||||
SyncPolygonOffset();
|
SyncPolygonOffset();
|
||||||
// TODO(bunnei): Sync framebuffer_scale uniform here
|
SyncAlphaTest();
|
||||||
// TODO(bunnei): Sync scissorbox uniform(s) here
|
|
||||||
|
|
||||||
// Draw the vertex batch
|
// Draw the vertex batch
|
||||||
const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
|
const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
|
||||||
|
@ -1121,10 +1118,17 @@ void RasterizerOpenGL::SyncPolygonOffset() {
|
||||||
state.polygon_offset.clamp = regs.polygon_offset_clamp;
|
state.polygon_offset.clamp = regs.polygon_offset_clamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::CheckAlphaTests() {
|
void RasterizerOpenGL::SyncAlphaTest() {
|
||||||
const auto& regs = system.GPU().Maxwell3D().regs;
|
const auto& regs = system.GPU().Maxwell3D().regs;
|
||||||
UNIMPLEMENTED_IF_MSG(regs.alpha_test_enabled != 0 && regs.rt_control.count > 1,
|
UNIMPLEMENTED_IF_MSG(regs.alpha_test_enabled != 0 && regs.rt_control.count > 1,
|
||||||
"Alpha Testing is enabled with more than one rendertarget");
|
"Alpha Testing is enabled with more than one rendertarget");
|
||||||
|
|
||||||
|
state.alpha_test.enabled = regs.alpha_test_enabled;
|
||||||
|
if (!state.alpha_test.enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.alpha_test.func = MaxwellToGL::ComparisonOp(regs.alpha_test_func);
|
||||||
|
state.alpha_test.ref = regs.alpha_test_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -166,8 +166,8 @@ private:
|
||||||
/// Syncs the polygon offsets
|
/// Syncs the polygon offsets
|
||||||
void SyncPolygonOffset();
|
void SyncPolygonOffset();
|
||||||
|
|
||||||
/// Check asserts for alpha testing.
|
/// Syncs the alpha test state to match the guest state
|
||||||
void CheckAlphaTests();
|
void SyncAlphaTest();
|
||||||
|
|
||||||
/// Check for extension that are not strictly required
|
/// Check for extension that are not strictly required
|
||||||
/// but are needed for correct emulation
|
/// but are needed for correct emulation
|
||||||
|
|
|
@ -1447,27 +1447,9 @@ private:
|
||||||
|
|
||||||
UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, "Sample mask write is unimplemented");
|
UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, "Sample mask write is unimplemented");
|
||||||
|
|
||||||
code.AddLine("if (alpha_test[0] != 0) {{");
|
|
||||||
++code.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 < Maxwell::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)) {
|
|
||||||
code.AddLine("if (!AlphaFunc({})) discard;", SafeGetRegister(current_reg));
|
|
||||||
current_reg += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
--code.scope;
|
|
||||||
code.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.
|
||||||
current_reg = 0;
|
u32 current_reg = 0;
|
||||||
for (u32 render_target = 0; render_target < Maxwell::NumRenderTargets; ++render_target) {
|
for (u32 render_target = 0; render_target < Maxwell::NumRenderTargets; ++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.
|
||||||
for (u32 component = 0; component < 4; ++component) {
|
for (u32 component = 0; component < 4; ++component) {
|
||||||
|
|
|
@ -28,7 +28,6 @@ layout (location = 0) out vec4 position;
|
||||||
layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config {
|
layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config {
|
||||||
vec4 viewport_flip;
|
vec4 viewport_flip;
|
||||||
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
|
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
|
||||||
uvec4 alpha_test;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
)";
|
)";
|
||||||
|
@ -91,7 +90,6 @@ layout (location = 0) out vec4 position;
|
||||||
layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config {
|
layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config {
|
||||||
vec4 viewport_flip;
|
vec4 viewport_flip;
|
||||||
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
|
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
|
||||||
uvec4 alpha_test;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
)";
|
)";
|
||||||
|
@ -129,33 +127,8 @@ layout (location = 0) in noperspective vec4 position;
|
||||||
layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config {
|
layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config {
|
||||||
vec4 viewport_flip;
|
vec4 viewport_flip;
|
||||||
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
|
uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
)";
|
)";
|
||||||
const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET);
|
const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET);
|
||||||
ProgramResult program =
|
ProgramResult program =
|
||||||
|
|
|
@ -48,17 +48,6 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D& maxwell, std::size_t shade
|
||||||
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;
|
||||||
|
|
||||||
auto func{static_cast<u32>(regs.alpha_test_func)};
|
|
||||||
// Normalize the gl variants of opCompare to be the same as the normal variants
|
|
||||||
const u32 op_gl_variant_base = static_cast<u32>(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;
|
|
||||||
|
|
||||||
instance_id = state.current_instance;
|
instance_id = state.current_instance;
|
||||||
|
|
||||||
// Assign in which stage the position has to be flipped
|
// Assign in which stage the position has to be flipped
|
||||||
|
|
|
@ -27,14 +27,8 @@ struct MaxwellUniformData {
|
||||||
GLuint flip_stage;
|
GLuint flip_stage;
|
||||||
GLfloat y_direction;
|
GLfloat y_direction;
|
||||||
};
|
};
|
||||||
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) == 32, "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");
|
||||||
|
|
||||||
|
|
|
@ -156,6 +156,10 @@ OpenGLState::OpenGLState() {
|
||||||
polygon_offset.factor = 0.0f;
|
polygon_offset.factor = 0.0f;
|
||||||
polygon_offset.units = 0.0f;
|
polygon_offset.units = 0.0f;
|
||||||
polygon_offset.clamp = 0.0f;
|
polygon_offset.clamp = 0.0f;
|
||||||
|
|
||||||
|
alpha_test.enabled = false;
|
||||||
|
alpha_test.func = GL_ALWAYS;
|
||||||
|
alpha_test.ref = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLState::ApplyDefaultState() {
|
void OpenGLState::ApplyDefaultState() {
|
||||||
|
@ -461,6 +465,14 @@ void OpenGLState::ApplyPolygonOffset() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLState::ApplyAlphaTest() const {
|
||||||
|
Enable(GL_ALPHA_TEST, cur_state.alpha_test.enabled, alpha_test.enabled);
|
||||||
|
if (UpdateTie(std::tie(cur_state.alpha_test.func, cur_state.alpha_test.ref),
|
||||||
|
std::tie(alpha_test.func, alpha_test.ref))) {
|
||||||
|
glAlphaFunc(alpha_test.func, alpha_test.ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLState::ApplyTextures() const {
|
void OpenGLState::ApplyTextures() const {
|
||||||
bool has_delta{};
|
bool has_delta{};
|
||||||
std::size_t first{};
|
std::size_t first{};
|
||||||
|
@ -533,6 +545,7 @@ void OpenGLState::Apply() const {
|
||||||
ApplyTextures();
|
ApplyTextures();
|
||||||
ApplySamplers();
|
ApplySamplers();
|
||||||
ApplyPolygonOffset();
|
ApplyPolygonOffset();
|
||||||
|
ApplyAlphaTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLState::EmulateViewportWithScissor() {
|
void OpenGLState::EmulateViewportWithScissor() {
|
||||||
|
|
|
@ -172,6 +172,12 @@ public:
|
||||||
GLfloat clamp;
|
GLfloat clamp;
|
||||||
} polygon_offset;
|
} polygon_offset;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool enabled; // GL_ALPHA_TEST
|
||||||
|
GLenum func; // GL_ALPHA_TEST_FUNC
|
||||||
|
GLfloat ref; // GL_ALPHA_TEST_REF
|
||||||
|
} alpha_test;
|
||||||
|
|
||||||
std::array<bool, 8> clip_distance; // GL_CLIP_DISTANCE
|
std::array<bool, 8> clip_distance; // GL_CLIP_DISTANCE
|
||||||
|
|
||||||
OpenGLState();
|
OpenGLState();
|
||||||
|
@ -215,6 +221,7 @@ public:
|
||||||
void ApplySamplers() const;
|
void ApplySamplers() const;
|
||||||
void ApplyDepthClamp() const;
|
void ApplyDepthClamp() const;
|
||||||
void ApplyPolygonOffset() const;
|
void ApplyPolygonOffset() const;
|
||||||
|
void ApplyAlphaTest() const;
|
||||||
|
|
||||||
/// Set the initial OpenGL state
|
/// Set the initial OpenGL state
|
||||||
static void ApplyDefaultState();
|
static void ApplyDefaultState();
|
||||||
|
|
Loading…
Reference in a new issue