diff options
author | Joshua Ashton <joshua@froggi.es> | 2022-07-31 04:24:13 +0300 |
---|---|---|
committer | Joshua Ashton <joshua@froggi.es> | 2022-07-31 19:05:36 +0300 |
commit | 9dda7c8c849a85e772fd4208d2579f7cb2d3e7f2 (patch) | |
tree | 29b7d7b8d904fd29f893519dd7df5d0ad587008f | |
parent | 4905c6a0e1261063773bf31f0cdcbb303c16a7dc (diff) |
-rw-r--r-- | src/d3d9/d3d9_device.cpp | 10 | ||||
-rw-r--r-- | src/d3d9/d3d9_device.h | 1 | ||||
-rw-r--r-- | src/d3d9/d3d9_fixed_function.cpp | 60 | ||||
-rw-r--r-- | src/d3d9/d3d9_fixed_function.h | 7 | ||||
-rw-r--r-- | src/d3d9/d3d9_spec_constants.h | 38 | ||||
-rw-r--r-- | src/dxso/dxso_compiler.cpp | 26 | ||||
-rw-r--r-- | src/dxso/dxso_compiler.h | 2 |
7 files changed, 117 insertions, 27 deletions
diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index 7f5ca44c..e3aead38 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -4874,6 +4874,11 @@ namespace dxvk { CanSWVP() ? sizeof(D3D9FixedFunctionVertexBlendDataSW) : sizeof(D3D9FixedFunctionVertexBlendDataHW)); + + m_specBuffer = D3D9ConstantBuffer(this, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + getSpecConstantBufferSlot(), + sizeof(D3D9SpecializationInfo)); } @@ -7284,6 +7289,11 @@ namespace dxvk { ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, i, cSpecInfo.data[i]); }); + // TODO: Make uploading specialization information less naive. + auto mapPtr = m_specBuffer.AllocSlice(); + auto dst = reinterpret_cast<D3D9SpecializationInfo*>(mapPtr); + *dst = m_specInfo; + m_flags.clr(D3D9DeviceFlag::DirtySpecializationEntries); } diff --git a/src/d3d9/d3d9_device.h b/src/d3d9/d3d9_device.h index 0e1b5401..02be7e31 100644 --- a/src/d3d9/d3d9_device.h +++ b/src/d3d9/d3d9_device.h @@ -1186,6 +1186,7 @@ namespace dxvk { D3D9ConstantBuffer m_vsVertexBlend; D3D9ConstantBuffer m_psFixedFunction; D3D9ConstantBuffer m_psShared; + D3D9ConstantBuffer m_specBuffer; Rc<DxvkBuffer> m_upBuffer; VkDeviceSize m_upBufferOffset = 0ull; diff --git a/src/d3d9/d3d9_fixed_function.cpp b/src/d3d9/d3d9_fixed_function.cpp index 45224b74..350bda75 100644 --- a/src/d3d9/d3d9_fixed_function.cpp +++ b/src/d3d9/d3d9_fixed_function.cpp @@ -40,10 +40,10 @@ namespace dxvk { spvModule.opAccessChain(floatPtr, fogCtx.RenderState, 1, &fogDensityMember)); uint32_t fogMode = spec.get( - spvModule, + spvModule, fogCtx.SpecUBO, fogCtx.IsPixel ? SpecPixelFogMode : SpecVertexFogMode); - uint32_t fogEnabled = spec.get(spvModule, SpecFogEnabled); + uint32_t fogEnabled = spec.get(spvModule, fogCtx.SpecUBO, SpecFogEnabled); fogEnabled = spvModule.opINotEqual(spvModule.defBoolType(), fogEnabled, spvModule.constu32(0)); uint32_t doFog = spvModule.allocateId(); @@ -244,7 +244,43 @@ namespace dxvk { } - D3D9PointSizeInfoVS GetPointSizeInfoVS(D3D9ShaderSpecConstantManager& spec, SpirvModule& spvModule, uint32_t vPos, uint32_t vtx, uint32_t perVertPointSize, uint32_t rsBlock, bool isFixedFunction) { + uint32_t SetupSpecUBO(SpirvModule& spvModule, std::vector<DxvkBindingInfo>& bindings) { + uint32_t uintType = spvModule.defIntType(32, 0); + + std::array<uint32_t, SpecConstantCount> specMembers; + for (auto& x : specMembers) + x = uintType; + + uint32_t specStruct = spvModule.defStructTypeUnique(uint32_t(specMembers.size()), specMembers.data()); + + spvModule.setDebugName (specStruct, "spec_state_t"); + spvModule.decorate (specStruct, spv::DecorationBlock); + + for (uint32_t i = 0; i < SpecConstantCount; i++) { + std::string name = str::format("dword", i); + spvModule.setDebugMemberName (specStruct, i, name.c_str()); + spvModule.memberDecorateOffset (specStruct, i, sizeof(uint32_t) * i); + } + + uint32_t specBlock = spvModule.newVar( + spvModule.defPointerType(specStruct, spv::StorageClassUniform), + spv::StorageClassUniform); + + spvModule.setDebugName (specBlock, "spec_state"); + spvModule.decorateDescriptorSet(specBlock, 0); + spvModule.decorateBinding (specBlock, getSpecConstantBufferSlot()); + + DxvkBindingInfo binding = { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER }; + binding.resourceBinding = getSpecConstantBufferSlot(); + binding.viewType = VK_IMAGE_VIEW_TYPE_MAX_ENUM; + binding.access = VK_ACCESS_UNIFORM_READ_BIT; + bindings.push_back(binding); + + return specBlock; + } + + + D3D9PointSizeInfoVS GetPointSizeInfoVS(D3D9ShaderSpecConstantManager& spec, SpirvModule& spvModule, uint32_t vPos, uint32_t vtx, uint32_t perVertPointSize, uint32_t rsBlock, uint32_t specUbo, bool isFixedFunction) { uint32_t floatType = spvModule.defFloatType(32); uint32_t floatPtr = spvModule.defPointerType(floatType, spv::StorageClassPushConstant); uint32_t vec3Type = spvModule.defVectorType(floatType, 3); @@ -260,7 +296,7 @@ namespace dxvk { uint32_t value = perVertPointSize != 0 ? perVertPointSize : LoadFloat(D3D9RenderStateItem::PointSize); if (isFixedFunction) { - uint32_t pointMode = spec.get(spvModule, SpecPointMode); + uint32_t pointMode = spec.get(spvModule, specUbo, SpecPointMode); uint32_t scaleBit = spvModule.opBitFieldUExtract(uint32Type, pointMode, spvModule.consti32(0), spvModule.consti32(1)); uint32_t isScale = spvModule.opIEqual(boolType, scaleBit, spvModule.constu32(1)); @@ -306,12 +342,12 @@ namespace dxvk { } - D3D9PointSizeInfoPS GetPointSizeInfoPS(D3D9ShaderSpecConstantManager& spec, SpirvModule& spvModule, uint32_t rsBlock) { + D3D9PointSizeInfoPS GetPointSizeInfoPS(D3D9ShaderSpecConstantManager& spec, SpirvModule& spvModule, uint32_t rsBlock, uint32_t specUbo) { uint32_t uint32Type = spvModule.defIntType(32, 0); uint32_t boolType = spvModule.defBoolType(); uint32_t boolVec4 = spvModule.defVectorType(boolType, 4); - uint32_t pointMode = spec.get(spvModule, SpecPointMode); + uint32_t pointMode = spec.get(spvModule, specUbo, SpecPointMode); uint32_t spriteBit = spvModule.opBitFieldUExtract(uint32Type, pointMode, spvModule.consti32(1), spvModule.consti32(1)); uint32_t isSprite = spvModule.opIEqual(boolType, spriteBit, spvModule.constu32(1)); @@ -615,6 +651,8 @@ namespace dxvk { uint32_t m_entryPointId; uint32_t m_rsBlock; + uint32_t m_specUbo; + uint32_t m_mainFuncLabel; D3D9FixedFunctionOptions m_options; @@ -1153,9 +1191,10 @@ namespace dxvk { fogCtx.IsPositionT = m_vsKey.Data.Contents.HasPositionT; fogCtx.HasSpecular = m_vsKey.Data.Contents.HasColor1; fogCtx.Specular = m_vs.in.COLOR[1]; + fogCtx.SpecUBO = m_specUbo; m_module.opStore(m_vs.out.FOG, DoFixedFunctionFog(m_spec, m_module, fogCtx)); - auto pointInfo = GetPointSizeInfoVS(m_spec, 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, m_specUbo, true); uint32_t pointSize = m_module.opFClamp(m_floatType, pointInfo.defaultValue, pointInfo.min, pointInfo.max); m_module.opStore(m_vs.out.POINTSIZE, pointSize); @@ -1416,6 +1455,7 @@ namespace dxvk { void D3D9FFShaderCompiler::setupVS() { setupRenderStateInfo(); + m_specUbo = SetupSpecUBO(m_module, m_bindings); // VS Caps m_module.enableCapability(spv::CapabilityClipDistance); @@ -1946,6 +1986,7 @@ namespace dxvk { fogCtx.IsPositionT = false; fogCtx.HasSpecular = false; fogCtx.Specular = 0; + fogCtx.SpecUBO = m_specUbo; current = DoFixedFunctionFog(m_spec, m_module, fogCtx); m_module.opStore(m_ps.out.COLOR, current); @@ -1955,6 +1996,7 @@ namespace dxvk { void D3D9FFShaderCompiler::setupPS() { setupRenderStateInfo(); + m_specUbo = SetupSpecUBO(m_module, m_bindings); // PS Caps m_module.enableCapability(spv::CapabilityDerivativeControl); @@ -1963,7 +2005,7 @@ namespace dxvk { spv::ExecutionModeOriginUpperLeft); uint32_t pointCoord = GetPointCoord(m_module); - auto pointInfo = GetPointSizeInfoPS(m_spec, m_module, m_rsBlock); + auto pointInfo = GetPointSizeInfoPS(m_spec, m_module, m_rsBlock, m_specUbo); // We need to replace TEXCOORD inputs with gl_PointCoord // if D3DRS_POINTSPRITEENABLE is set. @@ -2182,7 +2224,7 @@ namespace dxvk { uint32_t floatPtr = m_module.defPointerType(m_floatType, spv::StorageClassPushConstant); // Declare spec constants for render states - uint32_t alphaFuncId = m_spec.get(m_module, SpecAlphaCompareOp); + uint32_t alphaFuncId = m_spec.get(m_module, m_specUbo, 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 0649f842..c6007791 100644 --- a/src/d3d9/d3d9_fixed_function.h +++ b/src/d3d9/d3d9_fixed_function.h @@ -35,6 +35,7 @@ namespace dxvk { bool IsPositionT; bool HasSpecular; uint32_t Specular; + uint32_t SpecUBO; }; struct D3D9FixedFunctionOptions { @@ -57,18 +58,20 @@ namespace dxvk { }; // Default point size and point scale magic! - D3D9PointSizeInfoVS GetPointSizeInfoVS(D3D9ShaderSpecConstantManager& spec, 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, uint32_t specUbo, bool isFixedFunction); struct D3D9PointSizeInfoPS { uint32_t isSprite; }; - D3D9PointSizeInfoPS GetPointSizeInfoPS(D3D9ShaderSpecConstantManager& spec, SpirvModule& spvModule, uint32_t rsBlock); + D3D9PointSizeInfoPS GetPointSizeInfoPS(D3D9ShaderSpecConstantManager& spec, SpirvModule& spvModule, uint32_t rsBlock, uint32_t specUbo); uint32_t GetPointCoord(SpirvModule& spvModule); uint32_t GetSharedConstants(SpirvModule& spvModule); + uint32_t SetupSpecUBO(SpirvModule& spvModule, std::vector<DxvkBindingInfo>& bindings); + constexpr uint32_t TCIOffset = 16; constexpr uint32_t TCIMask = 0b111 << TCIOffset; diff --git a/src/d3d9/d3d9_spec_constants.h b/src/d3d9/d3d9_spec_constants.h index 16c2f519..3c4eef70 100644 --- a/src/d3d9/d3d9_spec_constants.h +++ b/src/d3d9/d3d9_spec_constants.h @@ -4,6 +4,7 @@ #include <cstdint> +#include "../dxvk/dxvk_limits.h" #include "../spirv/spirv_module.h" class D3D9DeviceEx; @@ -89,22 +90,28 @@ namespace dxvk { class D3D9ShaderSpecConstantManager { public: - uint32_t get(SpirvModule &module, D3D9SpecConstantId id) { + uint32_t get(SpirvModule &module, uint32_t specUbo, D3D9SpecConstantId id) { const auto &layout = D3D9SpecializationInfo::Layout[id]; - uint32_t val = getSpecConstDword(module, layout.dwordOffset); + uint32_t uintType = module.defIntType(32, 0); + uint32_t optimized = getOptimizedBool(module); + + uint32_t quickValue = getSpecUBODword(module, specUbo, layout.dwordOffset); + uint32_t optimizedValue = getSpecConstDword(module, layout.dwordOffset); + + uint32_t val = module.opSelect(uintType, optimized, optimizedValue, quickValue); if (layout.sizeInBits == 32) return val; return module.opBitFieldUExtract( - module.defIntType(32, 0), + uintType, val, module.consti32(layout.bitOffset), module.consti32(layout.sizeInBits)); } private: - uint32_t getSpecConstDword(SpirvModule &module, uint32_t idx) { + 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); @@ -113,7 +120,28 @@ namespace dxvk { return m_specConstantIds[idx]; } - std::array<uint32_t, D3D9SpecializationInfo::MaxSpecDwords> m_specConstantIds = {}; + uint32_t getSpecUBODword(SpirvModule& module, uint32_t specUbo, uint32_t idx) { + uint32_t uintType = module.defIntType(32, 0); + uint32_t uintPtr = module.defPointerType(uintType, spv::StorageClassUniform); + + uint32_t member = module.constu32(idx); + uint32_t dword = module.opLoad(uintType, module.opAccessChain(uintPtr, specUbo, 1, &member)); + + return dword; + } + + uint32_t getOptimizedBool(SpirvModule& module) { + uint32_t boolType = module.defBoolType(); + + // The spec constant at MaxNumSpecConstants is set to True + // when this is an optimized pipeline. + uint32_t optimized = getSpecConstDword(module, MaxNumSpecConstants); + optimized = module.opINotEqual(boolType, optimized, module.constu32(0)); + + return optimized; + } + + std::array<uint32_t, MaxNumSpecConstants + 1> m_specConstantIds = {}; }; }
\ No newline at end of file diff --git a/src/dxso/dxso_compiler.cpp b/src/dxso/dxso_compiler.cpp index 86937c27..1d5888bd 100644 --- a/src/dxso/dxso_compiler.cpp +++ b/src/dxso/dxso_compiler.cpp @@ -480,6 +480,8 @@ namespace dxvk { this->setupRenderStateInfo(); + m_specUbo = SetupSpecUBO(m_module, m_bindings); + this->emitFunctionBegin( m_vs.functionId, m_module.defVoidType(), @@ -513,7 +515,6 @@ namespace dxvk { m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeOriginUpperLeft); - // Main function of the pixel shader m_ps.functionId = m_module.allocateId(); m_module.setDebugName(m_ps.functionId, "ps_main"); @@ -521,6 +522,8 @@ namespace dxvk { this->setupRenderStateInfo(); this->emitPsSharedConstants(); + m_specUbo = SetupSpecUBO(m_module, m_bindings); + this->emitFunctionBegin( m_ps.functionId, m_module.defVoidType(), @@ -1029,7 +1032,7 @@ namespace dxvk { bitfield = m_module.opLoad(accessType, ptrId); } else { - bitfield = m_spec.get(m_module, + bitfield = m_spec.get(m_module, m_specUbo, m_programInfo.type() == DxsoProgramType::VertexShader ? SpecVertexShaderBools : SpecPixelShaderBools); @@ -2763,7 +2766,7 @@ void DxsoCompiler::emitControlFlowGenericLoop( uint32_t bool_t = m_module.defBoolType(); uint32_t shouldProj = m_module.opBitFieldUExtract( - m_module.defIntType(32, 0), m_spec.get(m_module, SpecProjectionType), + m_module.defIntType(32, 0), m_spec.get(m_module, m_specUbo, SpecProjectionType), m_module.consti32(samplerIdx), m_module.consti32(1)); shouldProj = m_module.opINotEqual(bool_t, shouldProj, m_module.constu32(0)); @@ -2930,7 +2933,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_spec.get(m_module, SpecFetch4), + m_module.defIntType(32, 0), m_spec.get(m_module, m_specUbo, SpecFetch4), m_module.consti32(samplerIdx), m_module.consti32(1)); uint32_t bool_t = m_module.defBoolType(); @@ -2963,7 +2966,7 @@ void DxsoCompiler::emitControlFlowGenericLoop( imageOperands); uint32_t shouldProj = m_module.opBitFieldUExtract( - m_module.defIntType(32, 0), m_spec.get(m_module, SpecProjectionType), + m_module.defIntType(32, 0), m_spec.get(m_module, m_specUbo, SpecProjectionType), m_module.consti32(samplerIdx), m_module.consti32(1)); shouldProj = m_module.opINotEqual(m_module.defBoolType(), shouldProj, m_module.constu32(0)); @@ -3026,7 +3029,7 @@ void DxsoCompiler::emitControlFlowGenericLoop( uint32_t offset = m_module.consti32(m_programInfo.type() == DxsoProgramTypes::VertexShader ? samplerIdx + 17 : samplerIdx); uint32_t bitCnt = m_module.consti32(1); - uint32_t isNull = m_module.opBitFieldUExtract(typeId, m_spec.get(m_module, SpecSamplerNull), offset, bitCnt); + uint32_t isNull = m_module.opBitFieldUExtract(typeId, m_spec.get(m_module, m_specUbo, SpecSamplerNull), offset, bitCnt); isNull = m_module.opINotEqual(m_module.defBoolType(), isNull, m_module.constu32(0)); // Only do the check for depth comp. samplers @@ -3036,7 +3039,7 @@ void DxsoCompiler::emitControlFlowGenericLoop( uint32_t depthLabel = m_module.allocateId(); uint32_t endLabel = m_module.allocateId(); - uint32_t isDepth = m_module.opBitFieldUExtract(typeId, m_spec.get(m_module, SpecSamplerDepthMode), offset, bitCnt); + uint32_t isDepth = m_module.opBitFieldUExtract(typeId, m_spec.get(m_module, m_specUbo, SpecSamplerDepthMode), offset, bitCnt); isDepth = m_module.opINotEqual(m_module.defBoolType(), isDepth, m_module.constu32(0)); m_module.opSelectionMerge(endLabel, spv::SelectionControlMaskNone); @@ -3076,7 +3079,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_spec.get(m_module, SpecSamplerType), offset, bitCnt); + uint32_t type = m_module.opBitFieldUExtract(typeId, m_spec.get(m_module, m_specUbo, SpecSamplerType), offset, bitCnt); m_module.opSelectionMerge(switchEndLabel, spv::SelectionControlMaskNone); m_module.opSwitch(type, @@ -3340,7 +3343,7 @@ void DxsoCompiler::emitControlFlowGenericLoop( if (m_programInfo.type() == DxsoProgramType::PixelShader) { pointCoord = GetPointCoord(m_module); - pointInfo = GetPointSizeInfoPS(m_spec, m_module, m_rsBlock); + pointInfo = GetPointSizeInfoPS(m_spec, m_module, m_rsBlock, m_specUbo); } for (uint32_t i = 0; i < m_isgn.elemCount; i++) { @@ -3570,7 +3573,7 @@ void DxsoCompiler::emitControlFlowGenericLoop( if (!outputtedColor1) OutputDefault(DxsoSemantic{ DxsoUsage::Color, 1 }); - auto pointInfo = GetPointSizeInfoVS(m_spec, 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, m_specUbo, false); if (m_vs.oPSize.id == 0) { m_vs.oPSize = this->emitRegisterPtr( @@ -3721,6 +3724,7 @@ void DxsoCompiler::emitControlFlowGenericLoop( fogCtx.IsPositionT = false; fogCtx.HasSpecular = false; fogCtx.Specular = 0; + fogCtx.SpecUBO = m_specUbo; m_module.opStore(oColor0Ptr.id, DoFixedFunctionFog(m_spec, m_module, fogCtx)); } @@ -3731,7 +3735,7 @@ 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, SpecAlphaCompareOp); + uint32_t alphaFuncId = m_spec.get(m_module, m_specUbo, SpecAlphaCompareOp); // Implement alpha test and fog DxsoRegister color0; diff --git a/src/dxso/dxso_compiler.h b/src/dxso/dxso_compiler.h index c5f1b8a8..4360e599 100644 --- a/src/dxso/dxso_compiler.h +++ b/src/dxso/dxso_compiler.h @@ -367,6 +367,8 @@ namespace dxvk { uint32_t m_usedSamplers; uint32_t m_usedRTs; + uint32_t m_specUbo = 0; + uint32_t m_rsBlock = 0; uint32_t m_mainFuncLabel = 0; |