mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-18 20:52:10 +01:00
[d3d9,dxso] Factor out common alpha test code
This commit is contained in:
parent
3806bd44d8
commit
2c713a34c9
@ -189,6 +189,86 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DoFixedFunctionAlphaTest(SpirvModule& spvModule, const D3D9AlphaTestContext& ctx) {
|
||||
// Labels for the alpha test
|
||||
std::array<SpirvSwitchCaseLabel, 8> atestCaseLabels = {{
|
||||
{ uint32_t(VK_COMPARE_OP_NEVER), spvModule.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_LESS), spvModule.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_EQUAL), spvModule.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_LESS_OR_EQUAL), spvModule.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_GREATER), spvModule.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_NOT_EQUAL), spvModule.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_GREATER_OR_EQUAL), spvModule.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_ALWAYS), spvModule.allocateId() },
|
||||
}};
|
||||
|
||||
uint32_t atestBeginLabel = spvModule.allocateId();
|
||||
uint32_t atestTestLabel = spvModule.allocateId();
|
||||
uint32_t atestDiscardLabel = spvModule.allocateId();
|
||||
uint32_t atestKeepLabel = spvModule.allocateId();
|
||||
uint32_t atestSkipLabel = spvModule.allocateId();
|
||||
|
||||
// if (alpha_func != ALWAYS) { ... }
|
||||
uint32_t boolType = spvModule.defBoolType();
|
||||
uint32_t isNotAlways = spvModule.opINotEqual(boolType, ctx.alphaFuncId, spvModule.constu32(VK_COMPARE_OP_ALWAYS));
|
||||
spvModule.opSelectionMerge(atestSkipLabel, spv::SelectionControlMaskNone);
|
||||
spvModule.opBranchConditional(isNotAlways, atestBeginLabel, atestSkipLabel);
|
||||
spvModule.opLabel(atestBeginLabel);
|
||||
|
||||
// switch (alpha_func) { ... }
|
||||
spvModule.opSelectionMerge(atestTestLabel, spv::SelectionControlMaskNone);
|
||||
spvModule.opSwitch(ctx.alphaFuncId,
|
||||
atestCaseLabels[uint32_t(VK_COMPARE_OP_ALWAYS)].labelId,
|
||||
atestCaseLabels.size(),
|
||||
atestCaseLabels.data());
|
||||
|
||||
std::array<SpirvPhiLabel, 8> atestVariables;
|
||||
|
||||
for (uint32_t i = 0; i < atestCaseLabels.size(); i++) {
|
||||
spvModule.opLabel(atestCaseLabels[i].labelId);
|
||||
|
||||
atestVariables[i].labelId = atestCaseLabels[i].labelId;
|
||||
atestVariables[i].varId = [&] {
|
||||
switch (VkCompareOp(atestCaseLabels[i].literal)) {
|
||||
case VK_COMPARE_OP_NEVER: return spvModule.constBool(false);
|
||||
case VK_COMPARE_OP_LESS: return spvModule.opFOrdLessThan (boolType, ctx.alphaId, ctx.alphaRefId);
|
||||
case VK_COMPARE_OP_EQUAL: return spvModule.opFOrdEqual (boolType, ctx.alphaId, ctx.alphaRefId);
|
||||
case VK_COMPARE_OP_LESS_OR_EQUAL: return spvModule.opFOrdLessThanEqual (boolType, ctx.alphaId, ctx.alphaRefId);
|
||||
case VK_COMPARE_OP_GREATER: return spvModule.opFOrdGreaterThan (boolType, ctx.alphaId, ctx.alphaRefId);
|
||||
case VK_COMPARE_OP_NOT_EQUAL: return spvModule.opFOrdNotEqual (boolType, ctx.alphaId, ctx.alphaRefId);
|
||||
case VK_COMPARE_OP_GREATER_OR_EQUAL: return spvModule.opFOrdGreaterThanEqual(boolType, ctx.alphaId, ctx.alphaRefId);
|
||||
default:
|
||||
case VK_COMPARE_OP_ALWAYS: return spvModule.constBool(true);
|
||||
}
|
||||
}();
|
||||
|
||||
spvModule.opBranch(atestTestLabel);
|
||||
}
|
||||
|
||||
// end switch
|
||||
spvModule.opLabel(atestTestLabel);
|
||||
|
||||
uint32_t atestResult = spvModule.opPhi(boolType,
|
||||
atestVariables.size(),
|
||||
atestVariables.data());
|
||||
uint32_t atestDiscard = spvModule.opLogicalNot(boolType, atestResult);
|
||||
|
||||
// if (do_discard) { ... }
|
||||
spvModule.opSelectionMerge(atestKeepLabel, spv::SelectionControlMaskNone);
|
||||
spvModule.opBranchConditional(atestDiscard, atestDiscardLabel, atestKeepLabel);
|
||||
|
||||
spvModule.opLabel(atestDiscardLabel);
|
||||
spvModule.opKill();
|
||||
|
||||
// end if (do_discard)
|
||||
spvModule.opLabel(atestKeepLabel);
|
||||
spvModule.opBranch(atestSkipLabel);
|
||||
|
||||
// end if (alpha_test)
|
||||
spvModule.opLabel(atestSkipLabel);
|
||||
}
|
||||
|
||||
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count) {
|
||||
uint32_t floatType = spvModule.defFloatType(32);
|
||||
uint32_t vec3Type = spvModule.defVectorType(floatType, 3);
|
||||
@ -2220,101 +2300,22 @@ namespace dxvk {
|
||||
|
||||
|
||||
void D3D9FFShaderCompiler::alphaTestPS() {
|
||||
// Alpha testing
|
||||
uint32_t boolType = m_module.defBoolType();
|
||||
uint32_t floatPtr = m_module.defPointerType(m_floatType, spv::StorageClassPushConstant);
|
||||
|
||||
// Declare spec constants for render states
|
||||
uint32_t alphaFuncId = m_spec.get(m_module, m_specUbo, SpecAlphaCompareOp);
|
||||
|
||||
// Implement alpha test
|
||||
auto oC0 = m_ps.out.COLOR;
|
||||
// Labels for the alpha test
|
||||
std::array<SpirvSwitchCaseLabel, 8> atestCaseLabels = { {
|
||||
{ uint32_t(VK_COMPARE_OP_NEVER), m_module.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_LESS), m_module.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_EQUAL), m_module.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_LESS_OR_EQUAL), m_module.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_GREATER), m_module.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_NOT_EQUAL), m_module.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_GREATER_OR_EQUAL), m_module.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_ALWAYS), m_module.allocateId() },
|
||||
} };
|
||||
|
||||
uint32_t atestBeginLabel = m_module.allocateId();
|
||||
uint32_t atestTestLabel = m_module.allocateId();
|
||||
uint32_t atestDiscardLabel = m_module.allocateId();
|
||||
uint32_t atestKeepLabel = m_module.allocateId();
|
||||
uint32_t atestSkipLabel = m_module.allocateId();
|
||||
|
||||
// if (alpha_test) { ... }
|
||||
uint32_t isNotAlways = m_module.opINotEqual(boolType, alphaFuncId, m_module.constu32(VK_COMPARE_OP_ALWAYS));
|
||||
m_module.opSelectionMerge(atestSkipLabel, spv::SelectionControlMaskNone);
|
||||
m_module.opBranchConditional(isNotAlways, atestBeginLabel, atestSkipLabel);
|
||||
m_module.opLabel(atestBeginLabel);
|
||||
|
||||
// Load alpha component
|
||||
uint32_t alphaComponentId = 3;
|
||||
uint32_t alphaId = m_module.opCompositeExtract(m_floatType,
|
||||
uint32_t alphaRefMember = m_module.constu32(uint32_t(D3D9RenderStateItem::AlphaRef));
|
||||
|
||||
D3D9AlphaTestContext alphaTestContext;
|
||||
alphaTestContext.alphaFuncId = m_spec.get(m_module, m_specUbo, SpecAlphaCompareOp);
|
||||
alphaTestContext.alphaRefId = m_module.opLoad(m_floatType,
|
||||
m_module.opAccessChain(floatPtr, m_rsBlock, 1, &alphaRefMember));
|
||||
alphaTestContext.alphaId = m_module.opCompositeExtract(m_floatType,
|
||||
m_module.opLoad(m_vec4Type, oC0),
|
||||
1, &alphaComponentId);
|
||||
|
||||
// Load alpha reference
|
||||
uint32_t alphaRefMember = m_module.constu32(uint32_t(D3D9RenderStateItem::AlphaRef));
|
||||
uint32_t alphaRefId = m_module.opLoad(m_floatType,
|
||||
m_module.opAccessChain(floatPtr, m_rsBlock, 1, &alphaRefMember));
|
||||
|
||||
// switch (alpha_func) { ... }
|
||||
m_module.opSelectionMerge(atestTestLabel, spv::SelectionControlMaskNone);
|
||||
m_module.opSwitch(alphaFuncId,
|
||||
atestCaseLabels[uint32_t(VK_COMPARE_OP_ALWAYS)].labelId,
|
||||
atestCaseLabels.size(),
|
||||
atestCaseLabels.data());
|
||||
|
||||
std::array<SpirvPhiLabel, 8> atestVariables;
|
||||
|
||||
for (uint32_t i = 0; i < atestCaseLabels.size(); i++) {
|
||||
m_module.opLabel(atestCaseLabels[i].labelId);
|
||||
|
||||
atestVariables[i].labelId = atestCaseLabels[i].labelId;
|
||||
atestVariables[i].varId = [&] {
|
||||
switch (VkCompareOp(atestCaseLabels[i].literal)) {
|
||||
case VK_COMPARE_OP_NEVER: return m_module.constBool(false);
|
||||
case VK_COMPARE_OP_LESS: return m_module.opFOrdLessThan(boolType, alphaId, alphaRefId);
|
||||
case VK_COMPARE_OP_EQUAL: return m_module.opFOrdEqual(boolType, alphaId, alphaRefId);
|
||||
case VK_COMPARE_OP_LESS_OR_EQUAL: return m_module.opFOrdLessThanEqual(boolType, alphaId, alphaRefId);
|
||||
case VK_COMPARE_OP_GREATER: return m_module.opFOrdGreaterThan(boolType, alphaId, alphaRefId);
|
||||
case VK_COMPARE_OP_NOT_EQUAL: return m_module.opFOrdNotEqual(boolType, alphaId, alphaRefId);
|
||||
case VK_COMPARE_OP_GREATER_OR_EQUAL: return m_module.opFOrdGreaterThanEqual(boolType, alphaId, alphaRefId);
|
||||
default:
|
||||
case VK_COMPARE_OP_ALWAYS: return m_module.constBool(true);
|
||||
}
|
||||
}();
|
||||
|
||||
m_module.opBranch(atestTestLabel);
|
||||
}
|
||||
|
||||
// end switch
|
||||
m_module.opLabel(atestTestLabel);
|
||||
|
||||
uint32_t atestResult = m_module.opPhi(boolType,
|
||||
atestVariables.size(),
|
||||
atestVariables.data());
|
||||
uint32_t atestDiscard = m_module.opLogicalNot(boolType, atestResult);
|
||||
|
||||
// if (do_discard) { ... }
|
||||
m_module.opSelectionMerge(atestKeepLabel, spv::SelectionControlMaskNone);
|
||||
m_module.opBranchConditional(atestDiscard, atestDiscardLabel, atestKeepLabel);
|
||||
|
||||
m_module.opLabel(atestDiscardLabel);
|
||||
m_module.opKill();
|
||||
|
||||
// end if (do_discard)
|
||||
m_module.opLabel(atestKeepLabel);
|
||||
m_module.opBranch(atestSkipLabel);
|
||||
|
||||
// end if (alpha_test)
|
||||
m_module.opLabel(atestSkipLabel);
|
||||
DoFixedFunctionAlphaTest(m_module, alphaTestContext);
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,6 +38,12 @@ namespace dxvk {
|
||||
uint32_t SpecUBO;
|
||||
};
|
||||
|
||||
struct D3D9AlphaTestContext {
|
||||
uint32_t alphaId;
|
||||
uint32_t alphaFuncId;
|
||||
uint32_t alphaRefId;
|
||||
};
|
||||
|
||||
struct D3D9FixedFunctionOptions {
|
||||
D3D9FixedFunctionOptions(const D3D9Options* options);
|
||||
|
||||
@ -48,6 +54,8 @@ namespace dxvk {
|
||||
// Returns new oColor if PS
|
||||
uint32_t DoFixedFunctionFog(D3D9ShaderSpecConstantManager& spec, SpirvModule& spvModule, const D3D9FogContext& fogCtx);
|
||||
|
||||
void DoFixedFunctionAlphaTest(SpirvModule& spvModule, const D3D9AlphaTestContext& ctx);
|
||||
|
||||
// Returns a render state block
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count);
|
||||
|
||||
|
@ -36,7 +36,7 @@ namespace dxvk {
|
||||
float fogEnd = 1.0f;
|
||||
float fogDensity = 1.0f;
|
||||
|
||||
float alphaRef = 0.0f;
|
||||
uint32_t alphaRef = 0u;
|
||||
|
||||
float pointSize = 1.0f;
|
||||
float pointSizeMin = 1.0f;
|
||||
|
@ -3698,8 +3698,6 @@ void DxsoCompiler::emitControlFlowGenericLoop(
|
||||
uint32_t floatType = m_module.defFloatType(32);
|
||||
uint32_t floatPtr = m_module.defPointerType(floatType, spv::StorageClassPushConstant);
|
||||
|
||||
uint32_t alphaFuncId = m_spec.get(m_module, m_specUbo, SpecAlphaCompareOp);
|
||||
|
||||
// Implement alpha test and fog
|
||||
DxsoRegister color0;
|
||||
color0.id = DxsoRegisterId{ DxsoRegisterType::ColorOut, 0 };
|
||||
@ -3709,107 +3707,18 @@ void DxsoCompiler::emitControlFlowGenericLoop(
|
||||
if (m_programInfo.majorVersion() < 3)
|
||||
emitFog();
|
||||
|
||||
// Labels for the alpha test
|
||||
std::array<SpirvSwitchCaseLabel, 8> atestCaseLabels = {{
|
||||
{ uint32_t(VK_COMPARE_OP_NEVER), m_module.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_LESS), m_module.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_EQUAL), m_module.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_LESS_OR_EQUAL), m_module.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_GREATER), m_module.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_NOT_EQUAL), m_module.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_GREATER_OR_EQUAL), m_module.allocateId() },
|
||||
{ uint32_t(VK_COMPARE_OP_ALWAYS), m_module.allocateId() },
|
||||
}};
|
||||
|
||||
uint32_t atestBeginLabel = m_module.allocateId();
|
||||
uint32_t atestTestLabel = m_module.allocateId();
|
||||
uint32_t atestDiscardLabel = m_module.allocateId();
|
||||
uint32_t atestKeepLabel = m_module.allocateId();
|
||||
uint32_t atestSkipLabel = m_module.allocateId();
|
||||
|
||||
// if (alpha_func != ALWAYS) { ... }
|
||||
uint32_t isNotAlways = m_module.opINotEqual(boolType, alphaFuncId, m_module.constu32(VK_COMPARE_OP_ALWAYS));
|
||||
m_module.opSelectionMerge(atestSkipLabel, spv::SelectionControlMaskNone);
|
||||
m_module.opBranchConditional(isNotAlways, atestBeginLabel, atestSkipLabel);
|
||||
m_module.opLabel(atestBeginLabel);
|
||||
|
||||
// Load alpha component
|
||||
uint32_t alphaRefMember = m_module.constu32(uint32_t(D3D9RenderStateItem::AlphaRef));
|
||||
uint32_t alphaComponentId = 3;
|
||||
uint32_t alphaId = m_module.opCompositeExtract(floatType,
|
||||
|
||||
D3D9AlphaTestContext alphaTestContext;
|
||||
alphaTestContext.alphaFuncId = m_spec.get(m_module, m_specUbo, SpecAlphaCompareOp);
|
||||
alphaTestContext.alphaRefId = m_module.opLoad(floatType,
|
||||
m_module.opAccessChain(floatPtr, m_rsBlock, 1, &alphaRefMember));
|
||||
alphaTestContext.alphaId = m_module.opCompositeExtract(floatType,
|
||||
m_module.opLoad(m_module.defVectorType(floatType, 4), oC0.id),
|
||||
1, &alphaComponentId);
|
||||
|
||||
if (m_moduleInfo.options.alphaTestWiggleRoom) {
|
||||
// NV has wonky interpolation of all 1's in a VS -> PS going to 0.999999...
|
||||
// This causes garbage-looking graphics on people's clothing in EverQuest 2 as it does alpha == 1.0.
|
||||
|
||||
// My testing shows the alpha test has a precision of 1/256 for all A8 and below formats,
|
||||
// and around 1 / 2048 for A32F formats and 1 / 4096 for A16F formats (It makes no sense to me too)
|
||||
// so anyway, we're just going to round this to a precision of 1 / 4096 and hopefully this should make things happy
|
||||
// everywhere.
|
||||
const uint32_t alphaSizeId = m_module.constf32(4096.0f);
|
||||
|
||||
alphaId = m_module.opFMul(floatType, alphaId, alphaSizeId);
|
||||
alphaId = m_module.opRound(floatType, alphaId);
|
||||
alphaId = m_module.opFDiv(floatType, alphaId, alphaSizeId);
|
||||
}
|
||||
|
||||
// Load alpha reference
|
||||
uint32_t alphaRefMember = m_module.constu32(uint32_t(D3D9RenderStateItem::AlphaRef));
|
||||
uint32_t alphaRefId = m_module.opLoad(floatType,
|
||||
m_module.opAccessChain(floatPtr, m_rsBlock, 1, &alphaRefMember));
|
||||
|
||||
// switch (alpha_func) { ... }
|
||||
m_module.opSelectionMerge(atestTestLabel, spv::SelectionControlMaskNone);
|
||||
m_module.opSwitch(alphaFuncId,
|
||||
atestCaseLabels[uint32_t(VK_COMPARE_OP_ALWAYS)].labelId,
|
||||
atestCaseLabels.size(),
|
||||
atestCaseLabels.data());
|
||||
|
||||
std::array<SpirvPhiLabel, 8> atestVariables;
|
||||
|
||||
for (uint32_t i = 0; i < atestCaseLabels.size(); i++) {
|
||||
m_module.opLabel(atestCaseLabels[i].labelId);
|
||||
|
||||
atestVariables[i].labelId = atestCaseLabels[i].labelId;
|
||||
atestVariables[i].varId = [&] {
|
||||
switch (VkCompareOp(atestCaseLabels[i].literal)) {
|
||||
case VK_COMPARE_OP_NEVER: return m_module.constBool(false);
|
||||
case VK_COMPARE_OP_LESS: return m_module.opFOrdLessThan (boolType, alphaId, alphaRefId);
|
||||
case VK_COMPARE_OP_EQUAL: return m_module.opFOrdEqual (boolType, alphaId, alphaRefId);
|
||||
case VK_COMPARE_OP_LESS_OR_EQUAL: return m_module.opFOrdLessThanEqual (boolType, alphaId, alphaRefId);
|
||||
case VK_COMPARE_OP_GREATER: return m_module.opFOrdGreaterThan (boolType, alphaId, alphaRefId);
|
||||
case VK_COMPARE_OP_NOT_EQUAL: return m_module.opFOrdNotEqual (boolType, alphaId, alphaRefId);
|
||||
case VK_COMPARE_OP_GREATER_OR_EQUAL: return m_module.opFOrdGreaterThanEqual(boolType, alphaId, alphaRefId);
|
||||
default:
|
||||
case VK_COMPARE_OP_ALWAYS: return m_module.constBool(true);
|
||||
}
|
||||
}();
|
||||
|
||||
m_module.opBranch(atestTestLabel);
|
||||
}
|
||||
|
||||
// end switch
|
||||
m_module.opLabel(atestTestLabel);
|
||||
|
||||
uint32_t atestResult = m_module.opPhi(boolType,
|
||||
atestVariables.size(),
|
||||
atestVariables.data());
|
||||
uint32_t atestDiscard = m_module.opLogicalNot(boolType, atestResult);
|
||||
|
||||
// if (do_discard) { ... }
|
||||
m_module.opSelectionMerge(atestKeepLabel, spv::SelectionControlMaskNone);
|
||||
m_module.opBranchConditional(atestDiscard, atestDiscardLabel, atestKeepLabel);
|
||||
|
||||
m_module.opLabel(atestDiscardLabel);
|
||||
m_module.opKill();
|
||||
|
||||
// end if (do_discard)
|
||||
m_module.opLabel(atestKeepLabel);
|
||||
m_module.opBranch(atestSkipLabel);
|
||||
|
||||
// end if (alpha_test)
|
||||
m_module.opLabel(atestSkipLabel);
|
||||
DoFixedFunctionAlphaTest(m_module, alphaTestContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user