[GPU] Add aproximate alpha test
This commit is contained in:
parent
321305cbf8
commit
9e86750bae
|
@ -12,11 +12,17 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
|
#include "xenia/base/cvar.h"
|
||||||
#include "xenia/base/math.h"
|
#include "xenia/base/math.h"
|
||||||
#include "xenia/gpu/draw_util.h"
|
#include "xenia/gpu/draw_util.h"
|
||||||
#include "xenia/gpu/render_target_cache.h"
|
#include "xenia/gpu/render_target_cache.h"
|
||||||
#include "xenia/gpu/texture_cache.h"
|
#include "xenia/gpu/texture_cache.h"
|
||||||
|
|
||||||
|
DEFINE_bool(use_fuzzy_alpha_epsilon, false,
|
||||||
|
"Use approximate compare for alpha values to prevent flickering on "
|
||||||
|
"NVIDIA graphics cards",
|
||||||
|
"GPU");
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
using namespace ucode;
|
using namespace ucode;
|
||||||
|
@ -2907,6 +2913,10 @@ void DxbcShaderTranslator::CompletePixelShader() {
|
||||||
dxbc::Dest alpha_test_op_dest(dxbc::Dest::R(alpha_test_temp, 0b0010));
|
dxbc::Dest alpha_test_op_dest(dxbc::Dest::R(alpha_test_temp, 0b0010));
|
||||||
dxbc::Src alpha_test_op_src(
|
dxbc::Src alpha_test_op_src(
|
||||||
dxbc::Src::R(alpha_test_temp, dxbc::Src::kYYYY));
|
dxbc::Src::R(alpha_test_temp, dxbc::Src::kYYYY));
|
||||||
|
dxbc::Dest alpha_test_fuzzy_diff_dest(
|
||||||
|
dxbc::Dest::R(alpha_test_temp, 0b0100));
|
||||||
|
dxbc::Src alpha_test_fuzzy_diff_src(
|
||||||
|
dxbc::Src::R(alpha_test_temp, dxbc::Src::kZZZZ));
|
||||||
// Extract the comparison mask to check if the test needs to be done at all.
|
// Extract the comparison mask to check if the test needs to be done at all.
|
||||||
// Don't care about flow control being somewhat dynamic - early Z is forced
|
// Don't care about flow control being somewhat dynamic - early Z is forced
|
||||||
// using a special version of the shader anyway.
|
// using a special version of the shader anyway.
|
||||||
|
@ -2929,29 +2939,73 @@ void DxbcShaderTranslator::CompletePixelShader() {
|
||||||
dxbc::Src alpha_test_reference_src(LoadSystemConstant(
|
dxbc::Src alpha_test_reference_src(LoadSystemConstant(
|
||||||
SystemConstants::Index::kAlphaTestReference,
|
SystemConstants::Index::kAlphaTestReference,
|
||||||
offsetof(SystemConstants, alpha_test_reference), dxbc::Src::kXXXX));
|
offsetof(SystemConstants, alpha_test_reference), dxbc::Src::kXXXX));
|
||||||
|
// Epsilon for alpha checks
|
||||||
|
dxbc::Src fuzzy_epsilon = dxbc::Src::LF(0.01f);
|
||||||
// Handle "not equal" specially (specifically as "not equal" so it's true
|
// Handle "not equal" specially (specifically as "not equal" so it's true
|
||||||
// for NaN, not "less or greater" which is false for NaN).
|
// for NaN, not "less or greater" which is false for NaN).
|
||||||
a_.OpIEq(alpha_test_op_dest, alpha_test_mask_src,
|
a_.OpIEq(alpha_test_op_dest, alpha_test_mask_src,
|
||||||
dxbc::Src::LU(uint32_t(xenos::CompareFunction::kNotEqual)));
|
dxbc::Src::LU(uint32_t(xenos::CompareFunction::kNotEqual)));
|
||||||
a_.OpIf(true, alpha_test_op_src);
|
a_.OpIf(true, alpha_test_op_src);
|
||||||
{ a_.OpNE(alpha_test_mask_dest, alpha_src, alpha_test_reference_src); }
|
{
|
||||||
|
if (cvars::use_fuzzy_alpha_epsilon) {
|
||||||
|
a_.OpAdd(alpha_test_fuzzy_diff_dest, alpha_src,
|
||||||
|
-alpha_test_reference_src);
|
||||||
|
// Check if distance to desired value is less then eps (false for NaN)
|
||||||
|
// and write the negated result
|
||||||
|
a_.OpLT(alpha_test_mask_dest, alpha_test_fuzzy_diff_src.Abs(),
|
||||||
|
fuzzy_epsilon);
|
||||||
|
a_.OpNot(alpha_test_mask_dest, alpha_test_mask_src);
|
||||||
|
} else {
|
||||||
|
a_.OpNE(alpha_test_mask_dest, alpha_src, alpha_test_reference_src);
|
||||||
|
}
|
||||||
|
}
|
||||||
a_.OpElse();
|
a_.OpElse();
|
||||||
{
|
{
|
||||||
// Less than.
|
if (cvars::use_fuzzy_alpha_epsilon) {
|
||||||
a_.OpLT(alpha_test_op_dest, alpha_src, alpha_test_reference_src);
|
// Less than.
|
||||||
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
|
a_.OpAdd(alpha_test_fuzzy_diff_dest, alpha_src, -fuzzy_epsilon);
|
||||||
dxbc::Src::LU(~uint32_t(1 << 0)));
|
a_.OpLT(alpha_test_op_dest, alpha_test_fuzzy_diff_src,
|
||||||
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src, alpha_test_op_src);
|
alpha_test_reference_src);
|
||||||
// Equals to.
|
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
|
||||||
a_.OpEq(alpha_test_op_dest, alpha_src, alpha_test_reference_src);
|
dxbc::Src::LU(~uint32_t(1 << 0)));
|
||||||
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
|
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src,
|
||||||
dxbc::Src::LU(~uint32_t(1 << 1)));
|
alpha_test_op_src);
|
||||||
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src, alpha_test_op_src);
|
// "Equals" to.
|
||||||
// Greater than.
|
a_.OpAdd(alpha_test_fuzzy_diff_dest, alpha_src,
|
||||||
a_.OpLT(alpha_test_op_dest, alpha_test_reference_src, alpha_src);
|
-alpha_test_reference_src);
|
||||||
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
|
a_.OpLT(alpha_test_op_dest, alpha_test_fuzzy_diff_src.Abs(),
|
||||||
dxbc::Src::LU(~uint32_t(1 << 2)));
|
fuzzy_epsilon);
|
||||||
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src, alpha_test_op_src);
|
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
|
||||||
|
dxbc::Src::LU(~uint32_t(1 << 1)));
|
||||||
|
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src,
|
||||||
|
alpha_test_op_src);
|
||||||
|
// Greater than.
|
||||||
|
a_.OpAdd(alpha_test_fuzzy_diff_dest, alpha_src, fuzzy_epsilon);
|
||||||
|
a_.OpLT(alpha_test_op_dest, alpha_test_reference_src,
|
||||||
|
alpha_test_fuzzy_diff_src);
|
||||||
|
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
|
||||||
|
dxbc::Src::LU(~uint32_t(1 << 2)));
|
||||||
|
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src,
|
||||||
|
alpha_test_op_src);
|
||||||
|
} else {
|
||||||
|
// Less than.
|
||||||
|
a_.OpLT(alpha_test_op_dest, alpha_src, alpha_test_reference_src);
|
||||||
|
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
|
||||||
|
dxbc::Src::LU(~uint32_t(1 << 0)));
|
||||||
|
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src,
|
||||||
|
alpha_test_op_src);
|
||||||
|
a_.OpEq(alpha_test_op_dest, alpha_src, alpha_test_reference_src);
|
||||||
|
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
|
||||||
|
dxbc::Src::LU(~uint32_t(1 << 1)));
|
||||||
|
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src,
|
||||||
|
alpha_test_op_src);
|
||||||
|
// Greater than.
|
||||||
|
a_.OpLT(alpha_test_op_dest, alpha_test_reference_src, alpha_src);
|
||||||
|
a_.OpOr(alpha_test_op_dest, alpha_test_op_src,
|
||||||
|
dxbc::Src::LU(~uint32_t(1 << 2)));
|
||||||
|
a_.OpAnd(alpha_test_mask_dest, alpha_test_mask_src,
|
||||||
|
alpha_test_op_src);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Close the "not equal" check.
|
// Close the "not equal" check.
|
||||||
a_.OpEndIf();
|
a_.OpEndIf();
|
||||||
|
|
Loading…
Reference in New Issue