diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index f3e490c7a..5cc87d97d 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -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 - 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(); - UpdatePushConstant(); - UpdatePushConstant(); - } + 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(); + UpdatePushConstant(); + UpdatePushConstant(); } + + 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(); - else if (m_lastPointMode != 0) - UpdatePointMode(); + UpdatePointMode(PrimitiveType == D3DPT_POINTLIST); if (likely(UseProgrammableVS())) { if (unlikely(m_flags.test(D3D9DeviceFlag::DirtyProgVertexShader))) { @@ -6045,14 +6019,14 @@ namespace dxvk { UploadConstants(); 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(); UpdatePushConstant(); m_flags.set(D3D9DeviceFlag::DirtyPointScale); - UpdatePointMode(); + 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(value)) + m_flags.set(D3D9DeviceFlag::DirtySpecializationEntries); + } + + + void D3D9DeviceEx::UpdateVertexBoolSpec(uint32_t value) { + if (m_specInfo.set(value)) + m_flags.set(D3D9DeviceFlag::DirtySpecializationEntries); + } + + + void D3D9DeviceEx::UpdatePixelBoolSpec(uint32_t value) { + if (m_specInfo.set(value)) + m_flags.set(D3D9DeviceFlag::DirtySpecializationEntries); + } + + + void D3D9DeviceEx::UpdatePixelShaderSamplerSpec(uint32_t types, uint32_t projections, uint32_t fetch4) { + bool dirty = m_specInfo.set(types); + dirty |= m_specInfo.set(projections); + dirty |= m_specInfo.set(fetch4); + + if (dirty) + m_flags.set(D3D9DeviceFlag::DirtySpecializationEntries); + } + + + void D3D9DeviceEx::UpdateCommonSamplerSpec(uint32_t nullMask, uint32_t depthMask) { + bool dirty = m_specInfo.set(depthMask); + dirty |= m_specInfo.set(nullMask); + + if (dirty) + m_flags.set(D3D9DeviceFlag::DirtySpecializationEntries); + } + + + void D3D9DeviceEx::UpdatePointModeSpec(uint32_t mode) { + if (m_specInfo.set(mode)) + m_flags.set(D3D9DeviceFlag::DirtySpecializationEntries); + } + + + void D3D9DeviceEx::UpdateFogModeSpec(bool fogEnabled, D3DFOGMODE vertexFogMode, D3DFOGMODE pixelFogMode) { + bool dirty = m_specInfo.set(fogEnabled); + dirty |= m_specInfo.set(vertexFogMode); + dirty |= m_specInfo.set(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); + } + } diff --git a/src/d3d9/d3d9_device.h b/src/d3d9/d3d9_device.h index 6b1d26412..0e1b5401b 100644 --- a/src/d3d9/d3d9_device.h +++ b/src/d3d9/d3d9_device.h @@ -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 @@ -80,6 +81,8 @@ namespace dxvk { DirtyPointScale, InScene, + + DirtySpecializationEntries, }; using D3D9DeviceFlags = Flags; @@ -776,8 +779,7 @@ namespace dxvk { void MarkTextureUploaded(D3D9CommonTexture* pResource); - template - 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; diff --git a/src/d3d9/d3d9_fixed_function.cpp b/src/d3d9/d3d9_fixed_function.cpp index 0fc845f75..45224b748 100644 --- a/src/d3d9/d3d9_fixed_function.cpp +++ b/src/d3d9/d3d9_fixed_function.cpp @@ -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; diff --git a/src/d3d9/d3d9_fixed_function.h b/src/d3d9/d3d9_fixed_function.h index e91de84a5..0649f8424 100644 --- a/src/d3d9/d3d9_fixed_function.h +++ b/src/d3d9/d3d9_fixed_function.h @@ -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); diff --git a/src/d3d9/d3d9_spec_constants.h b/src/d3d9/d3d9_spec_constants.h index 2c4fcc162..f30551cf3 100644 --- a/src/d3d9/d3d9_spec_constants.h +++ b/src/d3d9/d3d9_spec_constants.h @@ -1,31 +1,119 @@ #pragma once +#include + #include +#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 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 + bool set(const T& value) { + const uint32_t x = uint32_t(value); + if (get() == x) + return false; + + constexpr auto& layout = Layout[Id]; + + data[layout.dwordOffset] &= ~layout.mask(); + data[layout.dwordOffset] |= (x << layout.bitOffset) & layout.mask(); + + return true; + } + + template + uint32_t get() const { + constexpr auto& layout = Layout[Id]; + + return (data[layout.dwordOffset] & layout.mask()) >> layout.bitOffset; + } + + std::array 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 m_specConstantIds = {}; }; } \ No newline at end of file diff --git a/src/dxso/dxso_compiler.cpp b/src/dxso/dxso_compiler.cpp index a9e7fcedd..fc77d8183 100644 --- a/src/dxso/dxso_compiler.cpp +++ b/src/dxso/dxso_compiler.cpp @@ -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 @@ -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; diff --git a/src/dxso/dxso_compiler.h b/src/dxso/dxso_compiler.h index 93ee78fc5..c5f1b8a80 100644 --- a/src/dxso/dxso_compiler.h +++ b/src/dxso/dxso_compiler.h @@ -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