[d3d9, dxso] Refactor spec constants to use a bitfield layout

This allows us to use the same information to dump into a push constant for unoptimized pipelines.
This commit is contained in:
Joshua Ashton 2022-07-30 23:58:40 +01:00 committed by Joshie
parent 438ae5cdfc
commit b2cbf198e4
7 changed files with 271 additions and 242 deletions

View File

@ -144,6 +144,8 @@ namespace dxvk {
m_flags.set(D3D9DeviceFlag::DirtySharedPixelShaderData);
m_flags.set(D3D9DeviceFlag::DirtyDepthBounds);
m_flags.set(D3D9DeviceFlag::DirtyPointScale);
m_flags.set(D3D9DeviceFlag::DirtySpecializationEntries);
}
@ -5314,42 +5316,31 @@ namespace dxvk {
}
template <bool Points>
void D3D9DeviceEx::UpdatePointMode() {
if constexpr (!Points) {
m_lastPointMode = 0;
EmitCs([](DxvkContext* ctx) {
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::PointMode, 0);
});
void D3D9DeviceEx::UpdatePointMode(bool pointList) {
if (!pointList) {
UpdatePointModeSpec(0);
return;
}
else {
auto& rs = m_state.renderStates;
const bool scale = rs[D3DRS_POINTSCALEENABLE] && !UseProgrammableVS();
const bool sprite = rs[D3DRS_POINTSPRITEENABLE];
auto& rs = m_state.renderStates;
const uint32_t scaleBit = scale ? 1u : 0u;
const uint32_t spriteBit = sprite ? 2u : 0u;
const bool scale = rs[D3DRS_POINTSCALEENABLE] && !UseProgrammableVS();
const bool sprite = rs[D3DRS_POINTSPRITEENABLE];
uint32_t mode = scaleBit | spriteBit;
const uint32_t scaleBit = scale ? 1u : 0u;
const uint32_t spriteBit = sprite ? 2u : 0u;
if (rs[D3DRS_POINTSCALEENABLE] && m_flags.test(D3D9DeviceFlag::DirtyPointScale)) {
m_flags.clr(D3D9DeviceFlag::DirtyPointScale);
uint32_t mode = scaleBit | spriteBit;
UpdatePushConstant<D3D9RenderStateItem::PointScaleA>();
UpdatePushConstant<D3D9RenderStateItem::PointScaleB>();
UpdatePushConstant<D3D9RenderStateItem::PointScaleC>();
}
if (rs[D3DRS_POINTSCALEENABLE] && m_flags.test(D3D9DeviceFlag::DirtyPointScale)) {
m_flags.clr(D3D9DeviceFlag::DirtyPointScale);
if (unlikely(mode != m_lastPointMode)) {
EmitCs([cMode = mode] (DxvkContext* ctx) {
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::PointMode, cMode);
});
m_lastPointMode = mode;
}
UpdatePushConstant<D3D9RenderStateItem::PointScaleA>();
UpdatePushConstant<D3D9RenderStateItem::PointScaleB>();
UpdatePushConstant<D3D9RenderStateItem::PointScaleC>();
}
UpdatePointModeSpec(mode);
}
@ -5394,11 +5385,7 @@ namespace dxvk {
if (m_flags.test(D3D9DeviceFlag::DirtyFogState)) {
m_flags.clr(D3D9DeviceFlag::DirtyFogState);
EmitCs([cMode = mode] (DxvkContext* ctx) {
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::FogEnabled, true);
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::VertexFogMode, cMode);
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::PixelFogMode, D3DFOG_NONE);
});
UpdateFogModeSpec(true, mode, D3DFOG_NONE);
}
}
else if (pixelFog) {
@ -5409,11 +5396,7 @@ namespace dxvk {
if (m_flags.test(D3D9DeviceFlag::DirtyFogState)) {
m_flags.clr(D3D9DeviceFlag::DirtyFogState);
EmitCs([cMode = mode] (DxvkContext* ctx) {
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::FogEnabled, true);
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::VertexFogMode, D3DFOG_NONE);
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::PixelFogMode, cMode);
});
UpdateFogModeSpec(true, D3DFOG_NONE, mode);
}
}
else {
@ -5423,11 +5406,7 @@ namespace dxvk {
if (m_flags.test(D3D9DeviceFlag::DirtyFogState)) {
m_flags.clr(D3D9DeviceFlag::DirtyFogState);
EmitCs([cEnabled = fogEnabled] (DxvkContext* ctx) {
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::FogEnabled, cEnabled);
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::VertexFogMode, D3DFOG_NONE);
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::PixelFogMode, D3DFOG_NONE);
});
UpdateFogModeSpec(fogEnabled, D3DFOG_NONE, D3DFOG_NONE);
}
}
}
@ -5756,9 +5735,7 @@ namespace dxvk {
? DecodeCompareOp(D3DCMPFUNC(rs[D3DRS_ALPHAFUNC]))
: VK_COMPARE_OP_ALWAYS;
EmitCs([cAlphaOp = alphaOp] (DxvkContext* ctx) {
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::AlphaCompareOp, cAlphaOp);
});
UpdateAlphaTestSpec(alphaOp);
}
@ -6029,10 +6006,7 @@ namespace dxvk {
if (m_flags.test(D3D9DeviceFlag::DirtyClipPlanes))
UpdateClipPlanes();
if (PrimitiveType == D3DPT_POINTLIST)
UpdatePointMode<true>();
else if (m_lastPointMode != 0)
UpdatePointMode<false>();
UpdatePointMode(PrimitiveType == D3DPT_POINTLIST);
if (likely(UseProgrammableVS())) {
if (unlikely(m_flags.test(D3D9DeviceFlag::DirtyProgVertexShader))) {
@ -6045,14 +6019,14 @@ namespace dxvk {
UploadConstants<DxsoProgramTypes::VertexShader>();
if (likely(!CanSWVP())) {
UpdateBoolSpecConstantVertex(
UpdateVertexBoolSpec(
m_state.vsConsts.bConsts[0] &
m_consts[DxsoProgramType::VertexShader].meta.boolConstantMask);
} else
UpdateBoolSpecConstantVertex(0);
UpdateVertexBoolSpec(0);
}
else {
UpdateBoolSpecConstantVertex(0);
UpdateVertexBoolSpec(0);
UpdateFixedFunctionVS();
}
@ -6069,24 +6043,24 @@ namespace dxvk {
const auto& programInfo = GetCommonShader(m_state.pixelShader)->GetInfo();
if (programInfo.majorVersion() >= 2)
UpdatePsSamplerSpecConstants(m_d3d9Options.forceSamplerTypeSpecConstants ? m_textureTypes : 0u, 0u, fetch4);
UpdatePixelShaderSamplerSpec(m_d3d9Options.forceSamplerTypeSpecConstants ? m_textureTypes : 0u, 0u, fetch4);
else
UpdatePsSamplerSpecConstants(m_textureTypes, programInfo.minorVersion() >= 4 ? 0u : projected, fetch4); // For implicit samplers...
UpdatePixelShaderSamplerSpec(m_textureTypes, programInfo.minorVersion() >= 4 ? 0u : projected, fetch4); // For implicit samplers...
UpdateBoolSpecConstantPixel(
UpdatePixelBoolSpec(
m_state.psConsts.bConsts[0] &
m_consts[DxsoProgramType::PixelShader].meta.boolConstantMask);
}
else {
UpdateBoolSpecConstantPixel(0);
UpdatePsSamplerSpecConstants(0u, 0u, 0u);
UpdatePixelBoolSpec(0);
UpdatePixelShaderSamplerSpec(0u, 0u, 0u);
UpdateFixedFunctionPS();
}
const uint32_t nullTextureMask = usedSamplerMask & ~usedTextureMask;
const uint32_t depthTextureMask = m_depthTextures & usedTextureMask;
UpdateCommonSamplerSpecConstants(nullTextureMask, depthTextureMask);
UpdateCommonSamplerSpec(nullTextureMask, depthTextureMask);
if (m_flags.test(D3D9DeviceFlag::DirtySharedPixelShaderData)) {
m_flags.clr(D3D9DeviceFlag::DirtySharedPixelShaderData);
@ -6123,6 +6097,8 @@ namespace dxvk {
ctx->setDepthBounds(cDepthBounds);
});
}
BindSpecConstants();
}
@ -6717,65 +6693,6 @@ namespace dxvk {
}
void D3D9DeviceEx::UpdateBoolSpecConstantVertex(uint32_t value) {
if (value == m_lastBoolSpecConstantVertex)
return;
EmitCs([cBitfield = value](DxvkContext* ctx) {
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::VertexShaderBools, cBitfield);
});
m_lastBoolSpecConstantVertex = value;
}
void D3D9DeviceEx::UpdateBoolSpecConstantPixel(uint32_t value) {
if (value == m_lastBoolSpecConstantPixel)
return;
EmitCs([cBitfield = value](DxvkContext* ctx) {
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::PixelShaderBools, cBitfield);
});
m_lastBoolSpecConstantPixel = value;
}
void D3D9DeviceEx::UpdatePsSamplerSpecConstants(uint32_t types, uint32_t projections, uint32_t fetch4) {
if (m_lastSamplerTypes != types || m_lastProjectionBitfield != projections || m_lastFetch4 != fetch4) {
m_lastSamplerTypes = types;
m_lastProjectionBitfield = projections;
m_lastFetch4 = fetch4;
EmitCs([
cSamplerType = types,
cProjectionType = projections,
cFetch4 = fetch4
] (DxvkContext* ctx) {
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::SamplerType, cSamplerType);
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::ProjectionType, cProjectionType);
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::Fetch4, cFetch4);
});
}
}
void D3D9DeviceEx::UpdateCommonSamplerSpecConstants(uint32_t nullMask, uint32_t depthMask) {
if (m_lastSamplerNull != nullMask || m_lastSamplerDepthMode != depthMask) {
m_lastSamplerNull = nullMask;
m_lastSamplerDepthMode = depthMask;
EmitCs([
cNullMask = nullMask,
cDepthMask = depthMask
] (DxvkContext* ctx) {
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::SamplerNull, cNullMask);
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::SamplerDepthMode, cDepthMask);
});
}
}
void D3D9DeviceEx::ApplyPrimitiveType(
DxvkContext* pContext,
D3DPRIMITIVETYPE PrimType) {
@ -7018,7 +6935,7 @@ namespace dxvk {
UpdatePushConstant<D3D9RenderStateItem::PointSizeMin>();
UpdatePushConstant<D3D9RenderStateItem::PointSizeMax>();
m_flags.set(D3D9DeviceFlag::DirtyPointScale);
UpdatePointMode<false>();
UpdatePointMode(false);
rs[D3DRS_SRGBWRITEENABLE] = 0;
@ -7140,10 +7057,10 @@ namespace dxvk {
// We should do this...
m_flags.set(D3D9DeviceFlag::DirtyInputLayout);
UpdatePsSamplerSpecConstants(0u, 0u, 0u);
UpdateBoolSpecConstantVertex(0u);
UpdateBoolSpecConstantPixel(0u);
UpdateCommonSamplerSpecConstants(0u, 0u);
UpdatePixelShaderSamplerSpec(0u, 0u, 0u);
UpdateVertexBoolSpec(0u);
UpdatePixelBoolSpec(0u);
UpdateCommonSamplerSpec(0u, 0u);
return D3D_OK;
}
@ -7302,4 +7219,75 @@ namespace dxvk {
#endif
}
////////////////////////////////////
// D3D9 Device Specialization State
////////////////////////////////////
void D3D9DeviceEx::UpdateAlphaTestSpec(VkCompareOp alphaOp) {
uint32_t value = uint32_t(alphaOp);
if (m_specInfo.set<SpecAlphaCompareOp>(value))
m_flags.set(D3D9DeviceFlag::DirtySpecializationEntries);
}
void D3D9DeviceEx::UpdateVertexBoolSpec(uint32_t value) {
if (m_specInfo.set<SpecVertexShaderBools>(value))
m_flags.set(D3D9DeviceFlag::DirtySpecializationEntries);
}
void D3D9DeviceEx::UpdatePixelBoolSpec(uint32_t value) {
if (m_specInfo.set<SpecPixelShaderBools>(value))
m_flags.set(D3D9DeviceFlag::DirtySpecializationEntries);
}
void D3D9DeviceEx::UpdatePixelShaderSamplerSpec(uint32_t types, uint32_t projections, uint32_t fetch4) {
bool dirty = m_specInfo.set<SpecSamplerType>(types);
dirty |= m_specInfo.set<SpecProjectionType>(projections);
dirty |= m_specInfo.set<SpecFetch4>(fetch4);
if (dirty)
m_flags.set(D3D9DeviceFlag::DirtySpecializationEntries);
}
void D3D9DeviceEx::UpdateCommonSamplerSpec(uint32_t nullMask, uint32_t depthMask) {
bool dirty = m_specInfo.set<SpecSamplerDepthMode>(depthMask);
dirty |= m_specInfo.set<SpecSamplerNull>(nullMask);
if (dirty)
m_flags.set(D3D9DeviceFlag::DirtySpecializationEntries);
}
void D3D9DeviceEx::UpdatePointModeSpec(uint32_t mode) {
if (m_specInfo.set<SpecPointMode>(mode))
m_flags.set(D3D9DeviceFlag::DirtySpecializationEntries);
}
void D3D9DeviceEx::UpdateFogModeSpec(bool fogEnabled, D3DFOGMODE vertexFogMode, D3DFOGMODE pixelFogMode) {
bool dirty = m_specInfo.set<SpecFogEnabled>(fogEnabled);
dirty |= m_specInfo.set<SpecVertexFogMode>(vertexFogMode);
dirty |= m_specInfo.set<SpecPixelFogMode>(pixelFogMode);
if (dirty)
m_flags.set(D3D9DeviceFlag::DirtySpecializationEntries);
}
void D3D9DeviceEx::BindSpecConstants() {
if (!m_flags.test(D3D9DeviceFlag::DirtySpecializationEntries))
return;
EmitCs([cSpecInfo = m_specInfo](DxvkContext* ctx) {
for (size_t i = 0; i < cSpecInfo.data.size(); i++)
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, i, cSpecInfo.data[i]);
});
m_flags.clr(D3D9DeviceFlag::DirtySpecializationEntries);
}
}

View File

@ -26,6 +26,7 @@
#include "d3d9_fixed_function.h"
#include "d3d9_swvp_emu.h"
#include "d3d9_spec_constants.h"
#include "d3d9_shader_permutations.h"
#include <unordered_set>
@ -80,6 +81,8 @@ namespace dxvk {
DirtyPointScale,
InScene,
DirtySpecializationEntries,
};
using D3D9DeviceFlags = Flags<D3D9DeviceFlag>;
@ -776,8 +779,7 @@ namespace dxvk {
void MarkTextureUploaded(D3D9CommonTexture* pResource);
template <bool Points>
void UpdatePointMode();
void UpdatePointMode(bool pointList);
void UpdateFog();
@ -826,8 +828,6 @@ namespace dxvk {
void BindDepthBias();
void BindAlphaTestState();
inline void UploadSoftwareConstantSet(const D3D9ShaderConstantsVSSoftware& Src, const D3D9ConstantLayout& Layout);
inline void* CopySoftwareConstants(D3D9ConstantBuffer& dstBuffer, const void* src, uint32_t size);
@ -1134,13 +1134,17 @@ namespace dxvk {
bool UseProgrammablePS();
void UpdateBoolSpecConstantVertex(uint32_t value);
void BindAlphaTestState();
void UpdateBoolSpecConstantPixel(uint32_t value);
void UpdateAlphaTestSpec(VkCompareOp alphaOp);
void UpdateVertexBoolSpec(uint32_t value);
void UpdatePixelBoolSpec(uint32_t value);
void UpdatePixelShaderSamplerSpec(uint32_t types, uint32_t projections, uint32_t fetch4);
void UpdateCommonSamplerSpec(uint32_t boundMask, uint32_t depthMask);
void UpdatePointModeSpec(uint32_t mode);
void UpdateFogModeSpec(bool fogEnabled, D3DFOGMODE vertexFogMode, D3DFOGMODE pixelFogMode);
void UpdatePsSamplerSpecConstants(uint32_t types, uint32_t projections, uint32_t fetch4);
void UpdateCommonSamplerSpecConstants(uint32_t boundMask, uint32_t depthMask);
void BindSpecConstants();
void TrackBufferMappingBufferSequenceNumber(
D3D9CommonBuffer* pResource);
@ -1239,17 +1243,11 @@ namespace dxvk {
uint32_t m_fetch4Enabled = 0;
uint32_t m_fetch4 = 0;
uint32_t m_lastBoolSpecConstantVertex = 0;
uint32_t m_lastBoolSpecConstantPixel = 0;
uint32_t m_lastSamplerDepthMode = 0;
uint32_t m_lastProjectionBitfield = 0;
uint32_t m_lastSamplerNull = 0;
uint32_t m_lastSamplerTypes = 0;
uint32_t m_lastPointMode = 0;
uint32_t m_lastFetch4 = 0;
uint32_t m_lastHazardsDS = 0;
uint32_t m_lastSamplerTypesFF = 0;
D3D9SpecializationInfo m_specInfo = D3D9SpecializationInfo();
D3D9ShaderMasks m_vsShaderMasks = D3D9ShaderMasks();
D3D9ShaderMasks m_psShaderMasks = FixedFunctionMask;

View File

@ -16,9 +16,8 @@ namespace dxvk {
invariantPosition = options->invariantPosition;
}
uint32_t DoFixedFunctionFog(SpirvModule& spvModule, const D3D9FogContext& fogCtx) {
uint32_t DoFixedFunctionFog(D3D9ShaderSpecConstantManager& spec, SpirvModule& spvModule, const D3D9FogContext& fogCtx) {
uint32_t floatType = spvModule.defFloatType(32);
uint32_t uint32Type = spvModule.defIntType(32, 0);
uint32_t vec3Type = spvModule.defVectorType(floatType, 3);
uint32_t vec4Type = spvModule.defVectorType(floatType, 4);
uint32_t floatPtr = spvModule.defPointerType(floatType, spv::StorageClassPushConstant);
@ -40,20 +39,12 @@ namespace dxvk {
uint32_t fogDensity = spvModule.opLoad(floatType,
spvModule.opAccessChain(floatPtr, fogCtx.RenderState, 1, &fogDensityMember));
uint32_t fogMode = spvModule.specConst32(uint32Type, 0);
uint32_t fogMode = spec.get(
spvModule,
fogCtx.IsPixel ? SpecPixelFogMode : SpecVertexFogMode);
if (!fogCtx.IsPixel) {
spvModule.setDebugName(fogMode, "vertex_fog_mode");
spvModule.decorateSpecId(fogMode, D3D9SpecConstantId::VertexFogMode);
}
else {
spvModule.setDebugName(fogMode, "pixel_fog_mode");
spvModule.decorateSpecId(fogMode, D3D9SpecConstantId::PixelFogMode);
}
uint32_t fogEnabled = spvModule.specConstBool(false);
spvModule.setDebugName(fogEnabled, "fog_enabled");
spvModule.decorateSpecId(fogEnabled, D3D9SpecConstantId::FogEnabled);
uint32_t fogEnabled = spec.get(spvModule, SpecFogEnabled);
fogEnabled = spvModule.opINotEqual(spvModule.defBoolType(), fogEnabled, spvModule.constu32(0));
uint32_t doFog = spvModule.allocateId();
uint32_t skipFog = spvModule.allocateId();
@ -253,7 +244,7 @@ namespace dxvk {
}
D3D9PointSizeInfoVS GetPointSizeInfoVS(SpirvModule& spvModule, uint32_t vPos, uint32_t vtx, uint32_t perVertPointSize, uint32_t rsBlock, bool isFixedFunction) {
D3D9PointSizeInfoVS GetPointSizeInfoVS(D3D9ShaderSpecConstantManager& spec, SpirvModule& spvModule, uint32_t vPos, uint32_t vtx, uint32_t perVertPointSize, uint32_t rsBlock, bool isFixedFunction) {
uint32_t floatType = spvModule.defFloatType(32);
uint32_t floatPtr = spvModule.defPointerType(floatType, spv::StorageClassPushConstant);
uint32_t vec3Type = spvModule.defVectorType(floatType, 3);
@ -269,9 +260,7 @@ namespace dxvk {
uint32_t value = perVertPointSize != 0 ? perVertPointSize : LoadFloat(D3D9RenderStateItem::PointSize);
if (isFixedFunction) {
uint32_t pointMode = spvModule.specConst32(uint32Type, 0);
spvModule.setDebugName(pointMode, "point_mode");
spvModule.decorateSpecId(pointMode, D3D9SpecConstantId::PointMode);
uint32_t pointMode = spec.get(spvModule, SpecPointMode);
uint32_t scaleBit = spvModule.opBitFieldUExtract(uint32Type, pointMode, spvModule.consti32(0), spvModule.consti32(1));
uint32_t isScale = spvModule.opIEqual(boolType, scaleBit, spvModule.constu32(1));
@ -317,14 +306,12 @@ namespace dxvk {
}
D3D9PointSizeInfoPS GetPointSizeInfoPS(SpirvModule& spvModule, uint32_t rsBlock) {
D3D9PointSizeInfoPS GetPointSizeInfoPS(D3D9ShaderSpecConstantManager& spec, SpirvModule& spvModule, uint32_t rsBlock) {
uint32_t uint32Type = spvModule.defIntType(32, 0);
uint32_t boolType = spvModule.defBoolType();
uint32_t boolVec4 = spvModule.defVectorType(boolType, 4);
uint32_t pointMode = spvModule.specConst32(uint32Type, 0);
spvModule.setDebugName(pointMode, "point_mode");
spvModule.decorateSpecId(pointMode, D3D9SpecConstantId::PointMode);
uint32_t pointMode = spec.get(spvModule, SpecPointMode);
uint32_t spriteBit = spvModule.opBitFieldUExtract(uint32Type, pointMode, spvModule.consti32(1), spvModule.consti32(1));
uint32_t isSprite = spvModule.opIEqual(boolType, spriteBit, spvModule.constu32(1));
@ -631,6 +618,8 @@ namespace dxvk {
uint32_t m_mainFuncLabel;
D3D9FixedFunctionOptions m_options;
D3D9ShaderSpecConstantManager m_spec;
};
D3D9FFShaderCompiler::D3D9FFShaderCompiler(
@ -1164,9 +1153,9 @@ namespace dxvk {
fogCtx.IsPositionT = m_vsKey.Data.Contents.HasPositionT;
fogCtx.HasSpecular = m_vsKey.Data.Contents.HasColor1;
fogCtx.Specular = m_vs.in.COLOR[1];
m_module.opStore(m_vs.out.FOG, DoFixedFunctionFog(m_module, fogCtx));
m_module.opStore(m_vs.out.FOG, DoFixedFunctionFog(m_spec, m_module, fogCtx));
auto pointInfo = GetPointSizeInfoVS(m_module, 0, vtx, m_vs.in.POINTSIZE, m_rsBlock, true);
auto pointInfo = GetPointSizeInfoVS(m_spec, m_module, 0, vtx, m_vs.in.POINTSIZE, m_rsBlock, true);
uint32_t pointSize = m_module.opFClamp(m_floatType, pointInfo.defaultValue, pointInfo.min, pointInfo.max);
m_module.opStore(m_vs.out.POINTSIZE, pointSize);
@ -1957,7 +1946,7 @@ namespace dxvk {
fogCtx.IsPositionT = false;
fogCtx.HasSpecular = false;
fogCtx.Specular = 0;
current = DoFixedFunctionFog(m_module, fogCtx);
current = DoFixedFunctionFog(m_spec, m_module, fogCtx);
m_module.opStore(m_ps.out.COLOR, current);
@ -1974,7 +1963,7 @@ namespace dxvk {
spv::ExecutionModeOriginUpperLeft);
uint32_t pointCoord = GetPointCoord(m_module);
auto pointInfo = GetPointSizeInfoPS(m_module, m_rsBlock);
auto pointInfo = GetPointSizeInfoPS(m_spec, m_module, m_rsBlock);
// We need to replace TEXCOORD inputs with gl_PointCoord
// if D3DRS_POINTSPRITEENABLE is set.
@ -2193,9 +2182,7 @@ namespace dxvk {
uint32_t floatPtr = m_module.defPointerType(m_floatType, spv::StorageClassPushConstant);
// Declare spec constants for render states
uint32_t alphaFuncId = m_module.specConst32(m_module.defIntType(32, 0), 0);
m_module.setDebugName(alphaFuncId, "alpha_func");
m_module.decorateSpecId(alphaFuncId, D3D9SpecConstantId::AlphaCompareOp);
uint32_t alphaFuncId = m_spec.get(m_module, SpecAlphaCompareOp);
// Implement alpha test
auto oC0 = m_ps.out.COLOR;

View File

@ -17,6 +17,7 @@ namespace dxvk {
class SpirvModule;
struct D3D9Options;
class D3D9ShaderSpecConstantManager;
struct D3D9FogContext {
// General inputs...
@ -44,7 +45,7 @@ namespace dxvk {
// Returns new oFog if VS
// Returns new oColor if PS
uint32_t DoFixedFunctionFog(SpirvModule& spvModule, const D3D9FogContext& fogCtx);
uint32_t DoFixedFunctionFog(D3D9ShaderSpecConstantManager& spec, SpirvModule& spvModule, const D3D9FogContext& fogCtx);
// Returns a render state block
uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count);
@ -56,13 +57,13 @@ namespace dxvk {
};
// Default point size and point scale magic!
D3D9PointSizeInfoVS GetPointSizeInfoVS(SpirvModule& spvModule, uint32_t vPos, uint32_t vtx, uint32_t perVertPointSize, uint32_t rsBlock, bool isFixedFunction);
D3D9PointSizeInfoVS GetPointSizeInfoVS(D3D9ShaderSpecConstantManager& spec, SpirvModule& spvModule, uint32_t vPos, uint32_t vtx, uint32_t perVertPointSize, uint32_t rsBlock, bool isFixedFunction);
struct D3D9PointSizeInfoPS {
uint32_t isSprite;
};
D3D9PointSizeInfoPS GetPointSizeInfoPS(SpirvModule& spvModule, uint32_t rsBlock);
D3D9PointSizeInfoPS GetPointSizeInfoPS(D3D9ShaderSpecConstantManager& spec, SpirvModule& spvModule, uint32_t rsBlock);
uint32_t GetPointCoord(SpirvModule& spvModule);

View File

@ -1,31 +1,119 @@
#pragma once
#include <array>
#include <cstdint>
#include "../spirv/spirv_module.h"
class D3D9DeviceEx;
namespace dxvk {
enum D3D9SpecConstantId : uint32_t {
AlphaCompareOp = 0, // Range: 0 -> 7 | Bits: 3
SamplerType = 1, // 2 bits for 16 samplers | Bits: 32
// ^ not used for vertex shaders
FogEnabled = 2, // Range: 0 -> 1 | Bits: 1
VertexFogMode = 3, // Range: 0 -> 3 | Bits: 2
PixelFogMode = 4, // Range: 0 -> 3 | Bits: 2
SpecSamplerType, // 2 bits for 16 PS samplers | Bits: 32
PointMode = 5, // Range: 0 -> 3 | Bits: 3
ProjectionType = 6, // 1 bit for 6 samplers | Bits: 6
// ^ not supported for vertex shaders
// PS 1.x only supports up to 6 samplers
SpecSamplerDepthMode, // 1 bit for 20 VS + PS samplers | Bits: 20
SpecAlphaCompareOp, // Range: 0 -> 7 | Bits: 3
SpecPointMode, // Range: 0 -> 3 | Bits: 2
SpecVertexFogMode, // Range: 0 -> 3 | Bits: 2
SpecPixelFogMode, // Range: 0 -> 3 | Bits: 2
SpecFogEnabled, // Range: 0 -> 1 | Bits: 1
VertexShaderBools = 7, // 16 bools | Bits: 16
PixelShaderBools = 8, // 16 bools | Bits: 16
Fetch4 = 9, // 1 bit for 16 samplers | Bits: 16
// ^ not supported for vertex shaders
SpecSamplerNull, // 1 bit for 20 samplers | Bits: 20
SpecProjectionType, // 1 bit for 6 PS 1.x samplers | Bits: 6
SamplerDepthMode = 10, // 1 bit for 20 samplers | Bits: 20
// ^ vs + ps
SamplerNull = 11, // 1 bit for 20 samplers | Bits: 20
// ^ vs + ps
SpecVertexShaderBools, // 16 bools | Bits: 16
SpecPixelShaderBools, // 16 bools | Bits: 16
SpecFetch4, // 1 bit for 16 PS samplers | Bits: 16
SpecConstantCount,
};
struct BitfieldPosition {
constexpr uint32_t mask() const {
return uint32_t((1ull << sizeInBits) - 1) << bitOffset;
}
uint32_t dwordOffset;
uint32_t bitOffset;
uint32_t sizeInBits;
};
struct D3D9SpecializationInfo {
static constexpr uint32_t MaxSpecDwords = 5;
static constexpr std::array<BitfieldPosition, SpecConstantCount> Layout{{
{ 0, 0, 32 }, // SamplerType
{ 1, 0, 20 }, // SamplerDepthMode
{ 1, 20, 3 }, // AlphaCompareOp
{ 1, 23, 2 }, // PointMode
{ 1, 25, 2 }, // VertexFogMode
{ 1, 27, 2 }, // PixelFogMode
{ 1, 29, 1 }, // FogEnabled
{ 2, 0, 20 }, // SamplerNull
{ 2, 20, 6 }, // ProjectionType
{ 3, 0, 16 }, // VertexShaderBools
{ 3, 16, 16 }, // PixelShaderBools
{ 4, 0, 16 }, // Fetch4
}};
template <D3D9SpecConstantId Id, typename T>
bool set(const T& value) {
const uint32_t x = uint32_t(value);
if (get<Id>() == x)
return false;
constexpr auto& layout = Layout[Id];
data[layout.dwordOffset] &= ~layout.mask();
data[layout.dwordOffset] |= (x << layout.bitOffset) & layout.mask();
return true;
}
template <D3D9SpecConstantId Id>
uint32_t get() const {
constexpr auto& layout = Layout[Id];
return (data[layout.dwordOffset] & layout.mask()) >> layout.bitOffset;
}
std::array<uint32_t, MaxSpecDwords> data = {};
};
class D3D9ShaderSpecConstantManager {
public:
uint32_t get(SpirvModule &module, D3D9SpecConstantId id) {
const auto &layout = D3D9SpecializationInfo::Layout[id];
uint32_t val = getSpecConstDword(module, layout.dwordOffset);
if (layout.sizeInBits == 32)
return val;
return module.opBitFieldUExtract(
module.defIntType(32, 0),
val,
module.consti32(layout.bitOffset),
module.consti32(layout.sizeInBits));
}
private:
uint32_t getSpecConstDword(SpirvModule &module, uint32_t idx) {
if (!m_specConstantIds[idx]) {
m_specConstantIds[idx] = module.specConst32(module.defIntType(32, 0), 0);
module.decorateSpecId(m_specConstantIds[idx], idx);
}
return m_specConstantIds[idx];
}
std::array<uint32_t, D3D9SpecializationInfo::MaxSpecDwords> m_specConstantIds = {};
};
}

View File

@ -270,14 +270,6 @@ namespace dxvk {
this->emitDclConstantBuffer();
}
m_nullSpecConstant = m_module.specConst32(m_module.defIntType(32, 0), 0);
m_module.decorateSpecId(m_nullSpecConstant, D3D9SpecConstantId::SamplerNull);
m_module.setDebugName(m_nullSpecConstant, "nullSamplers");
m_depthSpecConstant = m_module.specConst32(m_module.defIntType(32, 0), 0);
m_module.decorateSpecId(m_depthSpecConstant, D3D9SpecConstantId::SamplerDepthMode);
m_module.setDebugName(m_depthSpecConstant, "depthSamplers");
this->emitDclInputArray();
// Initialize the shader module with capabilities
@ -338,13 +330,6 @@ namespace dxvk {
binding.viewType = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
binding.access = VK_ACCESS_UNIFORM_READ_BIT;
m_bindings.push_back(binding);
m_boolSpecConstant = m_module.specConst32(m_module.defIntType(32, 0), 0);
m_module.decorateSpecId(m_boolSpecConstant,
m_programInfo.type() == DxsoProgramType::VertexShader
? D3D9SpecConstantId::VertexShaderBools
: D3D9SpecConstantId::PixelShaderBools);
m_module.setDebugName(m_boolSpecConstant, "boolConstants");
}
template<DxsoConstantBufferType ConstantBufferType>
@ -533,22 +518,6 @@ namespace dxvk {
m_ps.functionId = m_module.allocateId();
m_module.setDebugName(m_ps.functionId, "ps_main");
if (m_programInfo.majorVersion() < 2 || m_moduleInfo.options.forceSamplerTypeSpecConstants) {
m_ps.samplerTypeSpec = m_module.specConst32(m_module.defIntType(32, 0), 0);
m_module.decorateSpecId(m_ps.samplerTypeSpec, D3D9SpecConstantId::SamplerType);
m_module.setDebugName(m_ps.samplerTypeSpec, "s_sampler_types");
if (m_programInfo.majorVersion() < 2) {
m_ps.projectionSpec = m_module.specConst32(m_module.defIntType(32, 0), 0);
m_module.decorateSpecId(m_ps.projectionSpec, D3D9SpecConstantId::ProjectionType);
m_module.setDebugName(m_ps.projectionSpec, "s_projections");
}
}
m_ps.fetch4Spec = m_module.specConst32(m_module.defIntType(32, 0), 0);
m_module.decorateSpecId(m_ps.fetch4Spec, D3D9SpecConstantId::Fetch4);
m_module.setDebugName(m_ps.fetch4Spec, "s_fetch4");
this->setupRenderStateInfo();
this->emitPsSharedConstants();
@ -1059,8 +1028,12 @@ namespace dxvk {
bitfield = m_module.opLoad(accessType, ptrId);
}
else
bitfield = m_boolSpecConstant;
else {
bitfield = m_spec.get(m_module,
m_programInfo.type() == DxsoProgramType::VertexShader
? SpecVertexShaderBools
: SpecPixelShaderBools);
}
uint32_t bitIdx = m_module.consti32(reg.id.num % 32);
@ -2790,7 +2763,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
uint32_t bool_t = m_module.defBoolType();
uint32_t shouldProj = m_module.opBitFieldUExtract(
m_module.defIntType(32, 0), m_ps.projectionSpec,
m_module.defIntType(32, 0), m_spec.get(m_module, SpecProjectionType),
m_module.consti32(samplerIdx), m_module.consti32(1));
shouldProj = m_module.opIEqual(bool_t, shouldProj, m_module.constu32(1));
@ -2957,7 +2930,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
uint32_t fetch4 = 0;
if (m_programInfo.type() == DxsoProgramType::PixelShader && samplerType != SamplerTypeTexture3D) {
fetch4 = m_module.opBitFieldUExtract(
m_module.defIntType(32, 0), m_ps.fetch4Spec,
m_module.defIntType(32, 0), m_spec.get(m_module, SpecFetch4),
m_module.consti32(samplerIdx), m_module.consti32(1));
uint32_t bool_t = m_module.defBoolType();
@ -2990,7 +2963,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
imageOperands);
uint32_t shouldProj = m_module.opBitFieldUExtract(
m_module.defIntType(32, 0), m_ps.projectionSpec,
m_module.defIntType(32, 0), m_spec.get(m_module, SpecProjectionType),
m_module.consti32(samplerIdx), m_module.consti32(1));
shouldProj = m_module.opIEqual(m_module.defBoolType(), shouldProj, m_module.constu32(1));
@ -3053,7 +3026,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
uint32_t offset = m_module.consti32(m_programInfo.type() == DxsoProgramTypes::VertexShader ? samplerIdx + caps::MaxTexturesPS : samplerIdx);
uint32_t bitCnt = m_module.consti32(1);
uint32_t isNull = m_module.opBitFieldUExtract(typeId, m_nullSpecConstant, offset, bitCnt);
uint32_t isNull = m_module.opBitFieldUExtract(typeId, m_spec.get(m_module, SpecSamplerNull), offset, bitCnt);
isNull = m_module.opIEqual(m_module.defBoolType(), isNull, m_module.constu32(1));
// Only do the check for depth comp. samplers
@ -3063,7 +3036,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
uint32_t depthLabel = m_module.allocateId();
uint32_t endLabel = m_module.allocateId();
uint32_t isDepth = m_module.opBitFieldUExtract(typeId, m_depthSpecConstant, offset, bitCnt);
uint32_t isDepth = m_module.opBitFieldUExtract(typeId, m_spec.get(m_module, SpecSamplerDepthMode), offset, bitCnt);
isDepth = m_module.opIEqual(m_module.defBoolType(), isDepth, m_module.constu32(1));
m_module.opSelectionMerge(endLabel, spv::SelectionControlMaskNone);
@ -3103,7 +3076,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
uint32_t offset = m_module.consti32(samplerIdx * 2);
uint32_t bitCnt = m_module.consti32(2);
uint32_t type = m_module.opBitFieldUExtract(typeId, m_ps.samplerTypeSpec, offset, bitCnt);
uint32_t type = m_module.opBitFieldUExtract(typeId, m_spec.get(m_module, SpecSamplerType), offset, bitCnt);
m_module.opSelectionMerge(switchEndLabel, spv::SelectionControlMaskNone);
m_module.opSwitch(type,
@ -3367,7 +3340,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
if (m_programInfo.type() == DxsoProgramType::PixelShader) {
pointCoord = GetPointCoord(m_module);
pointInfo = GetPointSizeInfoPS(m_module, m_rsBlock);
pointInfo = GetPointSizeInfoPS(m_spec, m_module, m_rsBlock);
}
for (uint32_t i = 0; i < m_isgn.elemCount; i++) {
@ -3597,7 +3570,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
if (!outputtedColor1)
OutputDefault(DxsoSemantic{ DxsoUsage::Color, 1 });
auto pointInfo = GetPointSizeInfoVS(m_module, m_vs.oPos.id, 0, 0, m_rsBlock, false);
auto pointInfo = GetPointSizeInfoVS(m_spec, m_module, m_vs.oPos.id, 0, 0, m_rsBlock, false);
if (m_vs.oPSize.id == 0) {
m_vs.oPSize = this->emitRegisterPtr(
@ -3749,7 +3722,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
fogCtx.HasSpecular = false;
fogCtx.Specular = 0;
m_module.opStore(oColor0Ptr.id, DoFixedFunctionFog(m_module, fogCtx));
m_module.opStore(oColor0Ptr.id, DoFixedFunctionFog(m_spec, m_module, fogCtx));
}
@ -3758,9 +3731,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
uint32_t floatType = m_module.defFloatType(32);
uint32_t floatPtr = m_module.defPointerType(floatType, spv::StorageClassPushConstant);
uint32_t alphaFuncId = m_module.specConst32(m_module.defIntType(32, 0), 0);
m_module.setDebugName (alphaFuncId, "alpha_func");
m_module.decorateSpecId (alphaFuncId, D3D9SpecConstantId::AlphaCompareOp);
uint32_t alphaFuncId = m_spec.get(m_module, SpecAlphaCompareOp);
// Implement alpha test and fog
DxsoRegister color0;

View File

@ -8,6 +8,7 @@
#include "../d3d9/d3d9_constant_layout.h"
#include "../d3d9/d3d9_shader_permutations.h"
#include "../d3d9/d3d9_spec_constants.h"
#include "../spirv/spirv_module.h"
namespace dxvk {
@ -155,9 +156,6 @@ namespace dxvk {
*/
struct DxsoCompilerPsPart {
uint32_t functionId = 0;
uint32_t samplerTypeSpec = 0;
uint32_t projectionSpec = 0;
uint32_t fetch4Spec = 0;
//////////////
// Misc Types
@ -269,9 +267,7 @@ namespace dxvk {
SpirvModule m_module;
uint32_t m_boolSpecConstant;
uint32_t m_nullSpecConstant;
uint32_t m_depthSpecConstant;
D3D9ShaderSpecConstantManager m_spec;
///////////////////////////////////////////////////////
// Resource slot description for the shader. This will